ó
    JjŒ"  ã                  ó  • S r SSKJr  SSKrSSKrSSKrSSKrSSKrSSKJ	r	  SSK
rSSKJr  SSKJr  \" S5      rSS jrSS	 jrSS
 jrSS jrSS jrSS jrSS jrSS jrSS jrS S jrS!S jrS"S jrS#S jrS$S%S jjrS&S jrS'S jr g)(aÅ  Agent identity, server fingerprint, and secret storage.

Responsibilities:
  * generate a stable server fingerprint (used for de-dup / re-registration)
  * persist the backend-assigned server_id into agent.conf
  * read/write the agent token under a root-only secrets dir

SECURITY: install tokens are NEVER written here. Only the long-lived agent
token is persisted (v1 returns no refresh token). The token is stored as a
plain file with restrictive permissions (0600) inside the root-only secrets
directory (0700). The agent has no third-party dependencies, so it installs and
runs on a clean Linux server without pip; sealing/encryption is a production
TODO that must not reintroduce a runtime dependency.
é    )ÚannotationsN)ÚPath)ÚConfig)Ú
get_loggerÚidentityc                óT   • [         R                  " SU R                  S5      USS5      $ )zFDerive 256-bit key from fingerprint and salt using PBKDF2-HMAC-SHA256.Úsha256úutf-8i'  é    )ÚhashlibÚpbkdf2_hmacÚencode)ÚfingerprintÚsalts     Ú2D:\Programs\laragon\www\wolf\agent\src\identity.pyÚ_derive_keyr       s'   € ä×Ò˜x¨×);Ñ);¸GÓ)DÀdÈEÐSUÓVÐVó    c                óN  • [         R                  " S5      n[         R                  " S5      n[        X5      nU R                  S5      n[	        [        U5      5      nSn[        S[        U5      S5       H‹  nUR                  SS5      n	[        R                  " XCU	-   [        R                  5      R                  5       n
[        S[        U5      U-
  5      n[        U5       H  nXXU-      X¬   -  XhU-   '   M     US-  nM�     X#-   [        U5      -   nSUR                  5        3$ )	zQEncrypt token using standard HMAC-CTR stream cipher bound to machine fingerprint.é   r
   r   r   é   Úbigé   úwp_enc:)ÚosÚurandomr   r   Ú	bytearrayÚlenÚrangeÚto_bytesÚhmacÚnewr   r	   ÚdigestÚminÚbytesÚhex)Útokenr   r   ÚivÚkeyÚ	plaintextÚ
ciphertextÚblock_indexÚoffsetÚcounter_bytesÚkeystream_blockÚ
chunk_sizeÚiÚpayloads                 r   Úencrypt_tokenr2   %   s  € ä�:Š:�b‹>€DÜ	�Š�B‹€BÜ
�kÓ
(€Cà—‘˜WÓ%€IÜœ3˜y›>Ó*€Jà€KÜ˜œ3˜y›>¨2Ö.ˆØ#×,Ñ,¨Q°Ó6ˆÜŸ(š( 3¨]Ñ(:¼G¿N¹NÓK×RÑRÓTˆä˜œS ›^¨fÑ4Ó5ˆ
Ü�zÖ"ˆAØ%.¸©zÑ%:¸_Ñ=OÑ%OˆJ ‘zÓ"ñ #à�qÑŠñ /ð ‰iœ% 
Ó+Ñ+€GØ�W—[‘[“]�OÐ$Ð$r   c                ót  • U R                  S5      (       d  U $ [        R                  U SS 5      n[        U5      S:  a  [	        S5      eUSS nUSS nUSS n[        X5      n[        [        U5      5      nSn[        S[        U5      S5       H‹  n	UR                  SS	5      n
[        R                  " XdU
-   [        R                  5      R                  5       n[        S[        U5      U	-
  5      n[        U5       H  nXYU-      X½   -  XyU-   '   M     US
-  nM�     [        U5      R                  S5      $ )zYDecrypt token using standard HMAC-CTR stream cipher (returns plaintext if not encrypted).r   é   Nr   z&Invalid encrypted token payload lengthr   r   r   r   r   r
   )Ú
startswithr$   Úfromhexr   Ú
ValueErrorr   r   r   r   r    r!   r   r	   r"   r#   Údecode)Úencrypted_datar   r1   r   r'   r*   r(   r)   r+   r,   r-   r.   r/   r0   s                 r   Údecrypt_tokenr:   <   s0  € à×$Ñ$ Y×/Ñ/ØÐä�m‰m˜N¨1¨2Ð.Ó/€GÜ
ˆ7ƒ|�bÓÜÐAÓBÐBà�3�Bˆ<€DØ	��Bˆ€BØ˜˜�€Jä
�kÓ
(€CÜœ#˜j›/Ó*€Ià€KÜ˜œ3˜z›?¨BÖ/ˆØ#×,Ñ,¨Q°Ó6ˆÜŸ(š( 3¨]Ñ(:¼G¿N¹NÓK×RÑRÓTˆä˜œS ›_¨vÑ5Ó6ˆ
Ü�zÖ"ˆAØ$.¸©zÑ$:¸_Ñ=OÑ$OˆI˜q‘jÓ!ñ #à�qÑŠñ 0ô �Ó×"Ñ" 7Ó+Ð+r   c                ó¾   •  [        U SSS9 nUR                  5       R                  5       =(       d    S sS S S 5        $ ! , (       d  f       g = f! [         a     g f = f)NÚrr
   ©Úencoding)ÚopenÚreadlineÚstripÚOSError)ÚpathÚhandles     r   Ú_read_first_linerE   Y   sJ   € ðÜ�$˜ gÒ.°&Ø—?‘?Ó$×*Ñ*Ó,×4°÷ /×.×.ûäó Ùðús+   ‚A �'>´	A ¾
AÁA ÁA Á
AÁAc                 ó4   • [         R                  " 5       n U S $ )z9Best-effort stable MAC-derived value from uuid.getnode().Ú012x)ÚuuidÚgetnode)Únodes    r   Ú_primary_macrK   a   s   € ä�<Š<‹>€DØ�4ˆ[Ðr   c                 ó  • [        S5      =(       d    [        S5      =(       d    S[        R                  " 5       [        5       /n [        R
                  " SR                  U 5      R                  S5      5      R                  5       nSUSS  3$ )	aN  Build a stable, non-secret server fingerprint.

Combines machine-id, hostname and a MAC-derived value, then hashes them so
the result is opaque and contains no directly identifying data. The same
server should produce the same fingerprint across reinstalls, which lets the
control plane detect re-registration vs. a brand new server.
z/etc/machine-idz/var/lib/dbus/machine-idÚ Ú|r
   Úfp_Nr   )	rE   ÚsocketÚgethostnamerK   r   r	   Újoinr   Ú	hexdigest)Úpartsr"   s     r   Úgenerate_fingerprintrU   g   sz   € ô 	Ð*Ó+÷ 	ÜÐ6Ó7÷	àÜ×ÒÓÜ‹ð€Eô �^Š^˜CŸH™H U›O×2Ñ2°7Ó;Ó<×FÑFÓH€FØ�˜˜��ÐÐr   c                óÊ  • U R                   U R                  U R                  U R                  U R                  U R
                  U R                  U R                  4 H  nUR                  SSS9  M     [        U R                   S5        [        U R                  S5        [        U R                  S5        U R                  R                  SSS9  [        U R                  S5        g)z?Create the runtime directory tree with appropriate permissions.T©ÚparentsÚexist_okéÀ  N)Úetc_dirÚopt_dirÚvar_dirÚlog_dirÚ	spool_dirÚjobs_dirÚdiscovery_dirÚ	cache_dirÚmkdirÚ_chmodÚsecrets_dir)ÚconfigÚ	directorys     r   Úensure_dirsrh   z   s·   € ð 	�‰Ø�‰Ø�‰Ø�‰Ø×ÑØ�‰Ø×ÑØ×Ñó	ˆ	ð 	�‰ ¨tˆÓ4ñ	ô ˆ6�>‰>˜5Ô!Ü
ˆ6�>‰>˜5Ô!Ü
ˆ6�>‰>˜5Ô!ð ×Ñ×Ñ T°DÐÑ9Ü
ˆ6×Ñ˜uÕ%r   c                óT   •  U R                  U5        g ! [        [        4 a     g f = f©N)ÚchmodrB   ÚNotImplementedError)rC   Úmodes     r   rd   rd   ’   s+   € ðØ�
‰
�4ÕøÜÔ(Ð)ó Ùðús   ‚ ”'¦'c                óò   • UR                   R                  SSS9  [        UR                   S5        [        5       n[	        X#5      nUR                  USS9  [        US5        [        R                  SU5        g)	z„Write a secret as an encrypted file with 0600 permissions in a 0700 dir.

The secret is encrypted bound to the machine fingerprint.
TrW   rZ   r
   r=   é€  zstored secret securely at %sN)Úparentrc   rd   rU   r2   Ú
write_textÚlogÚinfo)rf   rC   Úvaluer   Úencrypted_values        r   Úwrite_secretrv   ™   sd   € ð
 	‡K�K×Ñ˜d¨TÐÑ2Ü
ˆ4�;‰;˜Ôä&Ó(€KÜ# EÓ7€Oà‡O�O�O¨g€OÑ6Ü
ˆ4�ÔÜ‡H�HÐ+¨TÕ2r   c                ó˜   •  UR                  SS9R                  5       nU(       d  g [        5       n[        X#5      $ ! [         a     g f = f)Nr
   r=   )Ú	read_textrA   rU   r:   rB   )rf   rC   Údatar   s       r   Úread_secretrz   ©   sK   € ðØ�~‰~ wˆ~Ð/×5Ñ5Ó7ˆÞØÜ*Ó,ˆÜ˜TÓ/Ð/øÜó Ùðús   ‚$< §< ¼
A	ÁA	c                ó.  • U R                   R                  R                  SSS9  / nU R                   R                  5       (       a'  U R                   R	                  SS9R                  5       nSn[        U5       H9  u  pVUR                  5       R                  U S35      (       d  M.  U SU 3X5'   Sn  O   U(       d  UR                  U SU 35        U R                   R                  SR                  U5      S-   SS9  [        U R                   S5        g	)
z=Insert or update a KEY=VALUE line in agent.conf (idempotent).TrW   r
   r=   FÚ=Ú
ro   N)Ú	conf_filerp   rc   Úis_filerx   Ú
splitlinesÚ	enumeraterA   r5   Úappendrq   rR   rd   )rf   r(   rt   ÚlinesÚreplacedÚindexÚlines          r   Úset_conf_valuer‡   ´   sý   € à
×Ñ×Ñ×!Ñ!¨$¸Ð!Ñ>Ø€EØ×Ñ×Ñ×!Ñ!Ø× Ñ ×*Ñ*°GÐ*Ð<×GÑGÓIˆà€HÜ  Ö'‰ˆØ�:‰:‹<×"Ñ" c U¨! 9×-Ó-Ø!˜U ! E 7Ð+ˆE‰LØˆHÙñ	 (ö
 Ø�‰˜�u˜A˜e˜WÐ%Ô&à
×Ñ×Ñ §	¡	¨%Ó 0°4Ñ 7À'ÐÑJÜ
ˆ6×Ñ˜UÕ#r   c                óT   • [         R                  " U R                  XS:H  S9  Xl        g)z<Persist agent status in runtime state (never in agent.conf).Úrevoked)Ústatusr‰   N)Ústate_moduleÚupdate_stateÚ
state_filerŠ   )rf   rŠ   s     r   Úsave_statusrŽ   È   s'   € ä×ÒØ×Ñ &¸YÑ3Fòð …Mr   c                ód   • U=(       d    Sn[         R                  " U R                  US9  X l        g)zJPersist the latest heartbeat/registration error (single-line) or clear it.rM   )Ú
last_errorN)r‹   rŒ   r�   r�   )rf   Úerrorrt   s      r   Úsave_last_errorr’   Ð   s'   € à�K�R€EÜ×Ò˜f×/Ñ/¸EÒBØÕr   c                óÆ   • SU0nU(       a  SUS'   Ub  X#S'   [         R                  " U R                  40 UD6  Xl        SU;   a  [	        US   5      U l        Ub  X l        gg)zLRecord that registration is still owed (e.g. installer could not reach API).Úregistration_pendingÚpending_installrŠ   Nr�   )r‹   rŒ   r�   r”   ÚstrrŠ   r�   )rf   Úpendingr‘   Úchangess       r   Úset_registration_pendingr™   ×   sp   € à"8¸'Ð!B€GÞØ-ˆ�ÑØÑØ %�ÑÜ×Ò˜f×/Ñ/Ñ;°7Ò;Ø")ÔØ�7ÓÜ˜G HÑ-Ó.ˆŒØÑØ!Õð r   c                óä   • [        U SU5        [        X R                  U5        [        R                  " U R
                  SSSSS9  SU l        SU l        SU l        [        R                  SU5        g)u¸   Persist registration results: server_id to conf, agent token to secrets.

v1 contract returns only {agent_token, server_id, status} â€” there is no
agent_id or refresh_token to store.
ÚWOLFPANEL_SERVER_IDÚ
registeredrM   F)rŠ   r�   r”   r‰   z#credentials stored for server_id=%sN)r‡   rv   Úagent_token_filer‹   rŒ   r�   rŠ   r�   r”   rr   rs   )rf   Ú	server_idÚagent_tokens      r   Ústore_credentialsr    æ   sl   € ô �6Ð0°)Ô<Ü�×0Ñ0°+Ô>Ü×ÒØ×ÑØØØ"Øòð !€F„MØ€FÔØ"'€FÔÜ‡H�HÐ2°IÕ>r   c                ó,   • [        X R                  5      $ rj   )rz   r�   )rf   s    r   Úload_agent_tokenr¢   û   s   € Ü�v×6Ñ6Ó7Ð7r   )r   r–   r   r$   Úreturnr$   )r&   r–   r   r–   r£   r–   )r9   r–   r   r–   r£   r–   )rC   r–   r£   ú
str | None)r£   r–   )rf   r   r£   ÚNone)rC   r   rm   Úintr£   r¥   )rf   r   rC   r   rt   r–   r£   r¥   )rf   r   rC   r   r£   r¤   )rf   r   r(   r–   rt   r–   r£   r¥   )rf   r   rŠ   r–   r£   r¥   )rf   r   r‘   r¤   r£   r¥   rj   )rf   r   r—   Úboolr‘   r¤   r£   r¥   )rf   r   rž   r–   rŸ   r–   r£   r¥   )rf   r   r£   r¤   )!Ú__doc__Ú
__future__r   r    r   r   rP   rH   Úpathlibr   Ústater‹   rf   r   Úloggerr   rr   r   r2   r:   rE   rK   rU   rh   rd   rv   rz   r‡   rŽ   r’   r™   r    r¢   © r   r   Ú<module>r®      s…   ðñõ #ã Û 	Û Û Û Ý ã Ý Ý á�Ó€ôWô
%ô.,ô:ôôô&&ô0ô3ô ô$ô(ôö"ô?õ*8r   