Пример #1
0
    def makepdf(self, prev, udct, algomd, zeros):
        catalog = prev.trailer["/Root"]
        size = prev.trailer["/Size"]
        pages = catalog["/Pages"].getObject()
        page0ref = pages["/Kids"][udct.get("sigpage", 0)]

        while len(self._objects) < size - 1:
            self._objects.append(None)

        obj13 = po.DictionaryObject()
        obj13ref = self._addObject(obj13)
        obj12 = po.DictionaryObject()
        obj12ref = self._addObject(obj12)

        obj12.update({
            po.NameObject("/Type"):
            po.NameObject("/Sig"),
            po.NameObject("/Filter"):
            po.NameObject("/Adobe.PPKLite"),
            po.NameObject("/SubFilter"):
            po.NameObject("/adbe.pkcs7.detached"),
            po.NameObject("/Name"):
            po.createStringObject(udct["contact"]),
            po.NameObject("/Location"):
            po.createStringObject(udct["location"]),
            po.NameObject("/Reason"):
            po.createStringObject(udct["reason"]),
            po.NameObject("/M"):
            po.createStringObject(udct["signingdate"]),
            po.NameObject("/Contents"):
            UnencryptedBytes(zeros),
            po.NameObject("/ByteRange"):
            po.ArrayObject([
                WNumberObject(0),
                WNumberObject(0),
                WNumberObject(0),
                WNumberObject(0),
            ]),
        })
        obj13.update({
            po.NameObject("/FT"):
            po.NameObject("/Sig"),
            po.NameObject("/Type"):
            po.NameObject("/Annot"),
            po.NameObject("/Subtype"):
            po.NameObject("/Widget"),
            po.NameObject("/F"):
            po.NumberObject(udct.get("sigflagsft", 132)),
            po.NameObject("/T"):
            EncodedString(udct.get("sigfield", "Signature1")),
            po.NameObject("/V"):
            obj12ref,
            po.NameObject("/P"):
            page0ref,
            po.NameObject("/Rect"):
            po.ArrayObject([
                po.FloatObject(0.0),
                po.FloatObject(0.0),
                po.FloatObject(0.0),
                po.FloatObject(0.0),
            ]),
        })

        box = udct.get("signaturebox", None)
        if box is not None:
            from endesive.pdf.PyPDF2_annotate.annotations.text import FreeText
            from endesive.pdf.PyPDF2_annotate.annotations.image import Image
            from endesive.pdf.PyPDF2_annotate.config.appearance import Appearance
            from endesive.pdf.PyPDF2_annotate.config.location import Location
            from endesive.pdf.PyPDF2_annotate.util.geometry import identity

            annotationtext = udct.get("signature", None)
            x1, y1, x2, y2 = box
            if annotationtext is not None:
                annotation = FreeText(
                    Location(x1=x1, y1=y1, x2=x2, y2=y2, page=0),
                    Appearance(
                        fill=[0, 0, 0],
                        stroke_width=1,
                        wrap_text=True,
                        font_size=12,
                        content=annotationtext,
                    ),
                )
                names = ("BS", "C", "Contents", "DA")
                if not udct.get("sigbutton", False):
                    obj13[po.NameObject("/Subtype")] = po.NameObject(
                        "/FreeText")
            else:
                ap = Appearance()
                ap.image = udct["signature_img"]
                annotation = Image(
                    Location(x1=x1, y1=y1, x2=x2, y2=y2, page=0), ap)
                if not udct.get("sigbutton", False):
                    names = (
                        #
                        "Subtype", )
                else:
                    names = ()

            pdfa = annotation.as_pdf_object(identity(), page=page0ref)
            objapn = self._extend(pdfa["/AP"]["/N"])
            objapnref = self._addObject(objapn)

            for name in names + (
                    "Rect",
                    # "Subtype",
            ):
                key = po.NameObject("/" + name)
                v = pdfa[key]
                obj13[key] = v

            objap = po.DictionaryObject()
            objap[po.NameObject("/N")] = objapnref
            obj13.update({
                po.NameObject("/AP"):
                objap,
                po.NameObject("/SM"):
                po.createStringObject("TabletPOSinline"),
            })

            page0 = page0ref.getObject()
            annots = po.ArrayObject([obj13ref])
            if "/Annots" in page0:
                page0annots = page0["/Annots"]
                if isinstance(page0annots, po.IndirectObject):
                    annots.insert(0, page0annots)
                elif isinstance(page0annots, po.ArrayObject):
                    annots = page0annots
                    annots.append(obj13ref)
            page0.update({po.NameObject("/Annots"): annots})
            self._objects[page0ref.idnum - 1] = page0

        if "/Perms" not in catalog:
            obj10 = po.DictionaryObject()
            obj10ref = self._addObject(obj10)
            obj11 = po.DictionaryObject()
            obj11ref = self._addObject(obj11)
            obj14 = po.DictionaryObject()
            obj14ref = self._addObject(obj14)
            obj14.update({po.NameObject("/DocMDP"): obj12ref})
            obj10.update({
                po.NameObject("/Type"):
                po.NameObject("/TransformParams"),
                po.NameObject("/P"):
                po.NumberObject(2),
                po.NameObject("/V"):
                po.NameObject("/1.2"),
            })
            obj11.update({
                po.NameObject("/Type"):
                po.NameObject("/SigRef"),
                po.NameObject("/TransformMethod"):
                po.NameObject("/DocMDP"),
                po.NameObject("/DigestMethod"):
                po.NameObject("/" + algomd.upper()),
                po.NameObject("/TransformParams"):
                obj10ref,
            })
            obj12[po.NameObject("/Reference")] = po.ArrayObject([obj11ref])
            catalog[po.NameObject("/Perms")] = obj14ref

        if "/AcroForm" in catalog:
            form = catalog["/AcroForm"].getObject()
            if "/Fields" in form:
                fields = form["/Fields"]
            else:
                fields = po.ArrayObject()
            fields.append(obj13ref)
            form.update({
                po.NameObject("/Fields"):
                fields,
                po.NameObject("/SigFlags"):
                po.NumberObject(udct.get("sigflags", 3)),
            })
            formref = catalog.raw_get("/AcroForm")
            if isinstance(formref, po.IndirectObject):
                self._objects[formref.idnum - 1] = form
                form = formref
        else:
            form = po.DictionaryObject()
            form.update({
                po.NameObject("/Fields"):
                po.ArrayObject([obj13ref]),
                po.NameObject("/SigFlags"):
                po.NumberObject(udct.get("sigflags", 3)),
            })
        catalog[po.NameObject("/AcroForm")] = form

        if "/Metadata" in catalog:
            catalog[po.NameObject("/Metadata")] = catalog.raw_get("/Metadata")

        x_root = prev.trailer.raw_get("/Root")
        self._objects[x_root.idnum - 1] = catalog
        self.x_root = po.IndirectObject(x_root.idnum, 0, self)
        self.x_info = prev.trailer.raw_get("/Info")
