Add support to Google Apps Script.
parent
213cf53474
commit
491e6309e0
41
README.md
41
README.md
|
@ -1,5 +1,6 @@
|
|||
# ZgaPdfSigner
|
||||
A javascript tool to sign a pdf in web browser.
|
||||
And it also can be used in Google Apps Script.
|
||||
|
||||
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.
|
||||
|
@ -15,7 +16,7 @@ Just import the dependencies and this tool.
|
|||
```html
|
||||
<script src="https://unpkg.com/pdf-lib/dist/pdf-lib.min.js" type="text/javascript"></script>
|
||||
<script src="https://unpkg.com/node-forge/dist/forge.min.js" type="text/javascript"></script>
|
||||
<script src="https://github.com/zboris12/zgapdfsigner/releases/download/1.0.0/zgapdfsigner.js" type="text/javascript"></script>
|
||||
<script src="https://github.com/zboris12/zgapdfsigner/releases/download/1.1.0/zgapdfsigner.js" type="text/javascript"></script>
|
||||
```
|
||||
|
||||
## Let's sign
|
||||
|
@ -35,7 +36,7 @@ async function sign1(pdf, cert, pwd){
|
|||
p12cert: cert,
|
||||
pwd: pwd,
|
||||
};
|
||||
var signer = new PdfSigner(sopt);
|
||||
var signer = new Zga.PdfSigner(sopt);
|
||||
return await signer.sign(pdf);
|
||||
}
|
||||
```
|
||||
|
@ -67,7 +68,7 @@ async function sign2(pdf, cert, pwd, imgdat, imgtyp){
|
|||
imgType: imgtyp,
|
||||
},
|
||||
};
|
||||
var signer = new PdfSigner(sopt);
|
||||
var signer = new Zga.PdfSigner(sopt);
|
||||
return await signer.sign(pdf);
|
||||
}
|
||||
```
|
||||
|
@ -78,9 +79,41 @@ Sign with a visible signature of drawing a text.
|
|||
//TODO
|
||||
```
|
||||
|
||||
Use it in Google Apps Script
|
||||
|
||||
```js
|
||||
// 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/1.1.0/zgapdfsigner.js").getContentText());
|
||||
|
||||
// Load pdf, certificate
|
||||
var pdfBlob = DriveApp.getFilesByName("_test.pdf").next().getBlob();
|
||||
var certBlob = DriveApp.getFilesByName("_test.pfx").next().getBlob();
|
||||
// Sign the pdf
|
||||
var sopt = {
|
||||
p12cert: new Uint8Array(certBlob.getBytes()),
|
||||
pwd: "some passphrase",
|
||||
};
|
||||
var signer = new Zga.PdfSigner(sopt);
|
||||
var u8arr = await signer.sign(new Uint8Array(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__: string :point_right: A raw data of the certificate
|
||||
* __p12cert__: (Uint8Array|ArrayBuffer|string) :point_right: Certificate's data
|
||||
* __pwd__: string :point_right: The passphrase of the certificate
|
||||
* __reason__: string :point_right: (Optional) The reason for signing
|
||||
* __location__: string :point_right: (Optional) Your location
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
/**
|
||||
* the base point of x, y is top left corner.
|
||||
* @typedef
|
||||
* {{
|
||||
* x: number,
|
||||
* y: number,
|
||||
* w: number,
|
||||
* h: number,
|
||||
* }}
|
||||
*/
|
||||
var SignAreaInfo;
|
||||
/**
|
||||
* @typedef
|
||||
* {{
|
||||
* area: SignAreaInfo,
|
||||
* pageidx: (number|undefined),
|
||||
* imgData: (Uint8Array|ArrayBuffer|string|undefined),
|
||||
* imgType: (string|undefined),
|
||||
* text: (string|undefined),
|
||||
* fontData: (PDFLib.StandardFonts|Uint8Array|ArrayBuffer|string|undefined),
|
||||
* img: (PDFLib.PDFImage|undefined),
|
||||
* font: (PDFLib.PDFFont|undefined),
|
||||
* }}
|
||||
*/
|
||||
var SignDrawInfo;
|
||||
/**
|
||||
* @typedef
|
||||
* {{
|
||||
* p12cert: (Uint8Array|ArrayBuffer|string),
|
||||
* pwd: string,
|
||||
* reason: (string|undefined),
|
||||
* location: (string|undefined),
|
||||
* contact: (string|undefined),
|
||||
* signdate: (Date|undefined),
|
||||
* signame: (string|undefined),
|
||||
* drawinf: (SignDrawInfo|undefined),
|
||||
* }}
|
||||
*/
|
||||
var SignOption;
|
|
@ -39,9 +39,8 @@ function testSign(imgdat, imgtyp){
|
|||
var kf = document.getElementById("kkk").files[0];
|
||||
readAsArrayBuffer(fil, function(a_pdf){
|
||||
readAsArrayBuffer(kf, async function(b_kfbuf){
|
||||
var b_kfdat = String.fromCharCode.apply(null, new Uint8Array(b_kfbuf));
|
||||
var b_opt = {
|
||||
p12cert: b_kfdat,
|
||||
p12cert: b_kfbuf,
|
||||
pwd: document.getElementById("pwd").value,
|
||||
};
|
||||
if(imgdat){
|
||||
|
@ -56,10 +55,10 @@ function testSign(imgdat, imgtyp){
|
|||
imgType: imgtyp,
|
||||
};
|
||||
}
|
||||
var b_signer = new PdfSigner(b_opt);
|
||||
var b_blob = await b_signer.sign(a_pdf);
|
||||
var b_signer = new Zga.PdfSigner(b_opt);
|
||||
var b_u8s = await b_signer.sign(a_pdf);
|
||||
document.getElementById("download").download = "zzzs3.pdf";
|
||||
document.getElementById("download").href = window.URL.createObjectURL(b_blob);
|
||||
document.getElementById("download").href = window.URL.createObjectURL(new Blob([b_u8s], {"type" : "application/pdf"}));
|
||||
document.getElementById("download").click();
|
||||
});
|
||||
});
|
||||
|
|
111
zgapdfsigner.js
111
zgapdfsigner.js
|
@ -1,44 +1,8 @@
|
|||
/**
|
||||
* the base point of x, y is top left corner.
|
||||
* @typedef
|
||||
* {{
|
||||
* x: number,
|
||||
* y: number,
|
||||
* w: number,
|
||||
* h: number,
|
||||
* }}
|
||||
*/
|
||||
var SignAreaInfo;
|
||||
/**
|
||||
* @typedef
|
||||
* {{
|
||||
* area: SignAreaInfo,
|
||||
* pageidx: (number|undefined),
|
||||
* imgData: (Uint8Array|ArrayBuffer|string|undefined),
|
||||
* imgType: (string|undefined),
|
||||
* text: (string|undefined),
|
||||
* fontData: (PDFLib.StandardFonts|Uint8Array|ArrayBuffer|string|undefined),
|
||||
* img: (PDFLib.PDFImage|undefined),
|
||||
* font: (PDFLib.PDFFont|undefined),
|
||||
* }}
|
||||
*/
|
||||
var SignDrawInfo;
|
||||
/**
|
||||
* @typedef
|
||||
* {{
|
||||
* p12cert: string,
|
||||
* pwd: string,
|
||||
* reason: (string|undefined),
|
||||
* location: (string|undefined),
|
||||
* contact: (string|undefined),
|
||||
* signdate: (Date|undefined),
|
||||
* signame: (string|undefined),
|
||||
* drawinf: (SignDrawInfo|undefined),
|
||||
* }}
|
||||
*/
|
||||
var SignOption;
|
||||
'use strict';
|
||||
|
||||
class PdfSigner {
|
||||
globalThis.Zga = {
|
||||
|
||||
PdfSigner: class {
|
||||
/**
|
||||
* @constructor
|
||||
* @param {SignOption} signopt
|
||||
|
@ -51,7 +15,7 @@ class PdfSigner {
|
|||
/**
|
||||
* @public
|
||||
* @param {PDFLib.PDFDocument|Uint8Array|ArrayBuffer|string} pdf
|
||||
* @return {Blob}
|
||||
* @return {Promise<Uint8Array>}
|
||||
*/
|
||||
async sign(pdf){
|
||||
/** @type {PDFLib.PDFDocument} */
|
||||
|
@ -74,8 +38,7 @@ class PdfSigner {
|
|||
|
||||
this.addSignHolder(pdfdoc);
|
||||
var uarr = await pdfdoc.save({"useObjectStreams": false});
|
||||
// return new Blob([uarr], {"type" : "application/pdf"});
|
||||
var pdfstr = String.fromCharCode.apply(null, uarr);
|
||||
var pdfstr = Zga.u8arrToRaw(uarr);
|
||||
|
||||
return this.signPdf(pdfstr);
|
||||
}
|
||||
|
@ -91,7 +54,7 @@ class PdfSigner {
|
|||
const SIGNATURE_LENGTH = 3322;
|
||||
|
||||
/** @const {VisualSignature} */
|
||||
const visign = new VisualSignature(this.opt.drawinf);
|
||||
const visign = new Zga.VisualSignature(this.opt.drawinf);
|
||||
/** @const {PDFLib.PDFRef} */
|
||||
const strmRef = visign.createStream(pdfdoc, this.opt.signame);
|
||||
/** @const {PDFLib.PDFPage} */
|
||||
|
@ -118,7 +81,7 @@ class PdfSigner {
|
|||
"M": PDFLib.PDFString.fromDate(this.opt.signdate),
|
||||
"Prop_Build": pdfdoc.context.obj({
|
||||
"App": pdfdoc.context.obj({
|
||||
"Name": "ZbPdfSinger",
|
||||
"Name": "ZgaPdfSinger",
|
||||
}),
|
||||
}),
|
||||
};
|
||||
|
@ -167,7 +130,7 @@ class PdfSigner {
|
|||
/**
|
||||
* @private
|
||||
* @param {string} pdfstr
|
||||
* @return {Blob}
|
||||
* @return {Uint8Array}
|
||||
*/
|
||||
signPdf(pdfstr){
|
||||
if(!this.opt.signdate){
|
||||
|
@ -200,6 +163,9 @@ class PdfSigner {
|
|||
// Remove the placeholder signature
|
||||
pdfstr = pdfstr.slice(0, byteRange[1]) + pdfstr.slice(byteRange[2], byteRange[2] + byteRange[3]);
|
||||
|
||||
if(typeof this.opt.p12cert !== "string"){
|
||||
this.opt.p12cert = Zga.u8arrToRaw(new Uint8Array(this.opt.p12cert));
|
||||
}
|
||||
// Convert Buffer P12 to a forge implementation.
|
||||
var p12Asn1 = forge.asn1.fromDer(this.opt.p12cert);
|
||||
var p12 = forge.pkcs12.pkcs12FromAsn1(p12Asn1, true, this.opt.pwd);
|
||||
|
@ -271,29 +237,11 @@ class PdfSigner {
|
|||
// Place it in the document.
|
||||
pdfstr = pdfstr.slice(0, byteRange[1]) + "<" + sighex + ">" + pdfstr.slice(byteRange[1]);
|
||||
|
||||
return this.rawToBlob(pdfstr, "application/pdf");
|
||||
return Zga.rawToU8arr(pdfstr);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @param {string} raw
|
||||
* @param {string=} typ
|
||||
* @return {Blob}
|
||||
*/
|
||||
rawToBlob(raw, typ){
|
||||
var arr = new Uint8Array(raw.length);
|
||||
for(var i=0; i<raw.length; i++){
|
||||
arr[i] = raw.charCodeAt(i);
|
||||
}
|
||||
var opt = null;
|
||||
if(typ){
|
||||
opt = {"type" : typ};
|
||||
}
|
||||
return new Blob([arr], opt);
|
||||
}
|
||||
}
|
||||
|
||||
class VisualSignature {
|
||||
VisualSignature: class {
|
||||
/**
|
||||
* @constructor
|
||||
* @param {SignDrawInfo=} drawinf
|
||||
|
@ -504,4 +452,31 @@ class VisualSignature {
|
|||
}
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* @param {Uint8Array} uarr
|
||||
* @return {string}
|
||||
*/
|
||||
u8arrToRaw: function(uarr){
|
||||
/** @type {Array<string>} */
|
||||
var arr = [];
|
||||
for(var i=0; i<uarr.length; i++){
|
||||
arr.push(String.fromCharCode(uarr[i]));
|
||||
}
|
||||
return arr.join("");
|
||||
},
|
||||
|
||||
/**
|
||||
* @param {string} raw
|
||||
* @return {Uint8Array}
|
||||
*/
|
||||
rawToU8arr: function(raw){
|
||||
var arr = new Uint8Array(raw.length);
|
||||
for(var i=0; i<raw.length; i++){
|
||||
arr[i] = raw.charCodeAt(i);
|
||||
}
|
||||
return arr;
|
||||
},
|
||||
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue