§
    ‘v»j  ã                  ó  — d Z ddlmZ ddlZddlZddlZddlmZmZm	Z	m
Z
mZ ddlmZmZ  ed¬¦  «         G d„ d	¦  «        ¦   «         Z G d
„ dej        ¦  «        Z G d„ de¦  «        Z G d„ de¦  «        Z G d„ d¦  «        ZdS )z¶
Email verification service for quick registration and account activation.
Supports 6-digit secure numeric OTPs, activation link tokens, cooldown enforcement, and pluggable senders.
é    )ÚannotationsN)ÚAnyÚDictÚListÚOptionalÚTuple)Ú	dataclassÚfieldT)Úslotsc                  óv   — e Zd ZU dZded<   ded<   ded<   ded<   ded<   ded	<   d
Zded<   dZded<   ddd„ZdS )ÚVerificationCodez!Activation code and token record.ÚstrÚemailÚ
account_idÚcodeÚtokenÚfloatÚ
created_atÚ
expires_atr   ÚintÚfailed_attemptsFÚboolÚis_consumedNÚcurrent_timeúOptional[float]Úreturnc                óF   — |�|nt          j         ¦   «         }|| j        k    S ©N)Útimer   )Úselfr   Únows      ú7C:\Projects\FreeExile\server\auth\email_verification.pyÚ
is_expiredzVerificationCode.is_expired   s#   € Ø*Ð6ˆlˆl½D¼I¹K¼KˆØ�T”_Ò$Ð$ó    r   )r   r   r   r   )Ú__name__Ú
__module__Ú__qualname__Ú__doc__Ú__annotations__r   r   r#   © r$   r"   r   r      s“   € € € € € € à+Ð+Ø€J€J�JØ€O€O�OØ€I€I�IØ€J€J�JØÐÐÑØÐÐÑØ€OÐÐÐÑØ€KÐÐÐÑð%ð %ð %ð %ð %ð %ð %r$   r   c                  ó8   — e Zd ZdZej        	 ddd„¦   «         ZdS )ÚEmailSenderz)Abstract interface for email dispatching.NÚto_emailr   ÚsubjectÚbodyÚ	html_bodyúOptional[str]r   r   c                ó   — d S r   r*   ©r    r-   r.   r/   r0   s        r"   Ú
send_emailzEmailSender.send_email"   s	   € ð 	ˆr$   r   ©
r-   r   r.   r   r/   r   r0   r1   r   r   )r%   r&   r'   r(   ÚabcÚabstractmethodr4   r*   r$   r"   r,   r,      sF   € € € € € Ø3Ð3àÔð $(ðð ð ð ñ Ôðð ð r$   r,   c                  ó&   — e Zd ZdZdd„Z	 ddd„ZdS )ÚMockEmailSenderz;In-memory email sender for unit tests and local simulation.r   ÚNonec                ó   — g | _         d S r   )Úsent_messages)r    s    r"   Ú__init__zMockEmailSender.__init__0   s   € Ø35ˆÔÐÐr$   Nr-   r   r.   r/   r0   r1   r   c           
     ó†   — | j                              ||||pdt          t          j        ¦   «         ¦  «        dœ¦  «         dS )NÚ )Útor.   r/   r0   Ú	timestampT)r<   Úappendr   r   r3   s        r"   r4   zMockEmailSender.send_email3   sQ   € ð 	Ô×!Ò!ØØØØ"˜ bÝ�TœY™[œ[Ñ)Ô)ð#
ð #
ñ 	ô 	ð 	ð ˆtr$   )r   r:   r   r5   )r%   r&   r'   r(   r=   r4   r*   r$   r"   r9   r9   -   sL   € € € € € ØEÐEð6ð 6ð 6ð 6ð $(ðð ð ð ð ð ð r$   r9   c                  ó   — e Zd ZdZ	 ddd„ZdS )ÚConsoleEmailSenderz!Development console email sender.Nr-   r   r.   r/   r0   r1   r   r   c           	     ó8   — t          d|› d|› d|› d�¦  «         dS )Nz
[DEV EMAIL SENDER] To: z | Subject: ú
T)Úprintr3   s        r"   r4   zConsoleEmailSender.send_emailG   s3   € õ 	ÐS¨(ÐSÐSÀÐSÐSÈ4ÐSÐSÐSÑTÔTÐTØˆtr$   r   r5   )r%   r&   r'   r(   r4   r*   r$   r"   rD   rD   D   s8   € € € € € Ø+Ð+ð $(ðð ð ð ð ð ð r$   rD   c                  óJ   — e Zd ZdZ	 	 	 ddd„Zdd„Zdd„Zd d„Zd!d„Zd"d„Z	dS )#ÚEmailVerificationServicezHManages email activation OTPs, link tokens, cooldowns, and verification.é„  é<   é   Úemail_senderr,   Úcode_ttl_secondsr   Úcooldown_secondsÚmax_attemptsr   r:   c                óZ   — || _         || _        || _        || _        i | _        i | _        d S r   )rM   rN   rO   rP   Ú_recordsÚ
_last_sent)r    rM   rN   rO   rP   s        r"   r=   z!EmailVerificationService.__init__U   s6   € ð )ˆÔØ 0ˆÔØ 0ˆÔØ(ˆÔØ57ˆŒØ,.ˆŒˆˆr$   r   r   c                óN   — |                      ¦   «                              ¦   «         S r   )ÚstripÚlower©r    r   s     r"   Ú_normalize_emailz)EmailVerificationService._normalize_emailc   s   € Ø�{Š{‰}Œ}×"Ò"Ñ$Ô$Ð$r$   úTuple[bool, float]c                óÀ   — |                       |¦  «        }| j                             |¦  «        }|€dS t          j        ¦   «         |z
  }| j        |z
  }|dk    rd|fS dS )N)Tg        r   F)rX   rS   Úgetr   rO   )r    r   Ú
norm_emailÚ	last_timeÚelapsedÚ	remainings         r"   Ú
can_resendz#EmailVerificationService.can_resendf   sk   € Ø×*Ò*¨5Ñ1Ô1ˆ
Ø”O×'Ò'¨
Ñ3Ô3ˆ	ØÐØ�9å”)‘+”+ 	Ñ)ˆØÔ)¨GÑ3ˆ	Ø�qŠ=ˆ=Ø˜)Ð#Ð#Øˆyr$   r   r   c           	     óð  — |                       |¦  «        }t          j        ¦   «         }|                      |¦  «        \  }}|s t          dt	          |¦  «        › d�¦  «        ‚t          j        d¦  «        d›}t          j        d¦  «        }|| j        z   }	t          ||||||	¬¦  «        }
|
| j
        |<   || j        |<   d}d|› d	| j        d
z  › d|› d|› d�	}| j                             |||¬¦  «         |
S )z.Generate secure OTP and send activation email.zRate limited: Please wait z% seconds before requesting a new codei@B Ú06dé    )r   r   r   r   r   r   u<   [FreeExile] MÃ£ KÃ­ch Hoáº¡t TÃ i Khoáº£n Cá»• VÃµ Háº¯c Ã�muy   ChÃ o má»«ng chiáº¿n binh lÆ°u Ä‘Ã y Ä‘áº¿n vá»›i FreeExile!

MÃ£ xÃ¡c thá»±c kÃ­ch hoáº¡t tÃ i khoáº£n cá»§a báº¡n lÃ : u'   
MÃ£ nÃ y cÃ³ hiá»‡u lá»±c trong vÃ²ng rK   uj    phÃºt.

Hoáº·c nháº¥p vÃ o liÃªn káº¿t sau Ä‘á»ƒ kÃ­ch hoáº¡t nhanh:
https://freeexile.io/activate?email=z&token=uM   

Náº¿u báº¡n khÃ´ng thá»±c hiá»‡n yÃªu cáº§u nÃ y, vui lÃ²ng bá»� qua email.)r-   r.   r/   )rX   r   r`   Ú
ValueErrorr   ÚsecretsÚ	randbelowÚtoken_urlsaferN   r   rR   rS   rM   r4   )r    r   r   r\   r!   Úcan_sendr_   r   r   r   Úrecordr.   r/   s                r"   Úsend_activation_emailz.EmailVerificationService.send_activation_emailr   sZ  € à×*Ò*¨5Ñ1Ô1ˆ
ÝŒi‰kŒkˆà"Ÿošo¨jÑ9Ô9Ñˆ�)Øð 	qÝÐo½#¸i¹.¼.ÐoÐoÐoÑpÔpÐpõ Ô# IÑ.Ô.Ð4Ð4ˆÝÔ% bÑ)Ô)ˆØ˜4Ô0Ñ0ˆ
å!ØØ!ØØØØ!ð
ñ 
ô 
ˆð %+ˆŒ�jÑ!Ø&)ˆŒ˜
Ñ#àPˆð[ØJNð[ð [à59Ô5JÈbÑ5Pð[ð [ð 4>ð	[ð [ð GLð	[ð [ð [ð 	ð 	Ô×$Ò$¨jÀ'ÐPTÐ$ÑUÔUÐUØˆr$   úOptional[VerificationCode]c                ó\   — | j                              |                      |¦  «        ¦  «        S r   )rR   r[   rX   rW   s     r"   Úget_active_recordz*EmailVerificationService.get_active_record˜   s&   € ØŒ}× Ò  ×!6Ò!6°uÑ!=Ô!=Ñ>Ô>Ð>r$   Úcode_or_tokenúTuple[bool, str]c                óÞ  — |                       |¦  «        }| j                             |¦  «        }|sdS |j        rdS |                     ¦   «         rdS |j        | j        k    rdS |                     ¦   «         }t          j	        |j
        |¦  «        }t          j	        |j        |¦  «        }|s|r	d|_        dS |xj        dz  c_        t          d| j        |j        z
  ¦  «        }d	d
|› d�fS )zHVerify OTP or activation token with single-use and max retry protection.)Fz3No active verification request found for this email)Fz'Verification code has already been used)Fz7Verification code has expired. Please request a new one)Fz2Too many failed attempts. Code locked for securityT)TÚOKé   r   FzIncorrect code. z attempts remaining)rX   rR   r[   r   r#   r   rP   rU   re   Úcompare_digestr   r   Úmax)	r    r   rn   r\   ri   Úcleaned_inputÚis_code_matchÚis_token_matchÚremaining_attemptss	            r"   Úverify_codez$EmailVerificationService.verify_code›   s  € à×*Ò*¨5Ñ1Ô1ˆ
Ø”×"Ò" :Ñ.Ô.ˆàð 	PØOÐOàÔð 	DØCÐCà×ÒÑÔð 	TØSÐSàÔ! TÔ%6Ò6Ð6ØNÐNà%×+Ò+Ñ-Ô-ˆÝÔ.¨v¬{¸MÑJÔJˆÝ Ô/°´¸mÑLÔLˆàð 	˜Nð 	Ø!%ˆFÔØ�:àÐÔ !Ñ#ÐÔÝ   DÔ$5¸Ô8NÑ$NÑOÔOÐØÐPÐ);ÐPÐPÐPÐPÐPr$   N)rJ   rK   rL   )
rM   r,   rN   r   rO   r   rP   r   r   r:   )r   r   r   r   )r   r   r   rY   )r   r   r   r   r   r   )r   r   r   rk   )r   r   rn   r   r   ro   )
r%   r&   r'   r(   r=   rX   r`   rj   rm   ry   r*   r$   r"   rI   rI   R   s©   € € € € € ØRÐRð
 !$Ø "Øð/ð /ð /ð /ð /ð%ð %ð %ð %ð
ð 
ð 
ð 
ð$ð $ð $ð $ðL?ð ?ð ?ð ?ðQð Qð Qð Qð Qð Qr$   rI   )r(   Ú
__future__r   r6   re   r   Útypingr   r   r   r   r   Údataclassesr	   r
   r   ÚABCr,   r9   rD   rI   r*   r$   r"   ú<module>r~      sˆ  ððð ð
 #Ð "Ð "Ð "Ð "Ð "Ø 
€
€
€
Ø €€€Ø €€€Ø 3Ð 3Ð 3Ð 3Ð 3Ð 3Ð 3Ð 3Ð 3Ð 3Ð 3Ð 3Ð 3Ð 3Ø (Ð (Ð (Ð (Ð (Ð (Ð (Ð (ð €�ÐÑÔð%ð %ð %ð %ð %ñ %ô %ñ Ôð%ð ð ð ð ð �#”'ñ ô ð ðð ð ð ð �kñ ô ð ð.ð ð ð ð ˜ñ ô ð ðdQð dQð dQð dQð dQñ dQô dQð dQð dQð dQr$   