Added support to add a signature to a pdf which has already been signed.
parent
5c9ac474b5
commit
22f6628584
|
@ -10,6 +10,7 @@ And I use this name to hope the merits from this application will be dedicated t
|
||||||
* Sign a pdf with an invisible pkcs#7 signature.
|
* 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 with a visible pkcs#7 signature by drawing an image.
|
||||||
* Sign a pdf and set DocMDP(document modification detection and prevention).
|
* 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)
|
||||||
* Sign a pdf with a timestamp from TSA(Time Stamp Authority). (Only in Google Apps Script)
|
* Sign a pdf with a timestamp from TSA(Time Stamp Authority). (Only in Google Apps Script)
|
||||||
* Set password protection to a pdf. Supported algorithms:
|
* Set password protection to a pdf. Supported algorithms:
|
||||||
* 40bit RC4 Encryption
|
* 40bit RC4 Encryption
|
||||||
|
@ -213,7 +214,7 @@ async function protect2(pdf, cert){
|
||||||
var eopt = {
|
var eopt = {
|
||||||
mode: Zga.Crypto.Mode.AES_128,
|
mode: Zga.Crypto.Mode.AES_128,
|
||||||
pubkeys: [{
|
pubkeys: [{
|
||||||
c: Zga.u8arrToRaw(new Uint8Array(cert)),
|
c: cert,
|
||||||
p: ["copy", "modify", "copy-extract", "annot-forms", "fill-forms", "extract", "assemble"],
|
p: ["copy", "modify", "copy-extract", "annot-forms", "fill-forms", "extract", "assemble"],
|
||||||
}],
|
}],
|
||||||
};
|
};
|
||||||
|
|
|
@ -11,6 +11,19 @@ var PdfLoadOptions;
|
||||||
/** @const */
|
/** @const */
|
||||||
var PDFLib = {};
|
var PDFLib = {};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} str
|
||||||
|
* @param {Array<number>} buffer
|
||||||
|
* @param {number} offset
|
||||||
|
* @return {number}
|
||||||
|
*/
|
||||||
|
PDFLib.copyStringIntoBuffer = function(str, buffer, offset){};
|
||||||
|
/**
|
||||||
|
* @param {string|ArrayBuffer|Uint8Array} input
|
||||||
|
* @return {Uint8Array}
|
||||||
|
*/
|
||||||
|
PDFLib.toUint8Array = function(input){};
|
||||||
|
|
||||||
/** @constructor */
|
/** @constructor */
|
||||||
PDFLib.PDFDocument = function(){};
|
PDFLib.PDFDocument = function(){};
|
||||||
/**
|
/**
|
||||||
|
@ -56,6 +69,45 @@ PDFLib.PDFDocument.prototype.catalog;
|
||||||
/** @type {PDFLib.PDFContext} */
|
/** @type {PDFLib.PDFContext} */
|
||||||
PDFLib.PDFDocument.prototype.context;
|
PDFLib.PDFDocument.prototype.context;
|
||||||
|
|
||||||
|
/** @constructor */
|
||||||
|
PDFLib.PDFAcroField = function(){};
|
||||||
|
/**
|
||||||
|
* @returns {PDFLib.PDFString|PDFLib.PDFHexString}
|
||||||
|
*/
|
||||||
|
PDFLib.PDFAcroField.prototype.T = function(){};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @constructor
|
||||||
|
* @extends {PDFLib.PDFAcroField}
|
||||||
|
*/
|
||||||
|
PDFLib.PDFAcroTerminal = function(){};
|
||||||
|
/**
|
||||||
|
* @constructor
|
||||||
|
* @extends {PDFLib.PDFAcroTerminal}
|
||||||
|
*/
|
||||||
|
PDFLib.PDFAcroSignature = function(){};
|
||||||
|
|
||||||
|
/** @constructor */
|
||||||
|
PDFLib.PDFAcroForm = function(){};
|
||||||
|
/**
|
||||||
|
* @typedef
|
||||||
|
* {{
|
||||||
|
* 0: PDFLib.PDFAcroField,
|
||||||
|
* 1: PDFLib.PDFRef,
|
||||||
|
* }}
|
||||||
|
*/
|
||||||
|
var PdfFieldInfo;
|
||||||
|
/**
|
||||||
|
* @return {Array<PdfFieldInfo>}
|
||||||
|
*/
|
||||||
|
PDFLib.PDFAcroForm.prototype.getAllFields = function(){};
|
||||||
|
/**
|
||||||
|
* @param {PDFLib.PDFRef} field
|
||||||
|
*/
|
||||||
|
PDFLib.PDFAcroForm.prototype.addField = function(field){};
|
||||||
|
/** @type {PDFLib.PDFDict} */
|
||||||
|
PDFLib.PDFAcroForm.prototype.dict;
|
||||||
|
|
||||||
/** @constructor */
|
/** @constructor */
|
||||||
PDFLib.PDFCatalog = function(){};
|
PDFLib.PDFCatalog = function(){};
|
||||||
/**
|
/**
|
||||||
|
@ -63,6 +115,14 @@ PDFLib.PDFCatalog = function(){};
|
||||||
* @param {PDFLib.PDFObject} object
|
* @param {PDFLib.PDFObject} object
|
||||||
*/
|
*/
|
||||||
PDFLib.PDFCatalog.prototype.set = function(name, object){};
|
PDFLib.PDFCatalog.prototype.set = function(name, object){};
|
||||||
|
/**
|
||||||
|
* @return {PDFLib.PDFDict}
|
||||||
|
*/
|
||||||
|
PDFLib.PDFCatalog.prototype.AcroForm = function(){};
|
||||||
|
/**
|
||||||
|
* @return {PDFLib.PDFAcroForm}
|
||||||
|
*/
|
||||||
|
PDFLib.PDFCatalog.prototype.getOrCreateAcroForm = function(){};
|
||||||
|
|
||||||
/** @constructor */
|
/** @constructor */
|
||||||
PDFLib.PDFPage = function(){};
|
PDFLib.PDFPage = function(){};
|
||||||
|
@ -87,15 +147,25 @@ var PdfSize;
|
||||||
*/
|
*/
|
||||||
PDFLib.PDFPage.prototype.getSize = function(){};
|
PDFLib.PDFPage.prototype.getSize = function(){};
|
||||||
|
|
||||||
/** @constructor */
|
/**
|
||||||
|
* @constructor
|
||||||
|
* @extends {PDFLib.PDFDict}
|
||||||
|
*/
|
||||||
PDFLib.PDFPageLeaf = function(){};
|
PDFLib.PDFPageLeaf = function(){};
|
||||||
/**
|
/**
|
||||||
* @param {PDFLib.PDFName} name
|
* @param {PDFLib.PDFName} name
|
||||||
* @param {PDFLib.PDFObject} object
|
* @param {PDFLib.PDFObject} object
|
||||||
*/
|
*/
|
||||||
PDFLib.PDFPageLeaf.prototype.set = function(name, object){};
|
PDFLib.PDFPageLeaf.prototype.set = function(name, object){};
|
||||||
|
/**
|
||||||
|
* @return {PDFLib.PDFArray}
|
||||||
|
*/
|
||||||
|
PDFLib.PDFPageLeaf.prototype.Annots = function(){};
|
||||||
|
|
||||||
/** @constructor */
|
/**
|
||||||
|
* @constructor
|
||||||
|
* @extends {PDFLib.PDFObject}
|
||||||
|
*/
|
||||||
PDFLib.PDFRef = function(){};
|
PDFLib.PDFRef = function(){};
|
||||||
/** @type {number} */
|
/** @type {number} */
|
||||||
PDFLib.PDFRef.prototype.objectNumber;
|
PDFLib.PDFRef.prototype.objectNumber;
|
||||||
|
@ -108,7 +178,9 @@ PDFLib.PDFRef.prototype.generationNumber;
|
||||||
*/
|
*/
|
||||||
PDFLib.PDFRef.of = function(objectNumber, generationNumber){};
|
PDFLib.PDFRef.of = function(objectNumber, generationNumber){};
|
||||||
|
|
||||||
/** @constructor */
|
/**
|
||||||
|
* @constructor
|
||||||
|
*/
|
||||||
PDFLib.PDFContext = function(){};
|
PDFLib.PDFContext = function(){};
|
||||||
/**
|
/**
|
||||||
* @typedef
|
* @typedef
|
||||||
|
@ -154,6 +226,12 @@ PDFLib.PDFContext.prototype.obj = function(literal){};
|
||||||
* @return {PDFLib.PDFObject}
|
* @return {PDFLib.PDFObject}
|
||||||
*/
|
*/
|
||||||
PDFLib.PDFContext.prototype.lookup = function(ref){};
|
PDFLib.PDFContext.prototype.lookup = function(ref){};
|
||||||
|
/**
|
||||||
|
* @param {PDFLib.PDFRef} ref
|
||||||
|
* @param {*} typ
|
||||||
|
* @return {PDFLib.PDFObject}
|
||||||
|
*/
|
||||||
|
PDFLib.PDFContext.prototype.lookupMaybe = function(ref, typ){};
|
||||||
|
|
||||||
/** @constructor */
|
/** @constructor */
|
||||||
PDFLib.PDFObject = function(){};
|
PDFLib.PDFObject = function(){};
|
||||||
|
@ -161,12 +239,20 @@ PDFLib.PDFObject = function(){};
|
||||||
PDFLib.PDFObject.prototype.dict;
|
PDFLib.PDFObject.prototype.dict;
|
||||||
/** @type {Array<PDFLib.PDFName>} */
|
/** @type {Array<PDFLib.PDFName>} */
|
||||||
PDFLib.PDFObject.prototype.array;
|
PDFLib.PDFObject.prototype.array;
|
||||||
|
/**
|
||||||
|
* @param {Array<number>} _buffer
|
||||||
|
* @param {number} _offset
|
||||||
|
* @return {number}
|
||||||
|
*/
|
||||||
|
PDFLib.PDFObject.prototype.copyBytesInto = function(_buffer, _offset){};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @constructor
|
* @constructor
|
||||||
* @extends {PDFLib.PDFObject}
|
* @extends {PDFLib.PDFObject}
|
||||||
*/
|
*/
|
||||||
PDFLib.PDFName = function(){};
|
PDFLib.PDFName = function(){};
|
||||||
|
/** @type {PDFLib.PDFName} */
|
||||||
|
PDFLib.PDFName.Annots;
|
||||||
/**
|
/**
|
||||||
* @param {string} value
|
* @param {string} value
|
||||||
* @return {PDFLib.PDFName}
|
* @return {PDFLib.PDFName}
|
||||||
|
@ -176,9 +262,12 @@ PDFLib.PDFName.of = function(value){};
|
||||||
PDFLib.PDFName.prototype.encodedName;
|
PDFLib.PDFName.prototype.encodedName;
|
||||||
/** @type {number} */
|
/** @type {number} */
|
||||||
PDFLib.PDFName.prototype.numberValue;
|
PDFLib.PDFName.prototype.numberValue;
|
||||||
|
/** @return {string} */
|
||||||
|
PDFLib.PDFName.prototype.value = function(){};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @constructor
|
* @constructor
|
||||||
|
* @extends {PDFLib.PDFObject}
|
||||||
* @param {PDFLib.PDFContext} context
|
* @param {PDFLib.PDFContext} context
|
||||||
*/
|
*/
|
||||||
PDFLib.PDFArray = function(context){};
|
PDFLib.PDFArray = function(context){};
|
||||||
|
@ -191,6 +280,10 @@ PDFLib.PDFArray.prototype.push = function(object){};
|
||||||
* @return {PDFLib.PDFObject}
|
* @return {PDFLib.PDFObject}
|
||||||
*/
|
*/
|
||||||
PDFLib.PDFArray.prototype.get = function(idx){};
|
PDFLib.PDFArray.prototype.get = function(idx){};
|
||||||
|
/**
|
||||||
|
* @return {Array<PDFLib.PDFObject>}
|
||||||
|
*/
|
||||||
|
PDFLib.PDFArray.prototype.asArray = function(){};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @constructor
|
* @constructor
|
||||||
|
@ -207,6 +300,10 @@ PDFLib.PDFString.of = function(value){};
|
||||||
* @return {PDFLib.PDFString}
|
* @return {PDFLib.PDFString}
|
||||||
*/
|
*/
|
||||||
PDFLib.PDFString.fromDate = function(value){};
|
PDFLib.PDFString.fromDate = function(value){};
|
||||||
|
/**
|
||||||
|
* @return {string}
|
||||||
|
*/
|
||||||
|
PDFLib.PDFString.prototype.asString = function(){};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @constructor
|
* @constructor
|
||||||
|
@ -223,6 +320,10 @@ PDFLib.PDFHexString.of = function(value){};
|
||||||
* @return {PDFLib.PDFHexString}
|
* @return {PDFLib.PDFHexString}
|
||||||
*/
|
*/
|
||||||
PDFLib.PDFHexString.fromText = function(value){};
|
PDFLib.PDFHexString.fromText = function(value){};
|
||||||
|
/**
|
||||||
|
* @return {string}
|
||||||
|
*/
|
||||||
|
PDFLib.PDFHexString.prototype.decodeText = function(){};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @constructor
|
* @constructor
|
||||||
|
@ -318,9 +419,81 @@ PDFLib.PDFFlateStream.prototype.contentsCache;
|
||||||
*/
|
*/
|
||||||
PDFLib.PDFContentStream = function(){};
|
PDFLib.PDFContentStream = function(){};
|
||||||
/**
|
/**
|
||||||
* @param {PDFLib.PDFObject} dict
|
* @param {PDFLib.PDFDict} dict
|
||||||
* @param {Array<PDFLib.PDFOperator>} operators
|
* @param {Array<PDFLib.PDFOperator>} operators
|
||||||
* @param {boolean=} encode
|
* @param {boolean=} encode
|
||||||
* @return {PDFLib.PDFContentStream}
|
* @return {PDFLib.PDFContentStream}
|
||||||
*/
|
*/
|
||||||
PDFLib.PDFContentStream.of = function(dict, operators, encode){};
|
PDFLib.PDFContentStream.of = function(dict, operators, encode){};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @constructor
|
||||||
|
* @extends {PDFLib.PDFObject}
|
||||||
|
*/
|
||||||
|
PDFLib.PDFCrossRefSection = function(){};
|
||||||
|
/**
|
||||||
|
* @return {PDFLib.PDFCrossRefSection}
|
||||||
|
*/
|
||||||
|
PDFLib.PDFCrossRefSection.create = function(){};
|
||||||
|
/**
|
||||||
|
* @param {PDFLib.PDFRef} ref
|
||||||
|
* @param {number} offset
|
||||||
|
*/
|
||||||
|
PDFLib.PDFCrossRefSection.prototype.addEntry = function (ref, offset){};
|
||||||
|
/**
|
||||||
|
* @constructor
|
||||||
|
* @extends {PDFLib.PDFObject}
|
||||||
|
*/
|
||||||
|
PDFLib.PDFDict = function(){};
|
||||||
|
/**
|
||||||
|
* @param {PDFLib.PDFName} key
|
||||||
|
* @param {PDFLib.PDFObject} value
|
||||||
|
*/
|
||||||
|
PDFLib.PDFDict.prototype.set = function(key, value){};
|
||||||
|
/**
|
||||||
|
* @param {PDFLib.PDFName} key
|
||||||
|
* @param {*} typ
|
||||||
|
* @return {PDFLib.PDFObject}
|
||||||
|
*/
|
||||||
|
PDFLib.PDFDict.prototype.lookupMaybe = function(key, typ){};
|
||||||
|
/**
|
||||||
|
* @param {PDFLib.PDFName} key
|
||||||
|
* @return {PDFLib.PDFObject}
|
||||||
|
*/
|
||||||
|
PDFLib.PDFDict.prototype.lookup = function(key){};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @constructor
|
||||||
|
* @extends {PDFLib.PDFObject}
|
||||||
|
*/
|
||||||
|
PDFLib.PDFWriter = function(){};
|
||||||
|
/**
|
||||||
|
* @param {PDFLib.PDFContext} context
|
||||||
|
* @param {number} objectsPerTick
|
||||||
|
* @return {PDFLib.PDFWriter}
|
||||||
|
*/
|
||||||
|
PDFLib.PDFWriter.forContext = function(context, objectsPerTick){};
|
||||||
|
/**
|
||||||
|
* @return {PDFLib.PDFDict}
|
||||||
|
*/
|
||||||
|
PDFLib.PDFWriter.prototype.createTrailerDict = function(){};
|
||||||
|
/**
|
||||||
|
* @constructor
|
||||||
|
* @extends {PDFLib.PDFObject}
|
||||||
|
*/
|
||||||
|
PDFLib.PDFTrailerDict = function(){};
|
||||||
|
/**
|
||||||
|
* @param {PDFLib.PDFDict} dict
|
||||||
|
* @return {PDFLib.PDFTrailerDict}
|
||||||
|
*/
|
||||||
|
PDFLib.PDFTrailerDict.of = function(dict){};
|
||||||
|
/**
|
||||||
|
* @constructor
|
||||||
|
* @extends {PDFLib.PDFObject}
|
||||||
|
*/
|
||||||
|
PDFLib.PDFTrailer = function(){};
|
||||||
|
/**
|
||||||
|
* @param {number} offset
|
||||||
|
* @return {PDFLib.PDFTrailer}
|
||||||
|
*/
|
||||||
|
PDFLib.PDFTrailer.forLastCrossRefSectionOffset = function(offset){};
|
||||||
|
|
385
zgapdfsigner.js
385
zgapdfsigner.js
|
@ -76,6 +76,8 @@ z.NewRefMap = class extends Map{
|
||||||
this.idx = 0;
|
this.idx = 0;
|
||||||
/** @private @type {PDFLib.PDFContext} */
|
/** @private @type {PDFLib.PDFContext} */
|
||||||
this.pdfcont = null;
|
this.pdfcont = null;
|
||||||
|
/** @private @type {number} */
|
||||||
|
this.oriLastOnum = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -85,28 +87,32 @@ z.NewRefMap = class extends Map{
|
||||||
* @return {PDFLib.PDFRef} If enc is true, the return value is the unique reference reserved for encrypting information.
|
* @return {PDFLib.PDFRef} If enc is true, the return value is the unique reference reserved for encrypting information.
|
||||||
*/
|
*/
|
||||||
reorderPdfRefs(pdfdoc, enc){
|
reorderPdfRefs(pdfdoc, enc){
|
||||||
this.pdfcont = pdfdoc.context;
|
/** @type {z.NewRefMap} */
|
||||||
|
const _this = this;
|
||||||
|
_this.pdfcont = pdfdoc.context;
|
||||||
/** @type {PDFLib.PDFRef} */
|
/** @type {PDFLib.PDFRef} */
|
||||||
var encref = enc ? this.pdfcont.nextRef() : null;
|
var encref = enc ? _this.pdfcont.nextRef() : null;
|
||||||
|
|
||||||
pdfdoc.getPages().forEach(function(/** @type {PDFLib.PDFPage} */a_pg){
|
pdfdoc.getPages().forEach(function(/** @type {PDFLib.PDFPage} */a_pg){
|
||||||
this.addAndFindRelates(a_pg.ref, "Page");
|
_this.addAndFindRelates(a_pg.ref, "Page");
|
||||||
}.bind(this));
|
});
|
||||||
this.addAndFindRelates(this.pdfcont.trailerInfo.Root, "Catalog");
|
_this.addAndFindRelates(_this.pdfcont.trailerInfo.Root, "Catalog");
|
||||||
if(encref){
|
if(encref){
|
||||||
this.addAndFindRelates(encref, "Encrypt");
|
_this.addAndFindRelates(encref, "Encrypt");
|
||||||
}
|
}
|
||||||
this.pdfcont.enumerateIndirectObjects().forEach(function(/** @type {PdfObjEntry} */a_oety){
|
_this.pdfcont.enumerateIndirectObjects().forEach(function(/** @type {PdfObjEntry} */a_oety){
|
||||||
/** @type {string} */
|
/** @type {string} */
|
||||||
var a_tag = a_oety[0].tag;
|
var a_tag = a_oety[0].tag;
|
||||||
/** @type {z.NewRef} */
|
/** @type {z.NewRef} */
|
||||||
var a_new = this.get(a_tag);
|
var a_new = _this.get(a_tag);
|
||||||
if(!a_new){
|
if(!a_new){
|
||||||
a_new = new z.NewRef(a_oety[0], ++this.idx);
|
a_new = new z.NewRef(a_oety[0], ++_this.idx);
|
||||||
this.set(a_tag, a_new);
|
_this.set(a_tag, a_new);
|
||||||
}
|
}
|
||||||
}.bind(this));
|
});
|
||||||
this.changeAll();
|
_this.changeAll();
|
||||||
|
_this.oriLastOnum = _this.pdfcont.largestObjectNumber;
|
||||||
|
_this.pdfcont.largestObjectNumber = _this.idx;
|
||||||
return encref;
|
return encref;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -115,8 +121,10 @@ z.NewRefMap = class extends Map{
|
||||||
*/
|
*/
|
||||||
restoreAll(){
|
restoreAll(){
|
||||||
this.changeAll(true);
|
this.changeAll(true);
|
||||||
|
this.pdfcont.largestObjectNumber = this.oriLastOnum;
|
||||||
this.clear();
|
this.clear();
|
||||||
this.idx = 0;
|
this.idx = 0;
|
||||||
|
this.oriLastOnum = 0;
|
||||||
this.pdfcont = null;
|
this.pdfcont = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -134,7 +142,7 @@ z.NewRefMap = class extends Map{
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @private
|
* @private
|
||||||
* @param {PDFLib.PDFObject|Array|Map} a_val
|
* @param {PDFLib.PDFObject|Array<PDFLib.PDFObject>|Map} a_val
|
||||||
* @param {string=} a_nm
|
* @param {string=} a_nm
|
||||||
*/
|
*/
|
||||||
findRefs(a_val, a_nm){
|
findRefs(a_val, a_nm){
|
||||||
|
@ -200,6 +208,8 @@ z.PdfSigner = class{
|
||||||
constructor(signopt){
|
constructor(signopt){
|
||||||
/** @private @const {string} */
|
/** @private @const {string} */
|
||||||
this.DEFAULT_BYTE_RANGE_PLACEHOLDER = "**********";
|
this.DEFAULT_BYTE_RANGE_PLACEHOLDER = "**********";
|
||||||
|
/** @private @const {number} */
|
||||||
|
this.NEWLINE = 10;
|
||||||
/** @private @type {SignOption} */
|
/** @private @type {SignOption} */
|
||||||
this.opt = signopt;
|
this.opt = signopt;
|
||||||
/** @type {forge_key} */
|
/** @type {forge_key} */
|
||||||
|
@ -214,6 +224,10 @@ z.PdfSigner = class{
|
||||||
this.siglen = 0;
|
this.siglen = 0;
|
||||||
/** @private @type {PDFLib.PDFHexString} */
|
/** @private @type {PDFLib.PDFHexString} */
|
||||||
this.sigContents = null;
|
this.sigContents = null;
|
||||||
|
/** @private @type {Uint8Array} */
|
||||||
|
this.oriU8pdf = null;
|
||||||
|
/** @type {Array<PdfObjEntry>} */
|
||||||
|
this.apobjs = [];
|
||||||
/** @private @type {boolean} */
|
/** @private @type {boolean} */
|
||||||
this.debug = false;
|
this.debug = false;
|
||||||
|
|
||||||
|
@ -263,72 +277,105 @@ z.PdfSigner = class{
|
||||||
throw new Error("ZgaPdfCryptor is not imported.");
|
throw new Error("ZgaPdfCryptor is not imported.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @const {z.PdfSigner} */
|
||||||
|
const _this = this;
|
||||||
/** @type {PDFLib.PDFDocument} */
|
/** @type {PDFLib.PDFDocument} */
|
||||||
var pdfdoc = await z.loadPdf(pdf);
|
var pdfdoc = null;
|
||||||
|
if(pdf.addPage){
|
||||||
|
pdfdoc = /** @type {PDFLib.PDFDocument} */(pdf);
|
||||||
|
}else{
|
||||||
|
if(Array.isArray(pdf)){
|
||||||
|
_this.oriU8pdf = new Uint8Array(pdf);
|
||||||
|
}else{
|
||||||
|
_this.oriU8pdf = PDFLib.toUint8Array(/** @type {(ArrayBuffer|Uint8Array|string)} */(pdf));
|
||||||
|
}
|
||||||
|
pdfdoc = await PDFLib.PDFDocument.load(_this.oriU8pdf);
|
||||||
|
}
|
||||||
|
|
||||||
if(this.opt.drawinf && this.opt.drawinf.imgData && !this.opt.drawinf.img){
|
if(_this.opt.drawinf && _this.opt.drawinf.imgData && !_this.opt.drawinf.img){
|
||||||
/** @type {Uint8Array|ArrayBuffer|string} */
|
/** @type {Uint8Array|ArrayBuffer|string} */
|
||||||
var imgData2 = null;
|
var imgData2 = null;
|
||||||
if(Array.isArray(this.opt.drawinf.imgData)){
|
if(Array.isArray(_this.opt.drawinf.imgData)){
|
||||||
imgData2 = new Uint8Array(this.opt.drawinf.imgData);
|
imgData2 = new Uint8Array(_this.opt.drawinf.imgData);
|
||||||
}else{
|
}else{
|
||||||
imgData2 = this.opt.drawinf.imgData;
|
imgData2 = _this.opt.drawinf.imgData;
|
||||||
}
|
}
|
||||||
if(this.opt.drawinf.imgType == "png"){
|
if(_this.opt.drawinf.imgType == "png"){
|
||||||
this.opt.drawinf.img = await pdfdoc.embedPng(imgData2);
|
_this.opt.drawinf.img = await pdfdoc.embedPng(imgData2);
|
||||||
}else if(this.opt.drawinf.imgType == "jpg"){
|
}else if(_this.opt.drawinf.imgType == "jpg"){
|
||||||
this.opt.drawinf.img = await pdfdoc.embedJpg(imgData2);
|
_this.opt.drawinf.img = await pdfdoc.embedJpg(imgData2);
|
||||||
}else{
|
}else{
|
||||||
throw new Error("Unkown image type. " + this.opt.drawinf.imgType);
|
throw new Error("Unkown image type. " + _this.opt.drawinf.imgType);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @type {PDFLib.PDFRef} */
|
|
||||||
var encref = null;
|
/** @type {boolean} *///append mode or not
|
||||||
if(this.addSignHolder(pdfdoc)){
|
var apmode = _this.addSignHolder(pdfdoc);
|
||||||
// Signature in DocMDP mode may be invalid if the definitions of references are too chaotic
|
await pdfdoc.flush();
|
||||||
// So we make the order of references more neet.
|
_this.log("A signature holder has been added to the pdf.");
|
||||||
await pdfdoc.flush();
|
|
||||||
encref = z.newRefs.reorderPdfRefs(pdfdoc, cypopt ? true : false);
|
|
||||||
}
|
|
||||||
this.log("A signature holder has been added to the pdf.");
|
|
||||||
|
|
||||||
/** @type {forge_cert} */
|
/** @type {forge_cert} */
|
||||||
var cert = this.loadP12cert(this.opt.p12cert, this.opt.pwd);
|
var cert = _this.loadP12cert(_this.opt.p12cert, _this.opt.pwd);
|
||||||
if(cert){
|
if(cert){
|
||||||
z.fixCertAttributes(cert);
|
z.fixCertAttributes(cert);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(cypopt){
|
if(apmode){
|
||||||
if(cypopt.pubkeys){
|
if(_this.oriU8pdf){
|
||||||
if(cypopt.pubkeys.length == 0){
|
_this.log("The pdf has been signed already, so we add a new signature to it.");
|
||||||
cypopt.pubkeys.push({
|
}else{
|
||||||
c: cert,
|
throw new Error("When adding a new signature to a signed pdf, the original literal datas are necessary.");
|
||||||
});
|
}
|
||||||
}else{
|
|
||||||
cypopt.pubkeys.forEach(function(/** @type {PubKeyInfo} */a_pubkey){
|
// Find the changed objects
|
||||||
// If there is no c in the PubKeyInfo, set cert to it.
|
/** @type {PDFLib.PDFDocument} */
|
||||||
if(!a_pubkey.c){
|
var oriPdfdoc = await PDFLib.PDFDocument.load(_this.oriU8pdf);
|
||||||
a_pubkey.c = cert;
|
pdfdoc.context.enumerateIndirectObjects().forEach(function(/** @type {PdfObjEntry} */a_ele){
|
||||||
}
|
/** @type {PDFLib.PDFObject} */
|
||||||
});
|
var a_obj = oriPdfdoc.context.lookup(a_ele[0]);
|
||||||
}
|
if(!(a_obj && _this.isamePdfObject(a_ele[1], a_obj))){
|
||||||
|
_this.apobjs.push(a_ele);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
}else{
|
||||||
|
// If the definitions of references are too chaotic, a signature contains DocMDP or after adding a new signature,
|
||||||
|
// this signature may be invalid. So we make the order of references more neet.
|
||||||
|
/** @type {PDFLib.PDFRef} */
|
||||||
|
var encref = z.newRefs.reorderPdfRefs(pdfdoc, cypopt ? true : false);
|
||||||
|
|
||||||
|
if(cypopt){
|
||||||
|
if(cypopt.pubkeys){
|
||||||
|
if(cypopt.pubkeys.length == 0){
|
||||||
|
cypopt.pubkeys.push({
|
||||||
|
c: cert,
|
||||||
|
});
|
||||||
|
}else{
|
||||||
|
cypopt.pubkeys.forEach(function(/** @type {PubKeyInfo} */a_pubkey){
|
||||||
|
// If there is no c in the PubKeyInfo, set cert to it.
|
||||||
|
if(!a_pubkey.c){
|
||||||
|
a_pubkey.c = cert;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/** @type {Zga.PdfCryptor} */
|
||||||
|
var cypt = new z.PdfCryptor(cypopt);
|
||||||
|
await cypt.encryptPdf(pdfdoc, encref);
|
||||||
|
_this.log("Pdf data has been encrypted.");
|
||||||
}
|
}
|
||||||
/** @type {Zga.PdfCryptor} */
|
|
||||||
var cypt = new z.PdfCryptor(cypopt);
|
|
||||||
await cypt.encryptPdf(pdfdoc, encref);
|
|
||||||
this.log("Pdf data has been encrypted.");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @type {Uint8Array} */
|
/** @type {Uint8Array} */
|
||||||
var ret = await this.saveAndSign(pdfdoc);
|
var ret = await _this.saveAndSign(pdfdoc);
|
||||||
if(!ret){
|
if(!ret){
|
||||||
this.log("Change size of signature's placeholder and retry.");
|
_this.log("Change size of signature's placeholder and retry.");
|
||||||
this.sigContents.value = "0".repeat(this.siglen);
|
_this.sigContents.value = "0".repeat(_this.siglen);
|
||||||
ret = await this.saveAndSign(pdfdoc);
|
ret = await _this.saveAndSign(pdfdoc);
|
||||||
}
|
}
|
||||||
if(ret){
|
if(ret){
|
||||||
this.log("Signing pdf accomplished.");
|
_this.log("Signing pdf accomplished.");
|
||||||
}else{
|
}else{
|
||||||
throw new Error("Failed to sign the pdf.");
|
throw new Error("Failed to sign the pdf.");
|
||||||
}
|
}
|
||||||
|
@ -350,16 +397,158 @@ z.PdfSigner = class{
|
||||||
*/
|
*/
|
||||||
async saveAndSign(pdfdoc){
|
async saveAndSign(pdfdoc){
|
||||||
/** @type {Uint8Array} */
|
/** @type {Uint8Array} */
|
||||||
var uarr = await pdfdoc.save({"useObjectStreams": false});
|
var uarr = null;
|
||||||
|
if(this.apobjs.length > 0){
|
||||||
|
uarr = this.appendSignature(pdfdoc);
|
||||||
|
}else{
|
||||||
|
uarr = await pdfdoc.save({"useObjectStreams": false});
|
||||||
|
}
|
||||||
/** @type {string} */
|
/** @type {string} */
|
||||||
var pdfstr = z.u8arrToRaw(uarr);
|
var pdfstr = z.u8arrToRaw(uarr) + String.fromCharCode(this.NEWLINE);
|
||||||
return this.signPdf(pdfstr);
|
return this.signPdf(pdfstr);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @private
|
* @private
|
||||||
* @param {PDFLib.PDFDocument} pdfdoc
|
* @param {PDFLib.PDFDocument} pdfdoc
|
||||||
* @return {boolean} DocMDP mode or not.
|
* @return {Uint8Array}
|
||||||
|
*/
|
||||||
|
appendSignature(pdfdoc){
|
||||||
|
/** @const {z.PdfSigner} */
|
||||||
|
const _this = this;
|
||||||
|
/** @type {PDFLib.PDFCrossRefSection} */
|
||||||
|
var xref = PDFLib.PDFCrossRefSection.create();
|
||||||
|
/** @type {number} */
|
||||||
|
var stpos = _this.oriU8pdf.length;
|
||||||
|
/** @type {Array<number>} */
|
||||||
|
var buff = [];
|
||||||
|
buff[0] = _this.NEWLINE;
|
||||||
|
stpos++;
|
||||||
|
_this.apobjs.forEach(function(/** @type {PdfObjEntry} */a_ele){
|
||||||
|
/** @type {number} */
|
||||||
|
var a_len = _this.objEntryToBytes(a_ele, buff);
|
||||||
|
xref.addEntry(a_ele[0], stpos);
|
||||||
|
stpos += a_len;
|
||||||
|
});
|
||||||
|
xref.copyBytesInto(buff, buff.length);
|
||||||
|
|
||||||
|
/** @type {PDFLib.PDFDict} */
|
||||||
|
var tdic = PDFLib.PDFWriter.forContext(pdfdoc.context, 0).createTrailerDict();
|
||||||
|
tdic.set(PDFLib.PDFName.of("Prev"), PDFLib.PDFNumber.of(_this.findPrev(_this.oriU8pdf)));
|
||||||
|
/** @type {PDFLib.PDFTrailerDict} */
|
||||||
|
var ptdic = PDFLib.PDFTrailerDict.of(tdic);
|
||||||
|
ptdic.copyBytesInto(buff, buff.length);
|
||||||
|
buff.push(_this.NEWLINE);
|
||||||
|
|
||||||
|
/** @type {PDFLib.PDFTrailer} */
|
||||||
|
var ptlr = PDFLib.PDFTrailer.forLastCrossRefSectionOffset(stpos);
|
||||||
|
ptlr.copyBytesInto(buff, buff.length);
|
||||||
|
/** @type {Uint8Array} */
|
||||||
|
var ret = new Uint8Array(_this.oriU8pdf.length + buff.length);
|
||||||
|
ret.set(/** @type {!ArrayBufferView} */(_this.oriU8pdf));
|
||||||
|
ret.set(/** @type {!ArrayBufferView} */(new Uint8Array(buff)), _this.oriU8pdf.length);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
* @param {Uint8Array} u8pdf
|
||||||
|
* @return {number}
|
||||||
|
*/
|
||||||
|
findPrev(u8pdf){
|
||||||
|
/** @const {Uint8Array} */
|
||||||
|
const eof = Zga.rawToU8arr("%%EOF");
|
||||||
|
/** @const {number} */
|
||||||
|
const c0 = "0".charCodeAt(0);
|
||||||
|
/** @const {number} */
|
||||||
|
const c9 = "9".charCodeAt(0);
|
||||||
|
/** @type {number} */
|
||||||
|
var step = 0;
|
||||||
|
/** @type {string} */
|
||||||
|
var num = "";
|
||||||
|
for(var i = u8pdf.length - eof.length; i >= 0; i--){
|
||||||
|
switch(step){
|
||||||
|
case 0:
|
||||||
|
/** @type {boolean} */
|
||||||
|
var flg = true;
|
||||||
|
for(var j=0; j<eof.length; j++){
|
||||||
|
if(u8pdf[i+j] != eof[j]){
|
||||||
|
flg = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(flg){
|
||||||
|
step = 1;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
if(u8pdf[i] >= c0 && u8pdf[i] <= c9){
|
||||||
|
num = String.fromCharCode(u8pdf[i]);
|
||||||
|
step = 2;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
if(u8pdf[i] >= c0 && u8pdf[i] <= c9){
|
||||||
|
num = String.fromCharCode(u8pdf[i]) + num;
|
||||||
|
}else{
|
||||||
|
step = 9;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if(step >= 9){
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return parseInt(num, 10);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
* @param {PDFLib.PDFObject} obj1
|
||||||
|
* @param {PDFLib.PDFObject} obj2
|
||||||
|
* @return {boolean}
|
||||||
|
*/
|
||||||
|
isamePdfObject(obj1, obj2){
|
||||||
|
/** @type {Array<number>} */
|
||||||
|
var buff1 = [];
|
||||||
|
obj1.copyBytesInto(buff1, 0);
|
||||||
|
/** @type {Array<number>} */
|
||||||
|
var buff2 = [];
|
||||||
|
obj2.copyBytesInto(buff2, 0);
|
||||||
|
if(buff1.length != buff2.length){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
for(var i=0; i<buff1.length; i++){
|
||||||
|
if(buff1[i] != buff2[i]){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
* @param {PdfObjEntry} objety
|
||||||
|
* @param {Array<number>} buff
|
||||||
|
* @return {number}
|
||||||
|
*/
|
||||||
|
objEntryToBytes(objety, buff){
|
||||||
|
/** @type {number} */
|
||||||
|
var before = buff.length;
|
||||||
|
objety[0].copyBytesInto(buff, buff.length);
|
||||||
|
PDFLib.copyStringIntoBuffer("obj", buff, buff.length - 1);
|
||||||
|
buff[buff.length] = this.NEWLINE;
|
||||||
|
objety[1].copyBytesInto(buff, buff.length);
|
||||||
|
buff[buff.length] = this.NEWLINE;
|
||||||
|
PDFLib.copyStringIntoBuffer("endobj", buff, buff.length);
|
||||||
|
buff[buff.length] = this.NEWLINE;
|
||||||
|
return buff.length - before;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
* @param {PDFLib.PDFDocument} pdfdoc
|
||||||
|
* @return {boolean} append mode or not
|
||||||
*/
|
*/
|
||||||
addSignHolder(pdfdoc){
|
addSignHolder(pdfdoc){
|
||||||
/** @const {number} */
|
/** @const {number} */
|
||||||
|
@ -377,6 +566,28 @@ z.PdfSigner = class{
|
||||||
strmRef = signcrt.createEmptyField(pdfcont);
|
strmRef = signcrt.createEmptyField(pdfcont);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @type {Array<string>} */
|
||||||
|
var oldSigs = [];
|
||||||
|
/** @type {PDFLib.PDFAcroForm} */
|
||||||
|
var afrm = pdfdoc.catalog.getOrCreateAcroForm();
|
||||||
|
afrm.getAllFields().forEach(function(/** @type {PdfFieldInfo} */a_finf){
|
||||||
|
if(a_finf[0] instanceof PDFLib.PDFAcroSignature){
|
||||||
|
/** @type {PDFLib.PDFString|PDFLib.PDFHexString} */
|
||||||
|
var a_t = a_finf[0].T();
|
||||||
|
if(a_t instanceof PDFLib.PDFString){
|
||||||
|
oldSigs.push(a_t.asString());
|
||||||
|
}else if(a_t instanceof PDFLib.PDFHexString){
|
||||||
|
oldSigs.push(a_t.decodeText());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if(oldSigs.length > 0 && docMdp){
|
||||||
|
throw new Error("Since the pdf has been signed, can NOT sign with DocMDP. Because the signature field that contains DocMDP must be the first signed field in the document.");
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @type {string} */
|
||||||
|
var signm = this.fixSigName(oldSigs, this.opt.signame);
|
||||||
|
|
||||||
/** @type {Date} */
|
/** @type {Date} */
|
||||||
var signdate = new Date();
|
var signdate = new Date();
|
||||||
if(this.opt.signdate instanceof Date && !this.tsainf){
|
if(this.opt.signdate instanceof Date && !this.tsainf){
|
||||||
|
@ -440,7 +651,7 @@ z.PdfSigner = class{
|
||||||
"FT": "Sig",
|
"FT": "Sig",
|
||||||
"Rect": signcrt.getSignRect(),
|
"Rect": signcrt.getSignRect(),
|
||||||
"V": signatureDictRef,
|
"V": signatureDictRef,
|
||||||
"T": this.convToPDFString(this.opt.signame ? this.opt.signame : "Signature1"),
|
"T": this.convToPDFString(signm),
|
||||||
"F": 132,
|
"F": 132,
|
||||||
"P": page.ref,
|
"P": page.ref,
|
||||||
};
|
};
|
||||||
|
@ -453,16 +664,19 @@ z.PdfSigner = class{
|
||||||
var widgetDictRef = pdfcont.register(pdfcont.obj(widgetObj));
|
var widgetDictRef = pdfcont.register(pdfcont.obj(widgetObj));
|
||||||
|
|
||||||
// Add our signature widget to the page
|
// Add our signature widget to the page
|
||||||
page.node.set(PDFLib.PDFName.of("Annots"), pdfcont.obj([widgetDictRef]));
|
/** @type {PDFLib.PDFArray} */
|
||||||
|
var ans = page.node.Annots();
|
||||||
|
if(!ans){
|
||||||
|
ans = new PDFLib.PDFArray(pdfcont);
|
||||||
|
page.node.set(PDFLib.PDFName.Annots, ans);
|
||||||
|
}
|
||||||
|
ans.push(widgetDictRef);
|
||||||
|
|
||||||
|
if(!afrm.dict.lookup(PDFLib.PDFName.of("SigFlags"))){
|
||||||
|
afrm.dict.set(PDFLib.PDFName.of("SigFlags"), PDFLib.PDFNumber.of(3));
|
||||||
|
}
|
||||||
|
afrm.addField(widgetDictRef);
|
||||||
|
|
||||||
// Create an AcroForm object containing our signature widget
|
|
||||||
pdfdoc.catalog.set(
|
|
||||||
PDFLib.PDFName.of("AcroForm"),
|
|
||||||
pdfcont.obj({
|
|
||||||
"SigFlags": 3,
|
|
||||||
"Fields": [widgetDictRef],
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
if(docMdp){
|
if(docMdp){
|
||||||
pdfdoc.catalog.set(
|
pdfdoc.catalog.set(
|
||||||
PDFLib.PDFName.of("Perms"),
|
PDFLib.PDFName.of("Perms"),
|
||||||
|
@ -470,10 +684,34 @@ z.PdfSigner = class{
|
||||||
"DocMDP": signatureDictRef,
|
"DocMDP": signatureDictRef,
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
return true;
|
}
|
||||||
|
|
||||||
|
return (oldSigs.length > 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
* @param {Array<string>} oldSigs
|
||||||
|
* @param {string=} signm
|
||||||
|
* @param {number=} idx
|
||||||
|
* @return {string}
|
||||||
|
*/
|
||||||
|
fixSigName(oldSigs, signm, idx){
|
||||||
|
if(!signm){
|
||||||
|
signm = "Signature";
|
||||||
|
idx = 1;
|
||||||
|
}
|
||||||
|
/** @type {string} */
|
||||||
|
var nm = signm;
|
||||||
|
if(idx){
|
||||||
|
nm += idx;
|
||||||
}else{
|
}else{
|
||||||
return false;
|
idx = 0;
|
||||||
|
}
|
||||||
|
if(oldSigs.indexOf(nm) >= 0){
|
||||||
|
return this.fixSigName(oldSigs, signm, idx+1);
|
||||||
|
}else{
|
||||||
|
return nm;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -895,14 +1133,13 @@ z.SignatureCreator = class{
|
||||||
|
|
||||||
this.rect = this.calcRect(pgrot.angle, areainf);
|
this.rect = this.calcRect(pgrot.angle, areainf);
|
||||||
|
|
||||||
/** @type {PDFLib.PDFObject} */
|
var frmDict = /** @type {PDFLib.PDFDict} */(pdfdoc.context.obj({
|
||||||
var frmDict = pdfdoc.context.obj({
|
|
||||||
"Type": "XObject",
|
"Type": "XObject",
|
||||||
"Subtype": "Form",
|
"Subtype": "Form",
|
||||||
"FormType": 1,
|
"FormType": 1,
|
||||||
"BBox": [0, 0, areainf.w, areainf.h],
|
"BBox": [0, 0, areainf.w, areainf.h],
|
||||||
"Resources": rscObj,
|
"Resources": rscObj,
|
||||||
});
|
}));
|
||||||
/** @type {PDFLib.PDFContentStream} */
|
/** @type {PDFLib.PDFContentStream} */
|
||||||
var strm = PDFLib.PDFContentStream.of(frmDict, sigOprs, true);
|
var strm = PDFLib.PDFContentStream.of(frmDict, sigOprs, true);
|
||||||
return pdfdoc.context.register(strm);
|
return pdfdoc.context.register(strm);
|
||||||
|
|
Loading…
Reference in New Issue