§
    #Ÿ’j4  ã                  óž   — d dl mZ d dlZd dlmZmZ d dlmZ d dlmZ d dl	m
Z
 d dlmZmZmZ  ej        d¦  «        Z G d	„ d
e
¦  «        ZdS )é    )ÚannotationsN)ÚdatetimeÚtimezone)ÚAny)ÚHTTPException)ÚBasePostgresClient)Úhash_passwordÚvalidate_password_strengthÚverify_passwordzdscons.auth.user_authc                  óH   — e Zd ZdZ	 	 ddd
„Z	 	 	 ddd„Zdd„Z	 	 	 ddd„ZdS )ÚUserAuthMixinzMEmail authentication, secure password management, and brute-force protection.NÚemailÚstrÚpasswordú
str | NoneÚ	full_nameÚreturnúdict[str, Any]c           	     óX  — |                      ¦   «                              ¦   «         }|rd|vrt          dd¬¦  «        ‚|st          dd¬¦  «        ‚|                      ¦   «         5 }|                     ¦   «         5 }|                     d|f¦  «         |                     ¦   «         }|�rê|                     dd¦  «        st          d	d
¬¦  «        ‚|                     d¦  «        }|r\t          j	        t          j        ¦  «        }	|j        € |                     t          j        ¬¦  «        }||	k    rt          dd¬¦  «        ‚|                     d¦  «        }
|
s;|                     d¦  «        dk    rt          dd¬¦  «        ‚t          dd¬¦  «        ‚t          ||
¦  «        }|s¦|                     d¦  «        pddz   }|dk    rC|                     d||d         f¦  «         |                     ¦   «          t          dd¬¦  «        ‚|                     d||d         f¦  «         |                     ¦   «          t          dd¬¦  «        ‚|                     d|d         f¦  «         |                     ¦   «         }|                     ¦   «          nt          dd¬¦  «        ‚	 ddd¦  «         n# 1 swxY w Y   ddd¦  «         n# 1 swxY w Y   |                      |¦  «        }d|t#          |d         ¦  «        |d          |d!         |d"         |                     d#¦  «        d$œd%œS )&zJAuthenticate user by email and verified password with brute-force lockout.ú@é�  õ%   Ä�á»‹a chá»‰ email khÃ´ng há»£p lá»‡.©Ústatus_codeÚdetailu0   Vui lÃ²ng cung cáº¥p máº­t kháº©u Ä‘Äƒng nháº­p.a  
                    SELECT u.*, e.employee_code, e.department, e.job_title
                    FROM erp_users u
                    LEFT JOIN employees e ON u.linked_employee_id = e.id
                    WHERE LOWER(u.email) = %s
                    LIMIT 1;
                    Ú	is_activeTi“  uE   TÃ i khoáº£n nÃ y Ä‘Ã£ bá»‹ vÃ´ hiá»‡u hÃ³a bá»Ÿi quáº£n trá»‹ viÃªn.Úlocked_untilN)Útzinfoi§  uy   TÃ i khoáº£n táº¡m thá»�i bá»‹ khÃ³a do nháº­p sai máº­t kháº©u 5 láº§n liÃªn tiáº¿p. Vui lÃ²ng thá»­ láº¡i sau 15 phÃºt.Úpassword_hashÚoauth_providerÚgoogleut   TÃ i khoáº£n nÃ y Ä‘Æ°á»£c Ä‘Äƒng kÃ½ qua Google OAuth. Vui lÃ²ng chá»�n 'Continue with Google' Ä‘á»ƒ Ä‘Äƒng nháº­p.i‘  u-   Email hoáº·c máº­t kháº©u khÃ´ng chÃ­nh xÃ¡c.Úfailed_login_attemptsr   é   é   aJ  
                                UPDATE erp_users
                                SET failed_login_attempts = %s,
                                    locked_until = NOW() + INTERVAL '15 minutes',
                                    updated_at = NOW()
                                WHERE id = %s;
                                Úidu\   TÃ i khoáº£n Ä‘Ã£ bá»‹ táº¡m khÃ³a 15 phÃºt do nháº­p sai máº­t kháº©u 5 láº§n liÃªn tiáº¿p.zø
                                UPDATE erp_users
                                SET failed_login_attempts = %s,
                                    updated_at = NOW()
                                WHERE id = %s;
                                aW  
                        UPDATE erp_users
                        SET failed_login_attempts = 0,
                            locked_until = NULL,
                            last_login_at = NOW(),
                            updated_at = NOW()
                        WHERE id = %s
                        RETURNING *;
                        ÚBearerr   r   ÚroleÚ
