Made js files to compiled by closure compiler.

pull/2/head 2.0.0
zboris12 2022-10-04 21:37:17 +09:00
parent 8c2a614a08
commit c4e5dafa17
7 changed files with 836 additions and 52 deletions

16
closure/build.bat Normal file
View File

@ -0,0 +1,16 @@
@echo off
set csr=\java\8\jre\bin\java.exe -jar \closure-compiler\closure-compiler-v20220104.jar --charset UTF-8 --compilation_level SIMPLE_OPTIMIZATIONS --warning_level VERBOSE
doskey csr=%csr% $*
set externs=--externs closure\google-ext.js --externs closure\forge-ext.js --externs closure\pdflib-ext.js --externs closure\zb-externs.js
rem main
set src=.
set jss=--js %src%\zgapdfcryptor.js --js %src%\zgapdfsigner.js
echo $
set chkj=%%externs%% --checks_only %%jss%%
echo chkj=csr %chkj%
doskey chkj=%csr% %chkj%
set csrj=%%externs%% %%jss%% --js_output_file %src%\dist\zgapdfsigner.min.js
echo csrj=csr %csrj%
doskey csrj=%csr% %csrj%

319
closure/forge-ext.js Normal file
View File

@ -0,0 +1,319 @@
/** @const */
var forge = {};
forge.random = {};
/**
* @param {number} count
* @return {string}
*/
forge.random.getBytesSync = function(count){};
forge.util = {};
/** @constructor */
forge.util.ByteStringBuffer = function(){};
/**
* @return {string}
*/
forge.util.ByteStringBuffer.prototype.getBytes = function(){};
/**
* @param {string} value
* @return {forge.util.ByteStringBuffer}
*/
forge.util.ByteStringBuffer.prototype.putBytes = function(value){};
/**
* @param {number} i
* @return {forge.util.ByteStringBuffer}
*/
forge.util.ByteStringBuffer.prototype.putInt24Le = function(i){};
/**
* @param {number} i
* @return {forge.util.ByteStringBuffer}
*/
forge.util.ByteStringBuffer.prototype.putInt32Le = function(i){};
/**
* @param {number} b
* @param {number} n
* @return {forge.util.ByteStringBuffer}
*/
forge.util.ByteStringBuffer.prototype.fillWithByte = function(b, n){};
/**
* @param {number} count
* @return {forge.util.ByteStringBuffer}
*/
forge.util.ByteStringBuffer.prototype.truncate = function(count){};
/**
* @return {string}
*/
forge.util.ByteStringBuffer.prototype.toHex = function(){};
/** @type {string} */
forge.util.ByteStringBuffer.prototype.data;
/**
* @param {string} input
* @param {string=} encoding
* @return {forge.util.ByteStringBuffer}
*/
forge.util.createBuffer = function(input, encoding){};
/**
* @param {string} hex
* @return {string}
*/
forge.util.hexToBytes = function(hex){};
/**
* @param {string} value
* @return {string}
*/
forge.util.decodeUtf8 = function(value){};
/** @constructor */
forge.asn1 = function(){};
/**
* @typedef
* {{
* strict: (boolean|undefined),
* parseAllBytes: (boolean|undefined),
* decodeBitStrings: (boolean|undefined),
* }}
*/
var DerOption;
/**
* @param {forge.util.ByteStringBuffer|string} bytes
* @param {DerOption=} options
* @return {forge.asn1}
*/
forge.asn1.fromDer = function(bytes, options){};
/**
* @param {forge.asn1} obj
* @return {forge.util.ByteStringBuffer}
*/
forge.asn1.toDer = function(obj){};
/**
* @param {number} num
* @return {forge.util.ByteStringBuffer}
*/
forge.asn1.integerToDer = function(num){};
/**
* @param {string} oid
* @return {forge.util.ByteStringBuffer}
*/
forge.asn1.oidToDer = function(oid){};
forge.asn1.Type = {};
/** @type {number} */
forge.asn1.Type.UTF8;
/** @type {number} */
forge.asn1.Type.SET;
/** @type {number} */
forge.asn1.Type.SEQUENCE;
/** @type {number} */
forge.asn1.Type.BOOLEAN;
/** @type {number} */
forge.asn1.Type.INTEGER;
/** @type {number} */
forge.asn1.Type.OID;
/** @type {number} */
forge.asn1.Type.NULL;
/** @type {number} */
forge.asn1.Type.OCTETSTRING;
forge.asn1.Class = {};
/** @type {string} */
forge.asn1.Class.UNIVERSAL;
/**
* @param {string} tagClass
* @param {number} type
* @param {boolean} constructed
* @param {Array<string>} value
* @param {Object=} options
* @return {forge.asn1}
*/
forge.asn1.create = function(tagClass, type, constructed, value, options){};
/** @type {Array<forge.asn1>} */
forge.asn1.prototype.value;
/** @constructor */
const forge_BigInteger = function(){};
/**
* @param {forge_BigInteger} a
* @return {number}
*/
forge_BigInteger.prototype.compareTo = function(a){};
/** @constructor */
const forge_cert = function(){};
/** @type {forge_key} */
forge_cert.prototype.publicKey;
/** @type {forge_cert_issuer} */
forge_cert.prototype.issuer;
/** @constructor */
const forge_key = function(){};
/** @type {forge_BigInteger} */
forge_key.prototype.n;
/** @type {forge_BigInteger} */
forge_key.prototype.e;
/** @constructor */
const forge_cert_issuer = function(){};
/** @type {Array<forge_cert_attr>} */
forge_cert_issuer.prototype.attributes;
/**
* @typedef
* {{
* valueTagClass: (string|undefined),
* type: (string|undefined),
* value: (string|undefined),
* }}
*/
var forge_cert_attr;
/**
* @typedef
* {{
* key: (forge_key|undefined),
* certificate: (forge_cert|undefined),
* digestAlgorithm: (string|undefined),
* authenticatedAttributes: (Array<forge_cert_attr>|undefined),
* unauthenticatedAttributes: (Array<forge_cert_attr>|undefined),
* signature: (string|undefined),
* }}
*/
var forge_signer;
/** @constructor */
forge.pkcs7 = function(){};
/**
* @return {forge.pkcs7}
*/
forge.pkcs7.createSignedData = function(){};
/**
* @param {forge_cert} cert
*/
forge.pkcs7.prototype.addCertificate = function(cert){};
/**
* @param {forge_signer} signer
*/
forge.pkcs7.prototype.addSigner = function(signer){};
/** @type {Array<forge_signer>} */
forge.pkcs7.prototype.signers;
/** @type {Array<forge.asn1>} */
forge.pkcs7.prototype.signerInfos;
/**
* @typedef
* {{
* detached: (boolean|undefined),
* }}
*/
var forge_sign_option;
/**
* @param {forge_sign_option} options
*/
forge.pkcs7.prototype.sign = function(options){};
/**
* @return {forge.asn1}
*/
forge.pkcs7.prototype.toAsn1 = function(){};
/** @constructor */
forge.pkcs12 = function(){};
/**
* @param {forge.asn1} obj
* @param {boolean=} strict
* @param {string=} password
* @return {forge.pkcs12}
*/
forge.pkcs12.pkcs12FromAsn1 = function(obj, strict, password){};
/**
* @typedef
* {{
* localKeyId: (string|undefined),
* localKeyIdHex: (string|undefined),
* friendlyName: (string|undefined),
* bagType: (string|undefined),
* }}
*/
var P12BagsFilter;
/**
* @typedef
* {{
* cert: forge_cert,
* key: forge_key,
* }}
*/
var P12Bag;
/**
* @param {P12BagsFilter} filter
* @return {Object<string, Object<string|number, P12Bag>>}
*/
forge.pkcs12.prototype.getBags = function(filter){};
forge.oids = {};
/** @type {string} */
forge.oids.sha256;
forge.pki = {};
forge.pki.oids = {};
/** @type {string} */
forge.pki.oids.certBag;
/** @type {string} */
forge.pki.oids.pkcs8ShroudedKeyBag;
/** @type {string} */
forge.pki.oids.sha256;
/** @type {string} */
forge.pki.oids.contentType;
/** @type {string} */
forge.pki.oids.data;
/** @type {string} */
forge.pki.oids.messageDigest;
/** @type {string} */
forge.pki.oids.signingTime;
forge.md = {};
/** @constructor */
forge.md.digest = function(){};
/**
* @param {string=} msg
* @param {string=} encoding
* @return {forge.md.digest}
*/
forge.md.digest.prototype.update = function(msg, encoding){};
/**
* @return {forge.util.ByteStringBuffer}
*/
forge.md.digest.prototype.digest = function(){};
forge.md.md5 = {};
forge.md.sha256 = {};
/**
* @return {forge.md.digest}
*/
forge.md.md5.create = function(){};
/**
* @return {forge.md.digest}
*/
forge.md.sha256.create = function(){};
forge.cipher = {};
/** @constructor */
forge.cipher.BlockCipher = function(){};
/**
* @typedef
* {{
* iv: (string|undefined),
* additionalData: (string|undefined),
* tagLength: (number|undefined),
* tag: (string|undefined),
* output: (forge.util.ByteStringBuffer|undefined),
* }}
*/
var CipherOptions;
/**
* @param {CipherOptions} options
*/
forge.cipher.BlockCipher.prototype.start = function(options){};
/**
* @param {forge.util.ByteStringBuffer} input
*/
forge.cipher.BlockCipher.prototype.update = function(input){};
/**
* @return {boolean}
*/
forge.cipher.BlockCipher.prototype.finish = function(){};
/** @type {forge.util.ByteStringBuffer} */
forge.cipher.BlockCipher.prototype.output;
/**
* @param {string} algorithm
* @param {forge.util.ByteStringBuffer} key
* @return {forge.cipher.BlockCipher}
*/
forge.cipher.createCipher = function(algorithm, key) {};

50
closure/google-ext.js Normal file
View File

@ -0,0 +1,50 @@
/**
* @typedef
* {{
* contentType: (string|undefined),
* headers: (Object<string, *>|undefined),
* method: (string|undefined),
* payload: (string|Uint8Array|undefined),
* useIntranet: (boolean|undefined),
* validateHttpsCertificates: (boolean|undefined),
* followRedirects: (boolean|undefined),
* muteHttpExceptions: (boolean|undefined),
* escaping: (boolean|undefined),
* }}
*/
var UrlFetchParams;
/**
* @constructor
*/
function GoogleUrlFetchApp(){}
/**
* @param {string} url
* @param {UrlFetchParams} params
* @return {HTTPResponse}
*/
GoogleUrlFetchApp.prototype.fetch = function(url, params){};
/**
* @const {!GoogleUrlFetchApp}
*/
var UrlFetchApp;
/**
* @constructor
*/
function HTTPResponse(){}
/**
* @return {GBlob}
*/
HTTPResponse.prototype.getBlob = function(){};
/**
* @constructor
*/
function GBlob(){}
/**
* @return {Array<number>}
*/
GBlob.prototype.getBytes = function(){};

265
closure/pdflib-ext.js Normal file
View File

@ -0,0 +1,265 @@
/**
* @typedef
* {{
* ignoreEncryption: (boolean|undefined),
* parseSpeed: (number|undefined),
* throwOnInvalidObject: (boolean|undefined),
* }}
*/
var PdfLoadOptions;
/** @const */
var PDFLib = {};
/** @constructor */
PDFLib.PDFDocument = function(){};
/**
* @param {string|Uint8Array|ArrayBuffer} pdf
* @param {PdfLoadOptions=} options
* @return {PDFLib.PDFDocument}
*/
PDFLib.PDFDocument.load = function(pdf, options){};
/**
* @typedef
* {{
* useObjectStreams: (boolean|undefined),
* addDefaultPage: (boolean|undefined),
* objectsPerTick: (number|undefined),
* }}
*/
var PdfSaveOptions;
/**
* @param {PdfSaveOptions} options
* @returns {Promise<Uint8Array>}
*/
PDFLib.PDFDocument.prototype.save = function(options){};
/**
* @returns {Array<PDFLib.PDFPage>}
*/
PDFLib.PDFDocument.prototype.getPages = function(){};
/**
* @param {ArrayBuffer|Uint8Array|string} png
* @returns {Promise<PDFLib.PDFImage>}
*/
PDFLib.PDFDocument.prototype.embedPng = function(png){};
/**
* @param {ArrayBuffer|Uint8Array|string} jpg
* @returns {Promise<PDFLib.PDFImage>}
*/
PDFLib.PDFDocument.prototype.embedJpg = function(jpg){};
/** @type {PDFLib.PDFCatalog} */
PDFLib.PDFDocument.prototype.catalog;
/** @type {PDFLib.PDFContext} */
PDFLib.PDFDocument.prototype.context;
/** @constructor */
PDFLib.PDFCatalog = function(){};
/**
* @param {PDFLib.PDFName} name
* @param {PDFLib.PDFObject} object
*/
PDFLib.PDFCatalog.prototype.set = function(name, object){};
/** @constructor */
PDFLib.PDFPage = function(){};
/** @type {PDFLib.PDFRef} */
PDFLib.PDFPage.prototype.ref;
/** @type {PDFLib.PDFPageLeaf} */
PDFLib.PDFPage.prototype.node;
/**
* @return {PDFLib.Rotation}
*/
PDFLib.PDFPage.prototype.getRotation = function(){};
/**
* @typedef
* {{
* width: number,
* height: number,
* }}
*/
var PdfSize;
/**
* @return {PdfSize}
*/
PDFLib.PDFPage.prototype.getSize = function(){};
/** @constructor */
PDFLib.PDFPageLeaf = function(){};
/**
* @param {PDFLib.PDFName} name
* @param {PDFLib.PDFObject} object
*/
PDFLib.PDFPageLeaf.prototype.set = function(name, object){};
/** @constructor */
PDFLib.PDFRef = function(){};
/** @type {number} */
PDFLib.PDFRef.prototype.objectNumber;
/** @constructor */
PDFLib.PDFContext = function(){};
/**
* @typedef
* {{
* 0: PDFLib.PDFRef,
* 1: PDFLib.PDFObject,
* }}
*/
var PdfObjEntry;
/** @return {Array<PdfObjEntry>} */
PDFLib.PDFContext.prototype.enumerateIndirectObjects = function(){};
/** @type {Object<string, *>} */
PDFLib.PDFContext.prototype.trailerInfo;
/**
* @param {PDFLib.PDFObject} object
* @return {PDFLib.PDFRef}
*/
PDFLib.PDFContext.prototype.register = function(object){};
/**
* @param {*} literal
* @return {PDFLib.PDFObject}
*/
PDFLib.PDFContext.prototype.obj = function(literal){};
/** @constructor */
PDFLib.PDFObject = function(){};
/** @type {Map<PDFLib.PDFRef, PDFLib.PDFObject>} */
PDFLib.PDFObject.prototype.dict;
/** @type {Array<PDFLib.PDFName>} */
PDFLib.PDFObject.prototype.array;
/**
* @constructor
* @extends {PDFLib.PDFObject}
*/
PDFLib.PDFName = function(){};
/**
* @param {string} value
* @return {PDFLib.PDFName}
*/
PDFLib.PDFName.of = function(value){};
/** @type {string} */
PDFLib.PDFName.prototype.encodedName;
/** @type {number} */
PDFLib.PDFName.prototype.numberValue;
/**
* @constructor
* @param {PDFLib.PDFContext} context
*/
PDFLib.PDFArray = function(context){};
/**
* @param {PDFLib.PDFObject} object
*/
PDFLib.PDFArray.prototype.push = function(object){};
/**
* @constructor
* @extends {PDFLib.PDFObject}
*/
PDFLib.PDFString = function(){};
/**
* @param {string} value
* @return {PDFLib.PDFString}
*/
PDFLib.PDFString.of = function(value){};
/**
* @param {Date} value
* @return {PDFLib.PDFString}
*/
PDFLib.PDFString.fromDate = function(value){};
/**
* @constructor
* @extends {PDFLib.PDFObject}
*/
PDFLib.PDFHexString = function(){};
/**
* @param {string} value
* @return {PDFLib.PDFHexString}
*/
PDFLib.PDFHexString.of = function(value){};
/**
* @param {string} value
* @return {PDFLib.PDFHexString}
*/
PDFLib.PDFHexString.fromText = function(value){};
/**
* @constructor
* @extends {PDFLib.PDFObject}
*/
PDFLib.PDFNumber = function(){};
/**
* @param {number} value
* @return {PDFLib.PDFNumber}
*/
PDFLib.PDFNumber.of = function(value){};
/** @constructor */
PDFLib.PDFImage = function(){};
/**
* @return {PdfSize}
*/
PDFLib.PDFImage.prototype.size = function(){};
/** @type {PDFLib.PDFRef} */
PDFLib.PDFImage.prototype.ref;
/** @constructor */
PDFLib.PDFFont = function(){};
/** @type {PDFLib.PDFRef} */
PDFLib.PDFFont.prototype.ref;
/** @constructor */
PDFLib.StandardFonts = function(){};
PDFLib.RotationTypes = {};
/** @type {string} */
PDFLib.RotationTypes.Degrees;
/** @constructor */
PDFLib.Rotation = function(){};
/** @type {string} */
PDFLib.Rotation.prototype.type;
/**
* @param {number} d
* @return {PDFLib.Rotation}
*/
PDFLib.degrees = function(d){};
/**
* @param {PDFLib.Rotation} rot
* @return {PDFLib.Rotation}
*/
PDFLib.toDegrees = function(rot){};
/** @constructor */
PDFLib.PDFOperator = function(){};
/**
* @typedef
* {{
* x: (number|undefined),
* y: (number|undefined),
* width: (number|undefined),
* height: (number|undefined),
* rotate: (PDFLib.Rotation|undefined),
* xSkew: (PDFLib.Rotation|undefined),
* ySkew: (PDFLib.Rotation|undefined),
* }}
*/
var PdfDrawimgOption;
/**
* @param {string} name
* @param {PdfDrawimgOption} options
*/
PDFLib.drawImage = function(name, options){};
/**
* @constructor
* @extends {PDFLib.PDFObject}
*/
PDFLib.PDFContentStream = function(){};
/**
* @param {PDFLib.PDFObject} dict
* @param {Array<PDFLib.PDFOperator>} operators
* @param {boolean=} encode
* @return {PDFLib.PDFContentStream}
*/
PDFLib.PDFContentStream.of = function(dict, operators, encode){};

