
    Vh                    z   d dl mZ d dlZd dlZd dlZd dlZd dlZd dlZd dlZd dl	Z	d dl
Z
d dlZd dlmZ d dlmZ d dlmZ dZdZ	  ej&                         5   ej(                  de       d dlmZ ddd       d d	lmZ d d
lmZmZ d dlmZ d dlm Z  d dl!m"Z#m$Z$m%Z%  e       ZdZd dl'm(Z(m)Z) d dl*m+Z, d dl-m.Z. d dl/m0Z0m1Z1m2Z2 d dl3m4Z4 d dl5m6Z6m7Z7  e4       Z8dZ9 e:d      Z; e:d      Z<dZ= G d de(      Z> G d de>      Z? G d de(      Z@d ZAd  eBe9      fdZCd>d ZDd?d!ZEd?d"ZFd# ZGd$ ZHd% ZId>d&ZJ G d' d(      ZK G d) d*eK      ZLd+ ZMd@d,ZN G d- d.eK      ZO G d/ d0eO      ZP G d1 d2eP      ZQd3 ZRd4 ZSd>d5ZTd>d6ZU G d7 d8      ZV G d9 d:      ZW G d; d<      ZXd=eXiZYy# 1 sw Y   5xY w# e&$ r Y w xY w)A    )annotationsN)hexlify)	unhexlify)ErrorFignore)InvalidSignature)default_backend)hashespadding)HMAC)
PBKDF2HMAC)Cipher
algorithmsmodesT)AnsibleErrorAnsibleAssertionError)	constants)binary_type)to_bytesto_text	to_native)Display)makedirs_safeunfrackpaths   $ANSIBLE_VAULT)AES256zDansible-vault requires the cryptography library in order to functionc                      e Zd Zy)AnsibleVaultErrorN__name__
__module____qualname__     N/home/dcms/DCMS/lib/python3.12/site-packages/ansible/parsing/vault/__init__.pyr   r   H       r#   r   c                      e Zd Zy)AnsibleVaultPasswordErrorNr   r"   r#   r$   r'   r'   L   r%   r#   r'   c                      e Zd Zy)AnsibleVaultFormatErrorNr   r"   r#   r$   r)   r)   P   r%   r#   r)   c                    	 t        t        | ddd      dd      }|j	                  t
              ryy# t        t        f$ r Y yw xY w)z Test if this is vault encrypted data blob

    :arg data: a byte or text string to test whether it is recognized as vault
        encrypted data
    :returns: True if it is recognized.  Otherwise, False.
    asciistrict)encodingerrors	nonstring)r-   r.   FT)r   r   UnicodeError	TypeError
startswithb_HEADER)datab_datas     r$   is_encryptedr6   T   s]     '$U]^ip  zB  C " )$  	s   4 AAc                    | j                         }	 | j                  |       t        | j                  |            | j                  |       S # | j                  |       w xY w)a  Test if the contents of a file obj are a vault encrypted data blob.

    :arg file_obj: A file object that will be read from.
    :kwarg start_pos: A byte offset in the file to start reading the header
        from.  Defaults to 0, the beginning of the file.
    :kwarg count: Read up to this number of bytes from the file to determine
        if it looks like encrypted vault data. The default is the size of the
        the vault header, which is what is needed most times.
        For some IO classes, or files that don't begin with the vault itself,
        set to -1 to read to the end of file.
    :returns: True if the file looks like a vault file. Otherwise, False.
    )tellseekr6   read)file_obj	start_poscountcurrent_positions       r$   is_encrypted_filer?   j   sO      }}(i HMM%01 	&'&'s   *A A!c                P   | j                         }|d   j                         j                  d      }|d   j                         }t        |d   j                               }|}t	        |      dk\  rt        |d   j                               }dj                  |dd        }||||fS )Nr      ;            r#   )
splitlinesstripsplitr   lenjoin)b_vaulttext_envelopedefault_vault_id	b_tmpdatab_tmpheader	b_versioncipher_namevault_idb_ciphertexts           r$   _parse_vaulttext_enveloperS      s    $//1IA,$$&,,T2KA$$&I+a...01KH ;1;q>//1288IabM*LK99r#   c                    |xs t         j                  }	 t        | |      S # t        $ r$}d}|r|d|z  z  }|d|z  z  }t	        |      d}~ww xY w)a  Parse the vaulttext envelope

    When data is saved, it has a header prepended and is formatted into 80
    character lines.  This method extracts the information from the header
    and then removes the header and the inserted newlines.  The string returned
    is suitable for processing by the Cipher classes.

    :arg b_vaulttext: byte str containing the data from a save file
    :kwarg default_vault_id: The vault_id name to use if the vaulttext does not provide one.
    :kwarg filename: The filename that the data came from.  This is only
        used to make better error messages in case the data cannot be
        decrypted. This is optional.
    :returns: A tuple of byte str of the vaulttext suitable to pass to parse_vaultext,
        a byte str of the vault format version,
        the name of the cipher used, and the vault_id.
    :raises: AnsibleVaultFormatError: if the vaulttext_envelope format is invalid
    zVault envelope format error in %s: %sN)CDEFAULT_VAULT_IDENTITYrS   	Exceptionr)   )rK   rL   filenameexcmsgs        r$   parse_vaulttext_enveloper]      si    & (C1+C+C+()=?OPP ++8x((Cv|%c**+s   " 	AA

Ac                   |st        d      |xs d}|r|dk7  rd}t        |dd      }t        |dd      }t        |dd      }t        ||g}|dk(  r|r|j                  |       d	j	                  |      }|g}	|	t        d
t        |       d      D 
cg c]
  }
