SurfSense/surfsense_backend/app/services/turnstile_service.py

53 lines
1.6 KiB
Python
Raw Normal View History

"""Cloudflare Turnstile CAPTCHA verification service."""
from __future__ import annotations
import logging
import httpx
from app.config import config
logger = logging.getLogger(__name__)
TURNSTILE_VERIFY_URL = "https://challenges.cloudflare.com/turnstile/v0/siteverify"
async def verify_turnstile_token(token: str, remote_ip: str | None = None) -> bool:
"""Verify a Turnstile response token with Cloudflare.
Returns True when the token is valid and the challenge was solved by a
real user. Returns False (never raises) on network errors or invalid
tokens so callers can treat it as a simple boolean gate.
"""
if not config.TURNSTILE_ENABLED:
return True
secret = config.TURNSTILE_SECRET_KEY
if not secret:
logger.warning("TURNSTILE_SECRET_KEY is not set; skipping verification")
return True
payload: dict[str, str] = {
"secret": secret,
"response": token,
}
if remote_ip:
payload["remoteip"] = remote_ip
try:
async with httpx.AsyncClient(timeout=10) as client:
resp = await client.post(TURNSTILE_VERIFY_URL, data=payload)
resp.raise_for_status()
data = resp.json()
success = data.get("success", False)
if not success:
logger.info(
"Turnstile verification failed: %s",
data.get("error-codes", []),
)
return bool(success)
except Exception:
logger.exception("Turnstile verification request failed")
return False