parent
e5372e2652
commit
0d39f569ae
|
@ -18,9 +18,9 @@ And I use this name to hope the merits from this application will be dedicated t
|
||||||
* A visible signature can be placed on multiple pages. (In the same position)
|
* A visible signature can be placed on multiple pages. (In the same position)
|
||||||
* Sign a pdf and set [DocMDP](https://github.com/zboris12/zgapdfsigner/wiki/API#note).
|
* Sign a pdf and set [DocMDP](https://github.com/zboris12/zgapdfsigner/wiki/API#note).
|
||||||
* Add a new signature to a pdf if it has been signed already. (An incremental update)
|
* Add a new signature to a pdf if it has been signed already. (An incremental update)
|
||||||
* Add a document timestamp from [TSA](https://github.com/zboris12/zgapdfsigner/wiki/API#note). ( :no_entry_sign:__Not__ available in web browser)
|
* Add a document timestamp from [TSA](https://github.com/zboris12/zgapdfsigner/wiki/API#note). ( :no_entry_sign:__Not__ available in web browser :sunflower:)
|
||||||
* Sign a pdf with a timestamp from [TSA](https://github.com/zboris12/zgapdfsigner/wiki/API#note). ( :no_entry_sign:__Not__ available in web browser)
|
* Sign a pdf with a timestamp from [TSA](https://github.com/zboris12/zgapdfsigner/wiki/API#note). ( :no_entry_sign:__Not__ available in web browser :sunflower:)
|
||||||
* Enable signature's [LTV](https://github.com/zboris12/zgapdfsigner/wiki/API#note). ( :no_entry_sign:__Not__ available in web browser)
|
* Enable signature's [LTV](https://github.com/zboris12/zgapdfsigner/wiki/API#note). ( :no_entry_sign:__Not__ available in web browser :sunflower:)
|
||||||
* Set password protection to a pdf. Supported algorithms:
|
* Set password protection to a pdf. Supported algorithms:
|
||||||
* 40bit RC4 Encryption
|
* 40bit RC4 Encryption
|
||||||
* 128bit RC4 Encryption
|
* 128bit RC4 Encryption
|
||||||
|
@ -33,6 +33,8 @@ And I use this name to hope the merits from this application will be dedicated t
|
||||||
|
|
||||||
Because of the [CORS](https://github.com/zboris12/zgapdfsigner/wiki/API#note) security restrictions in web browser,
|
Because of the [CORS](https://github.com/zboris12/zgapdfsigner/wiki/API#note) security restrictions in web browser,
|
||||||
signing with a timestamp from [TSA](https://github.com/zboris12/zgapdfsigner/wiki/API#note) or enabling [LTV](https://github.com/zboris12/zgapdfsigner/wiki/API#note) can only be used in [Google Apps Script](https://developers.google.com/apps-script) or [nodejs](https://nodejs.org/).
|
signing with a timestamp from [TSA](https://github.com/zboris12/zgapdfsigner/wiki/API#note) or enabling [LTV](https://github.com/zboris12/zgapdfsigner/wiki/API#note) can only be used in [Google Apps Script](https://developers.google.com/apps-script) or [nodejs](https://nodejs.org/).
|
||||||
|
:sunflower: However, if you can avoid the [CORS](https://github.com/zboris12/zgapdfsigner/wiki/API#note) security restrictions
|
||||||
|
by creating your own service or providing a reverse proxy server, these features are also available in web browser.
|
||||||
|
|
||||||
## The Dependencies
|
## The Dependencies
|
||||||
|
|
||||||
|
|
8
build.sh
8
build.sh
|
@ -9,6 +9,8 @@ else
|
||||||
mkdir ${OUTFLDR}
|
mkdir ${OUTFLDR}
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
VER=$(sed -n -r "s/^.*\"version\": ?\"([0-9.]+)\".*$/\1/p" package.json)
|
||||||
|
|
||||||
GCCOPT="--charset UTF-8 --compilation_level SIMPLE_OPTIMIZATIONS --warning_level VERBOSE"
|
GCCOPT="--charset UTF-8 --compilation_level SIMPLE_OPTIMIZATIONS --warning_level VERBOSE"
|
||||||
GCCEXT="--externs closure/google-ext.js --externs closure/forge-ext.js --externs closure/pdflib-ext.js --externs closure/zb-externs.js"
|
GCCEXT="--externs closure/google-ext.js --externs closure/forge-ext.js --externs closure/pdflib-ext.js --externs closure/zb-externs.js"
|
||||||
jss=""
|
jss=""
|
||||||
|
@ -20,7 +22,12 @@ do
|
||||||
if [ "$c" != "#" ]
|
if [ "$c" != "#" ]
|
||||||
then
|
then
|
||||||
outf="${OUTFLDR}/_${js}"
|
outf="${OUTFLDR}/_${js}"
|
||||||
|
if [ "${js}" = "zgaindex.js" ]
|
||||||
|
then
|
||||||
|
sed -e "s/\/\/Only for nodejs Start\/\//\/*/g" -e "s/\/\/Only for nodejs End\/\//*\//g" -e "s/ver: \"\"/ver: \"${VER}\"/" "lib/${js}" > "${outf}"
|
||||||
|
else
|
||||||
sed -e "s/\/\/Only for nodejs Start\/\//\/*/g" -e "s/\/\/Only for nodejs End\/\//*\//g" "lib/${js}" > "${outf}"
|
sed -e "s/\/\/Only for nodejs Start\/\//\/*/g" -e "s/\/\/Only for nodejs End\/\//*\//g" "lib/${js}" > "${outf}"
|
||||||
|
fi
|
||||||
if [ $? -eq 0 ]
|
if [ $? -eq 0 ]
|
||||||
then
|
then
|
||||||
echo "Created js file: ${outf}"
|
echo "Created js file: ${outf}"
|
||||||
|
@ -32,6 +39,7 @@ do
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
done <<EOF
|
done <<EOF
|
||||||
|
zgafetch.js
|
||||||
zgacertsutil.js
|
zgacertsutil.js
|
||||||
zgapdfcryptor.js
|
zgapdfcryptor.js
|
||||||
zgapdfsigner.js
|
zgapdfsigner.js
|
||||||
|
|
|
@ -0,0 +1,140 @@
|
||||||
|
/**
|
||||||
|
* @param {Object<string, *>} z
|
||||||
|
*/
|
||||||
|
function supplyZgaUrlFetch(z){
|
||||||
|
|
||||||
|
//Only for nodejs Start//
|
||||||
|
const m_urlparser = require("url");
|
||||||
|
const m_h = {
|
||||||
|
"http:": require('follow-redirects').http,
|
||||||
|
"https:": require('follow-redirects').https,
|
||||||
|
};
|
||||||
|
// @type {boolean}
|
||||||
|
z.isNode = function(){return this === globalThis.global;}();
|
||||||
|
//Only for nodejs End//
|
||||||
|
|
||||||
|
/** @type {boolean} */
|
||||||
|
z.isBrowser = function(){return this === globalThis.self;}();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} url
|
||||||
|
* @param {UrlFetchParams} params
|
||||||
|
* @return {Promise<Uint8Array>}
|
||||||
|
*/
|
||||||
|
z.urlFetch = function(url, params){
|
||||||
|
|
||||||
|
//Only for nodejs Start//
|
||||||
|
if(z.isNode){
|
||||||
|
return new Promise(function(resolve, reject){
|
||||||
|
// @type {URL}
|
||||||
|
var opts = m_urlparser.parse(url);
|
||||||
|
var http = m_h[opts.protocol];
|
||||||
|
// @type {string|Buffer}
|
||||||
|
var dat = null;
|
||||||
|
var encoding = undefined;
|
||||||
|
opts.method = "GET";
|
||||||
|
if(params){
|
||||||
|
if(params.payload instanceof Buffer){
|
||||||
|
dat = params.payload;
|
||||||
|
}else if(params.payload instanceof Uint8Array){
|
||||||
|
dat = Buffer.from(params.payload.buffer);
|
||||||
|
}else if(params.payload instanceof ArrayBuffer){
|
||||||
|
dat = Buffer.from(params.payload);
|
||||||
|
}else{
|
||||||
|
dat = params.payload;
|
||||||
|
encoding = "binary";
|
||||||
|
}
|
||||||
|
if(params.headers){
|
||||||
|
opts.headers = params.headers;
|
||||||
|
}
|
||||||
|
if(params.method){
|
||||||
|
opts.method = params.method;
|
||||||
|
}
|
||||||
|
if(params.validateHttpsCertificates === false){
|
||||||
|
opts.rejectUnauthorized = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// @type {http.ClientRequest}
|
||||||
|
var hreq = http.request(opts, function(a_res){ // @type {http.IncomingMessage} a_res
|
||||||
|
if(a_res.statusCode !== 200){
|
||||||
|
var a_err = new Error("Failed to request url. " + url + "\n Status Code: " + a_res.statusCode);
|
||||||
|
a_res.resume();
|
||||||
|
throw a_err;
|
||||||
|
}
|
||||||
|
// @type {Array<Buffer>}
|
||||||
|
var a_bufs = [];
|
||||||
|
var a_bufs_len = 0;
|
||||||
|
a_res.on("data", function(b_chunk){ // @type {Buffer} b_chunk
|
||||||
|
a_bufs.push(b_chunk);
|
||||||
|
a_bufs_len += b_chunk.length;
|
||||||
|
});
|
||||||
|
a_res.on("end", function(){
|
||||||
|
// @type {Buffer}
|
||||||
|
var b_bdat = Buffer.concat(a_bufs, a_bufs_len);
|
||||||
|
resolve(b_bdat);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
hreq.on("error", function(a_err){
|
||||||
|
throw a_err;
|
||||||
|
});
|
||||||
|
hreq.end(dat, encoding);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
//Only for nodejs End//
|
||||||
|
|
||||||
|
// Google Apps Script
|
||||||
|
if(globalThis.UrlFetchApp){
|
||||||
|
return new Promise(function(resolve){
|
||||||
|
/** @type {GBlob} */
|
||||||
|
var tblob = UrlFetchApp.fetch(url, params).getBlob();
|
||||||
|
resolve(new Uint8Array(tblob.getBytes()));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// browser
|
||||||
|
if(z.isBrowser && globalThis.self.fetch){
|
||||||
|
/**
|
||||||
|
* @return {Promise<Uint8Array>}
|
||||||
|
*/
|
||||||
|
var func = async function(){
|
||||||
|
/** @type {!RequestInit} */
|
||||||
|
var reqinf = {
|
||||||
|
method: "GET",
|
||||||
|
redirect: "follow",
|
||||||
|
};
|
||||||
|
if(params){
|
||||||
|
if(params.payload){
|
||||||
|
reqinf.body = params.payload;
|
||||||
|
}
|
||||||
|
if(params.headers){
|
||||||
|
reqinf.headers = params.headers;
|
||||||
|
}
|
||||||
|
if(params.method){
|
||||||
|
reqinf.method = params.method;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/** @type {Response} */
|
||||||
|
var resp = await fetch(url, reqinf);
|
||||||
|
if(resp.ok){
|
||||||
|
/** @type {ArrayBuffer} */
|
||||||
|
var abdat = await resp.arrayBuffer();
|
||||||
|
return new Uint8Array(abdat);
|
||||||
|
}else{
|
||||||
|
/** @type {string} */
|
||||||
|
var msg = await resp.text();
|
||||||
|
throw new Error("Fetch failed." + resp.status + ": " + msg);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return func();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//Only for nodejs Start//
|
||||||
|
if(typeof exports === "object" && typeof module !== "undefined"){
|
||||||
|
module.exports = supplyZgaUrlFetch;
|
||||||
|
}
|
||||||
|
//Only for nodejs End//
|
|
@ -5,7 +5,9 @@
|
||||||
*/
|
*/
|
||||||
function genZga(){
|
function genZga(){
|
||||||
/** @const {Object<string, *>} */
|
/** @const {Object<string, *>} */
|
||||||
const z = {};
|
const z = {
|
||||||
|
ver: "",
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {...string} msg
|
* @param {...string} msg
|
||||||
|
@ -42,22 +44,6 @@ function genZga(){
|
||||||
return arr;
|
return arr;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Google Apps Script
|
|
||||||
if(globalThis.UrlFetchApp){
|
|
||||||
/**
|
|
||||||
* @param {string} url
|
|
||||||
* @param {UrlFetchParams} params
|
|
||||||
* @return {Promise<Uint8Array>}
|
|
||||||
*/
|
|
||||||
z.urlFetch = function(url, params){
|
|
||||||
return new Promise(function(resolve){
|
|
||||||
/** @type {GBlob} */
|
|
||||||
var tblob = UrlFetchApp.fetch(url, params).getBlob();
|
|
||||||
resolve(new Uint8Array(tblob.getBytes()));
|
|
||||||
});
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
return z;
|
return z;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -68,6 +54,7 @@ if(typeof exports === "object" && typeof module !== "undefined"){
|
||||||
//Only for nodejs End//
|
//Only for nodejs End//
|
||||||
if(!globalThis.Zga){
|
if(!globalThis.Zga){
|
||||||
globalThis.Zga = genZga();
|
globalThis.Zga = genZga();
|
||||||
|
supplyZgaUrlFetch(globalThis.Zga);
|
||||||
supplyZgaCertsChain(globalThis.Zga);
|
supplyZgaCertsChain(globalThis.Zga);
|
||||||
supplyZgaCryptor(globalThis.Zga);
|
supplyZgaCryptor(globalThis.Zga);
|
||||||
supplyZgaSigner(globalThis.Zga);
|
supplyZgaSigner(globalThis.Zga);
|
||||||
|
|
|
@ -9,69 +9,8 @@ z.PDFLib = require("pdf-lib");
|
||||||
// z.fontkit = require("@pdf-lib/fontkit");
|
// z.fontkit = require("@pdf-lib/fontkit");
|
||||||
z.fontkit = require("pdf-fontkit");
|
z.fontkit = require("pdf-fontkit");
|
||||||
z.pako = require("pako");
|
z.pako = require("pako");
|
||||||
/**
|
|
||||||
* @param {string} url
|
|
||||||
* @param {UrlFetchParams} params
|
|
||||||
* @return {Promise<Uint8Array>}
|
|
||||||
*/
|
|
||||||
z.urlFetch = function(url, params){
|
|
||||||
return new Promise(function(resolve, reject){
|
|
||||||
/** @type {URL} */
|
|
||||||
var opts = m_urlparser.parse(url);
|
|
||||||
var http = m_h[opts.protocol];
|
|
||||||
/** @type {string|Buffer} */
|
|
||||||
var dat = null;
|
|
||||||
var encoding = undefined;
|
|
||||||
opts.method = "GET";
|
|
||||||
if(params){
|
|
||||||
if(params.payload instanceof Buffer){
|
|
||||||
dat = params.payload;
|
|
||||||
}else if(params.payload instanceof Uint8Array){
|
|
||||||
dat = Buffer.from(params.payload.buffer);
|
|
||||||
}else if(params.payload instanceof ArrayBuffer){
|
|
||||||
dat = Buffer.from(params.payload);
|
|
||||||
}else{
|
|
||||||
dat = params.payload;
|
|
||||||
encoding = "binary";
|
|
||||||
}
|
|
||||||
if(params.headers){
|
|
||||||
opts.headers = params.headers;
|
|
||||||
}
|
|
||||||
if(params.method){
|
|
||||||
opts.method = params.method;
|
|
||||||
}
|
|
||||||
if(params.validateHttpsCertificates === false){
|
|
||||||
opts.rejectUnauthorized = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @type {http.ClientRequest} */
|
|
||||||
var hreq = http.request(opts, function(/** @type {http.IncomingMessage} */a_res){
|
|
||||||
if(a_res.statusCode !== 200){
|
|
||||||
var a_err = new Error("Failed to request url. " + url + "\n Status Code: " + a_res.statusCode);
|
|
||||||
a_res.resume();
|
|
||||||
throw a_err;
|
|
||||||
}
|
|
||||||
/** @type {Array<Buffer>} */
|
|
||||||
var a_bufs = [];
|
|
||||||
var a_bufs_len = 0;
|
|
||||||
a_res.on("data", function(/** @type {Buffer} */b_chunk){
|
|
||||||
a_bufs.push(b_chunk);
|
|
||||||
a_bufs_len += b_chunk.length;
|
|
||||||
});
|
|
||||||
a_res.on("end", function(){
|
|
||||||
/** @type {Buffer} */
|
|
||||||
var b_bdat = Buffer.concat(a_bufs, a_bufs_len);
|
|
||||||
resolve(b_bdat);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
hreq.on("error", function(a_err){
|
|
||||||
throw a_err;
|
|
||||||
});
|
|
||||||
hreq.end(dat, encoding);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
|
require("./zgafetch.js")(z);
|
||||||
require("./zgacertsutil.js")(z);
|
require("./zgacertsutil.js")(z);
|
||||||
require("./zgapdfcryptor.js")(z);
|
require("./zgapdfcryptor.js")(z);
|
||||||
require("./zgapdfsigner.js")(z);
|
require("./zgapdfsigner.js")(z);
|
||||||
|
|
|
@ -260,6 +260,9 @@ z.PdfSigner = class{
|
||||||
if(!(globalThis.forge || forge)){
|
if(!(globalThis.forge || forge)){
|
||||||
throw new Error("node-forge is not imported.");
|
throw new Error("node-forge is not imported.");
|
||||||
}
|
}
|
||||||
|
if(z.ver){
|
||||||
|
z.log("ZgaPdfSigner Version:", z.ver);
|
||||||
|
}
|
||||||
/** @type {?TsaServiceInfo} */
|
/** @type {?TsaServiceInfo} */
|
||||||
var tsainf = null;
|
var tsainf = null;
|
||||||
if(signopt.signdate){
|
if(signopt.signdate){
|
||||||
|
@ -273,11 +276,13 @@ z.PdfSigner = class{
|
||||||
}
|
}
|
||||||
if(tsainf){
|
if(tsainf){
|
||||||
if(!z.urlFetch){
|
if(!z.urlFetch){
|
||||||
throw new Error("Because of the CORS security restrictions, signing with TSA is not supported in web browser.");
|
// throw new Error("Because of the CORS security restrictions, signing with TSA is not supported in web browser.");
|
||||||
|
throw new Error("No fetch method found in this environment.");
|
||||||
}
|
}
|
||||||
if(z.TSAURLS[tsainf.url]){
|
if(z.TSAURLS[tsainf.url]){
|
||||||
Object.assign(tsainf, z.TSAURLS[tsainf.url]);
|
Object.assign(tsainf, z.TSAURLS[tsainf.url]);
|
||||||
}else if(!(new RegExp("^https?://")).test(tsainf.url)){
|
}else if(!tsainf.url || (!z.isBrowser && !(new RegExp("^https?://")).test(tsainf.url))){
|
||||||
|
// It may be a relative path in browser environment, so only check in non-browser environment
|
||||||
throw new Error("Unknown tsa data. " + JSON.stringify(tsainf));
|
throw new Error("Unknown tsa data. " + JSON.stringify(tsainf));
|
||||||
}
|
}
|
||||||
if(!tsainf.len){
|
if(!tsainf.len){
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "zgapdfsigner",
|
"name": "zgapdfsigner",
|
||||||
"version": "2.7.2",
|
"version": "2.7.3",
|
||||||
"author": "zboris12",
|
"author": "zboris12",
|
||||||
"description": "A javascript tool to sign a pdf or set protection to a pdf in web browser, Google Apps Script and nodejs.",
|
"description": "A javascript tool to sign a pdf or set protection to a pdf in web browser, Google Apps Script and nodejs.",
|
||||||
"homepage": "https://github.com/zboris12/zgapdfsigner",
|
"homepage": "https://github.com/zboris12/zgapdfsigner",
|
||||||
|
|
Loading…
Reference in New Issue