| |
|
dz     c}
z  }	|	dgz  }	dj	                  |	      }	|	S c c}
w )a   Add header and format to 80 columns

        :arg b_ciphertext: the encrypted and hexlified data as a byte string
        :arg cipher_name: unicode cipher name (for ex, u'AES256')
        :arg version: unicode vault version (for ex, '1.2'). Optional ('1.1' is default)
        :arg vault_id: unicode vault identifier. If provided, the version will be bumped to 1.2.
        :returns: a byte str that should be dumped into a file.  It's
            formatted to 80 char columns and has the header prepended
    z-the cipher must be set before adding a headerz1.1defaultz1.2utf-8r,   r.      1.2rA   r   P   r#      
)r   r   r3   appendrJ   rangerI   )rR   rP   versionrQ   rO   
b_vault_idb_cipher_nameheader_partsheaderb_vaulttextis              r$   format_vaulttext_envelopern      s     JKKG H
*'(;I(GH=J['(CM!#L FzJ'YY|$F(KE!S=NPR4STqL1r6*TTKC5K**[)K	 Us   Cc                d    	 t        |       S # t        t        f$ r}t        d|z        d }~ww xY w)Nz Vault format unhexlify error: %s)r   BinasciiErrorr1   r)   )r5   r[   s     r$   
_unhexlifyrq      s;    P  9% P%&H3&NOOPs   
 /*/c                z    t        |       } | j                  dd      \  }}}t        |      }t        |      }|||fS )Nrd   rC   )rq   rH   )rl   b_saltb_crypted_hmacrR   s       r$   _parse_vaulttextru      sF    [)K+6+<+<UA+F(FNLFl+L//r#   c                n    	 t        |       S # t        $ r  t        $ r}d|z  }t        |      d}~ww xY w)aw  Parse the vaulttext

    :arg b_vaulttext: byte str containing the vaulttext (ciphertext, salt, crypted_hmac)
    :returns: A tuple of byte str of the ciphertext suitable for passing to a
        Cipher class's decrypt() function, a byte str of the salt,
        and a byte str of the crypted_hmac
    :raises: AnsibleVaultFormatError: if the vaulttext format is invalid
    z Vault vaulttext format error: %sN)ru   r)   rY   )rl   r[   r\   s      r$   parse_vaulttextrw      sB    +,,"  +036%c**+s   
 4/4c                *    |xs d}| st        |      y)zCheck the secret against minimal requirements.

    Raises: AnsibleVaultPasswordError if the password does not meet requirements.

    Currently, only requirement is that the password is not None or an empty string.
    z#Invalid vault password was providedN)r'   )secretr\   s     r$   verify_secret_is_not_emptyrz      s"     
66C',, r#   c                  .    e Zd ZdZddZed        Zd Zy)VaultSecretzKOpaque/abstract objects for a single vault secret. ie, a password or a key.Nc                    || _         y N_bytes)selfr   s     r$   __init__zVaultSecret.__init__  s	    r#   c                    | j                   S )zThe secret as a bytestring.

        Sub classes that store text types will need to override to encode the text to bytes.
        r   r   s    r$   byteszVaultSecret.bytes  s     {{r#   c                    | j                   S r~   r   r   s    r$   loadzVaultSecret.load  s    {{r#   r~   )r   r    r!   __doc__r   propertyr   r   r"   r#   r$   r|   r|     s#    U  r#   r|   c                  H     e Zd ZdgZd fd	Zed        Zd Zd Zd Z	 xZ
S )PromptVaultSecretzVault password (%s): c                r    t         t        |   |       || _        || j                  | _        y || _        y )Nr   )superr   r   rQ   default_prompt_formatsprompt_formats)r   r   rQ   r   	__class__s       r$   r   zPromptVaultSecret.__init__!  s9    /v/> !"&"="=D"0Dr#   c                    | j                   S r~   r   r   s    r$   r   zPromptVaultSecret.bytes*  s    {{r#   c                .    | j                         | _        y r~   )ask_vault_passwordsr   r   s    r$   r   zPromptVaultSecret.load.  s    ..0r#   c                |   g }| j                   D ]c  }|d| j                  iz  }	 t        j                  |d      }t        |       t        |dd      j                         }|j                  |       e |D ]  }| j                  |d   |        |r|d   S y # t        $ r t        d| j                  z        w xY w)	NrQ   T)privatez$EOFError (ctrl-d) on prompt for (%s)r,   
simplerepr)r.   r/   r   )r   rQ   displaypromptEOFErrorr   rz   r   rG   re   confirm)r   b_vault_passwordsprompt_formatr   
vault_passb_vault_passb_vault_passwords          r$   r   z%PromptVaultSecret.ask_vault_passwords1  s    !00 
	3M"j$--%@@F`$^^FD^A
 'z2#Jx<X^^`L$$\2
	3 !2 	ALL*1-/?@	A $Q''  `'(NQUQ^Q^(^__`s   B"B;c                $    ||k7  rt        d      y )NzPasswords do not match)r   )r   b_vault_pass_1b_vault_pass_2s      r$   r   zPromptVaultSecret.confirmI  s     ^+788 ,r#   NNN)r   r    r!   r   r   r   r   r   r   r   __classcell__r   s   @r$   r   r     s4    561  109r#   r   c                l    t         j                  j                  |       \  }}|j                  d      ryy)zWDetermine if a vault secret script is a client script that can be given --vault-id argsz-clientTF)ospathsplitextendswith)rZ   script_namedummys      r$   script_is_clientr   Q  s3    
 ))(3K I&r#   c                   t        | d      }t        j                  j                  |      st	        d|z        t        j                  j                  |      rt	        d| d      |j                  |      rIt        |       r0t        j                  dt        |      z         t        ||||      S t        |||      S t        |||      S )	zI Get secret from file content or execute file and get secret from stdout F)followz(The vault password file %s was not foundz"The vault password file provided 'z' can not be a directoryz.The vault password file %s is a client script.)rZ   rQ   r-   loaderrZ   r-   r   )r   r   r   existsr   isdiris_executabler   r   vvvvr   ClientScriptVaultSecretScriptVaultSecretFileVaultSecret)rZ   rQ   r-   r   	this_paths        r$   get_file_vault_secretr   _  s     HU3I77>>)$E	QRR	ww}}Y?	{Jbcdd I&H%LLJWU^M__`*I[clrss !)hvVVIPPr#   c                  B     e Zd Zd fd	Zed        Zd Zd Zd Z xZ	S )r   c                x    t         t        |           || _        || _        |xs d| _        d | _        d | _        y )Nutf8)r   r   r   rZ   r   r-   r   _text)r   rZ   r-   r   r   s       r$   r   zFileVaultSecret.__init__~  s:    ot-/  *F 
r#   c                    | j                   r| j                   S | j                  r%| j                  j                  | j                        S y r~   )r   r   encoder-   r   s    r$   r   zFileVaultSecret.bytes  s6    ;;;;::::$$T]]33r#   c                D    | j                  | j                        | _        y r~   )
_read_filerZ   r   r   s    r$   r   zFileVaultSecret.load  s    oodmm4r#   c                V   	 t        |d      5 }|j                         j                         }ddd       | j                  j                  |      \  }}|j                  d      }t        |d|z         |S # 1 sw Y   KxY w# t        t        f$ r}t        d|d|      d}~ww xY w)z
        Read a vault password from a file or if executable, execute the script and
        retrieve password from STDOUT
        rbNz#Could not read vault password file :    
z2Invalid vault password was provided from file (%s)r\   )	openr:   rG   OSErrorIOErrorr   r   _decrypt_if_vault_datarz   )r   rZ   fr   eb_vault_datar   s          r$   r   zFileVaultSecret._read_file  s    	\h% .VVX^^-
.
 #kk@@XVe!''0
":'[^f'f	h . .! 	\hXYZ[[	\s-   B A7B 7B <B B(B##B(c                    | j                   r&| j                  j                  d| j                   dS d| j                  j                  z  S )N(filename='')%s())rZ   r   r   r   s    r$   __repr__zFileVaultSecret.__repr__  s7    ==*...*A*A4==QQ0011r#   r   )
r   r    r!   r   r   r   r   r   r   r   r   s   @r$   r   r   }  s+    	  5,2r#   r   c                  $    e Zd Zd Zd Zd Zd Zy)r   c                   | j                   j                  |      st        d|z        | j                         }| j	                  |      \  }}}| j                  |||       |j                  d      }d|z  }t        ||       |S )Nz/The vault password script %s was not executabler   z4Invalid vault password was provided from script (%s)r   )r   r   r   _build_command_run_check_resultsrG   rz   )r   rZ   commandstdoutstderrpr   empty_password_msgs           r$   r   zScriptVaultSecret._read_file  s    {{((2#$UX`$`aa%%' IIg.FFA.\\'*
SV^^":3EFr#   c                    	 t        j                  |t         j                        }|j                         \  }}|||fS # t        $ r#}d}|| j                  |fz  }t        |      d }~ww xY w)N)r   zpProblem running vault password script %s (%s). If this is not a script, remove the executable bit from the file.
subprocessPopenPIPEr   rZ   r   communicater   r   r   r   
msg_formatr\   r   r   s           r$   r   zScriptVaultSecret._run  ss    	$  AA vq    	$UJq11Cs##	$s   %? 	A+A&&A+c                r    |j                   dk7  r(t        d| j                  d|j                   d|      y )Nr   zVault password script  returned non-zero (): )
returncoder   rZ   r   r   r   popens       r$   r   z ScriptVaultSecret._check_results  s;    q  $u/?/? I J J !r#   c                    | j                   gS r~   rZ   r   s    r$   r   z ScriptVaultSecret._build_command  s    r#   N)r   r    r!   r   r   r   r   r"   r#   r$   r   r     s    "!J
r#   r   c                  <     e Zd ZdZd fd	Zd Zd Zd Zd Z xZ	S )r   rC   c                    t         t        |   |||       || _        t        j                  dt        |      dt        |             y )Nr   z(Executing vault password client script: z --vault-id )r   r   r   	_vault_idr   r   r   )r   rZ   r-   r   rQ   r   s        r$   r   z ClientScriptVaultSecret.__init__  sI    %t5x?G=C 	6 	E "T[\dTegnowgxyzr#   c                    	 t        j                  |t         j                  t         j                        }|j                         \  }}|||fS # t        $ r#}d}|| j                  |fz  }t        |      d }~ww xY w)N)r   r   zwProblem running vault password client script %s (%s). If this is not a script, remove the executable bit from the file.r   r   s           r$   r   zClientScriptVaultSecret._run  s}    		$  (2(29A vq    	$UJq11Cs##	$s   4A 	A:A55A:c           
        |j                   | j                  k(  r(t        d| j                  d| j                  d|      |j                   dk7  r5t        d| j                  d|j                   d| j                  d|      y )NzVault password client script z$ did not find a secret for vault-id=r   r   r   z#) when getting secret for vault-id=)r   VAULT_ID_UNKNOWN_RCr   rZ   r   r   s       r$   r   z&ClientScriptVaultSecret._check_results  s|    t777 $t~~v G H H q  $u/?/?QW Y Z Z !r#   c                r    | j                   g}| j                  r|j                  d| j                  g       |S )Nz
--vault-id)rZ   r   extend)r   r   s     r$   r   z&ClientScriptVaultSecret._build_command  s.    ==/>>NNL$..9:r#   c                    | j                   r3| j                  j                  d| j                   d| j                  dS d| j                  j                  z  S )Nr   z', vault_id='r   r   )rZ   r   r   r   r   s    r$   r   z ClientScriptVaultSecret.__repr__  sC    ==(($--I I0011r#   NNNN)
r   r    r!   r   r   r   r   r   r   r   r   s   @r$   r   r     s$    {!Z2r#   r   c                P    | sg S | D cg c]  \  }}||v s||f }}}|S c c}}w )zVFind all VaultSecret objects that are mapped to any of the target_vault_ids in secretsr"   )secretstarget_vault_idsrQ   ry   matchess        r$   match_secretsr   	  s:    	:Ab&6hXQaEa&!bGbN cs   ""c                *    t        | |      }|r|d   S y)zFind the best secret from secrets that matches target_vault_ids

    Since secrets should be ordered so the early secrets are 'better' than later ones, this
    just finds all the matches, then returns the first secretr   N)r   )r   r   r   s      r$   match_best_secretr     s!    
 G%56Gqzr#   c                    t         j                  dt        |      z         |t        d      |g}t	        | |      }|r|S t        d|d| D cg c]  \  }}|	 c}}      c c}}w )Nencrypt_vault_id=%szBmatch_encrypt_vault_id_secret requires a non None encrypt_vault_idz,Did not find a match for --encrypt-vault-id=z in the known vault-ids )r   r   r   r   r   r   )r   encrypt_vault_idencrypt_vault_id_matchersencrypt_secret_v_vss         r$   match_encrypt_vault_id_secretr    s    LL''2B*CCD_``!1 2&w0IJN  jz ~E  kFryrtvykm  kFG H H kFs   A&c                    t         j                  dt        |      z         |rt        | |      S | D cg c]  \  }}|	 }}}t	        | |      }|S c c}}w )z@Find the best/first/only secret in secrets to use for encryptingr   )r  )r   r   r   r  r   )r   r  r   r   _vault_id_matchersbest_secrets         r$   match_encrypt_secretr
  2  sj     LL''2B*CCD,W>NP 	P
 =DD(8	5)DD#G-?@K 	 Es   Ac                  <    e Zd ZddZed        ZddZd	dZd	dZy)
VaultLibNc                6    |xs g | _         d | _        d| _        y )Nrb   )r   rP   rO   )r   r   s     r$   r   zVaultLib.__init__E  s    }"r#   c                    t        |       S r~   )r6   )	vaulttexts    r$   r6   zVaultLib.is_encryptedJ  s    I&&r#   c                   |0| j                   rt        | j                         \  }}nt        d      t        |d      }t	        |      rt        d      | j                  r| j                  t        vrd| _        	 t        | j                            }|r.t        j                  dt        |      dt        |             n!t        j                  d	t        |      z         |j                  |||      }t        || j                  |
      }	|	S # t        $ r% t        dj                  | j                              w xY w)a  Vault encrypt a piece of data.

        :arg plaintext: a text or byte string to encrypt.
        :returns: a utf-8 encoded byte str of encrypted data.  The string
            contains a header identifying this as vault encrypted data and
            formatted to newline terminated lines of 80 characters.  This is
            suitable for dumping as is to a vault file.

        If the string passed in is a text string, it will be encoded to UTF-8
        before encryption.
        z2A vault password must be specified to encrypt datasurrogate_or_strictra   zinput is already encryptedr   {0} cipher could not be foundzEncrypting with vault_id "" and vault secret z3Encrypting without a vault_id using vault secret %srQ   )r   r
  r   r   r6   r   rP   CIPHER_WRITE_ALLOWLISTCIPHER_MAPPINGKeyErrorformatr   vvvvvr   encryptrn   )
r   	plaintextry   rQ   saltr   b_plaintextthis_cipherrR   rl   s
             r$   r  zVaultLib.encryptN  s+    >|| 4T\\ Bv'(\]]y1FG$;<<4#3#3;Q#Q(D	Z()9)9:<K
 MMRYZbRcelmsetuvMMPSZ[aSbbc"**;E 0040@0@9AC   	Z?FFtGWGWXYY	Zs   <D .D?c                6    | j                  |||      \  }}}|S )a  Decrypt a piece of vault encrypted data.

        :arg vaulttext: a string to decrypt.  Since vault encrypted data is an
            ascii text format this can be either a byte str or unicode string.
        :kwarg filename: a filename that the data came from.  This is only
            used to make better error messages in case the data cannot be
            decrypted.
        :returns: a byte string containing the decrypted data and the vault-id that was used

        )rZ   obj)decrypt_and_get_vault_id)r   r  rZ   r   r  rQ   vault_secrets          r$   decryptzVaultLib.decrypt|  s*     -1,I,I)^flo,I,p)	8\r#   c                   t        |dd      }| j                   d}|r|dt        |      z  z  }t        |      t	        |      s d}|r|dt        |      z  z  }t        |      t        ||	      \  }}}}|t        v rt        |          }	nt        d
j                  |            d}
| j                  st        d      g }d}d}|rt        j                  dt        |      z         |j                  |       t        | j                  |      }|r.t        j                  dt        |      dt        |             n!t        j                  dt        |      z         t        j                   s4|j#                  | j                  D cg c]  \  }}||k7  s| c}}       t        | j                  |      }|D ]  \  }}t        j                  dt        |      dt        |      dt        |             	 t        j%                  dt        |      dt        |             |	j'                  ||      }
|
H|}|}d}|rd|z  }t        j                  dt        |      dt        |      dt        |              n" d"}|r|d#t        |      z  z  }t        |      |
 d$}|r|d#t        |      z  z  }t        |      |
||fS c c}}w # t(        $ rJ}||_        d}|r|dt        |      z  z  }|dt        |      z  z  }t        j-                  |d        d}~wt
        $ r;}t        j%                  dt        |      d t        |      d!|       Y d}~d}~ww xY w)%a  Decrypt a piece of vault encrypted data.

        :arg vaulttext: a string to decrypt.  Since vault encrypted data is an
            ascii text format this can be either a byte str or unicode string.
        :kwarg filename: a filename that the data came from.  This is only
            used to make better error messages in case the data cannot be
            decrypted.
        :returns: a byte string containing the decrypted data and the vault-id vault-secret that was used

        r,   r`   )r.   r-   Nz2A vault password must be specified to decrypt dataz in file %sz#input is not vault encrypted data. z %s is not a vault encrypted filer   r  z0Attempting to decrypt but no vault secrets foundz&Found a vault_id (%s) in the vaulttextz+We have a secret associated with vault id (z), will try to use to decrypt z\Found a vault_id (%s) in the vault text, but we do not have a associated secret (--vault-id)zTrying to use vault secret=(z) id=z to decrypt zTrying secret z for vault_id= z of "%s"Decryptz successful with secret=z and vault_id=zThere was a vault format errorrU   rV   T)	formattedzTried to use the vault secret (z) to decrypt (z) but it failed. Error: zBDecryption failed (no vault secrets were found that could decrypt)z on %szDecryption failed)r   r   r   r   r6   r   r]   CIPHER_ALLOWLISTr  r  r   r  r   re   r   rW   DEFAULT_VAULT_ID_MATCHr   r   r#  r)   r   warning)r   r  rZ   r   rl   r\   r   rP   rQ   r  r  vault_id_matchersvault_id_usedvault_secret_used_matchesr   _dummymatched_secretsvault_secret_idr"  	file_slugr[   r   s                          r$   r!  z!VaultLib.decrypt_and_get_vault_id  s    yGL<<FC}y':::#C((K(7C9Ih<OOOs##4L[ck4l1UK **(57K>EEkRSS||#$VWW  MMCghFWWX$$X.$T\\3DEHry  {C  sD  FM  NV  FW  X  Y}  AH  IQ  AR  R  S ''$$%o4EIvYbfnYni%op'6GH .= !	))O\MMT[\hTikr  tC  lD  FM  NV  FW  X  YGLDY[bcr[stu)11+|L*$3M(4% "I$.$9	MMRYZcRdfmnzf{  ~E  FU  ~V  W  +!	)< WCx)H"555#C((%Cx)H"555s##M+<<<] &p, + 79(9::Cw--t4 %o68I1N Os2   K
K
>BK	M+AL$$M+00M&&M+r~   r   NN)	r   r    r!   r   staticmethodr6   r  r#  r!  r"   r#   r$   r  r  D  s,     
 ' ',\p=r#   r  c                  |    e Zd ZddZd Zd ZddZd ZddZddZ	dd	Z
dd
Zd Zd ZddZd ZddZd Zd Zy)VaultEditorNc                *    |xs
 t               | _        y r~   )r  vault)r   r8  s     r$   r   zVaultEditor.__init__  s    (hj
r#   c                *   t         j                  j                  |      }|dkD  rt        d|      }d}t	        |d      5 }t        |      D ]  }|j                  dd       t        j                  |dz  |      }t        j                  |      }t        d||z        D ]  }|j                  |        |j                  |d||z          |j                         |k7  r
t               t        j                  |        	 ddd       yy# 1 sw Y   yxY w)ar  "Destroy a file, when shred (core-utils) is not available

        Unix `shred' destroys files "so that they can be recovered only with great difficulty with
        specialised hardware, if at all". It is based on the method from the paper
        "Secure Deletion of Data from Magnetic and Solid-State Memory",
        Proceedings of the Sixth USENIX Security Symposium (San Jose, California, July 22-25, 1996).

        We do not go to that length to re-implement shred in Python; instead, overwriting with a block
        of random data should suffice.

        See https://github.com/ansible/ansible/pull/13700 .
        r   i    rE   wbrC   N)r   r   getsizeminr   rf   r9   randomrandinturandomwriter8   r   fsync)	r   tmp_pathfile_lenmax_chunk_lenpassesfhr   	chunk_lenr4   s	            r$   _shred_file_customzVaultEditor._shred_file_custom  s     77??8,a<:MFh% !"6] !EGGAqM &}/A= QI::i0D!&q(i*?!@ ''HHT"78i#789 wwyH,355HHRL!! !	 ! !s   B?D		Dc                    t         j                  j                  |      sy	 t        j                  d|g      }|dk7  r| j                  |       t        j                  |       y# t
        t        f$ r d}Y ?w xY w)aj  Securely destroy a decrypted file

        Note standard limitations of GNU shred apply (For flash, overwriting would have no effect
        due to wear leveling; for other storage systems, the async kernel->filesystem->disk calls never
        guarantee data hits the disk; etc). Furthermore, if your tmp dirs is on tmpfs (ramdisks),
        it is a non-issue.

        Nevertheless, some form of overwriting the data (instead of just removing the fs index entry) is
        a good idea. If shred is not available (e.g. on windows, or no core-utils installed), fall back on
        a custom shredding method.
        NshredrB   r   )	r   r   isfiler   callr   
ValueErrorrH  remove)r   rB  rs      r$   _shred_filezVaultEditor._shred_file)  so     ww~~h'	( 34A 6##H-
		( $ 	 A	s   A% %A98A9c           
        t         j                  j                  t         j                  j                  |            \  }}t	        j
                  |t        j                        \  }}	| j                  |	      }
	 |r| j                  ||d       t        j                  |       	 t        j                  |
       | j%                  |	      }|s||k7  r|| j&                  j)                  |||      }| j                  ||	       | j+                  |	|       t,        j/                  dt1        |      d	t1        |      d
t1        |      d       | j                  |	       y # t        $ r | j                  |	        w xY w# t        j                  |       w xY w# t        $ r?}| j                  |	       t        ddj!                  |
      dt#        |            d }~ww xY w)N)suffixdirFrJ  zUnable to execute the command " z": r  zSaved edited file "z" encrypted using z and  vault id "")r   r   r   realpathtempfilemkstemprW   DEFAULT_LOCAL_TMP_editor_shell_command
write_datarY   rP  closer   rL  r   rJ   r   	read_datar8  r  shuffle_filesr   r  r   )r   rZ   ry   existing_data
force_saverQ   rootextfdrB  cmdr   rM   rR   s                 r$   _edit_file_helperzVaultEditor._edit_file_helperJ  s    GG$$RWW%5%5h%?@	c''s8K8KLH((2	r? HHRL	iOOC  NN8,	 )3
  ::--i(-SLOOL(3 x2MM]dem]npwx~p  BI  JR  BS  T  U 	"?  	X&	
 HHRL
  	iX&388TW=ZcdeZfghh	is0   :E! &F !E==F   F	G"#:GG"c                R    |dk(  r|S t         j                  j                  |      }|S )N-)r   r   rW  )r   rZ   	real_paths      r$   
_real_pathzVaultEditor._real_pathu  s(    s?OGG$$X.	r#   c                B    | j                   j                  |||      }|S Nr  )r8  r  )r   r  ry   rQ   rR   s        r$   encrypt_byteszVaultEditor.encrypt_bytes}  s#    zz))+v)Qr#   c                    | j                  |      }| j                  |      }| j                  j                  |||      }| j	                  ||xs |       y rl  )rj  r^  r8  r  r\  )r   rZ   ry   rQ   output_filer  rR   s          r$   encrypt_filezVaultEditor.encrypt_file  sN     ??8,nnX.zz))+v)Qk&=X>r#   c                   | j                  |      }| j                  |      }	 | j                  j                  ||      }| j                  ||xs |d       y # t        $ r'}t	        t        |      dt        |            d }~ww xY w)Nr    for FrT  )rj  r^  r8  r#  r   r   r\  )r   rZ   ro  
ciphertextr  r   s         r$   decrypt_filezVaultEditor.decrypt_file  s     ??8,^^H-
	R

**:*II 		;#:(%H  	RilIh<OPQQ	Rs   A 	B
#"BB
c                ^   t         j                  j                  |      }|rKt         j                  j                  |      s,t        j                  dt        |      z         t        |       t         j                  j                  |      rt        d|z        | j                  |||       y)z create a new encrypted file z%s does not exist, creating...z$%s exists, please use 'edit' insteadr  N)r   r   dirnamer   r   r*  r   r   rK  r   rf  )r   rZ   ry   rQ   rv  s        r$   create_filezVaultEditor.create_file  s     ''//(+277>>'2OO=@PPQ'" 77>>(#EPQQx(Cr#   c                l   d }d }| j                  |      }| j                  |      }t        |      }	 | j                  j	                  |      \  }}}t        ||      \  }}}	}
|	t        v}| j                  |||||
       y # t
        $ r'}t        t        |      dt        |            d }~ww xY w)Nrr  r   )r`  ra  rQ   )
rj  r^  r   r8  r!  r   r   r]   r  rf  )r   rZ   r,  r-  rl   r  r  r   r   rP   rQ   ra  s               r$   	edit_filezVaultEditor.edit_file  s     ??8,nnX. K(		R ;?**:]:]^g:h7I}&7 /G{]e.f+uk8 ")??
 	x):)`ju}~  	RilIh<OPQQ	Rs   B 	B3"B..B3c                    | j                  |      }t        |      }	 | j                  j                  ||      }|S # t        $ r'}t        t        |      dt        |            d }~ww xY w)Nr   rr  )r^  r   r8  r#  r   r   r   )r   rZ   rl   r  r  r   s         r$   r  zVaultEditor.plaintext  sj    nnX.K(		W

**9x*HI 	W#9Q<8AT$UVV	Ws   = 	A-"A((A-c                D   | j                  |      }t        j                  |      }| j                  |      }t	        |      }t
        j                  dt	        |      dt	        |      dt	        |             	 | j                  j                  |      \  }}}	|t        d|z        t        i       }|j                  |||      }| j                  ||       t        j                  ||j                         t        j                   ||j"                  |j$                         t
        j                  dt	        |      d	t	        |      d
t	        |      dt	        |             y # t        $ r'}
t        t        |
      dt        |            d }
~
ww xY w)NzRekeying file "z" to with new vault-id "r  rr  z<The value for the new_password to rekey %s with is not valid)r   r  zRekeyed file "z" (decrypted with vault id "z$") was encrypted with new vault-id ")rj  r   statr^  r   r   r  r8  r!  r   r   r  r  r\  chmodst_modechownst_uidst_gid)r   rZ   new_vault_secretnew_vault_idprevrl   r  r  r,  r/  r   	new_vaultb_new_vaulttexts                r$   
rekey_filezVaultEditor.rekey_file  s\    ??8,wwx nnX.K(	x(',*?IYAZ\ 	]	R/3zz/R/RS\/],I}f
 #]`hhii R(	#++I7GR^+_2 	4<<(
4;;4x('-*@',BWY`aqYrt 	u1  	RilIh<OPQQ	Rs   =E/ /	F8"FFc                P   	 |dk(  r*t         j                  j                  j                         }|S t	        |d      5 }|j                         }d d d        |S # 1 sw Y   S xY w# t
        $ r7}t        |      }|st        |      }t        dt        |      d|      d }~ww xY w)Nrh  r   zUnable to read source file (r   )	sysstdinbufferr:   r   rY   r   reprr   )r   rZ   r4   rF  r   r\   s         r$   r^  zVaultEditor.read_data  s    
	c3yy'',,.  (D) %R779D% %   	cA,C1g	RZH[]`abb		cs9   -A% A% AA% A"A% "A% %	B%.2B  B%c                   t        |d      }d}	 t        |t              xr' t        j                  |t        j                        dk7  }|r-t        j                  |d       t        j                  ||       y|dk(  r;t        t        j                  dt        j                        }|j                  |       yt        j                  t        j                  j                  |      t        j                        s+t!        dt        j                  j                  |      z        t        j                  j#                  |      r)|r| j%                  |       nt        j&                  |       t        j(                  d	      }	 	 t        j*                  |t        j,                  t        j.                  z  t        j0                  z  t        j2                  z  |      }		 t        j                  |	d       t        j                  |	|       	 t        j<                  |	       	 t        j(                  |       y# t
        $ r Y w xY w# t4        $ rP}
|
j6                  t6        j8                  k(  rt!        d
t;        |
      z        t!        dt;        |
      z        d}
~
ww xY w# t4        $ r}t!        dt;        |      z        d}~ww xY w# t        j<                  |	       w xY w# t        j(                  |       w xY w)a  Write the data bytes to given path

        This is used to write a byte string to a file or stdout. It is used for
        writing the results of vault encryption or decryption. It is used for
        saving the ciphertext after encryption and it is also used for saving the
        plaintext after decrypting a vault. The type of the 'data' arg should be bytes,
        since in the plaintext case, the original contents can be of any text encoding
        or arbitrary binary data.

        When used to write the result of vault encryption, the value of the 'data' arg
        should be a utf-8 encoded byte string and not a text type.

        When used to write the result of vault decryption, the value of the 'data' arg
        should be a byte string and not a text type.

        :arg data: the byte string (bytes) data
        :arg thefile: file descriptor or filename to save 'data' to.
        :arg shred: if shred==True, make sure that the original data is first shredded so that is cannot be recovered.
        :returns: None
        r,   ra   Fr   rh  r  zDestination '%s' not writable?   z:Vault file got recreated while we were operating on it: %sz)Problem creating temporary vault file: %sNz+Unable to write to temporary vault file: %s)r   
isinstanceintfcntlF_GETFDrY   r   	ftruncater@  getattrr  r   accessr   rv  W_OKr   rK  rP  rN  umaskr   O_CREATO_EXCLO_RDWRO_TRUNCr   errnoEEXISTr   r]  )r   r4   thefilerJ  modeb_file_datais_fdoutputcurrent_umaskrd  oser   s               r$   r\  zVaultEditor.write_data  s1   . tH5 	-[%++gu}}2UY[2[E  LL!$HHWk*^ SZZ3::>FLL%99RWW__W5rww?"#BbggooV]F^#_``ww~~g&$$W-IIg& HHUOM(	e"**ryy*@299*Lrzz*Y[_`B!LLQ'HHR-
 HHRL'a  		<  e yyELL0*+gjstwjx+xyy&'RU^_bUc'cdde  e&'TW`abWc'cdde HHRL'sg   9H6 AI ,J" 
K$ 6	II	JAJJK$ "	K+KKK
 
K!!K$ $K;c                b   d }t         j                  j                  |      r*t        j                  |      }t        j                  |       t        j                  ||       |Lt        j                  ||j                         t        j                  ||j                  |j                         y y r~   )r   r   rK  r|  rN  shutilmover}  r~  r  r  r  )r   srcdestr  s       r$   r_  zVaultEditor.shuffle_files^  st    77>>$774=DIIdOC HHT4<<(HHT4;;4 r#   c                    t         j                  j                  d      }t        j                  |      }|j                  |       |S )NEDITOR)rW   configget_config_valueshlexrH   re   )r   rZ   
env_editoreditors       r$   r[  z!VaultEditor._editor_shell_commandm  s5    XX..x8
Z(hr#   r~   )NFNr3  )Ti  )r   r    r!   r   rH  rP  rf  rj  rm  rp  rt  rw  ry  r  r  r^  r\  r_  r[  r"   r#   r$   r6  r6    s^    )
#!JB)#V
?ID@	W&uP M(^5r#   r6  c                      e Zd ZdZd Zed        Zed        Zed        Z	ed        Z
edd       Zed	        Zed
        Zed        Zy)VaultAES256zw
    Vault implementation using AES-CTR with an HMAC-SHA256 authentication code.
    Keys are derived using PBKDF2
    c                .    t         st        t              y r~   )HAS_CRYPTOGRAPHYr   NEED_CRYPTO_LIBRARYr   s    r$   r   zVaultAES256.__init__  s    233  r#   c                    t        t        j                         d|z  |z   |dt              }|j	                  |       }|S )NrC   i'  )	algorithmlengthr  
iterationsbackend)r   r
   SHA256CRYPTOGRAPHY_BACKENDderive)
b_passwordrs   
key_length	iv_lengthkdfb_derivedkeys         r$   _create_key_cryptographyz$VaultAES256._create_key_cryptography  s@    mmoz>I-(* zz*-r#   c                    d}t         r@t        j                  j                  dz  }| j	                  ||||      }||dz  |dz  |z    }nt        t        dz         |d | }|||dz   }|||fS )N       rC   z(Detected in initctr))r  r   AES
block_sizer  r   r  )	clsr  rs   r  r  r  b_ivb_key1b_key2s	            r$   _gen_key_initctrzVaultAES256._gen_key_initctr  s     
"11Q6I77
FJXabLa*q.I1MND25LLMMkz*j*q.:vt##r#   c                X   t        t        j                  |      t        j                  |      t
              }|j                         }t        j                  t        j                  j                        j                         }|j                  |j                  |       |j                         z         }||j                         z  }t        |t        j                         t
              }|j                  |       |j                         }	t!        t#        |	      d      t#        |      fS )Nr  ra   )C_Cipherr   r  r   CTRr  	encryptorr   PKCS7r  padderupdatefinalizer   r
   r  r   r   )
r  r  r  r  cipherr  r  rR   hmacb_hmacs
             r$   _encrypt_cryptographyz!VaultAES256._encrypt_cryptography  s    *..0%))D/CWX$$&	z~~889@@B ''k(BV__EV(VW	**,, FFMMO-ABL!0EFP\H]]]r#   c                    t         j                  j                  d      }|st        j                  d      }t        |      S )NVAULT_ENCRYPT_SALTr  )rW   r  r  r   r?  r   )r  custom_salts     r$   	_get_saltzVaultAES256._get_salt  s2    hh//0DE**R.K$$r#   Nc                j   |t        d      || j                         }n|st        d      t        |      }|j                  }| j	                  ||      \  }}}t
        r| j                  ||||      \  }	}
nt        t        dz         dj                  t        |      |	|
g      }t        |      }|S )Nz'The secret passed to encrypt() was Nonez)Empty or invalid salt passed to encrypt()z(Detected in encrypt)rd   )r   r  r   r   r  r  r  r   r  rJ   r   )r  r  ry   r  rs   r  r  r  r  r  rR   rl   s               r$   r  zVaultAES256.encrypt  s     >#$MNN<]]_F#$OPPd^F\\
"33JG#&#<#<[&RXZ^#_ FL25LLMMjj'&/6<!HI k*r#   c                :   t        |t        j                         t              }|j	                  |       	 |j                  t        |             t        t        j                  |      t        j                  |      t              }|j                         }	t        j                   d      j#                         }
|
j	                  |	j	                  |      |	j%                         z         |
j%                         z   }|S # t        $ r}t        d|z        d }~ww xY w)NzHMAC verification failed: %s   )r   r
   r  r  r  verifyrq   r   r   r  r   r  r   r  	decryptorr   r  unpadderr  )r  rR   rt   r  r  r  r  r   r  r  r  r  s               r$   _decrypt_cryptographyz!VaultAES256._decrypt_cryptography  s     FFMMO-ABL!	HKK
>23 *..0%))D/CWX$$&	==%..0oo\*Y-?-?-AA
     	H#$BQ$FGG	Hs   C> >	DDDc                    t        | t              rt        |t              st        d      t        |       t        |      k7  ryd}t	        | |      D ]  \  }}|||z  z  } |dk(  S )z
        Comparing 2 byte arrays in constant time to avoid timing attacks.

        It would be nice if there were a library for this but hey.
        z6_is_equal can only be used to compare two byte stringsFr   )r  r   r1   rI   zip)b_ab_bresultb_xb_ys        r$   	_is_equalzVaultAES256._is_equal  sn     3,C1MTUU s8s3xC 	 HCcCiF	 {r#   c                    t        |      \  }}}|j                  }| j                  ||      \  }}}	t        r| j	                  |||||	      }
|
S t        t        dz         )Nz(Detected in decrypt))rw   r   r  r  r  r   r  )r  rl   ry   rR   rs   rt   r  r  r  r  r  s              r$   r#  zVaultAES256.decrypt  ss     0?{/K,fn \\
"33JG33L.RXZ`bfgK  25LLMMr#   r~   )r   r    r!   r   r   r4  r  classmethodr  r  r  r  r  r  r#  r"   r#   r$   r  r  y  s    4 	 	 $ $$ ^ ^ % %  4  &  $  r#   r  r   r~   r3  r   )Z
__future__r   r  r  r   r=  r  r  r   r  rX  warningsbinasciir   r   r   rp   r  r  catch_warningssimplefilterDeprecationWarningcryptography.exceptionsr   cryptography.hazmat.backendsr	   cryptography.hazmat.primitivesr
   r   #cryptography.hazmat.primitives.hmacr   )cryptography.hazmat.primitives.kdf.pbkdf2r   &cryptography.hazmat.primitives.ciphersr   r  r   r   ImportErroransible.errorsr   r   ansibler   rW   ansible.module_utils.sixr   +ansible.module_utils.common.text.convertersr   r   r   ansible.utils.displayr   ansible.utils.pathr   r   r   r3   	frozensetr(  r  r  r   r'   r)   r6   rI   r?   rS   r]   rn   rq   ru   rw   rz   r|   r   r   r   r   r   r   r   r   r  r
  r  r6  r  r  r"   r#   r$   <module>r     s  $ #   	     
     +  		 	 	 	" =h(:;<= =>8D  +, ? " 0 T T ) 9
) \* "<0  ] 	 		 1 		l 	, +,3x= (.:&+>&RP0+&	- &09 09fQ<02k 02f& &R-2/ -2`	H($v= v=ru uxX X| {a'= =  		s*   F1 F$15F1 $F.)F1 1F:9F: