Exemplo n.º 1
0
    def as_pdf_object(self) -> generic.StreamObject:
        """
        Render the object stream to a PDF stream object

        :return: An instance of :class:`~.generic.StreamObject`.
        """
        stream_header = BytesIO()
        main_body = BytesIO()
        for idnum, obj in self._obj_refs.items():
            offset = main_body.tell()
            obj.write_to_stream(main_body, None)
            stream_header.write(b'%d %d ' % (idnum, offset))

        first_obj_offset = stream_header.tell()
        stream_header.seek(0)
        sh_bytes = stream_header.read(first_obj_offset)
        stream_data = sh_bytes + main_body.getvalue()
        stream_object = generic.StreamObject({
            pdf_name('/Type'): pdf_name('/ObjStm'),
            pdf_name('/N'): generic.NumberObject(len(self._obj_refs)),
            pdf_name('/First'): generic.NumberObject(first_obj_offset)
        }, stream_data=stream_data)
        if self.compress:
            stream_object.compress()
        return stream_object
Exemplo n.º 2
0
    def __init__(self, cf: CIDFont):
        tt = cf.tt_font

        # Some metrics
        hhea = tt['hhea']
        head = tt['head']
        bbox = [head.xMin, head.yMin, head.xMax, head.yMax]
        os2 = tt['OS/2']
        weight = os2.usWeightClass
        stemv = int(10 + 220 * (weight - 50) / 900)
        super().__init__({
            pdf_name('/Type'): pdf_name('/FontDescriptor'),
            pdf_name('/FontName'): pdf_name('/' + cf.name),
            pdf_name('/Ascent'): generic.NumberObject(hhea.ascent),
            pdf_name('/Descent'): generic.NumberObject(hhea.descent),
            pdf_name('/FontBBox'): generic.ArrayObject(
                map(generic.NumberObject, bbox)
            ),
            # FIXME I'm setting the Serif and Symbolic flags here, but
            #  is there any way we can read/infer those from the TTF metadata?
            pdf_name('/Flags'): generic.NumberObject(0b110),
            pdf_name('/StemV'): generic.NumberObject(stemv),
            pdf_name('/ItalicAngle'): generic.FloatObject(
                getattr(tt['post'], 'italicAngle', 0)
            ),
            pdf_name('/CapHeight'): generic.NumberObject(
                getattr(os2, 'sCapHeight', 750)
            )
        })
Exemplo n.º 3
0
def test_sv_mdp_type():
    sv_dict = fields.SigSeedValueSpec().as_pdf_object()
    assert '/MDP' not in sv_dict
    sv_dict = fields.SigSeedValueSpec(
        seed_signature_type=fields.SeedSignatureType(None)).as_pdf_object()
    assert sv_dict['/MDP'] == generic.DictionaryObject(
        {pdf_name('/P'): generic.NumberObject(0)})
    sv_dict = fields.SigSeedValueSpec(
        seed_signature_type=fields.SeedSignatureType(
            fields.MDPPerm.NO_CHANGES)).as_pdf_object()
    assert sv_dict['/MDP'] == generic.DictionaryObject(
        {pdf_name('/P'): generic.NumberObject(1)})

    sv_spec = fields.SigSeedValueSpec.from_pdf_object(
        generic.DictionaryObject({
            pdf_name('/MDP'):
            generic.DictionaryObject({pdf_name('/P'): generic.NumberObject(0)})
        }))
    assert sv_spec.seed_signature_type == fields.SeedSignatureType(None)

    sv_spec = fields.SigSeedValueSpec.from_pdf_object(
        generic.DictionaryObject({
            pdf_name('/MDP'):
            generic.DictionaryObject({pdf_name('/P'): generic.NumberObject(2)})
        }))
    assert sv_spec.seed_signature_type == fields.SeedSignatureType(
        fields.MDPPerm.FILL_FORMS)

    with pytest.raises(SigningError):
        fields.SigSeedValueSpec.from_pdf_object(
            generic.DictionaryObject({
                pdf_name('/MDP'):
                generic.DictionaryObject(
                    {pdf_name('/P'): generic.NumberObject(5)})
            }))
    with pytest.raises(SigningError):
        fields.SigSeedValueSpec.from_pdf_object(
            generic.DictionaryObject({
                pdf_name('/MDP'):
                generic.DictionaryObject(
                    {pdf_name('/P'): generic.NullObject()})
            }))
    with pytest.raises(SigningError):
        fields.SigSeedValueSpec.from_pdf_object(
            generic.DictionaryObject(
                {pdf_name('/MDP'): generic.DictionaryObject()}))
    with pytest.raises(SigningError):
        fields.SigSeedValueSpec.from_pdf_object(
            generic.DictionaryObject({pdf_name('/MDP'): generic.NullObject()}))
Exemplo n.º 4
0
    def _widths():
        current_chunk = []
        prev_cid = None
        (first_cid, _), itr = peek(widths_by_cid_iter)
        for cid, width in itr:
            if current_chunk and cid != prev_cid + 1:
                yield generic.NumberObject(first_cid)
                yield generic.ArrayObject(current_chunk)
                current_chunk = []
                first_cid = cid

            current_chunk.append(generic.NumberObject(width))
            prev_cid = cid
        if current_chunk:
            yield generic.NumberObject(first_cid)
            yield generic.ArrayObject(current_chunk)
Exemplo n.º 5
0
    def __init__(
            self,
            field_name,
            *,
            box=None,
            include_on_page=None,
            is_annotation=True,
            # this sets the "print" bit
            annot_flags=0b100):

        if box is not None:
            rect = list(map(generic.FloatObject, box))
        else:
            rect = [generic.FloatObject(0)] * 4

        super().__init__({
            # Signature field properties
            pdf_name('/FT'):
            pdf_name('/Sig'),
            pdf_name('/T'):
            pdf_string(field_name),
        })
        if is_annotation:
            # Annotation properties: bare minimum
            self['/Type'] = pdf_name('/Annot')
            self['/Subtype'] = pdf_name('/Widget')
            self['/F'] = generic.NumberObject(annot_flags)
            self['/Rect'] = generic.ArrayObject(rect)
            if include_on_page is not None:
                self['/P'] = include_on_page
Exemplo n.º 6
0
    def __init__(self, stream_xrefs=True, init_page_tree=True):
        # root object
        root = generic.DictionaryObject({
            pdf_name("/Type"): pdf_name("/Catalog"),
        })

        id1 = generic.ByteStringObject(os.urandom(16))
        id2 = generic.ByteStringObject(os.urandom(16))
        id_obj = generic.ArrayObject([id1, id2])

        # info object
        info = generic.DictionaryObject({
            pdf_name('/Producer'): pdf_string(VENDOR)
        })

        super().__init__(root, info, id_obj, stream_xrefs=stream_xrefs)

        if init_page_tree:
            pages = generic.DictionaryObject({
                pdf_name("/Type"): pdf_name("/Pages"),
                pdf_name("/Count"): generic.NumberObject(0),
                pdf_name("/Kids"): generic.ArrayObject(),
            })

            root[pdf_name('/Pages')] = self.add_object(pages)
Exemplo n.º 7
0
    def __init__(self, field_name, *, box=None, include_on_page=None,
                 combine_annotation=True,
                 # this sets the "print" and "lock" bits
                 annot_flags=0b10000100):

        if box is not None:
            rect = list(map(generic.FloatObject, box))
        else:
            rect = [generic.FloatObject(0)] * 4

        super().__init__({
            # Signature field properties
            pdf_name('/FT'): pdf_name('/Sig'),
            pdf_name('/T'): pdf_string(field_name),
        })

        if combine_annotation:
            annot_dict = self
        else:
            annot_dict = generic.DictionaryObject()

        # Annotation properties: bare minimum
        annot_dict['/Type'] = pdf_name('/Annot')
        annot_dict['/Subtype'] = pdf_name('/Widget')
        annot_dict['/F'] = generic.NumberObject(annot_flags)
        annot_dict['/Rect'] = generic.ArrayObject(rect)

        self.page_ref = include_on_page
        if include_on_page is not None:
            annot_dict['/P'] = include_on_page

        self.annot_dict = annot_dict
Exemplo n.º 8
0
 def format_lock_dictionary(self) -> Optional[generic.DictionaryObject]:
     if self.field_mdp_spec is None:
         return
     result = self.field_mdp_spec.as_sig_field_lock()
     # this requires PDF 2.0 in principle, but meh, noncompliant
     # readers will ignore it anyway
     if self.doc_mdp_update_value is not None:
         result['/P'] = generic.NumberObject(self.doc_mdp_update_value.value)
     return result
Exemplo n.º 9
0
    def __init__(self,
                 field_name,
                 include_on_page,
                 *,
                 writer,
                 sig_object_ref=None,
                 box=None,
                 appearances: Optional[AnnotAppearances] = None):

        if box is not None:
            visible = True
            rect = list(map(generic.FloatObject, box))
            if appearances is not None:
                ap = appearances.as_pdf_object()
            else:
                ap = None
        else:
            rect = [generic.FloatObject(0)] * 4
            ap = None
            visible = False

        # this sets the "Print" bit, and activates "Locked" if the
        # signature field is ready to be filled
        flags = 0b100 if sig_object_ref is None else 0b10000100
        super().__init__({
            # Signature field properties
            pdf_name('/FT'):
            pdf_name('/Sig'),
            pdf_name('/T'):
            pdf_string(field_name),
            # Annotation properties: bare minimum
            pdf_name('/Type'):
            pdf_name('/Annot'),
            pdf_name('/Subtype'):
            pdf_name('/Widget'),
            pdf_name('/F'):
            generic.NumberObject(flags),
            pdf_name('/P'):
            include_on_page,
            pdf_name('/Rect'):
            generic.ArrayObject(rect)
        })
        if sig_object_ref is not None:
            self[pdf_name('/V')] = sig_object_ref
        if ap is not None:
            self[pdf_name('/AP')] = ap

        # register ourselves
        self.reference = self_reference = writer.add_object(self)
        # if we're building an invisible form field, this is all there is to it
        if visible:
            writer.register_annotation(include_on_page, self_reference)
Exemplo n.º 10
0
    def _write(self, stream, skip_header=False):

        object_positions = {}

        if self.stream_xrefs:
            trailer = XRefStream(object_positions)
            trailer.compress()
        else:
            trailer = generic.DictionaryObject()

        if not skip_header:
            self._write_header(stream)
        self._populate_trailer(trailer)
        self._write_objects(stream, object_positions)

        if self.stream_xrefs:
            xref_location = stream.tell()
            xrefs_id = self._lastobj_id + 1
            # add position of XRef stream to the XRef stream
            object_positions[(0, xrefs_id)] = xref_location
            trailer[pdf_name('/Size')] = generic.NumberObject(xrefs_id + 1)
            # write XRef stream
            stream.write(('%d %d obj' % (xrefs_id, 0)).encode('ascii'))
            trailer.write_to_stream(stream, None)
            stream.write(b'\nendobj\n')
        else:
            # classical xref table
            xref_location = _write_xref_table(stream, object_positions)
            trailer[pdf_name('/Size')] = generic.NumberObject(
                self._lastobj_id + 1
            )
            # write trailer
            stream.write(b'trailer\n')
            trailer.write_to_stream(stream, None)

        # write xref table pointer and EOF
        xref_pointer_string = '\nstartxref\n%s\n' % xref_location
        stream.write(xref_pointer_string.encode('ascii') + b'%%EOF\n')
Exemplo n.º 11
0
    def as_pdf_object(self):
        """
        Render this :class:`.SigSeedValueSpec` object to a PDF dictionary.

        :return:
            A :class:`~.generic.DictionaryObject`.
        """
        result = generic.DictionaryObject({
            pdf_name('/Type'):
            pdf_name('/SV'),
            pdf_name('/Ff'):
            generic.NumberObject(self.flags.value),
        })

        if self.subfilters is not None:
            result[pdf_name('/SubFilter')] = generic.ArrayObject(
                sf.value for sf in self.subfilters)
        if self.add_rev_info is not None:
            result[pdf_name('/AddRevInfo')] = generic.BooleanObject(
                self.add_rev_info)
        if self.digest_methods is not None:
            result[pdf_name('/DigestMethod')] = generic.ArrayObject(
                map(pdf_string, self.digest_methods))
        if self.reasons is not None:
            result[pdf_name('/Reasons')] = generic.ArrayObject(
                pdf_string(reason) for reason in self.reasons)
        if self.timestamp_server_url is not None:
            result[pdf_name('/TimeStamp')] = generic.DictionaryObject({
                pdf_name('/URL'):
                pdf_string(self.timestamp_server_url),
                pdf_name('/Ff'):
                generic.NumberObject(1 if self.timestamp_required else 0)
            })
        if self.cert is not None:
            result[pdf_name('/Cert')] = self.cert.as_pdf_object()
        return result
Exemplo n.º 12
0
    def insert_page(self, new_page, after=None):
        """
        Insert a page object into the tree.

        :param new_page:
            Page object to insert.
        :param after:
            Page number (zero-indexed) after which to insert the page.
        :return:
            A reference to the newly inserted page.
        """
        if new_page['/Type'] != pdf_name('/Page'):
            raise ValueError('Not a page object')
        if '/Parent' in new_page:
            raise ValueError('/Parent must not be set.')

        page_tree_root_ref = self.root.raw_get('/Pages')
        if after is None:
            page_count = page_tree_root_ref.get_object()['/Count']
            after = page_count - 1

        if after == -1:
            # there are no pages yet, this will be the first
            pages_obj_ref = page_tree_root_ref
            kid_ix = -1
        else:
            pages_obj_ref, kid_ix, _ = self.find_page_container(after)

        pages_obj = pages_obj_ref.get_object()
        try:
            kids = pages_obj['/Kids']
        except KeyError:  # pragma: nocover
            raise ValueError('/Pages must have /Kids')

        # increase page count for all parents
        parent = pages_obj
        while parent is not None:
            # can't use += 1 because of the way PyPDF2's generic types work
            count = parent['/Count']
            parent[pdf_name('/Count')] = generic.NumberObject(count + 1)
            parent = parent.get('/Parent')
        new_page_ref = self.add_object(new_page)
        kids.insert(kid_ix + 1, new_page_ref)
        new_page[pdf_name('/Parent')] = pages_obj_ref
        self.update_container(pages_obj)
        self.update_container(kids)

        return new_page_ref
Exemplo n.º 13
0
    def as_pdf_object(self):
        """
        Render this :class:`.SigCertConstraints` object to a PDF dictionary.

        :return:
            A :class:`~.generic.DictionaryObject`.
        """

        result = generic.DictionaryObject({
            pdf_name('/Type'): pdf_name('/SVCert'),
            pdf_name('/Ff'): generic.NumberObject(self.flags.value),
        })
        if self.subjects is not None:
            result[pdf_name('/Subject')] = generic.ArrayObject(
                generic.ByteStringObject(cert.dump())
                for cert in self.subjects
            )
        if self.subject_dn:
            # FIXME Adobe Reader seems to ignore this for some reason.
            #  Should try to figure out what I'm doing wrong
            result[pdf_name('/SubjectDN')] = generic.ArrayObject([
                generic.DictionaryObject({
                    pdf_name('/' + key): pdf_string(value)
                    for key, value in x509_name_keyval_pairs(
                        self.subject_dn, abbreviate_oids=True
                    )
                })
            ])
        if self.issuers is not None:
            result[pdf_name('/Issuer')] = generic.ArrayObject(
                generic.ByteStringObject(cert.dump())
                for cert in self.issuers
            )
        if self.info_url is not None:
            result[pdf_name('/URL')] = pdf_string(self.info_url)
            result[pdf_name('/URLType')] = self.url_type

        if self.key_usage is not None:
            result[pdf_name('/KeyUsage')] = generic.ArrayObject(
                pdf_string(ku.encode_to_sv_string()) for ku in self.key_usage
            )

        return result
Exemplo n.º 14
0
    def apply(self, sig_obj_ref, writer):
        """
        Apply the settings to a signature object.

        .. danger::
            This method is internal API.
        """

        certify = self.certify
        docmdp_perms = self.docmdp_perms

        lock = self.field_lock
        md_algorithm = self.md_algorithm

        reference_array = generic.ArrayObject()

        if certify:
            assert docmdp_perms is not None
            # To make a certification signature, we need to leave a record
            #  in the document catalog.
            root = writer.root
            try:
                perms = root['/Perms']
            except KeyError:
                root['/Perms'] = perms = generic.DictionaryObject()
            perms[pdf_name('/DocMDP')] = sig_obj_ref
            writer.update_container(perms)
            reference_array.append(
                docmdp_reference_dictionary(md_algorithm, docmdp_perms))

        if lock is not None:
            fieldmdp_ref = fieldmdp_reference_dictionary(
                lock, md_algorithm, data_ref=writer.root_ref)
            reference_array.append(fieldmdp_ref)

            if docmdp_perms is not None:
                # NOTE: this is NOT spec-compatible, but emulates Acrobat
                # behaviour
                fieldmdp_ref['/TransformParams']['/P'] = \
                    generic.NumberObject(docmdp_perms.value)

        if reference_array:
            sig_obj_ref.get_object()['/Reference'] = reference_array
