File tree Expand file tree Collapse file tree 4 files changed +55
-0
lines changed
Expand file tree Collapse file tree 4 files changed +55
-0
lines changed Original file line number Diff line number Diff line change 1+ import logging
2+
3+ import httpx
4+
5+ from app import settings
6+
7+ recaptcha_http_client = httpx .AsyncClient (
8+ base_url = "https://www.google.com/recaptcha" ,
9+ )
10+
11+
12+ async def verify_recaptcha (
13+ * ,
14+ recaptcha_token : str ,
15+ client_ip_address : str ,
16+ ) -> bool :
17+ try :
18+ response = await recaptcha_http_client .post (
19+ "/api/siteverify" ,
20+ data = {
21+ "secret" : settings .RECAPTCHA_SECRET_KEY ,
22+ "response" : recaptcha_token ,
23+ "remoteip" : client_ip_address , # https://stackoverflow.com/a/51920956
24+ },
25+ )
26+ response .raise_for_status ()
27+ response_data = response .json ()
28+ if not isinstance (response_data , dict ):
29+ raise ValueError ("Invalid response from recaptcha" )
30+ return response_data .get ("success" , False ) is True
31+
32+ except Exception :
33+ logging .exception (
34+ "Failed to verify recaptcha" ,
35+ extra = {
36+ "recaptcha_token" : recaptcha_token ,
37+ "client_ip_address" : client_ip_address ,
38+ },
39+ )
40+ return False
Original file line number Diff line number Diff line change @@ -107,6 +107,7 @@ async def logout(
107107
108108class InitializePasswordResetRequest (BaseModel ):
109109 username : str
110+ recaptcha_token : str
110111
111112
112113@router .post ("/public/api/v1/init-password-reset" )
@@ -117,6 +118,7 @@ async def initialize_password_reset(
117118) -> Response :
118119 response = await authentication .initialize_password_reset (
119120 username = args .username ,
121+ recaptcha_token = args .recaptcha_token ,
120122 client_ip_address = client_ip_address ,
121123 client_user_agent = client_user_agent ,
122124 )
Original file line number Diff line number Diff line change @@ -39,3 +39,5 @@ def read_bool(s: str) -> bool:
3939MAILGUN_BASE_URL = os .environ ["MAILGUN_BASE_URL" ]
4040MAILGUN_DOMAIN_NAME = os .environ ["MAILGUN_DOMAIN_NAME" ]
4141MAILGUN_API_KEY = os .environ ["MAILGUN_API_KEY" ]
42+
43+ RECAPTCHA_SECRET_KEY = os .environ ["RECAPTCHA_SECRET_KEY" ]
Original file line number Diff line number Diff line change 55
66from app import security
77from app .adapters import mailgun
8+ from app .adapters import recaptcha
89from app .common_types import UserPrivileges
910from app .errors import Error
1011from app .errors import ErrorCode
@@ -115,9 +116,19 @@ async def logout(
115116async def initialize_password_reset (
116117 * ,
117118 username : str ,
119+ recaptcha_token : str ,
118120 client_ip_address : str ,
119121 client_user_agent : str ,
120122) -> None | Error :
123+ if not await recaptcha .verify_recaptcha (
124+ recaptcha_token = recaptcha_token ,
125+ client_ip_address = client_ip_address ,
126+ ):
127+ return Error (
128+ error_code = ErrorCode .INCORRECT_CREDENTIALS ,
129+ user_feedback = "Invalid reCAPTCHA token." ,
130+ )
131+
121132 user = await users .fetch_one_by_username (username )
122133 if user is None :
123134 return Error (
You can’t perform that action at this time.
0 commit comments