Skip to content
Snippets Groups Projects
Commit 8b62dd4e authored by Zdravko Iliev's avatar Zdravko Iliev
Browse files

without build

parent b9493bc3
No related branches found
No related tags found
No related merge requests found
Showing
with 62 additions and 898 deletions
declare class GeneralError extends Error {
constructor(message: string);
}
declare class AppError extends GeneralError {
}
export { GeneralError, AppError };
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.AppError = exports.GeneralError = void 0;
class GeneralError extends Error {
constructor(message) {
super();
this.message = message;
}
}
exports.GeneralError = GeneralError;
class AppError extends GeneralError {
}
exports.AppError = AppError;
/// <reference types="node" />
export declare const checkForSubFilter: (pdfBuffer: Buffer) => void;
export declare const getByteRange: (pdfBuffer: Buffer) => {
byteRangePlaceholder: string;
byteRanges: number[][];
};
export declare const preparePDF: (pdf: any) => Buffer;
export declare const getMetaRegexMatch: (keyName: string) => (str: any) => any;
export declare const isPDF: (buf: Buffer) => boolean;
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.isPDF = exports.getMetaRegexMatch = exports.preparePDF = exports.getByteRange = exports.checkForSubFilter = void 0;
const errors_1 = require("./errors");
const DEFAULT_BYTE_RANGE_PLACEHOLDER = "**********";
const checkForSubFilter = (pdfBuffer) => {
const matches = pdfBuffer.toString().match(/\/SubFilter\s*\/([\w.]*)/);
const subFilter = Array.isArray(matches) && matches[1];
if (!subFilter) {
throw new errors_1.AppError("Can not find subfilter");
}
const supportedTypes = [
"adbe.pkcs7.detached",
"etsi.cades.detached",
"etsi.rfc3161",
];
if (!supportedTypes.includes(subFilter.trim().toLowerCase())) {
throw new errors_1.AppError("Subfilter not supported");
}
};
exports.checkForSubFilter = checkForSubFilter;
const getByteRange = (pdfBuffer) => {
const byteRangeStrings = pdfBuffer
.toString()
.match(/\/ByteRange\s*\[{1}\s*(?:(?:\d*|\/\*{10})\s+){3}(?:\d+|\/\*{10}){1}\s*\]{1}/g);
const byteRangePlaceholder = byteRangeStrings.find((s) => s.includes(`/${DEFAULT_BYTE_RANGE_PLACEHOLDER}`));
const strByteRanges = byteRangeStrings.map((brs) => brs.match(/[^[\s]*(?:\d|\/\*{10})/g));
const byteRanges = strByteRanges.map((n) => n.map(Number));
return {
byteRangePlaceholder,
byteRanges,
};
};
exports.getByteRange = getByteRange;
const preparePDF = (pdf) => {
try {
if (Buffer.isBuffer(pdf))
return pdf;
return Buffer.from(pdf);
}
catch (error) {
throw new errors_1.AppError(error);
}
};
exports.preparePDF = preparePDF;
const getMetaRegexMatch = (keyName) => (str) => {
const regex = new RegExp(`/${keyName}\\s*\\(([\\w.\\s@+~_\\-://,]*)`, "g");
const matches = [...str.matchAll(regex)];
const meta = matches.length ? matches[matches.length - 1][1] : null;
return meta;
};
exports.getMetaRegexMatch = getMetaRegexMatch;
const isPDF = (buf) => {
return (Buffer.isBuffer(buf) &&
buf.lastIndexOf("%PDF-") === 0 &&
buf.lastIndexOf("%%EOF") > -1);
};
exports.isPDF = isPDF;
/// <reference types="node" />
export declare const verifyPDF: (pdf: Buffer) => {
expired: any;
signatures: any;
verified?: undefined;
message?: undefined;
error?: undefined;
} | {
verified: boolean;
message: any;
error: any;
expired?: undefined;
signatures?: undefined;
};
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.verifyPDF = void 0;
const generalUtils_1 = require("./generalUtils");
const signatureUtils_1 = require("./signatureUtils");
const verify_1 = require("./verify");
const verifyPDF = (pdf) => {
const pdfBuffer = (0, generalUtils_1.preparePDF)(pdf);
try {
(0, generalUtils_1.checkForSubFilter)(pdfBuffer);
}
catch (error) {
console.log("no supported signatures found");
return null;
}
try {
const { signatureStr, signedData, signatureMeta } = (0, signatureUtils_1.extractSignature)(pdfBuffer);
const signatures = signedData.map((_signed, index) => {
return (0, verify_1.verify)(signatureStr[index], signatureMeta[index]);
});
return {
// authenticity: signatures.every((o) => o.authenticity === true),
expired: signatures.some((o) => o.expired === true),
signatures,
};
}
catch (error) {
return { verified: false, message: error.message, error };
}
};
exports.verifyPDF = verifyPDF;
export declare const extractSignature: (pdf: any) => {
byteRanges: number[][];
signatureStr: any[];
signedData: any[];
signatureMeta: {
reason: any;
contactInfo: any;
location: any;
signDate: string;
}[];
};
export declare const getMessageFromSignature: (signature: any) => any;
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.getMessageFromSignature = exports.extractSignature = void 0;
const forge = __importStar(require("@vereign/node-forge"));
const errors_1 = require("./errors");
const generalUtils_1 = require("./generalUtils");
const timeUtils_1 = require("./timeUtils");
// const rootCAs = require("./rootCAs");
const getSignatureMeta = (signedData) => {
const str = Buffer.isBuffer(signedData) ? signedData.toString() : signedData;
const formattedSignDate = (0, timeUtils_1.formatPdfTime)((0, generalUtils_1.getMetaRegexMatch)("M")(str));
return {
reason: (0, generalUtils_1.getMetaRegexMatch)("Reason")(str),
contactInfo: (0, generalUtils_1.getMetaRegexMatch)("ContactInfo")(str),
location: (0, generalUtils_1.getMetaRegexMatch)("Location")(str),
signDate: formattedSignDate,
};
};
// const verifyCaBundle = (certs) =>
// !!certs.find((cert, i) => certs[i + 1] && certs[i + 1].issued(cert));
// const getRootCAs = () => rootCAs;
// const verifyRootCert = (chainRootInForgeFormat) =>
// !!getRootCAs().find((rootCAInPem) => {
// try {
// const rootCAInForgeCert = forge.pki.certificateFromPem(rootCAInPem);
// return (
// forge.pki.certificateToPem(chainRootInForgeFormat) === rootCAInPem ||
// rootCAInForgeCert.issued(chainRootInForgeFormat)
// );
// } catch (e) {
// return false;
// }
// });
const extractSignature = (pdf) => {
const pdfBuffer = (0, generalUtils_1.preparePDF)(pdf);
const { byteRanges } = (0, generalUtils_1.getByteRange)(pdfBuffer);
const signatureStr = [];
const signedData = [];
byteRanges.forEach((byteRange) => {
signedData.push(Buffer.concat([
pdfBuffer.slice(byteRange[0], byteRange[0] + byteRange[1]),
pdfBuffer.slice(byteRange[2], byteRange[2] + byteRange[3]),
]));
const signatureHex = pdfBuffer
.slice(byteRange[0] + byteRange[1] + 1, byteRange[2])
.toString("latin1");
signatureStr.push(Buffer.from(signatureHex, "hex").toString("latin1"));
});
const signatureMeta = signedData.map((sd) => getSignatureMeta(sd));
return {
byteRanges,
signatureStr,
signedData,
signatureMeta,
};
};
exports.extractSignature = extractSignature;
const getMessageFromSignature = (signature) => {
try {
const p7Asn1 = forge.asn1.fromDer(signature);
return forge.pkcs7.messageFromAsn1(p7Asn1);
}
catch (error) {
//no signature is found return empty object
if (error.message === "Too few bytes to parse DER.") {
return {};
}
throw new errors_1.AppError(error);
}
};
exports.getMessageFromSignature = getMessageFromSignature;
// export const authenticateSignature = (certs) =>
// verifyCaBundle(certs) && verifyRootCert(certs[certs.length - 1]);
export declare const formatPdfTime: (datetimeString: string) => string;
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.formatPdfTime = void 0;
const formatPdfTime = (datetimeString) => {
if (!datetimeString)
return;
const result = datetimeString.split("D:");
const timestamp = result[1].split("Z");
const year = timestamp[0].substring(0, 4);
const month = timestamp[0].substring(4, 6);
const day = timestamp[0].substring(6, 8);
const hours = timestamp[0].substring(8, 10);
const min = timestamp[0].substring(10, 12);
const seconds = timestamp[0].substring(12, 14);
return `${year}.${month}.${day} ${hours}:${min}:${seconds}`;
};
exports.formatPdfTime = formatPdfTime;
export declare const verify: (signature: any, signatureMeta: any) => {
isExpired: boolean;
meta: any;
};
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.verify = void 0;
const forge = __importStar(require("@vereign/node-forge"));
const certUtils_1 = require("./certUtils");
const errors_1 = require("./errors");
const signatureUtils_1 = require("./signatureUtils");
const verify = (signature, signatureMeta) => {
const message = (0, signatureUtils_1.getMessageFromSignature)(signature);
const { certificates, rawCapture: { signature: sig, authenticatedAttributes: attrs, digestAlgorithm, }, } = message;
const hashAlgorithmOid = forge.asn1.derToOid(digestAlgorithm);
const hashAlgorithm = forge.pki.oids[hashAlgorithmOid].toLowerCase();
const set = forge.asn1.create(forge.asn1.Class.UNIVERSAL, forge.asn1.Type.SET, true, attrs);
const clientCertificate = (0, certUtils_1.getClientCertificate)(certificates);
const digest = forge.md[hashAlgorithm]
.create()
.update(forge.asn1.toDer(set).data)
.digest()
.getBytes();
const validAuthenticatedAttributes = clientCertificate["publicKey"].verify(digest, sig);
if (!validAuthenticatedAttributes) {
throw new errors_1.AppError("Wrong authenticated attributes");
}
// WIP: fix integrity check
// const messageDigestAttr = forge.pki.oids.messageDigest;
// const fullAttrDigest = attrs.find(
// (attr) => forge.asn1.derToOid(attr.value[0].value) === messageDigestAttr
// );
// const attrDigest = fullAttrDigest.value[1].value[0].value;
// const dataDigest = forge.md[hashAlgorithm]
// .create()
// .update(signedData.toString("latin1"))
// .digest()
// .getBytes();
// const integrity = dataDigest === attrDigest;
const sortedCerts = (0, certUtils_1.sortCertificateChain)(certificates);
const parsedCerts = (0, certUtils_1.extractCertificatesDetails)(sortedCerts);
//WIP: fix authenticity check after you have the root cert
// const authenticity = authenticateSignature(sortedCerts);
const isExpired = (0, certUtils_1.isCertsExpired)(sortedCerts);
return {
// verified: integrity && authenticity && !expired,
// authenticity,
// integrity,
isExpired,
meta: Object.assign({ certs: parsedCerts }, signatureMeta),
};
};
exports.verify = verify;
/// <reference types="node" />
import { IGetMetaResponse } from "./types";
declare type SealCoords = {
[key: string]: {
x: string;
y: string;
};
};
declare class PDFparser {
readonly document: any;
readonly config: any;
constructor(document: Buffer);
getPDFMeta: () => Promise<IGetMetaResponse>;
insertQrCode: (imgBytes: ArrayBuffer, url: string, coords: SealCoords, scaleFactor: number) => Promise<ArrayBuffer>;
private createPageLinkAnnotation;
}
export default PDFparser;
"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
const pdf_lib_1 = require("pdf-lib");
const pdfdataextract_1 = require("pdfdataextract");
const config_1 = require("./config");
const lib_1 = require("./lib");
const timeUtils_1 = require("./lib/timeUtils");
const errors_1 = require("./lib/errors");
const generalUtils_1 = require("./lib/generalUtils");
class PDFparser {
constructor(document) {
this.getPDFMeta = () => __awaiter(this, void 0, void 0, function* () {
if (!(this.document instanceof Buffer)) {
throw new errors_1.AppError("Document is not Buffer");
}
if (!(0, generalUtils_1.isPDF)(this.document)) {
throw new errors_1.AppError("Only pdf file type is supported");
}
try {
const signaturesMeta = yield (0, lib_1.verifyPDF)(this.document);
const pdfMeta = yield pdfdataextract_1.PdfData.extract(this.document, config_1.config);
const result = {
pages: pdfMeta.pages,
title: pdfMeta.info.Title || "Unknown",
author: pdfMeta.info.Author || "Unknown",
creation_date: (0, timeUtils_1.formatPdfTime)(pdfMeta.info.CreationDate),
mod_date: (0, timeUtils_1.formatPdfTime)(pdfMeta.info.ModDate),
};
if (signaturesMeta) {
result["signatures"] = signaturesMeta.signatures;
result["expired"] = signaturesMeta.expired;
}
return result;
}
catch (error) {
throw new errors_1.GeneralError(error);
}
});
this.insertQrCode = (imgBytes, url, coords, scaleFactor) => __awaiter(this, void 0, void 0, function* () {
const pdfDoc = yield pdf_lib_1.PDFDocument.load(this.document);
const img = yield pdfDoc.embedPng(imgBytes);
const scaled = img.scale(scaleFactor);
const pages = pdfDoc.getPages();
for (let index = 0; index < pages.length; index++) {
const page = pages[index];
const x = typeof coords[index + 1] !== "undefined"
? parseFloat(coords[index + 1].x)
: null;
const y = typeof coords[index + 1] !== "undefined"
? parseFloat(coords[index + 1].y)
: null;
if (x && y) {
page.drawImage(img, {
x,
y,
width: scaled.width,
height: scaled.height,
});
const link = this.createPageLinkAnnotation(page, url, {
imgXPos: x,
imgYPos: y,
imgWidth: scaled.width,
imagHeight: scaled.height,
});
page.node.set(pdf_lib_1.PDFName.of("Annots"), pdfDoc.context.obj([link]));
}
}
const pdfBytes = yield pdfDoc.save();
return pdfBytes;
});
this.createPageLinkAnnotation = (page, uri, { imgXPos, imgYPos, imgWidth, imagHeight }) => page.doc.context.register(page.doc.context.obj({
Type: "Annot",
Subtype: "Link",
Rect: [imgXPos, imgYPos, imgXPos + imgWidth, imgYPos + imagHeight],
A: {
Type: "Action",
S: "URI",
URI: pdf_lib_1.PDFString.of(uri),
},
}));
this.document = document;
this.config = config_1.config;
}
}
exports.default = PDFparser;
export interface ICert {
clientCertificate: boolean;
issuedBy: {
countryName: string;
organizationName: string;
commonName: string;
};
issuedTo: {
countryName: string;
organizationalUnitName: string;
organizationName: string;
commonName: string;
};
validityPeriod: {
notBefore: string;
notAfter: string;
};
pemCertificate: string;
}
export interface ISignature {
isExpired: boolean;
meta: {
certs: Array<ICert>;
reason: string;
contactInfo: string;
location: string;
signDate: string;
};
}
export interface IGetMetaResponse {
expired?: boolean;
signatures?: Array<ISignature>;
pages: number;
title: string;
author: string;
creation_date: string;
mod_date: string;
}
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
File deleted
// import { PDFName, PDFPage, PDFString, PDFDocument, PDFImage } from "pdf-lib";
import { nopodofo as npdf, NPDFImageFormat } from "nopodofo";
import { PdfData } from "pdfdataextract";
import { config } from "./config";
import { IGetMetaResponse } from "./types";
......@@ -7,46 +5,8 @@ import { verifyPDF } from "./lib";
import { formatPdfTime } from "./lib/timeUtils";
import { AppError, GeneralError } from "./lib/errors";
import { isPDF } from "./lib/generalUtils";
import {
getSignatureField,
pdf,
sign,
TimestampAndEnableLTV,
write,
} from "./utils";
import axios from "axios";
import {
createWriterToModify,
PDFPageModifier,
PDFRStreamForBuffer,
PDFWStreamForBuffer,
} from "hummus";
import Stream from "pdf-lib/cjs/core/streams/Stream";
import {
asPDFName,
degrees,
drawImage,
drawRectangle,
drawText,
PDFContentStream,
PDFDocument,
PDFName,
PDFOperator,
PDFOperatorNames,
PDFPage,
PDFString,
popGraphicsState,
pushGraphicsState,
rgb,
rotateDegrees,
translate,
} from "pdf-lib";
const { Readable } = require("stream");
const streams = require("memory-streams");
import signer from "node-signpdf";
import fs from "fs";
import { TimestampAndEnableLTV } from "./utils";
import { PDFNet } from "@pdftron/pdfnet-node";
// const { PDFNet } = require("@pdftron/pdfnet-node");
type SealCoords = {
[key: string]: { x: string; y: string };
......@@ -54,11 +14,9 @@ type SealCoords = {
class PDFparser {
readonly document;
readonly config;
constructor(document: Buffer) {
this.document = document;
this.config = config;
}
getPDFMeta = async (): Promise<IGetMetaResponse> => {
......@@ -97,218 +55,29 @@ class PDFparser {
imgBytes: ArrayBuffer,
url: string,
coords: SealCoords,
scaleFactor: number
scaleFactor: number,
licenseKey: string,
certPath: string,
certTSAUrl: string
): Promise<ArrayBuffer> => {
// tron pdf library start
// PDFNet.initialize(licenseKey);
await PDFNet.initialize(
"demo:1652778685773:7b893c000300000000b9c455b21b7b47780dc82f9ef63ddc54ce5c282b"
);
const input_path = `${__dirname}`;
// try {
// const doc = await PDFNet.PDFDoc.createFromBuffer(this.document);
// doc.initSecurityHandler();
// const approval_signature_field = await doc.createDigitalSignatureField(
// "PDFTronApprovalSig"
// );
// const widgetAnnotApproval =
// await PDFNet.SignatureWidget.createWithDigitalSignatureField(
// doc,
// new PDFNet.Rect(300, 287, 376, 306),
// approval_signature_field
// );
// const page1 = await doc.getPage(1);
// await page1.annotPushBack(widgetAnnotApproval);
// await doc.save(
// output_path + "abc.pdf",
// PDFNet.SDFDoc.SaveOptions.e_remove_unused
// );
// } catch (err) {
// console.log(err);
// }
const buf = await TimestampAndEnableLTV(
this.document,
`${__dirname}/GlobalSignRootForTST.cer`,
imgBytes
);
await PDFNet.initialize(licenseKey);
let buf;
try {
buf = await TimestampAndEnableLTV(
this.document,
certPath,
certTSAUrl,
imgBytes,
coords
);
} catch (error) {
console.log(error);
throw new GeneralError("Could Not sign pdf");
}
await PDFNet.shutdown();
return buf;
// try {
// if (
// !(await TimestampAndEnableLTV(
// this.document,
// input_path + "GlobalSignRootForTST.cer",
// input_path + "qrcode.png",
// output_path + "abc_LTV.pdf"
// ))
// ) {
// console.log("fail");
// }
// } catch (error) {
// console.log(error);
// }
// tron pdf library end
// lib-pdf signature start
// const pdfDoc = await PDFDocument.load(this.document);
// const pdfLibSigImg = await pdfDoc.embedPng(imgBytes);
// const pdfLibSigImgName = "PDF_LIB_SIG_IMG";
// const form = pdfDoc.getForm();
// const sig = form.getSignature("Signature1");
// sig.acroField.getWidgets().forEach((widget) => {
// const { context } = widget.dict;
// const { width, height } = widget.getRectangle();
// const appearance = [
// ...drawRectangle({
// x: 100,
// y: 0,
// width,
// height,
// borderWidth: 1,
// color: rgb(1, 0, 0),
// borderColor: rgb(1, 0.5, 0.75),
// rotate: degrees(0),
// xSkew: degrees(0),
// ySkew: degrees(0),
// }),
// ...drawImage(pdfLibSigImgName, {
// x: 100,
// y: 5,
// width: width - 10,
// height: height - 10,
// rotate: degrees(0),
// xSkew: degrees(0),
// ySkew: degrees(0),
// }),
// ];
// const stream = context.formXObject(appearance, {
// Resources: { XObject: { [pdfLibSigImgName]: pdfLibSigImg.ref } },
// BBox: context.obj([0, 0, width, height]),
// Matrix: context.obj([1, 0, 0, 1, 0, 0]),
// });
// const streamRef = context.register(stream);
// widget.setNormalAppearance(streamRef);
// });
// const pdfBytes = await pdfDoc.save();
// const signatureAppearanceStreamRef = this.imageAppearanceStream();
// pdfDoc.context.obj({
// Type: "Annot",
// Subtype: "Widget",
// FT: "Sig",
// Rect: [image.width, image.height, 0, 0],
// V: signatureDictRef,
// T: PDFString.of("Signature1"),
// F: 4,
// P: pages[pages.length - 1].ref, //lastPage
// AP: pdfDoc.context.obj({ N: signatureAppearanceStreamRef }),
// });
// for (let index = 0; index < pages.length; index++) {
// const page = pages[index];
// const x =
// typeof coords[index + 1] !== "undefined"
// ? parseFloat(coords[index + 1].x)
// : null;
// const y =
// typeof coords[index + 1] !== "undefined"
// ? parseFloat(coords[index + 1].y)
// : null;
// if (x && y) {
// page.drawImage(img, {
// x,
// y,
// width: scaled.width,
// height: scaled.height,
// });
// const link = this.createPageLinkAnnotation(page, url, {
// imgXPos: x,
// imgYPos: y,
// imgWidth: scaled.width,
// imagHeight: scaled.height,
// });
// page.node.set(PDFName.of("Annots"), pdfDoc.context.obj([link]));
// }
// }
// const pdfBytes = await pdfDoc.save();
//lib-pdf end
//HUMMUS lib start
// const result = new PDFWStreamForBuffer();
// const pdfWriter = createWriterToModify(
// new PDFRStreamForBuffer(Buffer.from(this.document)),
// result
// );
// const imageOptions = {
// transformation: [0.5, 0, 0, 0.5, 0, 0],
// index: 1000,
// };
// const pageModifier = new PDFPageModifier(pdfWriter, 0);
// pageModifier
// .startContext()
// .getContext()
// .drawImage(0, 100, __dirname + "/qrcode.png", imageOptions);
// pageModifier.endContext().writePage();
// pdfWriter.end();
//HUMMUS lib end
//qrcode as a signature nopodofo pdf lib start
// const pdfDoc = await pdf(this.document);
// const field = getSignatureField(pdfDoc);
// const signer = new npdf.Signer(pdfDoc);
// signer.signatureField = field;
// const result = await sign(signer);
//qrcode as a signature nopodofo pdf lib end
// return result;
// return pdfBytes;
// return result;
//node signer
//node signer
};
private createPageLinkAnnotation = (
page: PDFPage,
uri: string,
{ imgXPos, imgYPos, imgWidth, imagHeight }
) =>
page.doc.context.register(
page.doc.context.obj({
Type: "Annot",
Subtype: "Link",
Rect: [imgXPos, imgYPos, imgXPos + imgWidth, imgYPos + imagHeight],
A: {
Type: "Action",
S: "URI",
URI: PDFString.of(uri),
},
})
);
// imageAppearanceStream(image, rotation, width, height) {
// const dict = image.doc.context.obj({
// Type: "XObject",
// Subtype: "Form",
// FormType: 1,
// BBox: [0, 0, width, height],
// Resources: { XObject: { Image: image.ref } },
// });
// const operators = [
// rotateDegrees(rotation),
// translate(0, rotation % 90 === 0 ? -width : 0),
// ...drawImage("Image", {
// x: 0,
// y: width, //y = 0 is width for me
// width: width,
// height: height,
// rotate: degrees(0),
// xSkew: degrees(0),
// ySkew: degrees(0),
// }),
// ];
// const stream = PDFContentStream.of(dict, operators, false);
// return image.doc.context.register(stream);
// }
}
export default PDFparser;
import {
nopodofo as npdf,
NPDFAnnotation,
NPDFAnnotationFlag,
pdfDate,
} from "nopodofo";
import path from "path";
import { readFileSync } from "fs";
import { PDFNet } from "@pdftron/pdfnet-node";
export const pdf = (document: any): Promise<any> => {
return new Promise((resolve, reject) => {
const doc = new npdf.Document();
return doc.load(document, { forUpdate: true }, (e, data: any) => {
if (e instanceof Error) {
reject(e);
}
resolve(data);
});
});
};
export const write = (document: any): Promise<Buffer> => {
return new Promise((resolve, reject) => {
document.write((err, buf) => {
if (err instanceof Error) {
reject(err);
}
resolve(buf);
});
});
};
export const getSignatureField = (doc: any) => {
const rect = new npdf.Rect(360, 685, 50, 20),
page = doc.getPage(0),
annot = page.createAnnotation(NPDFAnnotation.Widget, rect);
annot.flags = NPDFAnnotationFlag.Print;
const image = new npdf.Image(doc, path.join(__dirname, "/qrcode.png"));
const painter = new npdf.Painter(doc);
painter.setPage(page);
painter.drawImage(image, rect.left, rect.bottom, {
width: rect.width,
height: rect.height,
});
painter.finishPage();
// end apply image to page
const field = new npdf.SignatureField(annot, doc);
// Set field properties
field.setReason("test");
field.setLocation("here");
field.setCreator("me");
field.setFieldName("signer.sign");
// This will set the date as now
field.setDate();
return field;
};
export const sign = (signer: any): Promise<Buffer> => {
const certificate = Buffer.from(
readFileSync(path.join(__dirname, "/certificate.pem"))
);
const pkey = Buffer.from(readFileSync(path.join(__dirname, "/key.pem")));
return new Promise((resolve, reject) => {
signer.loadCertificateAndKey(
certificate,
{
pKey: pkey,
},
(error, signatureLength) => {
if (error) {
reject(error);
}
signer.write(signatureLength, (e, d) => {
if (e) {
reject(e);
}
resolve(d);
});
}
);
});
};
function writeAp(pdfWriter, { w, h }, text, objId) {
const xf = pdfWriter.createFormXObject(0, 0, w, h, objId);
// draw text starting 1/4 of the way up
const textY = h / 4;
xf.getContentContext().writeText(text, 0, textY, {
size: fontSize,
colorspace: "rgb",
color: 0xfc2125,
font: arialFont,
});
pdfWriter.endFormXObject(xf);
}
export const TimestampAndEnableLTV = async (
in_docpath,
tsa_url,
in_trusted_cert_path,
in_appearance_img_path
in_appearance_img_path,
coords
) => {
const doc = await PDFNet.PDFDoc.createFromBuffer(in_docpath);
doc.initSecurityHandler();
const doctimestamp_signature_field = await doc.createDigitalSignatureField();
const tst_config = await PDFNet.TimestampingConfiguration.createFromURL(
"http://rfc3161timestamp.globalsign.com/advanced"
tsa_url
);
const opts = await PDFNet.VerificationOptions.create(
PDFNet.VerificationOptions.SecurityLevel.e_compatibility_and_archiving
);
/* It is necessary to add to the VerificationOptions a trusted root certificate corresponding to
the chain used by the timestamp authority to sign the timestamp token, in order for the timestamp
response to be verifiable during DocTimeStamp signing. It is also necessary in the context of this
function to do this for the later LTV section, because one needs to be able to verify the DocTimeStamp
in order to enable LTV for it, and we re-use the VerificationOptions opts object in that part. */
await opts.addTrustedCertificateUString(in_trusted_cert_path);
/* By default, we only check online for revocation of certificates using the newer and lighter
OCSP protocol as opposed to CRL, due to lower resource usage and greater reliability. However,
it may be necessary to enable online CRL revocation checking in order to verify some timestamps
(i.e. those that do not have an OCSP responder URL for all non-trusted certificates). */
await opts.enableOnlineCRLRevocationChecking(true);
const widgetAnnot =
await PDFNet.SignatureWidget.createWithDigitalSignatureField(
doc,
new PDFNet.Rect(0, 100, 200, 150),
doctimestamp_signature_field
);
await (await doc.getPage(1)).annotPushBack(widgetAnnot);
await opts.addTrustedCertificateUString(in_trusted_cert_path);
// (OPTIONAL) Add an appearance to the signature field.
const img = await PDFNet.Image.createFromMemory2(doc, in_appearance_img_path);
await widgetAnnot.createSignatureAppearance(img);
console.log("Testing timestamping configuration.");
const config_result = await tst_config.testConfiguration(opts);
if (await config_result.getStatus()) {
console.log(
"Success: timestamping configuration usable. Attempting to timestamp."
);
} else {
// Print details of timestamping failure.
console.log(await config_result.getString());
if (await config_result.hasResponseVerificationResult()) {
const tst_result = await config_result.getResponseVerificationResult();
console.log(
"CMS digest status: " + (await tst_result.getCMSDigestStatusAsString())
);
console.log(
"Message digest status: " +
(await tst_result.getMessageImprintDigestStatusAsString())
);
console.log(
"Trust status: " + (await tst_result.getTrustStatusAsString())
);
//make this dynamic with canvas lib
const imgWidth = 300;
const imgHeight = 300;
const pagesForSining = Object.keys(coords).map((k) => {
return parseInt(k);
});
const pages = await doc.getPageCount();
let result;
for (let p = 1; p <= pages; p++) {
if (!pagesForSining.includes(p)) {
continue;
}
// return false; throw error instead
}
const page = await doc.getPage(p);
const doctimestamp_signature_field =
await doc.createDigitalSignatureField();
const widgetAnnot =
await PDFNet.SignatureWidget.createWithDigitalSignatureField(
doc,
new PDFNet.Rect(
parseFloat(coords[p].x),
parseFloat(coords[p].x + imgWidth),
parseFloat(coords[p].y),
parseFloat(coords[p].y + imgHeight)
),
doctimestamp_signature_field
);
await doctimestamp_signature_field.timestampOnNextSave(tst_config, opts);
await page.annotPushBack(widgetAnnot);
await widgetAnnot.createSignatureAppearance(img);
await doctimestamp_signature_field.timestampOnNextSave(tst_config, opts);
// Save/signing throws if timestamping fails.
const res = await doc.saveMemoryBuffer(
PDFNet.SDFDoc.SaveOptions.e_incremental
);
result = await doc.saveMemoryBuffer(
PDFNet.SDFDoc.SaveOptions.e_incremental
);
}
return res.buffer;
return result.buffer;
};
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment