o `.E@s4dZddlmZddlmZddlmZddlZddlZddlZddlZddl Z ddl Z ddl m Z ddl m Z ddl mZdd l mZzdd lmZdd lmZWneygdd lmZdd lmZYnwd ZGdddeZGdddeZGdddeZ  d!ddZd"ddZd#ddZd$dd ZdS)%z duplicity's gpg interface, builds upon Frank Tobin's GnuPGInterface which is now patched with some code for iterative threaded execution see duplicity's README for details )next)str)objectN)config) gpginterface)tempdir)util)sha1)md5)newic@seZdZdZdS)GPGErrorz! Indicate some GPG Error N)__name__ __module__ __qualname____doc__rr//usr/lib/python3/dist-packages/duplicity/gpg.pyr 5sr c@s4eZdZdZ  dddZejZedZddZ dS) GPGProfilezF Just hold some GPG settings, avoid passing tons of arguments NcCs|dust|tdjfsJ||_||_||_d|_|dur)t|ts%J||_ng|_|dur;t|ts7J||_ ng|_ | t j |_ dS)a> Set all data with initializer passphrase is the passphrase. If it is None (not ""), assume it hasn't been set. sign_key can be blank if no signing is indicated, and recipients should be a list of keys. For all keys, the format should be an hex key like 'AA0E73D2'. N) isinstancer __class__ passphrasesigning_passphrasesign_keyencrypt_secringlist recipientshidden_recipientsget_gpg_versionr gpg_binary gpg_version)selfrrrrrrr__init__@s zGPGProfile.__init__sU^gpg.*\(GnuPG(?:/MacGPG2)?\) (?P[0-9]+)\.(?P[0-9]+)\.(?P[0-9]+)(-.+)?$cCst}|dur ||_tjrtjD] }|jj|q|j dgdgd}|j d }|j |}|durMt|dt|dt|dfStd||f)Nz --versionstdout) create_fhsmajminbugz/failed to determine gnupg version of %s from %s)rGnuPGcallr gpg_optionssplitoptions extra_argsappendrunhandlesreadlinerstrip _version_researchintgroupr )r!binarygnupgoptreslinemrrrras (zGPGProfile.get_gpg_version)NNNN) r rrrr"recompilercr3rrrrrr<s  rc@sZeZdZdZddZdddZddZd d Zd d Zd dZ ddZ ddZ ddZ dS)GPGFilezI File-like object that encrypts decrypts another file on the fly c Csd|_d|_tjtd|_tjtd|_||_ d|_ t }t jdur/t j|_d|j_|jjd|jjd|jdddkrUt jrT|jjdn%|jdd d kr_n|jdd d krst jsr|jjd ntd |jt jrt jD] }|jj|qg}|jr|j|j_|d|r|jr|jr|j}n|j}|durd}|r|jr|j|j_|d|jr|j|j_|d|js|js|d|jjdt jrdg}nddg}|j||| d|j|jdd} t js| j!d"|| j!d#| j!d|_$n[|js|jr,|j%r,|d||j%tjtd|_t jr?dg}nddg}|jdg|| d|j|j|jdd} t jsj| j!d"|| j!d#| j!d|_&| |_'||_(dS)a GPGFile initializer If recipients is set, use public key encryption and encrypt to the given keys. Otherwise, use symmetric encryption. encrypt_path is the Path of the gpg encrypted file. Right now only symmetric encryption/decryption is supported. If passphrase is false, do not set passphrase - GPG program should prompt for it. N)dirrz--no-secmem-warningz--ignore-mdc-errorrBz --use-agent)rDr)rDrBz--pinentry-mode=loopbackzUnsupported GNUPG version, %sz--signrz --encryptz --symmetricz --force-mdcstdinrwb)r#stderrlogger)r$ attach_fhsz--secret-keyringr#z --decryptrb)rEstatusrGrH)) status_fpclosedtempfile TemporaryFilerdefaultrA logger_fp stderr_fpname byte_countrr(rrr)r,meta_interactiver-r.r use_agentr r*r+r default_keyrrrrr/openr0writeclose gpg_inputr gpg_output gpg_processencrypt) r!r^ encrypt_pathprofiler8r9cmdlistr gnupg_fhsp1rrrr"xs               zGPGFile.__init__cCsPz|j|}|dur|jt|7_W|SW|Sty'|Y|SwN)r\readrTlen Exception gpg_failed)r!lengthr:rrrrfs  z GPGFile.readcCspz)|j|}|dur'tjjdkr|j|7_W|S|jt|7_W|SW|Sty7|Y|Sw)N) r[rYsys version_infomajorrTrgrhri)r!bufr:rrrrYs   z GPGFile.writecCs|jSre)rTr!rrrtellsz GPGFile.tellcCsH|jrJ||jksJd||jf||jkr"|||jdSdS)Nz%d < %d)r^rTrf)r!offsetrrrseeks  z GPGFile.seekc Csd}|d7}|j|jfD]6}|d|D],}z|t|tdd7}WqtyA}z||d7}WYd}~qd}~wwq |d7}|ddksRt |d S) NzGPG Failed, see log below: z===== Begin GnuPG log ===== rreplace z===== End GnuPG log ===== zinvalid packet (ctb=14)rdr) rQrRrsrstriplocalegetpreferredencodingrhfindr )r!msgfpr;errrris   zGPGFile.gpg_failedcCs |jr4z|jWn ty|Ynw|jr|z|jWnZty3|YnNwd}|rPz|j t }Wn tyM|Ynw|s8z|j Wn tyd|Ynw|jrl|z|jWn ty|Ynw|j |j d|_dS)NrB)r^r[rZrhrirL set_signaturer]waitr\rf blocksizerQrRrM)r!r:rrrrZsH             z GPGFile.closecCs^|jd|j}td|tj}|sd|_dSt|ddks%J|d |_dS)z Set self.signature to signature keyID This only applies to decrypted files. If the file was not signed, set self.signature to None. rs^\[GNUPG:\] GOODSIG ([0-9A-F]*)NrB) rLrsrfr=r4M signaturergr6decode)r! status_bufmatchrrrr}:s   zGPGFile.set_signaturecCs|jsJ|jS)z= Return keyID of signature, or None if none )rMrrprrr get_signatureKs zGPGFile.get_signatureN)rd) r rrrr"rfrYrqrsrirZr}rrrrrr@ts r  " r@ @csddlm}fdd}fdd}|d}||} td||} d} zD | |} | |kr3nz|j} Wn tyEd } Ynw| | q'| | | sc|}||krc|||| | | WSt yu| w) aJ Write GPG compressed file of given size This function writes a gpg compressed file by reading from the input iter and writing to filename. When it has read an amount close to the size limit, it "tops off" the incoming data with incompressible data, to try to hit the limit exactly. block_iter should have methods .next(size), which returns the next block of data, which should be at most size bytes long. Also .get_footer() returns a string to write at the end of the input file. The footer should have max length max_footer_size. Because gpg uses compression, we don't assume that putting bytes_in bytes into gpg will result in bytes_out = bytes_in out. However, do assume that bytes_out <= bytes_in approximately. Returns true if succeeded in writing until end of block_iter. r)pathcs.td}t||j||ksJ|dS)z Add bytelen of incompressible data to to_gpg_fp In this case we take the incompressible data from the beginning of filename (it should contain enough because size >> largest block size). rJN)rXr copyfileobjr[rZ)bytelenfileincompressible_fpfilenamerrtop_offms  zGPGWriteFile..top_offcs tjSre)osstatst_sizerrrrget_current_sizeys z&GPGWriteFile..get_current_sizeiTrB) duplicityrr@Path get_read_size__next__data StopIterationrY get_footerrZrh) block_iterrr`sizemax_footer_sizerrr target_size data_sizerat_end_of_blockiter bytes_to_gorcursizerrr GPGWriteFileSs>         rTc CsGdddt}|t|d}|rtddd|}n|}d} ||j}||kr+nzt|} Wn ty<d}Ynw|| j q| sL| rNJ|S) a Write gzipped compressed file of given size This is like the earlier GPGWriteFile except it writes a gzipped file instead of a gpg'd file. This function is somewhat out of place, because it doesn't deal with GPG at all, but it is very similar to GPGWriteFile so they might as well be defined together. The input requirements on block_iter and the output is the same as GPGWriteFile (returns true if wrote until end of block_iter). c@s(eZdZdZddZddZddZdS) z"GzipWriteFile..FileCountedzP Wrapper around file object that counts number of bytes written cSs||_d|_dS)Nr)fileobjrT)r!rrrrr"s z+GzipWriteFile..FileCounted.__init__cSs"|j|}|jt|7_|Sre)rrYrTrg)r!roresultrrrrYs z(GzipWriteFile..FileCounted.writecSs |jSre)rrZrprrrrZs z(GzipWriteFile..FileCounted.closeN)r rrrr"rYrZrrrr FileCounteds  rrFNrTrB) rrXgzipGzipFilerTrrrrYrrZ) rrrgzippedr file_countedoutfilerr new_blockrrr GzipWriteFiles(       rFcCst||||S)a Write plain uncompressed file of given size This is like the earlier GPGWriteFile except it writes a gzipped file instead of a gpg'd file. This function is somewhat out of place, because it doesn't deal with GPG at all, but it is very similar to GPGWriteFile so they might as well be defined together. The input requirements on block_iter and the output is the same as GPGWriteFile (returns true if wrote until end of block_iter). )r)rrrrrrrPlainWriteFiles rrBcCsv|d}|dkr t}n|dkrt}nJd|f |t}|s%n||q|r1J|r7|S|S)z Return hash of path hash should be "MD5" or "SHA1". The output will be in hexadecimal form if hex is true, and in text (base64) otherwise. rJSHA1MD5rzUnknown hash %s) rXr r rfrupdaterZ hexdigestdigest)hashrhexr{hash_objrorrrget_hashs    r)rr)rT)rFrC)rbuiltinsrrrrrlrNr=rrwrrrrrhashlibr r ImportErrorshar rrhr rr@rrrrrrrrs@          8a G 3