Skip to content

Commit edc78f1

Browse files
committed
recaptcha.refactoring
1 parent 2b28ded commit edc78f1

File tree

2 files changed

+51
-21
lines changed

2 files changed

+51
-21
lines changed

simon_aksw_org/recaptcha.py

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
"""Re-Captcha v2 validation"""
2+
3+
import httpx
4+
from pydantic import BaseModel
5+
6+
API_VERIFY_URL = "https://www.google.com/recaptcha/api/siteverify"
7+
8+
9+
class ValidationResponse(BaseModel):
10+
"""Response Token Validation Response
11+
12+
{'success': True, 'challenge_ts': '2026-03-08T21:48:08Z', 'hostname': 'localhost'}
13+
"""
14+
15+
success: bool
16+
17+
18+
class ResponseToken:
19+
"""Response token"""
20+
21+
def __init__(self, token: str, secret_key: str):
22+
self.token = token
23+
self.secret_key = secret_key
24+
25+
async def is_valid(self) -> bool:
26+
"""Check if response token is valid"""
27+
async with httpx.AsyncClient() as client:
28+
response = await client.post(
29+
url=API_VERIFY_URL,
30+
data={"secret": self.secret_key, "response": self.token},
31+
)
32+
validation = ValidationResponse(**response.json())
33+
return validation.success

simon_aksw_org/routers/home.py

Lines changed: 18 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,10 @@
55
import httpx
66
from fastapi import APIRouter, Form
77
from starlette.requests import Request
8-
from starlette.responses import HTMLResponse, RedirectResponse, Response
8+
from starlette.responses import HTMLResponse
99

1010
from simon_aksw_org.messages import get_messages, save_message
11+
from simon_aksw_org.recaptcha import ResponseToken
1112
from simon_aksw_org.settings import Settings, get_settings
1213

1314

@@ -35,10 +36,9 @@ async def homepage(request: Request) -> HTMLResponse:
3536
"""Homepage"""
3637
settings = get_settings()
3738
context = PageContext(settings)
38-
response: HTMLResponse = settings.templates.TemplateResponse(
39+
return settings.templates.TemplateResponse(
3940
request=request, name="home.html", context={"context": context}
4041
)
41-
return response
4242

4343

4444
@router.post("/", include_in_schema=False)
@@ -47,25 +47,22 @@ async def submit_statement(
4747
name: Annotated[str, Form()],
4848
message: Annotated[str, Form()],
4949
g_recaptcha_response: Annotated[str, Form(alias="g-recaptcha-response")] = "",
50-
) -> Response:
50+
) -> HTMLResponse:
5151
"""Process condolence form submission"""
5252
settings = get_settings()
53+
settings.logger.info(f"{name} submitted a message ... captcha: {g_recaptcha_response}")
54+
context = PageContext(settings)
55+
response_token = ResponseToken(
56+
token=g_recaptcha_response, secret_key=settings.recaptcha_secret_key.get_secret_value()
57+
)
5358

54-
async with httpx.AsyncClient() as client:
55-
resp = await client.post(
56-
"https://www.google.com/recaptcha/api/siteverify",
57-
data={
58-
"secret": settings.recaptcha_secret_key.get_secret_value(),
59-
"response": g_recaptcha_response,
60-
},
61-
)
62-
if not resp.json().get("success"):
63-
context = PageContext(
64-
settings, error="reCAPTCHA-Überprüfung fehlgeschlagen. Bitte versuchen Sie es erneut."
65-
)
66-
return settings.templates.TemplateResponse(
67-
request=request, name="home.html", context={"context": context}, status_code=400
68-
)
59+
if await response_token.is_valid():
60+
save_message(name=name, text=message, data_dir=settings.data_dir)
61+
status_code = httpx.codes.CREATED
62+
else:
63+
context.error = "reCAPTCHA validation failed"
64+
status_code = httpx.codes.BAD_REQUEST
6965

70-
save_message(name=name, text=message, data_dir=settings.data_dir)
71-
return RedirectResponse(url="/", status_code=303)
66+
return settings.templates.TemplateResponse(
67+
request=request, name="home.html", context={"context": context}, status_code=status_code
68+
)

0 commit comments

Comments
 (0)