Skip to content

Commit

Permalink
Move around into separate packages
Browse files Browse the repository at this point in the history
+ lint, test, build;
+ contactInfo, etc. required in placeholder helpers;
+ more types;
+ examples

🍱 Updated logo

📝 Play with links to repo files

v3.0.7

v3.0.8

📝 Provide better titles in the readmes

We're currently on 2.0.0. Aiming at 3.0.0

📝 Help contributors aroud lerna and yarn workspaces
  • Loading branch information
Valeri Buchinski authored and vbuch committed Oct 6, 2023
1 parent 2d3e49d commit 892ac1b
Show file tree
Hide file tree
Showing 212 changed files with 10,704 additions and 6,785 deletions.
15 changes: 0 additions & 15 deletions .babelrc

This file was deleted.

1 change: 1 addition & 0 deletions .eslintignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
node_modules
coverage
dist
jest.config.js
32 changes: 0 additions & 32 deletions .eslintrc

This file was deleted.

53 changes: 53 additions & 0 deletions .github/workflows/monorepo.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
on:
push:
branches:
- feature/split

name: monorepo

jobs:
do-de-stuff:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/setup-node@v2
- run: yarn
- run: ./node_modules/.bin/lerna run lint
- run: ./node_modules/.bin/lerna run test -- --coverage
- name: Coveralls (signpdf)
uses: coverallsapp/github-action@master
with:
parallel: true
flag-name: signpdf
github-token: ${{ secrets.GITHUB_TOKEN }}
base-path: packages/signpdf
path-to-lcov: packages/signpdf/coverage/lcov.info
- name: Coveralls (utils)
uses: coverallsapp/github-action@master
with:
parallel: true
flag-name: utils
github-token: ${{ secrets.GITHUB_TOKEN }}
base-path: packages/utils
path-to-lcov: packages/utils/coverage/lcov.info
- name: Coveralls (placeholder-pdfkit010)
uses: coverallsapp/github-action@master
with:
parallel: true
flag-name: placeholder-pdfkit010
github-token: ${{ secrets.GITHUB_TOKEN }}
base-path: packages/placeholder-pdfkit010
path-to-lcov: packages/placeholder-pdfkit010/coverage/lcov.info
- name: Coveralls (placeholder-plain)
uses: coverallsapp/github-action@master
with:
parallel: true
flag-name: placeholder-plain
github-token: ${{ secrets.GITHUB_TOKEN }}
base-path: packages/placeholder-plain
path-to-lcov: packages/placeholder-plain/coverage/lcov.info
- name: Close Coveralls
uses: coverallsapp/github-action@master
with:
parallel-finished: true
carryforward: "signpdf,utils,placeholder-pdfkit010,placeholder-plain"
15 changes: 0 additions & 15 deletions .github/workflows/not-travis.yml

This file was deleted.

1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ yarn-error.log*

coverage
.coveralls.yml
packages/examples/output

node_modules/
.npm
Expand Down
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
# CHANGELOG

## [3.0.0]

* Deprecating `node-signpdf` to be replaced by the `@signpdf` scoped packages;
* Split the helpers into separate packages `@signpdf/placeholder-pdfkit010` and `@signpdf/placeholder-plain`;
* placeholder helpers now require `contactInfo`, `location` and `name` which used to be optional;
* Introduced more types declarations through TS and JSDoc;
* Introduced examples in `packages/examples`;

## [2.0.0]

* Only publish dist files into npm (see https://bit.ly/46rykd7 on why this requires a major version);
Expand Down
16 changes: 13 additions & 3 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,21 @@
# Contributing

* All PRs are welcome in the `develop` branch.
* Please, stick to the repo's defined [Purpose](README.md#purpose) and try to write your code as readable as possible.
* **All PRs are welcome** in the `develop` branch.
* Please, stick to the defined [Purpose](https://github.com/vbuch/node-signpdf#purpose) of the repo and try to write your code as readable as possible.
* [Yarn Workspaces](https://classic.yarnpkg.com/lang/en/docs/workspaces/) + [Lerna](https://lerna.js.org/) are used in this **monorepo**.
* We do code reviews and may ask you to change things before we merge code.
* This is a git-flow repo. We use the default git flow with a `v` version prefix. You shouldn't care much while writeing a feature but good to know.
* Note that [gitmoji](https://gitmoji.carloscuesta.me/) is used in the commit messages. That's not a must but we think it's nice.

## Useful commands

- `$ yarn lint` - As run in your pre-commit
- `$ yarn test` - As run in your pre-push
- `$ ./node_modules/.bin/lerna run build` builds all the packages in their respective `dist` folders.
- `$ ./node_modules/.bin/lerna run test --scope=@signpdf/signpdf -- --watch --coverage` runs tests in a specified package tracking coverage and watching.
- `$ yarn workspace @signpdf/signpdf add node-forge -D` adds a `node-forge` as a dev dependency
of `@signpdf/signpdf`
- `$ yarn workspace @signpdf/signpdf add @signpdf/some-new-subpackage@* -D` adds a `@signpdf/some-new-subpackage` as a dev dependency of `@signpdf/signpdf`. Note the `@*` version specifier.

## Contributors

* [vbuch](https://github.com/vbuch)
Expand Down
97 changes: 60 additions & 37 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
# ![node-signpdf](https://raw.githubusercontent.com/vbuch/node-signpdf/master/resources/logo-horizontal.svg?sanitize=true)
# ![@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)
![Coverage as reported by Coveralls](https://img.shields.io/coverallsCoverage/github/vbuch/node-signpdf)
![GitHub last commit](https://img.shields.io/github/last-commit/vbuch/node-signpdf?color=red)
[![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)

Simple signing of PDFs in node.
`@signpdf` is a family of packages trying to make signing of PDFs simple in Node.js. Formerly known as [`node-signpdf`](https://www.npmjs.com/package/node-signpdf).

* [node-signpdf](#node-signpdf)
* [@signpdf](#signpdf)
* [Purpose](#purpose)
* [Usage](#usage)
* [Packages](#packages)
* [Notes](#notes)
* [Signing PDF in simple steps](#signing-pdf-in-simple-steps)
* [Generate a PDF](#generate-a-pdf)
Expand All @@ -22,27 +22,17 @@ Simple signing of PDFs in node.

## Purpose

The purpose of this package is not as much to be used as a dependendency, although it could. The main purpose 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.
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

Install with `npm i -S node-signpdf node-forge`.

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 pdfkit-created document

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).

Once you have the placeholder, just [[sign the document]](#sign-the-document).

### With any PDF document
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).

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).
Depending on your usecase you may need different combinations of packages.

Once you have the placeholder, just [[sign the document]](#sign-the-document).
### I am getting PDFs that already have placeholders

### Sign the document
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';
Expand All @@ -53,30 +43,55 @@ 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).

## Packages

### [signpdf](/packages/signpdf)

[![npm version](https://badge.fury.io/js/@signpdf%2Fsignpdf.svg)](https://badge.fury.io/js/@signpdf%2Fsignpdf)

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).

### [placeholder-pdfkit010](/packages/placeholder-pdfkit010)

[![npm version](https://badge.fury.io/js/@signpdf%2Fplaceholder-pdfkit010.svg)](https://badge.fury.io/js/@signpdf%2Fplaceholder-pdfkit010)

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.

### [placeholder-plain](/packages/placeholder-plain)

[![npm version](https://badge.fury.io/js/@signpdf%2Fplaceholder-plain.svg)](https://badge.fury.io/js/@signpdf%2Fplaceholder-plain)

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.

## 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](<https://ec.europa.eu/digital-building-blocks/wikis/display/DIGITAL/Standards+and+specifications#Standardsandspecifications-PAdES(PDFAdvancedElectronicSignature)BaselineProfile>).
* 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

### Generate a PDF
### Generate a PDF or read a ready one

See the [unit-testing code](https://github.com/vbuch/node-signpdf/blob/master/src/signpdf.test.js). PDFKit is used there for generating the document. This also allows easy addition of the signature placeholder.
We examples of PDFKit generation of documents and we also have some where a ready .pdf file is read. Browse through [our example](/packages/examples).

### Append a signature placeholder

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.
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](/packages/placeholder-pdfkit010/src/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.

Expand All @@ -87,7 +102,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({
...,
Expand All @@ -97,20 +113,27 @@ 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

* The whole signing flow is a rework of what's already [in pdfsign.js](https://github.com/Communication-Systems-Group/pdfsign.js/blob/master/src/js/main.js#L594) so thanks go to [@tbocek](https://github.com/tbocek)
* [node-forge](https://github.com/digitalbazaar/forge) is an awesome package written in pure JavaScript and [supports signing in detached mode](https://github.com/digitalbazaar/forge/pull/605). Many thanks to all the guys who wrote and maintain it.
* Thanks to the guys of [PDFKit](https://github.com/foliojs/pdfkit) as well. They've made PDF generation incredibly easy.

## [Contributing](CONTRIBUTING.md)
## [Contributing](/CONTRIBUTING.md)

## [Changelog](CHANGELOG.md)
## [Changelog](/CHANGELOG.md)
4 changes: 2 additions & 2 deletions RELEASE-CHECKLIST.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# RELEASE CHECKLIST

[ ] yarn build
[ ] ./node_modules/.bin/lerna run build
[ ] Update CHANGELOG
[ ] Update version in package.json
[ ] ./node_modules/.bin/lerna publish
12 changes: 12 additions & 0 deletions babel.config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"presets": [
[
"@babel/preset-env",
{
"targets": {
"node": "12"
}
}
]
]
}
30 changes: 0 additions & 30 deletions dist/SignPdfError.js

This file was deleted.

1 change: 0 additions & 1 deletion dist/helpers/const.d.ts.map

This file was deleted.

Loading

0 comments on commit 892ac1b

Please sign in to comment.