U
    giD                  
   @   sN  d Z ddlZddlmZ ddlmZ ddlmZmZ ddlm	Z	 ddl
mZmZmZmZ dd	lmZ dd
lmZ ddlmZmZ ddddddgZeddG dd dZG dd dejZeddG dd dZeddG dd dZejedddZdddddddddeee eee	j  eej  eee ee ej!dddZ"dS )zO
Utility classes for handling embedded files in PDFs.

.. versionadded:: 0.7.0
    N)	dataclass)datetime)ListOptional)x509   )cryptgenericmiscwriter)RecipientEncryptionPolicy)get_courier)pdf_name
pdf_string
embed_fileEmbeddedFileObjectEmbeddedFileParamsFileSpecRelatedFileSpecwrap_encrypted_payloadT)frozenc                   @   sF   e Zd ZU dZeed< dZeed< dZee	 ed< dZ
ee	 ed< dS )r   T
embed_sizeembed_checksumNcreation_datemodification_date)__name__
__module____qualname__r   bool__annotations__r   r   r   r   r    r    r    ;/tmp/pip-unpacked-wheel-owvgwkas/pyhanko/pdf_utils/embed.pyr      s
   


c                       sf   e Zd Zedejeee ee	 d dddZ
dejee ee	 d fddZd fd	d
	Z  ZS )r   TN)
pdf_writerdataparams	mime_typereturnc                 C   s    t ||||d}|r|  |S )a  
        Construct an embedded file object from file data.

        This is a very thin wrapper around the constructor, with a slightly
        less intimidating API.

        .. note::
            This method will not register the embedded file into the document's
            embedded file namespace, see :func:`.embed_file`.

        :param pdf_writer:
            PDF writer to use.
        :param data:
            File contents, as a :class:`bytes` object.
        :param compress:
            Whether to compress the embedded file's contents.
        :param params:
            Optional embedded file parameters.
        :param mime_type:
            Optional MIME type string.
        :return:
            An embedded file object.
        )r"   stream_datar$   r%   )r   compress)clsr"   r#   r(   r$   r%   resultr    r    r!   from_file_data?   s    !z!EmbeddedFileObject.from_file_data)r"   r$   r%   c                    sT   t  j||||jd td| d< |d k	r>td| | d< || | _|| _d S )N)	dict_datar'   encoded_datahandlerz/EmbeddedFile/Type/z/Subtype)super__init__security_handlerr	   r   
add_objectef_stream_refr$   )selfr"   r,   r'   r-   r$   r%   	__class__r    r!   r2   k   s    	zEmbeddedFileObject.__init__c           
         s   |d k	r:| j s:|j}|j}|j}|d k	r:||kr:| | | j}|d k	rt  | d< }|jrrt	t
| j|d< |jrt| j }	t|	|d< |jd k	rt|j|d< |jd k	rt|j|d< t j|||d d S )Nz/Paramsz/Sizez	/CheckSumz/CreationDatez/ModDate)r.   container_ref)Z_has_crypt_filtercrypt_filter_configZembedded_file_filter_namestream_filter_nameZadd_crypt_filterr$   r	   DictionaryObjectr   ZNumberObjectlenr#   r   hashlibmd5digestZByteStringObjectr   Zpdf_dater   r1   write_to_stream)
r6   streamr.   r9   ZcfcZef_filter_namer;   r$   Z
param_dictZchecksumr7   r    r!   rA      s<    


  z"EmbeddedFileObject.write_to_stream)TNN)NNNNN)NN)r   r   r   classmethodr   BasePdfFileWriterbytesr   r   strr+   r2   rA   __classcell__r    r    r7   r!   r   >   s,      .     c                   @   s8   e Zd ZU dZeed< eed< eed  dddZ	dS )r   z=
    Dataclass modelling a RelatedFile construct in PDF.
    nameembedded_datalstc                    s    fdd}t | S )Nc                  3   s&    D ]} t | jV  | jjV  qd S )N)r	   r   rH   rI   r5   )ZrfsrJ   r    r!   _gen   s    z/RelatedFileSpec.fmt_related_files.<locals>._gen)r	   ArrayObject)r)   rK   rL   r    rJ   r!   fmt_related_files   s    z!RelatedFileSpec.fmt_related_filesN)
