
    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 ^^CHHUO227;<FFHF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 TD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<dT:x&W%x N  		  <5s;;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    KKdT2
4;; v$$$||G$f%~~ell734T
4HH"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==?? 	II[\	  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::<""cU!9-!U!E7+E%LH	
 uAeW%&
		% 04 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FMr   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     KRE615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+>%FD!HH2I>r   c                .    t        | | j                        S rA   )r_   rz   )r=   s    r   load_agent_tokenr      s    vv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   