From 6ef22966bcef664fc7c3435a6a5271bc6cc05681 Mon Sep 17 00:00:00 2001 From: Zdravko Iliev <zdravko.iliev@vereign.com> Date: Wed, 19 Jan 2022 16:32:02 +0200 Subject: [PATCH] pdf meta parser --- .gitignore | 1 - __tests__/example.pdf | Bin 0 -> 58791 bytes __tests__/index.test.ts | 18 ++++++++++----- dist/config.d.ts | 13 +++++++++++ dist/config.js | 17 ++++++++++++++ dist/index.d.ts | 2 ++ dist/index.js | 4 ++++ dist/pdfParser.d.ts | 9 ++++++++ dist/pdfParser.js | 48 ++++++++++++++++++++++++++++++++++++++++ dist/types.d.ts | 38 +++++++++++++++++++++++++++++++ dist/types.js | 2 ++ package.json | 5 ++++- src/config.ts | 15 +++++++++++++ src/index.ts | 6 ++--- src/pdfParser.ts | 44 ++++++++++++++++++++++++++++++++++++ src/types.ts | 37 +++++++++++++++++++++++++++++++ yarn.lock | 24 ++++++++++++++++++++ 17 files changed, 273 insertions(+), 10 deletions(-) create mode 100644 __tests__/example.pdf create mode 100644 dist/config.d.ts create mode 100644 dist/config.js create mode 100644 dist/index.d.ts create mode 100644 dist/index.js create mode 100644 dist/pdfParser.d.ts create mode 100644 dist/pdfParser.js create mode 100644 dist/types.d.ts create mode 100644 dist/types.js create mode 100644 src/config.ts create mode 100644 src/pdfParser.ts create mode 100644 src/types.ts diff --git a/.gitignore b/.gitignore index 24ea571..f3c728e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,3 @@ node_modules .idea yarn-error.log -dist diff --git a/__tests__/example.pdf b/__tests__/example.pdf new file mode 100644 index 0000000000000000000000000000000000000000..4b628d3443868d3ae88403ef355431dbfaef0e94 GIT binary patch literal 58791 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	h%lYeL zZo0>*9T;a2NB13Io32E#vogDr*KkL6D=wcEL2mSLd(XHx-ZD;qmu=eiYluG(G-vZw z&+9gc<HIfg-J79>`F7^+P1E=TmXW(RT;uN%y>7EMeHnH4rf%$>^14mp`15v*S+WCa zZ(}?DBrbcE-I>SNK+)IVmox7=k3Y{keWScL*ud??kUQqfZl_lHd+z0ybp7ml$4*WB pX(9f^5PxSk!(U$FPdf3{6n|OBt-i-zZlO2X%MCF`qINI0{|A;*-je_T literal 0 HcmV?d00001 diff --git a/__tests__/index.test.ts b/__tests__/index.test.ts index 60b585e..f35d0d6 100644 --- a/__tests__/index.test.ts +++ b/__tests__/index.test.ts @@ -1,9 +1,17 @@ +import fs from "fs"; +import path from "path"; import { describe, it, expect } from "@jest/globals"; -import { add } from "../src"; +import PDFparser from "../src/pdfParser"; -describe("index test", () => { - it("should calculate sum", () => { - const sum = add(2, 5); - expect(sum).toEqual(7); +describe("PDF parser", () => { + it("should return pdf document metadata", async () => { + const file = fs.readFileSync(path.resolve(__dirname, "./example.pdf")); + + const parser = new PDFparser(file); + + const actual = await parser.getPDFMeta(); + + expect(actual.pages).toEqual(1); + expect(actual.title).toEqual("PDF Digital Signatures"); }); }); diff --git a/dist/config.d.ts b/dist/config.d.ts new file mode 100644 index 0000000..070fb3f --- /dev/null +++ b/dist/config.d.ts @@ -0,0 +1,13 @@ +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; + }; +}; diff --git a/dist/config.js b/dist/config.js new file mode 100644 index 0000000..8dfad7c --- /dev/null +++ b/dist/config.js @@ -0,0 +1,17 @@ +"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: true, + fingerprint: true, + outline: true, + metadata: true, + info: true, + permissions: true, + }, +}; diff --git a/dist/index.d.ts b/dist/index.d.ts new file mode 100644 index 0000000..98cc103 --- /dev/null +++ b/dist/index.d.ts @@ -0,0 +1,2 @@ +import PDFparser from "./pdfParser"; +export default PDFparser; diff --git a/dist/index.js b/dist/index.js new file mode 100644 index 0000000..8ee3e72 --- /dev/null +++ b/dist/index.js @@ -0,0 +1,4 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +const pdfParser_1 = require("./pdfParser"); +exports.default = pdfParser_1.default; diff --git a/dist/pdfParser.d.ts b/dist/pdfParser.d.ts new file mode 100644 index 0000000..7cf3fa1 --- /dev/null +++ b/dist/pdfParser.d.ts @@ -0,0 +1,9 @@ +/// <reference types="node" /> +import { IgetMetaResponse } from "./types"; +declare class PDFparser { + readonly document: any; + readonly config: any; + constructor(document: Buffer); + getPDFMeta: () => Promise<IgetMetaResponse>; +} +export default PDFparser; diff --git a/dist/pdfParser.js b/dist/pdfParser.js new file mode 100644 index 0000000..45a9adc --- /dev/null +++ b/dist/pdfParser.js @@ -0,0 +1,48 @@ +"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 verify_pdf_1 = require("@ninja-labs/verify-pdf"); +const pdfdataextract_1 = require("pdfdataextract"); +const config_1 = require("./config"); +class PDFparser { + constructor(document) { + this.getPDFMeta = () => __awaiter(this, void 0, void 0, function* () { + try { + const pdfMeta = yield pdfdataextract_1.PdfData.extract(this.document, config_1.config); + const signaturesMeta = yield verify_pdf_1.default(this.document); + return { + verified: signaturesMeta.verified, + authenticity: signaturesMeta.authenticity, + integrity: signaturesMeta.integrity, + expired: signaturesMeta.expired, + meta: { + certs: signaturesMeta.certs, + }, + pages: pdfMeta.pages, + fingerpring: pdfMeta.fingerprint, + creation_data: pdfMeta.info.CreationDate, + creator: pdfMeta.info.Creator, + author: pdfMeta.info.Author, + title: pdfMeta.info.Title, + description: pdfMeta.info.Keywords, + mod_date: pdfMeta.info.ModDate, + }; + } + catch (error) { + console.error(error); + throw new Error("Could not get pdf metadata"); + } + }); + this.document = document; + this.config = config_1.config; + } +} +exports.default = PDFparser; diff --git a/dist/types.d.ts b/dist/types.d.ts new file mode 100644 index 0000000..eb3c76f --- /dev/null +++ b/dist/types.d.ts @@ -0,0 +1,38 @@ +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 IgetMetaResponse { + verified: boolean; + authenticity: boolean; + integrity: boolean; + expired: boolean; + meta: { + certs: Array<{ + Icert: any; + }>; + }; + pages: number; + fingerpring: string; + creation_data: string; + creator: string; + author: string; + title: string; + description: string; + mod_date: string; +} diff --git a/dist/types.js b/dist/types.js new file mode 100644 index 0000000..c8ad2e5 --- /dev/null +++ b/dist/types.js @@ -0,0 +1,2 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); diff --git a/package.json b/package.json index e6d39b9..e84c325 100644 --- a/package.json +++ b/package.json @@ -35,5 +35,8 @@ "pre-commit": "lint-staged" } }, - "dependencies": {} + "dependencies": { + "@ninja-labs/verify-pdf": "^0.3.9", + "pdfdataextract": "^3.2.0" + } } diff --git a/src/config.ts b/src/config.ts new file mode 100644 index 0000000..bc82917 --- /dev/null +++ b/src/config.ts @@ -0,0 +1,15 @@ +import { VerbosityLevel } from "pdfdataextract"; + +export const config = { + verbosity: VerbosityLevel.ERRORS, // set the verbosity level for parsing + get: { + // enable or disable data extraction (all are optional and enabled by default) + pages: true, // get number of pages + text: true, // get text of each page + fingerprint: true, // get fingerprint + outline: true, // get outline + metadata: true, // get metadata + info: true, // get info + permissions: true, // get permissions + }, +}; diff --git a/src/index.ts b/src/index.ts index c68b57a..bb506d9 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,3 +1,3 @@ -export const add = (a: number, b: number) => { - return a + b; -}; +import PDFparser from "./pdfParser"; + +export default PDFparser; diff --git a/src/pdfParser.ts b/src/pdfParser.ts new file mode 100644 index 0000000..4a89503 --- /dev/null +++ b/src/pdfParser.ts @@ -0,0 +1,44 @@ +import verifyPDF from "@ninja-labs/verify-pdf"; +import { PdfData } from "pdfdataextract"; +import { config } from "./config"; +import { IgetMetaResponse } from "./types"; + +class PDFparser { + readonly document; + readonly config; + + constructor(document: Buffer) { + this.document = document; + this.config = config; + } + + getPDFMeta = async (): Promise<IgetMetaResponse> => { + try { + const pdfMeta = await PdfData.extract(this.document, config); + const signaturesMeta = await verifyPDF(this.document); + + return { + verified: signaturesMeta.verified, + authenticity: signaturesMeta.authenticity, + integrity: signaturesMeta.integrity, + expired: signaturesMeta.expired, + meta: { + certs: signaturesMeta.certs, + }, + pages: pdfMeta.pages, + fingerpring: pdfMeta.fingerprint, + creation_data: pdfMeta.info.CreationDate, + creator: pdfMeta.info.Creator, + author: pdfMeta.info.Author, + title: pdfMeta.info.Title, + description: pdfMeta.info.Keywords, + mod_date: pdfMeta.info.ModDate, + }; + } catch (error) { + console.error(error); + throw new Error("Could not get pdf metadata"); + } + }; +} + +export default PDFparser; diff --git a/src/types.ts b/src/types.ts new file mode 100644 index 0000000..7a21941 --- /dev/null +++ b/src/types.ts @@ -0,0 +1,37 @@ +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 IgetMetaResponse { + verified: boolean; + authenticity: boolean; + integrity: boolean; + expired: boolean; + meta: { + certs: Array<{ Icert }>; + }; + pages: number; + fingerpring: string; + creation_data: string; + creator: string; + author: string; + title: string; + description: string; + mod_date: string; +} diff --git a/yarn.lock b/yarn.lock index 1df3a5f..f58a781 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1070,6 +1070,13 @@ "@types/yargs" "^15.0.0" chalk "^4.0.0" +"@ninja-labs/verify-pdf@^0.3.9": + version "0.3.9" + resolved "https://registry.yarnpkg.com/@ninja-labs/verify-pdf/-/verify-pdf-0.3.9.tgz#46929f917b3452cb0cf28c833bce7dc9d1e7ae8f" + integrity sha512-TXuax5oaFoAICjEmDctxb28DhfeQkVe2vev7kw6GieHEliuCE5b3K5+puzSj7KcUr3EAYPtzQB740t7GCNrlxw== + dependencies: + node-forge "^0.10.0" + "@sinonjs/commons@^1.7.0": version "1.8.1" resolved "https://registry.yarnpkg.com/@sinonjs/commons/-/commons-1.8.1.tgz#e7df00f98a203324f6dc7cc606cad9d4a8ab2217" @@ -3662,6 +3669,11 @@ nice-try@^1.0.4: resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366" integrity sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ== +node-forge@^0.10.0: + version "0.10.0" + resolved "https://registry.yarnpkg.com/node-forge/-/node-forge-0.10.0.tgz#32dea2afb3e9926f02ee5ce8794902691a676bf3" + integrity sha512-PPmu8eEeG9saEUvI97fm4OYxXVB6bFvyNTyiUOBichBpFG8A1Ljw3bY62+5oOjDEMHRnd0Y7HQ+x7uzxOzC6JA== + node-int64@^0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/node-int64/-/node-int64-0.4.0.tgz#87a9065cdb355d3182d8f94ce11188b825c68a3b" @@ -3909,6 +3921,18 @@ path-type@^4.0.0: resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b" integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw== +pdfdataextract@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/pdfdataextract/-/pdfdataextract-3.2.0.tgz#c40d59fb0de4ed6e63a1da08f87d4f4550e841ec" + integrity sha512-t4W7h+cdr/aefdftzxmf+3w4ntVO70OlOFAGgH2zrbc+lDmYKIzAUXJhP+zpIqK6SnkRnZrQOC0fv/sejUJnrg== + dependencies: + pdfjs-dist "2.10.377" + +pdfjs-dist@2.10.377: + version "2.10.377" + resolved "https://registry.yarnpkg.com/pdfjs-dist/-/pdfjs-dist-2.10.377.tgz#feadc9f31bf1790795994e54b18930974cf4970a" + integrity sha512-i0jRShtvgfsVQUNCoFYH4SVhPO3U0yhtiFLfZ0RR0B+68N+Vnwq+8B3cjWjLEwWGh8wg1XQ/sYMYKUlHn/Qpsw== + performance-now@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b" -- GitLab