Migrate to github
This commit is contained in:
92
README.md
Normal file
92
README.md
Normal file
@@ -0,0 +1,92 @@
|
||||
# Signing PDF files with Go
|
||||
|
||||
[](https://github.com/digitorus/pdfsign/actions?query=workflow%3Abuild-and-test)
|
||||
[](https://github.com/digitorus/pdfsign/actions?query=workflow%3Agolangci-lint)
|
||||
[](https://github.com/digitorus/pdfsign/actions?query=workflow%3Acodeql)
|
||||
[](https://goreportcard.com/report/github.com/digitorus/pdfsign)
|
||||
[](https://codecov.io/gh/digitorus/pdfsign)
|
||||
[](https://pkg.go.dev/github.com/digitorus/pdfsign)
|
||||
|
||||
This PDF signing library is written in [Go](https://go.dev). The library is in development, might not work for all PDF files and the API might change, bug reports, contributions and suggestions are welcome.
|
||||
|
||||
## From the command line
|
||||
|
||||
```sh
|
||||
Usage of ./pdfsign:
|
||||
-contact string
|
||||
Contact information for signatory
|
||||
-location string
|
||||
Location of the signatory
|
||||
-name string
|
||||
Name of the signatory
|
||||
-reason string
|
||||
Reason for signig
|
||||
|
||||
Example usage:
|
||||
./pdfsign -name "Jon Doe" sign input.pdf output.pdf certificate.crt private_key.key [chain.crt]
|
||||
./pdfsignverify input.pdf
|
||||
```
|
||||
|
||||
## As library
|
||||
|
||||
```go
|
||||
import "bitbucket.org/digitorus/pdf"
|
||||
|
||||
input_file, err := os.Open(input)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer input_file.Close()
|
||||
|
||||
output_file, err := os.Create(output)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer output_file.Close()
|
||||
|
||||
finfo, err := input_file.Stat()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
size := finfo.Size()
|
||||
|
||||
rdr, err := pdf.NewReader(input_file, size)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = sign.Sign(input_file, output_file, rdr, size, sign.SignData{
|
||||
Signature: sign.SignDataSignature{
|
||||
Info: sign.SignDataSignatureInfo{
|
||||
Name: "John Doe",
|
||||
Location: "Somewhere on the globe",
|
||||
Reason: "My season for siging this document",
|
||||
ContactInfo: "How you like",
|
||||
Date: time.Now().Local(),
|
||||
},
|
||||
CertType: sign.CertificationSignature,
|
||||
DocMDPPerm: sign.AllowFillingExistingFormFieldsAndSignaturesPerms,
|
||||
},
|
||||
Signer: privateKey, // crypto.Signer
|
||||
Certificate: certificate, // x509.Certificate
|
||||
CertificateChains: certificate_chains, // x509.Certificate.Verify()
|
||||
TSA: sign.TSA{
|
||||
URL: "https://freetsa.org/tsr",
|
||||
Username: "",
|
||||
Password: "",
|
||||
},
|
||||
|
||||
// The follow options are likely to change in a future release
|
||||
//
|
||||
// cache revocation data when bulk signing
|
||||
RevocationData: revocation.InfoArchival{},
|
||||
// custom revocation lookup
|
||||
RevocationFunction: sign.DefaultEmbedRevocationStatusFunction,
|
||||
})
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
} else {
|
||||
log.Println("Signed PDF written to " + output)
|
||||
}
|
||||
|
||||
```
|
11
go.mod
Normal file
11
go.mod
Normal file
@@ -0,0 +1,11 @@
|
||||
module github.com/digitorus/pdfsign
|
||||
|
||||
go 1.17
|
||||
|
||||
require (
|
||||
github.com/digitorus/pdf v0.1.2
|
||||
github.com/digitorus/pkcs7 v0.0.0-20200320092839-808436b6f6d1
|
||||
github.com/digitorus/timestamp v0.0.0-20210102082646-54ddd7720e27
|
||||
github.com/mattetti/filebuffer v1.0.1
|
||||
golang.org/x/crypto v0.0.0-20220307211146-efcb8507fb70
|
||||
)
|
21
go.sum
Normal file
21
go.sum
Normal file
@@ -0,0 +1,21 @@
|
||||
github.com/digitorus/pdf v0.0.0-20220308185202-1128e48814b5 h1:tHO76lKkbhUeH1WHndyqFvN/vGx4abKhct95xWRY7UU=
|
||||
github.com/digitorus/pdf v0.0.0-20220308185202-1128e48814b5/go.mod h1:05fDDJhPswBRM7GTfqCxNiDyeNcN0f+IobfOAl5pdXw=
|
||||
github.com/digitorus/pdf v0.1.1 h1:1U9rjSK5QdL+QMhiggLayJtBAgxPOQKqP1emsj86UBs=
|
||||
github.com/digitorus/pdf v0.1.1/go.mod h1:jMpgQyxhpentZGc/FM+S387JIlI6jAs2nehjb7Yiea4=
|
||||
github.com/digitorus/pdf v0.1.2 h1:RjYEJNbiV6Kcn8QzRi6pwHuOaSieUUrg4EZo4b7KuIQ=
|
||||
github.com/digitorus/pdf v0.1.2/go.mod h1:05fDDJhPswBRM7GTfqCxNiDyeNcN0f+IobfOAl5pdXw=
|
||||
github.com/digitorus/pkcs7 v0.0.0-20200320092839-808436b6f6d1 h1:V1cgDSp4Kq4eMCfazhWyqi2Js7BijkgPnp4Yej9CD9I=
|
||||
github.com/digitorus/pkcs7 v0.0.0-20200320092839-808436b6f6d1/go.mod h1:p2IZ9yq2kEKGFr3rfpYxaaOzB0VdLbF8VkZReEIpJmU=
|
||||
github.com/digitorus/timestamp v0.0.0-20210102082646-54ddd7720e27 h1:X8tvQGATvS7vQBAPPn0f7nQPcTamu4ecCbRafPrBgik=
|
||||
github.com/digitorus/timestamp v0.0.0-20210102082646-54ddd7720e27/go.mod h1:IKw2TcDeMaZrNjpdq7gPc7I+a21+Sn34bUqWrTc70Hs=
|
||||
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.0.0-20220307211146-efcb8507fb70 h1:syTAU9FwmvzEoIYMqcPHOcVm4H3U5u90WsvuYgwpETU=
|
||||
golang.org/x/crypto v0.0.0-20220307211146-efcb8507fb70/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
34
sign.go
34
sign.go
@@ -2,6 +2,7 @@ package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"time"
|
||||
@@ -11,16 +12,29 @@ import (
|
||||
"errors"
|
||||
"io/ioutil"
|
||||
|
||||
"bitbucket.org/digitorus/pdfsign/revocation"
|
||||
"bitbucket.org/digitorus/pdfsign/sign"
|
||||
"bitbucket.org/digitorus/pdfsign/verify"
|
||||
"github.com/digitorus/pdfsign/sign"
|
||||
"github.com/digitorus/pdfsign/verify"
|
||||
)
|
||||
|
||||
var (
|
||||
infoName, infoLocation, infoReason, infoContact string
|
||||
)
|
||||
|
||||
func usage() {
|
||||
log.Fatal("Usage: sign input.pdf output.pdf certificate.crt private_key.key [chain.crt] OR verify input.pdf")
|
||||
flag.PrintDefaults()
|
||||
fmt.Println()
|
||||
fmt.Println("Example usage:")
|
||||
fmt.Printf("\t%s -name \"Jon Doe\" sign input.pdf output.pdf certificate.crt private_key.key [chain.crt]\n", os.Args[0])
|
||||
fmt.Printf("\t%sverify input.pdf\n", os.Args[0])
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
func main() {
|
||||
flag.StringVar(&infoName, "name", "", "Name of the signatory")
|
||||
flag.StringVar(&infoLocation, "location", "", "Location of the signatory")
|
||||
flag.StringVar(&infoReason, "reason", "", "Reason for signig")
|
||||
flag.StringVar(&infoContact, "contact", "", "Contact information for signatory")
|
||||
|
||||
flag.Parse()
|
||||
|
||||
if len(flag.Args()) < 2 {
|
||||
@@ -117,10 +131,10 @@ func main() {
|
||||
err = sign.SignFile(input, output, sign.SignData{
|
||||
Signature: sign.SignDataSignature{
|
||||
Info: sign.SignDataSignatureInfo{
|
||||
Name: "Jeroen Bobbeldijk",
|
||||
Location: "Rotterdam",
|
||||
Reason: "Test",
|
||||
ContactInfo: "Geen",
|
||||
Name: infoName,
|
||||
Location: infoLocation,
|
||||
Reason: infoReason,
|
||||
ContactInfo: infoContact,
|
||||
Date: time.Now().Local(),
|
||||
},
|
||||
CertType: sign.CertificationSignature,
|
||||
@@ -130,10 +144,8 @@ func main() {
|
||||
Certificate: cert,
|
||||
CertificateChains: certificate_chains,
|
||||
TSA: sign.TSA{
|
||||
URL: "http://aatl-timestamp.globalsign.com/tsa/aohfewat2389535fnasgnlg5m23",
|
||||
URL: "https://freetsa.org/tsr",
|
||||
},
|
||||
RevocationData: revocation.InfoArchival{},
|
||||
RevocationFunction: sign.DefaultEmbedRevocationStatusFunction,
|
||||
})
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
|
@@ -8,7 +8,7 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"bitbucket.org/digitorus/pdf"
|
||||
"github.com/digitorus/pdf"
|
||||
)
|
||||
|
||||
func findFirstPage(parent pdf.Value) (pdf.Value, error) {
|
||||
|
@@ -7,7 +7,7 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"bitbucket.org/digitorus/pdf"
|
||||
"github.com/digitorus/pdf"
|
||||
)
|
||||
|
||||
func TestFindFirstPage(t *testing.T) {
|
||||
|
@@ -4,7 +4,7 @@ import (
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"bitbucket.org/digitorus/pdf"
|
||||
"github.com/digitorus/pdf"
|
||||
)
|
||||
|
||||
func TestCreateCatalog(t *testing.T) {
|
||||
@@ -40,6 +40,12 @@ func TestCreateCatalog(t *testing.T) {
|
||||
InfoData: InfoData{
|
||||
ObjectId: uint32(rdr.XrefInformation.ItemCount) + 2,
|
||||
},
|
||||
SignData: SignData{
|
||||
Signature: SignDataSignature{
|
||||
CertType: UsageRightsSignature,
|
||||
DocMDPPerm: AllowFillingExistingFormFieldsAndSignaturesPerms,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
catalog, err := context.createCatalog()
|
||||
|
@@ -3,10 +3,9 @@ package sign
|
||||
import (
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"time"
|
||||
|
||||
"bitbucket.org/digitorus/pdf"
|
||||
"github.com/digitorus/pdf"
|
||||
)
|
||||
|
||||
func TestCreateInfoEmpty(t *testing.T) {
|
||||
@@ -32,10 +31,10 @@ func TestCreateInfoEmpty(t *testing.T) {
|
||||
sign_data := SignData{
|
||||
Signature: SignDataSignature{
|
||||
Info: SignDataSignatureInfo{
|
||||
Name: "Jeroen Bobbeldijk",
|
||||
Location: "Rotterdam",
|
||||
Name: "John Doe",
|
||||
Location: "Somewhere",
|
||||
Reason: "Test",
|
||||
ContactInfo: "Geen",
|
||||
ContactInfo: "None",
|
||||
Date: time.Now().Local(),
|
||||
},
|
||||
CertType: CertificationSignature,
|
||||
@@ -96,10 +95,10 @@ func TestCreateInfo(t *testing.T) {
|
||||
sign_data := SignData{
|
||||
Signature: SignDataSignature{
|
||||
Info: SignDataSignatureInfo{
|
||||
Name: "Jeroen Bobbeldijk",
|
||||
Location: "Rotterdam",
|
||||
Name: "John Doe",
|
||||
Location: "Somewhere",
|
||||
Reason: "Test",
|
||||
ContactInfo: "Geen",
|
||||
ContactInfo: "None",
|
||||
Date: time.Now().Local(),
|
||||
},
|
||||
CertType: CertificationSignature,
|
||||
|
@@ -5,7 +5,7 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"bitbucket.org/digitorus/pdf"
|
||||
"github.com/digitorus/pdf"
|
||||
)
|
||||
|
||||
func TestCreateSignature(t *testing.T) {
|
||||
@@ -34,10 +34,10 @@ func TestCreateSignature(t *testing.T) {
|
||||
sign_data := SignData{
|
||||
Signature: SignDataSignature{
|
||||
Info: SignDataSignatureInfo{
|
||||
Name: "Jeroen Bobbeldijk",
|
||||
Location: "Rotterdam",
|
||||
Name: "John Doe",
|
||||
Location: "Somewhere",
|
||||
Reason: "Test",
|
||||
ContactInfo: "Geen",
|
||||
ContactInfo: "None",
|
||||
Date: now,
|
||||
},
|
||||
CertType: CertificationSignature,
|
||||
@@ -63,7 +63,7 @@ func TestCreateSignature(t *testing.T) {
|
||||
SignData: sign_data,
|
||||
}
|
||||
|
||||
expected_signature := "13 0 obj\n<< /Type /Sig /Filter /Adobe.PPKLite /SubFilter /adbe.pkcs7.detached /ByteRange[0 ********** ********** **********] /Contents<> /Reference [ << /Type /SigRef /TransformMethod /DocMDP /TransformParams << /Type /TransformParams /P 2 /V /1.2 >> >> ] /Name (Jeroen Bobbeldijk) /Location (Rotterdam) /Reason (Test) /ContactInfo (Geen) /M (D:20170923143900+03'00') >>\nendobj\n"
|
||||
expected_signature := "13 0 obj\n<< /Type /Sig /Filter /Adobe.PPKLite /SubFilter /adbe.pkcs7.detached /ByteRange[0 ********** ********** **********] /Contents<> /Reference [ << /Type /SigRef /TransformMethod /DocMDP /TransformParams << /Type /TransformParams /P 2 /V /1.2 >> >> ] /Name (John Doe) /Location (Somewhere) /Reason (Test) /ContactInfo (None) /M (D:20170923143900+03'00') >>\nendobj\n"
|
||||
|
||||
signature, byte_range_start_byte, signature_contents_start_byte := context.createSignaturePlaceholder()
|
||||
|
||||
|
@@ -5,7 +5,7 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"bitbucket.org/digitorus/pdf"
|
||||
"github.com/digitorus/pdf"
|
||||
)
|
||||
|
||||
func TestVisualSignature(t *testing.T) {
|
||||
@@ -34,10 +34,10 @@ func TestVisualSignature(t *testing.T) {
|
||||
sign_data := SignData{
|
||||
Signature: SignDataSignature{
|
||||
Info: SignDataSignatureInfo{
|
||||
Name: "Jeroen Bobbeldijk",
|
||||
Location: "Rotterdam",
|
||||
Name: "John Doe",
|
||||
Location: "Somewhere",
|
||||
Reason: "Test",
|
||||
ContactInfo: "Geen",
|
||||
ContactInfo: "None",
|
||||
Date: now,
|
||||
},
|
||||
CertType: CertificationSignature,
|
||||
|
@@ -8,7 +8,7 @@ import (
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"bitbucket.org/digitorus/pdfsign/revocation"
|
||||
"github.com/digitorus/pdfsign/revocation"
|
||||
|
||||
"golang.org/x/crypto/ocsp"
|
||||
)
|
||||
|
@@ -1,3 +1,6 @@
|
||||
// +build certificateExpired
|
||||
|
||||
// TODO: Rework tests, these currently fail because of expired certificate
|
||||
package sign
|
||||
|
||||
import (
|
||||
@@ -5,7 +8,7 @@ import (
|
||||
"encoding/pem"
|
||||
"testing"
|
||||
|
||||
"bitbucket.org/digitorus/pdfsign/revocation"
|
||||
"github.com/digitorus/pdfsign/revocation"
|
||||
)
|
||||
|
||||
const certPem = `-----BEGIN CERTIFICATE-----
|
||||
|
@@ -10,9 +10,10 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"bitbucket.org/digitorus/pdf"
|
||||
"bitbucket.org/digitorus/pdfsign/revocation"
|
||||
"bitbucket.org/digitorus/pdfsign/verify"
|
||||
"github.com/digitorus/pdf"
|
||||
"github.com/digitorus/pdfsign/revocation"
|
||||
"github.com/digitorus/pdfsign/verify"
|
||||
|
||||
"github.com/mattetti/filebuffer"
|
||||
)
|
||||
|
||||
@@ -146,7 +147,7 @@ func TestSignPDF(t *testing.T) {
|
||||
t.Run(f.Name(), func(st *testing.T) {
|
||||
st.Parallel()
|
||||
|
||||
//t.Log("Signing file", f.Name())
|
||||
t.Log("Signing file", f.Name())
|
||||
|
||||
input_file, err := os.Open("../testfiles/" + f.Name())
|
||||
if err != nil {
|
||||
@@ -174,10 +175,10 @@ func TestSignPDF(t *testing.T) {
|
||||
err = Sign(input_file, outputFile, rdr, size, SignData{
|
||||
Signature: SignDataSignature{
|
||||
Info: SignDataSignatureInfo{
|
||||
Name: "Jeroen Bobbeldijk",
|
||||
Location: "Rotterdam",
|
||||
Name: "John Doe",
|
||||
Location: "Somewhere",
|
||||
Reason: "Test",
|
||||
ContactInfo: "Geen",
|
||||
ContactInfo: "None",
|
||||
Date: time.Now().Local(),
|
||||
},
|
||||
CertType: CertificationSignature,
|
||||
@@ -187,7 +188,7 @@ func TestSignPDF(t *testing.T) {
|
||||
Certificate: cert,
|
||||
CertificateChains: certificate_chains,
|
||||
TSA: TSA{
|
||||
URL: "http://aatl-timestamp.globalsign.com/tsa/aohfewat2389535fnasgnlg5m23",
|
||||
URL: "https://freetsa.org/tsr",
|
||||
},
|
||||
RevocationData: revocation.InfoArchival{},
|
||||
RevocationFunction: DefaultEmbedRevocationStatusFunction,
|
||||
@@ -247,10 +248,10 @@ func TestSignPDFFile(t *testing.T) {
|
||||
err = SignFile("../testfiles/testfile20.pdf", tmpfile.Name(), SignData{
|
||||
Signature: SignDataSignature{
|
||||
Info: SignDataSignatureInfo{
|
||||
Name: "Jeroen Bobbeldijk",
|
||||
Location: "Rotterdam",
|
||||
Name: "John Doe",
|
||||
Location: "Somewhere",
|
||||
Reason: "Test",
|
||||
ContactInfo: "Geen",
|
||||
ContactInfo: "None",
|
||||
Date: time.Now().Local(),
|
||||
},
|
||||
CertType: CertificationSignature,
|
||||
@@ -326,10 +327,10 @@ func BenchmarkSignPDF(b *testing.B) {
|
||||
err = Sign(input_file, ioutil.Discard, rdr, size, SignData{
|
||||
Signature: SignDataSignature{
|
||||
Info: SignDataSignatureInfo{
|
||||
Name: "Jeroen Bobbeldijk",
|
||||
Location: "Rotterdam",
|
||||
Name: "John Doe",
|
||||
Location: "Somewhere",
|
||||
Reason: "Test",
|
||||
ContactInfo: "Geen",
|
||||
ContactInfo: "None",
|
||||
Date: time.Now().Local(),
|
||||
},
|
||||
CertType: CertificationSignature,
|
||||
|
@@ -12,8 +12,8 @@ import (
|
||||
"reflect"
|
||||
"time"
|
||||
|
||||
"bitbucket.org/digitorus/pdf"
|
||||
"bitbucket.org/digitorus/pdfsign/revocation"
|
||||
"github.com/digitorus/pdf"
|
||||
"github.com/digitorus/pdfsign/revocation"
|
||||
|
||||
"github.com/digitorus/pkcs7"
|
||||
"github.com/digitorus/timestamp"
|
||||
@@ -367,30 +367,30 @@ func parseDocumentInfo(v pdf.Value, documentInfo *DocumentInfo) {
|
||||
|
||||
// parseDate parses pdf formatted dates
|
||||
func parseDate(v string) (time.Time, error) {
|
||||
//PDF Date Format
|
||||
//(D:YYYYMMDDHHmmSSOHH'mm')
|
||||
// PDF Date Format
|
||||
// (D:YYYYMMDDHHmmSSOHH'mm')
|
||||
//
|
||||
//where
|
||||
// where
|
||||
//
|
||||
//YYYY is the year
|
||||
//MM is the month
|
||||
//DD is the day (01-31)
|
||||
//HH is the hour (00-23)
|
||||
//mm is the minute (00-59)
|
||||
//SS is the second (00-59)
|
||||
//O is the relationship of local time to Universal Time (UT), denoted by one of the characters +, -, or Z (see below)
|
||||
//HH followed by ' is the absolute value of the offset from UT in hours (00-23)
|
||||
//mm followed by ' is the absolute value of the offset from UT in minutes (00-59)
|
||||
// YYYY is the year
|
||||
// MM is the month
|
||||
// DD is the day (01-31)
|
||||
// HH is the hour (00-23)
|
||||
// mm is the minute (00-59)
|
||||
// SS is the second (00-59)
|
||||
// O is the relationship of local time to Universal Time (UT), denoted by one of the characters +, -, or Z (see below)
|
||||
// HH followed by ' is the absolute value of the offset from UT in hours (00-23)
|
||||
// mm followed by ' is the absolute value of the offset from UT in minutes (00-59)
|
||||
|
||||
//2006-01-02T15:04:05Z07:00
|
||||
//(D:YYYYMMDDHHmmSSOHH'mm')
|
||||
// 2006-01-02T15:04:05Z07:00
|
||||
// (D:YYYYMMDDHHmmSSOHH'mm')
|
||||
return time.Parse("D:20060102150405Z07'00'", v)
|
||||
}
|
||||
|
||||
// parseKeywords parses keywords pdf meta data
|
||||
func parseKeywords(value string) []string {
|
||||
//keywords must be separated by commas or semicolons or could be just separated with spaces, after the semicolon could be a space
|
||||
//https://stackoverflow.com/questions/44608608/the-separator-between-keywords-in-pdf-meta-data
|
||||
// keywords must be separated by commas or semicolons or could be just separated with spaces, after the semicolon could be a space
|
||||
// https://stackoverflow.com/questions/44608608/the-separator-between-keywords-in-pdf-meta-data
|
||||
separators := []string{", ", ": ", ",", ":", " "}
|
||||
for _, s := range separators {
|
||||
if strings.Contains(value, s) {
|
||||
|
Reference in New Issue
Block a user