avatar_url©r%   r   r   r'   r(   ©Ú
token_typeÚaccess_tokenÚuser)ÚstripÚlowerr   Úget_connectionÚcursorÚexecuteÚfetchoneÚgetr   Únowr   Úutcr   Úreplacer   ÚcommitÚcreate_jwt_tokenr   )Úselfr   r   r   Úclean_emailÚconnÚcurr-   r   Únow_utcÚstored_hashÚis_validÚattemptsÚ	jwt_tokens                 ú<C:\Projects\DSCons\app\modules\auth\application\user_auth.pyÚauthenticate_email_userz%UserAuthMixin.authenticate_email_user   se  € ð —k’k‘m”m×)Ò)Ñ+Ô+ˆØð 	a˜c¨Ð4Ð4Ý¨CÐ8_Ð`Ñ`Ô`Ð`àð 	ÝØÐ(Zðñ ô ð ð × Ò Ñ"Ô"ð i	 dØ—’‘”ð h #à—’ðð !�Nñ	ô 	ð 	ð —|’|‘~”~�àñ ZàŸ8š8 K°Ñ6Ô6ð Ý+Ø(+Ø#jðñ ô ð ð $(§8¢8¨NÑ#;Ô#;�LØ#ð Ý"*¤,­x¬|Ñ"<Ô"<˜Ø'Ô.Ð6Ø+7×+?Ò+?ÅxÄ|Ð+?Ñ+TÔ+T˜LØ'¨'Ò1Ð1Ý"/Ø,/ð (cð#ñ #ô #ð ð #'§(¢(¨?Ñ";Ô";�KØ&ð 
ØŸ8š8Ð$4Ñ5Ô5¸ÒAÐAÝ"/Ø,/ð (^ð#ñ #ô #ð õ
 ,Ø(+Ø#Rðñ ô ð õ  /¨x¸ÑEÔE�HØ#ð  Ø$(§H¢HÐ-DÑ$EÔ$EÐ$JÈÈaÑ#O˜Ø# qš=˜=ØŸKšKð!$ð "*¨4°¬:Ð 6ñ	ô 	ð 	ð !ŸKšK™MœM˜MÝ"/Ø,/ð (Fð#ñ #ô #ð ð
  ŸKšKð!$ð "*¨4°¬:Ð 6ñô ð ð !ŸKšK™MœM˜MÝ"/Ø,/Ø'Vð#ñ #ô #ð ð —K’Kðð ˜dœ˜ñô ð ð Ÿ<š<™>œ>�DØ—K’K‘M”M�M�Mõ (Ø$'ØNðñ ô ð ð "ðEhð hð hñ hô hð hð hð hð hð hð høøøð hð hð hð hði	ð i	ð i	ñ i	ô i	ð i	ð i	ð i	ð i	ð i	ð i	øøøð i	ð i	ð i	ð i	ðV ×)Ò)¨$Ñ/Ô/ˆ	à"Ø%å˜$˜tœ*‘o”oØ˜gœØ! +Ô.Ø˜VœØ"Ÿhšh |Ñ4Ô4ðð ð

ð 

ð 
	
s7   Á%KÁ:H*J1Ê%KÊ1J5	Ê5KÊ8J5	Ê9KËKËKÚviewerr'   Úlinked_employee_idc                ó´  — |                      ¦   «                              ¦   «         }|rd|vrt          dd¬¦  «        ‚t          |¦  «        \  }}|st          d|pd¬¦  «        ‚|                      ¦   «         5 }	|	                     ¦   «         5 }
|
                     d|f¦  «         |
                     ¦   «         rt          dd¬¦  «        ‚|
                     d	¦  «         |
                     ¦   «         }|r|d
         nd}|p@|                     d¦  «        d          	                    dd¦  «         
                    ¦   «         }d| 	                    dd¦  «        › d�}t          |¦  «        }|
                     d||||d|› �|||f¦  «         |
                     ¦   «         }|	                     ¦   «          ddd¦  «         n# 1 swxY w Y   ddd¦  «         n# 1 swxY w Y   t          |d
         ¦  «        |d         |d         |d         |                     d¦  «        |d         |                     d¦  «        r|d                              ¦   «         nddœS )zMAdmin user creation endpoint for authorized Superadmin/Director provisioning.r   r   r   r   u4   Máº­t kháº©u khÃ´ng Ä‘Ã¡p á»©ng yÃªu cáº§u an toÃ n.z9SELECT id FROM erp_users WHERE LOWER(email) = %s LIMIT 1;i™  u<   TÃ i khoáº£n email nÃ y Ä‘Ã£ tá»“n táº¡i trong há»‡ thá»‘ng.z!SELECT id FROM companies LIMIT 1;r%   Nr   ú.ú ú!https://ui-avatars.com/api/?name=ú+z&background=0284c7&color=fffaI  
                    INSERT INTO erp_users (
                        company_id, email, full_name, avatar_url,
                        oauth_provider, oauth_sub, role, linked_employee_id,
                        password_hash, failed_login_attempts, locked_until,
                        password_changed_at, is_active, last_login_at
                    ) VALUES (
                        %s, %s, %s, %s,
                        'local', %s, %s, %s,
                        %s, 0, NULL,
                        NOW(), TRUE, NOW()
                    ) RETURNING *;
                    zlocal-r   r   r'   r(   r   Ú
created_at)r%   r   r   r'   r(   r   rL   )r.   r/   r   r
   r0   r1   r2   r3   Úsplitr7   Útitler	   r8   r   r4   Ú	isoformat)r:   r   r   r   r'   rF   r;   Úis_valid_strengthÚerr_msgr<   r=   ÚcompÚ
company_idÚnameÚavatarÚpwd_hashr-   s                    rC   Úcreate_user_accountz!UserAuthMixin.create_user_accountž   s  € ð —k’k‘m”m×)Ò)Ñ+Ô+ˆØð 	a˜c¨Ð4Ð4Ý¨CÐ8_Ð`Ñ`Ô`Ð`å%?ÀÑ%IÔ%IÑ"Ð˜7Ø ð 	ÝØØÐXÐ"Xðñ ô ð ð
 × Ò Ñ"Ô"ð .	 dØ—’‘”ð - #Ø—’ØOØ �Nñô ð ð —<’<‘>”>ð Ý'Ø$'Ø]ðñ ô ð ð
 —’Ð?Ñ@Ô@Ð@Ø—|’|‘~”~�Ø+/Ð9˜T $œZ˜Z°T�
à ÐW K×$5Ò$5°cÑ$:Ô$:¸1Ô$=×$EÒ$EÀcÈ3Ñ$OÔ$O×$UÒ$UÑ$WÔ$W�Øq¸T¿\º\È#ÈsÑ=SÔ=SÐqÐqÐq�Ý(¨Ñ2Ô2�à—’ðð #Ø#ØØØ. Ð.Ð.ØØ*Ø ð	ñô ð ð2 —|’|‘~”~�Ø—’‘”�ð[-ð -ð -ñ -ô -ð -ð -ð -ð -ð -ð -øøøð -ð -ð -ð -ð.	ð .	ð .	ñ .	ô .	ð .	ð .	ð .	ð .	ð .	ð .	øøøð .	ð .	ð .	ð .	õb �d˜4”j‘/”/Ø˜'”]Ø˜kÔ*Ø˜”LØŸ(š( <Ñ0Ô0Ø˜kÔ*à�xŠx˜Ñ%Ô%ð˜$˜|Ô,×6Ò6Ñ8Ô8Ð8àð

ð 

ð 
	
s7   Á9GÂD'GÆ5GÇG	ÇGÇG	Ç	GÇGÇGÚuser_idÚold_passwordÚnew_passwordc                ó”  — t          |¦  «        \  }}|st          d|pd¬¦  «        ‚|                      ¦   «         5 }|                     ¦   «         5 }|                     d|f¦  «         |                     ¦   «         }|st          dd¬¦  «        ‚|                     d¦  «        r't          ||d         ¦  «        st          dd¬¦  «        ‚t          |¦  «        }	|                     d	|	|f¦  «         | 	                    ¦   «          d
ddœcddd¦  «         cddd¦  «         S # 1 swxY w Y   	 ddd¦  «         dS # 1 swxY w Y   dS )zJChange user password securely with verification and complexity validation.r   u:   Máº­t kháº©u má»›i khÃ´ng Ä‘Ã¡p á»©ng yÃªu cáº§u an toÃ n.r   zNSELECT id, password_hash, oauth_provider FROM erp_users WHERE id = %s LIMIT 1;i”  u/   KhÃ´ng tÃ¬m tháº¥y tÃ i khoáº£n ngÆ°á»�i dÃ¹ng.r   u-   Máº­t kháº©u hiá»‡n táº¡i khÃ´ng chÃ­nh xÃ¡c.aI  
                    UPDATE erp_users
                    SET password_hash = %s,
                        password_changed_at = NOW(),
                        failed_login_attempts = 0,
                        locked_until = NULL,
                        updated_at = NOW()
                    WHERE id = %s;
                    Úsuccessu!   Ä�á»•i máº­t kháº©u thÃ nh cÃ´ng.)ÚstatusÚmessageN)
r
   r   r0   r1   r2   r3   r4   r   r	   r8   )
r:   rX   rY   rZ   rP   rQ   r<   r=   r-   Únew_hashs
             rC   Úchange_user_passwordz"UserAuthMixin.change_user_passwordî   s\  € õ &@ÀÑ%MÔ%MÑ"Ð˜7Ø ð 	ÝØØÐ^Ð"^ðñ ô ð ð
 × Ò Ñ"Ô"ð  	] dØ—’‘”ð ] #Ø—’ØdØ�Jñô ð ð —|’|‘~”~�Øð Ý'Ø$'Ð0aðñ ô ð ð —8’8˜OÑ,Ô,ð Ý*¨<¸¸oÔ9NÑOÔOð Ý+Ø(+Ð4cðñ ô ð õ )¨Ñ6Ô6�Ø—’ðð ˜wÐ'ñô ð ð —’‘”�Ø"+Ð8[Ð\Ð\ð?]ð ]ð ]ð ]ñ ]ô ]ð ]ð 	]ð  	]ð  	]ð  	]ñ  	]ô  	]ð  	]ð  	]ð]ð ]ð ]ð ]øøøð ]ð ]ð ]ð ]ð ]ð 	]ð  	]ð  	]ñ  	]ô  	]ð  	]ð  	]ð  	]ð  	]ð  	]ð  	]ð  	]øøøð  	]ð  	]ð  	]ð  	]ð  	]ð  	]s6   ¼D=ÁB:D$ÄD=Ä$D(	Ä(D=Ä+D(	Ä,D=Ä=EÅEúadmin@dscons.vnõ   Ban GiÃ¡m Ä�á»‘c DSConsÚ
superadminrT   c           	     ó^  — |d|› �|d|                      dd¦  «        › d�dœ}|                      |¦  «        }|                      ¦   «         5 }|                     ¦   «         5 }|                     d||d         f¦  «         |                     ¦   «         }|                     ¦   «          d	d	d	¦  «         n# 1 swxY w Y   d	d	d	¦  «         n# 1 swxY w Y   |                      |¦  «        }d
|t          |d         ¦  «        |d         |d         |d         | 	                    d¦  «        dœdœS )zSDevelopment and test helper to create an authenticated session and issue JWT token.zdev-rJ   rI   rK   z&background=0D8ABC&color=fff)r   ÚsubrT   Úpicturez9UPDATE erp_users SET role = %s WHERE id = %s RETURNING *;r%   Nr&   r   r   r'   r(   r)   r*   )
r7   Úget_or_create_google_userr0   r1   r2   r3   r8   r9   r   r4   )	r:   r   rT   r'   Údummy_profiler-   r<   r=   Útokens	            rC   Úcreate_dev_user_sessionz%UserAuthMixin.create_dev_user_session  s»  € ð Ø!˜%�>�>ØØo¸4¿<º<ÈÈSÑ;QÔ;QÐoÐoÐoð	
ð 
ˆð ×-Ò-¨mÑ<Ô<ˆØ× Ò Ñ"Ô"ð 	 dØ—’‘”ð  #Ø—’ØOØ˜4 œ:Ð&ñô ð ð —|’|‘~”~�Ø—’‘”�ðð ð ñ ô ð ð ð ð ð ð øøøð ð ð ð ð	ð 	ð 	ñ 	ô 	ð 	ð 	ð 	ð 	ð 	ð 	øøøð 	ð 	ð 	ð 	ð ×%Ò% dÑ+Ô+ˆà"Ø!å˜$˜tœ*‘o”oØ˜gœØ! +Ô.Ø˜VœØ"Ÿhšh |Ñ4Ô4ðð ð

ð 

ð 
	
s7   ÁCÁ!AB4Â(CÂ4B8	Â8CÂ;B8	Â<CÃCÃC)NN)r   r   r   r   r   r   r   r   )NrE   N)r   r   r   r   r   r   r'   r   rF   r   r   r   )rX   r   rY   r   rZ   r   r   r   )ra   rb   rc   )r   r   rT   r   r'   r   r   r   )Ú__name__Ú
__module__Ú__qualname__Ú__doc__rD   rW   r`   rj   © ó    rC   r   r      s¨   € € € € € ØWÐWð
  $Ø $ð	F
ð F
ð F
ð F
ð F
ðX !%ØØ)-ðN
ð N
ð N
ð N
ð N
ð`+]ð +]ð +]ð +]ð^ 'Ø-Ø ð	"
ð "
ð "
ð "
ð "
ð "
ð "
rp   r   )Ú
__future__r   Úloggingr   r   Útypingr   Úfastapir   Úapp.core.postgres.baser   Ú,app.modules.auth.application.password_hasherr	   r
   r   Ú	getLoggerÚloggerr   ro   rp   rC   ú<module>ry      sô   ðØ "Ð "Ð "Ð "Ð "Ð "à €€€Ø 'Ð 'Ð 'Ð 'Ð 'Ð 'Ð 'Ð 'Ø Ð Ð Ð Ð Ð à !Ð !Ð !Ð !Ð !Ð !à 5Ð 5Ð 5Ð 5Ð 5Ð 5ðð ð ð ð ð ð ð ð ð ð 
ˆÔ	Ð2Ñ	3Ô	3€ðj
ð j
ð j
ð j
ð j
Ð&ñ j
ô j
ð j
ð j
ð j
rp   