
    e;                       d Z ddl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m	Z	m
Z
 ddlZddlZdZdZdZdZej"                  dk(  r	 dd	lmZmZmZ 	 e d
ZeZeZeefZ ej<                  e      Z e jB                  s e jE                   ejF                                d
Z$ejJ                  j>                  dk(  rd Z&n ejN                  d      Z(d Z& ejR                         Z*d Z+d Z,d Z-d Z.d Z/d Z0d Z1 G d de2      Z3 G d de3      Z4 G d de3      Z5 ejN                  dejl                        Z7ddd d!d"d#d$Z8 G d% d&e3      Z9d' Z: G d( d)e3e;      Z< G d* d+e<      Z= G d, d-e=      Z> G d. d/e2      Z?d0d1d2d3d4d5d6d7d8d9d:d;d<d=d>d?Z@d@ ZA G dA dBe4e?      ZB G dC dDe3      ZC G dE dFe3      ZD G dG dHeC      ZE G dI dJe3      ZF G dK dLeF      ZG G dM dNe3e?      ZH ejN                  dOj                  dP            ZJ ejN                  dQejl                        ZK ejN                  dR      ZL G dS dTe2      ZMy# e$ r dZY w xY w# e$ r dZeZeZefZY w xY w)Ua   A wrapper for the GnuPG `gpg` command.

Portions of this module are derived from A.M. Kuchling's well-designed
GPG.py, using Richard Jones' updated version 1.3, which can be found
in the pycrypto CVS repository on Sourceforge:

http://pycrypto.cvs.sourceforge.net/viewvc/pycrypto/gpg/GPG.py

This module is *not* forward-compatible with amk's; some of the
old interface has changed.  For instance, since I've added decrypt
functionality, I elected to initialize with a 'gnupghome' argument
instead of 'keyring', so that gpg can find both the public and secret
keyrings.  I've also altered some of the returned objects in order for
the caller to not have to know as much about the internals of the
result classes.

While the rest of ISconf is released under the GPL, I am releasing
this single file under the same terms that A.M. Kuchling used for
pycrypto.

Steve Traugott, stevegt@terraluna.org
Thu Jun 23 21:27:20 PDT 2005

This version of the module has been modified from Steve Traugott's version
(see http://trac.t7a.org/isconf/browser/trunk/lib/python/isconf/GPG.py) by
Vinay Sajip to make use of the subprocess module (Steve's version uses os.fork()
and so does not work on Windows). Renamed to gnupg.py to avoid confusion with
the previous versions.

Modifications Copyright (C) 2008-2023 Vinay Sajip. All rights reserved.

For the full documentation, see https://docs.red-dove.com/python-gnupg/ or
https://gnupg.readthedocs.io/
    N)StringIO)PopenPIPEz0.5.2zVinay Sajipz$12-Dec-2023 07:52:07$nt)STARTUPINFOSTARTF_USESHOWWINDOWSW_HIDEFTntpathc                     d| z  S )Nz"%s" ss    '/usr/lib/python3/dist-packages/gnupg.pyshell_quoter   T   s    z    z[^\w%+,./:=@-]c                     t        | t              st        dt        |       z        | sd}|S t        j                  |       s| }|S d| j                  dd      z  }|S )au  
        Quote text so that it is safe for POSIX command shells.

        For example, "*.py" would be converted to "'*.py'". If the text is considered safe it is returned unquoted.

        Args:
            s (str): The value to quote
        Returns:
            str: A safe version of the input, from the point of view of POSIX
                 command shells.
        zExpected string type, got %sz''z'%s''z'\'')
isinstancestring_types	TypeErrortypeUNSAFEsearchreplace)r   results     r   r   r   ]   sh     !\*:T!WDEEF
 	 q!F  aiiW55Fr   c                 \    t         s%t        | t              r| j                  t              } | S )z7
    Legacy function which is a no-op on Python 3.
    )_py3kr   	text_typeencode
fsencodingr   s    r   no_quoter!      s#     Z9-HHZ Hr   c                 t   |dkD  sJ d}t        t        j                  d      rt        j                  j                  }nd}	 	 | j	                  |      }|sn!|t        |      z  }	 |j                  |       6	 |j                          t        j                  d	|       y # t
        $ r t        j                  dd       Y Jw xY w# t        $ r# |j                  |j                  |             Y zt
        $ r t        j                  d       Y w xY w# t        $ r t        j                  dd       Y w xY w)
Nr   encodingasciiz Exception occurred while reading   )exc_infozError sending dataz)Exception occurred while closing: ignoredzclosed output, %d bytes sent)hasattrsysstdinr#   read	ExceptionloggerwarninglenwriteUnicodeErrorr   	exceptioncloseIOErrordebug)instream	outstreambuffer_sizesentencdatas         r   
_copy_datar;      s!   ??Dsyy*%ii  
	==-D D		OOD! *P LL/6)  	NN=NJ	  	.OODKK,- 	 12		  PBQOPs<   B  &C 9D   CC)D1DD D76D7c                     |dkD  sJ t        j                  t        | ||f      }d|_        t        j                  d|| |       |j                          |S )Nr   targetargsTzdata copier: %r, %r, %r)	threadingThreadr;   daemonr,   r4   start)r5   r6   r7   wrs       r   _threaded_copy_datarE      sO    ??			8Y2T	UBBI
LL*B)DHHJIr   c                 |    d|z  }|j                  |      }| j                  |       t        j                  d       y )Nz%s
zWrote passphrase)r   r/   r,   r4   )stream
passphraser#   s      r   _write_passphraserI      s5    *$J""8,J
LL
LL#$r   c                 B    t        | t        t        t        t        f      S N)r   listtupleset	frozenset)instances    r   _is_sequencerQ      s    huc9 =>>r   c                 Z    	 ddl m}  ||       }|S # t        $ r t        |       }Y |S w xY w)Nr   )BytesIO)iorS   ImportErrorr   )r   rS   rvs      r   _make_memory_streamrW      s9    QZ I  a[Is    **c                     t         r,t        | t              r>| j                  |      } t        |       S t	        |       t        ur| j                  |      } t        |       S rK   )r   r   strr   r   rW   )r   r#   s     r   _make_binary_streamrZ      sQ    a"A q!! 7#"Aq!!r   c                       e Zd ZdZd Zd Zy)StatusHandlerzA
    The base class for handling status messages from `gpg`.
    c                     || _         y)zq
        Initialize an instance.

        Args:
            gpg (GPG): The :class:`GPG` instance in use.
        N)gpgselfr^   s     r   __init__zStatusHandler.__init__   s     r   c                     t         )a.  
        Handle status messages from the `gpg` child process. These are lines of the format

            [GNUPG:] <key> <value>

        Args:
            key (str): Identifies what the status message is.
            value (str): Identifies additional data, which differs depending on the key.
        )NotImplementedErrorr`   keyvalues      r   handle_statuszStatusHandler.handle_status   s
     "!r   N)__name__
__module____qualname____doc__ra   rg   r   r   r   r\   r\      s    
"r   r\   c                   j    e Zd ZdZdZdZdZdZdZdZ	eeeeee	dZ
d	d
dddZddiZdZd Zd ZeZd Zy)VerifyzJ
    This class handles status messages during signature verificaton.
    r   r%               )TRUST_EXPIREDTRUST_UNDEFINEDTRUST_NEVERTRUST_MARGINALTRUST_FULLYTRUST_ULTIMATEzpermission deniedzfile existszfile not foundznot a directory)r%   #   Q   a      zincorrect passphraseNc                    t         j                  | |       d| _        d x| _        x| _        | _        d x| _        | _        d | _        d | _        d | _	        d | _
        d | _        d | _        d | _        d | _        d | _        i | _        g | _        y NF)r\   ra   validfingerprintcreation_date	timestampsignature_idkey_idusername
key_statusstatuspubkey_fingerprintexpire_timestampsig_timestamp
trust_texttrust_levelsig_infoproblemsr_   s     r   ra   zVerify.__init__  s    tS)
AEEE4-*..DK"& $!r   c                     | j                   S rK   )r~   r`   s    r   __nonzero__zVerify.__nonzero__%  s    zzr   c                      fd}| j                   v rA| _         j                   |    _         | j                   j                         d  _        y |dv rt        j                  d||       y |dk(  rd _        d _        |j                  d d      \   _	         _
         j                  j                   j                   j                   j                  d	        | j                   j                   j                  
       y |dk(  rd _        |j                         }|d d \   _	        }}} _        t        |      dk\  r
|d    _        d _         | j                   j                   j                   j                          j                  j                   j                   j                   j                   j                  d       y |dk(  rd _        d _        |j                  d d      \   _	         _
         | j                   j                   j                  
        j                  j                   j                   j                   j                  d	       y |dk(  rWd _        d _        |j                  d d      \   _	         _
         | j                   j                   j                  
       y |dk(  r{|j                         }|d d \  }}	}
}||	|
|f\   _         _         _         _        t        |      dk\  r
|d    _        d _         |||	|
| j&                   j                         y |dk(  r=|j                         \  }}	}|	|d j(                  |<   ||	|c _         _         _        y |dk(  rHd _        | _	        d  _         j                  j                   j                   j                  d!       y |d"k(  rHd _        | _	        d# _         j                  j                   j                   j                  d!       y |d$v rd _        |j                         d%    _	        |d&k(  rd' _        nd( _         j*                   _         | j                   j                  !        j                  j                   j                   j                  d!       y |d)v rd _        |d*k(  rd+ _        y d,|z  }|j-                  d-d      \  }}|j/                         rt1        |      d.z  } j2                  j4                  r7| j2                  j4                  v r|d/ j2                  j4                  |   }n<t7        |d0z        }|d1z  }|r j8                  }n j:                  }||v r
|d/||   } j                  s| _        y y |d2k(  rd _        d3 _        y |d4v ry |d5v rd  _        y t        j=                  d6||       y )7Nc                      j                   }|r!j                  |   }|j                  |        y t        j	                  d|        y )Nz!Ignored due to missing sig iD: %s)r   r   updater,   r4   )kwargssig_idinfor`   s      r   update_sig_infoz-Verify.handle_status.<locals>.update_sig_info,  s:    &&F}}V,F#@&Ir   )r   r   WARNINGERRORpotential problem: %s: %sBADSIGFzsignature badr%   )r   keyiduser)r   r   r   ERRSIGrq         zsignature error)r   r   r   r   )r   r   r   r   EXPSIGzsignature expiredGOODSIGTzsignature goodVALIDSIGrp   
   	   zsignature valid)r   r   r   expiryr   r   SIG_ID)r   r   	NO_PUBKEYzno public key)r   r   	NO_SECKEYno secret key)	EXPKEYSIG	REVKEYSIGr   r   zsigning key has expiredzsigning key was revoked)
UNEXPECTEDFAILUREr   zunexpected dataz
error - %s i : i   i  NODATAz signature expected but not found)DECRYPTION_INFO	PLAINTEXTPLAINTEXT_LENGTHBEGIN_SIGNINGKEY_CONSIDERED)NEWSIGzmessage ignored: %r, %r)TRUST_LEVELSr   r   r   r,   r-   r~   r   splitr   r   r   appendr   r.   r   r   r   r   r   r   r   rsplitisdigitintr^   	error_mapboolGPG_SYSTEM_ERROR_CODESGPG_ERROR_CODESr4   )r`   re   rf   r   partsalgo	hash_algoclsr   r   sig_ts	expire_tsr   r   message	operationcodesystem_errormappings   `                  r   rg   zVerify.handle_status*  s'   	J $###!DO#005D(8(8T__U !%D((NN6UCH_DJ)DK).T1)=&DKMM  DKK$++W[WdWd!ef$++dkkZH_DJKKMEBG)?T[$	35zQ#(8 +DK$++&*nn(,(8(8#';;0 MM  ++!^^#//	"  H_DJ-DK).T1)=&DK$++dkkZMM  DKK$++W[WdWd!efIDJ*DK).T1)=&DK$++dkkZJKKME<A"1I9K	'2M69&U$Tt143E"5zR*/('+DK*7&,#,/3/F/F#';;0 H_/4{{},FM96CR[$\DMM&!GM}^gCT 2DNKDJDK)DKMM  DKK$++!NOKDJDK)DKMM  DKK$++!NO..DJ++-*DKk!";";//DK4;;dkkBMM  DKK$++!NO--DJl"/ '."',,sA"6	4<<>t9x/Dxx))ddhh6H6H.H.79K9KD9Q"R'+D6M':#f}'&*&A&AG&*&:&:G7?2;WT]&KG{{")DK #H_DJ<DKkkL  $DLL2C?r   )rh   ri   rj   rk   rr   rs   rt   ru   rv   rw   r   r   r   
returncodera   r   __bool__rg   r   r   r   rm   rm      s     MOKNKN '*"("(L 	 	"O J" HE@r   rm   c                   r    e Zd ZdZdj	                         ZdZd Zd ZeZ	dddd	d
ddZ
ddddddZd Zd Zy)ImportResultz?
    This class handles status messages during key import.
    zcount no_user_id imported imported_rsa unchanged n_uids n_subk n_sigs n_revoc sec_read sec_imported
            sec_dups not_importedNc                     t         j                  | |       g | _        g | _        | j                  D ]  }t        | |d        y )Nr   )r\   ra   resultsfingerprintscountssetattr)r`   r^   r   s      r   ra   zImportResult.__init__  s@    tS)kk 	%FD&!$	%r   c                 J    t        | j                   xr | j                        S rK   )r   not_importedr   r   s    r   r   zImportResult.__nonzero__  s!    )))?d.?.?@@r   zNot actually changedzEntirely new keyzNew user IDszNew signatureszNew subkeyszContains private key)0124816zNo specific reason givenzInvalid CertificatezIssuer Certificate missingzCertificate Chain too longzError storing certificate)r   r   r   3r   c           	      z   |dv rt         j                  d||       y |dv ry |dk(  r | j                  j                  d ddd       y |dk(  r|j	                         \  }}g }t        | j                  j                               D ]:  \  }}t        |      t        |      z  t        |      k(  s*|j                  |       < d	j                  |      d	z   }| j                  j                  |||d
       | j                  j                  |       y |dk(  rA	 |j	                         \  }}| j                  j                  ||| j                  |   d       y |dk(  rG|j	                         }	t        | j                        D ]  \  }
}t        | |t        |	|
                  y |dk(  r | j                  j                  d ddd       y |dk(  r | j                  j                  d ddd       y |dk(  r | j                  j                  d ddd       y t         j!                  d||       y # t        $ r |}d}Y w xY w)Nr   r   )IMPORTEDr   r   r   zNo valid data found)r   problemtext	IMPORT_OK
)r   okr   IMPORT_PROBLEMz	<unknown>
IMPORT_RES
KEYEXPIREDzKey expired
SIGEXPIREDzSignature expiredr   zOther failuremessage ignored: %s, %s)r,   r-   r   r   r   rL   	ok_reasonitemsr   joinr   r+   problem_reason	enumerater   r   r4   )r`   re   rf   reasonr   reasonsr   r   
reasontext
import_resicounts               r   rg   zImportResult.handle_status  s   &&NN6UC22H_LLNc deK"'++-FKG"4>>#7#7#9: )
dv;T*c&k9NN4() 7+d2JLL6S] ^_$$[1$$*&+kkm# LLX\XkXklrXs tuL J%dkk2 95eSA%789L LLm \]L LLNa bcILLo ^_LL2C?  *)*s   H) )H:9H:c                     g }|j                  d| j                  z         | j                  r|j                  d| j                  z         dj                  |      S )zi
        Return a summary indicating how many keys were imported and how many were not imported.
        z%d importedz%d not imported, )r   importedr   r   )r`   r   s     r   summaryzImportResult.summary  sN     mdmm34MM+d.?.??@yy  r   )rh   ri   rj   rk   r   r   r   ra   r   r   r   r   rg   r   r   r   r   r   r     sp    %%*UW  J%A H $$I ("))(N#@J!r   r   z\\x([0-9a-f][0-9a-f])r    )z\nz\rz\fz\vz\bz\0c                       e Zd ZdZdZd Zy)
SendResultz@
    This class handles status messages during key sending.
    Nc                 2    t         j                  d||       y )NzSendResult: %s: %s)r,   r4   rd   s      r   rg   zSendResult.handle_status  s    )36r   )rh   ri   rj   rk   r   rg   r   r   r   r  r    s     J7r   r  c                 b    t        |      D ]!  \  }}|t        |      k  r	||   | |<   d| |<   # y )Nunavailable)r   r.   )r>   
fieldnamesr?   r   vars        r   _set_fieldsr    s;    J' (3s4y=q'F3K'F3K	(r   c                   V    e Zd ZdZdZdj                         ZdZd Zd Z	d Z
d Zd	 Zy)

SearchKeysz?
    This class handles status messages during key search.
    r%   z#type keyid algo length date expiresNc                 Z    t         j                  | |       d | _        g | _        g | _        y rK   )r\   ra   curkeyr   uidsr_   s     r   ra   zSearchKeys.__init__3  s(    tS)	r   c                 L    i }t        || j                  |       g |d<   g |d<   |S )Z
        Internal method used to update the instance from a `gpg` status message.
        r  sigs)r  FIELDS)r`   r?   r   s      r   
get_fieldszSearchKeys.get_fields9  s0     FDKK.vvr   c                 V    | j                  |      x| _        }| j                  |       y)r  N)r  r  r   r`   r?   r  s      r   pubzSearchKeys.pubC  s%      $t44fFr   c                    || j                      }t        j                  d |      }t        j	                         D ]  \  }}|j                  ||      } | j                  d   j                  |       | j                  j                  |       y)r  c                 J    t        t        | j                  d      d            S )Nr%      )chrr   group)ms    r   <lambda>z SearchKeys.uid.<locals>.<lambda>O  s    3s1771:r/B+C r   r  N)		UID_INDEXESCAPE_PATTERNsubBASIC_ESCAPESr   r   r  r   r  )r`   r?   uidkvs        r   r   zSearchKeys.uidJ  sz     4>>"  !CSI!'') 	$DAq++a#C	$F""3'		r   c                      y rK   r   rd   s      r   rg   zSearchKeys.handle_statusU  s    r   )rh   ri   rj   rk   r  r   r  r   ra   r  r  r   rg   r   r   r   r	  r	  '  s:     I288:FJ	r   r	  c                   x     e Zd ZdZdZdj                         Z fdZd ZexZ	Z
d Zd Zd Zd	 Zd
 Zd Z xZS )ListKeysa  
    This class handles status messages during listing keys and signatures.

    Handle pub and uid (relating the latter to the former).

    We don't care about (info from GnuPG DETAILS file):

    crt = X.509 certificate
    crs = X.509 certificate and private key available
    uat = user attribute (same as user id except for field 10).
    sig = signature
    rev = revocation signature
    pkd = public key data (special field format, see below)
    grp = reserved for gpgsm
    rvk = revocation key
    r   ztype trust length algo keyid date expires dummy ownertrust uid sig cap issuer flag token hash curve compliance updated origin keygripc                 H    t         t        |   |       d| _        i | _        y r}   )superr%  ra   	in_subkeykey_map)r`   r^   	__class__s     r   ra   zListKeys.__init__o  s     h&s+r   c                     | j                  |      x| _        }|d   r|d   j                  |d          |d= g |d<   | j                  |       d| _        y)r  r   r  subkeysFN)r  r  r   r(  r  s      r   re   zListKeys.keyt  sZ      $t44f%=6N!!&-05MyFr   c                 n   |d   }|| j                   v r$| j                  j                  rt        d|z        | j                  sD|| j
                  d<   | j                  j                  |       | j
                  | j                   |<   y|| j
                  d   d   d<   | j
                  | j                   |<   y)r  r   z$Unexpected fingerprint collision: %sr   r,  rn   N)r)  r^   check_fingerprint_collisions
ValueErrorr(  r  r   r   )r`   r?   fps      r   fprzListKeys.fpr  s     !W$(("G"GCbHII~~)+DKK&$$R(#{{DLL,.DKK	"2&q)#{{DLLr   c                 p    |d   }| j                   s|| j                  d<   y|| j                  d   d   d<   y)r  r   keygripr,  r.  ro   N)r(  r  )r`   r?   grps      r   r5  zListKeys.grp  s:     1g~~%(DKK	",/DKK	"2&q)r   c                 j    |j                  di       }i }t        || j                  |       |||d   <   y )Nsubkey_inforp   )
setdefaultr  r  )r`   r  r?   info_mapr   s        r   _collect_subkey_infozListKeys._collect_subkey_info  s7    $$]B7D$++t, ar   c                     |d   |d   ddg}| j                   d   j                  |       | j                  | j                   |       d| _        y)r  rp   r{   Nr,  Tr  r   r:  r(  r`   r?   subkeys      r   r  zListKeys.sub  sL     q'48T40I%%f-!!$++t4r   c                     |d   dddg}| j                   d   j                  |       | j                  | j                   |       d| _        y)r  rp   Nr,  Tr<  r=  s      r   ssbzListKeys.ssb  sH     q'4t,I%%f-!!$++t4r   c                 X    | j                   d   j                  |d   |d   |d   f       y)r  r  rp   r   r   N)r  r   )r`   r?   s     r   sigzListKeys.sig  s.    
 	F""DGT!Wd2h#?@r   )rh   ri   rj   rk   r  r   r  ra   re   r  secr2  r5  r:  r  r@  rB  __classcell__r*  s   @r   r%  r%  Y  sW    " ITUZUZU\ 

 OC#+0!
Ar   r%  c                       e Zd ZdZd Zy)ScanKeyszB
    This class handles status messages during scanning keys.
    c                     |d   |d   ddg}| j                   d   j                  |       | j                  | j                   |       d| _        y)r  rp   r.  Nr,  Tr<  r=  s      r   r  zScanKeys.sub  sL     q'48T40I%%f-!!$++t4r   N)rh   ri   rj   rk   r  r   r   r   rG  rG    s    	r   rG  c                   &    e Zd Zd ZereZyeZd Zy)TextHandlerc                     | j                   j                  | j                  j                  | j                  j                        S rK   )r:   decoder^   r#   decode_errorsr   s    r   _as_textzTextHandler._as_text  s-    yy 1 14883I3IJJr   c                     | j                   S rK   )r:   r   s    r   __str__zTextHandler.__str__  s    99r   N)rh   ri   rj   rN  r   rP  __unicode__r   r   r   rJ  rJ    s    K 	r   rJ  zno specific reason givenz	not foundzambiguous specificationzwrong key usagekey revokedkey expiredzno crl knownzcrl too oldzpolicy mismatchznot a secret keyzkey not trustedzmissing certificatezmissing issuer certificatezkey disabledzsyntax error in specification)r   r%   rn   ro   rp   rq   r   r      r   r   r{            c                     | j                         }t        |      dk\  r	|d d \  }}n|d   }d}d|z  }	 t        |      }t        j	                  ||      }|d|S # t
        $ r |}Y w xY w)Nrn   r   z
<no ident>zunexpected return code %r:)r   r.   r   _INVALID_KEY_REASONSgetr0  )r   r   r   ident
unexpectedre   r   s          r   &_determine_invalid_recipient_or_signerr^    s    GGIE
5zQBQieQx,t3J$i%))#z: e$$  s   !A A+*A+c                   &    e Zd ZdZd Zd ZeZd Zy)CryptzN
    This class handles status messages during encryption and decryption.
    c                 v    t         j                  | |       d| _        d| _        d| _        d| _        d | _        y )N F)rm   ra   r:   r   r   status_detailr   r_   s     r   ra   zCrypt.__init__  s4    c"	r   c                 ,    t        | j                        S rK   )r   r   r   s    r   r   zCrypt.__nonzero__  s    DGG}r   c                    |dv rt         j                  d||       y |dk(  r| j                  dvrd| _        y y |dv r&|j                  dd      j	                         | _        y |d	k(  r| j                  d
k7  rd| _        y y |dk(  rd| _        y |dk(  r| j                  d
k7  rd| _        y y |dk(  rd| _        y |dk(  rd| _        d| _        y |dk(  rd| _        d| _        y |dk(  r9| j                  sd| _        nd| j                  z  | _        t        |      | _        y |dk(  rd| _        y |dk(  rd| _        y |dk(  rd| _        y |d k(  r|j                  dd!      d"   | _	        y |d#v ry t        j                  | ||       y )$Nr   r   r   )decryption failedzno data was provided)NEED_PASSPHRASEBAD_PASSPHRASEGOOD_PASSPHRASEMISSING_PASSPHRASEKEY_NOT_CREATEDNEED_PASSPHRASE_PIN_r   DECRYPTION_FAILEDr   rf  NEED_PASSPHRASE_SYMzneed symmetric passphraseBEGIN_DECRYPTIONzdecryption incompleteBEGIN_ENCRYPTIONzencryption incompleteDECRYPTION_OKAYzdecryption okTEND_ENCRYPTIONzencryption okINV_RECPzinvalid recipientzinvalid recipient: %sr   rS  SIG_CREATEDzsig createdr   zsig expiredENC_TOr%   r   )USERID_HINTGOODMDCEND_DECRYPTIONCARDCTRLBADMDCSC_OP_FAILURESC_OP_SUCCESSPINENTRY_LAUNCHED)r,   r-   r   r   lowerr   r^  rc  r   r   rm   rg   rd   s      r   rg   zCrypt.handle_status  s   &&NN6UCH_{{"994 : , ,++c3/557DK''{{o-1 .))5DK&&{{o-5 .&&1DK%%)DKDG$$)DKDGJ;;15C!G!NDL 'DKM!'DKL 'DKH_++c1-a0DK ; ;  sE2r   N)rh   ri   rj   rk   ra   r   r   rg   r   r   r   r`  r`     s     H,3r   r`  c                   0    e Zd ZdZdZd Zd ZeZd Zd Z	y)GenKeyzC
    This class handles status messages during key generation.
    Nc                 Z    t         j                  | |       d | _        d| _        d | _        y Nrb  r\   ra   r   r   r   r_   s     r   ra   zGenKey.__init__H  (    tS)	r   c                 ,    t        | j                        S rK   r   r   r   s    r   r   zGenKey.__nonzero__N      D$$%%r   c                     | j                   S rK   r   r   s    r   rP  zGenKey.__str__S      r   c                 (   |dv rt         j                  d||       y |dk(  r*|j                         }|d d \  | _        | _        d| _        y |dk(  r&|j                  dd      j                         | _        y |d	v ry t         j                  d
||       y )Nr   r   KEY_CREATEDrn   r   rk  rm  r   )PROGRESSri  r   )	r,   r-   r   r   r   r   r   r  r4   )r`   re   rf   r   s       r   rg   zGenKey.handle_statusV  s    &&NN6UCM!KKME,1"1I)TY(DK%%++c3/557DK33LL2C?r   
rh   ri   rj   rk   r   ra   r   r   rP  rg   r   r   r   r  r  A  s*     J& H @r   r  c                   0    e Zd ZdZdZd Zd ZeZd Zd Z	y)	AddSubkeyzD
    This class handles status messages during subkey addition.
    Nc                 Z    t         j                  | |       d | _        d| _        d | _        y r  r  r_   s     r   ra   zAddSubkey.__init__l  r  r   c                 ,    t        | j                        S rK   r  r   s    r   r   zAddSubkey.__nonzero__r  r  r   c                     | j                   S rK   r  r   s    r   rP  zAddSubkey.__str__w  r  r   c                     |dv rt         j                  d||       y |dk(  r%|j                         \  | _        | _        d| _        y t         j                  d||       y )Nr   r   r  r   r   )r,   r-   r   r   r   r   r4   rd   s      r   rg   zAddSubkey.handle_statusz  sQ    &&NN6UCM!,1KKM)TY(DKLL2C?r   r  r   r   r   r  r  e  s*     J& H @r   r  c                   "     e Zd ZdZ fdZ xZS )ExportResultz?
    This class handles status messages during key export.
    c                 8    |dv ry t         t        |   ||       y )N)EXPORTED
EXPORT_RES)r'  r  rg   )r`   re   rf   r*  s      r   rg   zExportResult.handle_status  s     ,,,3C?r   )rh   ri   rj   rk   rg   rD  rE  s   @r   r  r    s    @ @r   r  c                   <    e Zd ZdZdZd Zd ZddddZd	 Zd
 Z	e	Z
y)DeleteResultzA
    This class handles status messages during key deletion.
    Nc                 >    t         j                  | |       d| _        y Nr   )r\   ra   r   r_   s     r   ra   zDeleteResult.__init__  s    tS)r   c                     | j                   S rK   r   r   s    r   rP  zDeleteResult.__str__  s    {{r   zNo such keyzMust delete secret key firstzAmbiguous specification)r   r   r   c                     |dk(  r%| j                   j                  |d|z        | _        y t        j	                  d||       y )NDELETE_PROBLEMzUnknown error: %rr   )r   r[  r   r,   r4   rd   s      r   rg   zDeleteResult.handle_status  s<    ""--11%9Lu9TUDKLL2C?r   c                      | j                   dk(  S r  r  r   s    r   r   zDeleteResult.__nonzero__  s    {{d""r   )rh   ri   rj   rk   r   ra   rP  r   rg   r   r   r   r   r   r  r    s<     J +&N@# Hr   r  c                       e Zd ZdZy)TrustResultzF
    This class handles status messages during key trust setting.
    N)rh   ri   rj   rk   r   r   r   r  r    s     	r   r  c                   *    e Zd ZdZdZd Zd ZeZd Zy)Signz<
    This class handles status messages during signing.
    Nc                     t         j                  | |       d | _        d | _        d | _        d | _        d | _        d | _        d | _        y rK   )	r\   ra   r   r   r   r   rc  r   r   r_   s     r   ra   zSign.__init__  sE    tS)	!r   c                     | j                   d uS rK   r  r   s    r   r   zSign.__nonzero__  s    t++r   c                    |dv rt         j                  d||       y |dv rd| _        y |dk(  rd| _        y |dk(  r3|j                         \  | _        }| _        }| _        | _        d| _        y |d	k(  r |j                  d
d      \  | _        | _	        y |dk(  rd| _        y |dv r9| j                  sd| _        nd| j                  z  | _        t        |      | _        y |dv ry t         j                  d||       y )N)r   r   r   r   )r   r   rS  
KEYREVOKEDrR  ru  zsignature createdrw  r   r%   rh  zbad passphrase)INV_SGNRrt  zinvalid signerzinvalid signer: %s)rg  ri  r   r   )r,   r-   r   r   r   r   r   r   r   r   r^  rc  r4   )r`   re   rf   r   r   s        r   rg   zSign.handle_status  s    11NN6UC00'DKL 'DKM!W\WbWbWdTTYdnc4>4CS-DKM!).S!)<&DK$$*DK,,;;.2T[[@!G!NDKKLL2C?r   )	rh   ri   rj   rk   r   ra   r   r   rg   r   r   r   r  r    s%     J, H@r   r  z^cfg:version:(\d+(\.\d+)*)r$   z
[0-9a-f]+$zgpg: public key is (\w+)c                   |   e Zd ZdZdZdZdZeee	e
eeeeeeeeedZ	 	 	 	 	 	 	 	 	 d,dZd Zd-dZd	 Zd.d
Zd/dZd Zd Zd0dZd Zd Zd Z 	 	 	 	 	 	 	 d1dZ!d Z"d2dZ#d3dZ$d/dZ%d Z&d Z'd Z(d4dZ)	 	 	 	 	 	 d5dZ*d Z+d Z,d6dZ-d Z.d  Z/d7d!Z0d" Z1d# Z2d8d$Z3	 	 	 	 	 	 	 d9d%Z4d& Z5d' Z6d:d(Z7d) Z8d3d*Z9d+ Z:y);GPGzL
    This class provides a high-level programmatic interface for `gpg`.
    Nstricti @  )cryptdeletegenerate	addSubkeyimportsendrL   scanr   signtrustverifyexportc	                    || _         || _        || _        |r-t        j                  j                  |      st        d|z        |rt        |t              r|g}|| _	        |rt        |t              r|g}|| _
        || _        || _        t        |t              r|g}|| _        d| _        d| _        |rIt        j                  j                  | j                        s t        j"                  | j                  d       	 | j%                  ddg      }	 | j,                  d   |       }| j/                  |	||	j0                  	       |	j2                  d
k7  r%t        d|	j2                  d|j4                        t6        j9                  |j:                        }|sd| _        d| _$        ydj?                  d      }tA        |jC                         d
   jE                  |      D cg c]  }tG        |       c}      | _        d| _$        y# t&        $ r0 d| j                   z  }
t(        j+                  |
       t'        |
      w xY wc c}w )a9  Initialize a GPG process wrapper.

        Args:
            gpgbinary (str): A pathname for the GPG binary to use.

            gnupghome (str): A pathname to where we can find the public and private keyrings. The default is
                             whatever `gpg` defaults to.

            keyring (str|list): The name of alternative keyring file to use, or a list of such keyring files. If
                                specified, the default keyring is not used.

            options (list): A list of additional options to pass to the GPG binary.

            secret_keyring (str|list): The name of an alternative secret keyring file to use, or a list of such
                                       keyring files.

            env (dict): A dict of environment variables to be used for the GPG subprocess.
        z.gnupghome should be a directory (it isn't): %sNzlatin-1i  z--list-config--with-colonsz1Unable to run gpg (%s) - it may not be available.r  r)   r   zError invoking gpg: r   .r$   F)%	gpgbinary	gnupghomeenvospathisdirr0  r   r   keyringsecret_keyringverbose	use_agentrY   optionson_datar#   makedirs_open_subprocessOSErrorr,   r1   
result_map_collect_outputr)   r   stderr
VERSION_REmatchr:   versionr   rM   groupsr   r   r/  )r`   r  r  r  r  r  r  r  r  pmsgr   r  dotr   s                  r   ra   zGPG.__init__  s   6 #"RWW]]95NQZZ[[ '<0") .,7"0!1,"gs#iG
 "RWW]]4>>:KK.	%%&HIA
 +*40Qagg6<<1Q\\6==YZZV[[)DL -2) **W%C !((*Q-2E2Ec2J!KQ#a&!KLDL -2)#  	EVCS!#,	 "Ls   ?H	 #I	9Ic                    | j                   ddddg}dt        j                  v r|j                  ddg       |r"t	        | d      r| j
                  d	k\  rd
dg|dd |j                  g d       | j                  r&|j                  dt        | j                        g       | j                  r>|j                  d       | j                  D ]  }|j                  dt        |      g         | j                  r-| j                  D ]  }|j                  dt        |      g         |r|j                  ddg       | j                  r|j                  d       | j                  r|j                  | j                         |j                  |       |S )aN  
        Make a list of command line elements for GPG. The value of ``args``
        will be appended. The ``passphrase`` argument needs to be True if
        a passphrase will be sent to `gpg`, else False.

        Args:
            args (list[str]): A list of arguments.
            passphrase (str): The passphrase to use.
        z--status-fdr   z--no-ttyz--no-verbose	DEBUG_IPCz--debugipcr  rn   r%   z--pinentry-modeloopbackr%   )--fixed-list-modez--batchr  z	--homedirz--no-default-keyringz	--keyringz--secret-keyringz--passphrase-fdr   z--use-agent)r  r  environextendr'   r  r  r!   r  r   r  r  r  )r`   r?   rH   cmdfns        r   	make_argszGPG.make_argsZ  sK    ~~}c:~N"**$JJ	5)*'$	2||v%-z:Aa

DE>>JJXdnn%=>?<<JJ-.ll 8

K"678)) ?

.=>?JJ)3/0>>JJ}%<<JJt||$

4
r   c           	      `   ddl m} | j                  ||      }| j                  rt	         ||             t
        sd }n t               }t        |_        t        |_	        t        |dt        t        t        || j                        }t        j                  d|j                   ||             |S )Nr   )list2cmdlineF)shellr)   stdoutr  startupinfor  z%s: %s)
subprocessr  r  r  printr   r   dwFlagsr	   wShowWindowr   r   r  r,   r4   pid)r`   r?   rH   debug_printr  sir   s          r   r  zGPG._open_subprocess}  s     	;nnT:.<<+c"#BB-BJ$BNs%tD[]cgckcklXvzz;s+;<r   c                    g }	 |j                         }t        |      dk(  rn|j                  |       |j                         }| j                  rt        |       t        j                  d|       |dd dk(  rD|dd  }|j                  d d      }|d   }t        |      dkD  r|d   }nd}|j                  ||       dj                  |      |_        y )Nr   z%sr   z	[GNUPG:] r%   rb  )readliner.   r   rstripr  r  r,   r4   r   rg   r   r  )r`   rG   r   lineslineLkeywordrf   s           r   _read_responsezGPG._read_response  s     ??$D4yA~LL;;=D||dLLt$AayK'ABxJJtQ'A$q6A:aDEE$$We4% & r   c                 t   |dkD  sJ g }	 |j                  |      }t        |      dk(  r|r ||       nCt        rt        j	                  d|d d z         d}|r
 ||      du}|r|j                  |       mt        r% t        |             j                  |      |_	        y dj                  |      |_	        y )Nr   Tz	chunk: %r   Frb  )
r*   r.   log_everythingr,   r4   r   r   r   r   r:   )r`   rG   r   r  r7   chunksr:   r   s           r   
_read_datazGPG._read_data  s    Q;;{+D4yA~DM[4:56F e3d#  $$t*,++F3FK''&/FKr   c                 N    t        j                  | j                        |j                        }t	        j
                  | j                  ||f      }d|_        t        j                  d|       |j                          |j                  }t	        j
                  | j                  ||| j                  | j                  f      }d|_        t        j                  d|       |j                          |j                          |j                          ||j                  d       |j!                          |j"                  x|_        }	|	dk7  rt        j%                  d|	       |	 |j'                          |j'                          |j'                          |	S # t(        $ r Y -w xY w)a  
        Drain the subprocesses output streams, writing the collected output to the result. If a writer thread (writing
        to the subprocess) is given, make sure it's joined before returning. If a stdin stream is given, close it
        before returning.
        r=   Tzstderr reader: %rzstdout reader: %r{Gz?r   z&gpg returned a non-zero error code: %d)codecs	getreaderr#   r  r@   rA   r  rB   r,   r4   rC   r  r  r  r7   r   waitr   r-   r2   r3   )
r`   processr   writerr)   r  rrr  drrcs
             r   r  zGPG._collect_output  sH    1!!$--0@T%8%8?OP	("-

T__FFDLLZ^ZjZj;kl	("-


	
	KK!(!3!33B7NNCRH 			  s   &F 	F$#F$c                     t        |d      S )z
        A simplistic check for a file-like object.

        Args:
            fileobj (object): The object to test.
        Returns:
            bool: ``True`` if it's a file-like object, else ``False``.
        r*   )r'   )r`   fileobjs     r   is_valid_filezGPG.is_valid_file  s     w''r   c                     | j                  |      r|}|S t        |t              st        d|z        t        j
                  j                  |      st        d|z        t        |d      }|S )NzNot a valid file or path: %szNo such file: %srb)	r  r   
path_typesr   r  r  existsr0  open)r`   fileobj_or_pathr   s      r   _get_fileobjzGPG._get_fileobj  sk    o.$F  OZ8:_LMM0//ABB/40Fr   c                    | j                  |      }	 | j                  ||du      }|s0 t        j                  | j                        |j
                        }n|j
                  }|rt        ||| j                         t        ||| j                        }	| j                  |||	|       ||	j                  d       ||ur|j                          S S # 	j                  d       ||ur|j                          w w xY w)z;Handle a call to GPG - pass input data, collect output dataNr  )r  r  r  	getwriterr#   r)   rI   rE   r7   r  r   r2   )
r`   r?   r  r   rH   binaryr  r  r)   r  s
             r   
_handle_iozGPG._handle_io  s     ##O4	 %%dJd,BCA7((7@!%T]]C(%9I9IJF  FFE:KKo- . KKo- .s   BC (C9c                 x    t        || j                        } | j                  |fi |}|j                          |S )a  
        Sign a message. This method delegates most of the work to the `sign_file()` method.

        Args:
            message (str|bytes): The data to sign.
            kwargs (dict): Keyword arguments, which are passed to `sign_file()`:

                * keyid (str): The key id of the signer.

                * passphrase (str): The passphrase for the key.

                * clearsign (bool): Whether to use clear signing.

                * detach (bool): Whether to produce a detached signature.

                * binary (bool): Whether to produce a binary signature.

                * output (str): The path to write a detached signature to.

                * extra_args (list[str]): Additional arguments to pass to `gpg`.
        )rZ   r#   	sign_filer2   )r`   r   r   fr   s        r   r  zGPG.sign  s7    ,  7,V,		r   c                     t         j                  j                  |      r|j                  dg       |j                  dt	        |      g       y)a:  
        If writing to a file which exists, avoid a confirmation message by
        updating the *args* value in place to set the output path and avoid
        any cpmfirmation prompt.

        Args:
            args (list[str]): A list of arguments.
            output (str): The path to the outpur file.
        --yesz--outputN)r  r  r  r  r!   )r`   r?   outputs      r   set_output_without_confirmationz#GPG.set_output_without_confirmation0  s8     77>>&!KK	"Z&!123r   c                 "    d|vxr
 d|vxr d|vS )a  
        Confirm that the passphrase doesn't contain newline-type characters - it is passed in a pipe to `gpg`,
        and so not checking could lead to spoofing attacks by passing arbitrary text after passphrase and newline.

        Args:
            passphrase (str): The passphrase to test.

        Returns:
            bool: ``True`` if it's a valid passphrase, else ``False``.
        r   r   r   r   )r`   rH   s     r   is_valid_passphrasezGPG.is_valid_passphrase?  s$     J&^4z+A^fT^F^_r   c	                 d   |r| j                  |      st        d      t        j                  d|       |rdg}	ndg}	|r|	j	                  d       n|r|	j	                  d       |r|	j                  dt        |      g       |r| j                  |	|       |r|	j                  |        | j                  d   |       }
| j                  |      }| j                  |	|d	u      }	 |j                  }|rt        ||| j                         t        ||| j                        }|r|j'                  d       ||ur|j)                          	 | j+                  ||
|       |
S # t         $ r t#        j$                  d
       d	}Y `w xY w# r|j'                  d       ||ur|j)                          w w xY w)a]  
        Sign data in a file or file-like object.

        Args:
            fileobj_or_path (str|file): The file or file-like object to sign.

            keyid (str): The key id of the signer.

            passphrase (str): The passphrase for the key.

            clearsign (bool): Whether to use clear signing.

            detach (bool): Whether to produce a detached signature.

            binary (bool): Whether to produce a binary signature.

            output (str): The path to write a detached signature to.

            extra_args (list[str]): Additional arguments to pass to `gpg`.
        Invalid passphrasezsign_file: %sz-sz-saz--detach-signz--clearsign--default-keyr  Nzerror writing messager  )r  r0  r,   r4   r   r  r!   r  r  r  r  r)   rI   r#   rE   r7   r3   loggingr1   r   r2   r  )r`   r  r   rH   	clearsigndetachr  r  
extra_argsr?   r   r  r  r)   r  s                  r   r  zGPG.sign_fileL  s   : d66zB122_o66D7D KK(KK&KK(5/:;00v>KK
#((. ##O4!!$
$(>?	 GGE!%T]]C(%9I9IJF
 D!o-Q6  	56F	 D!o- .s$   %<E  F?F FF *F/c                 x    t        || j                        } | j                  |fi |}|j                          |S )a  
        Verify the signature on the contents of the string *data*. This method delegates most of the work to
        `verify_file()`.

        Args:
            data (str|bytes): The data to verify.
            kwargs (dict): Keyword arguments, which are passed to `verify_file()`:

                * fileobj_or_path (str|file): A path to a signature, or a file-like object containing one.

                * data_filename (str): If the signature is a detached one, the path to the data that was signed.

                * close_file (bool): If a file-like object is passed in, whether to close it.

                * extra_args (list[str]): Additional arguments to pass to `gpg`.
        )rZ   r#   verify_filer2   )r`   r:   r   r  r   s        r   r  z
GPG.verify  s9    "  dmm4!!!!.v.		r   c                    t         j                  d||        | j                  d   |       }dg}|r|j                  |       || j	                  |||d       |S t         j                  d       ddl}|j                  d	
      \  }}	|j                         }
|r|j                          t         j                  d|
       t        j                  ||
       t        j                  |       |j                  t        |	             |j                  t        |             	 | j                  |      }| j                  |||j                         t        j                   |	       |S # t        j                   |	       w xY w)a  
        Verify a signature.

        Args:
            fileobj_or_path (str|file): A path to a signature, or a file-like object containing one.

            data_filename (str): If the signature is a detached one, the path to the data that was signed.

            close_file (bool): If a file-like object is passed in, whether to close it.

            extra_args (list[str]): Additional arguments to pass to `gpg`.
        zverify_file: %r, %rr  --verifyNTr  zHandling detached verificationr   pygpg-prefixzWrote to temp file: %rr  )r,   r4   r  r  r  tempfilemkstempr*   r2   r  r/   r   r!   r  r  r)   remove)r`   r  data_filename
close_filer#  r   r?   r,  fdr  r   r  s               r   r%  zGPG.verify_file  s<    	*O]K**40|KK
# OOD/6$OG$ ! LL9:%%X%6FB$$&A%%'LL115HHROHHRLKK%KK/0))$/$$Qagg$>		" 		"s   "/E( (E?c                    t         j                  d||dd         | j                  d   |       }dg}|r|j                  |       |j                  t	        |      dg       t        |      }| j                  |||d       |S )	a  
        Verify the signature in sig_filename against data in memory

        Args:
            sig_filename (str): The path to a signature.

            data (str|bytes): The data to be verified.

            extra_args (list[str]): Additional arguments to pass to `gpg`.
        zverify_data: %r, %r ...Nr  r  r'  -Tr(  )r,   r4   r  r  r!   rW   r  )r`   sig_filenamer:   r#  r   r?   rG   s          r   verify_datazGPG.verify_data  s     	.d3BiH**40|KK
#Xl+S12$T*ffT:r   c                 F    | j                   d   |       }t        j                  d|dd        t        || j                        }dg}|r|j                  |       | j                  ||||d       t        j                  d|j                         |j                          |S )	a  
        Import the key_data into our keyring.

        Args:
            key_data (str|bytes): The key data to import.

            passphrase (str): The passphrase to use.

            extra_args (list[str]): Additional arguments to pass to `gpg`.
        r  zimport_keys: %rNr  --importTrH   r  zimport_keys result: %r)	r  r,   r4   rZ   r#   r  r  __dict__r2   )r`   key_datar#  rH   r   r:   r?   s          r   import_keyszGPG.import_keys  s     +*40&#7"8T]];|KK
#dFz$O-v?

r   c                     t        |d      5 } | j                  |j                         fi |cddd       S # 1 sw Y   yxY w)z
        Import the key data in key_path into our keyring.

        Args:
            key_path (str): A path to the key data to be imported.
        r
  N)r  r;  r*   )r`   key_pathr   r  s       r   import_keys_filezGPG.import_keys_file  s@     (D! 	8Q#4##AFFH77	8 	8 	8s	   !8Ac                     | j                   d   |       }t        j                  d|       t        d| j                        }dt        |      g}d|v r|j                  |d          |j                  d       |j                  |D cg c]  }t        |       c}       | j                  |||d       t        j                  d	|j                         |j                          |S c c}w )
z
        Import one or more keys from a keyserver.

        Args:
            keyserver (str): The key server hostname.

            keyids (str): A list of key ids to receive.
        r  zrecv_keys: %rrb  --keyserverr#  z--recv-keysTr(  zrecv_keys result: %rr  r,   r4   rZ   r#   r!   r  r   r  r9  r2   r`   	keyserverkeyidsr   r   r:   r?   r!  s           r   	recv_keyszGPG.recv_keys	  s     +*40_f-"2t}}5x	236!KK|,-M"&1QXa[12dF48+V__=

	 2   C'c                     | j                   d   |       }t        j                  d|       t        d| j                        }dt        |      g}d|v r|j                  |d          |j                  d       |j                  |D cg c]  }t        |       c}       | j                  |||d       t        j                  d	|j                         |j                          |S c c}w )
z
        Send one or more keys to a keyserver.

        Args:
            keyserver (str): The key server hostname.

            keyids (list[str]): A list of key ids to send.
        r  zsend_keys: %rrb  r@  r#  z--send-keysTr(  zsend_keys result: %rrA  rB  s           r   	send_keyszGPG.send_keys!  s     )(._f-"2t}}5x	236!KK|,-M"&1QXa[12dF48+V__=

	 2rF  c                    |r| j                  |      st        d      d}|r | j                  dk\  r||rt        d      d}t        |      r|D cg c]  }t	        |       }}nt	        |      g}|r|D cg c]  }|dz   	 }}d|z  g}	|r!| j                  dk\  r|	j                  dd	       |	j                  |        | j                  d
   |       }
|r| j                  dk  r1| j                  |	      }| j                  ||
|j                         |
S t        d| j                        }	 | j                  |	||
|d       |j                          |
S c c}w c c}w # |j                          w xY w)a9  
        Delete the indicated keys.

        Args:
            fingerprints (str|list[str]): The keys to delete.

            secret (bool): Whether to delete secret keys.

            passphrase (str): The passphrase to use.

            expect_passphrase (bool): Whether a passphrase is expected.

            exclamation_mode (bool): If specified, a `'!'` is appended to each fingerprint. This deletes only a subkey
                                     or an entire key, depending on what the fingerprint refers to.

        .. note:: Passphrases

           Since GnuPG 2.1, you can't delete secret keys without providing a passphrase. However, if you're expecting
           the passphrase to go to `gpg` via pinentry, you should specify expect_passphrase=False. (It's only checked
           for GnuPG >= 2.1).
        r  re   r  zHFor GnuPG >= 2.1, deleting secret keys needs a passphrase to be providedz
secret-key!z--delete-%sr   r  r  r  rb  Tr8  )r  r0  r  rQ   r!   insertr  r  r  r  r)   rZ   r#   r  r2   )r`   r   secretrH   expect_passphraseexclamation_modewhichr   r  r?   r   r  s               r   delete_keyszGPG.delete_keys;  sv   , d66zB122||v%**<AR  "E F F E%1=>AHQK>L>$\23L-9:AG:L:%&dllf,KK7#L!**40.%%d+A  F!'' :  $B6AaJtT	- ?
 ;  	s   E9E/E! !E3c                    |r| j                  |      st        d      d}|r d}| j                  dk\  r||rt        d      t        |      r|D 	cg c]  }	t	        |	       }}	nt	        |      g}d|z  g}
|r|
j                  d       |r|
j                  d	d
g       |r| j                  |
|       |
j                  |        | j                  d   |       }|r| j                  dk  r0| j                  |
      }| j                  |||j                         n=t        d| j                        }	 | j                  |
|||d       |j                          t         j#                  d|j$                  dd        |j$                  }|r&|j'                  | j                  | j(                        }|S c c}	w # |j                          w xY w)at  
        Export the indicated keys. A 'keyid' is anything `gpg` accepts.

        Args:
            keyids (str|list[str]): A single keyid or a list of them.

            secret (bool): Whether to export secret keys.

            armor (bool): Whether to ASCII-armor the output.

            minimal (bool): Whether to pass `--export-options export-minimal` to `gpg`.

            passphrase (str): The passphrase to use.

            expect_passphrase (bool): Whether a passphrase is expected.

            output (str): If specified, the path to write the exported key(s) to.

        .. note:: Passphrases

           Since GnuPG 2.1, you can't export secret keys without providing a passphrase. However, if you're expecting
           the passphrase to go to `gpg` via pinentry, you should specify expect_passphrase=False. (It's only checked
           for GnuPG >= 2.1).
        r  rb  z-secret-keyr  NzIFor GnuPG >= 2.1, exporting secret keys needs a passphrase to be providedz
--export%s--armorz--export-optionszexport-minimalr  r  Tr8  zexport_keys result[:100]: %rd   )r  r0  r  rQ   r!   r   r  r  r  r  r  r)   rZ   r#   r  r2   r,   r4   r:   rL  rM  )r`   rD  rL  armorminimalrH   rM  r  rO  r!  r?   r   r  r  s                 r   export_keyszGPG.export_keysr  s   @ d66zB122!E||v%**<AR  "E F F+12ahqk2F2v&'Fu$%KK	"KK+-=>?00v>F +*40.%%d+A  F!'' : $B6AaJtT	3V[[#5FG]]4==$2D2DEF= 30 	s   F23F7 7G	c                    |j                   j                  | j                  | j                        j	                         }dj                         }|D ]  }| j                  rt        |       t        j                  d|j                                |s |S |j                         j                  d      }|se|d   }||v so t        ||      |        |S )Nzpub uid sec fpr sub ssb sig grpline: %rrY  r   )r:   rL  r#   rM  
splitlinesr   r  r  r,   r4   r  stripgetattr)r`   r   r  valid_keywordsr  r  r  s          r   _decode_resultzGPG._decode_result  s    ""4==$2D2DEPPR:@@B 	,D||dLLT[[]3  

""3'AdG.(((+	, r   c                      | j                   |   |       }| j                  |||j                         | j                  |      S )Nr  )r  r  r)   r]  )r`   r  kindr   s       r   _get_list_outputzGPG._get_list_output  sA    &&t,Qagg6""6**r   c                     |rd}n|rdnd}d|z  ddg}| j                   dk\  r|j                  d       |r$t        |t              r|g}|j	                  |       | j                  |      }| j                  |d      S )	aZ  
        List the keys currently in the keyring.

        Args:
            secret (bool): Whether to list secret keys.

            keys (str|list[str]): A list of key ids to match.

            sigs (bool): Whether to include signature information.

        Returns:
            list[dict]: A list of dictionaries with key information.
        zsecret-keysr  keysz	--list-%s--fingerprintr  z--with-keygriprL   )r  r   r   r   r  r  r`  )r`   rL  rb  r  rO  r?   r  s          r   	list_keyszGPG.list_keys  s     !E"FEe#_oF<<6!KK()$-vKK!!$'$$Q//r   c                     | j                   dk\  rg d}nt        j                  d       g d}|j                  t	        |             | j                  |      }| j                  |d      S )a  
        List details of an ascii armored or binary key file without first importing it to the local keyring.

        Args:
            filename (str): The path to the file containing the key(s).

        .. warning:: Warning:
            Care is needed. The function works on modern GnuPG by running:

                $ gpg --dry-run --import-options import-show --import filename

            On older versions, it does the *much* riskier:

                $ gpg --with-fingerprint --with-colons filename
        r  z	--dry-runz--import-optionszimport-showr7  TTrying to list packets, but if the file is not a keyring, might accidentally decryptz--with-fingerprintr  r  r  )r  r,   r-   r   r!   r  r`  )r`   filenamer?   r  s       r   	scan_keyszGPG.scan_keys  sa      <<6!ODNN A BODHX&'!!$'$$Q//r   c                     | j                   d   |       }t        j                  d|dd        t        || j                        }| j
                  dk\  rg d}nt        j                  d       g d}| j                  |||d	
       t        j                  d|j                         |j                          | j                  |      S )a  
        List details of an ascii armored or binary key without first importing it to the local keyring.

        Args:
            key_data (str|bytes): The key data to import.

        .. warning:: Warning:
            Care is needed. The function works on modern GnuPG by running:

                $ gpg --dry-run --import-options import-show --import filename

            On older versions, it does the *much* riskier:

                $ gpg --with-fingerprint --with-colons filename
        r  zscan_keys: %rNr  r  rf  rg  rh  Tr(  zscan_keys result: %r)r  r,   r4   rZ   r#   r  r-   r  r9  r2   r]  )r`   r:  r   r:   r?   s        r   scan_keys_memzGPG.scan_keys_mem  s      )(._htn5"8T]];<<6!ODNN A BODdF48+V__=

""6**r   c                    |j                         }t        j                  |      rd|z   }ddt        |      g}|r|j	                  |       |j	                  dt        |      g       | j                  |      } | j                  d   |       }| j                  |||j                         |j                  j                  | j                  | j                        j                         }ddg}|D ]~  }	| j                  rt        |	       t         j#                  d	|	j%                                |	sA|	j                         j'                  d
      }
|
sc|
d   }||v sm t)        ||      |
        |S )a  
        search a keyserver by query (using the `--search-keys` option).

        Args:
            query(str): The query to use.

            keyserver (str): The key server hostname.

            extra_args (list[str]): Additional arguments to pass to `gpg`.
        0xrc  r@  z--search-keysr   r  r  r   rX  rY  r   )rZ  HEX_DIGITS_REr  r!   r  r  r  r  r)   r:   rL  r#   rM  rY  r  r  r,   r4   r  r   r[  )r`   queryrC  r#  r?   r  r   r  r\  r  r  r  s               r   search_keyszGPG.search_keys)  sI    u%5LE0CDKK
#_huo67!!$' +*40Qagg6""4==$2D2DEPPR 	,D||dLLT[[]3

""3'AdG.(((+	, r   c                     dg} | j                   d   |       }t        || j                        }| j                  |||d       |j	                          |S )z
        Generate a key; you might use `gen_key_input()` to create the input.

        Args:
            input (str): The input to the key creation operation.
        z	--gen-keyr  Tr(  )r  rZ   r#   r  r2   )r`   inputr?   r   r  s        r   gen_keyzGPG.gen_keyP  sR     },,T2t}}5a5		r   c                    i }|j                  dd      }t        |j                               D ]D  \  }}|j                  dd      j	                         }t        |      j                         s@|||<   F |j                  dd       d|vr|j                  dd	       |j                  d
d       t        j                  j                  d      xs# t        j                  j                  d      xs d}t        j                         }|j                  d|j                  dd      d|       d|j                  d      z  }t        |j                               D ]  \  }}||d|dz  } |r|dz  }|dz  }|S )z
        Generate `--gen-key` input  (see `gpg` documentation in DETAILS).

        Args:
            kwargs (dict): A list of keyword arguments.
        Returns:
            str: A string suitable for passing to the `gen_key()` method.
        no_protectionFrm  r3  zKey-TypeRSA	key_curvez
Key-Lengthi   z	Name-RealzAutogenerated KeyLOGNAMEUSERNAMEunspecifiedz
Name-Emailr   @zKey-Type: %s
r   r   z%no-protection
z%commit
)poprL   r   r   titlerY   rZ  r8  r  r  r[  socketgethostname)	r`   r   parmsrv  re   vallognamehostnameouts	            r   gen_key_inputzGPG.gen_key_input^  sV    

?E:V\\^, 	!HC++c3'--/C3x~~ c
	! 	U+f$\40&9:::>>),[

z0J[m%%''//#s2KX'VW:!66U[[]+ 	+HCc**C	+%%C{
r   c                 8   | j                   d   dk  rt        d      |st        d      |r| j                  |      st        d      d|||t	        |      g} | j
                  d   |       }t        d| j                        }| j                  ||||d	
       |S )ae  
        Add subkeys to a master key,

        Args:
            master_key (str): The master key.

            master_passphrase (str): The passphrase for the master key.

            algorithm (str): The key algorithm to use.

            usage (str): The desired uses for the subkey.

            expire (str): The expiration date of the subkey.
        r   rn   zNot available in GnuPG 1.xz#No master key fingerprint specifiedr  z--quick-add-keyr  rb  Tr8  )	r  rc   r0  r  rY   r  rZ   r#   r  )	r`   
master_keymaster_passphrase	algorithmusageexpirer?   r   r  s	            r   
add_subkeyzGPG.add_subkey  s     <<?Q%&BCCBCCT%=%=>O%P122!:y%VM--d3DMM2a4EdSr   c
                    |r| j                  |      st        d      dg}