View File

@ -51,7 +51,7 @@ var SignOption;
* @typedef * @typedef
* {{ * {{
* c: string, * c: string,
* p: (Array<Zga.Crypto.Permission>|undefined), * p: (Array<string>|undefined),
* }} * }}
*/ */
var PubKeyInfo; var PubKeyInfo;
@ -74,7 +74,7 @@ var PubKeyInfo;
* @typedef * @typedef
* {{ * {{
* mode: Zga.Crypto.Mode, * mode: Zga.Crypto.Mode,
* permissions: (Array<Zga.Crypto.Permission>|undefined), * permissions: (Array<string>|undefined),
* userpwd: (string|undefined), * userpwd: (string|undefined),
* ownerpwd: (string|undefined), * ownerpwd: (string|undefined),
* pubkeys: (Array<PubKeyInfo>|undefined), * pubkeys: (Array<PubKeyInfo>|undefined),
@ -101,3 +101,25 @@ var CFType;
* }} * }}
*/ */
var RC4LastInfo; var RC4LastInfo;
var Zga = {};
Zga.Crypto = {};
/** @enum {number} */
Zga.Crypto.Mode = {
RC4_40: 0,
RC4_128: 1,
AES_128: 2,
AES_256: 3,
};
/**
* @constructor
* @param {EncryptOption} encopt
*/
Zga.PdfCryptor = function(encopt){};
/**
* @param {PDFLib.PDFDocument|Array<number>|Uint8Array|ArrayBuffer|string} pdf
* @param {boolean=} reload
* @return {Promise<PDFLib.PDFDocument>}
*/
Zga.PdfCryptor.prototype.encryptPdf = function(pdf, reload){};

View File

