diff --git a/README.md b/README.md index ece32e3..814b9e1 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ [![npm](https://img.shields.io/npm/dm/node-qpdf)](https://www.npmjs.com/package/node-qpdf2) [![qpdf 11+](https://img.shields.io/badge/dependencies-qpdf-green)](https://github.com/qpdf/qpdf) -A very simple wrapper for [qpdf](https://github.com/qpdf/qpdf) which is performs content-preserving transformations on PDF files. It includes encrypting and decrypting PDF files with AES 256, AES 128, RC4 (128 & 40) encryption algorithms. This is a fork of [nrhirani/node-qpdf](https://github.com/nrhirani/node-qpdf), adding Promises and Types, and is kept mostly up to date with `qpdf`. +A very simple wrapper for [qpdf](https://github.com/qpdf/qpdf) which performs content-preserving transformations on PDF files. It includes encrypting and decrypting PDF files with AES 256, AES 128, RC4 (128 & 40) encryption algorithms. This is a fork of [nrhirani/node-qpdf](https://github.com/nrhirani/node-qpdf), adding `Promises` and `Types`, and is kept mostly up to date with `qpdf`. ## Dependencies @@ -16,94 +16,119 @@ A very simple wrapper for [qpdf](https://github.com/qpdf/qpdf) which is performs ## Installation -1. Install qpdf: - - Download [qpdf](https://github.com/qpdf/qpdf/releases) -2. Install node-qpdf: - ``` - npm install node-qpdf2 - ``` +1. Install [qpdf](https://github.com/qpdf/qpdf/releases): +2. Install `node-qpdf2`: -## Serverless? +```bash + npm install node-qpdf2 + # or + yarn add node-qpdf2 +``` -This package can be uses on serverless platforms by using your vendor's layers functionality. Use the zip release from `qpdf` as the layer. For example, `qpdf-11.1.0-bin-linux-x86_64.zip` can be directly uploaded as a layer, and has been tested using Amazon Lambda. +## Serverless? -## Encryption +This package can be used on serverless platforms and has been tested on `Amazon Lambda` and `Google Cloud Functions`. -You can encrypt your PDF by following: +### Amazon Lambda +Download latest `qpdf-XX.X.X-bin-linux-x86_64.zip` release from `qpdf` then directly upload it as a [layer](https://docs.aws.amazon.com/lambda/latest/dg/chapter-layers.html). -``` -import { encrypt } from "node-qpdf2"; +### Google Cloud Functions +Download latest `qpdf-XX.X.X-bin-linux-x86_64.zip` release then extract it's content where functions entry point (generally `index.js`) is: -const pdf = { - input: "./test/example.pdf", - output: "/tmp/encrypted.pdf", - password: "1234", +```bash +# package.json +{ + ... + # entry point + "main": "build/index.js", + ... } -await encrypt(pdf); +# directory structure +/root_dir + /build + # entry point + /index.js + /other files... + # you can rename qpdf folder to whatever you want + /qpdf_dir + # zip content + /bin + /lib + /src + /index.ts + /other files... ``` -### Options for Encryption +Then provide a `qpdfPath` pointing to `bin` folder inside `qpdf` directory: +```bash +import path from "path"; -Please see [src/encrypt.ts](https://github.com/Sparticuz/node-qpdf2/blob/master/src/encrypt.ts#L9) for the latest options, as well as [QPDF's documentation](https://qpdf.readthedocs.io/en/stable/cli.html#encryption) for information on what each restriction does. +const pdf = { + qpdfPath: path.join( process.cwd(), 'qpdf_dir/bin' ), + ... other props +} +``` -### Examples +## Encryption -#### Render and Save: +You can encrypt your PDF by following: -``` +```bash import { encrypt } from "node-qpdf2"; const options = { - input: "./test/example.pdf", - keyLength: 128, - output: "/tmp/encrypted.pdf", - password: 'YOUR_PASSWORD_TO_ENCRYPT', - restrictions: { - print: 'low', - useAes: 'y' - } + input: "./test/example.pdf", + output: "/tmp/encrypted.pdf", + password: 'ENCRYPTION_PASSWORD', + restrictions: { + print: 'low', + useAes: 'y' + } } await encrypt(options); ``` +### Encryption options + +Please see [src/encrypt.ts](https://github.com/Sparticuz/node-qpdf2/blob/master/src/encrypt.ts#L9) for the all available options, as well as [qpdf's documentation](https://qpdf.readthedocs.io/en/stable/cli.html#encryption) for informations about each restriction prop. + ## Decryption You can decrypt your PDF by following: -``` +```bash import { decrypt } from "node-qpdf2"; const options = { input: "/tmp/encrypted.pdf", output: "/tmp/decrypted.pdf", - password: "YOUR_PASSWORD_TO_DECRYPT_PDF", + password: "ENCRYPTION_PASSWORD", } await decrypt(options); ``` -## PDF Encryption info +## Encryption info -You can retrieve encryption information using the info function. This function will return a Promise. See [here](https://qpdf.readthedocs.io/en/stable/cli.html#option-show-encryption) for more information. +You can retrieve encryption information using the info function. This function will return a `Promise`. See [here](https://qpdf.readthedocs.io/en/stable/cli.html#option-show-encryption) for more information. -``` +```bash import { info } from "node-qpdf2"; const options = { input: "/tmp/encrypted.pdf", - password: "FILE_PASSWORD", + password: "ENCRYPTION_PASSWORD", } console.log(await info(options)); ``` - -If the file is not encrypted, the result will be "File is not encrypted". +If file is not encrypted, the result will be `File is not encrypted`. ## Coverage -| File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s | +| File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Lines | | ---------- | ------- | -------- | ------- | ------- | ----------------- | | All files | 100 | 100 | 100 | 100 | | decrypt.ts | 100 | 100 | 100 | 100 | diff --git a/src/decrypt.ts b/src/decrypt.ts index e1dabec..6a39136 100644 --- a/src/decrypt.ts +++ b/src/decrypt.ts @@ -2,6 +2,8 @@ import execute from "./spawn.js"; import { fileExists } from "./utils.js"; export interface DecryptSettings { + /** Optional - Path to custom qpdf binary */ + qpdfPath?: string /** The path for the encrypted pdf */ input: string; /** The path for the decrypted pdf */ @@ -36,5 +38,5 @@ export const decrypt = async (payload: DecryptSettings): Promise => { callArguments.push("-"); } - return execute(callArguments); + return execute(callArguments, payload.qpdfPath); }; diff --git a/src/encrypt.ts b/src/encrypt.ts index 4385e09..5ba6be3 100644 --- a/src/encrypt.ts +++ b/src/encrypt.ts @@ -7,6 +7,8 @@ const EncryptDefaults = { }; export interface EncryptOptions { + /** Optional - Path to custom qpdf binary */ + qpdfPath?: string /** The location of the unencrypted pdf file */ input: string; /** @@ -76,9 +78,9 @@ export const encrypt = async (userPayload: EncryptOptions): Promise => { const callArguments = []; - // If the keyLength is 40, `--allow-weak-crypto` needs to be specified before `--encrypt`. + // If the keyLength is not 256, `--allow-weak-crypto` needs to be specified before `--encrypt`. // This is required for qpdf 11+. - if (payload.keyLength === 40) callArguments.push("--allow-weak-crypto"); + if (payload.keyLength !== 256) callArguments.push("--allow-weak-crypto"); callArguments.push("--encrypt"); @@ -136,5 +138,5 @@ export const encrypt = async (userPayload: EncryptOptions): Promise => { callArguments.push("-"); } // Execute command and return stdout for pipe - return execute(callArguments); + return execute(callArguments, payload.qpdfPath); }; diff --git a/src/info.ts b/src/info.ts index 2006573..38dc5f8 100644 --- a/src/info.ts +++ b/src/info.ts @@ -2,6 +2,8 @@ import execute from "./spawn.js"; import { fileExists } from "./utils.js"; export interface InfoSettings { + /** Optional - Path to custom qpdf binary */ + qpdfPath?: string /** The path for the encrypted pdf */ input: string; /** The password for the encrypted pdf */ @@ -27,7 +29,7 @@ export const info = async (payload: InfoSettings): Promise => { // Input file path callArguments.push(payload.input); - const result = await execute(callArguments); + const result = await execute(callArguments, payload.qpdfPath); return result.toLocaleString().trim(); }; diff --git a/src/spawn.ts b/src/spawn.ts index a85b1ef..a6aff4c 100644 --- a/src/spawn.ts +++ b/src/spawn.ts @@ -3,9 +3,11 @@ import { spawn } from "node:child_process"; -export default (callArguments: string[]): Promise => +export default (callArguments: string[], qpdfPath?:string): Promise => new Promise((resolve, reject) => { - const process = spawn("qpdf", callArguments); + const process = spawn(qpdfPath? "./qpdf" :"qpdf", callArguments, { + cwd: qpdfPath + }); const stdout: string[] = []; const stderr: string[] = []; process.stdout.on("data", (data) => {