r   r   r   __doc__rF   r   r   rC   r   rN   r    r    r    r!   r      s
   
	c                   @   s   e Zd ZU dZeed< dZee ed< dZee	 ed< dZ
ee ed< dZeej ed< dZeee  ed< dZeee  ed	< ejd
ddZdS )r   zD
    Dataclass modelling an embedded file description in a PDF.
    file_spec_stringN	file_namerI   descriptionaf_relationshipf_related_filesuf_related_files)r&   c                 C   s   t tdtdtdt| ji}| jdk	r<t| j|d< | jdk	rzt td| jji |d< }| jdk	rz| jj|d< | jdk	rt 	| j|d< | j
dk	r| j
|d< | j}| j}|s|rt   |d	< }|rt||d< |r| jdk	rt||d< |S )
z>
        Represent the file spec as a PDF dictionary.
        r/   z	/Filespecz/FNz/UFz/EFz/Descz/AFRelationshipz/RF)r	   r<   r   r   rP   rQ   rI   r5   rR   TextStringObjectrS   rT   rU   r   rN   )r6   r*   Zef_dictZ	f_relatedZ
uf_relatedrfr    r    r!   as_pdf_object   s<      

 



zFileSpec.as_pdf_object)r   r   r   rO   rF   r   rQ   r   rI   r   rR   rS   r	   Z
NameObjectrT   r   r   rU   r<   rX   r    r    r    r!   r      s   


)r"   specc           
      C   s  |j }|dkrtd| }| j}z|d }W n2 tk
rd   t }| ||d< | 	  Y nX z|d }W n4 tk
r   t }| ||d< | 
| Y nX d|krtdz|d }W n4 tk
r   t }| ||d< | 
| Y nX |t|j | |}|| | 
| |jdk	r| jdd z|d	 }	W n4 tk
r   t }	| |	|d	< | 	  Y nX |	| n| jd
d dS )z
    Embed a file in the document-wide embedded file registry of a PDF writer.

    :param pdf_writer:
        PDF writer to house the embedded file.
    :param spec:
        File spec describing the embedded file.
    :return:
    Nz/File spec does not have an embedded file streamz/Namesz/EmbeddedFilesz/Kidsz,Only flat name trees are supported right now)   r   )versionz/AF)r      )rI   r
   ZPdfWriteErrorrX   rootKeyErrorr	   r<   r4   Zupdate_rootZupdate_containerNotImplementedErrorrM   appendr   rP   rS   Zensure_output_version)
r"   rY   Z	ef_streamZspec_objr]   Z
names_dictZef_name_treeZef_name_arrZspec_obj_refZroot_af_arrr    r    r!   r   "  sV    


zattachment.pdfzWrapped document)passwordcertsr3   rP   r$   rQ   rR   include_explanation_page)plaintext_payloadra   rb   r3   rP   r$   rQ   r&   c             	   C   s  t  }	|dkr|dk|dkkr(td|dkr|dk	s<ttjdddd}
|
  tjtjj	tj
jddtjtj|
itjdd}|
j|t d n8tjdd	}|  tjj|tjtj|itjddd
}|	| t  |	jd< }td|d< t||d< td|d< tj|	| d|p"t d}t||||d}t|	| |rttdttdt|	ii}d}tj |!dd}t j"|	#|d|d}|	$| |	S )a|
  
    Include a PDF document as an encrypted attachment in a wrapper document.

    This function sets certain flags in the wrapper document's collection
    dictionary to instruct compliant PDF viewers to display the attachment
    instead of the wrapping document. Viewers that do not fully support
    PDF collections will display a landing page instead, explaining
    how to open the attachment manually.

    Using this method mitigates some weaknesses in the PDF standard's encryption
    provisions, and makes it harder to manipulate the encrypted attachment
    without knowing the encryption key.

    .. danger::
        Until PDF supports authenticated encryption mechanisms, this is
        a mitigation strategy, not a foolproof defence mechanism.

    .. warning::
        While users of viewers that do not support PDF collections can still
        open the attached file manually, the viewer still has to support
        PDF files where only the attachments are encrypted.

    .. note::
        This is not quite the same as the "unencrypted wrapper document"
        pattern discussed in the PDF 2.0 specification. The latter is intended
        to support nonstandard security handlers. This function uses a standard
        security handler on the wrapping document to encrypt the attachment
        as a binary blob.
        Moreover, the functionality in this function is available in PDF 1.7
        viewers as well.

    :param plaintext_payload:
        The plaintext payload (a binary representation of a PDF document).
    :param security_handler:
        The security handler to use on the wrapper document.
        If ``None``, a security handler will be constructed based on the
        ``password`` or ``certs`` parameter.
    :param password:
        Password to encrypt the attachment with.
        Will be ignored if ``security_handler`` is provided.
    :param certs:
        Encrypt the file using PDF public-key encryption, targeting the
        keys in the provided certificates.
        Will be ignored if ``security_handler`` is provided.
    :param file_spec_string:
        PDFDocEncoded file spec string for the attachment.
    :param params:
        Embedded file parameters to use.
    :param file_name:
        Unicode file name for the attachment.
    :param description:
        Description for the attachment
    :param include_explanation_page:
        If ``False``, do not generate an explanation page in the wrapper
        document. This setting could be useful if you want to customise the
        wrapper document's behaviour yourself.
    :return:
        A :class:`~writer.PdfFileWriter` representing the wrapper document.
    NzSIf 'security_handler' is not provided, exactly one of 'password' or 'cert' must be.    F)keylenZacts_as_defaultencrypt_metadata)Zdefault_file_filter)r[   Zpubkey_handler_subfilterZlegacy_keylenrg   r:   )policy)rf   )r:   rg   z/Collectionr/   z/Dz/Hz/Viewzapplication/pdf)r#   r%   r$   )rP   rQ   rI   rR   z/Fontz/F1a  
        BT
            /F1 10 Tf 10 830 Td 12 TL
            (This document is a wrapper for an encrypted attachment.) '
            (Your viewer should prompt for a password and ) '
            (open the attached file automatically.) Tj
            (If not, navigate to the attached document manually.) ' T*
            (In addition, your viewer must support encryption ) '
            (scoped to embedded files.) Tj
        ET
        latin1)r'   )r   r   g
ףp=@gQO@)contentsZ	media_box	resources)%r   PdfFileWriter
ValueErrorAssertionErrorr   ZPubKeyAESCryptFilterZset_embedded_onlyZPubKeySecurityHandlerZSecurityHandlerVersionZAES256ZPubKeyAdbeSubFilterZS5ZCryptFilterConfigurationZDEF_EMBEDDED_FILEZadd_recipientsr   ZStandardAESCryptFilterZStandardSecurityHandlerZbuild_from_pwZSTD_CFZ_assign_security_handlerr	   r<   r]   r   rV   r   r+   r   r   r   r   StreamObjectencodeZ
PageObjectr4   Zinsert_page)rd   ra   rb   r3   rP   r$   rQ   rR   rc   wZ	pubkey_cfZstd_cfZcollection_dictZef_objrY   rk   Zstream_contentrB   Zexplanation_pager    r    r!   r   g  s    G  
 


 
)#rO   r>   Zdataclassesr   r   typingr   r   Z
asn1cryptor    r   r	   r
   r   Zcrypt.pubkeyr   Z
font.basicr   r   r   __all__r   ro   r   r   r   rD   r   rE   rF   ZCertificateZSecurityHandlerrl   r   r    r    r    r!   <module>   sT   
 g]H