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

build

parent 8b62dd4e
No related branches found
No related tags found
No related merge requests found
Showing
with 532 additions and 0 deletions
import { VerbosityLevel } from "pdfdataextract";
export declare const config: {
verbosity: VerbosityLevel;
get: {
pages: boolean;
text: boolean;
fingerprint: boolean;
outline: boolean;
metadata: boolean;
info: boolean;
permissions: boolean;
};
};
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.config = void 0;
const pdfdataextract_1 = require("pdfdataextract");
exports.config = {
verbosity: pdfdataextract_1.VerbosityLevel.ERRORS,
get: {
// enable or disable data extraction (all are optional and enabled by default)
pages: true,
text: false,
fingerprint: false,
outline: false,
metadata: false,
info: true,
permissions: false, // get permissions
},
};
import PDFparser from "./pdfParser";
export default PDFparser;
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const pdfParser_1 = __importDefault(require("./pdfParser"));
exports.default = pdfParser_1.default;
export declare const extractCertificatesDetails: (certs: any) => any;
export declare const sortCertificateChain: (certs: any) => unknown[];
export declare const getClientCertificate: (certs: any) => unknown;
export declare const isCertsExpired: (certs: any) => boolean;
"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.isCertsExpired = exports.getClientCertificate = exports.sortCertificateChain = exports.extractCertificatesDetails = void 0;
const forge = __importStar(require("@vereign/node-forge"));
const issued = (cert) => (anotherCert) => cert !== anotherCert && anotherCert.issued(cert);
const getIssuer = (certsArray) => (cert) => certsArray.find(issued(cert));
const inverse = (f) => (x) => !f(x);
const hasNoIssuer = (certsArray) => inverse(getIssuer(certsArray));
const getChainRootCertificateIdx = (certsArray) => certsArray.findIndex(hasNoIssuer(certsArray));
const isIssuedBy = (cert) => (anotherCert) => cert !== anotherCert && cert.issued(anotherCert);
const getChildIdx = (certsArray) => (parent) => certsArray.findIndex(isIssuedBy(parent));
const extractCertificatesDetails = (certs) => certs.map(extractSingleCertificateDetails).map((cert, i) => {
if (i)
return cert;
return Object.assign({ clientCertificate: true }, cert);
});
exports.extractCertificatesDetails = extractCertificatesDetails;
const mapEntityAtrributes = (attrs) => attrs.reduce((agg, { name, value }) => {
if (!name)
return agg;
agg[name] = value;
return agg;
}, {});
const extractSingleCertificateDetails = (cert) => {
const { issuer, subject, validity } = cert;
return {
issuedBy: mapEntityAtrributes(issuer.attributes),
issuedTo: mapEntityAtrributes(subject.attributes),
validityPeriod: validity,
pemCertificate: forge.pki.certificateToPem(cert),
};
};
const sortCertificateChain = (certs) => {
const certsArray = Array.from(certs);
const rootCertIndex = getChainRootCertificateIdx(certsArray);
const certificateChain = certsArray.splice(rootCertIndex, 1);
while (certsArray.length) {
const lastCert = certificateChain[0];
const childCertIdx = getChildIdx(certsArray)(lastCert);
if (childCertIdx === -1)
certsArray.splice(childCertIdx, 1);
else {
const [childCert] = certsArray.splice(childCertIdx, 1);
certificateChain.unshift(childCert);
}
}
return certificateChain;
};
exports.sortCertificateChain = sortCertificateChain;
const getClientCertificate = (certs) => (0, exports.sortCertificateChain)(certs)[0];
exports.getClientCertificate = getClientCertificate;
const isCertsExpired = (certs) => !!certs.find(({ validity: { notAfter, notBefore } }) => notAfter.getTime() < Date.now() || notBefore.getTime() > Date.now());
exports.isCertsExpired = isCertsExpired;
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;
constructor(document: Buffer);
getPDFMeta: () => Promise<IGetMetaResponse>;
insertQrCode: (imgBytes: ArrayBuffer, url: string, coords: SealCoords, scaleFactor: number, licenseKey: string, certPath: string, certTSAUrl: string) => Promise<ArrayBuffer>;
}
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 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");
const utils_1 = require("./utils");
const pdfnet_node_1 = require("@pdftron/pdfnet-node");
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, licenseKey, certPath, certTSAUrl) => __awaiter(this, void 0, void 0, function* () {
yield pdfnet_node_1.PDFNet.initialize(licenseKey);
let buf;
try {
buf = yield (0, utils_1.TimestampAndEnableLTV)(this.document, certPath, certTSAUrl, imgBytes, coords);
}
catch (error) {
console.log(error);
throw new errors_1.GeneralError("Could Not sign pdf");
}
yield pdfnet_node_1.PDFNet.shutdown();
return buf;
});
this.document = document;
}
}
exports.default = PDFparser;
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment