
    h5jb              
      :   U d Z ddlmZ ddlmZ ddlmZmZmZm	Z	 erddl
mZ ddlmZmZ g dZ eej"                  h      Z eej&                  ej(                  ej*                  ej,                  ej.                  ej0                  h      Z eej4                  ej6                  ej8                  ej:                  h      Zej6                  ej6                  fej8                  ej8                  fej>                  ej@                  ejB                  f ed       ed	      fiZ"d
e#d<   dZ$d%dZ%d&dZ&d'dZ'd(dZ(	 d)	 	 	 	 	 	 	 	 	 d*dZ)	 	 	 	 	 	 	 	 	 	 d+dZ*d,dZ+d-dZ,d.dZ-d/dZ.d/dZ/d/dZ0d0dZ1d/dZ2d/dZ3d/dZ4d/dZ5d/dZ6d/dZ7d/d Z8d/d!Z9 G d" d#      Z:y$)1u  Helpers for removing potentially unwanted content from a PDF.

What is "safe" to remove from a PDF depends entirely on your use case and
threat model. The functions in this module each perform one narrowly scoped,
low-risk operation: they remove active or auxiliary content (scripts, embedded
files, actions that reach the network or filesystem, multimedia and rich-media
content, thumbnails, search indexes, Web Capture information, private
application data, and the portfolio view) while leaving the standard page
content, page geometry, and document metadata in place.

These operations are *not* guaranteed to leave a document's appearance
unchanged. PDF JavaScript, for example, can alter how a document renders, so
removing it may change the result — although in practice most PDFs are designed
to display correctly without it, since many viewers do not run PDF JavaScript.

They deliberately do **not** strip XFA, AcroForm, annotations, the document
``/ID``, or metadata wholesale, because those operations frequently destroy
legitimate document content. See the :doc:`Sanitizing PDFs </topics/sanitize>`
topic for a discussion of the tradeoffs and the limits of what programmatic
sanitization can accomplish.
    )annotations)TYPE_CHECKING)Array
DictionaryNameStream)Callable)ObjectPdf)
	Sanitizerremove_attachmentsremove_collectionremove_external_accessremove_javascriptremove_multimediaremove_private_app_dataremove_search_indexremove_thumbnailsremove_web_capturez/3Dz/3DDzdict[Name, tuple[Name, ...]]_MEDIA_ANNOT_KEYS2   c                    t        | t        t        f      syt        | j                  t        j
                        t              S )zReturn True if *obj* looks like a PDF action dictionary.

    Action dictionaries carry an ``/S`` (subtype) key whose value is a Name.
    Streams are permitted because an action's dictionary part may, rarely, be
    attached to a stream object.
    F)
isinstancer   r   getr   S)objs    F/var/www/html/qr/venv/lib/python3.12/site-packages/pikepdf/sanitize.py_is_action_dictr   I   s/     cJ/0cggdffot,,    c                    t        |       sy| j                  t        j                        }t	        |t              xr ||v S )zEReturn True if *obj* is an action dict whose subtype is in *targets*.F)r   r   r   r   r   )r   targetssubtypes      r   _is_targeted_actionr#   U   s5    3ggdffoGgt$;G);;r   c                `    | j                   r"| j                  }||v ry|j                  |       y)zTrack visited indirect objects to break cyclic /Next chains.

    Direct (inline) objects all report objgen ``(0, 0)`` and cannot be
    deduplicated this way; the recursion depth cap handles those.
    TF)is_indirectobjgenadd)r   seenr&   s      r   
_cycle_hitr)   ]   s-     T>r   c                >    t        | t              rt        |       S | gS )z@Normalize a /Next value (single action dict or Array) to a list.)r   r   list)next_objs    r   _as_actionsr-   k   s    (E"H~:r   c                   | j                  t        j                        }|t        k\  s|yg }t	        |      D ]z  }t        ||      rt        ||||dz          t        ||      r=|j                  t        j                        }|O|j                  t	        |             j|j                  |       | |s| t        j                  = yt        |      dk(  r|d   | t        j                  <   yt        |      | t        j                  <   y)zPrune targeted actions from *action*'s /Next chain, in place.

    A pruned node's own (already-cleaned) /Next survivors are grafted upward so
    that legitimate downstream actions are preserved.
    N   r   )r   r   Next_MAX_CHAIN_DEPTHr-   r)   _neutralize_next_chainr#   extendappendlenr   )actionr!   r(   depthr,   	survivorschildgrafteds           r   r2   r2   r   s     zz$))$H  H$4 IX& $eT"ugtUQY?ug.ii		*G"  W!56U#$ 499	Y1	%aLtyy!),tyyr   c                    | j                  |      }|t        |      syt        ||      ryt        ||      r| |= yt	        |||       y)zNeutralize a single-action slot, e.g. an annotation's /A.

    If the action's subtype is targeted, the slot is deleted entirely;
    otherwise the action's /Next chain is pruned.
    N)r   r   r)   r#   r2   )holderkeyr!   r(   r6   s        r   _neutralize_slotr>      sM     ZZ_F~_V4&$67+3K67D1r   c                :   | j                  t        j                        }t        |t              syt        |j                               D ]!  }t        |t        |      |t                      # t        |j                               dk(  r| t        j                  = yy)zNeutralize every event in *holder*'s /AA additional-actions dictionary.

    The /AA dictionary is dropped if it becomes empty.
    Nr   )
r   r   AAr   r   r+   keysr>   setr5   )r<   r!   aa	event_keys       r   _neutralize_additional_actionsrE      sr    
 
DGG	Bb*%"'')_ >	T)_gsu=>
2779~477O r   c           	     d   | j                   }t        |t        j                  |t	                      t        ||       | j                  D ]  }|j                  }t        ||       |j                  t        j                        }t        |t              sK|D ]C  }t        |t              st        |t        j                  |t	                      t        ||       E  | j                  j                  r1| j                  j                   D ]  }t        |j                  |        t#        ||       y)zCWalk all known action-holder slots and neutralize targeted actions.N)Rootr>   r   
OpenActionrB   rE   pagesr   r   Annotsr   r   r   Aacroformexistsfields_neutralize_outlines)pdfr!   rootpagepobjannotsannotfields           r   _sanitize_actionsrW      s    88D T4??GSU;"41 		 	?xx&tW5$++&fe$ ?!%4 ?.ug>	?	? ||\\(( 	?E*599g>	? w'r   c                ,   | j                  t        j                        }t        |t              syt               }|j                  t        j                        g}|r|j                         }t        |t        t        f      s)t        ||      r6t        |t        j                  |t                      |j                  |j                  t        j                               |j                  |j                  t        j                               |ryy)zNeutralize targeted /A actions on every document outline item.

    Walks the outline tree via /First and /Next, descending into /First for
    children, with an objgen-based visited set to break cyclic or malformed
    sibling/child links.
    N)r   r   Outlinesr   r   rB   Firstpopr   r)   r>   rK   r4   r0   )rQ   r!   outlinesvisitedstackitems         r   rO   rO      s     xx&Hh
+$'EG\\$**%&E
yy{$V 45dG$tvvw6TXXdii()TXXdjj)* r   c                :    t        | t               t        |        y)av  Remove all JavaScript from a PDF, in place.

    Purges document-level named JavaScript (the ``/Root/Names/JavaScript``
    name tree) and every ``/JavaScript`` action reachable from document, page,
    annotation, form-field, and outline (bookmark) action slots, including
    actions chained via ``/Next``.

    Page content, annotations (minus their scripts), form fields, and metadata
    are left in place. Note that PDF JavaScript can alter how a document
    renders, so removing it may change the result; in practice most documents
    are designed to display correctly without it.

    The main legitimate use of PDF JavaScript is interactive form validation;
    removing it may break that. Most PDF viewers other than Acrobat do not
    fully execute PDF JavaScript and warn about or disable it.

    This operation is idempotent and safe to call on a PDF that contains no
    JavaScript.

    Args:
        pdf: The PDF to modify in place.

    Note:
        To scrub document metadata, use
        :meth:`pikepdf.Pdf.open_metadata` with ``set_pikepdf_as_editor=False``
        instead; this function does not touch metadata.
    N)rW   _JS_SUBTYPES_drop_named_javascriptrP   s    r   r   r      s    8 c<(3r   c                    | j                   j                  t        j                        }t	        |t
              r%t        j                  |v r|t        j                  = yyy)z=Drop the document-level ``/Root/Names/JavaScript`` name tree.N)rG   r   r   Namesr   r   
JavaScript)rP   namess     r   rb   rb     sB    HHLL$E%$E)A$//" *B$r   c                $   | j                   D ]S  }t        |t        t        f      st	        |j                  t        j                              sC|t        j                  = U | j                  j                          | j                  j                  t        j                        }t        |t              r#t        j                  |v r|t        j                  = | j                  D ]  }|j                  j                  t        j                        }t        |t               s=|D ]h  }t        |t              s|j                  t        j"                        t        j$                  k(  sEt        j&                  |v sX|t        j&                  = j  y)u  Remove all embedded files (attachments) from a PDF, in place.

    Clears the ``/Root/Names/EmbeddedFiles`` name tree (the
    :attr:`pikepdf.Pdf.attachments` mapping) and removes ``/AF`` (associated
    files) references from every object that carries one — the catalog, pages,
    annotations, XObjects, structure elements, and so on (PDF 2.0 14.13). As a
    precaution, an ``/AF`` reference is only removed if it points to an embedded
    file specification (one with an ``/EF`` entry), so an unrelated key that
    happens to be named ``/AF`` is left untouched. FileAttachment annotations
    are defanged by removing their embedded ``/FS`` file specification; the
    annotation itself is retained so page geometry is unchanged.

    Embedded files can be integral to a document, especially in digital-signing
    workflows, so remove them deliberately.

    This operation is idempotent and safe to call on a PDF that has no
    attachments.

    Args:
        pdf: The PDF to modify in place.
    N)objectsr   r   r   _af_holds_embedded_filer   r   AFattachmentsclearrG   re   EmbeddedFilesrI   r   rJ   r   SubtypeFileAttachmentFS)rP   r   rg   rR   rT   rU   s         r   r   r     s   : {{ cJ/05LGGDGG6
 DGG	 OO HHLL$E%$););u)D$$$% 		 'dkk*fe$ '!%499T\\*d.A.AAdggQVFVdgg	''r   c                P    t        | t              r| n| g}t        d |D              S )a~  Return True if an /AF value points to an embedded-file specification.

    /AF normally holds an array of file specification dictionaries; an embedded
    associated file carries the payload in an /EF entry. A direct (non-array)
    file spec is tolerated for robustness. Returning False for anything else
    avoids stripping unrelated keys that merely happen to be named /AF.
    c              3  p   K   | ].  }t        |t        t        f      xr t        j                  |v  0 y w)N)r   r   r   r   EF).0specs     r   	<genexpr>z*_af_holds_embedded_file.<locals>.<genexpr>V  s4       	4*f-.B477d?Bs   46)r   r   any)af
candidatess     r   rj   rj   M  s0     ""e,2$J   r   c                $    t        | t               y)a  Neutralize actions that reach the network or filesystem, in place.

    Removes ``/URI``, ``/Launch``, ``/GoToR`` (remote go-to), ``/GoToE``
    (embedded go-to), ``/SubmitForm``, and ``/ImportData`` actions wherever they
    are reachable from document, page, annotation, form-field, and outline
    (bookmark) action slots, including actions chained via ``/Next``.

    Link annotations are retained (so any visible underline or box is
    preserved) but their triggering action is removed, rendering them inert.
    Visible content and metadata are left intact.

    URI actions are usually benign hyperlinks; this function is a separate
    opt-in so callers can decide whether to sever external access.

    This operation is idempotent and safe to call on a PDF that contains no
    such actions.

    Args:
        pdf: The PDF to modify in place.

    Note:
        To scrub document metadata, use
        :meth:`pikepdf.Pdf.open_metadata` with ``set_pikepdf_as_editor=False``
        instead; this function does not touch metadata.
    N)rW   _EXTERNAL_SUBTYPESrc   s    r   r   r   \  s    4 c-.r   c                    | j                   D ]:  }t        j                  |j                  v s |j                  t        j                  = < y)aW  Remove embedded page thumbnails from a PDF, in place.

    Deletes the ``/Thumb`` thumbnail image stream from every page. Thumbnails
    are an optional convenience that viewers can regenerate on the fly, so
    removing them is safe; doing so reduces file size and avoids stale
    thumbnails that some editors fail to keep in sync with edited pages. A stale
    thumbnail can also leak the prior appearance of a page you intended to edit
    or redact.

    This operation is idempotent and safe to call on a PDF that has no
    thumbnails.

    Args:
        pdf: The PDF to modify in place.
    N)rI   r   Thumbr   rP   rR   s     r   r   r   y  s7      		 %::!$%r   c                .   | j                   j                  t        j                        }t	        |t
              syt        j                  |v r|t        j                  = t        |j                               dk(  r| j                   t        j                  = yy)a-  Remove an embedded full-text search index from a PDF, in place.

    Adobe Acrobat can embed a full-text search index in a document to speed up
    searching. It is stored as a ``/SearchIndex`` entry in the catalog's
    ``/PieceInfo`` dictionary. This function removes that entry (and the
    ``/PieceInfo`` dictionary itself if it becomes empty); the index's data
    streams become unreferenced and are dropped when the PDF is saved.

    Removing the index reduces file size, re-enables Fast Web View (which an
    embedded index precludes), and avoids a stale index leaking content you
    intended to edit or redact. Non-Acrobat viewers do not use it.

    This operation is idempotent and safe to call on a PDF that has no embedded
    search index.

    Args:
        pdf: The PDF to modify in place.
    Nr   )	rG   r   r   	PieceInfor   r   SearchIndexr5   rA   )rP   
piece_infos     r   r   r     sl    & dnn-Jj*-:%t''(
:??"HHT^^$ #r   c                :    t        | t               t        |        y)a  Remove multimedia and rich-media content from a PDF, in place.

    Neutralizes ``/Rendition``, ``/Movie``, ``/Sound``, and
    ``/RichMediaExecute`` actions (wherever reachable from document, page,
    annotation, outline, and form-field action slots, including ``/Next``
    chains), drops the document-level ``/Root/Names/Renditions`` name tree, and
    defangs media-bearing annotations by stripping their media references:

    * ``Movie`` annotations lose their ``/Movie`` dictionary;
    * ``Sound`` annotations lose their ``/Sound`` stream;
    * ``RichMedia`` annotations lose ``/RichMediaContent`` and
      ``/RichMediaSettings``;
    * ``3D`` annotations lose their ``/3DD`` 3D-data reference.

    ``Screen`` annotations are defanged by removing their ``/Rendition``
    action via the action walk above. In every case the annotation itself is
    retained so page geometry is unchanged.

    Multimedia handlers (Flash, embedded video, U3D/PRC 3D) are historically a
    source of parser vulnerabilities, and the underlying media can reference
    external URLs or files. ``Sound`` and ``Movie`` are deprecated in PDF 2.0.

    This operation is idempotent and safe to call on a PDF that contains no
    multimedia content.

    Args:
        pdf: The PDF to modify in place.
    N)rW   _MULTIMEDIA_SUBTYPES_remove_multimedia_structuralrc   s    r   r   r     s    : c/0!#&r   c                2   | j                   j                  t        j                        }t	        |t
              r#t        j                  |v r|t        j                  = | j                  D ]  }|j                  j                  t        j                        }t	        |t              s=|D ]k  }t	        |t
              s|j                  t        j                        }t	        |t              rt        j                  |      nd}|]|D ]
  }||v s||=  m  y)zDDrop the named-renditions tree and defang media-bearing annotations.N)rG   r   r   re   r   r   