|r$dg}
|dur[|
j                  dt        |      g       n>|st        d      t	        |      s|f}|D ]  }|
j                  dt        |      g         |r|
j                  d       |r| j                  |
|       |du r|
j                  d	       n|r|
j                  d	d
t        |      g       |r|
j                  ddg       |	r|
j                  |	        | j                  d   |       }| j                  |
|||d       t        j                  d|j                  dd        |S )a*  
        Encrypt data in a file or file-like object.

        Args:
            fileobj_or_path (str|file): A path to a file or a file-like object containing the data to be encrypted.

            recipients (str|list): A key id of a recipient of the encrypted data, or a list of such key ids.

            sign (str): If specified, the key id of a signer to sign the encrypted data.

            always_trust (bool): Whether to always trust keys.

            passphrase (str): The passphrase to use for a signature.

            armor (bool): Whether to ASCII-armor the output.

            output (str): A path to write the encrypted output to.

            symmetric (bool): Whether to use symmetric encryption,

            extra_args (list[str]): A list of additional arguments to pass to `gpg`.
        r  z	--encryptz--symmetricTz--cipher-algoz2No recipients specified with asymmetric encryptionz--recipientrR  z--signr  --trust-modelalwaysr  r8  zencrypt result[:100]: %rNrS  )r  r0  r  r!   rQ   r   r  r  r  r,   r4   r:   )r`   r  
recipientsr  always_trustrH   rT  r  	symmetricr#  r?   	recipientr   s                r   encrypt_filezGPG.encrypt_file  s\   @ d66zB122} "?D$_hy.ABC   ". / /
+(^
' B	]HY,?@ABKK	"00v>4<KK!KK?HTNCDKK(34KK
#))$/ov*UYZ/Tc1BCr   c                 z    t        || j                        } | j                  ||fi |}|j                          |S )a  
        Encrypt the message contained in the string *data* for *recipients*. This method delegates most of the work to
        `encrypt_file()`.

        Args:
            data (str|bytes): The data to encrypt.

            recipients (str|list[str]): A key id of a recipient of the encrypted data, or a list of such key ids.

            kwargs (dict): Keyword arguments, which are passed to `encrypt_file()`:
                * sign (str): If specified, the key id of a signer to sign the encrypted data.

                * always_trust (bool): Whether to always trust keys.

                * passphrase (str): The passphrase to use for a signature.

                * armor (bool): Whether to ASCII-armor the output.

                * output (str): A path to write the encrypted output to.

                * symmetric (bool): Whether to use symmetric encryption,

                * extra_args (list[str]): A list of additional arguments to pass to `gpg`.
        )rZ   r#   r  r2   )r`   r:   r  r   r   s        r   encryptzGPG.encrypt  s;    2 #47"""4>v>

r   c                 x    t        || j                        } | j                  |fi |}|j                          |S )ac  
        Decrypt the data in *message*. This method delegates most of the work to
        `decrypt_file()`.

        Args:
            message (str|bytes): The data to decrypt. A default key will be used for decryption.

            kwargs (dict): Keyword arguments, which are passed to `decrypt_file()`:

                * always_trust: Whether to always trust keys.

                * passphrase (str): The passphrase to use.

                * output (str): If specified, the path to write the decrypted data to.

                * extra_args (list[str]): A list of extra arguments to pass to `gpg`.
        )rZ   r#   decrypt_filer2   r`   r   r   r:   r   s        r   decryptzGPG.decrypt  s9    $ #7DMM:"""4262

r   c                 \   |r| j                  |      st        d      dg}|r| j                  ||       |r|j                  ddg       |r|j                  |        | j                  d   |       }| j                  ||||d       t        j                  d|j                  d	d
        |S )a  
        Decrypt data in a file or file-like object.

        Args:
            fileobj_or_path (str|file): A path to a file or a file-like object containing the data to be decrypted.

            always_trust: Whether to always trust keys.

            passphrase (str): The passphrase to use.

            output (str): If specified, the path to write the decrypted data to.

            extra_args (list[str]): A list of extra arguments to pass to `gpg`.
        r  	--decryptr  r  r  Tr(  zdecrypt result[:100]: %rNrS  )	r  r0  r  r  r  r  r,   r4   r:   )r`   r  r  rH   r  r#  r?   r   s           r   r  zGPG.decrypt_file/  s     d66zB122}00v>KK(34KK
#))$/ovz$O/Tc1BCr   c                 x    t        || j                        } | j                  |fi |}|j                          |S )a   Get the list of recipients for an encrypted message. This method delegates most of the work to
        `get_recipients_file()`.

        Args:
            message (str|bytes): The encrypted message.

            kwargs (dict): Keyword arguments, which are passed to `get_recipients_file()`:

                * extra_args (list[str]): A list of extra arguments to pass to `gpg`.
        )rZ   r#   get_recipients_filer2   r  s        r   get_recipientszGPG.get_recipientsM  s9     #7DMM:)))$9&9

r   c                    g d}|r|j                  |        | j                  d   |       }| j                  |||d       g }t        j	                  |j
                        D ]"  }|j                  |j                  d             $ |S )a0  
        Get the list of recipients for an encrypted message in a file or file-like object.

        Args:
            fileobj_or_path (str|file): A path to a file or file-like object containing the encrypted data.

            extra_args (list[str]): A list of extra arguments to pass to `gpg`.
        )r  z--list-onlyz-vr  Tr(  r%   )r  r  r  PUBLIC_KEY_REfinditerr  r   r  )r`   r  r#  r?   r   idsr  s          r   r  zGPG.get_recipients_file]  s}     2KK
#))$/ovdC''6 	#AJJqwwqz"	#
r   c                 ~   t         j                  }||vr,dj                  t        |            }t	        d|d|d      ||   dz   }ddl}	 |j                  d	      \  }}g }t        |t              r|g}|D ]  }	|j                  |	d
|d
        t        j                  j                  |      t        j                  z   }
t        j                  d|
       t        j                  ||
j                  | j                                t        j"                  |        | j$                  d   |       }| j'                  d|g      }| j)                  |||j*                         |j,                  dk7  rt	        d|j,                  z        	 t        j.                  |       |S # t        j.                         w xY w)aY  
        Set the trust level for one or more keys.

        Args:
            fingerprints (str|list[str]): A key id for which to set the trust level, or a list of such key ids.

            trustlevel (str): The trust level. This is one of the following.

                                  * ``'TRUST_EXPIRED'``
                                  * ``'TRUST_UNDEFINED'``
                                  * ``'TRUST_NEVER'``
                                  * ``'TRUST_MARGINAL'``
                                  * ``'TRUST_FULLY'``
                                  * ``'TRUST_ULTIMATE'``
        r   zInvalid trust level: "z" (must be one of )r%   r   Nr)  r*  rY  zwriting ownertrust info: %sr  z--import-ownertrustr  z&gpg returned an error - return code %d)rm   r   r   sortedr0  r,  r-  r   r   r   r  linesepr,   r4   r/   r   r#   r2   r  r  r  r)   r   r.  )r`   r   
trustlevellevelspossr,  r1  r  r  r  r   r   r  s                r   
trust_keyszGPG.trust_keysp  s|     $$V#99VF^,DPZ\`abbJ'!+
	%%X%6FBE,5 ,~! 9J789 

&3ALL6:HHR$--01HHRL-T__W-d3F%%'<b&ABA  F!'' :||q  !IALL!XYY ! IIbM IIbMs   D?F% %F<)r^   NFFNNNN)F)Ni   )NNr}   )NNTFFNN)NTNrK   )FNTF)FTFNTN)FNF)zpgp.mit.eduN)Nrsar  r3  )NFNTNFN)FNNN);rh   ri   rj   rk   r   rM  r7   r`  r  r  r  r   r  r%  rG  r	  r  r  rm   r  r  ra   r  r  r  r  r  r  r  r  r  r  r  r  r  r%  r5  r;  r>  rE  rH  rP  rV  r]  r`  rd  rj  rl  rq  rt  r  r  r  r  r  r  r  r  r  r   r   r   r  r    sw    IMK J 6 !  $M2^!F&'8*.!F	(	 264` ! !EN,%N2,8045r !!#&*GR"+0>04+<%NjL "' $ $ $BH<.< &)r   r  )Nrk   r  rT   r   r   r  rer  r  r   r   r(   r@   __version__
__author____date__r   namer   r	   rU   unicoder   
basestringr   r   bytesrY   r  	NameError	getLoggerrh   r,   handlers
addHandlerNullHandlerr  r  r   compiler   getfilesystemencodingr    r!   r;   rE   rI   rQ   rW   rZ   objectr\   rm   r   Ir  r  r  r  rL   r	  r%  rG  rJ  rZ  r^  r`  r  r  r  r  r  r  r   r  ro  r  r  r   r   r   <module>r     s  !F    	 	  " 
 
#77d?II
ELIJ 
		8	$
)g))+,  77x RZZ)*FB 'S&&(
!7H%?""F "6@] @DT!= T!n 4bdd;7 7(/ /dbAz bAJx "&  " $' &% >3FK >3B!@] !@H@ @>@6 @= @	, 	.@=+ .@b RZZ5<<WEF


="$$/

67i& iu    ELIJ	s$   
H6 I 6I III