Ë
    À7jý  ã                  óØ   — d Z ddlmZ ddlZddlZddlZddlmZ ddlm	Z	m
Z
 ddlmZ ddlmZ  ed«      Zdd	„Zdd
„Zdd„Zdd„Zdd„Zdd„Zdd„Zdd„Zdd„Zdd„Zdd„Zd d„Zd!d„Zy)"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). For v1 this is a plain file
with restrictive permissions; sealing/encryption is a production TODO.
é    )ÚannotationsN)ÚPath)ÚFernetÚInvalidToken)ÚConfig)Ú
get_loggerÚidentityc                ó®   — 	 t        | dd¬«      5 }|j                  «       j                  «       xs d cd d d «       S # 1 sw Y   y xY w# t        $ r Y y w xY w)NÚrúutf-8©Úencoding)ÚopenÚreadlineÚstripÚOSError)ÚpathÚhandles     úB/var/www/downloads.wolfpanel.net/public_html/agent/src/identity.pyÚ_read_first_liner      sS   € ðÜ�$˜ gÔ.ð 	5°&Ø—?‘?Ó$×*Ñ*Ó,Ò4°÷	5÷ 	5ò 	5ûäò Ùðús+   ‚A �"<²	A ¼AÁA ÁA Á	AÁAc                 ó2   — t        j                  «       } | d›S )z9Best-effort stable MAC-derived value from uuid.getnode().Ú012x)ÚuuidÚgetnode)Únodes    r   Ú_primary_macr   $   s   € ä�<‰<‹>€DØ�4ˆ[Ðó    c                 ó  — t        d«      xs t        d«      xs dt        j                  «       t        «       g} t	        j
                  dj                  | «      j                  d«      «      j                  «       }d|dd › �S )	ab  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_Né    )	r   ÚsocketÚgethostnamer   ÚhashlibÚsha256ÚjoinÚencodeÚ	hexdigest)ÚpartsÚdigests     r   Úgenerate_fingerprintr,   *   sz   € ô 	Ð*Ó+ò 	ÜÐ6Ó7ò	àÜ×ÑÓÜ‹ð€Eô �^‰^˜CŸH™H U›O×2Ñ2°7Ó;Ó<×FÑFÓH€FØ�˜˜��ÐÐr   c                óN  — | j                   | j                  | j                  | j                  | j                  | j
                  | j                  | j                  fD ]  }|j                  dd¬«       Œ | j                  j                  dd¬«       t        | j                  d«       y)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Úsecrets_dirÚ_chmod)ÚconfigÚ	directorys     r   Úensure_dirsr?   =   s�   € ð 	�‰Ø�‰Ø�‰Ø�‰Ø×ÑØ�‰Ø×ÑØ×Ñð	ò 
5ˆ	ð 	�‰ ¨tˆÕ4ð
5ð ×Ñ×Ñ T°DÐÔ9Ü
ˆ6×Ñ˜uÕ%r   c                óR   — 	 | j                  |«       y # t        t        f$ r Y y w xY w©N)Úchmodr   ÚNotImplementedError)r   Úmodes     r   r<   r<   P   s+   € ðØ�
‰
�4ÕøÜÔ(Ð)ò Ùðús   ‚ ”&¥&c                ó¢  — | j                   }|j                  «       r	 |j                  «       S t	        j
                  «       }	 |j                  j                  dd¬«       t        |j                  d«       |j                  |«       t        |d«       |S # t        $ r Y Œrw xY w# t        $ r!}t        j                  d|«       Y d}~|S d}~ww xY w)zFRead the key from agent.key or generate a new one if it doesn't exist.Tr.   r1   é€  zFailed to persist agent.key: %sN)Úagent_key_fileÚis_fileÚ
