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
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) ) })
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()}))
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)
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
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)
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
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
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)
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')
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
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
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
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
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) }) })
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
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)
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)
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)
def get_object(self, ref, *_args, **_kwargs): if ref.idnum == 0: return generic.TextStringObject('OK') else: return generic.ArrayObject([generic.NumberObject(7)])
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
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
@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',