+
    úÃîiÅ  ã                  ó´   a € 0 t $ R t^ RIHt ^ RIt^ RIt^ RIt^ RIHtHtH	t	 ^ RI
Ht ^ RIHt / tR]R&   ^
t^tR R	 ltR
 R ltR R ltR R ltR R ltR# )ux  
services/captcha_service.py â€” CAPTCHA Service
==============================================
Replaces the emoji-based AI captcha with a reliable math CAPTCHA.
Reasons:
  - Emoji grids are ambiguous and frustrating (what counts as a "vehicle"?)
  - OpenAI returns different emoji sets each time â€” hard to verify
  - Math challenges are unambiguous, instant, and work offline

Flow:
  1. GET  /api/auth/captcha/challenge  â†’ server generates math question, stores answer
  2. POST /api/auth/captcha/verify     â†’ candidate submits answer, server checks it
  3. On success â†’ issues a short-lived captcha_token (used in login)
)ÚannotationsN)ÚdatetimeÚ	timedeltaÚtimezone)Úsettings)Újson_dbzdict[str, dict]Ú_challengesc               ó   € V ^8„  d   QhRR/# ©é   ÚreturnÚdict© )Úformats   "Ú=D:\Python_Codes\gen_ai\people_hub\services\captcha_service.pyÚ__annotate__r   #   s   € ÷ Bñ B˜dñ Bó    c                 óÒ  € \         P                  ! . RO4      p V R8X  dz   \         P                  ! ^^4      p\         P                  ! ^^4      p\         P                  ! RR.4      pVR8X  d	   W!8”  d   Y!r!VR8X  d	   W,           MW,
          pRV RV RV R2pM¿\         P                  ! RR.4      pVR8X  dA   \         P                  ! ^^	4      p\         P                  ! ^^	4      pW,          pRV R	V R2pM`\         P                  ! ^^	4      p\         P                  ! ^^4      p\         P                  ! ^^4      pW,           V,           pRV R
V R
V R2pRVR\        V4      RV/# )zCGenerate a random arithmetic challenge. Returns {question, answer}.ÚeasyÚ+Ú-zWhat is Ú Ú?ÚmulÚchainu    Ã— z + ÚquestionÚanswerÚ
answer_int)r   r   Úmedium)ÚrandomÚchoiceÚrandintÚstr)ÚlevelÚaÚbÚopÚansÚqÚvariantÚcs           r   Ú_make_math_challenger+   #   sK  € ä�MŠMÒ4Ó5€Eà�„Ü�NŠN˜1˜bÓ!ˆÜ�NŠN˜1˜bÓ!ˆÜ�]Š]˜C ˜:Ó&ˆØ�Œ9˜œØˆqØ˜sœˆqŽu¨­ˆØ�q�c˜˜2˜$˜a ˜s !Ð$‰ô —-’- ¨Ð 0Ó1ˆØ�eÔÜ—’˜q !Ó$ˆAÜ—’˜q !Ó$ˆAØ•%ˆCØ˜1˜#˜T !  AÐ&‰Aô —’˜q !Ó$ˆAÜ—’˜q !Ó$ˆAÜ—’˜q !Ó$ˆAà•%˜!•)ˆCØ˜1˜#˜S   3 q c¨Ð+ˆAà˜˜8¤S¨£X¨|¸SÐAÐAr   c               ó   € V ^8„  d   QhRR/# r
   r   )r   s   "r   r   r   C   s   € ÷ ñ ˜$ñ r   c                 ó  € \        4       p \        P                  ! ^4      p\        P                  ! \
        P                  4      \        \        R7      ,           pRV R,          RVRRR^ /\        V&   RVRR	R
V R
,          /# )ua   
Generate a new math CAPTCHA challenge.
Returns the question to the client â€” never the answer.
)Úminutesr   Ú
expires_atÚusedFÚattemptsÚ
session_idÚchallenge_typeÚmathr   )
r+   ÚsecretsÚtoken_urlsafer   Únowr   Úutcr   Ú_EXPIRY_MINUTESr   )Úchallenge_datar2   r/   s      r   Úcreate_challenger;   C   s   € ô
 *Ó+€NÜ×&Ò& rÓ*€JÜ—’œhŸl™lÓ+¬iÄÔ.PÕP€Jð 	�n XÕ.Ø�jØ�eØ�að	„K�
Ñð 	˜*Ø˜&Ø˜.¨Õ4ðð r   c               ó    € V ^8„  d   QhRRRR/# )r   r2   r"   r   r   r   )r   s   "r   r   r   [   s   € ÷ ñ  #ð ¨$ñ r   c                óB   € \         P                  V R4       \        4       # )zg
Generate a fresh challenge, invalidating the old one.
Called when the user clicks the Refresh button.
N)r   Úpopr;   )r2   s   &r   Úrefresh_challenger?   [   s   € ô ‡O�O�J Ô%ÜÓÐr   c               ó$   € V ^8„  d   QhRRRRRR/# )r   r2   r"   r   r   r   r   )r   s   "r   r   r   e   s&   € ÷ Nñ N ð N¨cð N°dñ Nr   c                óN  € \         P                  ! \        P                  4      p\        P                  4        UUu. uF  w  r4W$R,          8”  g   K  VNK  	  pppV F  p\        P                  VR4       K  	  \        P                  V 4      pV'       g   RRRRRRRR	/# W&R,          8”  d!   \        P                  V R4       RRRRRR
RR	/# VR,          '       d   RRRRRRRR	/# VP                  R^ 4      ^,           VR&   VR,          \        8”  d!   \        P                  V R4       RRRRRRRR	/# \        T;'       g    R4      P                  4       P                  4       p\        VR,          4      P                  4       P                  4       pWx8w  d#   \        VR,          ,
          p	RRRRRRV	 R2RR/# R	VR&   \        P                  ! ^ 4      p
\        P                  ! \         P"                  RV
RV RR	R\        P$                  ! 4       /4       RR	RV
RRRR/# u uppi )zI
Verify the candidate's math answer.
Returns {verified, token, message}.
r/   NÚverifiedFÚtokenÚmessagezCChallenge expired or not found. Please click Refresh and try again.ÚrefreshTz6Challenge expired. Please click Refresh for a new one.r0   z>This challenge was already used. Please refresh for a new one.r1   z6Too many attempts. Please refresh for a new challenge.Ú r   zIncorrect answer. z attempt(s) remaining.Úcaptcha_tokenr2   Ú
created_atu   Verification successful âœ“)r   r7   r   r8   r   Úitemsr>   ÚgetÚ_MAX_ATTEMPTSr"   ÚstripÚlowerr5   r6   ÚdbÚinsertr   ÚSESSIONS_FILEÚnow_iso)r2   r   r7   ÚkÚvÚexpiredÚ	challengeÚ	submittedÚcorrectÚ	remainingrC   s   &&         r   Úverify_challengerY   e   sB  € ô �,Š,”x—|‘|Ó
$€CÜ(×.Ñ.Ô0ÔJÑ0‘T�Q°C¸L½/Ñ4I�qˆqÑ0€GÑJÛˆÜ�‰˜˜4Ö ñ ô —‘ 
Ó+€Ißà˜Ø˜ØÐ]Ø˜ð	
ð 	
ð �|Õ$Ô$Ü�‰˜
 DÔ)à˜Ø˜ØÐPØ˜ð	
ð 	
ð �×Ôà˜Ø˜ØÐXØ˜ð	
ð 	
ð &ŸM™M¨*°aÓ8¸1Õ<€IˆjÑà�Õœ}Ô,Ü�‰˜
 DÔ)à˜Ø˜ØÐPØ˜ð	
ð 	
ô �F—L�L˜bÓ!×'Ñ'Ó)×/Ñ/Ó1€IÜ�I˜hÕ'Ó(×.Ñ.Ó0×6Ñ6Ó8€GàÔÜ! I¨jÕ$9Õ9ˆ	à˜Ø˜ØÐ,¨Y¨KÐ7MÐNØ˜ð	
ð 	
ð €IˆfÑÜ×!Ò! "Ó%€Eä‡I‚IŒh×$Ñ$Ø˜Ø˜Ø˜ØœŸš›ð	'ô ð 	�DØ�EØÐ1Ø�Eð	ð ùóE Ks   ¼H!ÁH!c               ó    € V ^8„  d   QhRRRR/# )r   rC   r"   r   Úboolr   )r   s   "r   r   r   ¶   s   € ÷ ñ  #ð ¨$ñ r   c                óX   € \         P                  ! \        P                  V RR7      pVRJ# )z;Check a captcha_token issued after successful verification.T)rG   rB   N)rN   Úfind_oner   rP   )rC   Úrecords   & r   Úvalidate_captcha_tokenr_   ¶   s%   € ä�[Š[œ×/Ñ/¸uÈtÔT€FØ˜ÐÐr   )Ú__conditional_annotations__Ú__doc__Ú
__future__r   r5   r   Úoperatorr   r   r   Úconfigr   Úutilsr   rN   r   Ú__annotations__r9   rK   r+   r;   r?   rY   r_   )r`   s   @r   Ú<module>rg      sX   øðôõ #Û Û Û ß 2Ñ 2Ý Ý ð  "€ˆ_Ó !à€Ø€õBõ@õ0õN÷br   