Пример #2
0
    def makepdf(self, prev, udct, algomd, zeros, cert, **params):
        catalog = prev.trailer["/Root"]
        size = prev.trailer["/Size"]
        pages = catalog["/Pages"].getObject()
        page0ref = prev.getPage(udct.get("sigpage", 0)).indirectRef

        self._objects = []
        while len(self._objects) < size - 1:
            self._objects.append(None)


##        if params['mode'] == 'timestamp':
##            # deal with extensions
##            if '/Extensions' not in catalog:
##                extensions = po.DictionaryObject()
##            else:
##                extensions = catalog['/Extensions']
##
##            if '/ESIC' not in extensions:
##                extensions.update({
##                    po.NameObject("/ESIC"): po.DictionaryObject({
##                        po.NameObject('/BaseVersion'): po.NameObject('/1.7'),
##                        po.NameObject('/ExtensionLevel'): po.NumberObject(1),
##                        })
##                    })
##            else:
##                esic = extensions['/ESIC']
##                major, minor = esic['/BaseVersion'].lstrip('/').split('.')
##                if int(major) < 1 or int(minor) < 7:
##                    esic.update({
##                        po.NameObject('/BaseVersion'): po.NameObject('/1.7'),
##                        po.NameObject('/ExtensionLevel'): po.NumberObject(1),
##                        })
##            catalog.update({
##                po.NameObject('/Extensions'): extensions
##                })

