diff --git a/go.mod b/go.mod index cd94148..4949b27 100644 --- a/go.mod +++ b/go.mod @@ -1,12 +1,14 @@ module github.com/digitorus/pdfsign -go 1.22 +go 1.23.0 + +toolchain go1.23.6 require ( github.com/digitorus/pdf v0.1.2 github.com/digitorus/pkcs7 v0.0.0-20230818184609-3a137a874352 github.com/digitorus/timestamp v0.0.0-20231217203849-220c5c2851b7 github.com/mattetti/filebuffer v1.0.1 - golang.org/x/crypto v0.33.0 - golang.org/x/text v0.22.0 + golang.org/x/crypto v0.35.0 + golang.org/x/text v0.25.0 ) diff --git a/go.sum b/go.sum index efe10c3..a0c2832 100644 --- a/go.sum +++ b/go.sum @@ -7,7 +7,7 @@ github.com/digitorus/timestamp v0.0.0-20231217203849-220c5c2851b7 h1:lxmTCgmHE1G github.com/digitorus/timestamp v0.0.0-20231217203849-220c5c2851b7/go.mod h1:GvWntX9qiTlOud0WkQ6ewFm0LPy5JUR1Xo0Ngbd1w6Y= github.com/mattetti/filebuffer v1.0.1 h1:gG7pyfnSIZCxdoKq+cPa8T0hhYtD9NxCdI4D7PTjRLM= github.com/mattetti/filebuffer v1.0.1/go.mod h1:YdMURNDOttIiruleeVr6f56OrMc+MydEnTcXwtkxNVs= -golang.org/x/crypto v0.33.0 h1:IOBPskki6Lysi0lo9qQvbxiQ+FvsCC/YWOecCHAixus= -golang.org/x/crypto v0.33.0/go.mod h1:bVdXmD7IV/4GdElGPozy6U7lWdRXA4qyRVGJV57uQ5M= -golang.org/x/text v0.22.0 h1:bofq7m3/HAFvbF51jz3Q9wLg3jkvSPuiZu/pD1XwgtM= -golang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY= +golang.org/x/crypto v0.35.0 h1:b15kiHdrGCHrP6LvwaQ3c03kgNhhiMgvlhxHQhmg2Xs= +golang.org/x/crypto v0.35.0/go.mod h1:dy7dXNW32cAb/6/PRuTNsix8T+vJAqvuIy5Bli/x0YQ= +golang.org/x/text v0.25.0 h1:qVyWApTSYLk/drJRO5mDlNYskwQznZmkpV2c8q9zls4= +golang.org/x/text v0.25.0/go.mod h1:WEdwpYrmk1qmdHvhkSTNPm3app7v4rsT8F2UD6+VHIA= diff --git a/sign/pdfcatalog.go b/sign/pdfcatalog.go index a8c0d07..8f16c18 100644 --- a/sign/pdfcatalog.go +++ b/sign/pdfcatalog.go @@ -28,9 +28,10 @@ func (context *SignContext) createCatalog() ([]byte, error) { // written in the PDF file (for example, /1.4). // // If an incremental upgrade requires a version that is higher than specified by the document. - // if context.PDFReader.PDFVersion < "2.0" { - // catalog_buffer.WriteString(" /Version /2.0") - // } + // Ensure PDF version is at least 1.5 to support SigFlags in acroFormDict (1.4) and UF in the fileSpecDict (1.5) + if v, err := strconv.ParseFloat(context.PDFReader.PDFVersion, 64); err == nil && v < 1.5 { + catalog_buffer.WriteString(" /Version /1.5\n") + } // Retrieve the root, its pointer and set the root string root := context.PDFReader.Trailer().Key("Root") diff --git a/sign/pdfcatalog_test.go b/sign/pdfcatalog_test.go index e47a4ab..76da046 100644 --- a/sign/pdfcatalog_test.go +++ b/sign/pdfcatalog_test.go @@ -21,11 +21,11 @@ var testFiles = []struct { }, }, { - file: "../testfiles/testfile21.pdf", + file: "../testfiles/testfile12.pdf", expectedCatalogs: map[CertType]string{ - CertificationSignature: "<<\n /Type /Catalog\n /Metadata 8 0 R\n /Names 6 0 R\n /Pages 9 0 R\n /AcroForm <<\n /Fields [16 0 R]\n /SigFlags 3\n >>\n>>\n", - UsageRightsSignature: "<<\n /Type /Catalog\n /Metadata 8 0 R\n /Names 6 0 R\n /Pages 9 0 R\n /AcroForm <<\n /Fields [16 0 R]\n /SigFlags 1\n >>\n>>\n", - ApprovalSignature: "<<\n /Type /Catalog\n /Metadata 8 0 R\n /Names 6 0 R\n /Pages 9 0 R\n /AcroForm <<\n /Fields [16 0 R]\n /SigFlags 3\n >>\n>>\n", + CertificationSignature: "<<\n /Type /Catalog\n /Version /1.5\n /Outlines 2 0 R\n /Pages 3 0 R\n /AcroForm <<\n /Fields [16 0 R]\n /SigFlags 3\n >>\n>>\n", + UsageRightsSignature: "<<\n /Type /Catalog\n /Version /1.5\n /Outlines 2 0 R\n /Pages 3 0 R\n /AcroForm <<\n /Fields [16 0 R]\n /SigFlags 1\n >>\n>>\n", + ApprovalSignature: "<<\n /Type /Catalog\n /Version /1.5\n /Outlines 2 0 R\n /Pages 3 0 R\n /AcroForm <<\n /Fields [16 0 R]\n /SigFlags 3\n >>\n>>\n", }, }, } diff --git a/sign/pdftrailer.go b/sign/pdftrailer.go index 8268731..6227ae4 100644 --- a/sign/pdftrailer.go +++ b/sign/pdftrailer.go @@ -43,7 +43,7 @@ func (context *SignContext) writeTrailer() error { lines[i] = " " + strings.TrimSpace(line) } } - trailer_string = strings.Join(lines, "\n") + trailer_string = strings.Join(lines, "\n") + "\n" // Write the new trailer. if _, err := context.OutputBuffer.Write([]byte(trailer_string)); err != nil { @@ -54,7 +54,6 @@ func (context *SignContext) writeTrailer() error { return err } } - // Write the new xref start position. if _, err := context.OutputBuffer.Write([]byte(strconv.FormatInt(context.NewXrefStart, 10) + "\n")); err != nil { return err diff --git a/sign/pdfvisualsignature.go b/sign/pdfvisualsignature.go index 6e9e957..23c43c4 100644 --- a/sign/pdfvisualsignature.go +++ b/sign/pdfvisualsignature.go @@ -128,9 +128,25 @@ func (context *SignContext) createIncPageUpdate(pageNumber, annot uint32) ([]byt // TODO: Update digitorus/pdf to get raw values without resolving pointers for _, key := range page.Keys() { switch key { - case "Contents", "Parent": + case "Parent": ptr := page.Key(key).GetPtr() page_buffer.WriteString(fmt.Sprintf(" /%s %d 0 R\n", key, ptr.GetID())) + case "Contents": + // Special handling for Contents - must preserve stream structure + contentsValue := page.Key(key) + if contentsValue.Kind() == pdf.Array { + // If Contents is an array, keep it as an array reference + page_buffer.WriteString(" /Contents [") + for i := 0; i < contentsValue.Len(); i++ { + ptr := contentsValue.Index(i).GetPtr() + page_buffer.WriteString(fmt.Sprintf(" %d 0 R", ptr.GetID())) + } + page_buffer.WriteString(" ]\n") + } else { + // If Contents is a single reference, keep it as a single reference + ptr := contentsValue.GetPtr() + page_buffer.WriteString(fmt.Sprintf(" /%s %d 0 R\n", key, ptr.GetID())) + } case "Annots": page_buffer.WriteString(" /Annots [\n") for i := 0; i < page.Key("Annots").Len(); i++ { diff --git a/sign/pdfxref_test.go b/sign/pdfxref_test.go index 1a81a11..a107ca9 100644 --- a/sign/pdfxref_test.go +++ b/sign/pdfxref_test.go @@ -20,7 +20,6 @@ func TestGetLastObjectIDFromXref(t *testing.T) { {"testfile16.pdf", 567}, {"testfile17.pdf", 20}, {"testfile20.pdf", 10}, - {"testfile21.pdf", 16}, } for _, tc := range testCases { diff --git a/testfiles/testfile21.pdf b/testfiles/testfile21.pdf deleted file mode 100644 index f7f0908..0000000 Binary files a/testfiles/testfile21.pdf and /dev/null differ