Exemplo n.º 15
0
def docmdp_reference_dictionary(md_algorithm, permission_level: MDPPerm):
    # this is part of the /Reference entry of the signature object.
    return generic.DictionaryObject({
        pdf_name('/Type'):
        pdf_name('/SigRef'),
        pdf_name('/TransformMethod'):
        pdf_name('/DocMDP'),
        pdf_name('/DigestMethod'):
        pdf_name('/' + md_algorithm.upper()),
        pdf_name('/TransformParams'):
        generic.DictionaryObject({
            pdf_name('/Type'):
            pdf_name('/TransformParams'),
            pdf_name('/V'):
            pdf_name('/1.2'),
            pdf_name('/P'):
            generic.NumberObject(permission_level.value)
        })
    })
Exemplo n.º 16
0
def test_append_sig_field_with_simple_sv():
    w = IncrementalPdfFileWriter(BytesIO(MINIMAL))

    sv = fields.SigSeedValueSpec(
        reasons=['a', 'b', 'c'],
        cert=fields.SigCertConstraints(
            subject_dn=FROM_CA.signing_cert.subject,
            issuers=[INTERM_CERT],
            subjects=[FROM_CA.signing_cert],
            key_usage=[
                fields.SigCertKeyUsage.from_sets(
                    {'digital_signature', 'non_repudiation'},
                    {'key_agreement'})
            ]),
        digest_methods=['ssh256'],
        add_rev_info=True,
        subfilters=[fields.SigSeedSubFilter.ADOBE_PKCS7_DETACHED],
        timestamp_server_url='https://tsa.example.com',
    )
    sp = fields.SigFieldSpec('InvisibleSig', seed_value_dict=sv)
    fields.append_signature_field(w, sp)
    out = BytesIO()
    w.write(out)
    out.seek(0)
    r = PdfFileReader(out)
    _, _, sig_field_ref = next(fields.enumerate_sig_fields(r))
    sv_dict = sig_field_ref.get_object()['/SV']
    assert sv_dict['/V'] == generic.NumberObject(2)
    del sv_dict['/V']
    recovered_sv = fields.SigSeedValueSpec.from_pdf_object(sv_dict)
    # x509.Certificate doesn't have an __eq__ implementation apparently,
    # so for the purposes of the test, we replace them by byte dumps
    issuers1 = recovered_sv.cert.issuers
    issuers2 = sv.cert.issuers
    issuers1[0] = issuers1[0].dump()
    issuers2[0] = issuers2[0].dump()

    subjects1 = recovered_sv.cert.subjects
    subjects2 = sv.cert.subjects
    subjects1[0] = subjects1[0].dump()
    subjects2[0] = subjects2[0].dump()
    assert recovered_sv == sv
Exemplo n.º 17
0
def test_pubkey_encryption_dict_errors():
    sh = PubKeySecurityHandler.build_from_certs([PUBKEY_TEST_DECRYPTER.cert])
    original = sh.as_pdf_object()

    encrypt = generic.DictionaryObject(original)
    encrypt['/SubFilter'] = pdf_name('/asdflakdsjf')
    with pytest.raises(misc.PdfReadError):
        PubKeySecurityHandler.build(encrypt)

    encrypt = generic.DictionaryObject(original)
    encrypt['/Length'] = generic.NumberObject(13)
    with pytest.raises(misc.PdfError):
        PubKeySecurityHandler.build(encrypt)

    encrypt = generic.DictionaryObject(original)
    del encrypt['/CF']['/DefaultCryptFilter']['/CFM']
    with pytest.raises(misc.PdfReadError):
        PubKeySecurityHandler.build(encrypt)

    encrypt = generic.DictionaryObject(original)
    encrypt['/CF']['/DefaultCryptFilter']['/CFM'] = pdf_name('/None')
    with pytest.raises(misc.PdfReadError):
        PubKeySecurityHandler.build(encrypt)
Exemplo n.º 18
0
    def __init__(self, tt: ttLib.TTFont, subtype, registry, ordering,
                 supplement, base_ps_name, subset_prefix):

        self._tt = tt

        self.subset_prefix = subset_prefix

        ps_name = '%s+%s' % (subset_prefix, base_ps_name)

        self.name = ps_name
        self.ros = registry, ordering, supplement

        super().__init__({
            pdf_name('/Type'): pdf_name('/Font'),
            pdf_name('/Subtype'): pdf_name(subtype),
            pdf_name('/CIDSystemInfo'): generic.DictionaryObject({
                pdf_name('/Registry'): pdf_string(registry),
                pdf_name('/Ordering'): pdf_string(ordering),
                pdf_name('/Supplement'): generic.NumberObject(supplement)
            }),
            pdf_name('/BaseFont'): pdf_name('/' + ps_name)
        })
        self._font_descriptor = FontDescriptor(self)