read_bytesr   r   Úgenerate_keyÚparentr:   r<   Úwrite_bytesÚlogÚwarning)r=   Úkey_fileÚnew_keyÚexcs       r   Ú_get_fernet_keyrR   W   sÂ   € à×$Ñ$€HØ×ÑÔð	Ø×&Ñ&Ó(Ð(ô ×!Ñ!Ó#€Gð<Ø�‰×Ñ d°TÐÔ:Üˆx�‰ Ô&Ø×Ñ˜WÔ%Üˆx˜Ôð €Nøô ò 	Ùð	ûô ò <Ü�‰Ð5°s×;Ð;Ø€Nûð<ús*   žB ÁAB$ Â	B!Â B!Â$	CÂ-C	Ã	Cc                ó~  — |j                   j                  dd¬«       t        |j                   d«       || j                  k(  r|j	                  d«      }n6t        | «      }t        |«      }|j                  |j	                  d«      «      }|j                  |«       t        |d«       t        j                  d|«       y)zSWrite a secret, encrypted/sealed at rest with the agent key, with 0600 permissions.Tr.   r1   r   rF   zstored secret at %sN)rK   r:   r<   rG   r(   rR   r   ÚencryptrL   rM   Úinfo)r=   r   ÚvalueÚdataÚkeyÚfernets         r   Úwrite_secretrZ   k   s–   € à‡K�K×Ñ˜d¨TÐÔ2Ü
ˆ4�;‰;˜Ôð ˆv×$Ñ$Ò$Ø�|‰|˜GÓ$‰ä˜fÓ%ˆÜ˜“ˆØ�~‰~˜eŸl™l¨7Ó3Ó4ˆà×Ñ�TÔÜ
ˆ4�ÔÜ‡H�HÐ" DÕ)r   c                óv  — 	 |j                  «       }|sy || j                  k(  r|j                  d«      j                  «       S t	        | «      }t        |«      }	 |j                  |«      j                  d«      j                  «       S # t        $ r t        j                  d«       Y y w xY w# t        $ r Y y w xY w)Nr   zCStored secret could not be decrypted (invalid key or tampered file))rI   rG   Údecoder   rR   r   Údecryptr   rM   Úerrorr   )r=   r   rW   rX   rY   s        r   Úread_secretr_   }   s®   € ðØ�‰Ó ˆÙØð �6×(Ñ(Ò(Ø—;‘;˜wÓ'×-Ñ-Ó/Ð/ä˜fÓ%ˆÜ˜“ˆð	Ø—>‘> $Ó'×.Ñ.¨wÓ7×=Ñ=Ó?Ð?øÜò 	Ü�I‰IÐ[Ô\Ùð	ûô ò Ùðús:   ‚B, •-B, ÁB, Á-B ÂB)Â&B, Â(B)Â)B, Â,	B8Â7B8c                óö  — | j                   j                  j                  dd¬«       g }| j                   j                  «       r*| j                   j	                  d¬«      j                  «       }d}t        |«      D ]5  \  }}|j                  «       j                  |› d�«      sŒ)|› d|› �||<   d} n |s|j                  |› d|› �«       | j                   j                  dj                  |«      dz   d¬«       y)	z=Insert or update a KEY=VALUE line in agent.conf (idempotent).Tr.   r   r   Fú=ú
N)Ú	conf_filerK   r:   rH   Ú	read_textÚ
splitlinesÚ	enumerater   Ú
startswithÚappendÚ
write_textr'   )r=   rX   rV   ÚlinesÚreplacedÚindexÚlines          r   Úset_conf_valuern   ’   sð   € à
×Ñ×Ñ×!Ñ!¨$¸Ð!Ô>Ø€EØ×Ñ×ÑÔ!Ø× Ñ ×*Ñ*°GÐ*Ó<×GÑGÓIˆà€HÜ  Ó'ò ‰ˆˆtØ�:‰:‹<×"Ñ" c U¨! 9Õ-Ø!˜U ! E 7Ð+ˆE�%‰LØˆHÙð	ñ
 Ø�‰˜�u˜A˜e˜WÐ%Ô&à
×Ñ×Ñ §	¡	¨%Ó 0°4Ñ 7À'ÐÕJr   c                ó,   — t        | d|«       || _        y)z#Persist agent status in agent.conf.ÚWOLFPANEL_STATUSN)rn   Ústatus)r=   rq   s     r   Úsave_statusrr   ¥   s   € ä�6Ð-¨vÔ6Ø€F…Mr   c                ó8   — |xs d}t        | d|«       || _        y)z<Persist the latest heartbeat/registration error or clear it.r   ÚWOLFPANEL_LAST_ERRORN)rn   Ú
last_error)r=   r^   rV   s      r   Úsave_last_errorrv   «   s    € àŠK�R€EÜ�6Ð1°5Ô9Ø€FÕr   c                ó¨   — t        | d|«       t        | | j                  |«       t        | d«       t	        | d«       t
        j                  d|«       y)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Ú
registeredNz#credentials stored for server_id=%s)rn   rZ   Úagent_token_filerr   rv   rM   rU   )r=   Ú	server_idÚagent_tokens      r   Ústore_credentialsr}   ²   sF   € ô �6Ð0°)Ô<Ü�˜×0Ñ0°+Ô>Ü�˜Ô%Ü�F˜DÔ!Ü‡H�HÐ2°IÕ>r   c                ó.   — t        | | j                  «      S rA   )r_   rz   )r=   s    r   Úload_agent_tokenr   ¿   s   € Ü�v˜v×6Ñ6Ó7Ð7r   )r   ÚstrÚreturnú
str | None)r�   r€   )r=   r   r�   ÚNone)r   r   rD   Úintr�   rƒ   )r=   r   r�   Úbytes)r=   r   r   r   rV   r€   r�   rƒ   )r=   r   r   r   r�   r‚   )r=   r   rX   r€   rV   r€   r�   rƒ   )r=   r   rq   r€   r�   rƒ   )r=   r   r^   r‚   r�   rƒ   )r=   r   r{   r€   r|   r€   r�   rƒ   )r=   r   r�   r‚   )Ú__doc__Ú
__future__r   r%   r#   r   Úpathlibr   Úcryptography.fernetr   r   r=   r   Úloggerr   rM   r   r   r,   r?   r<   rR   rZ   r_   rn   rr   rv   r}   r   © r   r   ú<module>rŒ      sp   ðñ
õ #ã Û Û Ý ç 4å Ý á�Ó€óóóó&&ó&óó(*ó$ó*Kó&óó
?ô8r   