U
    cc<                  	   @   s|  d Z ddl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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mZmZ d	dlm Z m!Z!m"Z"m#Z# d	dl$m%Z%m&Z& d	dl'm(Z(m)Z) e*e+Z,dddgZ-edddZ.G dd deZ/e/e e% 0ej1e 0ej1e 0ej1e  0ej1e& 0ej1gee" e# e! gddZ2e/g ddZ3dS )zF
Module defining pyHanko's standard difference policy implementation.
    N)defaultdict)IteratorListOptionalUnion)misc)	PdfObject)HistoricalResolverPdfFileReader
RawPdfPath)FieldMDPSpecMDPPerm   )FormUpdatingRule)
DiffPolicy
DiffResultModificationLevelSuspiciousModification)CatalogModificationRuleObjectStreamRuleXrefStreamRule)DSSCompareRuleGenericFieldModificationRuleSigFieldCreationRuleSigFieldModificationRule)DocInfoRuleMetadataUpdateRule)QualifiedWhitelistRuleReferenceUpdateStandardDiffPolicyDEFAULT_DIFF_POLICYNO_CHANGES_DIFF_POLICY)hist_revc                    s      } j jd }t t }|D ]$}||rD|| q*| q*tt d fdd}| }|rzt	|}W n t
k
r   Y qY nX | j| jd8 }qn|S )za
    Within a revision, find new refs that can't be reached from refs in the
    older ones.
    r   )returnc                  3   s     j V  D ]}  | V  qd S N)Ztrailer_view)_refr"   Zupdated_old_refs ]/var/www/html/project/venv/lib/python3.8/site-packages/pyhanko/sign/diff_analysis/policies.py_objs_to_checkQ   s    z%_find_orphans.<locals>._objs_to_check)Zsince_revision)explicit_refs_in_revisionreaderget_historical_resolverrevisionsetZis_ref_availableaddr   r   nextStopIterationZcollect_dependencies)r"   Znew_refspreviousZcandidate_orphansrefr)   Zobj_iterobjr'   r&   r(   _find_orphans0   s(    

 
r5   c                   @   sz   e Zd ZdZdee ee dddZde	e	ee
 ee eddd	Zdeeee	f ee
 ee eeef d
ddZdS )r   aa  
    Run a list of rules to analyse the differences between two revisions.

    :param global_rules:
        The :class:`.QualifiedWhitelistRule` objects encoding the rules to
        apply.
    :param form_rule:
        The :class:`.FormUpdatingRule` that adjudicates changes to form fields
        and their values.
    :param reject_object_freeing:
        Always fail revisions that free objects that existed prior to signing.

        .. note::
            PyHanko resolves freed references to the ``null`` object in PDF,
            and a freeing instruction in a cross-reference section is
            always registered as a change that needs to be approved, regardless
            of the value of this setting.

            It is theoretically possible for a rule to permit deleting content,
            in which case allowing objects to be freed might be reasonable.
            That said, pyHanko takes the conservative default position to reject
            all object freeing instructions as suspect.
    :param ignore_orphaned_objects:
        Some PDF writers create objects that aren't used anywhere (tsk tsk).
        Since those don't affect the "actual" document content, they can usually
        be ignored. If ``True``, newly created orphaned objects will be
        cleared at level :attr:`.ModificationLevel.LTA_UPDATES`.
        Default is ``True``.
    Tglobal_rules	form_rulec                 C   s   || _ || _|| _|| _d S r$   )r7   r8   reject_object_freeingignore_orphaned_objects)selfr7   r8   r9   r:   r'   r'   r(   __init__   s    zStandardDiffPolicy.__init__N)oldnewfield_mdp_specdoc_mdpr#   c                    sj  |t jkrtd | jr6| }|r6td| d| tt	 fdd}| j
rxt|D ]} tj | qbt| ttd fdd}| jD ]$}	|	|D ]\}
}||
| qqt	 }| jrj| j|}fd	d
}|D ]x\}
}||
| |j}|d k	rH|jsH||r<td|j d| d||j |d k	r|jstd|j dq tj  }| tj  }| tj  }|r<tddd |D }td|j| dd  D }d|j dd dd |D  d}|r2dj d|j dd | }d||f }t| t|n"|rJtj}
n|rXtj}
ntj}
t!|
|dS )NzzStandardDiffPolicy was not designed to support DocMDP level 3 (MDPPerm.ANNOTATE). Unexpected validation results may occur.z	The refs zn were freed in the revision provided. The configured difference analysis policy does not allow object freeing.c                  3   s8       D ]&} | }|r| tjt|ffV  qd S r$   )Z_load_reverse_xref_cacheZ_get_usages_of_refr   NONEr.   )Znew_refusages)	new_xrefsr=   r'   r(   _init_multi_lut   s
    
z1StandardDiffPolicy.apply.<locals>._init_multi_lut)_level_updc                    s   |j }zb| \}}|jr"t }n$|jp*d}t|tr<|f}|| t|| } | |f|< |rfW d S W n tk
r|   Y nX  |  	| d S )Nr'   )
updated_refZblanket_approver.   paths_checked
isinstancer   difference_updatemaxKeyErrorr/   )rE   rF   r3   Zcurrent_max_levelrB   rH   )	explainedold_usages_to_clearr'   r(   
ingest_ref   s     




z,StandardDiffPolicy.apply.<locals>.ingest_refc                    s    d k	o  | S r$   )	is_locked)Zfq_name)r?   r'   r(   rP      s    z+StandardDiffPolicy.apply.<locals>.is_lockedz
Update of z' is not allowed because the form field z is locked.zL is only allowed after an approval signature, not a certification signature.
c                 s   s.   | ]&}d t |t | dd f V  qdS )z%s:%s...Ni,  )reprZ
get_object.0xr'   r'   r(   	<genexpr>   s
    z+StandardDiffPolicy.apply.<locals>.<genexpr>z$Unexplained xrefs in revision %d:
%sc              	   S   s>   g | ]6\}\}}|rd t | dddd |D  dqS )z - z is also used at , c                 s   s   | ]}t |V  qd S r$   )str)rT   pr'   r'   r(   rV     s     z6StandardDiffPolicy.apply.<locals>.<listcomp>.<genexpr>z in the prior revision.)rR   join)rT   r3   _Zpaths_remainingr'   r'   r(   
<listcomp>  s   
z,StandardDiffPolicy.apply.<locals>.<listcomp>z(There are unexplained xrefs in revision z: rW   c                 s   s   | ]}t |V  qd S r$   )rR   rS   r'   r'   r(   rV     s     .zSome objects from revision z were replaced in revision z  without precise justification:
z%s
%s)modification_levelchanged_form_fields)"r   ZANNOTATEloggerwarningr9   Zrefs_freed_in_revisionr   r*   r   r.   r:   r5   r   LTA_UPDATESr/   dictr   r7   Zapply_qualifiedr8   apply
field_nameZvalid_when_lockedrG   Zvalid_when_certifyingZFORM_FILLINGZANNOTATIONSr   ZLazyJoindebugr-   itemsrZ   r   )r;   r=   r>   r?   r@   ZfreedrD   r%   rO   rulelevelZupdr_   Zform_changesrP   Zfure   Zunexplained_ltaZunexplained_formfillZunexplained_annotmsgZunexplained_overrideserr_msgZunchecked_paths_msgr'   )rM   r?   rC   r=   rN   r(   rd      s    





  "

 zStandardDiffPolicy.apply)r+   base_revisionr?   r@   r#   c                 C   s   t  }|jj}tj}t|tr*||}n
|}|j}t	|d |D ]}	z| j
|||	||d}
W nH tk
r } z*tjd| d|	 |d | W Y   S d}~X Y nX t||
j}||
jO }qBt||S )z
        Implementation of :meth:`.DiffPolicy.review_file` that reviews
        each intermediate revision between the base revision and the current one
        individually.
        r   )r=   r>   r?   r@   z)Error in diff operation between revision z and )exc_infoN)r.   ZxrefsZtotal_revisionsr   rA   rI   intr,   r-   rangerd   r   r`   ra   rK   r^   r_   r   )r;   r+   rl   r?   r@   r_   Z	rev_countZcurrent_maxZbase_rev_resolverr-   Zdiff_resulter'   r'   r(   review_file#  s4    
 
zStandardDiffPolicy.review_file)TT)NN)NN)__name__
__module____qualname____doc__r   r   r   r   r<   r	   r   r   r   rd   r
   r   rn   r   rq   r'   r'   r'   r(   r   d   s,       	      

)Zfield_rulesr6   )4ru   loggingcollectionsr   typingr   r   r   r   Zpyhanko.pdf_utilsr   Zpyhanko.pdf_utils.genericr   Zpyhanko.pdf_utils.readerr	   r
   r   Zpyhanko.sign.fieldsr   r   Zform_rules_apir   Z
policy_apir   r   r   r   Zrules.file_structure_rulesr   r   r   Zrules.form_field_rulesr   r   r   r   Zrules.metadata_rulesr   r   Z	rules_apir   r   	getLoggerrr   r`   __all__r5   r   Zas_qualifiedrb   r    r!   r'   r'   r'   r(   <module>   sL   
 4 x %