Exemplo n.º 19
0
def test_sv_deserialisation():
    sv_input = generic.DictionaryObject({
        pdf_name('/SubFilter'):
        generic.ArrayObject(
            map(pdf_name, ['/foo', '/adbe.pkcs7.detached', '/bleh'])),
        pdf_name('/LegalAttestation'):
        generic.ArrayObject(['xyz', 'abc', 'def']),
        pdf_name('/AppearanceFilter'):
        generic.pdf_string('blah'),
        pdf_name('/LockDocument'):
        generic.pdf_name('/true')
    })
    sv = fields.SigSeedValueSpec.from_pdf_object(sv_input)
    assert len(sv.subfilters) == 1
    assert len(sv.legal_attestations) == 3
    assert sv.lock_document == fields.SeedLockDocument.LOCK
    sv_output = sv.as_pdf_object()
    assert sv_output['/AppearanceFilter'] == sv_input['/AppearanceFilter']
    assert sv_output['/LockDocument'] == sv_input['/LockDocument']
    assert sv_output['/LegalAttestation'] == sv_input['/LegalAttestation']

    with pytest.raises(SigningError):
        fields.SigSeedValueSpec.from_pdf_object(
            generic.DictionaryObject(
                {pdf_name('/LockDocument'): generic.pdf_name('/nonsense')}))
        fields.SigSeedValueSpec.from_pdf_object(
            generic.DictionaryObject(
                {pdf_name('/LockDocument'): generic.BooleanObject(True)}))
    bad_filter = generic.DictionaryObject(
        {pdf_name('/Filter'): pdf_name('/unsupported')})
    # this should run
    fields.SigSeedValueSpec.from_pdf_object(bad_filter)
    with pytest.raises(SigningError):
        bad_filter[pdf_name('/Ff')] = \
            generic.NumberObject(fields.SigSeedValFlags.FILTER.value)
        fields.SigSeedValueSpec.from_pdf_object(bad_filter)
Exemplo n.º 20
0
 def get_object(self, ref, *_args, **_kwargs):
     if ref.idnum == 0:
         return generic.TextStringObject('OK')
     else:
         return generic.ArrayObject([generic.NumberObject(7)])
Exemplo n.º 21
0
    def as_pdf_object(self):
        """
        Render this :class:`.SigSeedValueSpec` object to a PDF dictionary.

        :return:
            A :class:`~.generic.DictionaryObject`.
        """
        min_version = SeedValueDictVersion.PDF_1_5
        result = generic.DictionaryObject({
            pdf_name('/Type'):
            pdf_name('/SV'),
            pdf_name('/Ff'):
            generic.NumberObject(self.flags.value),
        })

        if self.subfilters is not None:
            result[pdf_name('/SubFilter')] = generic.ArrayObject(
                sf.value for sf in self.subfilters)
        if self.add_rev_info is not None:
            min_version = SeedValueDictVersion.PDF_1_7
            result[pdf_name('/AddRevInfo')] = generic.BooleanObject(
                self.add_rev_info)
        if self.digest_methods is not None:
            min_version = SeedValueDictVersion.PDF_1_7
            result[pdf_name('/DigestMethod')] = generic.ArrayObject(
                map(pdf_string, self.digest_methods))
        if self.reasons is not None:
            result[pdf_name('/Reasons')] = generic.ArrayObject(
                pdf_string(reason) for reason in self.reasons)
        if self.timestamp_server_url is not None:
            min_version = SeedValueDictVersion.PDF_1_7
            result[pdf_name('/TimeStamp')] = generic.DictionaryObject({
                pdf_name('/URL'):
                pdf_string(self.timestamp_server_url),
                pdf_name('/Ff'):
                generic.NumberObject(1 if self.timestamp_required else 0)
            })
        if self.cert is not None:
            result[pdf_name('/Cert')] = self.cert.as_pdf_object()
        if self.seed_signature_type is not None:
            mdp_perm = self.seed_signature_type.mdp_perm
            result[pdf_name('/MDP')] = generic.DictionaryObject({
                pdf_name('/P'):
                generic.NumberObject(
                    mdp_perm.value if mdp_perm is not None else 0)
            })
        if self.legal_attestations is not None:
            result[pdf_name('/LegalAttestation')] = generic.ArrayObject(
                pdf_string(att) for att in self.legal_attestations)
        if self.lock_document is not None:
            min_version = SeedValueDictVersion.PDF_2_0
            result[pdf_name('/LockDocument')] = self.lock_document.value
        if self.appearance is not None:
            result[pdf_name('/AppearanceFilter')] = pdf_string(self.appearance)

        specified_version = self.sv_dict_version
        if specified_version is not None:
            result[pdf_name('/V')] = generic.NumberObject(
                specified_version.
                value if isinstance(specified_version, SeedValueDictVersion
                                    ) else specified_version)
        else:
            result[pdf_name('/V')] = generic.NumberObject(min_version.value)
        return result
Exemplo n.º 22
0
def _prepare_sig_field(sig_field_name,
                       root,
                       update_writer: BasePdfFileWriter,
                       existing_fields_only=False,
                       lock_sig_flags=True,
                       **kwargs):
    """
    Returns a tuple of a boolean and a reference to a signature field.
    The boolean is ``True`` if the field was created, and ``False`` otherwise.
    """
    if sig_field_name is None:  # pragma: nocover
        raise ValueError

    try:
        form = root['/AcroForm']

        try:
            fields = form['/Fields']
        except KeyError:
            raise ValueError('/AcroForm has no /Fields')

        candidates = enumerate_sig_fields_in(fields, with_name=sig_field_name)
        sig_field_ref = None
        try:
            field_name, value, sig_field_ref = next(candidates)
            if value is not None:
                raise SigningError(
                    'Signature field with name %s appears to be filled already.'
                    % sig_field_name)
        except StopIteration:
            if existing_fields_only:
                raise SigningError(
                    'No empty signature field with name %s found.' %
                    sig_field_name)
        form_created = False
    except KeyError:
        # we have to create the form
        if existing_fields_only:
            raise SigningError('This file does not contain a form.')
        # no AcroForm present, so create one
        form = generic.DictionaryObject()
        root[pdf_name('/AcroForm')] = update_writer.add_object(form)
        fields = generic.ArrayObject()
        form[pdf_name('/Fields')] = fields
        # now we need to mark the root as updated
        update_writer.update_root()
        form_created = True
        sig_field_ref = None

    if sig_field_ref is not None:
        return False, sig_field_ref

    # no signature field exists, so create one
    # default: grab a reference to the first page
    page_ref = update_writer.find_page_for_modification(0)[0]
    sig_form_kwargs = {'include_on_page': page_ref}
    sig_form_kwargs.update(**kwargs)
    sig_field = SignatureFormField(sig_field_name, **sig_form_kwargs)
    created, sig_field_ref = _insert_or_get_field_at(
        update_writer,
        fields,
        path=sig_field_name.split('.'),
        field_obj=sig_field)
    update_writer.register_annotation(page_ref, sig_field_ref)

    # make sure /SigFlags is present. If not, create it
    sig_flags = 3 if lock_sig_flags else 1
    form.setdefault(pdf_name('/SigFlags'), generic.NumberObject(sig_flags))
    # if a field was added to an existing form, register an extra update
    if not form_created:
        update_writer.update_container(fields)
    return True, sig_field_ref
Exemplo n.º 23
0
    @property
    def document_id(self) -> Tuple[bytes, bytes]:
        raise NotImplementedError

    def get_object(self, ref, *_args, **_kwargs):
        if ref.idnum == 0:
            return generic.TextStringObject('OK')
        else:
            return generic.ArrayObject([generic.NumberObject(7)])


path_test_obj = generic.DictionaryObject({
    pdf_name('/Blah'):
    generic.DictionaryObject({
        pdf_name('/Bleh'):
        generic.ArrayObject([generic.NumberObject(5),
                             pdf_name('/Foo')]),
        pdf_name('/Null'):
        generic.NullObject(),
    }),
    pdf_name('/WithRefs'):
    generic.DictionaryObject({
        pdf_name('/Arr'):
        generic.IndirectObject(1, 0, PathMockHandler()),
        pdf_name('/String'):
        generic.IndirectObject(0, 0, PathMockHandler())
    })
})


@pytest.mark.parametrize('path, result',