@c9up/vellum 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (72) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +473 -0
  3. package/dist/Vellum.d.ts +460 -0
  4. package/dist/Vellum.d.ts.map +1 -0
  5. package/dist/Vellum.js +479 -0
  6. package/dist/Vellum.js.map +1 -0
  7. package/dist/VellumProvider.d.ts +28 -0
  8. package/dist/VellumProvider.d.ts.map +1 -0
  9. package/dist/VellumProvider.js +33 -0
  10. package/dist/VellumProvider.js.map +1 -0
  11. package/dist/augmentations.d.ts +22 -0
  12. package/dist/augmentations.d.ts.map +1 -0
  13. package/dist/augmentations.js +16 -0
  14. package/dist/augmentations.js.map +1 -0
  15. package/dist/config.d.ts +33 -0
  16. package/dist/config.d.ts.map +1 -0
  17. package/dist/config.js +31 -0
  18. package/dist/config.js.map +1 -0
  19. package/dist/configure.d.ts +17 -0
  20. package/dist/configure.d.ts.map +1 -0
  21. package/dist/configure.js +78 -0
  22. package/dist/configure.js.map +1 -0
  23. package/dist/errors.d.ts +9 -0
  24. package/dist/errors.d.ts.map +1 -0
  25. package/dist/errors.js +19 -0
  26. package/dist/errors.js.map +1 -0
  27. package/dist/index.d.ts +44 -0
  28. package/dist/index.d.ts.map +1 -0
  29. package/dist/index.js +44 -0
  30. package/dist/index.js.map +1 -0
  31. package/dist/native/generated.d.ts +255 -0
  32. package/dist/native/generated.d.ts.map +1 -0
  33. package/dist/native/generated.js +7 -0
  34. package/dist/native/generated.js.map +1 -0
  35. package/dist/native.d.ts +50 -0
  36. package/dist/native.d.ts.map +1 -0
  37. package/dist/native.js +194 -0
  38. package/dist/native.js.map +1 -0
  39. package/dist/responder.d.ts +29 -0
  40. package/dist/responder.d.ts.map +1 -0
  41. package/dist/responder.js +101 -0
  42. package/dist/responder.js.map +1 -0
  43. package/dist/services/main.d.ts +15 -0
  44. package/dist/services/main.d.ts.map +1 -0
  45. package/dist/services/main.js +39 -0
  46. package/dist/services/main.js.map +1 -0
  47. package/dist/signers.d.ts +81 -0
  48. package/dist/signers.d.ts.map +1 -0
  49. package/dist/signers.js +98 -0
  50. package/dist/signers.js.map +1 -0
  51. package/index.darwin-arm64.node +0 -0
  52. package/index.darwin-x64.node +0 -0
  53. package/index.linux-arm64-gnu.node +0 -0
  54. package/index.linux-x64-gnu.node +0 -0
  55. package/index.win32-x64-msvc.node +0 -0
  56. package/package.json +67 -0
  57. package/scripts/build-napi-types.mjs +69 -0
  58. package/scripts/copy-napi.mjs +48 -0
  59. package/scripts/generate-metrics.py +150 -0
  60. package/scripts/generate-napi-types.mjs +156 -0
  61. package/src/Vellum.ts +829 -0
  62. package/src/VellumProvider.ts +51 -0
  63. package/src/augmentations.ts +25 -0
  64. package/src/config.ts +47 -0
  65. package/src/configure.ts +92 -0
  66. package/src/errors.ts +20 -0
  67. package/src/index.ts +74 -0
  68. package/src/native/generated.ts +375 -0
  69. package/src/native.ts +358 -0
  70. package/src/responder.ts +116 -0
  71. package/src/services/main.ts +48 -0
  72. package/src/signers.ts +149 -0
package/dist/native.js ADDED
@@ -0,0 +1,194 @@
1
+ /**
2
+ * Loader for the Rust PDF engine.
3
+ *
4
+ * The engine is not optional. Parsing, authoring and rendering PDF have no
5
+ * JavaScript implementation in this package, so a missing binary is a hard
6
+ * failure with an actionable message — never a silent degradation that lets
7
+ * one deployment behave differently from another.
8
+ */
9
+ import { createRequire } from "node:module";
10
+ import { dirname, join } from "node:path";
11
+ import { arch, platform } from "node:process";
12
+ import { fileURLToPath } from "node:url";
13
+ import { VellumError } from "./errors.js";
14
+ const requireNative = createRequire(import.meta.url);
15
+ const here = dirname(fileURLToPath(import.meta.url));
16
+ const platformMap = {
17
+ "linux-x64": "linux-x64-gnu",
18
+ "linux-arm64": "linux-arm64-gnu",
19
+ "darwin-x64": "darwin-x64",
20
+ "darwin-arm64": "darwin-arm64",
21
+ "win32-x64": "win32-x64-msvc",
22
+ };
23
+ let native;
24
+ let loadError;
25
+ try {
26
+ const suffix = platformMap[`${platform}-${arch}`];
27
+ if (suffix) {
28
+ native = requireNative(join(here, `../index.${suffix}.node`));
29
+ }
30
+ }
31
+ catch (error) {
32
+ loadError = error;
33
+ }
34
+ export function isNativeAvailable() {
35
+ return native !== undefined;
36
+ }
37
+ /** Why the engine could not be loaded, phrased for whoever has to fix it. */
38
+ function unavailableReason() {
39
+ const target = `${platform}-${arch}`;
40
+ if (loadError !== undefined) {
41
+ return `failed to load (${loadError instanceof Error ? loadError.message : String(loadError)})`;
42
+ }
43
+ return platformMap[target] !== undefined
44
+ ? "binary not found"
45
+ : `no prebuilt binary for ${target}`;
46
+ }
47
+ /** Raised when an operation needs the Rust engine and it is not there. */
48
+ export class VellumNativeRequiredError extends VellumError {
49
+ constructor() {
50
+ super("NAPI_REQUIRED", `The Rust PDF engine is required but not loaded — ${unavailableReason()}.\n` +
51
+ "Install the prebuilt binary for this platform, or build it with `pnpm build:napi`.");
52
+ this.name = "VellumNativeRequiredError";
53
+ }
54
+ }
55
+ /** The engine, or a refusal explaining how to get one. */
56
+ function engine() {
57
+ if (native === undefined)
58
+ throw new VellumNativeRequiredError();
59
+ return native;
60
+ }
61
+ /**
62
+ * Run engine work, translating its failures into coded errors.
63
+ *
64
+ * The engine reports failures as plain reasons. Without this, a caller
65
+ * catching a corrupt upload would get an `Error` it cannot branch on.
66
+ */
67
+ function run(code, work) {
68
+ const loaded = engine();
69
+ try {
70
+ return work(loaded);
71
+ }
72
+ catch (error) {
73
+ throw new VellumError(code, error instanceof Error ? error.message : String(error), { cause: error });
74
+ }
75
+ }
76
+ export function inspectNative(pdf) {
77
+ return run("INVALID_PDF", (loaded) => loaded.inspect(pdf));
78
+ }
79
+ export function createBlankNative(pages) {
80
+ return run("WRITE_FAILED", (loaded) => loaded.createBlank([...pages]));
81
+ }
82
+ /**
83
+ * Rasterise one page, addressed from zero.
84
+ *
85
+ * The engine hands this to the libuv thread pool, so the returned promise
86
+ * settles without the calling thread ever blocking.
87
+ */
88
+ export async function renderPageNative(pdf, pageIndex, options) {
89
+ const loaded = engine();
90
+ try {
91
+ return await loaded.renderPage(pdf, pageIndex, options);
92
+ }
93
+ catch (error) {
94
+ throw new VellumError("RENDER_FAILED", error instanceof Error ? error.message : String(error), { cause: error });
95
+ }
96
+ }
97
+ /** Rasterise every page, in document order. */
98
+ export async function renderAllNative(pdf, options) {
99
+ const loaded = engine();
100
+ try {
101
+ return await loaded.renderAll(pdf, options);
102
+ }
103
+ catch (error) {
104
+ throw new VellumError("RENDER_FAILED", error instanceof Error ? error.message : String(error), { cause: error });
105
+ }
106
+ }
107
+ export function pageDimensionsNative(pdf) {
108
+ return run("INVALID_PDF", (loaded) => loaded.pageDimensions(pdf));
109
+ }
110
+ export function metadataNative(pdf) {
111
+ return run("INVALID_PDF", (loaded) => loaded.metadata(pdf));
112
+ }
113
+ export async function extractTextNative(pdf, pageIndex) {
114
+ const loaded = engine();
115
+ try {
116
+ return await loaded.extractText(pdf, pageIndex);
117
+ }
118
+ catch (error) {
119
+ throw new VellumError("EXTRACT_FAILED", error instanceof Error ? error.message : String(error), { cause: error });
120
+ }
121
+ }
122
+ export async function extractTextAllNative(pdf) {
123
+ const loaded = engine();
124
+ try {
125
+ return await loaded.extractTextAll(pdf);
126
+ }
127
+ catch (error) {
128
+ throw new VellumError("EXTRACT_FAILED", error instanceof Error ? error.message : String(error), { cause: error });
129
+ }
130
+ }
131
+ async function edit(code, work) {
132
+ const loaded = engine();
133
+ try {
134
+ return await work(loaded);
135
+ }
136
+ catch (error) {
137
+ throw new VellumError(code, error instanceof Error ? error.message : String(error), { cause: error });
138
+ }
139
+ }
140
+ export function mergeNative(documents) {
141
+ return edit("MERGE_FAILED", (loaded) => loaded.merge([...documents]));
142
+ }
143
+ export function selectPagesNative(pdf, pageIndexes) {
144
+ return edit("SELECT_FAILED", (loaded) => loaded.selectPages(pdf, [...pageIndexes]));
145
+ }
146
+ export function splitNative(pdf) {
147
+ return edit("SPLIT_FAILED", (loaded) => loaded.split(pdf));
148
+ }
149
+ export function rotateNative(pdf, degrees, pageIndexes) {
150
+ return edit("ROTATE_FAILED", (loaded) => loaded.rotate(pdf, degrees, pageIndexes ? [...pageIndexes] : undefined));
151
+ }
152
+ export function stampNative(pdf, image, options) {
153
+ return edit("STAMP_FAILED", (loaded) => loaded.stamp(pdf, image, options));
154
+ }
155
+ export function stampTextNative(pdf, text, options) {
156
+ return edit("STAMP_TEXT_FAILED", (loaded) => loaded.stampText(pdf, text, options));
157
+ }
158
+ export function formFieldsNative(pdf) {
159
+ return run("INVALID_PDF", (loaded) => loaded.formFields(pdf));
160
+ }
161
+ export function fillFormNative(pdf, values) {
162
+ return edit("FILL_FAILED", (loaded) => loaded.fillForm(pdf, values));
163
+ }
164
+ export function flattenFormNative(pdf) {
165
+ return edit("FLATTEN_FAILED", (loaded) => loaded.flattenForm(pdf));
166
+ }
167
+ export function prepareSignatureNative(pdf, options) {
168
+ return edit("SIGN_FAILED", (loaded) => loaded.prepareSignature(pdf, options));
169
+ }
170
+ export function embedSignatureNative(prepared, value) {
171
+ return edit("SIGN_FAILED", (loaded) => loaded.embedSignature(prepared, value));
172
+ }
173
+ export function signCmsNative(digest, key, certificates, signedAt) {
174
+ return edit("SIGN_FAILED", (loaded) => loaded.signCms(digest, key, [...certificates], signedAt));
175
+ }
176
+ export function timestampQueryNative(cms) {
177
+ return run("TIMESTAMP_FAILED", (loaded) => loaded.timestampQuery(cms));
178
+ }
179
+ export function attachTimestampNative(cms, response, nonce) {
180
+ return run("TIMESTAMP_FAILED", (loaded) => loaded.attachTimestamp(cms, response, nonce));
181
+ }
182
+ export function verifySignaturesNative(pdf, trust) {
183
+ return edit("VERIFY_FAILED", (loaded) => loaded.verifySignatures(pdf, trust));
184
+ }
185
+ export function responderUrlNative(certificate) {
186
+ return run("VERIFY_FAILED", (loaded) => loaded.responderUrl(certificate));
187
+ }
188
+ export function revocationQueryNative(certificate, issuer) {
189
+ return run("VERIFY_FAILED", (loaded) => loaded.revocationQuery(certificate, issuer));
190
+ }
191
+ export function readRevocationNative(response, certificate, issuer, at) {
192
+ return run("VERIFY_FAILED", (loaded) => loaded.readRevocation(response, certificate, issuer, at ?? undefined));
193
+ }
194
+ //# sourceMappingURL=native.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"native.js","sourceRoot":"","sources":["../src/native.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,29 @@
1
+ /**
2
+ * Deciding whether a revocation responder may be contacted.
3
+ *
4
+ * The address comes out of the certificate inside the document being checked,
5
+ * which is to say: from whoever sent the document. Following it unconditionally
6
+ * turns "check whether this signature is still valid" into "make my server
7
+ * issue an HTTP request wherever this stranger points" — the cloud metadata
8
+ * endpoint, a Redis on loopback, or simply a URL that confirms the document was
9
+ * opened and reveals the address it was opened from.
10
+ *
11
+ * So the default is a public responder over HTTP, and an application whose
12
+ * authority answers on the internal network says so by name. Everything
13
+ * refused answers `"unknown"`, never `"good"`: a responder that was not asked
14
+ * has told us nothing.
15
+ */
16
+ /** Who an application is willing to ask about revocation. */
17
+ export type ResponderPolicy = ReadonlyArray<string> | ((url: URL) => boolean | Promise<boolean>);
18
+ /** Why a responder was refused, in a sentence a caller can act on. */
19
+ export interface ResponderRefusal {
20
+ refused: string;
21
+ }
22
+ /**
23
+ * Decide whether `url` may be asked.
24
+ *
25
+ * @param policy What the application allows: a list of hostnames, or a
26
+ * predicate. Absent, only public hosts over http/https are contacted.
27
+ */
28
+ export declare function mayAsk(url: string, policy?: ResponderPolicy): Promise<URL | ResponderRefusal>;
29
+ //# sourceMappingURL=responder.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"responder.d.ts","sourceRoot":"","sources":["../src/responder.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,6DAA6D;AAC7D,MAAM,MAAM,eAAe,GACxB,aAAa,CAAC,MAAM,CAAC,GACrB,CAAC,CAAC,GAAG,EAAE,GAAG,KAAK,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC;AA2C9C,sEAAsE;AACtE,MAAM,WAAW,gBAAgB;IAChC,OAAO,EAAE,MAAM,CAAC;CAChB;AAED;;;;;GAKG;AACH,wBAAsB,MAAM,CAC3B,GAAG,EAAE,MAAM,EACX,MAAM,CAAC,EAAE,eAAe,GACtB,OAAO,CAAC,GAAG,GAAG,gBAAgB,CAAC,CAuCjC"}
@@ -0,0 +1,101 @@
1
+ /**
2
+ * Deciding whether a revocation responder may be contacted.
3
+ *
4
+ * The address comes out of the certificate inside the document being checked,
5
+ * which is to say: from whoever sent the document. Following it unconditionally
6
+ * turns "check whether this signature is still valid" into "make my server
7
+ * issue an HTTP request wherever this stranger points" — the cloud metadata
8
+ * endpoint, a Redis on loopback, or simply a URL that confirms the document was
9
+ * opened and reveals the address it was opened from.
10
+ *
11
+ * So the default is a public responder over HTTP, and an application whose
12
+ * authority answers on the internal network says so by name. Everything
13
+ * refused answers `"unknown"`, never `"good"`: a responder that was not asked
14
+ * has told us nothing.
15
+ */
16
+ /** Hosts that are never a public certificate authority. */
17
+ function isPrivateHost(hostname) {
18
+ const host = hostname.replace(/^\[|\]$/g, "").toLowerCase();
19
+ if (host === "localhost" || host.endsWith(".localhost"))
20
+ return true;
21
+ // IPv6 loopback, unspecified, unique-local (fc00::/7) and link-local (fe80::/10).
22
+ if (host === "::1" || host === "::")
23
+ return true;
24
+ if (/^f[cd][0-9a-f]{2}:/.test(host))
25
+ return true;
26
+ if (/^fe[89ab][0-9a-f]:/.test(host))
27
+ return true;
28
+ // An IPv4-mapped IPv6 address is the same machine under another spelling,
29
+ // and the URL parser rewrites `::ffff:127.0.0.1` as `::ffff:7f00:1` — so a
30
+ // check that only reads dotted quads waves loopback straight through.
31
+ const mapped = /^::ffff:(\d+\.\d+\.\d+\.\d+)$/.exec(host) ??
32
+ (() => {
33
+ const hex = /^::ffff:([0-9a-f]{1,4}):([0-9a-f]{1,4})$/.exec(host);
34
+ if (hex === null)
35
+ return null;
36
+ const packed = (Number.parseInt(hex[1], 16) << 16) |
37
+ Number.parseInt(hex[2], 16);
38
+ return [
39
+ host,
40
+ [24, 16, 8, 0].map((shift) => (packed >>> shift) & 0xff).join("."),
41
+ ];
42
+ })();
43
+ const literal = mapped?.[1] ?? host;
44
+ const parts = literal.split(".");
45
+ if (parts.length !== 4 || !parts.every((p) => /^\d{1,3}$/.test(p)))
46
+ return false;
47
+ const [a, b] = parts.map(Number);
48
+ return (a === 0 || // this network
49
+ a === 127 || // loopback
50
+ a === 10 || // private
51
+ (a === 172 && b >= 16 && b <= 31) || // private
52
+ (a === 192 && b === 168) || // private
53
+ (a === 169 && b === 254) || // link-local, and the cloud metadata address
54
+ (a === 100 && b >= 64 && b <= 127) || // carrier-grade NAT
55
+ a >= 224 // multicast and reserved
56
+ );
57
+ }
58
+ /**
59
+ * Decide whether `url` may be asked.
60
+ *
61
+ * @param policy What the application allows: a list of hostnames, or a
62
+ * predicate. Absent, only public hosts over http/https are contacted.
63
+ */
64
+ export async function mayAsk(url, policy) {
65
+ let parsed;
66
+ try {
67
+ parsed = new URL(url);
68
+ }
69
+ catch {
70
+ return { refused: `the certificate names "${url}", which is not a URL` };
71
+ }
72
+ if (typeof policy === "function") {
73
+ return (await policy(parsed))
74
+ ? parsed
75
+ : { refused: `the configured policy refused ${parsed.origin}` };
76
+ }
77
+ if (policy !== undefined) {
78
+ return policy.includes(parsed.hostname)
79
+ ? parsed
80
+ : {
81
+ refused: `${parsed.hostname} is not among the responders this application allows` +
82
+ ` (${policy.join(", ") || "none"})`,
83
+ };
84
+ }
85
+ // OCSP is defined over HTTP. Anything else is a scheme somebody wanted the
86
+ // server to speak, not a way to ask about a certificate.
87
+ if (parsed.protocol !== "http:" && parsed.protocol !== "https:") {
88
+ return {
89
+ refused: `the certificate names a ${parsed.protocol.replace(":", "")} responder, which is not asked`,
90
+ };
91
+ }
92
+ if (isPrivateHost(parsed.hostname)) {
93
+ return {
94
+ refused: `the certificate names ${parsed.hostname}, an address on this network — ` +
95
+ "a document does not get to choose which of your own services is contacted. " +
96
+ "Name it in `allowedResponders` if that really is your authority.",
97
+ };
98
+ }
99
+ return parsed;
100
+ }
101
+ //# sourceMappingURL=responder.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"responder.js","sourceRoot":"","sources":["../src/responder.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Container service accessor — `import vellum from '@c9up/vellum/services/main'`.
3
+ *
4
+ * Populated by `VellumProvider.boot()`. Reading it before the provider has
5
+ * booted throws rather than answering with an unconfigured service, which
6
+ * would render with defaults nobody chose.
7
+ */
8
+ import type { Vellum } from "../Vellum.js";
9
+ /** @internal Called by the provider once the service exists. */
10
+ export declare function setVellum(service: Vellum): void;
11
+ /** @internal Test helper — forget the service between cases. */
12
+ export declare function clearVellum(): void;
13
+ declare const vellum: Vellum;
14
+ export default vellum;
15
+ //# sourceMappingURL=main.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"main.d.ts","sourceRoot":"","sources":["../../src/services/main.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAI3C,gEAAgE;AAChE,wBAAgB,SAAS,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAE/C;AAED,gEAAgE;AAChE,wBAAgB,WAAW,IAAI,IAAI,CAElC;AAYD,QAAA,MAAM,MAAM,EAAE,MAaZ,CAAC;AAEH,eAAe,MAAM,CAAC"}
@@ -0,0 +1,39 @@
1
+ /**
2
+ * Container service accessor — `import vellum from '@c9up/vellum/services/main'`.
3
+ *
4
+ * Populated by `VellumProvider.boot()`. Reading it before the provider has
5
+ * booted throws rather than answering with an unconfigured service, which
6
+ * would render with defaults nobody chose.
7
+ */
8
+ let instance;
9
+ /** @internal Called by the provider once the service exists. */
10
+ export function setVellum(service) {
11
+ instance = service;
12
+ }
13
+ /** @internal Test helper — forget the service between cases. */
14
+ export function clearVellum() {
15
+ instance = undefined;
16
+ }
17
+ function resolve() {
18
+ if (!instance) {
19
+ throw new Error("[vellum] Vellum service accessed before VellumProvider.boot() ran. " +
20
+ "Check that `@c9up/vellum/provider` is listed in your reamrc.ts providers.");
21
+ }
22
+ return instance;
23
+ }
24
+ const vellum = new Proxy(Object.create(null), {
25
+ get(_target, property) {
26
+ // A module loader probes an imported binding for `then` to see whether
27
+ // it is thenable, and for well-known symbols. Answering those by
28
+ // resolving the service would throw during the import itself, before
29
+ // any provider had a chance to boot.
30
+ if (property === "then" || typeof property === "symbol") {
31
+ return undefined;
32
+ }
33
+ const service = resolve();
34
+ const value = Reflect.get(service, property, service);
35
+ return typeof value === "function" ? value.bind(service) : value;
36
+ },
37
+ });
38
+ export default vellum;
39
+ //# sourceMappingURL=main.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"main.js","sourceRoot":"","sources":["../../src/services/main.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAIH,IAAI,QAA4B,CAAC;AAEjC,gEAAgE;AAChE,MAAM,UAAU,SAAS,CAAC,OAAe;IACxC,QAAQ,GAAG,OAAO,CAAC;AACpB,CAAC;AAED,gEAAgE;AAChE,MAAM,UAAU,WAAW;IAC1B,QAAQ,GAAG,SAAS,CAAC;AACtB,CAAC;AAED,SAAS,OAAO;IACf,IAAI,CAAC,QAAQ,EAAE,CAAC;QACf,MAAM,IAAI,KAAK,CACd,qEAAqE;YACpE,2EAA2E,CAC5E,CAAC;IACH,CAAC;IACD,OAAO,QAAQ,CAAC;AACjB,CAAC;AAED,MAAM,MAAM,GAAW,IAAI,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE;IACrD,GAAG,CAAC,OAAO,EAAE,QAAQ;QACpB,uEAAuE;QACvE,iEAAiE;QACjE,qEAAqE;QACrE,qCAAqC;QACrC,IAAI,QAAQ,KAAK,MAAM,IAAI,OAAO,QAAQ,KAAK,QAAQ,EAAE,CAAC;YACzD,OAAO,SAAS,CAAC;QAClB,CAAC;QACD,MAAM,OAAO,GAAG,OAAO,EAAE,CAAC;QAC1B,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,OAAO,EAAE,QAAQ,EAAE,OAAO,CAAC,CAAC;QACtD,OAAO,OAAO,KAAK,KAAK,UAAU,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC;IAClE,CAAC;CACD,CAAC,CAAC;AAEH,eAAe,MAAM,CAAC"}
@@ -0,0 +1,81 @@
1
+ /**
2
+ * Signers that need nothing but a key you hold.
3
+ *
4
+ * A signer bound to a certified provider is not here and should not be: it
5
+ * belongs to whoever has the account, as an adapter of its own. This package
6
+ * ships the contract and the one implementation that has no vendor behind it.
7
+ */
8
+ import type { Signer } from "./Vellum.js";
9
+ /** A key you hold, and the certificate that vouches for it. */
10
+ export interface Pkcs8SignerOptions {
11
+ /** The private key, PKCS#8 DER. */
12
+ key: Buffer;
13
+ /** The signer's certificate, DER. */
14
+ certificate: Buffer;
15
+ /**
16
+ * The rest of the chain, DER, nearest issuer first.
17
+ *
18
+ * Worth supplying: a verifier that has to go and find the issuers itself
19
+ * will often decide it cannot.
20
+ */
21
+ chain?: ReadonlyArray<Buffer>;
22
+ }
23
+ /**
24
+ * Sign with a key held by the application.
25
+ *
26
+ * ```ts
27
+ * // config/vellum.ts
28
+ * signers: {
29
+ * internal: pkcs8Signer({
30
+ * key: readFileSync(app.makePath('storage/signing.key.der')),
31
+ * certificate: readFileSync(app.makePath('storage/signing.crt.der')),
32
+ * }),
33
+ * }
34
+ * ```
35
+ *
36
+ * This is an *advanced* signature: it proves the document has not changed
37
+ * since a particular key signed it. Whether that is enough is a question about
38
+ * the document, not about the code — where the law requires a qualified
39
+ * signature, the key has to live with a certified provider, and that is an
40
+ * adapter rather than this.
41
+ *
42
+ * PKCS#8 and DER rather than a `.p12` bundle: reading PKCS#12 in Rust is not
43
+ * something to put underneath a signature, and
44
+ * `openssl pkcs12 -in bundle.p12 -nodes` gets you here in one command.
45
+ */
46
+ export declare function pkcs8Signer(options: Pkcs8SignerOptions): Signer;
47
+ /** Where to ask for a timestamp, and how. */
48
+ export interface TimestampOptions {
49
+ /** The authority's RFC 3161 endpoint. */
50
+ url: string;
51
+ /** Anything the authority needs, such as an Authorization header. */
52
+ headers?: Record<string, string>;
53
+ /** How long to wait before giving up. Default 10 seconds. */
54
+ timeoutMs?: number;
55
+ }
56
+ /**
57
+ * Add a trusted timestamp to whatever `inner` signs.
58
+ *
59
+ * ```ts
60
+ * signers: {
61
+ * internal: timestamped(pkcs8Signer({ key, certificate }), {
62
+ * url: 'https://freetsa.org/tsr',
63
+ * }),
64
+ * }
65
+ * ```
66
+ *
67
+ * A signature proves a document has not changed since a key signed it, not
68
+ * *when*. Once the signing certificate expires, a verifier cannot tell a
69
+ * signature made while it was valid from one forged afterwards, and stops
70
+ * accepting it. For a document kept for years — which is most of the documents
71
+ * anyone bothers to sign — a timestamp is what keeps it verifiable.
72
+ *
73
+ * It wraps any signer, so it works over a provider's as well as the local one.
74
+ * The token goes on as an unsigned attribute, which is what lets it be added
75
+ * without disturbing the signature.
76
+ *
77
+ * The signature grows by a few kilobytes, so a document prepared with a tight
78
+ * `capacity` may need a larger one.
79
+ */
80
+ export declare function timestamped(inner: Signer, options: TimestampOptions): Signer;
81
+ //# sourceMappingURL=signers.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"signers.d.ts","sourceRoot":"","sources":["../src/signers.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAQH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAE1C,+DAA+D;AAC/D,MAAM,WAAW,kBAAkB;IAClC,mCAAmC;IACnC,GAAG,EAAE,MAAM,CAAC;IACZ,qCAAqC;IACrC,WAAW,EAAE,MAAM,CAAC;IACpB;;;;;OAKG;IACH,KAAK,CAAC,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC;CAC9B;AAED;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAgB,WAAW,CAAC,OAAO,EAAE,kBAAkB,GAAG,MAAM,CAmB/D;AAED,6CAA6C;AAC7C,MAAM,WAAW,gBAAgB;IAChC,yCAAyC;IACzC,GAAG,EAAE,MAAM,CAAC;IACZ,qEAAqE;IACrE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,6DAA6D;IAC7D,SAAS,CAAC,EAAE,MAAM,CAAC;CACnB;AAED;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,gBAAgB,GAAG,MAAM,CAuC5E"}
@@ -0,0 +1,98 @@
1
+ /**
2
+ * Signers that need nothing but a key you hold.
3
+ *
4
+ * A signer bound to a certified provider is not here and should not be: it
5
+ * belongs to whoever has the account, as an adapter of its own. This package
6
+ * ships the contract and the one implementation that has no vendor behind it.
7
+ */
8
+ import { VellumError } from "./errors.js";
9
+ import { attachTimestampNative, signCmsNative, timestampQueryNative, } from "./native.js";
10
+ /**
11
+ * Sign with a key held by the application.
12
+ *
13
+ * ```ts
14
+ * // config/vellum.ts
15
+ * signers: {
16
+ * internal: pkcs8Signer({
17
+ * key: readFileSync(app.makePath('storage/signing.key.der')),
18
+ * certificate: readFileSync(app.makePath('storage/signing.crt.der')),
19
+ * }),
20
+ * }
21
+ * ```
22
+ *
23
+ * This is an *advanced* signature: it proves the document has not changed
24
+ * since a particular key signed it. Whether that is enough is a question about
25
+ * the document, not about the code — where the law requires a qualified
26
+ * signature, the key has to live with a certified provider, and that is an
27
+ * adapter rather than this.
28
+ *
29
+ * PKCS#8 and DER rather than a `.p12` bundle: reading PKCS#12 in Rust is not
30
+ * something to put underneath a signature, and
31
+ * `openssl pkcs12 -in bundle.p12 -nodes` gets you here in one command.
32
+ */
33
+ export function pkcs8Signer(options) {
34
+ if (options.key.length === 0) {
35
+ throw new VellumError("SIGNER_INVALID", "The signing key is empty.");
36
+ }
37
+ if (options.certificate.length === 0) {
38
+ throw new VellumError("SIGNER_INVALID", "The certificate is empty.");
39
+ }
40
+ const certificates = [options.certificate, ...(options.chain ?? [])];
41
+ return {
42
+ async sign(digest) {
43
+ return signCmsNative(digest, options.key, certificates, new Date().toISOString());
44
+ },
45
+ };
46
+ }
47
+ /**
48
+ * Add a trusted timestamp to whatever `inner` signs.
49
+ *
50
+ * ```ts
51
+ * signers: {
52
+ * internal: timestamped(pkcs8Signer({ key, certificate }), {
53
+ * url: 'https://freetsa.org/tsr',
54
+ * }),
55
+ * }
56
+ * ```
57
+ *
58
+ * A signature proves a document has not changed since a key signed it, not
59
+ * *when*. Once the signing certificate expires, a verifier cannot tell a
60
+ * signature made while it was valid from one forged afterwards, and stops
61
+ * accepting it. For a document kept for years — which is most of the documents
62
+ * anyone bothers to sign — a timestamp is what keeps it verifiable.
63
+ *
64
+ * It wraps any signer, so it works over a provider's as well as the local one.
65
+ * The token goes on as an unsigned attribute, which is what lets it be added
66
+ * without disturbing the signature.
67
+ *
68
+ * The signature grows by a few kilobytes, so a document prepared with a tight
69
+ * `capacity` may need a larger one.
70
+ */
71
+ export function timestamped(inner, options) {
72
+ return {
73
+ async sign(digest) {
74
+ const cms = await inner.sign(digest);
75
+ const { query, nonce } = timestampQueryNative(cms);
76
+ let answer;
77
+ try {
78
+ answer = await fetch(options.url, {
79
+ method: "POST",
80
+ headers: {
81
+ "content-type": "application/timestamp-query",
82
+ ...options.headers,
83
+ },
84
+ body: new Uint8Array(query),
85
+ signal: AbortSignal.timeout(options.timeoutMs ?? 10_000),
86
+ });
87
+ }
88
+ catch (error) {
89
+ throw new VellumError("TIMESTAMP_UNREACHABLE", `The timestamp authority at ${options.url} could not be reached.`, { cause: error });
90
+ }
91
+ if (!answer.ok) {
92
+ throw new VellumError("TIMESTAMP_REFUSED", `The timestamp authority at ${options.url} answered ${answer.status}.`);
93
+ }
94
+ return attachTimestampNative(cms, Buffer.from(await answer.arrayBuffer()), nonce);
95
+ },
96
+ };
97
+ }
98
+ //# sourceMappingURL=signers.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"signers.js","sourceRoot":"","sources":["../src/signers.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,EACN,qBAAqB,EACrB,aAAa,EACb,oBAAoB,GACpB,MAAM,aAAa,CAAC;AAkBrB;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,MAAM,UAAU,WAAW,CAAC,OAA2B;IACtD,IAAI,OAAO,CAAC,GAAG,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC9B,MAAM,IAAI,WAAW,CAAC,gBAAgB,EAAE,2BAA2B,CAAC,CAAC;IACtE,CAAC;IACD,IAAI,OAAO,CAAC,WAAW,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACtC,MAAM,IAAI,WAAW,CAAC,gBAAgB,EAAE,2BAA2B,CAAC,CAAC;IACtE,CAAC;IAED,MAAM,YAAY,GAAG,CAAC,OAAO,CAAC,WAAW,EAAE,GAAG,CAAC,OAAO,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC,CAAC;IACrE,OAAO;QACN,KAAK,CAAC,IAAI,CAAC,MAAc;YACxB,OAAO,aAAa,CACnB,MAAM,EACN,OAAO,CAAC,GAAG,EACX,YAAY,EACZ,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CACxB,CAAC;QACH,CAAC;KACD,CAAC;AACH,CAAC;AAYD;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,MAAM,UAAU,WAAW,CAAC,KAAa,EAAE,OAAyB;IACnE,OAAO;QACN,KAAK,CAAC,IAAI,CAAC,MAAc;YACxB,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;YACrC,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,GAAG,oBAAoB,CAAC,GAAG,CAAC,CAAC;YAEnD,IAAI,MAAgB,CAAC;YACrB,IAAI,CAAC;gBACJ,MAAM,GAAG,MAAM,KAAK,CAAC,OAAO,CAAC,GAAG,EAAE;oBACjC,MAAM,EAAE,MAAM;oBACd,OAAO,EAAE;wBACR,cAAc,EAAE,6BAA6B;wBAC7C,GAAG,OAAO,CAAC,OAAO;qBAClB;oBACD,IAAI,EAAE,IAAI,UAAU,CAAC,KAAK,CAAC;oBAC3B,MAAM,EAAE,WAAW,CAAC,OAAO,CAAC,OAAO,CAAC,SAAS,IAAI,MAAM,CAAC;iBACxD,CAAC,CAAC;YACJ,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBAChB,MAAM,IAAI,WAAW,CACpB,uBAAuB,EACvB,8BAA8B,OAAO,CAAC,GAAG,wBAAwB,EACjE,EAAE,KAAK,EAAE,KAAK,EAAE,CAChB,CAAC;YACH,CAAC;YAED,IAAI,CAAC,MAAM,CAAC,EAAE,EAAE,CAAC;gBAChB,MAAM,IAAI,WAAW,CACpB,mBAAmB,EACnB,8BAA8B,OAAO,CAAC,GAAG,aAAa,MAAM,CAAC,MAAM,GAAG,CACtE,CAAC;YACH,CAAC;YAED,OAAO,qBAAqB,CAC3B,GAAG,EACH,MAAM,CAAC,IAAI,CAAC,MAAM,MAAM,CAAC,WAAW,EAAE,CAAC,EACvC,KAAK,CACL,CAAC;QACH,CAAC;KACD,CAAC;AACH,CAAC"}
Binary file
Binary file
Binary file
Binary file
Binary file