Skip to content

Commit

Permalink
Prepare examples for rc-v3.29.0 (#164)
Browse files Browse the repository at this point in the history
* Add more advanced text search and replace example

* Added a new example with the signing document twice. It works with a previously signed document.

* Added a new example with signing an encrypted document.

* Fix naming

* return license check

* fix permissions for write file

* update modules etc

* fix for compatibility

Co-authored-by: Adrian-George Bostan <adrg@epistack.com>
Co-authored-by: Fizz <diku55@mail.ru>
  • Loading branch information
3 people committed Sep 24, 2021
1 parent 7f18899 commit afb2e6c
Show file tree
Hide file tree
Showing 5 changed files with 743 additions and 4 deletions.
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ require (
github.com/miekg/pkcs11 v1.0.3 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/sirupsen/logrus v1.8.1 // indirect
github.com/unidoc/unipdf/v3 v3.28.0
github.com/unidoc/unipdf/v3 v3.29.0
github.com/wcharczuk/go-chart/v2 v2.1.0
golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b
golang.org/x/image v0.0.0-20210220032944-ac19c3e999fb // indirect
Expand Down
5 changes: 2 additions & 3 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,8 @@ github.com/unidoc/pkcs7 v0.0.0-20200411230602-d883fd70d1df h1:1RV3lxQ6L6xGFNhngp
github.com/unidoc/pkcs7 v0.0.0-20200411230602-d883fd70d1df/go.mod h1:UEzOZUEpJfDpywVJMUT8QiugqEZC29pDq7kdIZhWCr8=
github.com/unidoc/timestamp v0.0.0-20200412005513-91597fd3793a h1:RLtvUhe4DsUDl66m7MJ8OqBjq8jpWBXPK6/RKtqeTkc=
github.com/unidoc/timestamp v0.0.0-20200412005513-91597fd3793a/go.mod h1:j+qMWZVpZFTvDey3zxUkSgPJZEX33tDgU/QIA0IzCUw=
github.com/unidoc/unipdf/v3 v3.28.0 h1:flSCHcrfPHbxaSMltbUqk2Kd+2CsYWOiItj8XqRQc4o=
github.com/unidoc/unipdf/v3 v3.28.0/go.mod h1:WdRz3hVhi/M0jFGXhsT5/9FDyRfga6KgI2ZQqjiOXaM=
github.com/unidoc/unipdf/v3 v3.29.0 h1:aM1qO1dFfM5H6BOXdgTbIJBBFxyEDI36cJnCS8JXmRQ=
github.com/unidoc/unipdf/v3 v3.29.0/go.mod h1:WdRz3hVhi/M0jFGXhsT5/9FDyRfga6KgI2ZQqjiOXaM=
github.com/unidoc/unitype v0.2.1 h1:x0jMn7pB/tNrjEVjy3Ukpxo++HOBQaTCXcTYFA6BH3w=
github.com/unidoc/unitype v0.2.1/go.mod h1:mafyug7zYmDOusqa7G0dJV45qp4b6TDAN+pHN7ZUIBU=
github.com/wcharczuk/go-chart/v2 v2.1.0 h1:tY2slqVQ6bN+yHSnDYwZebLQFkphK4WNrVwnt7CJZ2I=
Expand Down Expand Up @@ -89,7 +89,6 @@ golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1N
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
gopkg.in/gographics/imagick.v2 v2.6.0 h1:ewRsUQk3QkjGumERlndbFn/kTYRjyMaPY5gxwpuAhik=
gopkg.in/gographics/imagick.v2 v2.6.0/go.mod h1:/QVPLV/iKdNttRKthmDkeeGg+vdHurVEPc8zkU0XgBk=
Expand Down
233 changes: 233 additions & 0 deletions signatures/pdf_sign_and_encrypt_pdf.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,233 @@
/*
* This example showcases how to append a new page with signature to a PDF document.
* The file is signed using a private/public key pair.
*
* $ ./pdf_sign_encrypted_pdf <INPUT_PDF_PATH> <OUTPUT_PDF_PATH>
*/
package main

import (
"bytes"
"crypto/rand"
"crypto/rsa"
"crypto/x509"
"crypto/x509/pkix"
"fmt"
"github.com/unidoc/unipdf/v3/common/license"
"github.com/unidoc/unipdf/v3/core/security"
"io/ioutil"
"log"
"math/big"
"os"
"time"

"github.com/unidoc/unipdf/v3/annotator"
"github.com/unidoc/unipdf/v3/core"
"github.com/unidoc/unipdf/v3/model"
"github.com/unidoc/unipdf/v3/model/sighandler"
)

func init() {
//Make sure to load your metered License API key prior to using the library.
//If you need a key, you can sign up and create a free one at https://cloud.unidoc.io
err := license.SetMeteredKey(os.Getenv(`UNIDOC_LICENSE_API_KEY`))
if err != nil {
panic(err)
}
}

func main() {
args := os.Args
if len(args) < 3 {
log.Fatalln("Usage: go run pdf_sign_encrypted_pdf INPUT_PDF_PATH OUTPUT_PDF_PATH")
}

inputPath := args[1]
outputPath := args[2]

// Read the original file.
f, err := os.Open(inputPath)
if err != nil {
log.Fatalf("Fail: %v\n", err)
}
defer f.Close()

pdfReader, err := model.NewPdfReader(f)
if err != nil {
log.Fatalf("Fail: %v\n", err)
}

password := "password"

permissions := security.PermPrinting | // Allow printing with low quality
security.PermFullPrintQuality |
security.PermModify | // Allow modifications.
security.PermAnnotate | // Allow annotations.
security.PermFillForms |
security.PermRotateInsert | // Allow modifying page order, rotating pages etc.
security.PermExtractGraphics | // Allow extracting graphics.
security.PermDisabilityExtract // Allow extracting graphics (accessibility)

encryptOptions := &model.EncryptOptions{
Permissions: permissions,
Algorithm: model.AES_128bit,
}

// Ecnrypt document
buf, err := encryptDocument(pdfReader, password, encryptOptions)
if err != nil {
log.Fatalf("Fail: %v\n", err)
}

readerOpts := model.NewReaderOpts()
readerOpts.Password = password

// Open reader for the signed document
pdfReader, err = model.NewPdfReaderWithOpts(bytes.NewReader(buf), readerOpts)
if err != nil {
log.Fatalf("Fail: %v\n", err)
}

// Create appender.
pdfAppender, err := model.NewPdfAppenderWithOpts(pdfReader, readerOpts, encryptOptions)
if err != nil {
log.Fatalf("Fail: %v\n", err)
}

// Add signature
buf, err = addSignature(pdfAppender, 1)
if err != nil {
log.Fatalf("Fail: %v\n", err)
}

// Write the resulting file to output.pdf file.
err = ioutil.WriteFile(outputPath, buf, 0666)
if err != nil {
log.Fatalf("Fail: %v\n", err)
}
log.Printf("PDF file successfully saved to output path: %s\n", outputPath)

fmt.Println("Done")
}

func encryptDocument(pdfReader *model.PdfReader, password string, encryptOptions *model.EncryptOptions) ([]byte, error) {
pdfWriter, err := pdfReader.ToWriter(nil)
if err != nil {
return nil, err
}

// Encrypt document before writing to file.
err = pdfWriter.Encrypt([]byte(password), []byte(password), encryptOptions)
if err != nil {
return nil, err
}

buf := &bytes.Buffer{}
// Write output PDF file.
if err = pdfWriter.Write(buf); err != nil {
return nil, err
}

log.Println("PDF file successfully encrypted")

return buf.Bytes(), nil
}

func addSignature(pdfAppender *model.PdfAppender, pageNum int) ([]byte, error) {
// Generate key pair.
priv, cert, err := generateSigKeys()
if err != nil {
return nil, err
}

// Create signature handler.
handler, err := sighandler.NewAdobePKCS7Detached(priv, cert)
if err != nil {
return nil, err
}

// Create signature.
signature := model.NewPdfSignature(handler)
signature.SetName("Test Signature Appearance Name")
signature.SetReason("TestSignatureAppearance Reason")
signature.SetDate(time.Now(), "")

// Initialize signature.
if err := signature.Initialize(); err != nil {
return nil, err
}

opts := annotator.NewSignatureFieldOpts()
opts.FontSize = 8
opts.Rect = []float64{float64(50), 250, float64(150), 300}
opts.TextColor = model.NewPdfColorDeviceRGB(255, 0, 0)

sigField, err := annotator.NewSignatureField(
signature,
[]*annotator.SignatureLine{
annotator.NewSignatureLine("Name", "John Doe"),
annotator.NewSignatureLine("Date", "2019.03.14"),
annotator.NewSignatureLine("Reason", fmt.Sprintf("Test sign")),
annotator.NewSignatureLine("Location", "London"),
annotator.NewSignatureLine("DN", "authority2:name2"),
},
opts,
)
if err != nil {
return nil, err
}

sigField.T = core.MakeString(fmt.Sprintf("New Page Signature"))

if err = pdfAppender.Sign(pageNum, sigField); err != nil {
log.Fatalf("Fail: %v\n", err)
}

buf := &bytes.Buffer{}
// Write output PDF file.
if err = pdfAppender.Write(buf); err != nil {
return nil, err
}

log.Println("PDF file successfully signed")

return buf.Bytes(), nil
}

func generateSigKeys() (*rsa.PrivateKey, *x509.Certificate, error) {
var now = time.Now()

// Generate private key.
priv, err := rsa.GenerateKey(rand.Reader, 2048)
if err != nil {
return nil, nil, err
}

// Initialize X509 certificate template.
template := x509.Certificate{
SerialNumber: big.NewInt(1),
Subject: pkix.Name{
CommonName: "any",
Organization: []string{"Test Company"},
},
NotBefore: now.Add(-time.Hour),
NotAfter: now.Add(time.Hour * 24 * 365),

KeyUsage: x509.KeyUsageDigitalSignature,
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
BasicConstraintsValid: true,
}

// Generate X509 certificate.
certData, err := x509.CreateCertificate(rand.Reader, &template, &template, priv.Public(), priv)
if err != nil {
return nil, nil, err
}

cert, err := x509.ParseCertificate(certData)
if err != nil {
return nil, nil, err
}

return priv, cert, nil
}

0 comments on commit afb2e6c

Please sign in to comment.