Skip to content

Commit 528eaad

Browse files
committed
Added support run in node js.
1 parent 22f6628 commit 528eaad

File tree

4 files changed

+312
-10
lines changed

4 files changed

+312
-10
lines changed

package-lock.json

+106
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
{
2+
"name": "zgapdfsigner",
3+
"version": "2.3.0",
4+
"private": false,
5+
"scripts": {
6+
"dev": "",
7+
"build": ""
8+
},
9+
"dependencies": {
10+
"pdf-lib": "1.17.1",
11+
"node-forge": "1.3.1"
12+
},
13+
"devDependencies": {
14+
}
15+
}

test4node.js

+164
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,164 @@
1+
const m_fs = require("fs");
2+
const m_path = require("path");
3+
const m_urlparser = require("url");
4+
const m_h = {
5+
"http:": require("http"),
6+
"https:": require("http"),
7+
};
8+
9+
globalThis.PDFLib = require("pdf-lib");
10+
globalThis.forge = require("node-forge");
11+
require("./zgapdfcryptor.js");
12+
require("./zgapdfsigner.js");
13+
14+
Zga.UrlFetchApp = {};
15+
/**
16+
* @param {string} url
17+
* @param {UrlFetchParams} params
18+
* @return {Promise<Uint8Array>}
19+
*/
20+
Zga.UrlFetchApp.fetch = function(url, params){
21+
return new Promise(function(resolve, reject){
22+
/** @type {URL} */
23+
var opts = m_urlparser.parse(url);
24+
var http = m_h[opts.protocol];
25+
/** @type {string|Buffer} */
26+
var dat = null;
27+
var encoding = undefined;
28+
if(params.payload instanceof Buffer){
29+
dat = params.payload;
30+
}else if(params.payload instanceof Uint8Array){
31+
dat = Buffer.from(params.payload.buffer);
32+
}else if(params.payload instanceof ArrayBuffer){
33+
dat = Buffer.from(params.payload);
34+
}else{
35+
dat = params.payload;
36+
encoding = "binary";
37+
}
38+
39+
if(params.headers){
40+
opts.headers = params.headers;
41+
}
42+
if(params.method){
43+
opts.method = params.method;
44+
}
45+
if(params.validateHttpsCertificates === false){
46+
opts.rejectUnauthorized = false;
47+
}
48+
49+
/** @type {http.ClientRequest} */
50+
var hreq = http.request(opts, function(/** @type {http.IncomingMessage} */a_res){
51+
if(a_res.statusCode !== 200){
52+
var a_err = new Error("Failed to request url. " + url + "\n Status Code: " + a_res.statusCode);
53+
a_res.resume();
54+
throw a_err;
55+
}
56+
/** @type {Array<Buffer>} */
57+
var a_bufs = [];
58+
var a_bufs_len = 0;
59+
a_res.on("data", function(/** @type {Buffer} */b_chunk){
60+
a_bufs.push(b_chunk);
61+
a_bufs_len += b_chunk.length;
62+
});
63+
a_res.on("end", function(){
64+
/** @type {Buffer} */
65+
var b_bdat = Buffer.concat(a_bufs, a_bufs_len);
66+
resolve(b_bdat);
67+
});
68+
});
69+
hreq.on("error", function(a_err){
70+
throw a_err;
71+
});
72+
hreq.end(dat, encoding);
73+
});
74+
};
75+
76+
async function main(){
77+
/** @type {string} */
78+
var pdfPath = m_path.join(__dirname, "test/_test.pdf");
79+
/** @type {string} */
80+
var pfxPath = m_path.join(__dirname, "test/_test.pfx");
81+
/** @type {string} */
82+
var ps = "";
83+
/** @type {string} */
84+
var imgPath = m_path.join(__dirname, "test/_test.png");
85+
86+
if(process.argv.length > 3){
87+
pfxPath = process.argv[2];
88+
ps = process.argv[3];
89+
}else if(process.argv[2]){
90+
ps = process.argv[2];
91+
}
92+
93+
if(!ps){
94+
throw new Error("The passphrase is not specified.");
95+
}
96+
97+
/** @type {Buffer} */
98+
var pdf = m_fs.readFileSync(pdfPath);
99+
/** @type {Buffer} */
100+
var pfx = m_fs.readFileSync(pfxPath);
101+
/** @type {Buffer} */
102+
var img = null;
103+
/** @type {string} */
104+
var imgType = "";
105+
if(imgPath){
106+
img = m_fs.readFileSync(imgPath);
107+
imgType = m_path.extname(imgPath).slice(1);
108+
}
109+
110+
/** @type {SignOption} */
111+
var sopt = null;
112+
if(pfx){
113+
sopt = {
114+
p12cert: pfx,
115+
pwd: ps,
116+
permission: 1,
117+
signdate: "1",
118+
reason: "I have a test reason.",
119+
location: "I am on the earth.",
120+
contact: "[email protected]",
121+
debug: true,
122+
};
123+
if(img){
124+
sopt.drawinf = {
125+
area: {
126+
x: 25, // left
127+
y: 150, // top
128+
w: 60,
129+
h: 60,
130+
},
131+
// pageidx: 2,
132+
imgData: img,
133+
imgType: imgType,
134+
};
135+
}
136+
}
137+
138+
/** @type {EncryptOption} */
139+
var eopt = undefined;
140+
eopt = {
141+
mode: Zga.Crypto.Mode.AES_256,
142+
permissions: ["copy", "copy-extract", "print-high"],
143+
userpwd: "123",
144+
};
145+
// eopt.pubkeys = [];
146+
147+
/** @type {Uint8Array} */
148+
var u8dat = null;
149+
if(sopt){
150+
/** @type {Zga.PdfSigner} */
151+
var ser = new Zga.PdfSigner(sopt);
152+
u8dat = await ser.sign(pdf, eopt);
153+
}
154+
155+
if(u8dat){
156+
/** @type {string} */
157+
var outPath = m_path.join(__dirname, "test/test_test2.pdf");
158+
m_fs.writeFileSync(outPath, u8dat);
159+
console.log("Output file: " + outPath);
160+
}
161+
console.log("Done");
162+
}
163+
164+
main();

zgapdfsigner.js

+27-10
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,23 @@ z.TSAURLS = {
1616
"7": {url: "https://freetsa.org/tsr", len: 14500},
1717
};
1818

19+
// Google Apps Script
20+
if(globalThis.UrlFetchApp){
21+
z.UrlFetchApp = {};
22+
/**
23+
* @param {string} url
24+
* @param {UrlFetchParams} params
25+
* @return {Promise<Uint8Array>}
26+
*/
27+
z.UrlFetchApp.fetch = function(url, params){
28+
return new Promise(function(resolve){
29+
/** @type {GBlob} */
30+
var tblob = UrlFetchApp.fetch(url, params).getBlob();
31+
resolve(new Uint8Array(tblob.getBytes()));
32+
});
33+
};
34+
}
35+
1936
z.NewRef = class{
2037
/**
2138
* @param {PDFLib.PDFRef} ref
@@ -247,7 +264,7 @@ z.PdfSigner = class{
247264
}
248265
}
249266
if(this.tsainf){
250-
if(!globalThis.UrlFetchApp){
267+
if(!z.UrlFetchApp){
251268
throw new Error("Because of the CORS security restrictions, signing with TSA is not supported in web browser.");
252269
}
253270
if(z.TSAURLS[this.tsainf.url]){
@@ -405,7 +422,7 @@ z.PdfSigner = class{
405422
}
406423
/** @type {string} */
407424
var pdfstr = z.u8arrToRaw(uarr) + String.fromCharCode(this.NEWLINE);
408-
return this.signPdf(pdfstr);
425+
return await this.signPdf(pdfstr);
409426
}
410427

411428
/**
@@ -770,9 +787,9 @@ z.PdfSigner = class{
770787
/**
771788
* @private
772789
* @param {string} pdfstr
773-
* @return {Uint8Array}
790+
* @return {Promise<Uint8Array>}
774791
*/
775-
signPdf(pdfstr){
792+
async signPdf(pdfstr){
776793
/** @type {Date} */
777794
var signdate = new Date();
778795
if(this.opt.signdate instanceof Date && !this.tsainf){
@@ -850,7 +867,7 @@ z.PdfSigner = class{
850867

851868
if(this.tsainf){
852869
/** @type {forge.asn1} */
853-
var tsatoken = this.queryTsa(p7.signers[0].signature);
870+
var tsatoken = await this.queryTsa(p7.signers[0].signature);
854871
p7.signerInfos[0].value.push(tsatoken);
855872
this.log("Timestamp from " + this.tsainf.url + " has been added to the signature.");
856873
}
@@ -972,9 +989,9 @@ z.PdfSigner = class{
972989
/**
973990
* @private
974991
* @param {string=} signature
975-
* @return {forge.asn1}
992+
* @return {Promise<forge.asn1>}
976993
*/
977-
queryTsa(signature){
994+
async queryTsa(signature){
978995
/** @lends {forge.asn1} */
979996
var asn1 = forge.asn1;
980997
/** @type {string} */
@@ -987,10 +1004,10 @@ z.PdfSigner = class{
9871004
"headers": {"Content-Type": "application/timestamp-query"},
9881005
"payload": tu8s,
9891006
};
990-
/** @type {GBlob} */
991-
var tblob = UrlFetchApp.fetch(this.tsainf.url, options).getBlob();
1007+
/** @type {Uint8Array} */
1008+
var tesp = await z.UrlFetchApp.fetch(this.tsainf.url, options);
9921009
/** @type {string} */
993-
var tstr = z.u8arrToRaw(new Uint8Array(tblob.getBytes()));
1010+
var tstr = z.u8arrToRaw(tesp);
9941011
/** @type {forge.asn1} */
9951012
var token = asn1.fromDer(tstr).value[1];
9961013

0 commit comments

Comments
 (0)