Skip to content
Snippets Groups Projects
Commit 2d1ecb82 authored by Damyan Mitev's avatar Damyan Mitev :beach: Committed by Sasha Ilieva
Browse files

Make ES Lint happy

parent f329d221
No related branches found
No related tags found
3 merge requests!48269 implement workflow for signing already uploaded document dev,!47269 implement workflow for signing already uploaded document,!41268 convert odt file to pdf
This commit is part of merge request !41. Comments created here will be created in the context of that merge request.
...@@ -9,367 +9,362 @@ ...@@ -9,367 +9,362 @@
*/ */
import { import {
ObjectIdentifier, ObjectIdentifier,
UTCTime, UTCTime,
OctetString OctetString
} from 'asn1js'; } from 'asn1js';
import { import {
ContentInfo, ContentInfo,
SignedData, SignedData,
Attribute, Attribute,
SignerInfo, SignerInfo,
IssuerAndSerialNumber, IssuerAndSerialNumber,
SignedAndUnsignedAttributes, SignedAndUnsignedAttributes,
EncapsulatedContentInfo, EncapsulatedContentInfo,
getCrypto getCrypto
} from 'pkijs'; } from 'pkijs';
import { import {
parseCertificate, parseCertificate,
parsePrivateKey, parsePrivateKey
} from './signingUtilities'; } from './signingUtilities';
//keep this import to include the patched version of pdfjs library //keep this import to include the patched version of pdfjs library
import {PDFJS} from "../lib/pdfjs.parser.js"; import {PDFJS} from "../lib/pdfjs.parser.js";
function createXrefTable(xrefEntries) { function createXrefTable(xrefEntries) {
xrefEntries = sortOnKeys(xrefEntries); xrefEntries = sortOnKeys(xrefEntries);
var retVal ='xref\n'; let retVal = 'xref\n';
var last = -2; let last = -2;
for(var i in xrefEntries) { for (let i in xrefEntries) {
i = parseInt(i); i = parseInt(i);
if(typeof xrefEntries[i].offset === 'undefined') { continue; } if (typeof xrefEntries[i].offset === 'undefined') { continue; }
retVal += calcFlow(i, last, xrefEntries); retVal += calcFlow(i, last, xrefEntries);
var offset = xrefEntries[i].offset; const offset = xrefEntries[i].offset;
retVal += pad10(offset)+' '+pad5(xrefEntries[i].gen)+' '+(xrefEntries[i].free?'f':'n')+' \n'; retVal += pad10(offset) + ' ' + pad5(xrefEntries[i].gen) + ' ' + (xrefEntries[i].free ? 'f' : 'n') + ' \n';
last = i; last = i;
} }
return retVal; return retVal;
} }
function calcFlow(i, last, xrefEntries) { function calcFlow(i, last, xrefEntries) {
if(last + 1 === i) {return '';} if (last + 1 === i) { return ''; }
var count = 1; let count = 1;
while(typeof xrefEntries[(i+count)] !== 'undefined' while (typeof xrefEntries[i + count] !== 'undefined' &&
&& typeof xrefEntries[(i+count)].offset !== 'undefined') {count ++;} typeof xrefEntries[i + count].offset !== 'undefined') { count++; }
return i + ' '+count+'\n'; return i + ' ' + count + '\n';
} }
function createTrailer(topDict, startxref, sha256Hex, size, prev) { function createTrailer(topDict, startxref, sha256Hex, size, prev) {
var retVal ='trailer <<\n'; let retVal = 'trailer <<\n';
retVal +=' /Size '+(size)+'\n'; retVal += ' /Size ' + size + '\n';
var refRoot = topDict.getRaw('Root'); const refRoot = topDict.getRaw('Root');
if(typeof refRoot !== 'undefined') { if (typeof refRoot !== 'undefined') {
retVal +=' /Root '+refRoot.num+' '+refRoot.gen+' R\n'; retVal += ' /Root ' + refRoot.num + ' ' + refRoot.gen + ' R\n';
} }
var refInfo = topDict.getRaw('Info'); const refInfo = topDict.getRaw('Info');
if(typeof refInfo !== 'undefined') { if (typeof refInfo !== 'undefined') {
retVal +=' /Info '+refInfo.num+' '+refInfo.gen+' R\n'; retVal += ' /Info ' + refInfo.num + ' ' + refInfo.gen + ' R\n';
} }
retVal +=' /ID [<'+sha256Hex.substring(0,32)+'><'+sha256Hex.substring(32,64)+'>]\n'; retVal += ' /ID [<' + sha256Hex.substring(0,32) + '><' + sha256Hex.substring(32,64) + '>]\n';
if(typeof prev !== 'undefined' ) { if (typeof prev !== 'undefined') {
retVal +=' /Prev '+prev+'\n'; retVal += ' /Prev ' + prev + '\n';
} }
retVal +='>>\n'; retVal += '>>\n';
retVal +='startxref\n'; retVal += 'startxref\n';
retVal +=startxref + '\n'; retVal += startxref + '\n';
retVal +='%%EOF\n'; retVal += '%%EOF\n';
return retVal; return retVal;
} }
function createXrefTableAppend(xrefEntries) { function createXrefTableAppend(xrefEntries) {
xrefEntries = sortOnKeys(xrefEntries); xrefEntries = sortOnKeys(xrefEntries);
var retVal ='xref\n'; let retVal = 'xref\n';
var last = -2; let last = -2;
for(var i in xrefEntries) { for (let i in xrefEntries) {
i = parseInt(i); i = parseInt(i);
if(typeof xrefEntries[i].offset === 'undefined') { continue; } if (typeof xrefEntries[i].offset === 'undefined') { continue; }
retVal += calcFlow(i, last, xrefEntries); retVal += calcFlow(i, last, xrefEntries);
var offset = xrefEntries[i].offset; const offset = xrefEntries[i].offset;
retVal += pad10(offset)+' '+pad5(xrefEntries[i].gen)+' '+(xrefEntries[i].free?'f':'n')+' \n'; retVal += pad10(offset) + ' ' + pad5(xrefEntries[i].gen) + ' ' + (xrefEntries[i].free ? 'f' : 'n') + ' \n';
last = i; last = i;
} }
return retVal; return retVal;
} }
//http://stackoverflow.com/questions/10946880/sort-a-dictionary-or-whatever-key-value-data-structure-in-js-on-word-number-ke //http://stackoverflow.com/questions/10946880/sort-a-dictionary-or-whatever-key-value-data-structure-in-js-on-word-number-ke
function sortOnKeys(dict) { function sortOnKeys(dict) {
var sorted = []; const sorted = [];
for(var key in dict) { for (const key in dict) {
sorted[sorted.length] = key; sorted[sorted.length] = key;
} }
sorted.sort(); sorted.sort();
var tempDict = {}; const tempDict = {};
for(var i = 0; i < sorted.length; i++) { for (let i = 0; i < sorted.length; i++) {
tempDict[sorted[i]] = dict[sorted[i]]; tempDict[sorted[i]] = dict[sorted[i]];
} }
return tempDict; return tempDict;
} }
function removeFromArray(array, from, to) { function removeFromArray(array, from, to) {
var cutlen = to - from; const cutlen = to - from;
var buf = new Uint8Array(array.length - cutlen); const buf = new Uint8Array(array.length - cutlen);
for (var i = 0; i < from; i++) { for (let i = 0; i < from; i++) {
buf[i] = array[i]; buf[i] = array[i];
} }
for (var i = to, len = array.length; i < len; i++) { for (let i = to, len = array.length; i < len; i++) {
buf[i-cutlen] = array[i]; buf[i - cutlen] = array[i];
} }
return buf; return buf;
} }
function findXrefBlocks(xrefBlocks) { function findXrefBlocks(xrefBlocks) {
var num = xrefBlocks.length / 2; const num = xrefBlocks.length / 2;
var retVal = []; const retVal = [];
for (var i=0;i<num;i++) { for (let i = 0; i < num; i++) {
retVal.push({start: xrefBlocks[i], end: xrefBlocks[i+num]}); retVal.push({start: xrefBlocks[i],
} end: xrefBlocks[i + num]});
return retVal; }
return retVal;
} }
function convertUint8ArrayToBinaryString(u8Array) { function convertUint8ArrayToBinaryString(u8Array) {
var i, len = u8Array.length, b_str = ""; let i, len = u8Array.length, bStr = "";
for (i=0; i<len; i++) { for (i = 0; i < len; i++) {
b_str += String.fromCharCode(u8Array[i]); bStr += String.fromCharCode(u8Array[i]);
} }
return b_str; return bStr;
} }
function arrayObjectIndexOf(array, start, end, orig) { function arrayObjectIndexOf(array, start, end, orig) {
for(var i = 0, len = array.length; i < len; i++) { for (let i = 0, len = array.length; i < len; i++) {
if ((array[i].start === start) && (array[i].end === end) && (array[i].orig === orig)) { if ((array[i].start === start) && (array[i].end === end) && (array[i].orig === orig)) {
return i; return i;
}
} }
return -1; }
return -1;
} }
function pad10(num) { function pad10(num) {
var s = "000000000" + num; const s = "000000000" + num;
return s.substr(s.length-10); return s.substr(s.length - 10);
} }
function pad5(num) { function pad5(num) {
var s = "0000" + num; const s = "0000" + num;
return s.substr(s.length-5); return s.substr(s.length - 5);
} }
function pad2(num) { function pad2(num) {
var s = "0" + num; const s = "0" + num;
return s.substr(s.length-2); return s.substr(s.length - 2);
} }
function findRootEntry(xref) { function findRootEntry(xref) {
var rootNr = xref.root.objId.substring(0, xref.root.objId.length - 1); const rootNr = xref.root.objId.substring(0, xref.root.objId.length - 1);
return xref.entries[rootNr]; return xref.entries[rootNr];
} }
function findSuccessorEntry(xrefEntries, current) { function findSuccessorEntry(xrefEntries, current) {
//find it first //find it first
var currentOffset = current.offset; const currentOffset = current.offset;
var currentMin = Number.MAX_SAFE_INTEGER; let currentMin = Number.MAX_SAFE_INTEGER;
var currentMinIndex = -1; let currentMinIndex = -1;
for(var i in xrefEntries) { for (const i in xrefEntries) {
if(xrefEntries[i].offset > currentOffset) { if (xrefEntries[i].offset > currentOffset) {
if(xrefEntries[i].offset < currentMin) { if (xrefEntries[i].offset < currentMin) {
currentMin = xrefEntries[i].offset; currentMin = xrefEntries[i].offset;
currentMinIndex = i; currentMinIndex = i;
} }
} }
} }
if(currentMinIndex === -1) { if (currentMinIndex === -1) {
return current; return current;
} }
return xrefEntries[currentMinIndex]; return xrefEntries[currentMinIndex];
} }
function updateArray(array, pos, str) { function updateArray(array, pos, str) {
var upd = stringToUint8Array(str); const upd = stringToUint8Array(str);
for (var i = 0, len=upd.length; i < len; i++) { for (let i = 0, len = upd.length; i < len; i++) {
array[i+pos] = upd[i]; array[i + pos] = upd[i];
} }
return array; return array;
} }
function copyToEnd(array, from, to) { function copyToEnd(array, from, to) {
var buf = new Uint8Array(array.length + (to - from)); const buf = new Uint8Array(array.length + (to - from));
for (var i = 0, len=array.length; i < len; i++) { for (let i = 0, len = array.length; i < len; i++) {
buf[i] = array[i]; buf[i] = array[i];
} }
for (var i = 0, len=(to - from); i < len; i++) { for (let i = 0, len = to - from; i < len; i++) {
buf[array.length + i] = array[from + i]; buf[array.length + i] = array[from + i];
} }
return buf; return buf;
} }
function insertIntoArray(array, pos, str) { function insertIntoArray(array, pos, str) {
var ins = stringToUint8Array(str); const ins = stringToUint8Array(str);
var buf = new Uint8Array(array.length + ins.length); const buf = new Uint8Array(array.length + ins.length);
for (var i = 0; i < pos; i++) { for (let i = 0; i < pos; i++) {
buf[i] = array[i]; buf[i] = array[i];
} }
for (var i = 0; i < ins.length; i++) { for (let i = 0; i < ins.length; i++) {
buf[pos+i] = ins[i]; buf[pos + i] = ins[i];
} }
for (var i = pos; i < array.length; i++) { for (let i = pos; i < array.length; i++) {
buf[ins.length+i] = array[i]; buf[ins.length + i] = array[i];
} }
return buf; return buf;
} }
function stringToUint8Array(str) { function stringToUint8Array(str) {
var buf = new Uint8Array(str.length); const buf = new Uint8Array(str.length);
for (var i=0, strLen=str.length; i<strLen; i++) { for (let i = 0, strLen = str.length; i < strLen; i++) {
buf[i] = str.charCodeAt(i); buf[i] = str.charCodeAt(i);
} }
return buf; return buf;
} }
function uint8ArrayToString(buf, from, to) { function uint8ArrayToString(buf, from, to) {
if(typeof from !== 'undefined' && typeof to !== 'undefined') { if (typeof from !== 'undefined' && typeof to !== 'undefined') {
var s = ''; let s = '';
for (var i=from; i<to; i++) { for (let i = from; i < to; i++) {
s = s + String.fromCharCode(buf[i]); s = s + String.fromCharCode(buf[i]);
}
return s;
} }
return String.fromCharCode.apply(null, buf); return s;
}
return String.fromCharCode.apply(null, buf);
} }
function findFreeXrefNr(xrefEntries, used) { function findFreeXrefNr(xrefEntries, used) {
used = typeof used !== 'undefined' ? used : []; used = typeof used !== 'undefined' ? used : [];
var inc = used.length; let inc = used.length;
for (var i=1;i<xrefEntries.length;i++) { for (let i = 1; i < xrefEntries.length; i++) {
const index = used.indexOf(i);
var index = used.indexOf(i); const entry = xrefEntries["" + i];
var entry = xrefEntries[""+i]; if (index === -1 && (typeof entry === 'undefined' || entry.free)) {
if(index === -1 && (typeof entry === 'undefined' || entry.free)) { return i;
return i; }
} if (index !== -1) {
if(index !== -1) { inc--;
inc--;
}
} }
return xrefEntries.length + inc; }
return xrefEntries.length + inc;
} }
function find(uint8, needle, start, limit) { function find(uint8, needle, start, limit) {
start = typeof start !== 'undefined' ? start : 0; start = typeof start !== 'undefined' ? start : 0;
limit = typeof limit !== 'undefined' ? limit : Number.MAX_SAFE_INTEGER; limit = typeof limit !== 'undefined' ? limit : Number.MAX_SAFE_INTEGER;
var search = stringToUint8Array(needle); const search = stringToUint8Array(needle);
var match = 0; let match = 0;
for(var i=start;i<uint8.length && i<limit;i++) { for (let i = start; i < uint8.length && i < limit; i++) {
if(uint8[i] === search[match]) { if (uint8[i] === search[match]) {
match++; match++;
} else { } else {
match = 0; match = 0;
if(uint8[i] === search[match]) { if (uint8[i] === search[match]) {
match++; match++;
} }
} }
if(match === search.length) { if (match === search.length) {
return (i + 1) - match; return (i + 1) - match;
}
} }
return -1; }
return -1;
} }
function findBackwards(uint8, needle, start, limit) { function findBackwards(uint8, needle, start, limit) {
start = typeof start !== 'undefined' ? start : uint8.length; start = typeof start !== 'undefined' ? start : uint8.length;
limit = typeof limit !== 'undefined' ? limit : Number.MAX_SAFE_INTEGER; limit = typeof limit !== 'undefined' ? limit : Number.MAX_SAFE_INTEGER;
var search = stringToUint8Array(needle); const search = stringToUint8Array(needle);
var match = search.length - 1; let match = search.length - 1;
for(var i=start;i>=0 && i<limit;i--) { for (let i = start; i >= 0 && i < limit; i--) {
if(uint8[i] === search[match]) { if (uint8[i] === search[match]) {
match--; match--;
} else { } else {
match = search.length - 1; match = search.length - 1;
if(uint8[i] === search[match]) { if (uint8[i] === search[match]) {
match--; match--;
} }
}
if(match === 0) {
return i - 1;
}
} }
return -1;
} if (match === 0) {
return i - 1;
function strHex(s) {
var a = "";
for( var i=0; i<s.length; i++ ) {
a = a + pad2(s.charCodeAt(i).toString(16));
} }
return a; }
return -1;
} }
function strHex(s) {
let a = "";
for (let i = 0; i < s.length; i++) {
a = a + pad2(s.charCodeAt(i).toString(16));
}
return a;
}
async function sha256(array) { async function sha256(array) {
const cryptoLib = getCrypto();
const cryptoLib = getCrypto(); const digestTmpBuf = await cryptoLib.digest({ name: "SHA-256" }, array);
const digestTmpBuf = await cryptoLib.digest({ name: "SHA-256" }, array); const digestTmpArray = new Uint8Array(digestTmpBuf);
const digestTmpArray = new Uint8Array(digestTmpBuf); const digestTmpStr = uint8ArrayToString(digestTmpArray);
const digestTmpStr = uint8ArrayToString(digestTmpArray); const sha256Hex = strHex(digestTmpStr);
const sha256Hex = strHex(digestTmpStr); return sha256Hex;
return sha256Hex;
} }
function isSigInRoot(pdf) { function isSigInRoot(pdf) {
if (typeof pdf.acroForm === 'undefined') { if (typeof pdf.acroForm === 'undefined') {
return false; return false;
} }
return pdf.acroForm.get('SigFlags') === 3; return pdf.acroForm.get('SigFlags') === 3;
} }
function updateXrefOffset(xref, offset, offsetDelta) { function updateXrefOffset(xref, offset, offsetDelta) {
for(var i in xref.entries) { for (const i in xref.entries) {
if(xref.entries[i].offset >= offset) { if (xref.entries[i].offset >= offset) {
xref.entries[i].offset += offsetDelta; xref.entries[i].offset += offsetDelta;
}
} }
for(var i in xref.xrefBlocks) { }
if(xref.xrefBlocks[i] >= offset) { for (const i in xref.xrefBlocks) {
xref.xrefBlocks[i] += offsetDelta; if (xref.xrefBlocks[i] >= offset) {
} xref.xrefBlocks[i] += offsetDelta;
} }
}
} }
function updateXrefBlocks(xrefBlocks, offset, offsetDelta) { function updateXrefBlocks(xrefBlocks, offset, offsetDelta) {
for(var i in xrefBlocks) { for (const i in xrefBlocks) {
if(xrefBlocks[i].start >= offset) { if (xrefBlocks[i].start >= offset) {
xrefBlocks[i].start += offsetDelta; xrefBlocks[i].start += offsetDelta;
} }
if(xrefBlocks[i].end >= offset) { if (xrefBlocks[i].end >= offset) {
xrefBlocks[i].end += offsetDelta; xrefBlocks[i].end += offsetDelta;
}
} }
}
} }
function updateOffset(pos, offset, offsetDelta) { function updateOffset(pos, offset, offsetDelta) {
if(pos >= offset) { if (pos >= offset) {
return pos + offsetDelta; return pos + offsetDelta;
} }
return pos; return pos;
} }
function round256(x) { function round256(x) {
return (Math.ceil(x/256)*256) - 1; return (Math.ceil(x / 256) * 256) - 1;
} }
/** /**
...@@ -387,349 +382,359 @@ function round256(x) { ...@@ -387,349 +382,359 @@ function round256(x) {
* mm shall be the absolute value of the offset from UT in minutes (00–59) * mm shall be the absolute value of the offset from UT in minutes (00–59)
*/ */
function now(date) { function now(date) {
//date = typeof date !== 'undefined' ? date : new Date(); //date = typeof date !== 'undefined' ? date : new Date();
var yyyy = date.getFullYear().toString(); const yyyy = date.getFullYear().toString();
var MM = pad2(date.getMonth() + 1); const MM = pad2(date.getMonth() + 1);
var dd = pad2(date.getDate()); const dd = pad2(date.getDate());
var hh = pad2(date.getHours()); const hh = pad2(date.getHours());
var mm = pad2(date.getMinutes()); const mm = pad2(date.getMinutes());
var ss = pad2(date.getSeconds()); const ss = pad2(date.getSeconds());
return yyyy + MM + dd+ hh + mm + ss + createOffset(date); return yyyy + MM + dd + hh + mm + ss + createOffset(date);
} }
function createOffset(date) { function createOffset(date) {
var sign = (date.getTimezoneOffset() > 0) ? "-" : "+"; const sign = date.getTimezoneOffset() > 0 ? "-" : "+";
var offset = Math.abs(date.getTimezoneOffset()); const offset = Math.abs(date.getTimezoneOffset());
var hours = pad2(Math.floor(offset / 60)); const hours = pad2(Math.floor(offset / 60));
var minutes = pad2(offset % 60); const minutes = pad2(offset % 60);
return sign + hours + "'" + minutes; return sign + hours + "'" + minutes;
} }
async function newSig(pdf, root, rootSuccessor, date, signingCert, certificateChain, privateKey) { async function newSig(pdf, root, rootSuccessor, date, signingCert, certificateChain, privateKey) {
// {annotEntry} is the ref to the annot widget. If we enlarge the array, make sure all the offsets // {annotEntry} is the ref to the annot widget. If we enlarge the array, make sure all the offsets
// after the modification will be updated -> xref table and startxref // after the modification will be updated -> xref table and startxref
var annotEntry = findFreeXrefNr(pdf.xref.entries); const annotEntry = findFreeXrefNr(pdf.xref.entries);
// we'll store all the modifications we make, as we need to adjust the offset in the PDF // we'll store all the modifications we make, as we need to adjust the offset in the PDF
var offsetForm = find(pdf.stream.bytes, '<<', root.offset, rootSuccessor.offset) + 2; const offsetForm = find(pdf.stream.bytes, '<<', root.offset, rootSuccessor.offset) + 2;
//first we need to find the root element and add the following: //first we need to find the root element and add the following:
// //
// /AcroForm<</Fields[{annotEntry} 0 R] /SigFlags 3>> // /AcroForm<</Fields[{annotEntry} 0 R] /SigFlags 3>>
// //
var appendAcroForm = '/AcroForm<</Fields['+annotEntry+' 0 R] /SigFlags 3>>'; const appendAcroForm = '/AcroForm<</Fields[' + annotEntry + ' 0 R] /SigFlags 3>>';
//before we insert the acroform, we find the right place for annotentry //before we insert the acroform, we find the right place for annotentry
//we need to add Annots [x y R] to the /Type /Page section. We can do that by searching /Contents[ //we need to add Annots [x y R] to the /Type /Page section. We can do that by searching /Contents[
var pages = pdf.catalog.catDict.get('Pages'); const pages = pdf.catalog.catDict.get('Pages');
//get first page, we have hidden sig, so don't bother //get first page, we have hidden sig, so don't bother
var ref = pages.get('Kids')[0]; const ref = pages.get('Kids')[0];
var xref = pdf.xref.fetch(ref); const xref = pdf.xref.fetch(ref);
var offsetContentEnd = xref.get('#Contents_offset'); const offsetContentEnd = xref.get('#Contents_offset');
//we now search backwards, this is safe as we don't expect user content here //we now search backwards, this is safe as we don't expect user content here
var offsetContent = findBackwards(pdf.stream.bytes, '/Contents', offsetContentEnd); let offsetContent = findBackwards(pdf.stream.bytes, '/Contents', offsetContentEnd);
var appendAnnots = '/Annots['+annotEntry+' 0 R]\n '; const appendAnnots = '/Annots[' + annotEntry + ' 0 R]\n ';
//now insert string into stream //now insert string into stream
var array = insertIntoArray(pdf.stream.bytes, offsetForm, appendAcroForm); let array = insertIntoArray(pdf.stream.bytes, offsetForm, appendAcroForm);
//recalculate the offsets in the xref table, only update those that are affected //recalculate the offsets in the xref table, only update those that are affected
updateXrefOffset(pdf.xref, offsetForm, appendAcroForm.length); updateXrefOffset(pdf.xref, offsetForm, appendAcroForm.length);
offsetContent = updateOffset(offsetContent, offsetForm, appendAcroForm.length); offsetContent = updateOffset(offsetContent, offsetForm, appendAcroForm.length);
var array = insertIntoArray(array, offsetContent, appendAnnots); array = insertIntoArray(array, offsetContent, appendAnnots);
updateXrefOffset(pdf.xref, offsetContent, appendAnnots.length); updateXrefOffset(pdf.xref, offsetContent, appendAnnots.length);
offsetContent = -1; //not needed anymore, don't update when offset changes offsetContent = -1; //not needed anymore, don't update when offset changes
//Then add to the next free object (annotEntry) //Then add to the next free object (annotEntry)
//add right before the xref table or stream //add right before the xref table or stream
//if its a table, place element before the xref table //if its a table, place element before the xref table
// //
// sigEntry is the ref to the signature content. Next we need the signature object // sigEntry is the ref to the signature content. Next we need the signature object
var sigEntry = findFreeXrefNr(pdf.xref.entries, [annotEntry]); const sigEntry = findFreeXrefNr(pdf.xref.entries, [annotEntry]);
// //
// {annotEntry} 0 obj // {annotEntry} 0 obj
// <</F 132/Type/Annot/Subtype/Widget/Rect[0 0 0 0]/FT/Sig/DR<<>>/T(signature)/V Y 0 R>> // <</F 132/Type/Annot/Subtype/Widget/Rect[0 0 0 0]/FT/Sig/DR<<>>/T(signature)/V Y 0 R>>
// endobj // endobj
// //
var append = annotEntry + ' 0 obj\n<</F 132/Type/Annot/Subtype/Widget/Rect[0 0 0 0]/FT/Sig/DR<<>>/T(signature'+annotEntry+')/V '+sigEntry+' 0 R>>\nendobj\n\n'; const append = annotEntry + ' 0 obj\n<</F 132/Type/Annot/Subtype/Widget/Rect[0 0 0 0]/FT/Sig/DR<<>>/T(signature' + annotEntry + ')/V ' + sigEntry + ' 0 R>>\nendobj\n\n';
// we want the offset just before the last xref table or entry // we want the offset just before the last xref table or entry
var blocks = findXrefBlocks(pdf.xref.xrefBlocks); const blocks = findXrefBlocks(pdf.xref.xrefBlocks);
var offsetAnnot = blocks[0].start; let offsetAnnot = blocks[0].start;
array = insertIntoArray(array, offsetAnnot, append); array = insertIntoArray(array, offsetAnnot, append);
//no updateXrefOffset, as the next entry will be following //no updateXrefOffset, as the next entry will be following
// //
// {sigEntry} 0 obj // {sigEntry} 0 obj
// <</Contents <0481801e6d931d561563fb254e27c846e08325570847ed63d6f9e35 ... b2c8788a5> // <</Contents <0481801e6d931d561563fb254e27c846e08325570847ed63d6f9e35 ... b2c8788a5>
// /Type/Sig/SubFilter/adbe.pkcs7.detached/Location(Ghent)/M(D:20120928104114+02'00') // /Type/Sig/SubFilter/adbe.pkcs7.detached/Location(Ghent)/M(D:20120928104114+02'00')
// /ByteRange [A B C D]/Filter/Adobe.PPKLite/Reason(Test)/ContactInfo()>> // /ByteRange [A B C D]/Filter/Adobe.PPKLite/Reason(Test)/ContactInfo()>>
// endobj // endobj
// //
//the next entry goes below the above //the next entry goes below the above
var offsetSig = offsetAnnot + append.length; let offsetSig = offsetAnnot + append.length;
// Both {annotEntry} and {sigEntry} objects need to be added to the last xref table. The byte range needs // Both {annotEntry} and {sigEntry} objects need to be added to the last xref table. The byte range needs
// to be adjusted. Since the signature will always be in a gap, use first an empty sig // to be adjusted. Since the signature will always be in a gap, use first an empty sig
// to check the size, add ~25% size, then calculate the signature and place in the empty // to check the size, add ~25% size, then calculate the signature and place in the empty
// space. // space.
var start = sigEntry+ ' 0 obj\n<</Contents <'; const start = sigEntry + ' 0 obj\n<</Contents <';
var dummy = await sign_pki(signingCert, certificateChain, privateKey, stringToUint8Array('A'), date); const dummy = await signPki(signingCert, certificateChain, privateKey, stringToUint8Array('A'), date);
//TODO: Adobe thinks its important to have the right size, no idea why this is the case //TODO: Adobe thinks its important to have the right size, no idea why this is the case
var crypto = new Array(round256(dummy.length * 2)).join( '0' ); const crypto = new Array(round256(dummy.length * 2)).join('0');
var middle = '>\n/Type/Sig/SubFilter/adbe.pkcs7.detached/Location()/M(D:'+now(date)+'\')\n/ByteRange '; const middle = '>\n/Type/Sig/SubFilter/adbe.pkcs7.detached/Location()/M(D:' + now(date) + '\')\n/ByteRange ';
var byteRange = '[0000000000 0000000000 0000000000 0000000000]'; let byteRange = '[0000000000 0000000000 0000000000 0000000000]';
var end = '/Filter/Adobe.PPKLite/Reason()/ContactInfo()>>\nendobj\n\n'; const end = '/Filter/Adobe.PPKLite/Reason()/ContactInfo()>>\nendobj\n\n';
//all together //all together
var append2 = start+crypto+middle+byteRange+end; const append2 = start + crypto + middle + byteRange + end;
var offsetByteRange = start.length+crypto.length+middle.length; const offsetByteRange = start.length + crypto.length + middle.length;
array = insertIntoArray(array, offsetSig, append2); array = insertIntoArray(array, offsetSig, append2);
updateXrefOffset(pdf.xref, offsetAnnot, append2.length + append.length); updateXrefOffset(pdf.xref, offsetAnnot, append2.length + append.length);
//find the xref tables, remove them and also the EOF, as we'll write a new table //find the xref tables, remove them and also the EOF, as we'll write a new table
var xrefBlocks = findXrefBlocks(pdf.xref.xrefBlocks); const xrefBlocks = findXrefBlocks(pdf.xref.xrefBlocks);
for(var i in xrefBlocks) { for (const i in xrefBlocks) {
var oldSize = array.length; const oldSize = array.length;
array = removeFromArray(array, xrefBlocks[i].start, xrefBlocks[i].end); array = removeFromArray(array, xrefBlocks[i].start, xrefBlocks[i].end);
var length = array.length - oldSize; const length = array.length - oldSize;
updateXrefOffset(pdf.xref, xrefBlocks[i].start, length); updateXrefOffset(pdf.xref, xrefBlocks[i].start, length);
//check for %%EOF and remove it as well //check for %%EOF and remove it as well
var offsetEOF = find(array, '%%EOF', xrefBlocks[i].start, xrefBlocks[i].start+20); const offsetEOF = find(array, '%%EOF', xrefBlocks[i].start, xrefBlocks[i].start + 20);
if(offsetEOF > 0) { if (offsetEOF > 0) {
var lengthEOF = '%%EOF'.length; const lengthEOF = '%%EOF'.length;
array = removeFromArray(array, offsetEOF, offsetEOF + lengthEOF); array = removeFromArray(array, offsetEOF, offsetEOF + lengthEOF);
updateXrefOffset(pdf.xref, offsetEOF, -lengthEOF); updateXrefOffset(pdf.xref, offsetEOF, -lengthEOF);
updateXrefBlocks(xrefBlocks, offsetEOF, -lengthEOF); updateXrefBlocks(xrefBlocks, offsetEOF, -lengthEOF);
offsetAnnot = updateOffset(offsetAnnot, offsetEOF, -lengthEOF); offsetAnnot = updateOffset(offsetAnnot, offsetEOF, -lengthEOF);
offsetSig = updateOffset(offsetSig, offsetEOF, -lengthEOF); offsetSig = updateOffset(offsetSig, offsetEOF, -lengthEOF);
} }
updateXrefBlocks(xrefBlocks, xrefBlocks[i].start, length); updateXrefBlocks(xrefBlocks, xrefBlocks[i].start, length);
offsetAnnot = updateOffset(offsetAnnot, xrefBlocks[i].start, length); offsetAnnot = updateOffset(offsetAnnot, xrefBlocks[i].start, length);
offsetSig = updateOffset(offsetSig, xrefBlocks[i].start, length); offsetSig = updateOffset(offsetSig, xrefBlocks[i].start, length);
} }
var sha256Hex = await sha256(array); const sha256Hex = await sha256(array);
//add the new entries to the xref //add the new entries to the xref
pdf.xref.entries[annotEntry] = {offset:offsetAnnot, gen:0, free:false}; pdf.xref.entries[annotEntry] = {offset: offsetAnnot,
pdf.xref.entries[sigEntry] = {offset:offsetSig, gen:0, free:false}; gen: 0,
free: false};
var xrefTable = createXrefTable(pdf.xref.entries); pdf.xref.entries[sigEntry] = {offset: offsetSig,
//also empty entries count as in the PDF spec, page 720 (example) gen: 0,
xrefTable += createTrailer(pdf.xref.topDict, array.length, sha256Hex, pdf.xref.entries.length); free: false};
array = insertIntoArray(array, array.length, xrefTable);
let xrefTable = createXrefTable(pdf.xref.entries);
//since we consolidate, no prev! [adjust /Prev -> rawparsing + offset] //also empty entries count as in the PDF spec, page 720 (example)
var from1 = 0; xrefTable += createTrailer(pdf.xref.topDict, array.length, sha256Hex, pdf.xref.entries.length);
var to1 = offsetSig+start.length; array = insertIntoArray(array, array.length, xrefTable);
var from2 = to1 + crypto.length;
var to2 = (array.length - from2) - 1; //since we consolidate, no prev! [adjust /Prev -> rawparsing + offset]
var byteRange = '['+pad10(from1)+' '+pad10(to1 - 1) + ' ' +pad10(from2 + 1)+ ' ' + pad10(to2) + ']'; const from1 = 0;
array = updateArray(array, (offsetSig + offsetByteRange), byteRange); const to1 = offsetSig + start.length;
var data = removeFromArray(array, to1 - 1, from2 + 1); const from2 = to1 + crypto.length;
var crypto2 = await sign_pki(signingCert, certificateChain, privateKey, data.buffer, date); const to2 = (array.length - from2) - 1;
array = updateArray(array, to1, crypto2); byteRange = '[' + pad10(from1) + ' ' + pad10(to1 - 1) + ' ' + pad10(from2 + 1) + ' ' + pad10(to2) + ']';
return array; array = updateArray(array, offsetSig + offsetByteRange, byteRange);
const data = removeFromArray(array, to1 - 1, from2 + 1);
const crypto2 = await signPki(signingCert, certificateChain, privateKey, data.buffer, date);
array = updateArray(array, to1, crypto2);
return array;
} }
async function appendSig(pdf, root, rootSuccessor, date, signingCert, certificateChain, privateKey) { async function appendSig(pdf, root, rootSuccessor, date, signingCert, certificateChain, privateKey) {
//copy root and the entry with contents to the end //copy root and the entry with contents to the end
var startRoot = pdf.stream.bytes.length + 1; const startRoot = pdf.stream.bytes.length + 1;
var array = copyToEnd(pdf.stream.bytes, root.offset - 1, rootSuccessor.offset); let array = copyToEnd(pdf.stream.bytes, root.offset - 1, rootSuccessor.offset);
//since we signed the first one, we know how the pdf has to look like: //since we signed the first one, we know how the pdf has to look like:
var offsetAcroForm = find(array, '/AcroForm<</Fields', startRoot); const offsetAcroForm = find(array, '/AcroForm<</Fields', startRoot);
var endOffsetAcroForm = find(array, ']', offsetAcroForm); const endOffsetAcroForm = find(array, ']', offsetAcroForm);
var annotEntry = findFreeXrefNr(pdf.xref.entries); const annotEntry = findFreeXrefNr(pdf.xref.entries);
var sigEntry = findFreeXrefNr(pdf.xref.entries, [annotEntry]); const sigEntry = findFreeXrefNr(pdf.xref.entries, [annotEntry]);
var appendAnnot = ' ' + annotEntry + ' 0 R'; const appendAnnot = ' ' + annotEntry + ' 0 R';
array = insertIntoArray(array, endOffsetAcroForm, appendAnnot); array = insertIntoArray(array, endOffsetAcroForm, appendAnnot);
//we need to add Annots [x y R] to the /Type /Page section. We can do that by searching /Annots //we need to add Annots [x y R] to the /Type /Page section. We can do that by searching /Annots
var pages = pdf.catalog.catDict.get('Pages'); const pages = pdf.catalog.catDict.get('Pages');
//get first page, we have hidden sig, so don't bother //get first page, we have hidden sig, so don't bother
var contentRef = pages.get('Kids')[0]; const contentRef = pages.get('Kids')[0];
var xref = pdf.xref.fetch(contentRef); const xref = pdf.xref.fetch(contentRef);
var offsetAnnotEnd = xref.get('#Annots_offset'); const offsetAnnotEnd = xref.get('#Annots_offset');
//we now search ], this is safe as we signed it previously //we now search ], this is safe as we signed it previously
var endOffsetAnnot = find(array, ']', offsetAnnotEnd); const endOffsetAnnot = find(array, ']', offsetAnnotEnd);
var xrefEntry = pdf.xref.getEntry(contentRef.num); const xrefEntry = pdf.xref.getEntry(contentRef.num);
var xrefEntrySuccosser = findSuccessorEntry(pdf.xref.entries, xrefEntry); const xrefEntrySuccosser = findSuccessorEntry(pdf.xref.entries, xrefEntry);
var offsetAnnotRelative = endOffsetAnnot - xrefEntrySuccosser.offset; const offsetAnnotRelative = endOffsetAnnot - xrefEntrySuccosser.offset;
var startContent = array.length; const startContent = array.length;
array = copyToEnd(array, xrefEntry.offset, xrefEntrySuccosser.offset); array = copyToEnd(array, xrefEntry.offset, xrefEntrySuccosser.offset);
array = insertIntoArray(array, array.length + offsetAnnotRelative, appendAnnot); array = insertIntoArray(array, array.length + offsetAnnotRelative, appendAnnot);
var startAnnot = array.length; const startAnnot = array.length;
var append = annotEntry + ' 0 obj\n<</F 132/Type/Annot/Subtype/Widget/Rect[0 0 0 0]/FT/Sig/DR<<>>/T(signature'+annotEntry+')/V '+sigEntry+' 0 R>>\nendobj\n\n'; const append = annotEntry + ' 0 obj\n<</F 132/Type/Annot/Subtype/Widget/Rect[0 0 0 0]/FT/Sig/DR<<>>/T(signature' + annotEntry + ')/V ' + sigEntry + ' 0 R>>\nendobj\n\n';
array = insertIntoArray(array, startAnnot, append); array = insertIntoArray(array, startAnnot, append);
var startSig = array.length; const startSig = array.length;
var start = sigEntry+ ' 0 obj\n<</Contents <'; const start = sigEntry + ' 0 obj\n<</Contents <';
var dummy = await sign_pki(signingCert, certificateChain, privateKey, stringToUint8Array('A'), date); const dummy = await signPki(signingCert, certificateChain, privateKey, stringToUint8Array('A'), date);
//TODO: Adobe thinks its important to have the right size, no idea why this is the case //TODO: Adobe thinks its important to have the right size, no idea why this is the case
var crypto = new Array(round256(dummy.length * 2)).join( '0' ); const crypto = new Array(round256(dummy.length * 2)).join('0');
var middle = '>\n/Type/Sig/SubFilter/adbe.pkcs7.detached/Location()/M(D:'+now(date)+'\')\n/ByteRange '; const middle = '>\n/Type/Sig/SubFilter/adbe.pkcs7.detached/Location()/M(D:' + now(date) + '\')\n/ByteRange ';
var byteRange = '[0000000000 0000000000 0000000000 0000000000]'; let byteRange = '[0000000000 0000000000 0000000000 0000000000]';
var end = '/Filter/Adobe.PPKLite/Reason()/ContactInfo()>>\nendobj\n\n'; const end = '/Filter/Adobe.PPKLite/Reason()/ContactInfo()>>\nendobj\n\n';
//all together //all together
var append2 = start+crypto+middle+byteRange+end; const append2 = start + crypto + middle + byteRange + end;
array = insertIntoArray(array, startSig, append2); array = insertIntoArray(array, startSig, append2);
var sha256Hex = await sha256(array); const sha256Hex = await sha256(array);
var prev = pdf.xref.xrefBlocks[0]; const prev = pdf.xref.xrefBlocks[0];
var startxref = array.length; const startxref = array.length;
var xrefEntries = []; const xrefEntries = [];
xrefEntries[0] = {offset:0, gen:65535, free:true}; xrefEntries[0] = {offset: 0,
xrefEntries[pdf.xref.topDict.getRaw('Root').num] = {offset:startRoot, gen:0, free:false}; gen: 65535,
xrefEntries[contentRef.num] = {offset:startContent, gen:0, free:false}; free: true};
xrefEntries[annotEntry] = {offset:startAnnot, gen:0, free:false}; xrefEntries[pdf.xref.topDict.getRaw('Root').num] = {offset: startRoot,
xrefEntries[sigEntry] = {offset:startSig, gen:0, free:false}; gen: 0,
var xrefTable = createXrefTableAppend(xrefEntries); free: false};
xrefTable += createTrailer(pdf.xref.topDict, startxref, sha256Hex, xrefEntries.length, prev); xrefEntries[contentRef.num] = {offset: startContent,
array = insertIntoArray(array, array.length, xrefTable); gen: 0,
free: false};
var from1 = 0; xrefEntries[annotEntry] = {offset: startAnnot,
var to1 = startSig + start.length; gen: 0,
var from2 = to1 + crypto.length; free: false};
var to2 = (array.length - from2) - 1; xrefEntries[sigEntry] = {offset: startSig,
var byteRange = '['+pad10(from1)+' '+pad10(to1 - 1) + ' ' +pad10(from2 + 1)+ ' ' + pad10(to2) + ']'; gen: 0,
free: false};
array = updateArray(array, from2 + middle.length, byteRange); let xrefTable = createXrefTableAppend(xrefEntries);
//now sign from1-to1 / from2-to2 and update byterange xrefTable += createTrailer(pdf.xref.topDict, startxref, sha256Hex, xrefEntries.length, prev);
array = insertIntoArray(array, array.length, xrefTable);
var data = removeFromArray(array, to1 - 1, from2 + 1);
var crypto2 = await sign_pki(signingCert, certificateChain, privateKey, data.buffer, date); const from1 = 0;
array = updateArray(array, to1, crypto2); const to1 = startSig + start.length;
return array; const from2 = to1 + crypto.length;
const to2 = (array.length - from2) - 1;
byteRange = '[' + pad10(from1) + ' ' + pad10(to1 - 1) + ' ' + pad10(from2 + 1) + ' ' + pad10(to2) + ']';
array = updateArray(array, from2 + middle.length, byteRange);
//now sign from1-to1 / from2-to2 and update byterange
const data = removeFromArray(array, to1 - 1, from2 + 1);
const crypto2 = await signPki(signingCert, certificateChain, privateKey, data.buffer, date);
array = updateArray(array, to1, crypto2);
return array;
} }
function loadPdf(pdfArray) { function loadPdf(pdfArray) {
var pdf = new pdfjsCoreDocument.PDFDocument(false, pdfArray, ''); const pdf = new pdfjsCoreDocument.PDFDocument(false, pdfArray, '');
pdf.parseStartXRef(); pdf.parseStartXRef();
pdf.parse(); pdf.parse();
return pdf; return pdf;
} }
//data must be Uint8Array //data must be Uint8Array
async function sign_pki(signingCert, certificateChain, privateKey, data, date) { async function signPki(signingCert, certificateChain, privateKey, data, date) {
const crypto = getCrypto();
const crypto = getCrypto();
//date = typeof date !== 'undefined' ? date : new Date();
//date = typeof date !== 'undefined' ? date : new Date();
const hashAlg = "SHA-256";
const hashAlg = "SHA-256";
const digest = await crypto.digest({ name: hashAlg }, data);
const digest = await crypto.digest({ name: hashAlg }, data);
const signedAttr = [];
const signedAttr = [];
signedAttr.push(new Attribute({
signedAttr.push(new Attribute({ type: "1.2.840.113549.1.9.3",
type: "1.2.840.113549.1.9.3", values: [
values: [ new ObjectIdentifier({ value: "1.2.840.113549.1.7.1" })
new ObjectIdentifier({ value: "1.2.840.113549.1.7.1" }) ]
] })); // contentType
})); // contentType
signedAttr.push(new Attribute({
signedAttr.push(new Attribute({ type: "1.2.840.113549.1.9.4",
type: "1.2.840.113549.1.9.4", values: [
values: [ new OctetString({ valueHex: digest })
new OctetString({ valueHex: digest }) ]
] })); // messageDigest
})); // messageDigest
signedAttr.push(new Attribute({
signedAttr.push(new Attribute({ type: "1.2.840.113549.1.9.5",
type: "1.2.840.113549.1.9.5", values: [
values: [ new UTCTime({ valueDate: date })
new UTCTime({ valueDate: date }) ]
] })); // signingTime
})); // signingTime
const cmsSignedSimpl = new SignedData({
const cmsSignedSimpl = new SignedData({ version: 1,
encapContentInfo: new EncapsulatedContentInfo({
eContentType: "1.2.840.113549.1.7.1" // "data" content type
}),
signerInfos: [
new SignerInfo({
version: 1, version: 1,
encapContentInfo: new EncapsulatedContentInfo({ sid: new IssuerAndSerialNumber({
eContentType: "1.2.840.113549.1.7.1" // "data" content type issuer: signingCert.issuer,
serialNumber: signingCert.serialNumber
}), }),
signerInfos: [ signedAttrs: new SignedAndUnsignedAttributes({
new SignerInfo({ type: 0,
version: 1, attributes: signedAttr
sid: new IssuerAndSerialNumber({ })
issuer: signingCert.issuer, })
serialNumber: signingCert.serialNumber ],
}), certificates: certificateChain
signedAttrs: new SignedAndUnsignedAttributes({ });
type: 0,
attributes: signedAttr
})
})
],
certificates: certificateChain
});
const signatureBuffer = await cmsSignedSimpl.sign(privateKey, 0, hashAlg, data.buffer); await cmsSignedSimpl.sign(privateKey, 0, hashAlg, data.buffer);
const cmsSignedSchema = cmsSignedSimpl.toSchema(true); const cmsSignedSchema = cmsSignedSimpl.toSchema(true);
const cmsContentSimp = new ContentInfo({ const cmsContentSimp = new ContentInfo({
contentType: "1.2.840.113549.1.7.2", contentType: "1.2.840.113549.1.7.2",
content: cmsSignedSchema content: cmsSignedSchema
}); });
const _cmsSignedSchema = cmsContentSimp.toSchema(); const _cmsSignedSchema = cmsContentSimp.toSchema();
//region Make length of some elements in "indefinite form" //region Make length of some elements in "indefinite form"
_cmsSignedSchema.lenBlock.isIndefiniteForm = true; _cmsSignedSchema.lenBlock.isIndefiniteForm = true;
const block1 = _cmsSignedSchema.valueBlock.value[1]; const block1 = _cmsSignedSchema.valueBlock.value[1];
block1.lenBlock.isIndefiniteForm = true; block1.lenBlock.isIndefiniteForm = true;
const block2 = block1.valueBlock.value[0]; const block2 = block1.valueBlock.value[0];
block2.lenBlock.isIndefiniteForm = true; block2.lenBlock.isIndefiniteForm = true;
//endregion //endregion
let cmsSignedBuffer = _cmsSignedSchema.toBER(false); const cmsSignedBuffer = _cmsSignedSchema.toBER(false);
const cmsSignedArray = new Uint8Array(cmsSignedBuffer); const cmsSignedArray = new Uint8Array(cmsSignedBuffer);
const cmsSignedString = uint8ArrayToString(cmsSignedArray); const cmsSignedString = uint8ArrayToString(cmsSignedArray);
const hex = strHex(cmsSignedString); const hex = strHex(cmsSignedString);
return hex; return hex;
} }
async function signPdfObjects(pdfRaw, signingCert, certificateChain, privateKey, date) {
async function signPdfObjects (pdfRaw, signingCert, certificateChain, privateKey, date) { date = typeof date !== 'undefined' ? date : new Date();
date = typeof date !== 'undefined' ? date : new Date(); if (pdfRaw instanceof ArrayBuffer) {
if(pdfRaw instanceof ArrayBuffer) { pdfRaw = new Uint8Array(pdfRaw);
pdfRaw = new Uint8Array(pdfRaw); }
} const pdf = loadPdf(pdfRaw);
var pdf = loadPdf(pdfRaw); const root = findRootEntry(pdf.xref);
var root = findRootEntry(pdf.xref); const rootSuccessor = findSuccessorEntry(pdf.xref.entries, root);
var rootSuccessor = findSuccessorEntry(pdf.xref.entries, root); if (!isSigInRoot(pdf)) {
if(!isSigInRoot(pdf)) { return await newSig(pdf, root, rootSuccessor, date, signingCert, certificateChain, privateKey);
return await newSig(pdf, root, rootSuccessor, date, signingCert, certificateChain, privateKey); } else {
} else { return await appendSig(pdf, root, rootSuccessor, date, signingCert, certificateChain, privateKey);
return await appendSig(pdf, root, rootSuccessor, date, signingCert, certificateChain, privateKey); }
}
} }
export function signPdf(pdfRaw, signingCert, certificateChain, privateKey) { export function signPdf(pdfRaw, signingCert, certificateChain, privateKey) {
const signingCertObj = parseCertificate(signingCert); const signingCertObj = parseCertificate(signingCert);
const certificateChainObj = []; const certificateChainObj = [];
certificateChainObj[0] = parseCertificate(signingCert); certificateChainObj[0] = parseCertificate(signingCert);
for (let i = 0; i < certificateChain.length; i++) { for (let i = 0; i < certificateChain.length; i++) {
certificateChainObj[i + 1] = parseCertificate(certificateChain[i]) certificateChainObj[i + 1] = parseCertificate(certificateChain[i]);
} }
return parsePrivateKey(privateKey).then(privateKeyDecoded => { return parsePrivateKey(privateKey).then(privateKeyDecoded => {
return signPdfObjects(pdfRaw, signingCertObj, certificateChainObj, privateKeyDecoded); return signPdfObjects(pdfRaw, signingCertObj, certificateChainObj, privateKeyDecoded);
}); });
} }
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment