From 83590c9b825c3cbc1889e3faeef3e885a32e75de Mon Sep 17 00:00:00 2001 From: Valery Buchinsky Date: Thu, 5 Oct 2023 11:06:08 +0300 Subject: [PATCH] =?UTF-8?q?=F0=9F=93=9D=20Updated=20README=20to=20reflect?= =?UTF-8?q?=20on=20the=20new=20structure?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 67 ++++++++++++++++++++++++++++++++----------------------- 1 file changed, 39 insertions(+), 28 deletions(-) diff --git a/README.md b/README.md index 1479dfa3..2c4a1abc 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,6 @@ # ![@signpdf](https://raw.githubusercontent.com/vbuch/node-signpdf/master/resources/logo-horizontal.svg?sanitize=true) -[![npm version](https://badge.fury.io/js/node-signpdf.svg)](https://badge.fury.io/js/node-signpdf) -[![Coverage Status](https://coveralls.io/repos/github/vbuch/node-signpdf/badge.svg?branch=master)](https://coveralls.io/github/vbuch/node-signpdf?branch=master) -[![Known Vulnerabilities](https://snyk.io/test/npm/node-signpdf/badge.svg)](https://snyk.io/test/npm/node-signpdf) -[![Donate to this project using Buy Me A Coffee](https://img.shields.io/badge/buy%20me%20a%20coffee-donate-yellow.svg)](https://buymeacoffee.com/vbuch) -![GitHub last commit](https://img.shields.io/github/last-commit/vbuch/node-signpdf?color=red) - -Simple signing of PDFs in node. +A family of packages to make signing of PDFs simple in Node.js. * [@signpdf](#signpdf) * [Purpose](#purpose) @@ -24,25 +18,29 @@ Simple signing of PDFs in node. The main purpose of this package is **to demonstrate** the way signing can be achieved **in a piece of readable code** as it can take a lot of hours to figure out. -## Usage +## Packages -Install with `npm i -S node-signpdf node-forge`. +### [signpdf](./packages/signpdf) -In practice we expect that most people will just read through the code we've written in the testing part of this package and figure it out themselves. If that's your case, you should read the [[Signing PDF in simple steps]](#signing-pdf-in-simple-steps) section. +With the help of `node-forge` provides the actual cryptographic signing of a well-prepared PDF document. A PDF document is well-prepared if it has a signature placeholder - that is the e-signature aquivallent of the label "Signature:......." in your paper document. If your PDF does not have that, you may want to add one using one of our placeholder helpers (see the other packages). -### With pdfkit-created document +### [placeholder-pdfkit010](./packages/placeholder-pdfkit010) -You have already created a PDF using foliojs/pdfkit and you want to sign that. Before saving (writing to fs, or just converting to `Buffer`) your file, you need to a add a signature placeholder to it. We have a helper for that. This is demonstrated in [the `signs input PDF` test](./src/signpdf.test.js#L125). +Works on top of `PDFKit 0.10.0` and given a PDFDocument that is in the works, adds an e-signature placeholder. When the PDF is ready you can pass it to `@signpdf/signpdf` to complete the process. -Once you have the placeholder, just [[sign the document]](#sign-the-document). +### [placeholder-plain](./packages/placeholder-plain) -### With any PDF document +Uses the process and knowledge of adding e-signature placeholder from `placeholder-pdfkit010` but implements it with plain string operations (.indexOf(), .replace(), .match(), etc.). Because of the lack of semantics it is rather fragile. Additionally it doesn't support streams and only works on PDF version <= 1.3. Regardless of those disadvantages this helper seems to be the most popular among the users of @signpdf. + +## Usage -Yes. This is new since version 1.0. We have a helper that can add a signature placeholder in at least the most basic PDFs without depending on pdfkit. You can see how this is done in [the `signs a ready pdf` test](./src/signpdf.test.js#L167). +When this repo was started we really wanted people to understand the signing flow. If that's your case, you should read the [[Signing PDF in simple steps]](#signing-pdf-in-simple-steps) section. If you are here with "Give me the code", you should maybe go to [our packages/examples](./packages/examples). -Once you have the placeholder, just [[sign the document]](#sign-the-document). +Depending on your usecase you may need different combinations of packages. -### Sign the document +### I am getting PDFs that already have placeholders + +This is the most simple case of them all. You only need the signer. `$ npm i -S @signpdf/signpdf node-forge`. Then have a look at the [with-placeholder.js example](./packages/examples/with-placeholder.js). It should be as simple as: ```javascript import signer from 'node-signpdf'; @@ -53,14 +51,19 @@ const signedPdf = signer.sign( ); ``` +### I am generating a PDF with PDFKit + +This is how the library was started as we needed to sign a document that we were generating on the fly. You will need `$ npm i -S @signpdf/signpdf @signpdf/placeholder-pdfkit010 node-forge` and a look at the [pdfkit010.js example](./packages/examples/pdfkit010.js). + +### I have a .pdf file and I want to sign it + +This seems to be the most common usecase - people work with PDF documents coming from different sources and they need to digitally sign them. The [placeholder-plain](#placeholder-plain) helper can help here. Start with `$ npm i -S @signpdf/signpdf @signpdf/placeholder-plain node-forge`. Head over to either [the JS example](./packages/examples/javascript.js) or [the TS one](./packages/examples/typescript.ts). And note that the process may look simple on the surface but it is very fragile inside. Should you need some help go stright to [our GitHub Issues](https://github.com/vbuch/node-signpdf/issues?q=is%3Aissue). + ## Notes * The process of signing a document is described in the [Digital Signatures in PDF](https://www.adobe.com/devnet-docs/etk_deprecated/tools/DigSig/Acrobat_DigitalSignatures_in_PDF.pdf) document. As Adobe's files are deprecated, [here is the standard as defined by ETSI](). -* This lib: - * requires the [signature placeholder](#append-a-signature-placeholder) to already be in the document (There are helpers included that can try to add it); - * requires the `Contents` descriptor in the `Sig` be placed after the `ByteRange` one; - * takes `Buffer`s of the PDF and a P12 certificate to use when [signing](#generate-and-apply-signature); - * does cover only basic scenarios of signing a PDF. If you have suggestions, ideas or anything, please [CONTRIBUTE](#contributing); +* The @signpdf/signpdf lib requires the [signature placeholder](#append-a-signature-placeholder) to already be in the document. See the placeholder packages for assistance with that; +* We cover only basic scenarios of signing a PDF. If you have suggestions, ideas or anything, please [CONTRIBUTE](#contributing); * Feel free to copy and paste any part of this code. See its defined [Purpose](#purpose). ## Signing PDF in simple steps @@ -73,10 +76,10 @@ See the [unit-testing code](https://github.com/vbuch/node-signpdf/blob/master/sr What's needed is a `Sig` element and a `Widget` that is also linked in a `Form`. The form needs to be referenced in the root descriptor of the PDF as well. A (hopefully) [readable sample](https://github.com/vbuch/node-signpdf/blob/master/src/helpers/pdfkitAddPlaceholder.js) is available in the helpers. Note the `Contents` descriptor of the `Sig` where zeros are placed that will later be replaced with the actual signature. -This package provides two [helpers](https://github.com/vbuch/node-signpdf/blob/master/src/helpers/index.js) for adding the signature placeholder: +This package provides two helpers for adding the signature placeholder: -* pdfkitAddPlaceholder -* plainAddPlaceholder +* [`@signpdf/placeholder-pdfkit010`](#placeholder-pdfkit010) +* [`@signpdf/placeholder-plain`](#placeholder-plain) **Note:** Signing in detached mode makes the signature length independent of the PDF's content length, but it may still vary between different signing certificates. So every time you sign using the same P12 you will get the same length of the output signature, no matter the length of the signed content. It is safe to find out the actual signature length your certificate produces and use it to properly configure the placeholder length. @@ -87,7 +90,8 @@ To produce PAdES compliant signatures, the ETSI Signature Dictionary SubFilter v This can be declared using the subFilter option argument passed to `pdfkitAddPlaceholder` and `plainAddPlaceholder`. ```js -import { SUBFILTER_ETSI_CADES_DETACHED, pdfkitAddPlaceholder } from 'node-signpdf'; +import { pdfkitAddPlaceholder } from '@signpdf/placeholder-pdfkit010'; +import { SUBFILTER_ETSI_CADES_DETACHED } from '@signpdf/utils'; const pdfToSign = pdfkitAddPlaceholder({ ..., @@ -97,13 +101,20 @@ const pdfToSign = pdfkitAddPlaceholder({ ### Generate and apply signature -That's where the Signer kicks in. Given a PDF and a P12 certificate a signature is generated in detached mode and is replaced in the placeholder. This is best demonstrated in [the tests](https://github.com/vbuch/node-signpdf/blob/master/src/signpdf.test.js#L122). +That's where the Signer kicks in. Given a PDF and a P12 certificate a signature is generated in detached mode and is replaced in the placeholder. + +```js +import signer from '@signpdf/signpdf'; + +... +const signedPdf = signer.sign(pdfBuffer, certificateBuffer); +``` ## Dependencies [node-forge](https://github.com/digitalbazaar/forge) is used for working with signatures. -[PDFKit](https://github.com/foliojs/pdfkit) is used in the tests for generating a PDF with a signature placeholder. +[PDFKit](https://github.com/foliojs/pdfkit) is extensively used for generating PDFs with a signature placeholder and additionally its flows are used in `placeholder-plain`. ## Credits