2022-11-14 14:20:19 +01:00
'use strict' ;
2022-10-02 14:45:06 +02:00
/ * *
* @ param { Object < string , * > } z
* /
function supplyZgaSigner ( z ) {
2022-09-18 09:49:56 +02:00
2022-11-06 10:03:48 +01:00
//Only for nodejs Start//
if ( z . forge ) {
var forge = z . forge ;
}
if ( z . PDFLib ) {
var PDFLib = z . PDFLib ;
}
//Only for nodejs End//
2022-09-24 06:59:30 +02:00
/** @type {Object<string, TsaServiceInfo>} */
2022-10-02 14:45:06 +02:00
z . TSAURLS = {
2022-11-06 10:03:48 +01:00
"1" : { url : "http://ts.ssl.com" , len : 12100 } ,
"2" : { url : "http://timestamp.digicert.com" , len : 11900 } ,
"3" : { url : "http://timestamp.sectigo.com" , len : 9900 } ,
"4" : { url : "http://timestamp.entrust.net/TSS/RFC3161sha2TS" , len : 10850 } ,
"5" : { url : "http://timestamp.apple.com/ts01" , len : 8600 } ,
"6" : { url : "http://www.langedge.jp/tsa" , len : 5700 } ,
"7" : { url : "https://freetsa.org/tsr" , len : 11000 } ,
2022-10-02 14:45:06 +02:00
} ;
2022-10-14 14:12:43 +02:00
z . NewRef = class {
/ * *
* @ param { PDFLib . PDFRef } ref
* @ param { number = } num
* @ param { string = } nm
* /
constructor ( ref , num , nm ) {
/** @private @type {number} */
this . oriNumber = ref . objectNumber ;
/** @private @type {number} */
this . oriGeneration = ref . generationNumber ;
/** @private @type {string} */
this . name = nm ? nm : "" ;
/** @private @type {number} */
this . newNumber = num ? num : 0 ;
}
/ * *
* @ public
* @ param { number } num
* /
setNewNumber ( num ) {
this . newNumber = num ;
}
/ * *
* @ public
* @ param { boolean = } restore
* /
changeNumber ( restore ) {
if ( ! this . newNumber ) {
if ( restore ) {
return ;
} else {
throw new Error ( "Can NOT change number since new number is not set." ) ;
}
}
/** @type {PDFLib.PDFRef} */
var ref = PDFLib . PDFRef . of ( this . oriNumber , this . oriGeneration ) ;
ref . objectNumber = restore ? this . oriNumber : this . newNumber ;
ref . tag = ref . objectNumber + " " + this . oriGeneration + " R" ;
}
/ * *
* @ public
* @ return { string }
* /
toString ( ) {
return this . name + " -> old:" + this . oriNumber + ", new:" + this . newNumber ;
}
} ;
z . NewRefMap = class extends Map {
constructor ( ) {
super ( ) ;
/** @private @type {number} */
this . idx = 0 ;
/** @private @type {PDFLib.PDFContext} */
this . pdfcont = null ;
2022-10-20 14:28:27 +02:00
/** @private @type {number} */
this . oriLastOnum = 0 ;
2022-10-14 14:12:43 +02:00
}
/ * *
* @ public
* @ param { PDFLib . PDFDocument } pdfdoc
* @ param { boolean = } enc
* @ return { PDFLib . PDFRef } If enc is true , the return value is the unique reference reserved for encrypting information .
* /
reorderPdfRefs ( pdfdoc , enc ) {
2022-10-20 14:28:27 +02:00
/** @type {z.NewRefMap} */
const _this = this ;
_this . pdfcont = pdfdoc . context ;
2022-10-14 14:12:43 +02:00
/** @type {PDFLib.PDFRef} */
2022-10-20 14:28:27 +02:00
var encref = enc ? _this . pdfcont . nextRef ( ) : null ;
2022-10-14 14:12:43 +02:00
pdfdoc . getPages ( ) . forEach ( function ( /** @type {PDFLib.PDFPage} */ a _pg ) {
2022-10-20 14:28:27 +02:00
_this . addAndFindRelates ( a _pg . ref , "Page" ) ;
} ) ;
_this . addAndFindRelates ( _this . pdfcont . trailerInfo . Root , "Catalog" ) ;
2022-10-14 14:12:43 +02:00
if ( encref ) {
2022-10-20 14:28:27 +02:00
_this . addAndFindRelates ( encref , "Encrypt" ) ;
2022-10-14 14:12:43 +02:00
}
2022-10-20 14:28:27 +02:00
_this . pdfcont . enumerateIndirectObjects ( ) . forEach ( function ( /** @type {PdfObjEntry} */ a _oety ) {
2022-10-14 14:12:43 +02:00
/** @type {string} */
var a _tag = a _oety [ 0 ] . tag ;
/** @type {z.NewRef} */
2022-10-20 14:28:27 +02:00
var a _new = _this . get ( a _tag ) ;
2022-10-14 14:12:43 +02:00
if ( ! a _new ) {
2022-10-20 14:28:27 +02:00
a _new = new z . NewRef ( a _oety [ 0 ] , ++ _this . idx ) ;
_this . set ( a _tag , a _new ) ;
2022-10-14 14:12:43 +02:00
}
2022-10-20 14:28:27 +02:00
} ) ;
_this . changeAll ( ) ;
_this . oriLastOnum = _this . pdfcont . largestObjectNumber ;
_this . pdfcont . largestObjectNumber = _this . idx ;
2022-10-14 14:12:43 +02:00
return encref ;
}
/ * *
* @ public
* /
restoreAll ( ) {
2022-10-15 15:06:13 +02:00
this . changeAll ( true ) ;
2022-10-20 14:28:27 +02:00
this . pdfcont . largestObjectNumber = this . oriLastOnum ;
2022-10-14 14:12:43 +02:00
this . clear ( ) ;
this . idx = 0 ;
2022-10-20 14:28:27 +02:00
this . oriLastOnum = 0 ;
2022-10-14 14:12:43 +02:00
this . pdfcont = null ;
}
/ * *
* @ private
* @ param { PDFLib . PDFRef } a _ref
* @ param { string = } a _nm
* /
addAndFindRelates ( a _ref , a _nm ) {
if ( ! this . get ( a _ref . tag ) ) {
this . set ( a _ref . tag , new z . NewRef ( a _ref , ++ this . idx , a _nm ) ) ;
this . findRefs ( this . pdfcont . lookup ( a _ref ) , a _nm ) ;
}
}
/ * *
* @ private
2022-10-20 14:28:27 +02:00
* @ param { PDFLib . PDFObject | Array < PDFLib . PDFObject > | Map } a _val
2022-10-14 14:12:43 +02:00
* @ param { string = } a _nm
* /
findRefs ( a _val , a _nm ) {
if ( ! a _val || a _nm == "/Parent" ) {
return ;
}
if ( a _val instanceof PDFLib . PDFRef ) {
this . addAndFindRelates ( a _val , a _nm ) ;
return ;
}
if ( a _val . array ) {
a _val = a _val . array ;
}
if ( Array . isArray ( a _val ) ) {
a _val . forEach ( function ( /** @type {PDFLib.PDFObject} */ b _val ) {
this . findRefs ( b _val , a _nm ) ;
} . bind ( this ) ) ;
return ;
}
if ( a _val instanceof PDFLib . PDFPage ) {
a _val = a _val . node ;
}
while ( a _val . dict && ! ( a _val instanceof Map ) ) {
a _val = a _val . dict ;
}
if ( a _val instanceof Map ) {
/** @type {Iterator} */
var a _es = a _val . entries ( ) ;
/** @type {IIterableResult<PdfObjEntry>} */
var a _result = a _es . next ( ) ;
while ( ! a _result . done ) {
this . findRefs ( a _result . value [ 1 ] , a _result . value [ 0 ] . encodedName ) ;
a _result = a _es . next ( ) ;
}
return ;
}
}
2022-10-15 15:06:13 +02:00
/ * *
* @ private
* @ param { boolean = } restore
* /
changeAll ( restore ) {
/** @type {Iterator} */
var es = this . entries ( ) ;
/** @type {IIterableResult} */
var result = es . next ( ) ;
while ( ! result . done ) {
result . value [ 1 ] . changeNumber ( restore ) ;
result = es . next ( ) ;
}
}
2022-10-14 14:12:43 +02:00
} ;
/** @type {z.NewRefMap<string, z.NewRef>} */
z . newRefs = new z . NewRefMap ( ) ;
2022-10-02 14:45:06 +02:00
z . PdfSigner = class {
2022-09-17 14:55:09 +02:00
/ * *
* @ param { SignOption } signopt
* /
constructor ( signopt ) {
2022-11-06 10:03:48 +01:00
/** @public @type {Zga.TsaFetcher} */
this . tsaFetcher = null ;
2022-11-14 14:20:19 +01:00
/** @public @type {Zga.PdfCryptor} */
this . cyptr = null ;
2022-11-06 10:03:48 +01:00
2022-10-02 14:45:06 +02:00
/** @private @const {string} */
this . DEFAULT _BYTE _RANGE _PLACEHOLDER = "**********" ;
2022-10-20 14:28:27 +02:00
/** @private @const {number} */
this . NEWLINE = 10 ;
2022-09-17 14:55:09 +02:00
/** @private @type {SignOption} */
this . opt = signopt ;
2022-10-06 15:02:11 +02:00
/** @type {forge_key} */
this . privateKey = null ;
2022-11-06 10:03:48 +01:00
/** @type {Zga.CertsChain} */
this . cchain = null ;
/** @private @type {string} */
this . signature = "" ;
2022-10-02 14:45:06 +02:00
/** @private @type {number} */
this . siglen = 0 ;
/** @private @type {PDFLib.PDFHexString} */
this . sigContents = null ;
2022-10-20 14:28:27 +02:00
/** @private @type {Uint8Array} */
this . oriU8pdf = null ;
2022-11-06 10:03:48 +01:00
/** @private @type {Array<PdfObjEntry>} */
this . apobjs = null ;
2022-09-24 06:59:30 +02:00
2022-11-06 10:03:48 +01:00
if ( typeof this . opt . debug == "boolean" ) {
z . debug = this . opt . debug ;
} else if ( globalThis . debug ) {
z . debug = true ;
}
if ( ! ( globalThis . PDFLib || PDFLib ) ) {
2022-09-24 06:59:30 +02:00
throw new Error ( "pdf-lib is not imported." ) ;
}
2022-11-06 10:03:48 +01:00
if ( ! ( globalThis . forge || forge ) ) {
2022-09-24 06:59:30 +02:00
throw new Error ( "node-forge is not imported." ) ;
}
2022-11-14 14:20:19 +01:00
/** @type {?TsaServiceInfo} */
var tsainf = null ;
2022-09-24 06:59:30 +02:00
if ( signopt . signdate ) {
if ( typeof signopt . signdate == "string" ) {
2022-11-14 14:20:19 +01:00
tsainf = {
2022-09-24 06:59:30 +02:00
url : signopt . signdate ,
} ;
} else if ( signopt . signdate . url ) {
2022-11-14 14:20:19 +01:00
tsainf = /** @type {TsaServiceInfo} */ ( Object . assign ( { } , signopt . signdate ) ) ;
2022-09-24 06:59:30 +02:00
}
}
2022-11-14 14:20:19 +01:00
if ( tsainf ) {
2022-10-24 14:36:47 +02:00
if ( ! z . urlFetch ) {
2022-09-24 06:59:30 +02:00
throw new Error ( "Because of the CORS security restrictions, signing with TSA is not supported in web browser." ) ;
}
2022-11-14 14:20:19 +01:00
if ( z . TSAURLS [ tsainf . url ] ) {
Object . assign ( tsainf , z . TSAURLS [ tsainf . url ] ) ;
} else if ( ! ( new RegExp ( "^https?://" ) ) . test ( tsainf . url ) ) {
throw new Error ( "Unknown tsa data. " + JSON . stringify ( tsainf ) ) ;
2022-09-24 06:59:30 +02:00
}
2022-11-14 14:20:19 +01:00
if ( ! tsainf . len ) {
tsainf . len = 16000 ;
2022-09-24 06:59:30 +02:00
}
2022-11-14 14:20:19 +01:00
this . tsaFetcher = new z . TsaFetcher ( /** @type {TsaServiceInfo} */ ( tsainf ) ) ;
2022-09-24 06:59:30 +02:00
}
2022-11-06 10:03:48 +01:00
if ( signopt . ltv && ! z . urlFetch ) {
throw new Error ( "Because of the CORS security restrictions, signing with LTV is not supported in web browser." ) ;
}
2022-11-14 14:20:19 +01:00
// if(signopt.permission == 1 && signopt.ltv){
// z.log("To enable LTV we need to append informations after signing, this will destroy the signature if full DocMDP protection is set. (Sign with permission = 1)");
// throw new Error("When set full DocMDP protection, LTV can't be enabled.");
// }
2022-09-17 14:55:09 +02:00
}
/ * *
* @ public
2022-09-24 06:59:30 +02:00
* @ param { PDFLib . PDFDocument | Array < number > | Uint8Array | ArrayBuffer | string } pdf
2022-10-02 14:45:06 +02:00
* @ param { EncryptOption = } cypopt
2022-09-18 09:49:56 +02:00
* @ return { Promise < Uint8Array > }
2022-09-17 14:55:09 +02:00
* /
2022-10-02 14:45:06 +02:00
async sign ( pdf , cypopt ) {
if ( cypopt && ! z . PdfCryptor ) {
throw new Error ( "ZgaPdfCryptor is not imported." ) ;
2022-09-17 14:55:09 +02:00
}
2022-10-20 14:28:27 +02:00
/** @const {z.PdfSigner} */
const _this = this ;
2022-10-02 14:45:06 +02:00
/** @type {PDFLib.PDFDocument} */
2022-10-20 14:28:27 +02:00
var pdfdoc = null ;
if ( pdf . addPage ) {
pdfdoc = /** @type {PDFLib.PDFDocument} */ ( pdf ) ;
} else {
if ( Array . isArray ( pdf ) ) {
_this . oriU8pdf = new Uint8Array ( pdf ) ;
} else {
2022-11-14 14:20:19 +01:00
_this . oriU8pdf = PDFLib . toUint8Array ( /** @type {ArrayBuffer|Uint8Array|string} */ ( pdf ) ) ;
2022-10-20 14:28:27 +02:00
}
pdfdoc = await PDFLib . PDFDocument . load ( _this . oriU8pdf ) ;
}
2022-10-02 14:45:06 +02:00
2022-10-20 14:28:27 +02:00
if ( _this . opt . drawinf && _this . opt . drawinf . imgData && ! _this . opt . drawinf . img ) {
2022-09-24 06:59:30 +02:00
/** @type {Uint8Array|ArrayBuffer|string} */
var imgData2 = null ;
2022-10-20 14:28:27 +02:00
if ( Array . isArray ( _this . opt . drawinf . imgData ) ) {
imgData2 = new Uint8Array ( _this . opt . drawinf . imgData ) ;
2022-09-24 06:59:30 +02:00
} else {
2022-10-20 14:28:27 +02:00
imgData2 = _this . opt . drawinf . imgData ;
2022-09-24 06:59:30 +02:00
}
2022-10-20 14:28:27 +02:00
if ( _this . opt . drawinf . imgType == "png" ) {
_this . opt . drawinf . img = await pdfdoc . embedPng ( imgData2 ) ;
} else if ( _this . opt . drawinf . imgType == "jpg" ) {
_this . opt . drawinf . img = await pdfdoc . embedJpg ( imgData2 ) ;
2022-09-17 14:55:09 +02:00
} else {
2022-10-20 14:28:27 +02:00
throw new Error ( "Unkown image type. " + _this . opt . drawinf . imgType ) ;
2022-09-17 14:55:09 +02:00
}
}
2022-10-06 15:02:11 +02:00
/** @type {forge_cert} */
2022-10-20 14:28:27 +02:00
var cert = _this . loadP12cert ( _this . opt . p12cert , _this . opt . pwd ) ;
2022-11-06 10:03:48 +01:00
/** @type {Zga.CertsChain} */
var cchain = null ;
2022-10-06 15:02:11 +02:00
if ( cert ) {
2022-11-06 10:03:48 +01:00
if ( z . urlFetch ) {
cchain = new z . CertsChain ( ) ;
/** @type {?boolean} */
var rootok = await cchain . buildChain ( cert ) ;
if ( rootok ) {
_this . cchain = cchain ;
}
}
2022-10-06 15:02:11 +02:00
z . fixCertAttributes ( cert ) ;
2022-11-14 14:20:19 +01:00
} else if ( _this . tsaFetcher ) {
2022-11-06 10:03:48 +01:00
z . log ( "No certificate is specified, so only add a document timestamp." )
2022-10-24 14:36:47 +02:00
} else {
throw new Error ( "Nothing to do because no certificate nor tsa is specified." ) ;
2022-10-06 15:02:11 +02:00
}
2022-10-24 14:36:47 +02:00
/** @type {boolean} */ //append mode or not
var apmode = _this . addSignHolder ( pdfdoc ) ;
2022-11-06 10:03:48 +01:00
z . log ( "A signature holder has been added to the pdf." ) ;
2022-10-24 14:36:47 +02:00
2022-11-14 14:20:19 +01:00
if ( _this . opt . permission == 1 && ( _this . opt . ltv == 1 || _this . opt . ltv == 2 ) ) {
if ( ! _this . cchain ) {
// Query a timestamp from tsa with dummy string to obtain the certificates.
await _this . queryTsa ( "dummy" ) ;
}
/** @type {PDFLib.PDFDocument} */
var dmydoc = await _this . addDss ( pdfdoc ) ;
if ( dmydoc ) {
z . log ( "In order to enable LTV, DSS informations has been added to the pdf." ) ;
}
// Clear ltv
_this . opt . ltv = 0 ;
} else {
await pdfdoc . flush ( ) ;
}
2022-10-20 14:28:27 +02:00
if ( apmode ) {
if ( _this . oriU8pdf ) {
2022-11-06 10:03:48 +01:00
z . log ( "The pdf has been signed already, so we add a new signature to it." ) ;
2022-10-20 14:28:27 +02:00
} else {
throw new Error ( "When adding a new signature to a signed pdf, the original literal datas are necessary." ) ;
}
// Find the changed objects
2022-11-06 10:03:48 +01:00
await _this . findChangedObjects ( pdfdoc ) ;
2022-10-20 14:28:27 +02:00
} 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 ;
}
} ) ;
}
2022-10-06 15:02:11 +02:00
}
2022-10-20 14:28:27 +02:00
/** @type {Zga.PdfCryptor} */
2022-11-14 14:20:19 +01:00
_this . cyptr = new z . PdfCryptor ( cypopt ) ;
await _this . cyptr . encryptPdf ( pdfdoc , encref ) ;
2022-11-06 10:03:48 +01:00
z . log ( "Pdf data has been encrypted." ) ;
2022-10-06 15:02:11 +02:00
}
2022-10-02 14:45:06 +02:00
}
2022-09-24 06:59:30 +02:00
/** @type {Uint8Array} */
2022-10-20 14:28:27 +02:00
var ret = await _this . saveAndSign ( pdfdoc ) ;
2022-10-02 14:45:06 +02:00
if ( ! ret ) {
2022-11-06 10:03:48 +01:00
z . log ( "Change size of signature's placeholder and retry." ) ;
_this . sigContents . value = "0" . repeat ( _this . siglen + 10 ) ;
2022-10-20 14:28:27 +02:00
ret = await _this . saveAndSign ( pdfdoc ) ;
2022-10-02 14:45:06 +02:00
}
2022-10-14 14:12:43 +02:00
// Because PDFRefs in PDFLib are stored staticly,
// we need to restore all changed PDFRefs
// for preparing the next execution.
if ( z . newRefs . size > 0 ) {
z . newRefs . restoreAll ( ) ;
}
2022-11-06 10:03:48 +01:00
if ( ret ) {
z . log ( "Pdf has been signed." ) ;
} else {
throw new Error ( "Failed to sign the pdf." ) ;
}
2022-11-14 14:20:19 +01:00
pdfdoc = await _this . addDss ( ret ) ;
if ( pdfdoc ) {
await _this . findChangedObjects ( pdfdoc , true ) ;
ret = _this . appendIncrement ( pdfdoc ) ;
z . log ( "LTV has been enabled." ) ;
2022-11-06 10:03:48 +01:00
}
2022-09-24 06:59:30 +02:00
return ret ;
2022-09-17 14:55:09 +02:00
}
/ * *
* @ private
* @ param { PDFLib . PDFDocument } pdfdoc
2022-10-02 14:45:06 +02:00
* @ return { Promise < Uint8Array > }
2022-09-17 14:55:09 +02:00
* /
2022-10-02 14:45:06 +02:00
async saveAndSign ( pdfdoc ) {
/** @type {Uint8Array} */
2022-10-20 14:28:27 +02:00
var uarr = null ;
2022-11-06 10:03:48 +01:00
if ( this . apobjs && this . apobjs . length > 0 ) {
uarr = this . appendIncrement ( pdfdoc ) ;
2022-10-20 14:28:27 +02:00
} else {
uarr = await pdfdoc . save ( { "useObjectStreams" : false } ) ;
}
2022-10-02 14:45:06 +02:00
/** @type {string} */
2022-10-20 14:28:27 +02:00
var pdfstr = z . u8arrToRaw ( uarr ) + String . fromCharCode ( this . NEWLINE ) ;
2022-10-22 11:42:13 +02:00
return await this . signPdf ( pdfstr ) ;
2022-10-02 14:45:06 +02:00
}
2022-09-17 14:55:09 +02:00
2022-11-06 10:03:48 +01:00
/ * *
* @ private
* @ param { PDFLib . PDFDocument } pdfdoc
* @ param { boolean = } ignoreInfo
* @ return { Promise }
* /
async findChangedObjects ( pdfdoc , ignoreInfo ) {
/** @const {z.PdfSigner} */
const _this = this ;
// Find the changed objects
/** @type {PDFLib.PDFDocument} */
var oriPdfdoc = await PDFLib . PDFDocument . load ( _this . oriU8pdf , { ignoreEncryption : true } ) ;
_this . apobjs = [ ] ;
pdfdoc . context . enumerateIndirectObjects ( ) . forEach ( function ( /** @type {PdfObjEntry} */ a _ele ) {
if ( ! ( ignoreInfo && a _ele [ 0 ] == pdfdoc . context . trailerInfo . Info ) ) {
/** @type {PDFLib.PDFObject} */
var a _obj = oriPdfdoc . context . lookup ( a _ele [ 0 ] ) ;
if ( ! ( a _obj && _this . isamePdfObject ( a _ele [ 1 ] , a _obj ) ) ) {
2022-11-14 14:20:19 +01:00
if ( _this . cyptr ) {
_this . cyptr . encryptObject ( a _ele [ 0 ] . objectNumber , a _ele [ 1 ] ) ;
}
2022-11-06 10:03:48 +01:00
_this . apobjs . push ( a _ele ) ;
}
}
} ) ;
}
2022-10-02 14:45:06 +02:00
/ * *
* @ private
* @ param { PDFLib . PDFDocument } pdfdoc
2022-10-20 14:28:27 +02:00
* @ return { Uint8Array }
* /
2022-11-06 10:03:48 +01:00
appendIncrement ( pdfdoc ) {
2022-10-20 14:28:27 +02:00
/** @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} */
2022-11-06 10:03:48 +01:00
const eof = z . rawToU8arr ( "%%EOF" ) ;
2022-10-20 14:28:27 +02:00
/** @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 ;
}
2022-10-24 14:36:47 +02:00
/ * *
* @ private
* @ param { Array < number > | Uint8Array | ArrayBuffer | string = } p12cert
* @ param { string = } pwd
* @ return { forge _cert }
* /
loadP12cert ( p12cert , pwd ) {
2022-11-06 10:03:48 +01:00
/** @const {z.PdfSigner} */
const _this = this ;
2022-10-24 14:36:47 +02:00
// load P12 certificate
if ( ! p12cert ) {
return null ;
} else if ( typeof p12cert !== "string" ) {
p12cert = z . u8arrToRaw ( new Uint8Array ( p12cert ) ) ;
}
// Convert Buffer P12 to a forge implementation.
/** @type {forge.asn1} */
var p12Asn1 = forge . asn1 . fromDer ( p12cert ) ;
/** @type {forge.pkcs12} */
var p12 = forge . pkcs12 . pkcs12FromAsn1 ( p12Asn1 , true , pwd ) ;
// Extract safe bags by type.
// We will need all the certificates and the private key.
/** @type {Object<string|number, P12Bag>} */
var certBags = p12 . getBags ( {
"bagType" : forge . pki . oids . certBag ,
} ) [ forge . pki . oids . certBag ] ;
/** @type {Object<string|number, P12Bag>} */
var keyBags = p12 . getBags ( {
"bagType" : forge . pki . oids . pkcs8ShroudedKeyBag ,
} ) [ forge . pki . oids . pkcs8ShroudedKeyBag ] ;
2022-11-06 10:03:48 +01:00
_this . privateKey = keyBags [ 0 ] . key ;
/** @type {Array<forge_cert>} */
var certs = [ ] ;
/** @type {number} */
var certIdx = - 1 ;
2022-10-24 14:36:47 +02:00
if ( certBags ) {
// Get all the certificates (-cacerts & -clcerts)
// Keep track of the last found client certificate.
// This will be the public key that will be bundled in the signature.
Object . keys ( certBags ) . forEach ( function ( a _ele ) {
/** @type {forge_cert} */
var a _cert = certBags [ a _ele ] . cert ;
2022-11-06 10:03:48 +01:00
certs . push ( a _cert ) ;
2022-10-24 14:36:47 +02:00
// Try to find the certificate that matches the private key.
2022-11-06 10:03:48 +01:00
if ( _this . privateKey . n . compareTo ( a _cert . publicKey . n ) === 0
&& _this . privateKey . e . compareTo ( a _cert . publicKey . e ) === 0 ) {
certIdx = certs . length ;
2022-10-24 14:36:47 +02:00
}
2022-11-06 10:03:48 +01:00
} ) ;
2022-10-24 14:36:47 +02:00
}
2022-11-06 10:03:48 +01:00
if ( certIdx > 0 ) {
certIdx -- ;
_this . cchain = new z . CertsChain ( certs ) ;
if ( _this . cchain . getSignCert ( ) != certs [ certIdx ] ) {
throw new Error ( "Chain of certificates is invalid." ) ;
}
return certs [ certIdx ] ;
2022-10-24 14:36:47 +02:00
} else {
throw new Error ( "Failed to find a certificate." ) ;
}
}
2022-10-20 14:28:27 +02:00
/ * *
* @ private
* @ param { PDFLib . PDFDocument } pdfdoc
* @ return { boolean } append mode or not
2022-10-02 14:45:06 +02:00
* /
addSignHolder ( pdfdoc ) {
2022-10-24 14:36:47 +02:00
/** @const {z.PdfSigner} */
const _this = this ;
2022-10-14 14:12:43 +02:00
/** @const {number} */
2022-11-06 10:03:48 +01:00
const docMdp = ( _this . cchain && _this . opt . permission >= 1 && _this . opt . permission <= 3 ) ? _this . opt . permission : 0 ;
2022-10-14 14:12:43 +02:00
/** @const {PDFLib.PDFContext} */
const pdfcont = pdfdoc . context ;
/** @const {z.SignatureCreator} */
2022-10-24 14:36:47 +02:00
const signcrt = new z . SignatureCreator ( _this . opt . drawinf ) ;
2022-09-17 14:55:09 +02:00
/** @const {PDFLib.PDFPage} */
2022-10-14 14:12:43 +02:00
const page = pdfdoc . getPages ( ) [ signcrt . getPageIndex ( ) ] ;
/** @type {PDFLib.PDFRef} */
2022-10-24 14:36:47 +02:00
var strmRef = signcrt . createStream ( pdfdoc , _this . opt . signame ) ;
2022-10-14 14:12:43 +02:00
if ( docMdp && ! strmRef ) {
strmRef = signcrt . createEmptyField ( pdfcont ) ;
}
2022-09-17 14:55:09 +02:00
2022-10-20 14:28:27 +02:00
/** @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} */
2022-10-24 14:36:47 +02:00
var signm = _this . fixSigName ( oldSigs , _this . opt . signame ) ;
2022-10-20 14:28:27 +02:00
2022-09-24 06:59:30 +02:00
/** @type {Date} */
var signdate = new Date ( ) ;
2022-11-14 14:20:19 +01:00
if ( _this . opt . signdate instanceof Date && ! _this . tsaFetcher ) {
2022-10-24 14:36:47 +02:00
signdate = _this . opt . signdate ;
2022-09-17 14:55:09 +02:00
}
/** @type {PDFLib.PDFArray} */
2022-10-14 14:12:43 +02:00
var bytrng = new PDFLib . PDFArray ( pdfcont ) ;
2022-09-17 14:55:09 +02:00
bytrng . push ( PDFLib . PDFNumber . of ( 0 ) ) ;
2022-10-24 14:36:47 +02:00
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 ) ) ;
2022-10-02 14:45:06 +02:00
2022-11-14 14:20:19 +01:00
_this . siglen = /** @type {number} */ ( _this . tsaFetcher ? _this . tsaFetcher . len : 3322 ) ;
2022-10-24 14:36:47 +02:00
_this . sigContents = PDFLib . PDFHexString . of ( "0" . repeat ( _this . siglen ) ) ;
2022-09-17 14:55:09 +02:00
/** @type {Object<string, *>} */
var signObj = {
"Type" : "Sig" ,
"Filter" : "Adobe.PPKLite" ,
"SubFilter" : "adbe.pkcs7.detached" ,
"ByteRange" : bytrng ,
2022-10-24 14:36:47 +02:00
"Contents" : _this . sigContents ,
2022-10-14 14:12:43 +02:00
"Prop_Build" : pdfcont . obj ( {
"App" : pdfcont . obj ( {
2022-09-18 09:49:56 +02:00
"Name" : "ZgaPdfSinger" ,
2022-09-17 14:55:09 +02:00
} ) ,
} ) ,
} ;
2022-11-06 10:03:48 +01:00
if ( _this . cchain ) {
2022-10-24 14:36:47 +02:00
signObj . M = PDFLib . PDFString . fromDate ( signdate ) ;
} else {
signObj . Type = "DocTimeStamp" ;
signObj . SubFilter = "ETSI.RFC3161" ;
}
2022-10-14 14:12:43 +02:00
if ( docMdp ) {
/** @type {PDFLib.PDFArray} */
var rfrc = new PDFLib . PDFArray ( pdfcont ) ;
rfrc . push ( pdfcont . obj ( {
"Type" : "SigRef" ,
"TransformMethod" : "DocMDP" ,
"TransformParams" : pdfcont . obj ( {
"Type" : "TransformParams" ,
"P" : docMdp ,
"V" : "1.2" ,
} ) ,
} ) ) ;
signObj [ "Reference" ] = rfrc ;
}
2022-10-24 14:36:47 +02:00
if ( _this . opt . reason ) {
signObj [ "Reason" ] = _this . convToPDFString ( _this . opt . reason ) ;
2022-09-17 14:55:09 +02:00
}
2023-02-27 07:05:24 +01:00
if ( _this . opt . signame ) {
signObj [ "Name" ] = _this . convToPDFString ( _this . opt . signame ) ;
}
2022-10-24 14:36:47 +02:00
if ( _this . opt . location ) {
signObj [ "Location" ] = _this . convToPDFString ( _this . opt . location ) ;
2022-09-17 14:55:09 +02:00
}
2022-10-24 14:36:47 +02:00
if ( _this . opt . contact ) {
signObj [ "ContactInfo" ] = _this . convToPDFString ( _this . opt . contact ) ;
2022-09-17 14:55:09 +02:00
}
2022-10-14 14:12:43 +02:00
/** @type {PDFLib.PDFRef} */
var signatureDictRef = pdfcont . register ( pdfcont . obj ( signObj ) ) ;
2022-09-17 14:55:09 +02:00
/** @type {Object<string, *>} */
var widgetObj = {
"Type" : "Annot" ,
"Subtype" : "Widget" ,
"FT" : "Sig" ,
2022-10-14 14:12:43 +02:00
"Rect" : signcrt . getSignRect ( ) ,
2022-09-17 14:55:09 +02:00
"V" : signatureDictRef ,
2022-10-24 14:36:47 +02:00
"T" : _this . convToPDFString ( signm ) ,
2022-09-17 14:55:09 +02:00
"F" : 132 ,
"P" : page . ref ,
} ;
if ( strmRef ) {
2022-10-14 14:12:43 +02:00
widgetObj [ "AP" ] = pdfcont . obj ( {
2022-09-17 14:55:09 +02:00
"N" : strmRef ,
} ) ;
}
2022-10-14 14:12:43 +02:00
/** @type {PDFLib.PDFRef} */
var widgetDictRef = pdfcont . register ( pdfcont . obj ( widgetObj ) ) ;
2022-09-17 14:55:09 +02:00
// Add our signature widget to the page
2022-10-20 14:28:27 +02:00
/** @type {PDFLib.PDFArray} */
var ans = page . node . Annots ( ) ;
if ( ! ans ) {
ans = new PDFLib . PDFArray ( pdfcont ) ;
2022-11-14 14:20:19 +01:00
// if(docMdp){
page . node . set ( PDFLib . PDFName . Annots , ans ) ;
// }else{
// page.node.set(PDFLib.PDFName.Annots, pdfcont.register(ans));
// }
2022-10-20 14:28:27 +02:00
}
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 ) ;
2022-10-14 14:12:43 +02:00
if ( docMdp ) {
pdfdoc . catalog . set (
PDFLib . PDFName . of ( "Perms" ) ,
pdfcont . obj ( {
"DocMDP" : signatureDictRef ,
} ) ,
) ;
2022-10-20 14:28:27 +02:00
}
2022-09-17 14:55:09 +02:00
2022-10-20 14:28:27 +02:00
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 ;
2022-10-14 14:12:43 +02:00
} else {
2022-10-20 14:28:27 +02:00
idx = 0 ;
}
if ( oldSigs . indexOf ( nm ) >= 0 ) {
return this . fixSigName ( oldSigs , signm , idx + 1 ) ;
} else {
return nm ;
2022-10-02 14:45:06 +02:00
}
}
2022-10-06 15:02:11 +02:00
/ * *
* @ private
2022-10-24 14:36:47 +02:00
* @ param { string } str
* @ return { PDFLib . PDFString | PDFLib . PDFHexString }
2022-10-06 15:02:11 +02:00
* /
2022-10-24 14:36:47 +02:00
convToPDFString ( str ) {
// Check if there is a multi-bytes char in the string.
/** @type {boolean} */
var flg = false ;
for ( var i = 0 ; i < str . length ; i ++ ) {
if ( str . charCodeAt ( i ) > 0xFF ) {
flg = true ;
break ;
}
2022-10-06 15:02:11 +02:00
}
2022-10-24 14:36:47 +02:00
if ( flg ) {
return PDFLib . PDFHexString . fromText ( str ) ;
2022-10-06 15:02:11 +02:00
} else {
2022-10-24 14:36:47 +02:00
return PDFLib . PDFString . of ( str ) ;
2022-10-06 15:02:11 +02:00
}
}
2022-09-17 14:55:09 +02:00
/ * *
* @ private
* @ param { string } pdfstr
2022-10-22 11:42:13 +02:00
* @ return { Promise < Uint8Array > }
2022-09-17 14:55:09 +02:00
* /
2022-10-22 11:42:13 +02:00
async signPdf ( pdfstr ) {
2022-11-06 10:03:48 +01:00
/** @const {z.PdfSigner} */
const _this = this ;
2022-09-17 14:55:09 +02:00
// Finds ByteRange information within a given PDF Buffer if one exists
2022-10-04 14:37:17 +02:00
/** @type {Array<string>} */
2022-09-17 14:55:09 +02:00
var byteRangeStrings = pdfstr . match ( /\/ByteRange\s*\[{1}\s*(?:(?:\d*|\/\*{10})\s+){3}(?:\d+|\/\*{10}){1}\s*]{1}/g ) ;
2022-10-04 14:37:17 +02:00
/** @type {string|undefined} */
2022-11-06 10:03:48 +01:00
var byteRangePlaceholder = byteRangeStrings . find ( function ( /** @type {string} */ a _str ) {
return a _str . includes ( "/" + _this . DEFAULT _BYTE _RANGE _PLACEHOLDER ) ;
} ) ;
2022-09-17 14:55:09 +02:00
if ( ! byteRangePlaceholder ) {
throw new Error ( "no signature placeholder" ) ;
}
2022-10-04 14:37:17 +02:00
/** @type {number} */
2022-09-17 14:55:09 +02:00
var byteRangePos = pdfstr . indexOf ( byteRangePlaceholder ) ;
2022-10-04 14:37:17 +02:00
/** @type {number} */
2022-09-17 14:55:09 +02:00
var byteRangeEnd = byteRangePos + byteRangePlaceholder . length ;
2022-10-04 14:37:17 +02:00
/** @type {number} */
2022-09-17 14:55:09 +02:00
var contentsTagPos = pdfstr . indexOf ( '/Contents ' , byteRangeEnd ) ;
2022-10-04 14:37:17 +02:00
/** @type {number} */
2022-09-17 14:55:09 +02:00
var placeholderPos = pdfstr . indexOf ( '<' , contentsTagPos ) ;
2022-10-04 14:37:17 +02:00
/** @type {number} */
2022-09-17 14:55:09 +02:00
var placeholderEnd = pdfstr . indexOf ( '>' , placeholderPos ) ;
2022-10-04 14:37:17 +02:00
/** @type {number} */
2022-09-17 14:55:09 +02:00
var placeholderLengthWithBrackets = placeholderEnd + 1 - placeholderPos ;
2022-10-04 14:37:17 +02:00
/** @type {number} */
2022-09-17 14:55:09 +02:00
var placeholderLength = placeholderLengthWithBrackets - 2 ;
2022-10-04 14:37:17 +02:00
/** @type {Array<number>} */
2022-09-17 14:55:09 +02:00
var byteRange = [ 0 , 0 , 0 , 0 ] ;
byteRange [ 1 ] = placeholderPos ;
byteRange [ 2 ] = byteRange [ 1 ] + placeholderLengthWithBrackets ;
byteRange [ 3 ] = pdfstr . length - byteRange [ 2 ] ;
2022-10-04 14:37:17 +02:00
/** @type {string} */
2022-09-17 14:55:09 +02:00
var actualByteRange = "/ByteRange [" + byteRange . join ( " " ) + "]" ;
actualByteRange += ' ' . repeat ( byteRangePlaceholder . length - actualByteRange . length ) ;
// Replace the /ByteRange placeholder with the actual ByteRange
pdfstr = pdfstr . slice ( 0 , byteRangePos ) + actualByteRange + pdfstr . slice ( byteRangeEnd ) ;
// Remove the placeholder signature
pdfstr = pdfstr . slice ( 0 , byteRange [ 1 ] ) + pdfstr . slice ( byteRange [ 2 ] , byteRange [ 2 ] + byteRange [ 3 ] ) ;
2022-10-24 14:36:47 +02:00
/** @type {forge.asn1} */
var asn1sig = null ;
2022-11-06 10:03:48 +01:00
if ( _this . cchain ) {
2022-10-24 14:36:47 +02:00
/** @type {Date} */
var signdate = new Date ( ) ;
2022-11-14 14:20:19 +01:00
if ( _this . opt . signdate instanceof Date && ! _this . tsaFetcher ) {
2022-11-06 10:03:48 +01:00
signdate = _this . opt . signdate ;
2022-10-24 14:36:47 +02:00
}
2022-09-17 14:55:09 +02:00
2022-10-24 14:36:47 +02:00
// Here comes the actual PKCS#7 signing.
/** @type {forge.pkcs7} */
var p7 = null ;
p7 = forge . pkcs7 . createSignedData ( ) ;
// Start off by setting the content.
p7 . content = forge . util . createBuffer ( pdfstr ) ;
2022-09-17 14:55:09 +02:00
2022-10-24 14:36:47 +02:00
// Add all the certificates (-cacerts & -clcerts) to p7
2022-11-06 10:03:48 +01:00
_this . cchain . getAllCerts ( ) . forEach ( function ( /** @type {forge_cert} */ a _cert ) {
2022-10-24 14:36:47 +02:00
p7 . addCertificate ( a _cert ) ;
} ) ;
2022-09-17 14:55:09 +02:00
2022-10-24 14:36:47 +02:00
// Add a sha256 signer. That's what Adobe.PPKLite adbe.pkcs7.detached expects.
p7 . addSigner ( {
2022-11-06 10:03:48 +01:00
key : _this . privateKey ,
certificate : _this . cchain . getSignCert ( ) ,
2022-10-24 14:36:47 +02:00
digestAlgorithm : forge . pki . oids . sha256 ,
authenticatedAttributes : [
{
"type" : forge . pki . oids . contentType ,
"value" : forge . pki . oids . data ,
} , {
"type" : forge . pki . oids . signingTime ,
"value" : signdate ,
2023-02-24 12:09:38 +01:00
} , {
"type" : forge . pki . oids . messageDigest ,
2022-10-24 14:36:47 +02:00
} ,
] ,
} ) ;
2022-09-24 06:59:30 +02:00
2022-10-24 14:36:47 +02:00
// Sign in detached mode.
p7 . sign ( { "detached" : true } ) ;
2022-11-14 14:20:19 +01:00
if ( _this . tsaFetcher ) {
2022-10-24 14:36:47 +02:00
/** @type {forge.asn1} */
2022-11-06 10:03:48 +01:00
var tsatoken = await _this . queryTsa ( p7 . signers [ 0 ] . signature , true ) ;
2022-10-24 14:36:47 +02:00
p7 . signerInfos [ 0 ] . value . push ( tsatoken ) ;
}
asn1sig = p7 . toAsn1 ( ) ;
} else {
2022-11-06 10:03:48 +01:00
asn1sig = await _this . queryTsa ( pdfstr ) ;
2022-09-24 06:59:30 +02:00
}
2022-09-17 14:55:09 +02:00
// Check if the PDF has a good enough placeholder to fit the signature.
2022-11-06 10:03:48 +01:00
/** @type {forge.util.ByteStringBuffer} */
var sigbuf = forge . asn1 . toDer ( asn1sig ) ;
2022-10-04 14:37:17 +02:00
/** @type {string} */
2022-11-06 10:03:48 +01:00
var sighex = sigbuf . toHex ( ) ;
_this . signature = sigbuf . getBytes ( ) ;
2022-09-17 14:55:09 +02:00
// placeholderLength represents the length of the HEXified symbols but we're
// checking the actual lengths.
2022-11-06 10:03:48 +01:00
z . log ( "Size of signature is " + sighex . length + "/" + placeholderLength ) ;
2022-09-17 14:55:09 +02:00
if ( sighex . length > placeholderLength ) {
2022-10-02 14:45:06 +02:00
// throw new Error("Signature is too big. Needs: " + sighex.length);
2022-11-06 10:03:48 +01:00
_this . siglen = sighex . length ;
2022-10-02 14:45:06 +02:00
return null ;
2022-09-17 14:55:09 +02:00
} else {
// Pad the signature with zeroes so the it is the same length as the placeholder
sighex += "0" . repeat ( placeholderLength - sighex . length ) ;
}
// Place it in the document.
pdfstr = pdfstr . slice ( 0 , byteRange [ 1 ] ) + "<" + sighex + ">" + pdfstr . slice ( byteRange [ 1 ] ) ;
2022-10-02 14:45:06 +02:00
return z . rawToU8arr ( pdfstr ) ;
2022-09-17 14:55:09 +02:00
}
2022-09-19 04:53:54 +02:00
/ * *
* @ private
2022-10-24 14:36:47 +02:00
* @ param { string = } data
2022-11-06 10:03:48 +01:00
* @ param { boolean = } forP7
2022-10-24 14:36:47 +02:00
* @ return { Promise < forge . asn1 > }
2022-09-19 04:53:54 +02:00
* /
2022-11-06 10:03:48 +01:00
async queryTsa ( data , forP7 ) {
/** @const {z.PdfSigner} */
const _this = this ;
/** @type {?string} */
var err = await _this . tsaFetcher . queryTsa ( data ) ;
if ( err ) {
throw new Error ( err ) ;
2022-10-24 14:36:47 +02:00
} else {
2022-11-06 10:03:48 +01:00
/** @type {forge.asn1} */
var asn1 = _this . tsaFetcher . getToken ( forP7 ) ;
2022-11-14 14:20:19 +01:00
z . log ( "Timestamp from " + _this . tsaFetcher . url + " has been obtained." ) ;
2022-11-06 10:03:48 +01:00
return asn1 ;
}
}
/ * *
2022-11-14 14:20:19 +01:00
* @ private
* @ param { PDFLib . PDFDocument | Uint8Array } pdf
* @ return { Promise < PDFLib . PDFDocument > }
2022-11-06 10:03:48 +01:00
* /
2022-11-14 14:20:19 +01:00
async addDss ( pdf ) {
2022-11-06 10:03:48 +01:00
/** @const {z.PdfSigner} */
const _this = this ;
2022-11-14 14:20:19 +01:00
if ( _this . opt . ltv != 1 && _this . opt . ltv != 2 ) {
2022-11-06 10:03:48 +01:00
return null ;
}
2022-11-14 14:20:19 +01:00
/** @type {Zga.CertsChain} */
var cchain = _this . cchain ? _this . cchain : _this . tsaFetcher . getCertsChain ( ) ;
if ( cchain . isSelfSignedCert ( ) ) {
z . log ( "No need to enable LTV because the certificate is a self signed one." ) ;
return null ;
}
/** @type {boolean} */
var crlOnly = ( _this . opt . ltv == 2 ) ;
/** @type {?DSSInfo} */
var dssinf = await cchain . prepareDSSInf ( crlOnly ) ;
if ( ! dssinf ) {
2022-11-06 10:03:48 +01:00
return null ;
}
2022-09-24 06:59:30 +02:00
2022-11-14 14:20:19 +01:00
/** @type {PDFLib.PDFDocument} */
var pdfdoc = null ;
if ( pdf . addPage ) {
pdfdoc = /** @type {PDFLib.PDFDocument} */ ( pdf ) ;
} else {
_this . oriU8pdf = /** @type {Uint8Array} */ ( pdf ) ;
pdfdoc = await PDFLib . PDFDocument . load ( _this . oriU8pdf , { ignoreEncryption : true } ) ;
}
2022-11-06 10:03:48 +01:00
/** @type {PDFLib.PDFContext} */
var pdfcont = pdfdoc . context ;
/** @type {Array<PDFLib.PDFRef>} */
var certRefs = null ;
/** @type {Array<PDFLib.PDFRef>} */
var ocspRefs = null ;
/** @type {Array<PDFLib.PDFRef>} */
var crlRefs = null ;
if ( dssinf && dssinf . ocsps && dssinf . ocsps . length > 0 ) {
ocspRefs = [ ] ;
dssinf . ocsps . forEach ( function ( /** @type {string|Uint8Array} */ a _ocsp ) {
/** @type {PDFLib.PDFRawStream} */
var a _strmOcsp = pdfcont . flateStream ( a _ocsp ) ;
ocspRefs . push ( pdfcont . register ( a _strmOcsp ) ) ;
} ) ;
}
if ( dssinf && dssinf . crls && dssinf . crls . length > 0 ) {
crlRefs = [ ] ;
dssinf . crls . forEach ( function ( /** @type {string|Uint8Array} */ a _crl ) {
/** @type {PDFLib.PDFRawStream} */
var a _strmCrl = pdfcont . flateStream ( a _crl ) ;
crlRefs . push ( pdfcont . register ( a _strmCrl ) ) ;
} ) ;
}
if ( ! ( ocspRefs || crlRefs ) ) {
// Nothing to do.
2022-11-14 14:20:19 +01:00
return null ;
2022-11-06 10:03:48 +01:00
}
if ( dssinf && dssinf . certs && dssinf . certs . length > 0 ) {
certRefs = [ ] ;
dssinf . certs . forEach ( function ( /** @type {forge_cert} */ a _cert ) {
/** @type {forge.asn1} */
var a _asn1Cert = forge . pki . certificateToAsn1 ( a _cert ) ;
/** @type {PDFLib.PDFRawStream} */
var a _strmCert = pdfcont . flateStream ( forge . asn1 . toDer ( a _asn1Cert ) . getBytes ( ) ) ;
certRefs . push ( pdfcont . register ( a _strmCert ) ) ;
} ) ;
}
/** @type {string} */
2022-11-14 14:20:19 +01:00
var sighex = "" ;
if ( _this . signature ) {
/** @type {forge.md.digest} */
var md = forge . md . sha1 . create ( ) ;
md . update ( _this . signature ) ;
sighex = md . digest ( ) . toHex ( ) . toUpperCase ( ) ;
}
2022-11-06 10:03:48 +01:00
var dss = /** @type {PDFLib.PDFDict} */ ( pdfdoc . catalog . lookupMaybe ( PDFLib . PDFName . of ( "DSS" ) , PDFLib . PDFDict ) ) ;
/** @type {PDFLib.PDFArray} */
var certsarr = null ;
/** @type {PDFLib.PDFArray} */
var ocpsarr = null ;
/** @type {PDFLib.PDFArray} */
var crlsarr = null ;
/** @type {PDFLib.PDFDict} */
var vri = null ;
/** @type {Object<string, *>} */
2022-11-14 14:20:19 +01:00
var vriObj = null ;
if ( sighex ) {
vriObj = {
TU : PDFLib . PDFString . fromDate ( new Date ( ) ) ,
} ;
}
2022-11-06 10:03:48 +01:00
/** @type {PDFLib.PDFArray} */
var sigcertsarr = null ;
/** @type {PDFLib.PDFArray} */
var sigocpsarr = null ;
/** @type {PDFLib.PDFArray} */
var sigcrlsarr = null ;
if ( dss ) {
certsarr = /** @type {PDFLib.PDFArray} */ ( dss . lookupMaybe ( PDFLib . PDFName . of ( "Certs" ) , PDFLib . PDFArray ) ) ;
crlsarr = /** @type {PDFLib.PDFArray} */ ( dss . lookupMaybe ( PDFLib . PDFName . of ( "CRLs" ) , PDFLib . PDFArray ) ) ;
ocpsarr = /** @type {PDFLib.PDFArray} */ ( dss . lookupMaybe ( PDFLib . PDFName . of ( "OCSPs" ) , PDFLib . PDFArray ) ) ;
vri = /** @type {PDFLib.PDFDict} */ ( dss . lookupMaybe ( PDFLib . PDFName . of ( "VRI" ) , PDFLib . PDFDict ) ) ;
} else {
dss = /** @type {PDFLib.PDFDict} */ ( pdfcont . obj ( { } ) ) ;
pdfdoc . catalog . set ( PDFLib . PDFName . of ( "DSS" ) , pdfcont . register ( dss ) ) ;
2022-09-24 06:59:30 +02:00
}
2022-11-06 10:03:48 +01:00
if ( certRefs ) {
2022-11-14 14:20:19 +01:00
if ( vriObj ) {
sigcertsarr = new PDFLib . PDFArray ( pdfcont ) ;
vriObj [ "Cert" ] = sigcertsarr ;
}
2022-11-06 10:03:48 +01:00
if ( ! certsarr ) {
certsarr = new PDFLib . PDFArray ( pdfcont ) ;
dss . set ( PDFLib . PDFName . of ( "Certs" ) , pdfcont . register ( certsarr ) ) ;
}
certRefs . forEach ( function ( /** @type {PDFLib.PDFRef} */ a _ref ) {
2022-11-14 14:20:19 +01:00
if ( sigcertsarr ) {
sigcertsarr . push ( a _ref ) ;
}
2022-11-06 10:03:48 +01:00
certsarr . push ( a _ref ) ;
} ) ;
}
if ( ocspRefs ) {
2022-11-14 14:20:19 +01:00
if ( vriObj ) {
sigocpsarr = new PDFLib . PDFArray ( pdfcont ) ;
vriObj [ "OCSP" ] = sigocpsarr ;
}
2022-11-06 10:03:48 +01:00
if ( ! ocpsarr ) {
ocpsarr = new PDFLib . PDFArray ( pdfcont ) ;
dss . set ( PDFLib . PDFName . of ( "OCSPs" ) , pdfcont . register ( ocpsarr ) ) ;
}
ocspRefs . forEach ( function ( /** @type {PDFLib.PDFRef} */ a _ref ) {
2022-11-14 14:20:19 +01:00
if ( sigocpsarr ) {
sigocpsarr . push ( a _ref ) ;
}
2022-11-06 10:03:48 +01:00
ocpsarr . push ( a _ref ) ;
} ) ;
}
if ( crlRefs ) {
2022-11-14 14:20:19 +01:00
if ( vriObj ) {
sigcrlsarr = new PDFLib . PDFArray ( pdfcont ) ;
vriObj [ "CRL" ] = sigcrlsarr ;
}
2022-11-06 10:03:48 +01:00
if ( ! crlsarr ) {
crlsarr = new PDFLib . PDFArray ( pdfcont ) ;
dss . set ( PDFLib . PDFName . of ( "CRLs" ) , pdfcont . register ( crlsarr ) ) ;
}
crlRefs . forEach ( function ( /** @type {PDFLib.PDFRef} */ a _ref ) {
2022-11-14 14:20:19 +01:00
if ( sigcrlsarr ) {
sigcrlsarr . push ( a _ref ) ;
}
2022-11-06 10:03:48 +01:00
crlsarr . push ( a _ref ) ;
} ) ;
}
2022-11-14 14:20:19 +01:00
if ( sighex && vriObj ) {
if ( ! vri ) {
vri = /** @type {PDFLib.PDFDict} */ ( pdfcont . obj ( { } ) ) ;
dss . set ( PDFLib . PDFName . of ( "VRI" ) , pdfcont . register ( vri ) ) ;
}
vri . set ( PDFLib . PDFName . of ( sighex ) , pdfcont . register ( pdfcont . obj ( vriObj ) ) ) ;
2022-11-06 10:03:48 +01:00
}
2022-11-14 14:20:19 +01:00
await pdfdoc . flush ( ) ;
return pdfdoc ;
2022-09-24 06:59:30 +02:00
}
2022-10-02 14:45:06 +02:00
} ;
2022-09-17 14:55:09 +02:00
2022-10-14 14:12:43 +02:00
z . SignatureCreator = class {
2022-09-17 14:55:09 +02:00
/ * *
* @ param { SignDrawInfo = } drawinf
* /
constructor ( drawinf ) {
/** @private @type {number} */
this . pgidx = 0 ;
/** @private @type {Array<number>} */
this . rect = [ 0 , 0 , 0 , 0 ] ;
2022-10-04 14:37:17 +02:00
/** @private @type {?SignDrawInfo} */
2022-09-17 14:55:09 +02:00
this . drawinf = null ;
if ( drawinf ) {
this . drawinf = drawinf ;
if ( this . drawinf . pageidx ) {
this . pgidx = this . drawinf . pageidx ;
}
}
}
/ * *
* @ public
* @ return { number }
* /
getPageIndex ( ) {
return this . pgidx ;
}
/ * *
* @ public
* @ return { Array < number > }
* /
getSignRect ( ) {
return this . rect ;
}
2022-10-14 14:12:43 +02:00
/ * *
* @ public
* @ param { PDFLib . PDFContext } pdfcont
* @ return { PDFLib . PDFRef }
* /
createEmptyField ( pdfcont ) {
return pdfcont . register ( pdfcont . obj ( {
"Type" : "XObject" ,
"Subtype" : "Form" ,
"FormType" : 1 ,
"BBox" : [ 0 , 0 , 0 , 0 ] ,
} ) ) ;
}
2022-09-17 14:55:09 +02:00
/ * *
* @ public
* @ param { PDFLib . PDFDocument } pdfdoc
* @ param { string = } signame
* @ return { PDFLib . PDFRef } The unique reference assigned to the signature stream
* /
createStream ( pdfdoc , signame ) {
if ( ! this . drawinf ) {
return null ;
} else if ( ! ( this . drawinf . img || ( this . drawinf . font && this . drawinf . font ) ) ) {
return null ;
}
/** @type {Array<PDFLib.PDFPage>} */
var pages = pdfdoc . getPages ( ) ;
/** @type {PDFLib.PDFPage} */
var page = null ;
if ( this . pgidx < pages . length ) {
page = pages [ this . pgidx ] ;
} else {
throw new Error ( "Page index is overflow to pdf pages." ) ;
}
2022-10-04 14:37:17 +02:00
/** @type {PDFLib.Rotation} */
2022-09-17 14:55:09 +02:00
var pgrot = page . getRotation ( ) ;
pgrot . angle = PDFLib . toDegrees ( pgrot ) % 360 ;
pgrot . type = PDFLib . RotationTypes . Degrees ;
2022-10-04 14:37:17 +02:00
/** @type {PdfSize} */
2022-09-17 14:55:09 +02:00
var pgsz = page . getSize ( ) ;
2022-10-04 14:37:17 +02:00
/** @type {SignAreaInfo} */
2022-09-17 14:55:09 +02:00
var areainf = this . calcAreaInf ( pgsz , pgrot . angle , this . drawinf . area ) ;
// resources object
2022-10-04 14:37:17 +02:00
/** @type {Object<string, *>} */
2022-09-17 14:55:09 +02:00
var rscObj = { } ;
/** @type {Array<PDFLib.PDFOperator>} */
var sigOprs = [ ] ;
2022-10-04 14:37:17 +02:00
/** @type {string} */
2022-09-17 14:55:09 +02:00
var imgName = signame ? signame . concat ( "Img" ) : "SigImg" ;
2022-10-04 14:37:17 +02:00
/** @type {string} */
2022-09-17 14:55:09 +02:00
var fontName = signame ? signame . concat ( "Font" ) : "SigFont" ;
if ( this . drawinf . img ) {
// Get scaled image size
2022-10-04 14:37:17 +02:00
/** @type {PdfSize} */
2022-09-17 14:55:09 +02:00
var imgsz = this . drawinf . img . size ( ) ;
2022-10-04 14:37:17 +02:00
/** @type {number} */
2022-09-17 14:55:09 +02:00
var tmp = areainf . w * imgsz . height / imgsz . width ;
if ( tmp <= areainf . h ) {
areainf . h = tmp ;
} else {
areainf . w = areainf . h * imgsz . width / imgsz . height ;
}
rscObj [ "XObject" ] = {
[ imgName ] : this . drawinf . img . ref ,
} ;
sigOprs = sigOprs . concat ( PDFLib . drawImage ( imgName , this . calcDrawImgInf ( pgrot , areainf ) ) ) ;
}
if ( this . drawinf . font ) {
rscObj [ "Font" ] = {
[ fontName ] : this . drawinf . font . ref ,
} ;
}
this . rect = this . calcRect ( pgrot . angle , areainf ) ;
2022-10-20 14:28:27 +02:00
var frmDict = /** @type {PDFLib.PDFDict} */ ( pdfdoc . context . obj ( {
2022-09-17 14:55:09 +02:00
"Type" : "XObject" ,
"Subtype" : "Form" ,
"FormType" : 1 ,
"BBox" : [ 0 , 0 , areainf . w , areainf . h ] ,
"Resources" : rscObj ,
2022-10-20 14:28:27 +02:00
} ) ) ;
2022-10-04 14:37:17 +02:00
/** @type {PDFLib.PDFContentStream} */
2022-10-14 14:12:43 +02:00
var strm = PDFLib . PDFContentStream . of ( frmDict , sigOprs , true ) ;
2022-09-17 14:55:09 +02:00
return pdfdoc . context . register ( strm ) ;
}
/ * *
* Calculate area informations for drawing signature after rotate
*
* @ private
2022-10-04 14:37:17 +02:00
* @ param { PdfSize } pgsz
2022-09-17 14:55:09 +02:00
* @ param { number } angle
* @ param { SignAreaInfo } visinf
* @ return { SignAreaInfo }
* /
calcAreaInf ( pgsz , angle , visinf ) {
2022-10-04 14:37:17 +02:00
var ret = /** @type {SignAreaInfo} */ ( Object . assign ( { } , visinf ) ) ;
2022-09-17 14:55:09 +02:00
// Calculate position after rotate
switch ( angle ) {
case 90 :
ret . w = visinf . h ;
ret . h = visinf . w ;
2022-10-01 10:20:53 +02:00
ret . x = visinf . y + visinf . h ;
2022-09-17 14:55:09 +02:00
ret . y = visinf . x ;
break ;
case 180 :
case - 180 :
ret . x = pgsz . width - visinf . x ;
2022-10-01 10:20:53 +02:00
ret . y = visinf . y + visinf . h ;
2022-09-17 14:55:09 +02:00
break ;
case 270 :
case - 90 :
ret . w = visinf . h ;
ret . h = visinf . w ;
2022-10-01 10:20:53 +02:00
ret . x = pgsz . width - visinf . y - visinf . h ;
2022-09-17 14:55:09 +02:00
ret . y = pgsz . height - visinf . x ;
break ;
default :
2022-10-01 10:20:53 +02:00
ret . y = pgsz . height - visinf . y - visinf . h ;
2022-09-17 14:55:09 +02:00
}
return ret ;
}
/ * *
* @ private
* @ param { number } angle
* @ param { SignAreaInfo } areainf // { x, y, w, h }
* @ return { Array < number > }
* /
calcRect ( angle , areainf ) {
2022-10-04 14:37:17 +02:00
/** @type {Array<number>} */
2022-09-17 14:55:09 +02:00
var rect = [ 0 , 0 , 0 , 0 ] ;
rect [ 0 ] = areainf . x ;
rect [ 1 ] = areainf . y ;
switch ( angle ) {
case 90 :
rect [ 2 ] = areainf . x - areainf . h ;
rect [ 3 ] = areainf . y + areainf . w ;
break ;
case 180 :
case - 180 :
rect [ 2 ] = areainf . x - areainf . w ;
rect [ 3 ] = areainf . y - areainf . h ;
break ;
case 270 :
case - 90 :
rect [ 2 ] = areainf . x + areainf . h ;
rect [ 3 ] = areainf . y - areainf . w ;
break ;
default :
rect [ 2 ] = areainf . x + areainf . w ;
rect [ 3 ] = areainf . y + areainf . h ;
}
return rect ;
}
/ * *
* Calculate informations for drawing image after rotate
*
* @ private
* @ param { PDFLib . Rotation } rot
* @ param { SignAreaInfo } areainf // { x, y, w, h }
2022-10-04 14:37:17 +02:00
* @ return { PdfDrawimgOption }
2022-09-17 14:55:09 +02:00
* /
calcDrawImgInf ( rot , areainf ) {
2022-10-04 14:37:17 +02:00
/** @type {PdfDrawimgOption} */
2022-09-17 14:55:09 +02:00
var ret = {
"x" : 0 ,
"y" : 0 ,
"width" : areainf . w ,
"height" : areainf . h ,
"rotate" : rot ,
"xSkew" : PDFLib . degrees ( 0 ) ,
"ySkew" : PDFLib . degrees ( 0 ) ,
} ;
switch ( rot . angle ) {
case 90 :
ret [ "x" ] = areainf . w ;
ret [ "width" ] = areainf . h ;
ret [ "height" ] = areainf . w ;
break ;
case 180 :
case - 180 :
ret [ "x" ] = areainf . w ;
ret [ "y" ] = areainf . h ;
break ;
case 270 :
case - 90 :
ret [ "y" ] = areainf . h ;
ret [ "width" ] = areainf . h ;
ret [ "height" ] = areainf . w ;
break ;
}
return ret ;
}
2022-10-02 14:45:06 +02:00
} ;
2022-09-18 09:49:56 +02:00
2022-10-02 14:45:06 +02:00
}
2022-09-18 09:49:56 +02:00
2022-11-06 10:03:48 +01:00
//Only for nodejs Start//
if ( typeof exports === "object" && typeof module !== "undefined" ) {
module . exports = supplyZgaSigner ;
2022-10-02 14:45:06 +02:00
}
2022-11-06 10:03:48 +01:00
//Only for nodejs End//