# obj12 is the digital signature
        obj12, obj12ref = self._make_signature(
            Type=po.NameObject("/Sig"),
            SubFilter=po.NameObject("/adbe.pkcs7.detached"),
            Contents=UnencryptedBytes(zeros),
        )

        if params['mode'] == 'timestamp':
            # obj12 is a timestamp this time
            obj12.update({
                po.NameObject("/Type"):
                po.NameObject("/DocTimeStamp"),
                po.NameObject("/SubFilter"):
                po.NameObject("/ETSI.RFC3161"),
                po.NameObject("/V"):
                po.NumberObject(0),
            })
        else:
            obj12.update({
                po.NameObject("/Name"):
                po.createStringObject(udct["contact"]),
                po.NameObject("/Location"):
                po.createStringObject(udct["location"]),
                po.NameObject("/Reason"):
                po.createStringObject(udct["reason"]),
            })
            if params.get('use_signingdate'):
                obj12.update({
                    po.NameObject("/M"):
                    po.createStringObject(udct["signingdate"]),
                })

        # obj13 is a combined AcroForm Sig field with Widget annotation
        new_13 = True
        #obj13 = po.DictionaryObject()
        if udct.get('signform', False):
            # Attaching signature to existing field in AcroForm
            if "/AcroForm" in catalog:
                form = catalog["/AcroForm"].getObject()
                if "/Fields" in form:
                    fields = form["/Fields"].getObject()
                    obj13ref = [
                        f for f in fields if f.getObject()['/T'] == udct.get(
                            'sigfield', 'Signature1')
                    ][0]
                    obj13 = obj13ref.getObject()
                    self._objects[obj13ref.idnum - 1] = obj13
                    new_13 = False

        # box is coordinates of the annotation to fill
        box = udct.get("signaturebox", None)

        if new_13:
            obj13, obj13ref = self._make_sig_annotation(
                F=po.NumberObject(udct.get("sigflagsft", 132)),
                T=EncodedString(udct.get("sigfield", "Signature1")),
                Vref=obj12ref,
                Pref=page0ref,
            )
        else:
            # original obj13 is a merged SigField/SigAnnot
            # Setting /V on the AcroForm field sets the signature
            # for the field
            obj13.update({
                po.NameObject("/V"): obj12ref,
            })
            # fill the existing signature field annotation,
            # ignore any other location
            if "/Rect" in obj13:
                box = [float(f) for f in obj13["/Rect"]]

        # add an annotation if there is a field to fill
        if box is not None:
            from endesive.pdf.PyPDF2_annotate.annotations.signature import Signature
            from endesive.pdf.PyPDF2_annotate.config.appearance import Appearance
            from endesive.pdf.PyPDF2_annotate.config.location import Location
            from endesive.pdf.PyPDF2_annotate.util.geometry import identity

            x1, y1, x2, y2 = box
            annotation = Signature(
                Location(x1=x1, y1=y1, x2=x2, y2=y2, page=0),
                Appearance(),
            )
            if 'signature' in udct:
                # Plain text signature with the default font
                # text to render is contained in udct['signature']
                # font parameters are in udct['signature']['text']
                annotationtext = udct["signature"]
                wrap_text = udct.get('text', {}).get('wraptext', True)
                font_size = udct.get('text', {}).get('fontsize', 12)
                text_align = udct.get('text', {}).get('textalign', 'left')
                line_spacing = udct.get('text', {}).get('linespacing', 1.2)

                annotation.add_default_font()
                annotation.set_signature_appearance(
                    ['fill_colour', 0, 0, 0], ['font', 'default', font_size], [
                        'text_box', annotationtext, 'default', 0, 0, x2 - x1,
                        y2 - y1, font_size, wrap_text, text_align, 'middle',
                        line_spacing
                    ])
            elif 'signature_img' in udct:
                # Simple image signature, stretches to fit the box
                # image to render is contained in udct['signature_image']
                annotation.add_image(udct["signature_img"], "Image")
                annotation.set_signature_appearance([
                    'image',
                    "Image",
                    0,
                    0,
                    x2 - x1,
                    y2 - y1,
                    udct.get('signature_img_distort', True),
                    udct.get('signature_img_centred', False),
                ])
            elif 'signature_appearance' in udct:
                # Adobe-inspired signature with text and images
                # Parameters are contained in udct['signature_appearance']
                # If a field is included in the display list, that field
                # will be contained in the annotation.
                #
                # Text and border are the colour specified by outline,
                # and border is the the inset distance from the outer
                # edge of the annotation.  The R G B values range between
                # 0 and 1.
                #
                # Icon is an image to display above the background and
                # border at the left-hand side of the anntoation.  If
                # there is no text, it is centred.
                #
                # The text block is left-aligned to the right of the icon
                # image.  If there is no image, the text is left-aliged
                # with the left-hand border of the annotation
                #
                # display fields:
                #   CN, DN, date, contact, reason, location
                #
                # Dict format:
                #   appearance = dict(
                #       background = Image with alpha / None,
                #       icon = Image with alpha / None,
                #       labels = bool,
                #       display = list,
                #       software = str,
                #       outline = [R, G, B],
                #       border = int,
                #       )
                sig = {}
                for f in ('background', 'icon', 'labels', 'border', 'outline'):
                    if f in udct['signature_appearance']:
                        sig[f] = udct['signature_appearance'][f]

                toggles = udct['signature_appearance'].get('display', [])
                for f in ('contact', 'reason', 'location', 'contact',
                          'signingdate'):
                    if f in toggles:
                        sig[f] = udct.get(f, '{} unknown'.format(f))
                if 'date' in toggles:
                    sig['date'] = udct['signingdate']
                if 'CN' in toggles:
                    from cryptography.x509 import ObjectIdentifier
                    sig['CN'] = cert.subject.get_attributes_for_oid(
                        ObjectIdentifier('2.5.4.3'))[0].value
                if 'DN' in toggles:
                    sig['DN'] = cert.subject.rfc4514_string()
                annotation.simple_signature(sig)
            else:
                # Manual signature annotation creation
                #
                # Make your own appearance with an arbitrary number of
                # images and fonts
                if 'manual_images' in udct:
                    for name, img in udct['manual_images'].items():
                        annotation.add_image(img, name=name)
                if 'manual_fonts' in udct:
                    for name, path in udct['manual_fonts'].items():
                        annotation.add_ttf_font(path, name=name)
                annotation.add_default_font()
                annotation.set_signature_appearance(*udct['signature_manual'])

            pdfa = annotation.as_pdf_object(identity(), page=page0ref)
            objapn = self._extend(pdfa["/AP"]["/N"])
            objapnref = self._addObject(objapn)

            objap = po.DictionaryObject()
            objap[po.NameObject("/N")] = objapnref
            obj13.update({
                po.NameObject("/Rect"):
                po.ArrayObject([
                    po.FloatObject(x1),
                    po.FloatObject(y1),
                    po.FloatObject(x2),
                    po.FloatObject(y2),
                ]),
                po.NameObject("/AP"):
                objap,
                #po.NameObject("/SM"): po.createStringObject("TabletPOSinline"),
            })

            page0 = page0ref.getObject()
            if new_13:
                annots = po.ArrayObject([obj13ref])
                if "/Annots" in page0:
                    page0annots = page0["/Annots"]
                    if isinstance(page0annots, po.IndirectObject):
                        annots.insert(0, page0annots)
                    elif isinstance(page0annots, po.ArrayObject):
                        annots = page0annots
                        annots.append(obj13ref)
            else:
                annots = page0["/Annots"]
            page0.update({po.NameObject("/Annots"): annots})
            self._objects[page0ref.idnum - 1] = page0

        if udct.get("sigandcertify", False) and "/Perms" not in catalog:
            obj10 = po.DictionaryObject()
            obj10ref = self._addObject(obj10)
            obj11 = po.DictionaryObject()
            obj11ref = self._addObject(obj11)
            obj14 = po.DictionaryObject()
            obj14ref = self._addObject(obj14)
            obj14.update({po.NameObject("/DocMDP"): obj12ref})
            obj10.update({
                po.NameObject("/Type"):
                po.NameObject("/TransformParams"),
                po.NameObject("/P"):
                po.NumberObject(udct.get("sigflags", 3)),
                po.NameObject("/V"):
                po.NameObject("/1.2"),
            })
            obj11.update({
                po.NameObject("/Type"):
                po.NameObject("/SigRef"),
                po.NameObject("/TransformMethod"):
                po.NameObject("/DocMDP"),
                po.NameObject("/DigestMethod"):
                po.NameObject("/" + algomd.upper()),
                po.NameObject("/TransformParams"):
                obj10ref,
            })
            obj12[po.NameObject("/Reference")] = po.ArrayObject([obj11ref])
            catalog[po.NameObject("/Perms")] = obj14ref

        if "/AcroForm" in catalog:
            form = catalog["/AcroForm"].getObject()
            if "/Fields" in form:
                fields = form["/Fields"]
                old_field_names = [f.getObject()['/T'] for f in fields]
            else:
                fields = po.ArrayObject()
                old_field_names = []
            if udct.get('auto_sigfield',
                        False) and obj13['/T'] in old_field_names:
                name_base = udct.get('sigfield', 'Signature1')
                checklist = [
                    f[len(name_base):] for f in old_field_names
                    if f.startswith(name_base)
                ]
                for i in range(1, len(checklist) + 1):
                    suffix = '_{}'.format(i)
                    if suffix in checklist:
                        next

                    new_name = '{}{}'.format(name_base, suffix)
                    obj13.update(
                        {po.NameObject("/T"): EncodedString(new_name)})
                    break

            old_flags = int(form.get("/SigFlags", 0))
            new_flags = int(form.get("/SigFlags", 0)) | udct.get("sigflags", 3)
            if new_13:
                fields.append(obj13ref)
                form.update({
                    po.NameObject("/Fields"):
                    fields,
                    po.NameObject("/SigFlags"):
                    po.NumberObject(new_flags),
                })
            elif new_flags > old_flags:
                form.update({
                    po.NameObject("/SigFlags"):
                    po.NumberObject(new_flags),
                })
            formref = catalog.raw_get("/AcroForm")
            if isinstance(formref, po.IndirectObject):
                self._objects[formref.idnum - 1] = form
                form = formref
        else:
            form = po.DictionaryObject()
            form.update({
                po.NameObject("/Fields"):
                po.ArrayObject([obj13ref]),
                po.NameObject("/SigFlags"):
                po.NumberObject(udct.get("sigflags", 3)),
            })
        catalog[po.NameObject("/AcroForm")] = form

        if "/Metadata" in catalog:
            catalog[po.NameObject("/Metadata")] = catalog.raw_get("/Metadata")

        x_root = prev.trailer.raw_get("/Root")
        self._objects[x_root.idnum - 1] = catalog
        self.x_root = po.IndirectObject(x_root.idnum, 0, self)
        self.x_info = prev.trailer.get("/Info")