@ -14,11 +14,11 @@ z.loadPdf = async function(pdf){
/** @type {PDFLib.PDFDocument} */ /** @type {PDFLib.PDFDocument} */
var pdfdoc = null; var pdfdoc = null;
if(pdf.addPage){ if(pdf.addPage){
pdfdoc = pdf; pdfdoc = /** @type {PDFLib.PDFDocument} */(pdf);
}else if(Array.isArray(pdf)){ }else if(Array.isArray(pdf)){
pdfdoc = await PDFLib.PDFDocument.load(new Uint8Array(pdf)); pdfdoc = await PDFLib.PDFDocument.load(new Uint8Array(pdf));
}else{ }else{
pdfdoc = await PDFLib.PDFDocument.load(pdf); pdfdoc = await PDFLib.PDFDocument.load(/** @type {(ArrayBuffer|Uint8Array|string)} */(pdf));
} }
return pdfdoc; return pdfdoc;
}; };
@ -41,6 +41,7 @@ z.u8arrToRaw = function(uarr){
* @return {Uint8Array} * @return {Uint8Array}
*/ */
z.rawToU8arr = function(raw){ z.rawToU8arr = function(raw){
/** @type {Uint8Array} */
var arr = new Uint8Array(raw.length); var arr = new Uint8Array(raw.length);
for(var i=0; i<raw.length; i++){ for(var i=0; i<raw.length; i++){
arr[i] = raw.charCodeAt(i); arr[i] = raw.charCodeAt(i);
@ -86,9 +87,12 @@ z.Crypto = {
if(!s){ if(!s){
return s; return s;
} }
/** @const {Array<string>} */
const CHARS = "\\()".split(""); const CHARS = "\\()".split("");
/** @type {Array<string>} */
var arr = []; var arr = [];
for(var i=0; i<s.length; i++){ for(var i=0; i<s.length; i++){
/** @type {string} */
var c = s.charAt(i); var c = s.charAt(i);
if(c == "\r"){ if(c == "\r"){
arr.push("\\r"); arr.push("\\r");
@ -108,6 +112,7 @@ z.Crypto = {
* @return {string} containing random data * @return {string} containing random data
*/ */
getRandomSeed: function(seed){ getRandomSeed: function(seed){
/** @type {string} */
var ret = forge.random.getBytesSync(256); var ret = forge.random.getBytesSync(256);
if(seed){ if(seed){
ret += seed; ret += seed;
@ -127,10 +132,14 @@ z.Crypto = {
_RC4: function(key, txt, lastinf){ _RC4: function(key, txt, lastinf){
/** @type {Array<number>} */ /** @type {Array<number>} */
var rc4 = null; var rc4 = null;
/** @type {number} */
var i = 0; var i = 0;
/** @type {number} */
var j = 0; var j = 0;
/** @type {number} */
var t = 0; var t = 0;
if(lastinf.enckey != key){ if(lastinf.enckey != key){
/** @type {string} */
var k = key.repeat(256 / key.length + 1); var k = key.repeat(256 / key.length + 1);
rc4 = new Array(256); rc4 = new Array(256);
// Initialize rc4 // Initialize rc4
@ -148,9 +157,13 @@ z.Crypto = {
}else{ }else{
rc4 = [].concat(lastinf.enckeyc); rc4 = [].concat(lastinf.enckeyc);
} }
/** @type {number} */
var len = txt.length; var len = txt.length;
/** @type {number} */
var a = 0; var a = 0;
/** @type {number} */
var b = 0; var b = 0;
/** @type {string} */
var out = ""; var out = "";
for(i=0; i<len; i++){ for(i=0; i<len; i++){
a = (a + 1) % 256; a = (a + 1) % 256;
@ -167,14 +180,16 @@ z.Crypto = {
/** /**
* Return the permission code used on encryption (P value). * Return the permission code used on encryption (P value).
* *
* @param {Array<Zga.Crypto.Permission>=} permissions the set of permissions (specify the ones you want to block). * @param {Array<string>=} permissions the set of permissions (specify the ones you want to block).
* @param {Zga.Crypto.Mode=} mode * @param {z.Crypto.Mode=} mode
* @return {number} * @return {number}
*/ */
getUserPermissionCode: function(permissions, mode){ getUserPermissionCode: function(permissions, mode){
/** @type {number} */
var protection = 2147422012; // 32 bit: (01111111 11111111 00001111 00111100) var protection = 2147422012; // 32 bit: (01111111 11111111 00001111 00111100)
if(permissions){ if(permissions){
permissions.forEach(function(a_itm){ permissions.forEach(function(a_itm){
/** @type {number} */
var a_p = z.Crypto.Permission[a_itm]; var a_p = z.Crypto.Permission[a_itm];
if(a_p){ if(a_p){
if(mode > 0 || a_p <= 32){ if(mode > 0 || a_p <= 32){
@ -198,6 +213,7 @@ z.Crypto = {
* @return {string} * @return {string}
*/ */
getEncPermissionsString: function(protection){ getEncPermissionsString: function(protection){
/** @type {forge.util.ByteStringBuffer} */
var buff = new forge.util.ByteStringBuffer(); var buff = new forge.util.ByteStringBuffer();
buff.putInt32Le(protection); buff.putInt32Le(protection);
return buff.getBytes(); return buff.getBytes();
@ -209,6 +225,7 @@ z.Crypto = {
* @return {string} MD5 encrypted binary string * @return {string} MD5 encrypted binary string
*/ */
_md5_16: function(str){ _md5_16: function(str){
/** @type {forge.md.digest} */
var md = forge.md.md5.create(); var md = forge.md.md5.create();
md.update(str); md.update(str);
return md.digest().getBytes(); return md.digest().getBytes();
@ -223,13 +240,17 @@ z.Crypto = {
*/ */
_AES: function(key, txt){ _AES: function(key, txt){
// padding (RFC 2898, PKCS #5: Password-Based Cryptography Specification Version 2.0) // padding (RFC 2898, PKCS #5: Password-Based Cryptography Specification Version 2.0)
/** @type {string} */ /** @type {number} */
var padding = 16 - (txt.length % 16); var padding = 16 - (txt.length % 16);
/** @type {forge.util.ByteStringBuffer} */
var buff = forge.util.createBuffer(txt); var buff = forge.util.createBuffer(txt);
buff.fillWithByte(padding, padding); buff.fillWithByte(padding, padding);
/** @type {string} */
var iv = forge.random.getBytesSync(16); var iv = forge.random.getBytesSync(16);
/** @type {forge.util.ByteStringBuffer} */
var key2 = forge.util.createBuffer(key); var key2 = forge.util.createBuffer(key);
/** @type {forge.cipher.BlockCipher} */
var cipher = forge.cipher.createCipher("AES-CBC", key2); var cipher = forge.cipher.createCipher("AES-CBC", key2);
cipher.start({iv: iv}); cipher.start({iv: iv});
cipher.update(buff); cipher.update(buff);
@ -245,9 +266,13 @@ z.Crypto = {
* @return {string} encrypted text * @return {string} encrypted text
*/ */
_AESnopad: function(key, txt) { _AESnopad: function(key, txt) {
/** @type {forge.util.ByteStringBuffer} */
var buff = forge.util.createBuffer(txt); var buff = forge.util.createBuffer(txt);
/** @type {string} */
var iv = String.fromCharCode(0).repeat(16); var iv = String.fromCharCode(0).repeat(16);
/** @type {forge.util.ByteStringBuffer} */
var key2 = forge.util.createBuffer(key); var key2 = forge.util.createBuffer(key);
/** @type {forge.cipher.BlockCipher} */
var cipher = forge.cipher.createCipher("AES-CBC", key2); var cipher = forge.cipher.createCipher("AES-CBC", key2);
cipher.start({iv: iv}); cipher.start({iv: iv});
cipher.update(buff); cipher.update(buff);
@ -259,18 +284,17 @@ z.Crypto = {
z.PdfCryptor = class{ z.PdfCryptor = class{
/** /**
* @constructor
* @param {EncryptOption} encopt * @param {EncryptOption} encopt
*/ */
constructor(encopt){ constructor(encopt){
/** @private @type {string} */ /** @private @type {string} */
this.fileid = ""; this.fileid = "";
/** @private @type {string} */ /** @private @type {string} */
this.key = null; this.key = "";
/** @private @type {Array<PubKeyInfo>} */ /** @private @type {Array<PubKeyInfo>|undefined} */
this.pubkeys = encopt.pubkeys; this.pubkeys = encopt.pubkeys;
/** @private @type {number} */ /** @private @type {z.Crypto.Mode} */
this.mode = encopt.mode; this.mode = /** @type {z.Crypto.Mode} */(encopt.mode);
/** @private @type {number} */ /** @private @type {number} */
this.protection = 0; this.protection = 0;
/** @private @type {string} */ /** @private @type {string} */
@ -289,7 +313,7 @@ z.PdfCryptor = class{
this.V = 1; this.V = 1;
/** @private @type {number} */ /** @private @type {number} */
this.Length = 0; this.Length = 0;
/** @private @type {CFType} */ /** @private @type {?CFType} */
this.CF = null; this.CF = null;
/** @private @type {string} */ /** @private @type {string} */
this.SubFilter = ""; this.SubFilter = "";
@ -325,7 +349,6 @@ z.PdfCryptor = class{
}; };
if(this.pubkeys){ if(this.pubkeys){
throw new Error("Public key mode is not supported yet.");
if(this.mode == z.Crypto.Mode.RC4_40){ if(this.mode == z.Crypto.Mode.RC4_40){
// public-Key Security requires at least 128 bit // public-Key Security requires at least 128 bit
this.mode = z.Crypto.Mode.RC4_128; this.mode = z.Crypto.Mode.RC4_128;
@ -333,6 +356,7 @@ z.PdfCryptor = class{
this.Filter = "Adobe.PubSec"; this.Filter = "Adobe.PubSec";
this.StmF = "DefaultCryptFilter"; this.StmF = "DefaultCryptFilter";
this.StrF = "DefaultCryptFilter"; this.StrF = "DefaultCryptFilter";
throw new Error("Public key mode is not supported yet.");
} }
if(encopt.userpwd){ if(encopt.userpwd){
@ -341,6 +365,7 @@ z.PdfCryptor = class{
if(encopt.ownerpwd){ if(encopt.ownerpwd){
this.ownerpwd = encopt.ownerpwd; this.ownerpwd = encopt.ownerpwd;
}else{ }else{
/** @type {forge.md.digest} */
var md = forge.md.md5.create(); var md = forge.md.md5.create();
md.update(z.Crypto.getRandomSeed()); md.update(z.Crypto.getRandomSeed());
this.ownerpwd = md.digest().toHex(); this.ownerpwd = md.digest().toHex();
@ -379,6 +404,8 @@ z.PdfCryptor = class{
this.Recipients = []; this.Recipients = [];
} }
break; break;
default:
throw new Error("Unknown crypto mode. " + this.mode);
} }
this.protection = z.Crypto.getUserPermissionCode(encopt.permissions, this.mode); this.protection = z.Crypto.getUserPermissionCode(encopt.permissions, this.mode);
@ -411,7 +438,7 @@ z.PdfCryptor = class{
/** /**
* @param {number} a_num * @param {number} a_num
* @param {*} a_val * @param {PDFLib.PDFObject} a_val
*/ */
var func = function(a_num, a_val){ var func = function(a_num, a_val){
if(a_val instanceof PDFLib.PDFStream){ if(a_val instanceof PDFLib.PDFStream){
@ -430,7 +457,7 @@ z.PdfCryptor = class{
if(a_val.dict instanceof Map){ if(a_val.dict instanceof Map){
/** @type {Iterator} */ /** @type {Iterator} */
var a_es = a_val.dict.entries(); var a_es = a_val.dict.entries();
/** @type {IteratorResult} */ /** @type {IIterableResult<PdfObjEntry>} */
var a_res = a_es.next(); var a_res = a_es.next();
while(!a_res.done){ while(!a_res.done){
func(a_num, a_res.value[1]); func(a_num, a_res.value[1]);
@ -438,7 +465,7 @@ z.PdfCryptor = class{
} }
} }
}.bind(this); }.bind(this);
pdfcont.enumerateIndirectObjects().forEach(function(a_arr){ pdfcont.enumerateIndirectObjects().forEach(function(/** @type {PdfObjEntry} */a_arr){
func(a_arr[0].objectNumber, a_arr[1]); func(a_arr[0].objectNumber, a_arr[1]);
}); });
@ -456,12 +483,17 @@ z.PdfCryptor = class{
*/ */
prepareEncrypt(pdfcont){ prepareEncrypt(pdfcont){
if(!pdfcont.trailerInfo.ID){ if(!pdfcont.trailerInfo.ID){
/** @type {forge.md.digest} */
var md = forge.md.md5.create(); var md = forge.md.md5.create();
md.update(z.Crypto.getRandomSeed()); md.update(z.Crypto.getRandomSeed());
/** @type {forge.util.ByteStringBuffer} */
var res = md.digest(); var res = md.digest();
/** @type {string} */
var idhex = res.toHex(); var idhex = res.toHex();
/** @type {string} */
this.fileid = res.getBytes(); this.fileid = res.getBytes();
/** @type {PDFLib.PDFArray} */
var trIds = new PDFLib.PDFArray(pdfcont); var trIds = new PDFLib.PDFArray(pdfcont);
trIds.push(PDFLib.PDFHexString.of(idhex)); trIds.push(PDFLib.PDFHexString.of(idhex));
trIds.push(PDFLib.PDFHexString.of(idhex)); trIds.push(PDFLib.PDFHexString.of(idhex));
@ -484,6 +516,7 @@ z.PdfCryptor = class{
if(this.V >= 4){ if(this.V >= 4){
// A dictionary whose keys shall be crypt filter names and whose values shall be the corresponding crypt filter dictionaries. // A dictionary whose keys shall be crypt filter names and whose values shall be the corresponding crypt filter dictionaries.
if(this.CF){ if(this.CF){
/** @type {Object<string, *>} */
var objStmF = { var objStmF = {
Type: "CryptFilter", Type: "CryptFilter",
}; };
@ -492,11 +525,11 @@ z.PdfCryptor = class{
objStmF.CFM = this.CF.CFM; objStmF.CFM = this.CF.CFM;
if(this.pubkeys){ if(this.pubkeys){
/** @type {PDFLib.PDFArray} */ /** @type {PDFLib.PDFArray} */
var recps = new PDFLib.PDFArray(pdfcont); var recps1 = new PDFLib.PDFArray(pdfcont);
this.Recipients.forEach(function(a_ele){ this.Recipients.forEach(function(a_ele){
recps.push(PDFLib.PDFHexString.of(a_ele)); recps1.push(PDFLib.PDFHexString.of(a_ele));
}); });
objStmF.Recipients = recps; objStmF.Recipients = recps1;
if(typeof this.CF.EncryptMetadata == "boolean" && !this.CF.EncryptMetadata){ if(typeof this.CF.EncryptMetadata == "boolean" && !this.CF.EncryptMetadata){
objStmF.EncryptMetadata = false; objStmF.EncryptMetadata = false;
}else{ }else{
@ -517,6 +550,7 @@ z.PdfCryptor = class{
objStmF.Length = this.CF.Length; objStmF.Length = this.CF.Length;
} }
/** @type {Object<string, *>} */
var objCF = { var objCF = {
[this.StmF]: pdfcont.obj(objStmF), [this.StmF]: pdfcont.obj(objStmF),
}; };
@ -569,7 +603,9 @@ z.PdfCryptor = class{
* @return {Uint8Array} * @return {Uint8Array}
*/ */
encryptU8arr(num, dat){ encryptU8arr(num, dat){
/** @type {string} */
var str = z.u8arrToRaw(dat); var str = z.u8arrToRaw(dat);
/** @type {string} */
var enc = this._encrypt_data(num, str); var enc = this._encrypt_data(num, str);
return z.rawToU8arr(enc); return z.rawToU8arr(enc);
} }
@ -581,7 +617,9 @@ z.PdfCryptor = class{
* @return {string} * @return {string}
*/ */
encryptHexstr(num, dat){ encryptHexstr(num, dat){
/** @type {string} */
var str = forge.util.hexToBytes(dat); var str = forge.util.hexToBytes(dat);
/** @type {string} */
var enc = this._encrypt_data(num, str); var enc = this._encrypt_data(num, str);
return forge.util.createBuffer(enc).toHex(); return forge.util.createBuffer(enc).toHex();
} }
@ -595,6 +633,7 @@ z.PdfCryptor = class{
* @return {string} object key * @return {string} object key
*/ */
_objectkey(n){ _objectkey(n){
/** @type {forge.util.ByteStringBuffer} */
var buff = forge.util.createBuffer(this.key); var buff = forge.util.createBuffer(this.key);
//pack('VXxx', $n) //pack('VXxx', $n)
buff.putInt24Le(n); buff.putInt24Le(n);
@ -604,8 +643,10 @@ z.PdfCryptor = class{
buff.putBytes("sAlT"); buff.putBytes("sAlT");
} }
/** @type {forge.md.digest} */
var md = forge.md.md5.create(); var md = forge.md.md5.create();
md.update(buff.getBytes()); md.update(buff.getBytes());
/** @type {forge.util.ByteStringBuffer} */
var ret = md.digest(); var ret = md.digest();
return ret.getBytes().substr(0, Math.min(16, (this.Length / 8) + 5)); return ret.getBytes().substr(0, Math.min(16, (this.Length / 8) + 5));
} }
@ -640,13 +681,19 @@ z.PdfCryptor = class{
* @return {string} U value * @return {string} U value
*/ */
_Uvalue(){ _Uvalue(){
/** @type {string} */
var ret = "";
if(this.mode == z.Crypto.Mode.RC4_40){ if(this.mode == z.Crypto.Mode.RC4_40){
return z.Crypto._RC4(this.key, z.Crypto.EncPadding, this.rc4inf); ret = z.Crypto._RC4(this.key, z.Crypto.EncPadding, this.rc4inf);
}else if(this.mode < z.Crypto.Mode.AES_256) { // RC4-128, AES-128 }else if(this.mode < z.Crypto.Mode.AES_256) { // RC4-128, AES-128
/** @type {string} */
var tmp = z.Crypto._md5_16(z.Crypto.EncPadding + this.fileid); var tmp = z.Crypto._md5_16(z.Crypto.EncPadding + this.fileid);
/** @type {string} */
var enc = z.Crypto._RC4(this.key, tmp, this.rc4inf); var enc = z.Crypto._RC4(this.key, tmp, this.rc4inf);
/** @type {number} */
var len = tmp.length; var len = tmp.length;
for(var i=1; i<=19; i++){ for(var i=1; i<=19; i++){
/** @type {string} */
var ek = ""; var ek = "";
for(var j=0; j<len; j++){ for(var j=0; j<len; j++){
ek += String.fromCharCode(this.key.charCodeAt(j) ^ i); ek += String.fromCharCode(this.key.charCodeAt(j) ^ i);
@ -654,19 +701,24 @@ z.PdfCryptor = class{
enc = z.Crypto._RC4(ek, enc, this.rc4inf); enc = z.Crypto._RC4(ek, enc, this.rc4inf);
} }
enc += String.fromCharCode(0).repeat(16); enc += String.fromCharCode(0).repeat(16);
return enc.substr(0, 32); ret = enc.substr(0, 32);
}else if(this.mode == z.Crypto.Mode.AES_256){ }else if(this.mode == z.Crypto.Mode.AES_256){
/** @type {string} */
var seed = z.Crypto._md5_16(z.Crypto.getRandomSeed()); var seed = z.Crypto._md5_16(z.Crypto.getRandomSeed());
// User Validation Salt // User Validation Salt
/** @type {string} */
this.UVS = seed.substr(0, 8); this.UVS = seed.substr(0, 8);
// User Key Salt // User Key Salt
/** @type {string} */
this.UKS = seed.substr(8, 16); this.UKS = seed.substr(8, 16);
/** @type {forge.md.digest} */
var md = forge.md.sha256.create(); var md = forge.md.sha256.create();
md.update(this.userpwd + this.UVS); md.update(this.userpwd + this.UVS);
return md.digest().getBytes() + this.UVS + this.UKS; ret = md.digest().getBytes() + this.UVS + this.UKS;
} }
return ret;
} }
/** /**
@ -675,6 +727,7 @@ z.PdfCryptor = class{
* @return {string} UE value * @return {string} UE value
*/ */
_UEvalue(){ _UEvalue(){
/** @type {forge.md.digest} */
var md = forge.md.sha256.create(); var md = forge.md.sha256.create();
md.update(this.userpwd + this.UKS); md.update(this.userpwd + this.UKS);
return z.Crypto._AESnopad(md.digest().getBytes(), this.key); return z.Crypto._AESnopad(md.digest().getBytes(), this.key);
@ -686,37 +739,47 @@ z.PdfCryptor = class{
* @return {string} O value * @return {string} O value
*/ */
_Ovalue(){ _Ovalue(){
/** @type {string} */
var ret = "";
if(this.mode < z.Crypto.Mode.AES_256){ // RC4-40, RC4-128, AES-128 if(this.mode < z.Crypto.Mode.AES_256){ // RC4-40, RC4-128, AES-128
/** @type {string} */
var tmp = z.Crypto._md5_16(this.ownerpwd); var tmp = z.Crypto._md5_16(this.ownerpwd);
if(this.mode > z.Crypto.Mode.RC4_40){ if(this.mode > z.Crypto.Mode.RC4_40){
for(var i=0; i<50; i++){ for(var i=0; i<50; i++){
tmp = z.Crypto._md5_16(tmp); tmp = z.Crypto._md5_16(tmp);
} }
} }
/** @type {string} */
var owner_key = tmp.substr(0, this.Length / 8); var owner_key = tmp.substr(0, this.Length / 8);
var enc = z.Crypto._RC4(owner_key, this.userpwd, this.rc4inf); ret = z.Crypto._RC4(owner_key, this.userpwd, this.rc4inf);
if(this.mode > z.Crypto.Mode.RC4_40){ if(this.mode > z.Crypto.Mode.RC4_40){
/** @type {number} */
var len = owner_key.length; var len = owner_key.length;
for(var i=1; i<=19; i++){ for(var i=1; i<=19; i++){
/** @type {string} */
var ek = ""; var ek = "";
for(var j=0; j<len; j++){ for(var j=0; j<len; j++){
ek += String.fromCharCode(owner_key.charCodeAt(j) ^ i); ek += String.fromCharCode(owner_key.charCodeAt(j) ^ i);
} }
enc = z.Crypto._RC4(ek, enc, this.rc4inf); ret = z.Crypto._RC4(ek, ret, this.rc4inf);
} }
} }
return enc;
}else if(this.mode == z.Crypto.Mode.AES_256){ }else if(this.mode == z.Crypto.Mode.AES_256){
/** @type {string} */
var seed = z.Crypto._md5_16(z.Crypto.getRandomSeed()); var seed = z.Crypto._md5_16(z.Crypto.getRandomSeed());
// Owner Validation Salt // Owner Validation Salt
/** @type {string} */
this.OVS = seed.substr(0, 8); this.OVS = seed.substr(0, 8);
// Owner Key Salt // Owner Key Salt
/** @type {string} */
this.OKS = seed.substr(8, 16); this.OKS = seed.substr(8, 16);
/** @type {forge.md.digest} */
var md = forge.md.sha256.create(); var md = forge.md.sha256.create();
md.update(this.ownerpwd + this.OVS + this.U); md.update(this.ownerpwd + this.OVS + this.U);
return md.digest().getBytes() + this.OVS + this.OKS; ret = md.digest().getBytes() + this.OVS + this.OKS;
} }
return ret;
} }
/** /**
@ -725,6 +788,7 @@ z.PdfCryptor = class{
* @return {string} OE value * @return {string} OE value
*/ */
_OEvalue(){ _OEvalue(){
/** @type {forge.md.digest} */
var md = forge.md.sha256.create(); var md = forge.md.sha256.create();
md.update(this.ownerpwd + this.OKS + this.U); md.update(this.ownerpwd + this.OKS + this.U);
return z.Crypto._AESnopad(md.digest().getBytes(), this.key); return z.Crypto._AESnopad(md.digest().getBytes(), this.key);
@ -745,11 +809,13 @@ z.PdfCryptor = class{
* @private * @private
*/ */
_generateencryptionkey(){ _generateencryptionkey(){
/** @type {number} */
var keybytelen = this.Length / 8; var keybytelen = this.Length / 8;
// standard mode // standard mode
if(!this.pubkeys){ if(!this.pubkeys){
if(this.mode == z.Crypto.Mode.AES_256){ if(this.mode == z.Crypto.Mode.AES_256){
// generate 256 bit random key // generate 256 bit random key
/** @type {forge.md.digest} */
var md = forge.md.sha256.create(); var md = forge.md.sha256.create();
md.update(z.Crypto.getRandomSeed()); md.update(z.Crypto.getRandomSeed());
this.key = md.digest().getBytes().substr(0, keybytelen); this.key = md.digest().getBytes().substr(0, keybytelen);
@ -767,6 +833,7 @@ z.PdfCryptor = class{
// Compute P value // Compute P value
this.P = this.protection; this.P = this.protection;
// Computing the encryption dictionary's Perms (permissions) value // Computing the encryption dictionary's Perms (permissions) value
/** @type {string} */
var perms = z.Crypto.getEncPermissionsString(this.protection); // bytes 0-3 var perms = z.Crypto.getEncPermissionsString(this.protection); // bytes 0-3
perms += String.fromCharCode(255).repeat(4); // bytes 4-7 perms += String.fromCharCode(255).repeat(4); // bytes 4-7
if(typeof this.CF.EncryptMetadata == "boolean" && !this.CF.EncryptMetadata){ // byte 8 if(typeof this.CF.EncryptMetadata == "boolean" && !this.CF.EncryptMetadata){ // byte 8
@ -784,8 +851,10 @@ z.PdfCryptor = class{
// Compute O value // Compute O value
this.O = this._Ovalue(); this.O = this._Ovalue();
// get default permissions (reverse byte order) // get default permissions (reverse byte order)
/** @type {string} */
var permissions = z.Crypto.getEncPermissionsString(this.protection); var permissions = z.Crypto.getEncPermissionsString(this.protection);
// Compute encryption key // Compute encryption key
/** @type {string} */
var tmp = z.Crypto._md5_16(this.userpwd + this.O + permissions + this.fileid); var tmp = z.Crypto._md5_16(this.userpwd + this.O + permissions + this.fileid);
if(this.mode > z.Crypto.Mode.RC4_40) { if(this.mode > z.Crypto.Mode.RC4_40) {
for(var i=0; i<50; i++){ for(var i=0; i<50; i++){

View File

@ -18,7 +18,6 @@ z.TSAURLS = {
z.PdfSigner = class{ z.PdfSigner = class{
/** /**
* @constructor
* @param {SignOption} signopt * @param {SignOption} signopt
*/ */
constructor(signopt){ constructor(signopt){
@ -26,7 +25,7 @@ z.PdfSigner = class{
this.DEFAULT_BYTE_RANGE_PLACEHOLDER = "**********"; this.DEFAULT_BYTE_RANGE_PLACEHOLDER = "**********";
/** @private @type {SignOption} */ /** @private @type {SignOption} */
this.opt = signopt; this.opt = signopt;
/** @private @type {TsaServiceInfo} */ /** @private @type {?TsaServiceInfo} */
this.tsainf = null; this.tsainf = null;
/** @private @type {number} */ /** @private @type {number} */
this.siglen = 0; this.siglen = 0;
@ -47,7 +46,7 @@ z.PdfSigner = class{
url: signopt.signdate, url: signopt.signdate,
}; };
}else if(signopt.signdate.url){ }else if(signopt.signdate.url){
this.tsainf = Object.assign({}, signopt.signdate); this.tsainf = /** @type {TsaServiceInfo} */(Object.assign({}, signopt.signdate));
} }
} }
if(this.tsainf){ if(this.tsainf){
@ -150,7 +149,7 @@ z.PdfSigner = class{
* @param {PDFLib.PDFDocument} pdfdoc * @param {PDFLib.PDFDocument} pdfdoc
*/ */
addSignHolder(pdfdoc){ addSignHolder(pdfdoc){
/** @const {VisualSignature} */ /** @const {z.VisualSignature} */
const visign = new z.VisualSignature(this.opt.drawinf); const visign = new z.VisualSignature(this.opt.drawinf);
/** @const {PDFLib.PDFRef} */ /** @const {PDFLib.PDFRef} */
const strmRef = visign.createStream(pdfdoc, this.opt.signame); const strmRef = visign.createStream(pdfdoc, this.opt.signame);
@ -170,7 +169,7 @@ z.PdfSigner = class{
bytrng.push(PDFLib.PDFName.of(this.DEFAULT_BYTE_RANGE_PLACEHOLDER)); bytrng.push(PDFLib.PDFName.of(this.DEFAULT_BYTE_RANGE_PLACEHOLDER));
bytrng.push(PDFLib.PDFName.of(this.DEFAULT_BYTE_RANGE_PLACEHOLDER)); bytrng.push(PDFLib.PDFName.of(this.DEFAULT_BYTE_RANGE_PLACEHOLDER));
this.siglen = this.tsainf ? this.tsainf.len : 3322; this.siglen = /** @type {number} */(this.tsainf ? this.tsainf.len : 3322);
this.sigContents = PDFLib.PDFHexString.of("0".repeat(this.siglen)); this.sigContents = PDFLib.PDFHexString.of("0".repeat(this.siglen));
/** @type {Object<string, *>} */ /** @type {Object<string, *>} */
@ -239,13 +238,13 @@ z.PdfSigner = class{
var istgt = false; var istgt = false;
/** @type {PDFLib.PDFHexString} */ /** @type {PDFLib.PDFHexString} */
var sigContents = null; var sigContents = null;
/** @type {Array<*>} */ /** @type {Array<PdfObjEntry>} */
var objarr = pdfdoc.context.enumerateIndirectObjects(); var objarr = pdfdoc.context.enumerateIndirectObjects();
for(var i=objarr.length - 1; i>= 0; i--){ for(var i=objarr.length - 1; i>= 0; i--){
if(objarr[i][1].dict instanceof Map){ if(objarr[i][1].dict instanceof Map){
/** @type {Iterator} */ /** @type {Iterator<PdfObjEntry>} */
var es = objarr[i][1].dict.entries(); var es = objarr[i][1].dict.entries();
/** @type {IteratorResult} */ /** @type {IIterableResult<PdfObjEntry>} */
var res = es.next(); var res = es.next();
istgt = false; istgt = false;
sigContents = null; sigContents = null;
@ -272,6 +271,7 @@ z.PdfSigner = class{
} }
} }
} }
return null;
} }
/** /**
@ -287,24 +287,35 @@ z.PdfSigner = class{
} }
// Finds ByteRange information within a given PDF Buffer if one exists // Finds ByteRange information within a given PDF Buffer if one exists
/** @type {Array<string>} */
var byteRangeStrings = pdfstr.match(/\/ByteRange\s*\[{1}\s*(?:(?:\d*|\/\*{10})\s+){3}(?:\d+|\/\*{10}){1}\s*]{1}/g); var byteRangeStrings = pdfstr.match(/\/ByteRange\s*\[{1}\s*(?:(?:\d*|\/\*{10})\s+){3}(?:\d+|\/\*{10}){1}\s*]{1}/g);
/** @type {string|undefined} */
var byteRangePlaceholder = byteRangeStrings.find(function(a_str){ var byteRangePlaceholder = byteRangeStrings.find(function(a_str){
return a_str.includes("/"+this.DEFAULT_BYTE_RANGE_PLACEHOLDER); return a_str.includes("/"+this.DEFAULT_BYTE_RANGE_PLACEHOLDER);
}.bind(this)); }.bind(this));
if(!byteRangePlaceholder){ if(!byteRangePlaceholder){
throw new Error("no signature placeholder"); throw new Error("no signature placeholder");
} }
/** @type {number} */
var byteRangePos = pdfstr.indexOf(byteRangePlaceholder); var byteRangePos = pdfstr.indexOf(byteRangePlaceholder);
/** @type {number} */
var byteRangeEnd = byteRangePos + byteRangePlaceholder.length; var byteRangeEnd = byteRangePos + byteRangePlaceholder.length;
/** @type {number} */
var contentsTagPos = pdfstr.indexOf('/Contents ', byteRangeEnd); var contentsTagPos = pdfstr.indexOf('/Contents ', byteRangeEnd);
/** @type {number} */
var placeholderPos = pdfstr.indexOf('<', contentsTagPos); var placeholderPos = pdfstr.indexOf('<', contentsTagPos);
/** @type {number} */
var placeholderEnd = pdfstr.indexOf('>', placeholderPos); var placeholderEnd = pdfstr.indexOf('>', placeholderPos);
/** @type {number} */
var placeholderLengthWithBrackets = placeholderEnd + 1 - placeholderPos; var placeholderLengthWithBrackets = placeholderEnd + 1 - placeholderPos;
/** @type {number} */
var placeholderLength = placeholderLengthWithBrackets - 2; var placeholderLength = placeholderLengthWithBrackets - 2;
/** @type {Array<number>} */
var byteRange = [0, 0, 0, 0]; var byteRange = [0, 0, 0, 0];
byteRange[1] = placeholderPos; byteRange[1] = placeholderPos;
byteRange[2] = byteRange[1] + placeholderLengthWithBrackets; byteRange[2] = byteRange[1] + placeholderLengthWithBrackets;
byteRange[3] = pdfstr.length - byteRange[2]; byteRange[3] = pdfstr.length - byteRange[2];
/** @type {string} */
var actualByteRange = "/ByteRange [" + byteRange.join(" ") +"]"; var actualByteRange = "/ByteRange [" + byteRange.join(" ") +"]";
actualByteRange += ' '.repeat(byteRangePlaceholder.length - actualByteRange.length); actualByteRange += ' '.repeat(byteRangePlaceholder.length - actualByteRange.length);
// Replace the /ByteRange placeholder with the actual ByteRange // Replace the /ByteRange placeholder with the actual ByteRange
@ -316,20 +327,26 @@ z.PdfSigner = class{
this.opt.p12cert = z.u8arrToRaw(new Uint8Array(this.opt.p12cert)); this.opt.p12cert = z.u8arrToRaw(new Uint8Array(this.opt.p12cert));
} }
// Convert Buffer P12 to a forge implementation. // Convert Buffer P12 to a forge implementation.
/** @type {forge.asn1} */
var p12Asn1 = forge.asn1.fromDer(this.opt.p12cert); var p12Asn1 = forge.asn1.fromDer(this.opt.p12cert);
/** @type {forge.pkcs12} */
var p12 = forge.pkcs12.pkcs12FromAsn1(p12Asn1, true, this.opt.pwd); var p12 = forge.pkcs12.pkcs12FromAsn1(p12Asn1, true, this.opt.pwd);
// Extract safe bags by type. // Extract safe bags by type.
// We will need all the certificates and the private key. // We will need all the certificates and the private key.
/** @type {Object<string|number, P12Bag>} */
var certBags = p12.getBags({ var certBags = p12.getBags({
"bagType": forge.pki.oids.certBag, "bagType": forge.pki.oids.certBag,
})[forge.pki.oids.certBag]; })[forge.pki.oids.certBag];
/** @type {Object<string|number, P12Bag>} */
var keyBags = p12.getBags({ var keyBags = p12.getBags({
"bagType": forge.pki.oids.pkcs8ShroudedKeyBag, "bagType": forge.pki.oids.pkcs8ShroudedKeyBag,
})[forge.pki.oids.pkcs8ShroudedKeyBag]; })[forge.pki.oids.pkcs8ShroudedKeyBag];
/** @type {forge_key} */
var privateKey = keyBags[0].key; var privateKey = keyBags[0].key;
// Here comes the actual PKCS#7 signing. // Here comes the actual PKCS#7 signing.
/** @type {forge.pkcs7} */
var p7 = forge.pkcs7.createSignedData(); var p7 = forge.pkcs7.createSignedData();
// Start off by setting the content. // Start off by setting the content.
p7.content = forge.util.createBuffer(pdfstr); p7.content = forge.util.createBuffer(pdfstr);
@ -337,8 +354,11 @@ z.PdfSigner = class{
// Then add all the certificates (-cacerts & -clcerts) // Then add all the certificates (-cacerts & -clcerts)
// Keep track of the last found client certificate. // Keep track of the last found client certificate.
// This will be the public key that will be bundled in the signature. // This will be the public key that will be bundled in the signature.
/** @type {forge_cert} */
var cert = null; var cert = null;
if(certBags){
Object.keys(certBags).forEach(function(a_ele){ Object.keys(certBags).forEach(function(a_ele){
/** @type {forge_cert} */
var a_cert = certBags[a_ele].cert; var a_cert = certBags[a_ele].cert;
p7.addCertificate(a_cert); p7.addCertificate(a_cert);
@ -349,6 +369,7 @@ z.PdfSigner = class{
cert = a_cert; cert = a_cert;
} }
}); });
}
if(cert){ if(cert){
// When converting to asn1, forge will encode the value of issuer to utf8 if the valueTagClass is UTF8. // When converting to asn1, forge will encode the value of issuer to utf8 if the valueTagClass is UTF8.
// But the value load from pfx is already utf8 encoded, so the encoding action will break the final signature. // But the value load from pfx is already utf8 encoded, so the encoding action will break the final signature.
@ -389,6 +410,7 @@ z.PdfSigner = class{
p7.sign({"detached": true}); p7.sign({"detached": true});
if(this.tsainf){ if(this.tsainf){
/** @type {forge.asn1} */
var tsatoken = this.queryTsa(p7.signers[0].signature); var tsatoken = this.queryTsa(p7.signers[0].signature);
p7.signerInfos[0].value[6].value[0].value[1] = forge.asn1.create( p7.signerInfos[0].value[6].value[0].value[1] = forge.asn1.create(
forge.asn1.Class.UNIVERSAL, forge.asn1.Class.UNIVERSAL,
@ -400,6 +422,7 @@ z.PdfSigner = class{
} }
// Check if the PDF has a good enough placeholder to fit the signature. // Check if the PDF has a good enough placeholder to fit the signature.
/** @type {string} */
var sighex = forge.asn1.toDer(p7.toAsn1()).toHex(); var sighex = forge.asn1.toDer(p7.toAsn1()).toHex();
// placeholderLength represents the length of the HEXified symbols but we're // placeholderLength represents the length of the HEXified symbols but we're
// checking the actual lengths. // checking the actual lengths.
@ -425,6 +448,7 @@ z.PdfSigner = class{
*/ */
convToPDFString(str){ convToPDFString(str){
// Check if there is a multi-bytes char in the string. // Check if there is a multi-bytes char in the string.
/** @type {boolean} */
var flg = false; var flg = false;
for(var i=0; i<str.length; i++){ for(var i=0; i<str.length; i++){
if(str.charCodeAt(i) > 0xFF){ if(str.charCodeAt(i) > 0xFF){
@ -441,14 +465,16 @@ z.PdfSigner = class{
/** /**
* @private * @private
* @param {string} signature * @param {string=} signature
* @return {string} * @return {string}
*/ */
genTsrData(signature){ genTsrData(signature){
// Generate SHA256 hash from signature content for TSA // Generate SHA256 hash from signature content for TSA
/** @type {forge.md.digest} */
var md = forge.md.sha256.create(); var md = forge.md.sha256.create();
md.update(signature); md.update(signature);
// Generate TSA request // Generate TSA request
/** @type {forge.asn1} */
var asn1Req = forge.asn1.create( var asn1Req = forge.asn1.create(
forge.asn1.Class.UNIVERSAL, forge.asn1.Class.UNIVERSAL,
forge.asn1.Type.SEQUENCE, forge.asn1.Type.SEQUENCE,
@ -511,19 +537,25 @@ z.PdfSigner = class{
/** /**
* @private * @private
* @param {string} signature * @param {string=} signature
* @return {Object} * @return {forge.asn1}
*/ */
queryTsa(signature){ queryTsa(signature){
/** @type {string} */
var tsr = this.genTsrData(signature); var tsr = this.genTsrData(signature);
/** @type {Uint8Array} */
var tu8s = z.rawToU8arr(tsr); var tu8s = z.rawToU8arr(tsr);
/** @type {UrlFetchParams} */
var options = { var options = {
"method": "POST", "method": "POST",
"headers": {"Content-Type": "application/timestamp-query"}, "headers": {"Content-Type": "application/timestamp-query"},
"payload": tu8s, "payload": tu8s,
}; };
/** @type {GBlob} */
var tblob = UrlFetchApp.fetch(this.tsainf.url, options).getBlob(); var tblob = UrlFetchApp.fetch(this.tsainf.url, options).getBlob();
/** @type {string} */
var tstr = z.u8arrToRaw(new Uint8Array(tblob.getBytes())); var tstr = z.u8arrToRaw(new Uint8Array(tblob.getBytes()));
/** @type {forge.asn1} */
var token = forge.asn1.fromDer(tstr).value[1]; var token = forge.asn1.fromDer(tstr).value[1];
return token; return token;
} }
@ -541,7 +573,6 @@ z.PdfSigner = class{
z.VisualSignature = class{ z.VisualSignature = class{
/** /**
* @constructor
* @param {SignDrawInfo=} drawinf * @param {SignDrawInfo=} drawinf
*/ */
constructor(drawinf){ constructor(drawinf){
@ -549,7 +580,7 @@ z.VisualSignature = class{
this.pgidx = 0; this.pgidx = 0;
/** @private @type {Array<number>} */ /** @private @type {Array<number>} */
this.rect = [0, 0, 0, 0]; this.rect = [0, 0, 0, 0];
/** @private @type {SignDrawInfo} */ /** @private @type {?SignDrawInfo} */
this.drawinf = null; this.drawinf = null;
if(drawinf){ if(drawinf){
@ -598,21 +629,29 @@ z.VisualSignature = class{
}else{ }else{
throw new Error("Page index is overflow to pdf pages."); throw new Error("Page index is overflow to pdf pages.");
} }
/** @type {PDFLib.Rotation} */
var pgrot = page.getRotation(); var pgrot = page.getRotation();
pgrot.angle = PDFLib.toDegrees(pgrot) % 360; pgrot.angle = PDFLib.toDegrees(pgrot) % 360;
pgrot.type = PDFLib.RotationTypes.Degrees; pgrot.type = PDFLib.RotationTypes.Degrees;
/** @type {PdfSize} */
var pgsz = page.getSize(); var pgsz = page.getSize();
/** @type {SignAreaInfo} */
var areainf = this.calcAreaInf(pgsz, pgrot.angle, this.drawinf.area); var areainf = this.calcAreaInf(pgsz, pgrot.angle, this.drawinf.area);
// resources object // resources object
/** @type {Object<string, *>} */
var rscObj = {}; var rscObj = {};
/** @type {Array<PDFLib.PDFOperator>} */ /** @type {Array<PDFLib.PDFOperator>} */
var sigOprs = []; var sigOprs = [];
/** @type {string} */
var imgName = signame ? signame.concat("Img") : "SigImg"; var imgName = signame ? signame.concat("Img") : "SigImg";
/** @type {string} */
var fontName = signame ? signame.concat("Font") : "SigFont"; var fontName = signame ? signame.concat("Font") : "SigFont";
if(this.drawinf.img){ if(this.drawinf.img){
// Get scaled image size // Get scaled image size
/** @type {PdfSize} */
var imgsz = this.drawinf.img.size(); var imgsz = this.drawinf.img.size();
/** @type {number} */
var tmp = areainf.w * imgsz.height / imgsz.width; var tmp = areainf.w * imgsz.height / imgsz.width;
if(tmp <= areainf.h){ if(tmp <= areainf.h){
areainf.h = tmp; areainf.h = tmp;
@ -633,6 +672,7 @@ z.VisualSignature = class{
this.rect = this.calcRect(pgrot.angle, areainf); this.rect = this.calcRect(pgrot.angle, areainf);
/** @type {PDFLib.PDFObject} */
var frmDict = pdfdoc.context.obj({ var frmDict = pdfdoc.context.obj({
"Type": "XObject", "Type": "XObject",
"Subtype": "Form", "Subtype": "Form",
@ -640,6 +680,7 @@ z.VisualSignature = class{
"BBox": [0, 0, areainf.w, areainf.h], "BBox": [0, 0, areainf.w, areainf.h],
"Resources": rscObj, "Resources": rscObj,
}); });
/** @type {PDFLib.PDFContentStream} */
var strm = PDFLib.PDFContentStream.of(frmDict, sigOprs, false); var strm = PDFLib.PDFContentStream.of(frmDict, sigOprs, false);
return pdfdoc.context.register(strm); return pdfdoc.context.register(strm);
} }
@ -648,13 +689,13 @@ z.VisualSignature = class{
* Calculate area informations for drawing signature after rotate * Calculate area informations for drawing signature after rotate
* *
* @private * @private
* @param {Object<string, number>} pgsz // { width, height } * @param {PdfSize} pgsz
* @param {number} angle * @param {number} angle
* @param {SignAreaInfo} visinf * @param {SignAreaInfo} visinf
* @return {SignAreaInfo} * @return {SignAreaInfo}
*/ */
calcAreaInf(pgsz, angle, visinf){ calcAreaInf(pgsz, angle, visinf){
var ret = Object.assign({}, visinf); var ret = /** @type {SignAreaInfo} */(Object.assign({}, visinf));
// Calculate position after rotate // Calculate position after rotate
switch(angle){ switch(angle){
case 90: case 90:
@ -688,6 +729,7 @@ z.VisualSignature = class{
* @return {Array<number>} * @return {Array<number>}
*/ */
calcRect(angle, areainf){ calcRect(angle, areainf){
/** @type {Array<number>} */
var rect = [0, 0, 0, 0]; var rect = [0, 0, 0, 0];
rect[0] = areainf.x; rect[0] = areainf.x;
rect[1] = areainf.y; rect[1] = areainf.y;
@ -719,9 +761,10 @@ z.VisualSignature = class{
* @private * @private
* @param {PDFLib.Rotation} rot * @param {PDFLib.Rotation} rot
* @param {SignAreaInfo} areainf // { x, y, w, h } * @param {SignAreaInfo} areainf // { x, y, w, h }
* @return {Object<string, *>} // { x, y, width, height, rotate, xSkew, ySkew } * @return {PdfDrawimgOption}
*/ */
calcDrawImgInf(rot, areainf){ calcDrawImgInf(rot, areainf){
/** @type {PdfDrawimgOption} */
var ret = { var ret = {
"x": 0, "x": 0,
"y": 0, "y": 0,