![]() |
||
---|---|---|
closure | ||
lib | ||
.env.sample | ||
.gitignore | ||
LICENSE | ||
README.md | ||
closure.js | ||
logo.png | ||
package-lock.json | ||
package.json | ||
test.html | ||
test4node.js |
README.md

ZgaPdfSigner
A javascript tool to sign a pdf or set protection of a pdf in web browser.
And it also can be used in Google Apps Script and nodejs.
PS: ZGA is the abbreviation of my father's name.
And I use this name to hope the merits from this application will be dedicated to my parents.
Main features
- Sign a pdf with an invisible pkcs#7 signature.
- Sign a pdf with a visible pkcs#7 signature by drawing an image.
- Sign a pdf and set DocMDP(document modification detection and prevention).
- Add a new signature to a pdf if it has been signed already. (An incremental update)
- Add a document timestamp from TSA(Time Stamp Authority). (Only in Google Apps Script and nodejs)
- Sign a pdf with a timestamp from TSA. (Only in Google Apps Script and nodejs)
- Set password protection to a pdf. Supported algorithms:
- 40bit RC4 Encryption
- 128bit RC4 Encryption
- 128bit AES Encryption
- 256bit AES Encryption
- Set public-key certificate protection to a pdf. Supported algorithms are as same as the password protection.
About signing with TSA
Because of the CORS security restrictions in web browser, signing with a timestamp from TSA can only be used in Google Apps Script.
The Dependencies
How to use this tool
Just import the dependencies and this tool.
<script src="https://unpkg.com/pdf-lib@1.17.1/dist/pdf-lib.min.js" type="text/javascript"></script>
<script src="https://unpkg.com/node-forge@1.3.1/dist/forge.min.js" type="text/javascript"></script>
<script src="https://github.com/zboris12/zgapdfsigner/releases/download/2.2.0/zgapdfsigner.min.js" type="text/javascript"></script>
Let's sign
Sign with an invisible signature.
/**
* @param {ArrayBuffer} pdf
* @param {ArrayBuffer} cert
* @param {string} pwd
* @return {Promise<Blob>}
*/
async function sign1(pdf, cert, pwd){
/** @type {SignOption} */
var sopt = {
p12cert: cert,
pwd: pwd,
permission: 1,
};
var signer = new Zga.PdfSigner(sopt);
var u8arr = await signer.sign(pdf);
return new Blob([u8arr], {"type" : "application/pdf"});
}
Sign with a visible signature of an image.
/**
* @param {ArrayBuffer} pdf
* @param {ArrayBuffer} cert
* @param {string} pwd
* @param {ArrayBuffer} imgdat
* @param {string} imgtyp
* @return {Promise<Blob>}
*/
async function sign2(pdf, cert, pwd, imgdat, imgtyp){
/** @type {SignOption} */
var sopt = {
p12cert: cert,
pwd: pwd,
drawinf: {
area: {
x: 25, // left
y: 150, // top
w: 60, // width
h: 60, // height
},
imgData: imgdat,
imgType: imgtyp,
},
};
var signer = new Zga.PdfSigner(sopt);
var u8arr = await signer.sign(pdf);
return new Blob([u8arr], {"type" : "application/pdf"});
}
Sign with a visible signature of drawing a text.
//TODO
Use it in Google Apps Script
// Simulate setTimeout function for pdf-lib
function setTimeout(func, sleep){
Utilities.sleep(sleep);
func();
}
// Simulate window for node-forge
var window = globalThis;
// Load pdf-lib
eval(UrlFetchApp.fetch("https://unpkg.com/pdf-lib@1.17.1/dist/pdf-lib.min.js").getContentText());
// Load node-forge
eval(UrlFetchApp.fetch("https://unpkg.com/node-forge@1.3.1/dist/forge.min.js").getContentText());
// Load ZgaPdfSigner
eval(UrlFetchApp.fetch("https://github.com/zboris12/zgapdfsigner/releases/download/2.2.0/zgapdfsigner.min.js").getContentText());
// Load pdf, certificate
var pdfBlob = DriveApp.getFilesByName("_test.pdf").next().getBlob();
var certBlob = DriveApp.getFilesByName("_test.pfx").next().getBlob();
// Sign the pdf
/** @type {SignOption} */
var sopt = {
p12cert: certBlob.getBytes(),
pwd: "some passphrase",
signdate: "1",
};
var signer = new Zga.PdfSigner(sopt);
var u8arr = await signer.sign(pdfBlob.getBytes());
// Save the result pdf to some folder
var fld = DriveApp.getFolderById("a folder's id");
fld.createFile(Utilities.newBlob(u8arr, "application/pdf").setName("signed_test.pdf"));
Detail of SignOption
- p12cert: Array|Uint8Array|ArrayBuffer|string 👉 (Optional) Certificate's data. In the case of adding a document timestamp, it must be omitted.
- pwd: string 👉 (Optional) The passphrase of the certificate. In the case of adding a document timestamp, it must be omitted.
- permission: number 👉 (Optional) The modification permissions granted for this document.
This is a setting of DocMDP(document modification detection and prevention). Valid values are:
- 1: No changes to the document are permitted; any change to the document invalidates the signature.
- 2: Permitted changes are filling in forms, instantiating page templates, and signing; other changes invalidate the signature.
- 3: Permitted changes are the same as for 2, as well as annotation creation, deletion, and modification; other changes invalidate the signature.
- reason: string 👉 (Optional) The reason for signing
- location: string 👉 (Optional) Your location
- contact: string 👉 (Optional) Your contact information
- signdate: Date|string|TsaServiceInfo 👉 (Optional) In the case of adding a document timestamp, it can't be omitted and can't be a Date.
- When it is a Date, it means the date and time of signing.
- When it is a string, it can be an url of TSA or an index of the preset TSAs as below:
- When it is a TsaServiceInfo, it means a full customized information of a TSA.
- url: string 👉 The url of TSA
- len: number 👉 (Optional) The length of signature's placeholder
- headers: Object<string, *> 👉 (Optional) The customized headers for sending to tsa server
- When it is omitted, the system timestamp will be used.
- signame: string 👉 (Optional) The name of the signature
- drawinf: SignDrawInfo 👉 (Optional) Visible signature's information
- area: SignAreaInfo 👉 The signature's drawing area, these numbers are dots on 72dpi.
- x: number 👉 Distance from left
- y: number 👉 Distance from top
- w: number 👉 Width
- h: number 👉 Height
- pageidx: number 👉 (Optional) The index of a page where the signature will be drawn.
- imgData: Array|Uint8Array|ArrayBuffer|string 👉 (Optional) The image's data
- imgType: string 👉 (Optional) The image's type, only support jpg and png
- text: string 👉 (Optional) A text drawing for the signature, not implemented yet
- fontData: PDFLib.StandardFonts|Array|Uint8Array|ArrayBuffer|string 👉 (Optional) The font's data for drawing text, not implemented yet
- area: SignAreaInfo 👉 The signature's drawing area, these numbers are dots on 72dpi.
Let's protect the pdf
Set password protection to the pdf.
/**
* @param {ArrayBuffer} pdf
* @param {string} upwd
* @param {string} opwd
* @return {Promise<Blob>}
*/
async function protect1(pdf, upwd, opwd){
/** @type {EncryptOption} */
var eopt = {
mode: Zga.Crypto.Mode.RC4_40,
permissions: ["modify", "annot-forms", "fill-forms", "extract", "assemble"],
userpwd: upwd,
ownerpwd: opwd,
};
var cyptor = new Zga.PdfCryptor(eopt);
var pdfdoc = await cyptor.encryptPdf(pdf);
u8arr = await pdfdoc.save({"useObjectStreams": false});
return new Blob([u8arr], {"type" : "application/pdf"});
}
Set public-key certificate protection to the pdf.
/**
* @param {ArrayBuffer} pdf
* @param {ArrayBuffer} cert
* @return {Promise<Blob>}
*/
async function protect2(pdf, cert){
/** @type {EncryptOption} */
var eopt = {
mode: Zga.Crypto.Mode.AES_128,
pubkeys: [{
c: cert,
p: ["copy", "modify", "copy-extract", "annot-forms", "fill-forms", "extract", "assemble"],
}],
};
var cyptor = new Zga.PdfCryptor(eopt);
var pdfdoc = await cyptor.encryptPdf(pdf);
u8arr = await pdfdoc.save({"useObjectStreams": false});
return new Blob([u8arr], {"type" : "application/pdf"});
}
Sign and set protection.
/**
* @param {ArrayBuffer} pdf
* @param {ArrayBuffer} cert
* @param {string} pwd
* @param {string} opwd
* @return {Promise<Blob>}
*/
async function signAndProtect1(pdf, cert, pwd, opwd){
/** @type {SignOption} */
var sopt = {
p12cert: cert,
pwd: pwd,
};
/** @type {EncryptOption} */
var eopt = {
mode: Zga.Crypto.Mode.RC4_128,
permissions: ["modify", "annot-forms", "fill-forms", "extract", "assemble"],
ownerpwd: opwd,
};
var signer = new Zga.PdfSigner(sopt);
var u8arr = await signer.sign(pdf, eopt);
return new Blob([u8arr], {"type" : "application/pdf"});
}
Sign and set protection by the same certificate.
/**
* @param {ArrayBuffer} pdf
* @param {ArrayBuffer} cert
* @param {string} pwd
* @return {Promise<Blob>}
*/
async function signAndProtect2(pdf, cert, pwd){
/** @type {SignOption} */
var sopt = {
p12cert: cert,
pwd: pwd,
};
/** @type {EncryptOption} */
var eopt = {
mode: Zga.Crypto.Mode.AES_256,
permissions: ["modify", "annot-forms", "fill-forms", "extract", "assemble"],
pubkeys: [],
};
var signer = new Zga.PdfSigner(sopt);
var u8arr = await signer.sign(pdf, eopt);
return new Blob([u8arr], {"type" : "application/pdf"});
}
Detail of EncryptOption
- mode: Zga.Crypto.Mode 👉 The values of Zga.Crypto.Mode
- RC4_40: 40bit RC4 Encryption
- RC4_128: 128bit RC4 Encryption
- AES_128: 128bit AES Encryption
- AES_256: 256bit AES Encryption
- permissions: Array 👉 (Optional) The set of permissions to be blocked
- "copy": (Only valid on public-key mode) Copy text and graphics from the document;
- "print": Print the document;
- "modify": Modify the contents of the document by operations other than those controlled by 'fill-forms', 'extract' and 'assemble';
- "copy-extract": Copy or otherwise extract text and graphics from the document;
- "annot-forms": Add or modify text annotations, fill in interactive form fields, and, if 'modify' is also set, create or modify interactive form fields (including signature fields);
- "fill-forms": Fill in existing interactive form fields (including signature fields), even if 'annot-forms' is not specified;
- "extract": Extract text and graphics (in support of accessibility to users with disabilities or for other purposes);
- "assemble": Assemble the document (insert, rotate, or delete pages and create bookmarks or thumbnail images), even if 'modify' is not set;
- "print-high": Print the document to a representation from which a faithful digital copy of the PDF content could be generated. When this is not set, printing is limited to a low-level representation of the appearance, possibly of degraded quality.
- userpwd: string 👉 (Optional) User password. Used when opening the pdf.
- ownerpwd: string 👉 (Optional) Owner password. If not specified, a random value is used.
- pubkeys: Array<PubKeyInfo> 👉 (Optional) Array of recipients containing public-key certificates ('c') and permissions ('p').
- c: Array|Uint8Array|ArrayBuffer|string|forge_cert 👉 (Optional) A public-key certificate. Only when you want to encrypt the pdf by the certificate used in signing, the c can be omitted.
- p: Array 👉 (Optional) Permissions
Thanks
- The module of setting protection was almost migrated from TCPDF.
License
This tool is available under the MIT license.