minify all files required for signpdf

This commit is contained in:
prafullnavkar-nxg
2023-10-25 15:57:26 +05:30
parent 57a3716092
commit 6a15193d7e
41 changed files with 61 additions and 1258 deletions
+1 -1
View File
@@ -23,7 +23,7 @@ function App() {
const handleCredentials = () => {
const appId = process.env.REACT_APP_APPID;
const baseurl = process.env.REACT_APP_SEVERURL;
const baseurl = process.env.REACT_APP_SERVERURL;
const appName = "contracts";
try {
localStorage.setItem("BaseUrl12", `${baseurl}/`);
+1 -1
View File
@@ -3,7 +3,7 @@ export const appInfo = {
appTitle: "contracts",
applogo: logo,
appname: "contracts",
baseurl: process.env.REACT_APP_SEVERURL,
baseurl: process.env.REACT_APP_SERVERURL,
defaultRole: "contracts_User",
fbAppId: process.env.REACT_APP_FBAPPID
? `${process.env.REACT_APP_FBAPPID}`
File diff suppressed because one or more lines are too long
@@ -1,31 +0,0 @@
const signer = require("node-signpdf").default;
class SignPDF {
constructor(pdfBuffer, certBuffer) {
this.pdfDoc = pdfBuffer;
this.certificate = certBuffer;
}
/**
* @return Promise<Buffer>
*/
async signPDF() {
let newPDF = signer.sign(this.pdfDoc, this.certificate, {
passphrase: "emudhra",
});
return newPDF;
}
/**
* @param {Uint8Array} unit8
*/
static unit8ToBuffer(unit8) {
let buf = Buffer.alloc(unit8.byteLength);
const view = new Uint8Array(unit8);
for (let i = 0; i < buf.length; ++i) {
buf[i] = view[i];
}
return buf;
}
}
module.exports = SignPDF;
@@ -0,0 +1 @@
const signer=require("node-signpdf").default;class SignPDF{constructor(e,t){this.pdfDoc=e,this.certificate=t}async signPDF(){return signer.sign(this.pdfDoc,this.certificate,{passphrase:"emudhra"})}static unit8ToBuffer(e){var t=Buffer.alloc(e.byteLength),r=new Uint8Array(e);for(let e=0;e<t.length;++e)t[e]=r[e];return t}}module.exports=SignPDF;
@@ -1,18 +0,0 @@
/*
PDFAbstractReference by Devon Govett used below.
The class is part of pdfkit. See https://github.com/foliojs/pdfkit
LICENSE: MIT. Included in this folder.
Modifications may have been applied for the purposes of node-signpdf.
*/
/*
PDFAbstractReference - abstract class for PDF reference
*/
class PDFAbstractReference {
toString() {
throw new Error('Must be implemented by subclasses');
}
}
export default PDFAbstractReference;
@@ -0,0 +1 @@
class PDFAbstractReference{toString(){throw new Error("Must be implemented by subclasses")}}export default PDFAbstractReference;
@@ -1,17 +0,0 @@
import PDFAbstractReference from './PDFAbstractReference.js';
class PDFKitReferenceMock extends PDFAbstractReference {
constructor(index, additionalData = undefined) {
super();
this.index = index;
if (typeof additionalData !== 'undefined') {
Object.assign(this, additionalData);
}
}
toString() {
return `${this.index} 0 R`;
}
}
export default PDFKitReferenceMock;
@@ -0,0 +1 @@
import PDFAbstractReference from"./PDFAbstractReference.min.js";class PDFKitReferenceMock extends PDFAbstractReference{constructor(e,t=void 0){super(),this.index=e,void 0!==t&&Object.assign(this,t)}toString(){return this.index+" 0 R"}}export default PDFKitReferenceMock;
@@ -1,19 +0,0 @@
export const ERROR_TYPE_UNKNOWN = 1;
export const ERROR_TYPE_INPUT = 2;
export const ERROR_TYPE_PARSE = 3;
export const ERROR_VERIFY_SIGNATURE = 4;
class SignPdfError extends Error {
constructor(msg, type = ERROR_TYPE_UNKNOWN) {
super(msg);
this.type = type;
}
}
// Shorthand
SignPdfError.TYPE_UNKNOWN = ERROR_TYPE_UNKNOWN;
SignPdfError.TYPE_INPUT = ERROR_TYPE_INPUT;
SignPdfError.TYPE_PARSE = ERROR_TYPE_PARSE;
SignPdfError.VERIFY_SIGNATURE = ERROR_VERIFY_SIGNATURE;
export default SignPdfError;
@@ -0,0 +1 @@
const ERROR_TYPE_UNKNOWN=1,ERROR_TYPE_INPUT=2,ERROR_TYPE_PARSE=3,ERROR_VERIFY_SIGNATURE=4;class SignPdfError extends Error{constructor(R,E=ERROR_TYPE_UNKNOWN){super(R),this.type=E}}SignPdfError.TYPE_UNKNOWN=ERROR_TYPE_UNKNOWN,SignPdfError.TYPE_INPUT=ERROR_TYPE_INPUT,SignPdfError.TYPE_PARSE=ERROR_TYPE_PARSE,SignPdfError.VERIFY_SIGNATURE=ERROR_VERIFY_SIGNATURE;export default SignPdfError;export{ERROR_TYPE_UNKNOWN,ERROR_TYPE_INPUT,ERROR_TYPE_PARSE,ERROR_VERIFY_SIGNATURE};
@@ -1,6 +0,0 @@
export const DEFAULT_SIGNATURE_LENGTH = 8192;
export const DEFAULT_BYTE_RANGE_PLACEHOLDER = '**********';
export const SUBFILTER_ADOBE_PKCS7_DETACHED = 'adbe.pkcs7.detached';
export const SUBFILTER_ADOBE_PKCS7_SHA1 = 'adbe.pkcs7.sha1';
export const SUBFILTER_ADOBE_X509_SHA1 = 'adbe.x509.rsa.sha1';
export const SUBFILTER_ETSI_CADES_DETACHED = 'ETSI.CAdES.detached';
@@ -0,0 +1 @@
const DEFAULT_SIGNATURE_LENGTH=8192,DEFAULT_BYTE_RANGE_PLACEHOLDER="**********",SUBFILTER_ADOBE_PKCS7_DETACHED="adbe.pkcs7.detached",SUBFILTER_ADOBE_PKCS7_SHA1="adbe.pkcs7.sha1",SUBFILTER_ADOBE_X509_SHA1="adbe.x509.rsa.sha1",SUBFILTER_ETSI_CADES_DETACHED="ETSI.CAdES.detached";export{DEFAULT_SIGNATURE_LENGTH,DEFAULT_BYTE_RANGE_PLACEHOLDER,SUBFILTER_ADOBE_PKCS7_DETACHED,SUBFILTER_ADOBE_PKCS7_SHA1,SUBFILTER_ADOBE_X509_SHA1,SUBFILTER_ETSI_CADES_DETACHED};
@@ -1,40 +0,0 @@
import findObject from './findObject.js';
import getIndexFromRef from './getIndexFromRef.js';
const createBufferPageWithAnnotation = (pdf, info, pagesRef, widget) => {
const pagesDictionary = findObject(pdf, info.xref, pagesRef).toString();
// Extend page dictionary with newly created annotations
let annotsStart; let annotsEnd; let
annots;
annotsStart = pagesDictionary.indexOf('/Annots');
if (annotsStart > -1) {
annotsEnd = pagesDictionary.indexOf(']', annotsStart);
annots = pagesDictionary.substr(annotsStart, annotsEnd + 1 - annotsStart);
annots = annots.substr(0, annots.length - 1); // remove the trailing ]
} else {
annotsStart = pagesDictionary.length;
annotsEnd = pagesDictionary.length;
annots = '/Annots [';
}
const pagesDictionaryIndex = getIndexFromRef(info.xref, pagesRef);
const widgetValue = widget.toString();
annots = `${annots} ${widgetValue}]`; // add the trailing ] back
const preAnnots = pagesDictionary.substr(0, annotsStart);
let postAnnots = '';
if (pagesDictionary.length > annotsEnd) {
postAnnots = pagesDictionary.substr(annotsEnd + 1);
}
return Buffer.concat([
Buffer.from(`${pagesDictionaryIndex} 0 obj\n`),
Buffer.from('<<\n'),
Buffer.from(`${preAnnots + annots + postAnnots}\n`),
Buffer.from('\n>>\nendobj\n'),
]);
};
export default createBufferPageWithAnnotation;
@@ -0,0 +1,3 @@
import findObject from"./findObject.min.js";import getIndexFromRef from"./getIndexFromRef.min.js";const createBufferPageWithAnnotation=(e,t,n,f)=>{e=findObject(e,t.xref,n).toString();let r,o,i;r=e.indexOf("/Annots"),i=-1<r?(o=e.indexOf("]",r),(i=e.substr(r,o+1-r)).substr(0,i.length-1)):(r=e.length,o=e.length,"/Annots [");t=getIndexFromRef(t.xref,n),n=f.toString(),i+=` ${n}]`,f=e.substr(0,r);let m="";return e.length>o&&(m=e.substr(o+1)),Buffer.concat([Buffer.from(t+` 0 obj
`),Buffer.from("<<\n"),Buffer.from(f+i+m+`
`),Buffer.from("\n>>\nendobj\n")])};export default createBufferPageWithAnnotation;
@@ -1,15 +0,0 @@
import getIndexFromRef from './getIndexFromRef.js';
const createBufferRootWithAcroform = (pdf, info, form) => {
const rootIndex = getIndexFromRef(info.xref, info.rootRef);
return Buffer.concat([
Buffer.from(`${rootIndex} 0 obj\n`),
Buffer.from('<<\n'),
Buffer.from(`${info.root}\n`),
Buffer.from(`/AcroForm ${form}`),
Buffer.from('\n>>\nendobj\n'),
]);
};
export default createBufferRootWithAcroform;
@@ -0,0 +1,3 @@
import getIndexFromRef from"./getIndexFromRef.min.js";const createBufferRootWithAcroform=(r,f,o)=>{var e=getIndexFromRef(f.xref,f.rootRef);return Buffer.concat([Buffer.from(e+` 0 obj
`),Buffer.from("<<\n"),Buffer.from(f.root+`
`),Buffer.from("/AcroForm "+o),Buffer.from("\n>>\nendobj\n")])};export default createBufferRootWithAcroform;
@@ -1,28 +0,0 @@
const createBufferTrailer = (pdf, info, addedReferences) => {
let rows = [];
rows[0] = '0000000000 65535 f '; // info.xref.tableRows[0];
addedReferences.forEach((offset, index) => {
const paddedOffset = (`0000000000${offset}`).slice(-10);
rows[index + 1] = `${index} 1\n${paddedOffset} 00000 n `;
});
rows = rows.filter((row) => row !== undefined);
return Buffer.concat([
Buffer.from('xref\n'),
Buffer.from(`${info.xref.startingIndex} 1\n`),
Buffer.from(rows.join('\n')),
Buffer.from('\ntrailer\n'),
Buffer.from('<<\n'),
Buffer.from(`/Size ${info.xref.maxIndex + 1}\n`),
Buffer.from(`/Root ${info.rootRef}\n`),
Buffer.from(info.infoRef ? `/Info ${info.infoRef}\n` : ''),
Buffer.from(`/Prev ${info.xRefPosition}\n`),
Buffer.from('>>\n'),
Buffer.from('startxref\n'),
Buffer.from(`${pdf.length}\n`),
Buffer.from('%%EOF'),
]);
};
export default createBufferTrailer;
@@ -0,0 +1,8 @@
const createBufferTrailer=(f,r,e)=>{let o=[];return o[0]="0000000000 65535 f ",e.forEach((f,r)=>{f=("0000000000"+f).slice(-10);o[r+1]=r+` 1
${f} 00000 n `}),o=o.filter(f=>void 0!==f),Buffer.concat([Buffer.from("xref\n"),Buffer.from(r.xref.startingIndex+` 1
`),Buffer.from(o.join("\n")),Buffer.from("\ntrailer\n"),Buffer.from("<<\n"),Buffer.from(`/Size ${r.xref.maxIndex+1}
`),Buffer.from(`/Root ${r.rootRef}
`),Buffer.from(r.infoRef?`/Info ${r.infoRef}
`:""),Buffer.from(`/Prev ${r.xRefPosition}
`),Buffer.from(">>\n"),Buffer.from("startxref\n"),Buffer.from(f.length+`
`),Buffer.from("%%EOF")])};export default createBufferTrailer;
@@ -1,21 +0,0 @@
import getIndexFromRef from './getIndexFromRef.js';
/**
* @param {Buffer} pdf
* @param {Map} refTable
* @returns {object}
*/
const findObject = (pdf, refTable, ref) => {
const index = getIndexFromRef(refTable, ref);
const offset = refTable.offsets.get(index);
let slice = pdf.slice(offset);
slice = slice.slice(0, slice.indexOf('endobj', 'utf8'));
// FIXME: What if it is a stream?
slice = slice.slice(slice.indexOf('<<', 'utf8') + 2);
slice = slice.slice(0, slice.lastIndexOf('>>', 'utf8'));
return slice;
};
export default findObject;
@@ -0,0 +1 @@
import getIndexFromRef from"./getIndexFromRef.min.js";const findObject=(e,t,f)=>{f=getIndexFromRef(t,f),t=t.offsets.get(f);let n=e.slice(t);return n=(n=(n=n.slice(0,n.indexOf("endobj","utf8"))).slice(n.indexOf("<<","utf8")+2)).slice(0,n.lastIndexOf(">>","utf8"))};export default findObject;
@@ -1,21 +0,0 @@
import SignPdfError from './SignPdfError.js';
/**
* @param {object} refTable
* @param {string} ref
* @returns {number}
*/
const getIndexFromRef = (refTable, ref) => {
let [index] = ref.split(' ');
index = parseInt(index);
if (!refTable.offsets.has(index)) {
throw new SignPdfError(
`Failed to locate object "${ref}".`,
SignPdfError.TYPE_PARSE,
);
}
return index;
};
export default getIndexFromRef;
@@ -0,0 +1 @@
import SignPdfError from"./SignPdfError.min.js";const getIndexFromRef=(r,e)=>{var[o]=e.split(" "),o=parseInt(o);if(r.offsets.has(o))return o;throw new SignPdfError(`Failed to locate object "${e}".`,SignPdfError.TYPE_PARSE)};export default getIndexFromRef;
@@ -1,41 +0,0 @@
import getPagesDictionaryRef from "./getPagesDictionaryRef.js";
import findObject from "./findObject.js";
/**
* Finds the reference to a page.
*
* @param {Buffer} pdfBuffer
* @param {Object} info As extracted from readRef()
* @param {Number} Page is pageNo on which we want widget/sign
*/
export default function getPageRef(pdfBuffer, info, Page) {
const pagesRef = getPagesDictionaryRef(info);
const pagesDictionary = findObject(pdfBuffer, info.xref, pagesRef);
const kidsPosition = pagesDictionary.indexOf("/Kids");
const kidsStart = pagesDictionary.indexOf("[", kidsPosition) + 1;
const kidsEnd = pagesDictionary.indexOf("]", kidsPosition);
const pages = pagesDictionary.slice(kidsStart, kidsEnd).toString();
// console.log("pages ", pages);
// const split = pages.trim().split(" ", 3);
// return `${split[0]} ${split[1]} ${split[2]}`;
// below code is used to get pageIndex (10 0 R) from pageNo to add sign widget on it
let indices = [];
for (var i = 0; i < pages.length; i++) {
if (pages[i] === "R") indices.push(i);
}
let pageIndex = {};
let startPosition = 0;
indices.forEach((x, index) => {
pageIndex = {
...pageIndex,
[index + 1]: pages.substring(startPosition + 1, x + 1),
};
startPosition = x + 1;
});
// console.log("pageIndex ", pageIndex);
const pageStr = Page ? pageIndex[Page] : pageIndex[1];
// console.log("pageStr ", pageStr);
return pageStr;
}
@@ -0,0 +1 @@
import getPagesDictionaryRef from"./getPagesDictionaryRef.min.js";import findObject from"./findObject.min.js";export default function getPageRef(e,t,i){var n=getPagesDictionaryRef(t),e=findObject(e,t.xref,n),t=e.indexOf("/Kids"),n=e.indexOf("[",t)+1,t=e.indexOf("]",t);const f=e.slice(n,t).toString();for(var r=[],o=0;o<f.length;o++)"R"===f[o]&&r.push(o);let a={},g=0;return r.forEach((e,t)=>{a={...a,[t+1]:f.substring(g+1,e+1)},g=e+1}),i?a[i]:a[1]}
@@ -1,18 +0,0 @@
import SignPdfError from './SignPdfError.js';
/**
* @param {Object} info As extracted from readRef()
*/
export default function getPagesDictionaryRef(info) {
const pagesRefRegex = /\/Pages\s+(\d+\s+\d+\s+R)/g;
const match = pagesRefRegex.exec(info.root);
if (match === null) {
throw new SignPdfError(
'Failed to find the pages descriptor. This is probably a problem in node-signpdf.',
SignPdfError.TYPE_PARSE,
);
}
return match[1];
}
@@ -0,0 +1 @@
import SignPdfError from"./SignPdfError.min.js";export default function getPagesDictionaryRef(r){r=/\/Pages\s+(\d+\s+\d+\s+R)/g.exec(r.root);if(null===r)throw new SignPdfError("Failed to find the pages descriptor. This is probably a problem in node-signpdf.",SignPdfError.TYPE_PARSE);return r[1]}
@@ -1,131 +0,0 @@
/*
PDFObject by Devon Govett used below.
The class is part of pdfkit. See https://github.com/foliojs/pdfkit
LICENSE: MIT. Included in this folder.
Modifications may have been applied for the purposes of node-signpdf.
*/
import PDFAbstractReference from './PDFAbstractReference.js';
/*
PDFObject - converts JavaScript types into their corresponding PDF types.
By Devon Govett
*/
const pad = (str, length) => (Array(length + 1).join('0') + str).slice(-length);
const escapableRe = /[\n\r\t\b\f()\\]/g;
const escapable = {
'\n': '\\n',
'\r': '\\r',
'\t': '\\t',
'\b': '\\b',
'\f': '\\f',
'\\': '\\\\',
'(': '\\(',
')': '\\)',
};
// Convert little endian UTF-16 to big endian
const swapBytes = (buff) => buff.swap16();
export default class PDFObject {
static convert(object, encryptFn = null) {
// String literals are converted to the PDF name type
if (typeof object === 'string') {
return `/${object}`;
// String objects are converted to PDF strings (UTF-16)
} if (object instanceof String) {
let string = object;
// Detect if this is a unicode string
let isUnicode = false;
for (let i = 0, end = string.length; i < end; i += 1) {
if (string.charCodeAt(i) > 0x7f) {
isUnicode = true;
break;
}
}
// If so, encode it as big endian UTF-16
let stringBuffer;
if (isUnicode) {
stringBuffer = swapBytes(Buffer.from(`\ufeff${string}`, 'utf16le'));
} else {
stringBuffer = Buffer.from(string, 'ascii');
}
// Encrypt the string when necessary
if (encryptFn) {
string = encryptFn(stringBuffer).toString('binary');
} else {
string = stringBuffer.toString('binary');
}
// Escape characters as required by the spec
string = string.replace(escapableRe, (c) => escapable[c]);
return `(${string})`;
// Buffers are converted to PDF hex strings
} if (Buffer.isBuffer(object)) {
return `<${object.toString('hex')}>`;
} if (object instanceof PDFAbstractReference) {
return object.toString();
} if (object instanceof Date) {
let string = `D:${pad(object.getUTCFullYear(), 4)}${pad(object.getUTCMonth() + 1, 2)}${pad(object.getUTCDate(), 2)}${pad(object.getUTCHours(), 2)}${pad(object.getUTCMinutes(), 2)}${pad(object.getUTCSeconds(), 2)}Z`;
// Encrypt the string when necessary
if (encryptFn) {
string = encryptFn(Buffer.from(string, 'ascii')).toString('binary');
// Escape characters as required by the spec
string = string.replace(escapableRe, (c) => escapable[c]);
}
return `(${string})`;
} if (Array.isArray(object)) {
const items = object.map((e) => PDFObject.convert(e, encryptFn)).join(' ');
return `[${items}]`;
}
if ({}.toString.call(object) === '[object Object]') {
const out = ['<<'];
let streamData;
// @todo this can probably be refactored into a reduce
Object.entries(object).forEach(([key, val]) => {
let checkedValue = '';
if (val && val.toString().indexOf('<<') !== -1) {
checkedValue = val;
} else {
checkedValue = PDFObject.convert(val, encryptFn);
}
// // if (key === 'stream') {
// // streamData = `${key}\n${val}\nendstream`;
// // }
// else {
out.push(`/${key} ${checkedValue}`);
// }
});
out.push('>>');
// if (streamData) {
// out.push(streamData);
// }
return out.join('\n');
}
if (typeof object === 'number') {
return PDFObject.number(object);
}
return `${object}`;
}
static number(n) {
if (n > -1e21 && n < 1e21) {
return Math.round(n * 1e6) / 1e6;
}
throw new Error(`unsupported number: ${n}`);
}
}
@@ -0,0 +1 @@
import PDFAbstractReference from"./PDFAbstractReference.min.js";const pad=(e,t)=>(Array(t+1).join("0")+e).slice(-t),escapableRe=/[\n\r\t\b\f()\\]/g,escapable={"\n":"\\n","\r":"\\r","\t":"\\t","\b":"\\b","\f":"\\f","\\":"\\\\","(":"\\(",")":"\\)"},swapBytes=e=>e.swap16();export default class PDFObject{static convert(t,a=null){if("string"==typeof t)return"/"+t;if(t instanceof String){let r=t,n=!1;for(let e=0,t=r.length;e<t;e+=1)if(127<r.charCodeAt(e)){n=!0;break}let e;return e=n?swapBytes(Buffer.from(``+r,"utf16le")):Buffer.from(r,"ascii"),`(${r=(r=(a?a(e):e).toString("binary")).replace(escapableRe,e=>escapable[e])})`}if(Buffer.isBuffer(t))return`<${t.toString("hex")}>`;if(t instanceof PDFAbstractReference)return t.toString();if(t instanceof Date){let e=`D:${pad(t.getUTCFullYear(),4)}${pad(t.getUTCMonth()+1,2)}${pad(t.getUTCDate(),2)}${pad(t.getUTCHours(),2)}${pad(t.getUTCMinutes(),2)}${pad(t.getUTCSeconds(),2)}Z`;return`(${e=a?(e=a(Buffer.from(e,"ascii")).toString("binary")).replace(escapableRe,e=>escapable[e]):e})`}if(Array.isArray(t))return`[${t.map(e=>PDFObject.convert(e,a)).join(" ")}]`;if("[object Object]"!=={}.toString.call(t))return"number"==typeof t?PDFObject.number(t):""+t;{const n=["<<"];return Object.entries(t).forEach(([e,t])=>{let r="";r=t&&-1!==t.toString().indexOf("<<")?t:PDFObject.convert(t,a),n.push(`/${e} `+r)}),n.push(">>"),n.join("\n")}}static number(e){if(-1e21<e&&e<1e21)return Math.round(1e6*e)/1e6;throw new Error("unsupported number: "+e)}}
@@ -1,449 +0,0 @@
import {
DEFAULT_BYTE_RANGE_PLACEHOLDER,
DEFAULT_SIGNATURE_LENGTH,
SUBFILTER_ADOBE_PKCS7_DETACHED,
} from "./const.js";
// eslint-disable-next-line import/no-unresolved
import PDFKitReferenceMock from "./PDFKitReferenceMock.js";
/**
* Adds the objects that are needed for Adobe.PPKLite to read the signature.
* Also includes a placeholder for the actual signature.
* Returns an Object with all the added PDFReferences.
* @param {PDFDocument} pdf
* @param {string} reason
* @returns {object}
*/
// testing
import PNG from "png-js";
import zlib from "zlib";
import fs from "node:fs";
const specialCharacters = [
"á",
"Á",
"é",
"É",
"í",
"Í",
"ó",
"Ó",
"ö",
"Ö",
"ő",
"Ő",
"ú",
"Ú",
"ű",
"Ű",
];
const MARKERS = [
0xffc0, 0xffc1, 0xffc2, 0xffc3, 0xffc5, 0xffc6, 0xffc7, 0xffc8, 0xffc9,
0xffca, 0xffcb, 0xffcc, 0xffcd, 0xffce, 0xffcf,
];
const COLOR_SPACE_MAP = {
1: "DeviceGray",
3: "DeviceRGB",
4: "DeviceCMYK",
};
// testing
function getImage(imagePath, pdf) {
let img;
const data = imagePath; //fs.readFileSync(imagePath);
if (data[0] === 0xff && data[1] === 0xd8) {
img = getJpgImage(pdf, data);
} else if (data[0] === 0x89 && data.toString("ascii", 1, 4) === "PNG") {
img = getPngImage(pdf, data);
} else {
throw new Error("Unknown image format.");
}
return img;
}
function getAnnotationApparance(pdf, IMG, APFONT) {
return pdf.ref(
{
CropBox: [0, 0, 197, 70],
Type: "XObject",
FormType: 1,
BBox: [0, 0, 197.0, 70.0], //[-10, 10, 197.0, 70.0],
Resources: `<</XObject <<\n/Img${IMG.index} ${IMG.index} 0 R\n>>\n/Font <<\n/f1 ${APFONT.index} 0 R\n>>\n>>`,
MediaBox: [0, 0, 197, 70],
Subtype: "Form",
},
null,
getStream(IMG.index)
);
}
const getStream = (imgIndex) => {
// (Aláírta: ${userInformation.commonName}) Tj
// (Aláírta: testing name) Tj
// (${new Date().toISOString().slice(0, 10)}) Tj
return getConvertedText(`
1.0 1.0 1.0 rg
0.0 0.0 0.0 RG
q
q
200 0 0 50 0 10 cm
/Img${imgIndex} Do
Q
0 0 0 rg
BT
0 Tr
/f1 10.0 Tf
1.4 0 0 1 20 45.97412 Tm
ET
BT
0 Tr
/f1 10.0 Tf
1.4 0 0 1 20 33.56006 Tm
ET
Q`);
};
const getFont = (pdf, baseFont) => {
return pdf.ref({
Type: "Font",
BaseFont: baseFont,
Encoding: "WinAnsiEncoding",
Subtype: "Type1",
});
};
const getJpgImage = (pdf, data) => {
if (data.readUInt16BE(0) !== 0xffd8) {
throw "SOI not found in JPEG";
}
let pos = 2;
let marker;
while (pos < data.length) {
marker = data.readUInt16BE(pos);
pos += 2;
if (MARKERS.includes(marker)) {
break;
}
pos += data.readUInt16BE(pos);
}
if (!MARKERS.includes(marker)) {
throw "Invalid JPEG.";
}
pos += 2;
const bits = data[pos++];
const height = data.readUInt16BE(pos);
pos += 2;
const width = data.readUInt16BE(pos);
pos += 2;
const channels = data[pos++];
const colorSpace = COLOR_SPACE_MAP[channels];
const baseJpgData = {
Type: "XObject",
Subtype: "Image",
BitsPerComponent: bits,
Width: width,
Height: height,
ColorSpace: colorSpace,
Filter: "DCTDecode",
};
if (colorSpace === "DeviceCMYK") {
baseJpgData["Decode"] = [1.0, 0.0, 1.0, 0.0, 1.0, 0.0, 1.0, 0.0];
}
const image = pdf.ref(baseJpgData, null, data);
return image;
};
const getPngImage = (pdf, data) => {
const image = new PNG(data);
const hasAlphaChannel = image.hasAlphaChannel;
const pngBaseData = {
Type: "XObject",
Subtype: "Image",
BitsPerComponent: hasAlphaChannel ? 8 : image.bits,
Width: image.width,
Height: image.height,
Filter: "FlateDecode",
};
if (!hasAlphaChannel) {
const params = pdf.ref({
Predictor: 15,
Colors: image.colors,
BitsPerComponent: image.bits,
Columns: image.width,
});
pngBaseData["DecodeParms"] = params;
}
if (image.palette.length === 0) {
pngBaseData["ColorSpace"] = image.colorSpace;
} else {
const palette = pdf.ref({
stream: new Buffer(image.palette),
});
pngBaseData["ColorSpace"] = [
"Indexed",
"DeviceRGB",
image.palette.length / 3 - 1,
palette,
];
}
if (image.transparency.grayscale != null) {
const val = image.transparency.grayscale;
pngBaseData["Mask"] = [val, val];
} else if (image.transparency.rgb) {
const { rgb } = image.transparency;
const mask = [];
for (let x of rgb) {
mask.push(x, x);
}
pngBaseData["Mask"] = mask;
} else if (image.transparency.indexed) {
loadIndexedAlphaChannel(image);
} else if (hasAlphaChannel) {
splitAlphaChannel(image);
const sMask = getSmask(pdf, image);
pngBaseData["Mask"] = sMask;
}
const pngImage = pdf.ref(pngBaseData, null, image.imgData);
return pngImage;
};
const loadIndexedAlphaChannel = (image) => {
const transparency = image.transparency.indexed;
return image.decodePixels((pixels) => {
const alphaChannel = new Buffer(image.width * image.height);
let i = 0;
for (let j = 0, end = pixels.length; j < end; j++) {
alphaChannel[i++] = transparency[pixels[j]];
}
image.alphaChannel = zlib.deflateSync(alphaChannel);
});
};
const splitAlphaChannel = (image) => {
image.decodePixels((pixels) => {
let a, p;
const colorCount = image.colors;
const pixelCount = image.width * image.height;
const imgData = new Buffer(pixelCount * colorCount);
const alphaChannel = new Buffer(pixelCount);
let i = (p = a = 0);
const len = pixels.length;
const skipByteCount = image.bits === 16 ? 1 : 0;
while (i < len) {
for (let colorIndex = 0; colorIndex < colorCount; colorIndex++) {
imgData[p++] = pixels[i++];
i += skipByteCount;
}
alphaChannel[a++] = pixels[i++];
i += skipByteCount;
}
image.imgData = zlib.deflateSync(imgData);
image.alphaChannel = zlib.deflateSync(alphaChannel);
});
};
const getSmask = (pdf, image) => {
let sMask;
console.log("image.hasAlphaChannel ", image.hasAlphaChannel);
if (image.hasAlphaChannel) {
console.log("image.alphaChannel ", image.alphaChannel);
sMask = pdf.ref({
Type: "XObject",
Subtype: "Image",
Height: image.height,
Width: image.width,
BitsPerComponent: 8,
Filter: "FlateDecode",
ColorSpace: "DeviceGray",
Decode: [0, 1],
stream: image.alphaChannel,
});
}
return sMask;
};
const getConvertedText = (text) => {
return text
.split("")
.map((character) => {
return specialCharacters.includes(character)
? getOctalCodeFromCharacter(character)
: character;
})
.join("");
};
const getOctalCodeFromCharacter = (character) => {
return "\\" + character.charCodeAt(0).toString(8);
};
//
const pdfkitAddPlaceholder = ({
pdf,
pdfBuffer,
reason,
contactInfo = "emailfromp1289@gmail.com",
name = "Name from p12",
location = "Location from p12",
signatureLength = DEFAULT_SIGNATURE_LENGTH,
byteRangePlaceholder = DEFAULT_BYTE_RANGE_PLACEHOLDER,
subFilter = SUBFILTER_ADOBE_PKCS7_DETACHED,
sign,
}) => {
// testing
const FONT = getFont(pdf, "Helvetica");
const ZAF = getFont(pdf, "ZapfDingbats");
const APFONT = getFont(pdf, "Helvetica");
// const imagePath = "exports/img.jpg";
const signBase64 = sign.Base64;
const imagePath = Buffer.from(signBase64, "base64");
const IMG = getImage(imagePath, pdf);
const AP = getAnnotationApparance(pdf, IMG, APFONT);
//
/* eslint-disable no-underscore-dangle,no-param-reassign */
// Generate the signature placeholder
const signature = pdf.ref({
Type: "Sig",
Filter: "Adobe.PPKLite",
SubFilter: subFilter,
ByteRange: [
0,
byteRangePlaceholder,
byteRangePlaceholder,
byteRangePlaceholder,
],
Contents: Buffer.from(String.fromCharCode(0).repeat(signatureLength)),
Reason: new String(reason), // eslint-disable-line no-new-wrappers
M: new Date(),
ContactInfo: new String(contactInfo), // eslint-disable-line no-new-wrappers
Name: new String(name), // eslint-disable-line no-new-wrappers
Location: new String(location), // eslint-disable-line no-new-wrappers
});
// Check if pdf already contains acroform field
const acroFormPosition = pdfBuffer.lastIndexOf("/Type /AcroForm");
const isAcroFormExists = acroFormPosition !== -1;
let fieldIds = [];
let acroFormId;
if (isAcroFormExists) {
let acroFormStart = acroFormPosition;
// 10 is the distance between "/Type /AcroForm" and AcroFrom ID
const charsUntilIdEnd = 10;
const acroFormIdEnd = acroFormPosition - charsUntilIdEnd;
// Let's find AcroForm ID by trying to find the "\n" before the ID
// 12 is a enough space to find the "\n"
// (generally it's 2 or 3, but I'm giving a big space though)
const maxAcroFormIdLength = 12;
let foundAcroFormId = "";
let index = charsUntilIdEnd + 1;
for (index; index < charsUntilIdEnd + maxAcroFormIdLength; index += 1) {
const acroFormIdString = pdfBuffer
.slice(acroFormPosition - index, acroFormIdEnd)
.toString();
if (acroFormIdString[0] === "\n") {
break;
}
foundAcroFormId = acroFormIdString;
acroFormStart = acroFormPosition - index;
}
const pdfSlice = pdfBuffer.slice(acroFormStart);
const acroForm = pdfSlice.slice(0, pdfSlice.indexOf("endobj")).toString();
acroFormId = parseInt(foundAcroFormId);
const acroFormFields = acroForm.slice(
acroForm.indexOf("/Fields [") + 9,
acroForm.indexOf("]")
);
fieldIds = acroFormFields
.split(" ")
.filter((element, i) => i % 3 === 0)
.map((fieldId) => new PDFKitReferenceMock(fieldId));
}
const signatureName = "Signature";
const signatureLeftOffset = fieldIds.length * 125;
const signatureBottomOffset = 5;
const left = sign.Left; //461.50001525878906 //477.3333282470703//409.5000305175781; // first block 44.33332824707031;
const bottom = sign.Bottom; // 730.1979598999023 - 39 + 5.072906494140625 //720.1979598999023 - 30 + 15.072906494140625; // first block 652.1979598999023 - 60 + 19.072906494140625;
const RightX = left + sign.Width; // 98;
const RightY = bottom + sign.Height; //39;
// Generate signature annotation widget
const widget = pdf.ref({
Type: "Annot",
Subtype: "Widget",
FT: "Sig",
Rect: [left, bottom, RightX, RightY], // [signatureLeftOffset, 0, signatureLeftOffset + 90, signatureBottomOffset + 60, ], // [50, 50, 100, 100], //[25, 25, 100, 300], //
V: signature,
T: new String(signatureName + (fieldIds.length + 1)), // eslint-disable-line no-new-wrappers
F: 4,
P: pdf.page.dictionary, // eslint-disable-line no-underscore-dangle
AP: `<</N ${AP.index} 0 R>>`, // testing
DA: new String("/Helvetica 0 Tf 0 g"), // eslint-disable-line no-new-wrappers // testing
});
pdf.page.dictionary.data.Annots = [widget];
// Include the widget in a page
let form;
if (!isAcroFormExists) {
// Create a form (with the widget) and link in the _root
form = pdf.ref({
Type: "AcroForm",
SigFlags: 3,
Fields: [...fieldIds, widget],
});
} else {
// Use existing acroform and extend the fields with newly created widgets
form = pdf.ref(
{
Type: "AcroForm",
SigFlags: 3,
Fields: [...fieldIds, widget],
DR: `<</Font\n<</Helvetica ${FONT.index} 0 R/ZapfDingbats ${ZAF.index} 0 R>>\n>>`, /// testing
},
acroFormId
);
}
pdf._root.data.AcroForm = form;
return {
signature,
form,
widget,
};
/* eslint-enable no-underscore-dangle,no-param-reassign */
};
export default pdfkitAddPlaceholder;
@@ -0,0 +1,28 @@
import{DEFAULT_BYTE_RANGE_PLACEHOLDER,DEFAULT_SIGNATURE_LENGTH,SUBFILTER_ADOBE_PKCS7_DETACHED}from"./const.min.js";import PDFKitReferenceMock from"./PDFKitReferenceMock.min.js";import PNG from"png-js";import zlib from"zlib";import fs from"node:fs";const specialCharacters=["á","Á","é","É","í","Í","ó","Ó","ö","Ö","ő","Ő","ú","Ú","ű","Ű"],MARKERS=[65472,65473,65474,65475,65477,65478,65479,65480,65481,65482,65483,65484,65485,65486,65487],COLOR_SPACE_MAP={1:"DeviceGray",3:"DeviceRGB",4:"DeviceCMYK"};function getImage(e,t){let n;if(255===e[0]&&216===e[1])n=getJpgImage(t,e);else{if(137!==e[0]||"PNG"!==e.toString("ascii",1,4))throw new Error("Unknown image format.");n=getPngImage(t,e)}return n}function getAnnotationApparance(e,t,n){return e.ref({CropBox:[0,0,197,70],Type:"XObject",FormType:1,BBox:[0,0,197,70],Resources:`<</XObject <<
/Img${t.index} ${t.index} 0 R
>>
/Font <<
/f1 ${n.index} 0 R
>>
>>`,MediaBox:[0,0,197,70],Subtype:"Form"},null,getStream(t.index))}const getStream=e=>getConvertedText(`
1.0 1.0 1.0 rg
0.0 0.0 0.0 RG
q
q
200 0 0 50 0 10 cm
/Img${e} Do
Q
0 0 0 rg
BT
0 Tr
/f1 10.0 Tf
1.4 0 0 1 20 45.97412 Tm
ET
BT
0 Tr
/f1 10.0 Tf
1.4 0 0 1 20 33.56006 Tm
ET
Q`),getFont=(e,t)=>e.ref({Type:"Font",BaseFont:t,Encoding:"WinAnsiEncoding",Subtype:"Type1"}),getJpgImage=(e,t)=>{if(65496!==t.readUInt16BE(0))throw"SOI not found in JPEG";let n=2,a;for(;n<t.length&&(a=t.readUInt16BE(n),n+=2,!MARKERS.includes(a));)n+=t.readUInt16BE(n);if(!MARKERS.includes(a))throw"Invalid JPEG.";n+=2;var r=t[n++],o=t.readUInt16BE(n),i=(n+=2,t.readUInt16BE(n)),l=(n+=2,t[n++]),l=COLOR_SPACE_MAP[l],r={Type:"XObject",Subtype:"Image",BitsPerComponent:r,Width:i,Height:o,ColorSpace:l,Filter:"DCTDecode"},i=("DeviceCMYK"===l&&(r.Decode=[1,0,1,0,1,0,1,0]),e.ref(r,null,t));return i},getPngImage=(e,t)=>{var t=new PNG(t),n=t.hasAlphaChannel,a={Type:"XObject",Subtype:"Image",BitsPerComponent:n?8:t.bits,Width:t.width,Height:t.height,Filter:"FlateDecode"};if(n||(r=e.ref({Predictor:15,Colors:t.colors,BitsPerComponent:t.bits,Columns:t.width}),a.DecodeParms=r),0===t.palette.length?a.ColorSpace=t.colorSpace:(r=e.ref({stream:new Buffer(t.palette)}),a.ColorSpace=["Indexed","DeviceRGB",t.palette.length/3-1,r]),null!=t.transparency.grayscale){var r=t.transparency.grayscale;a.Mask=[r,r]}else if(t.transparency.rgb){var o,r=t.transparency["rgb"],i=[];for(o of r)i.push(o,o);a.Mask=i}else t.transparency.indexed?loadIndexedAlphaChannel(t):n&&(splitAlphaChannel(t),r=getSmask(e,t),a.Mask=r);return e.ref(a,null,t.imgData)},loadIndexedAlphaChannel=e=>{const o=e.transparency.indexed;return e.decodePixels(n=>{var a=new Buffer(e.width*e.height);let r=0;for(let e=0,t=n.length;e<t;e++)a[r++]=o[n[e]];e.alphaChannel=zlib.deflateSync(a)})},splitAlphaChannel=d=>{d.decodePixels(t=>{let e,n;var a=d.colors,r=d.width*d.height,o=new Buffer(r*a),i=new Buffer(r);let l=n=e=0;for(var g=t.length,c=16===d.bits?1:0;l<g;){for(let e=0;e<a;e++)o[n++]=t[l++],l+=c;i[e++]=t[l++],l+=c}d.imgData=zlib.deflateSync(o),d.alphaChannel=zlib.deflateSync(i)})},getSmask=(e,t)=>{let n;return console.log("image.hasAlphaChannel ",t.hasAlphaChannel),t.hasAlphaChannel&&(console.log("image.alphaChannel ",t.alphaChannel),n=e.ref({Type:"XObject",Subtype:"Image",Height:t.height,Width:t.width,BitsPerComponent:8,Filter:"FlateDecode",ColorSpace:"DeviceGray",Decode:[0,1],stream:t.alphaChannel})),n},getConvertedText=e=>e.split("").map(e=>specialCharacters.includes(e)?getOctalCodeFromCharacter(e):e).join(""),getOctalCodeFromCharacter=e=>"\\"+e.charCodeAt(0).toString(8),pdfkitAddPlaceholder=({pdf:e,pdfBuffer:a,reason:r,contactInfo:t="emailfromp1289@gmail.com",name:n="Name from p12",location:o="Location from p12",signatureLength:i=DEFAULT_SIGNATURE_LENGTH,byteRangePlaceholder:l=DEFAULT_BYTE_RANGE_PLACEHOLDER,subFilter:g=SUBFILTER_ADOBE_PKCS7_DETACHED,sign:c})=>{var d=getFont(e,"Helvetica"),s=getFont(e,"ZapfDingbats"),f=getFont(e,"Helvetica"),p=c.Base64,p=getAnnotationApparance(e,getImage(Buffer.from(p,"base64"),e),f),f=e.ref({Type:"Sig",Filter:"Adobe.PPKLite",SubFilter:g,ByteRange:[0,l,l,l],Contents:Buffer.from(String.fromCharCode(0).repeat(i)),Reason:new String(r),M:new Date,ContactInfo:new String(t),Name:new String(n),Location:new String(o)}),h=a.lastIndexOf("/Type /AcroForm"),g=-1!==h;let m=[],C;if(g){let e=h;var S=h-10;let t="",n=11;for(n;n<22;n+=1){var A=a.slice(h-n,S).toString();if("\n"===A[0])break;t=A,e=h-n}l=a.slice(e),i=l.slice(0,l.indexOf("endobj")).toString(),r=(C=parseInt(t),i.slice(i.indexOf("/Fields [")+9,i.indexOf("]")));m=r.split(" ").filter((e,t)=>t%3==0).map(e=>new PDFKitReferenceMock(e))}m.length;t=c.Left,n=c.Bottom,o=t+c.Width,l=n+c.Height,i=e.ref({Type:"Annot",Subtype:"Widget",FT:"Sig",Rect:[t,n,o,l],V:f,T:new String("Signature"+(m.length+1)),F:4,P:e.page.dictionary,AP:`<</N ${p.index} 0 R>>`,DA:new String("/Helvetica 0 Tf 0 g")});e.page.dictionary.data.Annots=[i];let T;return T=g?e.ref({Type:"AcroForm",SigFlags:3,Fields:[...m,i],DR:`<</Font
<</Helvetica ${d.index} 0 R/ZapfDingbats ${s.index} 0 R>>
>>`},C):e.ref({Type:"AcroForm",SigFlags:3,Fields:[...m,i]}),{signature:f,form:e._root.data.AcroForm=T,widget:i}};export default pdfkitAddPlaceholder;
@@ -1,138 +0,0 @@
import PDFObject from "./pdfObject.js";
import PDFKitReferenceMock from "./PDFKitReferenceMock.js";
import removeTrailingNewLine from "./removeTrailingNewLine.js";
import {
DEFAULT_SIGNATURE_LENGTH,
SUBFILTER_ADOBE_PKCS7_DETACHED,
} from "./const.js";
import pdfkitAddPlaceholder from "./pdfkitAddPlaceholder.js";
import getIndexFromRef from "./getIndexFromRef.js";
import readPdf from "./readPdf.js";
import getPageRef from "./getPageRef.js";
import createBufferRootWithAcroform from "./createBufferRootWithAcroform.js";
import createBufferPageWithAnnotation from "./createBufferPageWithAnnotation.js";
import createBufferTrailer from "./createBufferTrailer.js";
const isContainBufferRootWithAcroform = (pdf) => {
const bufferRootWithAcroformRefRegex = /\/AcroForm\s+(\d+\s\d+\sR)/g;
const match = bufferRootWithAcroformRefRegex.exec(pdf.toString());
return match != null && match[1] != null && match[1] !== "";
};
// testing
const getAssembledPdf = (pdf, index, input, stream) => {
let finalPdf = pdf;
finalPdf = Buffer.concat([
finalPdf,
Buffer.from("\n"),
Buffer.from(`${index} 0 obj\n`),
Buffer.from(PDFObject.convert(input)),
]);
if (stream) {
finalPdf = Buffer.concat([
finalPdf,
Buffer.from("\nstream\n"),
Buffer.from(stream),
Buffer.from("\nendstream"),
]);
}
finalPdf = Buffer.concat([finalPdf, Buffer.from("\nendobj\n")]);
return finalPdf;
};
//
/**
* Adds a signature placeholder to a PDF Buffer.
*
* This contrasts with the default pdfkit-based implementation.
* Parsing is done using simple string operations.
* Adding is done with `Buffer.concat`.
* This allows node-signpdf to be used on any PDF and
* not only on a freshly created through PDFKit one.
*/
const plainAddPlaceholder = ({
pdfBuffer,
reason,
contactInfo = "emailfromp1289@gmail.com",
name = "Name from p12",
location = "Location from p12",
signatureLength = DEFAULT_SIGNATURE_LENGTH,
subFilter = SUBFILTER_ADOBE_PKCS7_DETACHED,
sign,
}) => {
let pdf = removeTrailingNewLine(pdfBuffer);
const info = readPdf(pdf);
const pageRef = getPageRef(pdf, info, sign.Page);
const pageIndex = getIndexFromRef(info.xref, pageRef);
const addedReferences = new Map();
const pdfKitMock = {
ref: (input, additionalIndex, stream) => {
info.xref.maxIndex += 1;
const index =
additionalIndex != null ? additionalIndex : info.xref.maxIndex;
addedReferences.set(index, pdf.length + 1); // + 1 new line
pdf = getAssembledPdf(pdf, index, input, stream);
return new PDFKitReferenceMock(info.xref.maxIndex);
},
page: {
dictionary: new PDFKitReferenceMock(pageIndex, {
data: {
Annots: [],
},
}),
},
_root: {
data: {},
},
};
const { form, widget } = pdfkitAddPlaceholder({
pdf: pdfKitMock,
pdfBuffer,
reason,
contactInfo,
name,
location,
signatureLength,
subFilter,
sign,
});
if (!isContainBufferRootWithAcroform(pdf)) {
const rootIndex = getIndexFromRef(info.xref, info.rootRef);
addedReferences.set(rootIndex, pdf.length + 1);
pdf = Buffer.concat([
pdf,
Buffer.from("\n"),
createBufferRootWithAcroform(pdf, info, form),
]);
}
addedReferences.set(pageIndex, pdf.length + 1);
pdf = Buffer.concat([
pdf,
Buffer.from("\n"),
createBufferPageWithAnnotation(pdf, info, pageRef, widget),
]);
pdf = Buffer.concat([
pdf,
Buffer.from("\n"),
createBufferTrailer(pdf, info, addedReferences),
]);
return pdf;
};
export default plainAddPlaceholder;
@@ -0,0 +1,2 @@
import PDFObject from"./pdfObject.min.js";import PDFKitReferenceMock from"./PDFKitReferenceMock.min.js";import removeTrailingNewLine from"./removeTrailingNewLine.min.js";import{DEFAULT_SIGNATURE_LENGTH,SUBFILTER_ADOBE_PKCS7_DETACHED}from"./const.min.js";import pdfkitAddPlaceholder from"./pdfkitAddPlaceholder.min.js";import getIndexFromRef from"./getIndexFromRef.min.js";import readPdf from"./readPdf.min.js";import getPageRef from"./getPageRef.min.js";import createBufferRootWithAcroform from"./createBufferRootWithAcroform.min.js";import createBufferPageWithAnnotation from"./createBufferPageWithAnnotation.min.js";import createBufferTrailer from"./createBufferTrailer.min.js";const isContainBufferRootWithAcroform=e=>{e=/\/AcroForm\s+(\d+\s\d+\sR)/g.exec(e.toString());return null!=e&&null!=e[1]&&""!==e[1]},getAssembledPdf=(e,r,f,o)=>{let t=e;return t=Buffer.concat([t,Buffer.from("\n"),Buffer.from(r+` 0 obj
`),Buffer.from(PDFObject.convert(f))]),o&&(t=Buffer.concat([t,Buffer.from("\nstream\n"),Buffer.from(o),Buffer.from("\nendstream")])),t=Buffer.concat([t,Buffer.from("\nendobj\n")])},plainAddPlaceholder=({pdfBuffer:e,reason:r,contactInfo:f="emailfromp1289@gmail.com",name:o="Name from p12",location:t="Location from p12",signatureLength:n=DEFAULT_SIGNATURE_LENGTH,subFilter:i=SUBFILTER_ADOBE_PKCS7_DETACHED,sign:m})=>{let a=removeTrailingNewLine(e);const c=readPdf(a);var d=getPageRef(a,c,m.Page),u=getIndexFromRef(c.xref,d);const l=new Map;var s={ref:(e,r,f)=>{c.xref.maxIndex+=1;r=null!=r?r:c.xref.maxIndex;return l.set(r,a.length+1),a=getAssembledPdf(a,r,e,f),new PDFKitReferenceMock(c.xref.maxIndex)},page:{dictionary:new PDFKitReferenceMock(u,{data:{Annots:[]}})},_root:{data:{}}},{form:s,widget:e}=pdfkitAddPlaceholder({pdf:s,pdfBuffer:e,reason:r,contactInfo:f,name:o,location:t,signatureLength:n,subFilter:i,sign:m});return isContainBufferRootWithAcroform(a)||(r=getIndexFromRef(c.xref,c.rootRef),l.set(r,a.length+1),a=Buffer.concat([a,Buffer.from("\n"),createBufferRootWithAcroform(a,c,s)])),l.set(u,a.length+1),a=Buffer.concat([a,Buffer.from("\n"),createBufferPageWithAnnotation(a,c,d,e)]),a=Buffer.concat([a,Buffer.from("\n"),createBufferTrailer(a,c,l)])};export default plainAddPlaceholder;
@@ -1,54 +0,0 @@
import readRefTable from './readRefTable.js';
import findObject from './findObject.js';
const getValue = (trailer, key) => {
let index = trailer.indexOf(key);
if (index === -1) {
return undefined;
}
const slice = trailer.slice(index);
index = slice.indexOf('/', 1);
if (index === -1) {
index = slice.indexOf('>', 1);
}
return slice.slice(key.length + 1, index).toString().trim(); // key + at least one space
};
/**
* Simplified parsing of a PDF Buffer.
* Extracts reference table, root info and trailer start.
*
* See section 7.5.5 (File Trailer) of the PDF specs.
*
* @param {Buffer} pdfBuffer
*/
const readPdf = (pdfBuffer) => {
// Extract the trailer dictionary.
const trailerStart = pdfBuffer.lastIndexOf('trailer');
// The trailer is followed by xref. Then an EOF. EOF's length is 6 characters.
const trailer = pdfBuffer.slice(trailerStart, pdfBuffer.length - 6);
let xRefPosition = trailer.slice(trailer.lastIndexOf('startxref') + 10).toString();
xRefPosition = parseInt(xRefPosition);
const refTable = readRefTable(pdfBuffer);
const rootRef = getValue(trailer, '/Root');
const root = findObject(pdfBuffer, refTable, rootRef).toString();
const infoRef = getValue(trailer, '/Info');
return {
xref: refTable,
rootRef,
root,
infoRef,
trailerStart,
previousXrefs: [],
xRefPosition,
};
};
export default readPdf;
@@ -0,0 +1 @@
import readRefTable from"./readRefTable.min.js";import findObject from"./findObject.min.js";const getValue=(e,t)=>{let r=e.indexOf(t);if(-1!==r)return e=e.slice(r),-1===(r=e.indexOf("/",1))&&(r=e.indexOf(">",1)),e.slice(t.length+1,r).toString().trim()},readPdf=e=>{var t=e.lastIndexOf("trailer"),r=e.slice(t,e.length-6),f=r.slice(r.lastIndexOf("startxref")+10).toString(),f=parseInt(f),i=readRefTable(e),n=getValue(r,"/Root");return{xref:i,rootRef:n,root:findObject(e,i,n).toString(),infoRef:getValue(r,"/Info"),trailerStart:t,previousXrefs:[],xRefPosition:f}};export default readPdf;
@@ -1,118 +0,0 @@
import SignPdfError from './SignPdfError.js';
import xrefToRefMap from './xrefToRefMap.js';
export const getLastTrailerPosition = (pdf) => {
const trailerStart = pdf.lastIndexOf(Buffer.from('trailer', 'utf8'));
const trailer = pdf.slice(trailerStart, pdf.length - 6);
const xRefPosition = trailer
.slice(trailer.lastIndexOf(Buffer.from('startxref', 'utf8')) + 10)
.toString();
return parseInt(xRefPosition);
};
export const getXref = (pdf, position) => {
let refTable = pdf.slice(position); // slice starting from where xref starts
const realPosition = refTable.indexOf(Buffer.from('xref', 'utf8'));
if (realPosition === -1) {
throw new SignPdfError(
`Could not find xref anywhere at or after ${position}.`,
SignPdfError.TYPE_PARSE,
);
}
if (realPosition > 0) {
const prefix = refTable.slice(0, realPosition);
if (prefix.toString().replace(/\s*/g, '') !== '') {
throw new SignPdfError(
`Expected xref at ${position} but found other content.`,
SignPdfError.TYPE_PARSE,
);
}
}
const nextEofPosition = refTable.indexOf(Buffer.from('%%EOF', 'utf8'));
if (nextEofPosition === -1) {
throw new SignPdfError(
'Expected EOF after xref and trailer but could not find one.',
SignPdfError.TYPE_PARSE,
);
}
refTable = refTable.slice(0, nextEofPosition);
refTable = refTable.slice(realPosition + 4); // move ahead with the "xref"
refTable = refTable.slice(refTable.indexOf('\n') + 1); // move after the next new line
// extract the size
let size = refTable.toString().split('/Size')[1];
if (!size) {
throw new SignPdfError(
'Size not found in xref table.',
SignPdfError.TYPE_PARSE,
);
}
size = (/^\s*(\d+)/).exec(size);
if (size === null) {
throw new SignPdfError(
'Failed to parse size of xref table.',
SignPdfError.TYPE_PARSE,
);
}
size = parseInt(size[1]);
const [objects, infos] = refTable.toString().split('trailer');
const isContainingPrev = infos.split('/Prev')[1] != null;
let prev;
if (isContainingPrev) {
const pagesRefRegex = /Prev (\d+)/g;
const match = pagesRefRegex.exec(infos);
const [, prevPosition] = match;
prev = prevPosition;
}
const xRefContent = xrefToRefMap(objects);
return {
size,
prev,
xRefContent,
};
};
export const getFullXrefTable = (pdf) => {
const lastTrailerPosition = getLastTrailerPosition(pdf);
const lastXrefTable = getXref(pdf, lastTrailerPosition);
if (lastXrefTable.prev === undefined) {
return lastXrefTable.xRefContent;
}
const pdfWithoutLastTrailer = pdf.slice(0, lastTrailerPosition);
const partOfXrefTable = getFullXrefTable(pdfWithoutLastTrailer);
const mergedXrefTable = new Map([
...partOfXrefTable,
...lastXrefTable.xRefContent,
]);
return mergedXrefTable;
};
/**
* @param {Buffer} pdfBuffer
* @returns {object}
*/
const readRefTable = (pdf) => {
const fullXrefTable = getFullXrefTable(pdf);
const startingIndex = 0;
const maxIndex = Math.max(...fullXrefTable.keys());
return {
startingIndex,
maxIndex,
offsets: fullXrefTable,
};
};
export default readRefTable;
@@ -0,0 +1 @@
import SignPdfError from"./SignPdfError.min.js";import xrefToRefMap from"./xrefToRefMap.min.js";const getLastTrailerPosition=e=>{var r=e.lastIndexOf(Buffer.from("trailer","utf8")),r=e.slice(r,e.length-6),e=r.slice(r.lastIndexOf(Buffer.from("startxref","utf8"))+10).toString();return parseInt(e)},getXref=(e,r)=>{let t=e.slice(r);e=t.indexOf(Buffer.from("xref","utf8"));if(-1===e)throw new SignPdfError(`Could not find xref anywhere at or after ${r}.`,SignPdfError.TYPE_PARSE);if(0<e&&""!==t.slice(0,e).toString().replace(/\s*/g,""))throw new SignPdfError(`Expected xref at ${r} but found other content.`,SignPdfError.TYPE_PARSE);r=t.indexOf(Buffer.from("%%EOF","utf8"));if(-1===r)throw new SignPdfError("Expected EOF after xref and trailer but could not find one.",SignPdfError.TYPE_PARSE);if(!(r=(t=(t=(t=t.slice(0,r)).slice(e+4)).slice(t.indexOf("\n")+1)).toString().split("/Size")[1]))throw new SignPdfError("Size not found in xref table.",SignPdfError.TYPE_PARSE);if(null===(r=/^\s*(\d+)/.exec(r)))throw new SignPdfError("Failed to parse size of xref table.",SignPdfError.TYPE_PARSE);var r=parseInt(r[1]),[e,f]=t.toString().split("trailer");let n;null!=f.split("/Prev")[1]&&([,f]=/Prev (\d+)/g.exec(f),n=f);f=xrefToRefMap(e);return{size:r,prev:n,xRefContent:f}},getFullXrefTable=e=>{var r=getLastTrailerPosition(e),t=getXref(e,r);return void 0===t.prev?t.xRefContent:(e=e.slice(0,r),r=getFullXrefTable(e),new Map([...r,...t.xRefContent]))},readRefTable=e=>{e=getFullXrefTable(e);return{startingIndex:0,maxIndex:Math.max(...e.keys()),offsets:e}};export default readRefTable;export{getLastTrailerPosition,getXref,getFullXrefTable};
@@ -1,42 +0,0 @@
import SignPdfError from './SignPdfError.js';
const sliceLastChar = (pdf, character) => {
const lastChar = pdf.slice(pdf.length - 1).toString();
if (lastChar === character) {
return pdf.slice(0, pdf.length - 1);
}
return pdf;
};
/**
* Removes a trailing new line if there is such.
*
* Also makes sure the file ends with an EOF line as per spec.
* @param {Buffer} pdf
* @returns {Buffer}
*/
const removeTrailingNewLine = (pdf) => {
if (!(pdf instanceof Buffer)) {
throw new SignPdfError(
'PDF expected as Buffer.',
SignPdfError.TYPE_INPUT,
);
}
let output = pdf;
output = sliceLastChar(output, '\n');
output = sliceLastChar(output, '\r');
const lastLine = output.slice(output.length - 6).toString();
if (lastLine !== '\n%%EOF') {
throw new SignPdfError(
'A PDF file must end with an EOF line.',
SignPdfError.TYPE_PARSE,
);
}
return output;
};
export default removeTrailingNewLine;
@@ -0,0 +1 @@
import SignPdfError from"./SignPdfError.min.js";const sliceLastChar=(r,e)=>{return r.slice(r.length-1).toString()===e?r.slice(0,r.length-1):r},removeTrailingNewLine=r=>{if(!(r instanceof Buffer))throw new SignPdfError("PDF expected as Buffer.",SignPdfError.TYPE_INPUT);r=sliceLastChar(r,"\n");if("\n%%EOF"!==(r=sliceLastChar(r,"\r")).slice(r.length-6).toString())throw new SignPdfError("A PDF file must end with an EOF line.",SignPdfError.TYPE_PARSE);return r};export default removeTrailingNewLine;
@@ -1,48 +0,0 @@
import SignPdfError from './SignPdfError.js';
const xrefToRefMap = (xrefString) => {
const lines = xrefString.split('\n').filter((l) => l !== '');
let index = 0;
let expectedLines = 0;
const xref = new Map();
lines.forEach((line) => {
const split = line.split(' ');
if (split.length === 2) {
index = parseInt(split[0]);
expectedLines = parseInt(split[1]);
return;
}
if (expectedLines <= 0) {
throw new SignPdfError(
'Too many lines in xref table.',
SignPdfError.TYPE_PARSE,
);
}
expectedLines -= 1;
const [offset, , inUse] = split;
if (inUse.trim() === 'f') {
index += 1;
return;
}
if (inUse.trim() !== 'n') {
throw new SignPdfError(
`Unknown in-use flag "${inUse}". Expected "n" or "f".`,
SignPdfError.TYPE_PARSE,
);
}
if (!/^\d+$/.test(offset.trim())) {
throw new SignPdfError(
`Expected integer offset. Got "${offset}".`,
SignPdfError.TYPE_PARSE,
);
}
const storeOffset = parseInt(offset.trim());
xref.set(index, storeOffset);
index += 1;
});
return xref;
};
export default xrefToRefMap;
@@ -0,0 +1 @@
import SignPdfError from"./SignPdfError.min.js";const xrefToRefMap=r=>{r=r.split("\n").filter(r=>""!==r);let n=0,t=0;const f=new Map;return r.forEach(r=>{r=r.split(" ");if(2===r.length)n=parseInt(r[0]),t=parseInt(r[1]);else{if(t<=0)throw new SignPdfError("Too many lines in xref table.",SignPdfError.TYPE_PARSE);--t;var[r,,e]=r;if("f"!==e.trim()){if("n"!==e.trim())throw new SignPdfError(`Unknown in-use flag "${e}". Expected "n" or "f".`,SignPdfError.TYPE_PARSE);if(!/^\d+$/.test(r.trim()))throw new SignPdfError(`Expected integer offset. Got "${r}".`,SignPdfError.TYPE_PARSE);e=parseInt(r.trim());f.set(n,e)}n+=1}}),f};export default xrefToRefMap;