RenditionsrI   r   rJ   r   ro   r   )rP   rg   rR   rT   rU   r"   rA   r=   s           r   r   r     s    HHLL$E%$E)A$//"		 #dkk*&%( 		#EeZ0ii-G5?5N$((1TXD| #%<c
#		#	#r   c                t    t         j                  | j                  v r| j                  t         j                  = yy)a1  Remove Web Capture (spider) information from a PDF, in place.

    Deletes the catalog's ``/SpiderInfo`` dictionary, which Adobe Acrobat
    records when content is captured from the web. It stores source URLs and
    capture settings, so removing it drops potentially sensitive provenance
    that is otherwise invisible in the document, and is ignored by viewers that
    do not implement Web Capture.

    This operation is idempotent and safe to call on a PDF that has no Web
    Capture information.

    Args:
        pdf: The PDF to modify in place.
    N)r   
SpiderInforG   rc   s    r   r   r     s)     #(("HHT__% #r   c                   t         j                  | j                  v r| j                  t         j                  = | j                  D ]:  }t         j                  |j                  v s |j                  t         j                  = < y)a  Remove private application data (page-piece dictionaries), in place.

    Deletes every ``/PieceInfo`` page-piece dictionary, both at the document
    catalog level and on every page. PDF processors use ``/PieceInfo`` to store
    private, application-specific data (for example, an editor's own editable
    representation of the page) that the PDF specification does not interpret.

    Such data can fall out of sync with the visible document and leak content
    you intended to edit or redact. Removing it does not change how the document
    renders, but applications that wrote it lose their private editing state.

    This is a broader operation than :func:`remove_search_index`, which removes
    only the catalog's ``/PieceInfo/SearchIndex`` entry; this function removes
    all page-piece data wherever it appears.

    This operation is idempotent and safe to call on a PDF that has no
    private application data.

    Args:
        pdf: The PDF to modify in place.
    N)r   r   rG   rI   r   r   s     r   r   r     sW    , ~~!HHT^^$		 )>>TXX%()r   c                t    t         j                  | j                  v r| j                  t         j                  = yy)a  Remove the PDF portfolio (collection) presentation, in place.

    Deletes the catalog's ``/Collection`` dictionary, which marks a document as
    a *PDF portfolio* (also called a PDF package) and configures how its
    embedded files are presented in a navigator UI. Removing it causes the
    document to be presented as an ordinary PDF showing its cover sheet.

    This does **not** remove the embedded files themselves; pair it with
    :func:`remove_attachments` if you want the attachments gone as well. A
    portfolio's navigator can also be driven by JavaScript, so consider
    :func:`remove_javascript` too.

    This operation is idempotent and safe to call on a PDF that is not a
    portfolio.

    Args:
        pdf: The PDF to modify in place.
    N)r   
CollectionrG   rc   s    r   r   r     s)    & #(("HHT__% #r   c                  h    e Zd ZdZddZddZddZddZddZddZ	ddZ
dd	Zdd
ZddZddZy)r   a  A fluent builder that accumulates sanitization operations.

    Each ``remove_*`` method records an operation and returns ``self`` so calls
    can be chained. Nothing happens until :meth:`apply` is called with a PDF;
    this lets a single :class:`Sanitizer` be configured once and reused across
    many documents. The action-based removals (JavaScript, external access) are
    coalesced into a single traversal of the document when applied.

    The methods correspond to the module-level functions of the same name and
    have the same scope and caveats. Like those functions, the operations are
    deliberately limited to the curated, low-risk set; there is no "remove
    everything" option, because blanket removal of forms, annotations, or XFA
    usually destroys legitimate content.

    Example:
        Configure once, apply to many files::

            scrubber = (
                pikepdf.sanitize.Sanitizer()
                .remove_javascript()
                .remove_external_access()
                .remove_attachments()
            )
            for path in untrusted_paths:
                with pikepdf.open(path) as pdf:
                    scrubber.apply(pdf).save(out_dir / path.name)
    c                >    t               | _        d| _        g | _        y)z6Create an empty sanitizer with no operations recorded.FN)rB   _action_subtypes_drop_named_js_structuralselfs    r   __init__zSanitizer.__init__E  s    +.5#8:r   c                F    | xj                   t        z  c_         d| _        | S )z@Record removal of all JavaScript. See :func:`remove_javascript`.T)r   ra   r   r   s    r   r   zSanitizer.remove_javascriptK  s     -"r   c                8    | xj                   t        z  c_         | S )z`Record removal of external-access actions.

        See :func:`remove_external_access`.
        )r   r|   r   s    r   r   z Sanitizer.remove_external_accessQ  s    
 	!33r   c                D    | j                   j                  t               | S )zARecord removal of embedded files. See :func:`remove_attachments`.)r   r4   r   r   s    r   r   zSanitizer.remove_attachmentsY       23r   c                D    | j                   j                  t               | S )zARecord removal of page thumbnails. See :func:`remove_thumbnails`.)r   r4   r   r   s    r   r   zSanitizer.remove_thumbnails^       12r   c                D    | j                   j                  t               | S )z^Record removal of an embedded search index.

        See :func:`remove_search_index`.
        )r   r4   r   r   s    r   r   zSanitizer.remove_search_indexc  s    
 	 34r   c                v    | xj                   t        z  c_         | j                  j                  t               | S )zDRecord removal of multimedia content. See :func:`remove_multimedia`.)r   r   r   r4   r   r   s    r   r   zSanitizer.remove_multimediak  s.    !55 =>r   c                D    | j                   j                  t               | S )zCRecord removal of Web Capture info. See :func:`remove_web_capture`.)r   r4   r   r   s    r   r   zSanitizer.remove_web_captureq  r   r   c                D    | j                   j                  t               | S )zbRecord removal of private application data.

        See :func:`remove_private_app_data`.
        )r   r4   r   r   s    r   r   z!Sanitizer.remove_private_app_datav  s    
 	 78r   c                D    | j                   j                  t               | S )zDRecord removal of the portfolio view. See :func:`remove_collection`.)r   r4   r   r   s    r   r   zSanitizer.remove_collection~  r   r   c                    | j                   rt        |t        | j                                | j                  rt	        |       | j
                  D ]
  } ||        |S )a  Apply the recorded operations to *pdf*, in place.

        The action-based removals run as a single combined traversal, followed
        by the structural removals in the order they were recorded.

        Args:
            pdf: The PDF to modify in place.

        Returns:
            The same ``pdf``, to allow further chaining, e.g.
            ``.apply(pdf).save(...)``.
        )r   rW   	frozensetr   rb   r   )r   rP   	operations      r   applyzSanitizer.apply  sT       c9T-B-B#CD"3')) 	IcN	
r   N)returnNone)r   r   )rP   r   r   r   )__name__
__module____qualname____doc__r   r   r   r   r   r   r   r   r   r   r    r   r   r   r   (  s>    8;



r   r   N)r   Object | Noner   bool)r   r
   r!   frozenset[Name]r   r   )r   r
   r(   set[tuple[int, int]]r   r   )r,   r
   r   zlist[Object])r   )
r6   r
   r!   r   r(   r   r7   intr   r   )
r<   r
   r=   r   r!   r   r(   r   r   r   )r<   r
   r!   r   r   r   )rP   r   r!   r   r   r   )rQ   r
   r!   r   r   r   )rP   r   r   r   )ry   r   r   r   );r   
__future__r   typingr   pikepdf.objectsr   r   r   r   collections.abcr	   pikepdfr
   r   __all__r   rf   ra   URILaunchGoToRGoToE
SubmitForm
ImportDatar|   	RenditionMovieSoundRichMediaExecuter   	RichMediaRichMediaContentRichMediaSettingsr   __annotations__r1   r   r#   r)   r-   r2   r>   rE   rW   rO   r   rb   r   rj   r   r   r   r   r   r   r   r   r   r   r   r   <module>r      s  , #   ; ;(# $//*+	XXt{{DJJ

DOOT__U  !	^^TZZT-B-BC  	JJJJNNT**D,B,BCK$v,	3 /   	-< 	"-"-"- "- 	"-
 
"-J22	2 2 	2
 
2,(:+. @#4'n/:%*%8'B#,&&):&.n nr   