Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WIP: Initial digital signature support (v3) #334

Merged
merged 27 commits into from
Feb 19, 2019
Merged

WIP: Initial digital signature support (v3) #334

merged 27 commits into from
Feb 19, 2019

Conversation

gunnsth
Copy link
Contributor

@gunnsth gunnsth commented Jan 25, 2019

Expands on #280 and addresses a few issues pointed out there.

@codecov
Copy link

codecov bot commented Jan 25, 2019

Codecov Report

Merging #334 into v3 will increase coverage by 0.64%.
The diff coverage is 71.2%.

Impacted file tree graph

@@            Coverage Diff            @@
##              v3     #334      +/-   ##
=========================================
+ Coverage   59.6%   60.24%   +0.64%     
=========================================
  Files        149      152       +3     
  Lines      26742    27169     +427     
=========================================
+ Hits       15940    16369     +429     
- Misses     10291    10408     +117     
+ Partials     511      392     -119
Impacted Files Coverage Δ
pdf/model/form.go 60.34% <100%> (-0.13%) ⬇️
pdf/core/primitives.go 78.85% <100%> (+0.72%) ⬆️
pdf/model/writer.go 82.92% <100%> (+0.36%) ⬆️
pdf/model/sighandler/sighandler_rsa_sha1.go 7.31% <5.4%> (ø)
pdf/model/sighandler/sighandler_pkcs7.go 66.66% <66.66%> (ø)
pdf/model/signature_handler.go 68.8% <68.8%> (ø)
pdf/model/structures.go 80% <80%> (ø) ⬆️
pdf/model/fields.go 54.94% <88%> (+1.33%) ⬆️
pdf/model/signature.go 87.7% <88.75%> (+32.14%) ⬆️
pdf/model/appender.go 86.63% <93.98%> (+7.68%) ⬆️
... and 49 more

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 65e8637...0fa9092. Read the comment docs.

@gunnsth gunnsth requested a review from adrg February 7, 2019 10:05
@gunnsth gunnsth added this to the v3.0.0-alpha.3 milestone Feb 7, 2019
Copy link
Collaborator

@adrg adrg left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The code and the logic look good to me. I left a couple of suggestions, minor changes.

pdf/model/appender.go Show resolved Hide resolved
}
a.written = true
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should the written field be set at the end of the method, after a successful write?

@@ -90,8 +174,15 @@ func (sig *PdfSignature) ToPdfObject() core.PdfObject {
if sig.ContactInfo != nil {
dict.Set("ContactInfo", sig.ContactInfo)
}

// FIXME: ByteRange and Contents need to be updated dynamically.
if sig.ByteRange != nil {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe use:

dict.SetIfNotNil("ByteRange", sig.ByteRange)
dict.SetIfNotNil("Contents", sig.Contents)

container := pss.container
dict := container.PdfObject.(*core.PdfObjectDictionary)

if pss.Ff != nil {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

dict.SetIfNotNil can be used for all the fields that may be nil

func (pcs *PdfCertificateSeed) ToPdfObject() core.PdfObject {
container := pcs.container
dict := container.PdfObject.(*core.PdfObjectDictionary)
if pcs.Ff != nil {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

dict.SetIfNotNil can be used for all the fields that may be nil.

if err != nil {
return nil, err
}
pairs = append(pairs, &sigFieldPair{sig: sig, field: f})
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Finding the applicable handler could be done here in order to avoid extra iterations:

pair := &sigFieldPair{sig: sig, field: f}
for _, handler := range handlers {
    if handler.IsApplicable(pair.sig) {
        pair.handler = handler
        break
    }
}

pairs = append(pairs, pair)

@@ -201,6 +291,9 @@ func (sf *PdfSignatureField) ToPdfObject() core.PdfObject {
if sf.SV != nil {
dict.Set("SV", sf.SV)
}
if sf.Kids != nil {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

dict.SetIfNotNil can be used for all the fields that may be nil


// PdfSignatureAppearance defines a signature with a specified form field and
// annotation widget for appearance styling.
type PdfSignatureAppearance struct {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@adrg Can you check whether you feel that this type is a duplicate of PdfFieldSignature in fields.go?

type PdfFieldSignature struct {

Technically this one is more high level for creating signatures, so I suppose it's OK, although it could be confusing.

Copy link
Collaborator

@adrg adrg Feb 13, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@gunnsth I do find it very similar to PdfFieldSignature. The only difference I can see is that PdfSignatureAppearance is also a widget. If that's the case, the PdfSignatureAppearance struct could be merged into PdfFieldSignature.

Can you please review my branch v3-a5i-pdf-sign? I merged the two structures there.
https://github.com/adrg/unidoc/tree/v3-a5i-pdf-sign

Copy link
Contributor Author

@gunnsth gunnsth left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A few minor changes needed.

@@ -370,19 +379,72 @@ func (a *PdfAppender) ReplacePage(pageNum int, page *PdfPage) {
}
}

// ReplaceAcroForm replaces the acrobat form. It appends a new form to the Pdf which replaces the original acrobat form.
// Sign signs a specific page with a digital signature using a specified signature handler.
// Returns a PdfFieldSignature that can be used to customize the signature appearance.
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Inaccurate "Returns a PdfFieldSignature..."

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should be:
The signature field specified must have a valid signature dictionary specified by its V field.

func (a *PdfAppender) ReplaceAcroForm(acroForm *PdfAcroForm) {
a.acroForm = acroForm
}

// Write writes the Appender output to io.Writer.
// It can only be called once and further invokations will result in an error.
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

invocations

@@ -132,7 +141,7 @@ func (a *PdfAppender) addNewObjects(obj core.PdfObject) {
switch v := obj.(type) {
case *core.PdfIndirectObject:
// Check the object is changing.
// If the indirect object has not the readonly parser then the object is changed.
// If the indirect object has not the read-only parser then the object is changed.
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the indirect object does not have the read-only parser, then the object has changed.

handler := *a
sig.Handler = &handler
sig.Filter = core.MakeName("Adobe.PPKLite")
//sig.Filter = core.MakeName("Adobe.PPKMS")
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove commented code

/*
switch sa {
case x509.SHA1WithRSA:
return crypto.SHA1, true
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove commented code

if hasSigDict {
// For signatures, we need to write twice. First to find the byte offset of the Contents and then
// dynamically update file with the signature and ByteRange.
// Thus we create an empty buffer to write to and then at the e
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Incomplete sentence

@gunnsth gunnsth merged commit c8b70ef into v3 Feb 19, 2019
@gunnsth gunnsth deleted the v3-a5i-pdf-sign branch February 19, 2019 17:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
3 participants