-
Notifications
You must be signed in to change notification settings - Fork 87
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
Conversation
…res. Whitespace was causing ByteRange to not cover the entire document. Ideally should be everything outside the < > in the signature Contents field.
Using updated pkcs7 package updated by mozilla
…riting to a buffer.
Codecov Report
@@ 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
Continue to review full report at Codecov.
|
There was a problem hiding this 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
Outdated
} | ||
a.written = true |
There was a problem hiding this comment.
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?
pdf/model/signature.go
Outdated
@@ -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 { |
There was a problem hiding this comment.
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)
pdf/model/signature.go
Outdated
container := pss.container | ||
dict := container.PdfObject.(*core.PdfObjectDictionary) | ||
|
||
if pss.Ff != nil { |
There was a problem hiding this comment.
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
pdf/model/signature.go
Outdated
func (pcs *PdfCertificateSeed) ToPdfObject() core.PdfObject { | ||
container := pcs.container | ||
dict := container.PdfObject.(*core.PdfObjectDictionary) | ||
if pcs.Ff != nil { |
There was a problem hiding this comment.
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.
pdf/model/signature_handler.go
Outdated
if err != nil { | ||
return nil, err | ||
} | ||
pairs = append(pairs, &sigFieldPair{sig: sig, field: f}) |
There was a problem hiding this comment.
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)
pdf/model/signature.go
Outdated
@@ -201,6 +291,9 @@ func (sf *PdfSignatureField) ToPdfObject() core.PdfObject { | |||
if sf.SV != nil { | |||
dict.Set("SV", sf.SV) | |||
} | |||
if sf.Kids != nil { |
There was a problem hiding this comment.
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
pdf/model/appearance.go
Outdated
|
||
// PdfSignatureAppearance defines a signature with a specified form field and | ||
// annotation widget for appearance styling. | ||
type PdfSignatureAppearance struct { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
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
There was a problem hiding this 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.
pdf/model/appender.go
Outdated
@@ -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. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Inaccurate "Returns a PdfFieldSignature..."
There was a problem hiding this comment.
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.
pdf/model/appender.go
Outdated
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. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
invocations
pdf/model/appender.go
Outdated
@@ -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. |
There was a problem hiding this comment.
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") |
There was a problem hiding this comment.
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 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
remove commented code
pdf/model/appender.go
Outdated
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 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Incomplete sentence
Minor code documentation improvements
Expands on #280 and addresses a few issues pointed out there.