@f-o-t/e-signature 1.1.0 → 1.2.1

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.
package/README.md CHANGED
@@ -19,7 +19,7 @@ bun add @f-o-t/e-signature
19
19
 
20
20
  ## API
21
21
 
22
- ### `signPdf(pdf: Uint8Array, options: PdfSignOptions): Promise<Uint8Array>`
22
+ ### `signPdf(pdf: Uint8Array | ReadableStream<Uint8Array>, options: PdfSignOptions): Promise<Uint8Array>`
23
23
 
24
24
  Sign a PDF document with a digital certificate. Supports PAdES-BES and PAdES with ICP-Brasil compliance (signing-certificate-v2 and signature-policy attributes).
25
25
 
@@ -63,6 +63,35 @@ const signedPdf = await signPdf(pdfBytes, {
63
63
 
64
64
  `appearance` and `appearances` can be used simultaneously — both stamps are rendered. An empty `appearances: []` is a no-op.
65
65
 
66
+ #### TSA Resilience
67
+
68
+ Control timeout, retry, and fallback behavior for timestamp requests:
69
+
70
+ ```ts
71
+ const signedPdf = await signPdf(pdfBytes, {
72
+ certificate: { p12, password: "secret" },
73
+ timestamp: true,
74
+ tsaUrl: TIMESTAMP_SERVERS.VALID,
75
+ tsaTimeout: 5000, // 5s per attempt (default: 10000)
76
+ tsaRetries: 2, // 2 retries after initial attempt, 3 total (default: 0)
77
+ tsaFallbackUrls: [ // tried in order after primary fails
78
+ TIMESTAMP_SERVERS.SAFEWEB,
79
+ TIMESTAMP_SERVERS.CERTISIGN,
80
+ ],
81
+ });
82
+ ```
83
+
84
+ If all servers fail, a `TimestampError` is thrown with a descriptive message identifying which servers were tried and the last error.
85
+
86
+ #### Signing from a ReadableStream
87
+
88
+ ```ts
89
+ const stream: ReadableStream<Uint8Array> = getFileStream("document.pdf");
90
+ const signedPdf = await signPdf(stream, {
91
+ certificate: { p12, password: "secret" },
92
+ });
93
+ ```
94
+
66
95
  ### `buildSigningCertificateV2(certDer: Uint8Array): Uint8Array`
67
96
 
68
97
  Build the `id-aa-signingCertificateV2` attribute value (RFC 5035). Links the signature to the specific certificate used, preventing substitution attacks.
@@ -75,7 +104,7 @@ Build the `id-aa-ets-sigPolicyId` attribute value. Downloads the ICP-Brasil PAdE
75
104
 
76
105
  Clear the cached signature policy data, forcing a re-download on the next call.
77
106
 
78
- ### `requestTimestamp(data: Uint8Array, tsaUrl: string, hashAlgorithm?: "sha256" | "sha384" | "sha512"): Promise<Uint8Array>`
107
+ ### `requestTimestamp(data: Uint8Array, tsaUrl: string, hashAlgorithm?: "sha256" | "sha384" | "sha512", options?: { tsaTimeout?: number; tsaRetries?: number; tsaFallbackUrls?: string[] }): Promise<Uint8Array>`
79
108
 
80
109
  Request an RFC 3161 timestamp from a TSA server. Returns the DER-encoded TimeStampToken.
81
110
 
@@ -85,6 +114,50 @@ import { requestTimestamp, TIMESTAMP_SERVERS } from "@f-o-t/e-signature";
85
114
  const token = await requestTimestamp(signatureBytes, TIMESTAMP_SERVERS.VALID);
86
115
  ```
87
116
 
117
+ ### `signPdfBatch(files: BatchSignInput[], options: PdfSignOptions): AsyncGenerator<BatchSignEvent>`
118
+
119
+ Sign multiple PDFs sequentially, yielding progress events. Yields control between each signing to prevent blocking the event loop.
120
+
121
+ ```ts
122
+ import { signPdfBatch, signPdfBatchToArray, TIMESTAMP_SERVERS } from "@f-o-t/e-signature";
123
+
124
+ for await (const event of signPdfBatch(
125
+ [
126
+ { filename: "doc1.pdf", pdf: pdf1Bytes },
127
+ { filename: "doc2.pdf", pdf: pdf2Bytes, options: { reason: "Custom reason" } },
128
+ ],
129
+ { certificate: { p12, password: "secret" } },
130
+ )) {
131
+ switch (event.type) {
132
+ case "file_start": console.log(`Signing ${event.filename}...`); break;
133
+ case "file_complete": console.log(`Signed ${event.filename}`); break;
134
+ case "file_error": console.error(`Failed ${event.filename}: ${event.error}`); break;
135
+ case "batch_complete": console.log(`Done: ${event.totalFiles} files, ${event.errorCount} errors`); break;
136
+ }
137
+ }
138
+ ```
139
+
140
+ Per-file `options` are merged with the base options (per-file takes priority). Error in one file emits a `file_error` event and continues with the next file.
141
+
142
+ ### `signPdfBatchToArray(files: BatchSignInput[], options: PdfSignOptions): Promise<...[]>`
143
+
144
+ Convenience wrapper that collects all results:
145
+
146
+ ```ts
147
+ const results = await signPdfBatchToArray(
148
+ [
149
+ { filename: "doc1.pdf", pdf: pdf1Bytes },
150
+ { filename: "doc2.pdf", pdf: pdf2Bytes },
151
+ ],
152
+ { certificate: { p12, password: "secret" } },
153
+ );
154
+
155
+ for (const r of results) {
156
+ if (r.signed) await Bun.write(r.filename, r.signed);
157
+ else console.error(`${r.filename}: ${r.error}`);
158
+ }
159
+ ```
160
+
88
161
  ## Constants
89
162
 
90
163
  ### `ICP_BRASIL_OIDS`
@@ -119,6 +192,14 @@ type PdfSignOptions = {
119
192
  policy?: "pades-ades" | "pades-icp-brasil";
120
193
  timestamp?: boolean;
121
194
  tsaUrl?: string;
195
+ /** Timeout in ms per TSA attempt (default: 10000) */
196
+ tsaTimeout?: number;
197
+ /** Number of retry attempts after the initial TSA request fails (default: 0); total attempts = 1 + tsaRetries */
198
+ tsaRetries?: number;
199
+ /** Fallback TSA server URLs tried in order after primary is exhausted */
200
+ tsaFallbackUrls?: string[];
201
+ /** Called when timestamping fails (non-fatal). Receives the error for logging/metrics. */
202
+ onTimestampError?: (error: unknown) => void;
122
203
  /** Single visual stamp (false to disable) */
123
204
  appearance?: SignatureAppearance | false;
124
205
  /** Multiple visual stamps — renders one per entry, useful for multi-page documents */
@@ -141,6 +222,21 @@ type QrCodeConfig = {
141
222
  data?: string;
142
223
  size?: number;
143
224
  };
225
+
226
+ type BatchSignInput = {
227
+ /** Filename for identification in events */
228
+ filename: string;
229
+ /** PDF content as Uint8Array or ReadableStream */
230
+ pdf: Uint8Array | ReadableStream<Uint8Array>;
231
+ /** Per-file option overrides merged with base options */
232
+ options?: Partial<PdfSignOptions>;
233
+ };
234
+
235
+ type BatchSignEvent =
236
+ | { type: "file_start"; fileIndex: number; filename: string }
237
+ | { type: "file_complete"; fileIndex: number; filename: string; signed: Uint8Array }
238
+ | { type: "file_error"; fileIndex: number; filename: string; error: string }
239
+ | { type: "batch_complete"; totalFiles: number; errorCount: number };
144
240
  ```
145
241
 
146
242
  ## Error Classes
@@ -0,0 +1,61 @@
1
+ import type { PdfSignOptions } from "./types.ts";
2
+ /**
3
+ * Input for a single PDF in a batch signing operation.
4
+ */
5
+ export type BatchSignInput = {
6
+ /** Filename for identification in events */
7
+ filename: string;
8
+ /** PDF content as Uint8Array or ReadableStream */
9
+ pdf: Uint8Array | ReadableStream<Uint8Array>;
10
+ /** Per-file option overrides merged with base options */
11
+ options?: Partial<PdfSignOptions>;
12
+ };
13
+ /**
14
+ * Events emitted during batch signing.
15
+ */
16
+ export type BatchSignEvent = {
17
+ type: "file_start";
18
+ fileIndex: number;
19
+ filename: string;
20
+ } | {
21
+ type: "file_complete";
22
+ fileIndex: number;
23
+ filename: string;
24
+ signed: Uint8Array;
25
+ } | {
26
+ type: "file_error";
27
+ fileIndex: number;
28
+ filename: string;
29
+ error: string;
30
+ } | {
31
+ type: "batch_complete";
32
+ totalFiles: number;
33
+ errorCount: number;
34
+ };
35
+ /**
36
+ * Sign multiple PDFs sequentially, yielding progress events.
37
+ *
38
+ * Yields control between each signing operation to prevent blocking
39
+ * the event loop under bulk load.
40
+ *
41
+ * @param files - Array of PDFs with filename and optional per-file options
42
+ * @param options - Base signing options (per-file options override these)
43
+ * @yields BatchSignEvent for each file start, completion, error, and batch complete
44
+ */
45
+ export declare function signPdfBatch(files: BatchSignInput[], options: PdfSignOptions): AsyncGenerator<BatchSignEvent>;
46
+ /**
47
+ * Sign multiple PDFs sequentially, collecting all results.
48
+ *
49
+ * Convenience wrapper around {@link signPdfBatch} that collects all events
50
+ * into an array of results.
51
+ *
52
+ * @param files - Array of PDFs with filename and optional per-file options
53
+ * @param options - Base signing options
54
+ * @returns Array of results with signed PDF bytes or error per file
55
+ */
56
+ export declare function signPdfBatchToArray(files: BatchSignInput[], options: PdfSignOptions): Promise<{
57
+ filename: string;
58
+ signed?: Uint8Array;
59
+ error?: string;
60
+ }[]>;
61
+ //# sourceMappingURL=batch.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"batch.d.ts","sourceRoot":"","sources":["../src/batch.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAEjD;;GAEG;AACH,MAAM,MAAM,cAAc,GAAG;IAC3B,4CAA4C;IAC5C,QAAQ,EAAE,MAAM,CAAC;IACjB,kDAAkD;IAClD,GAAG,EAAE,UAAU,GAAG,cAAc,CAAC,UAAU,CAAC,CAAC;IAC7C,yDAAyD;IACzD,OAAO,CAAC,EAAE,OAAO,CAAC,cAAc,CAAC,CAAC;CACnC,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,cAAc,GACtB;IAAE,IAAI,EAAE,YAAY,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,GAC3D;IAAE,IAAI,EAAE,eAAe,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,UAAU,CAAA;CAAE,GAClF;IAAE,IAAI,EAAE,YAAY,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GAC1E;IAAE,IAAI,EAAE,gBAAgB,CAAC;IAAC,UAAU,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAA;CAAE,CAAC;AAEvE;;;;;;;;;GASG;AACH,wBAAuB,YAAY,CACjC,KAAK,EAAE,cAAc,EAAE,EACvB,OAAO,EAAE,cAAc,GACtB,cAAc,CAAC,cAAc,CAAC,CAiChC;AAED;;;;;;;;;GASG;AACH,wBAAsB,mBAAmB,CACvC,KAAK,EAAE,cAAc,EAAE,EACvB,OAAO,EAAE,cAAc,GACtB,OAAO,CAAC;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,UAAU,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,EAAE,CAAC,CAoBtE"}
package/dist/index.d.ts CHANGED
@@ -6,6 +6,8 @@
6
6
  *
7
7
  * @packageDocumentation
8
8
  */
9
+ export { signPdfBatch, signPdfBatchToArray } from "./batch.ts";
10
+ export type { BatchSignEvent, BatchSignInput } from "./batch.ts";
9
11
  export { buildSignaturePolicy, buildSigningCertificateV2, clearPolicyCache, ICP_BRASIL_OIDS, SignaturePolicyError, } from "./icp-brasil.ts";
10
12
  export { pdfSignOptionsSchema } from "./schemas.ts";
11
13
  export { PdfSignError, signPdf } from "./sign-pdf.ts";
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EACJ,oBAAoB,EACpB,yBAAyB,EACzB,gBAAgB,EAChB,eAAe,EACf,oBAAoB,GACtB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAC;AACpD,OAAO,EAAE,YAAY,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AACtD,OAAO,EACJ,gBAAgB,EAChB,iBAAiB,EACjB,mBAAmB,EACnB,cAAc,GAChB,MAAM,gBAAgB,CAAC;AACxB,YAAY,EACT,cAAc,EACd,YAAY,EACZ,mBAAmB,GACrB,MAAM,YAAY,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,YAAY,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AAC/D,YAAY,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AACjE,OAAO,EACJ,oBAAoB,EACpB,yBAAyB,EACzB,gBAAgB,EAChB,eAAe,EACf,oBAAoB,GACtB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAC;AACpD,OAAO,EAAE,YAAY,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AACtD,OAAO,EACJ,gBAAgB,EAChB,iBAAiB,EACjB,mBAAmB,EACnB,cAAc,GAChB,MAAM,gBAAgB,CAAC;AACxB,YAAY,EACT,cAAc,EACd,YAAY,EACZ,mBAAmB,GACrB,MAAM,YAAY,CAAC"}
package/dist/index.js CHANGED
@@ -1,136 +1,6 @@
1
1
  // @bun
2
2
  var __require = import.meta.require;
3
3
 
4
- // src/icp-brasil.ts
5
- import {
6
- contextTag,
7
- decodeDer,
8
- encodeDer,
9
- ia5String,
10
- nullValue,
11
- octetString,
12
- oid,
13
- sequence
14
- } from "@f-o-t/asn1";
15
- import { hash } from "@f-o-t/crypto";
16
- var SHA256_OID = "2.16.840.1.101.3.4.2.1";
17
- var SIGNING_CERTIFICATE_V2_OID = "1.2.840.113549.1.9.16.2.47";
18
- var SIGNATURE_POLICY_OID = "1.2.840.113549.1.9.16.2.15";
19
- var POLICY_CONFIG = {
20
- OID: "2.16.76.1.7.1.11.1.1",
21
- URL: "http://politicas.icpbrasil.gov.br/PA_PAdES_AD_RB_v1_1.der"
22
- };
23
- var SPQ_ETS_URI_OID = "1.2.840.113549.1.9.16.5.1";
24
- var cachedPolicyData = null;
25
- function clearPolicyCache() {
26
- cachedPolicyData = null;
27
- }
28
- function buildSigningCertificateV2(certDer) {
29
- const certHash = hash("sha256", certDer);
30
- const hashAlgId = sequence(oid(SHA256_OID), nullValue());
31
- const cert = decodeDer(certDer);
32
- const tbsCert = cert.value[0];
33
- const tbs = tbsCert.value;
34
- let idx = 0;
35
- if (tbs[0].class === "context" && tbs[0].tag === 0) {
36
- idx = 1;
37
- }
38
- const serialNumber = tbs[idx];
39
- const issuerName = tbs[idx + 2];
40
- const generalName = contextTag(4, [issuerName]);
41
- const generalNames = sequence(generalName);
42
- const issuerSerial = sequence(generalNames, serialNumber);
43
- const essCertIdV2 = sequence(hashAlgId, octetString(certHash), issuerSerial);
44
- const signingCertV2 = sequence(sequence(essCertIdV2));
45
- return encodeDer(signingCertV2);
46
- }
47
- async function downloadAndParsePolicyDocument() {
48
- if (cachedPolicyData) {
49
- return cachedPolicyData;
50
- }
51
- const response = await fetch(POLICY_CONFIG.URL);
52
- if (!response.ok) {
53
- throw new SignaturePolicyError(`Failed to download signature policy: HTTP ${response.status}`);
54
- }
55
- const arrayBuffer = await response.arrayBuffer();
56
- const data = new Uint8Array(arrayBuffer);
57
- if (data.length === 0 || data[0] !== 48) {
58
- throw new SignaturePolicyError("Invalid DER format in policy document");
59
- }
60
- const asn1 = decodeDer(data);
61
- const children = asn1.value;
62
- if (!Array.isArray(children) || children.length < 3) {
63
- throw new SignaturePolicyError(`Unexpected policy structure: expected 3+ children, got ${children?.length}`);
64
- }
65
- const algIdChildren = children[0].value;
66
- if (!Array.isArray(algIdChildren) || algIdChildren.length === 0) {
67
- throw new SignaturePolicyError("Invalid AlgorithmIdentifier in policy");
68
- }
69
- const { bytesToOid } = await import("@f-o-t/asn1");
70
- const hashAlgOid = bytesToOid(algIdChildren[0].value);
71
- const hashNode = children[2];
72
- if (hashNode.tag !== 4) {
73
- throw new SignaturePolicyError(`Expected OCTET STRING at child[2], got tag 0x${hashNode.tag.toString(16)}`);
74
- }
75
- cachedPolicyData = {
76
- hashAlgOid,
77
- policyHash: hashNode.value
78
- };
79
- return cachedPolicyData;
80
- }
81
- async function buildSignaturePolicy() {
82
- const { hashAlgOid, policyHash } = await downloadAndParsePolicyDocument();
83
- const hashAlgId = sequence(oid(hashAlgOid));
84
- const sigPolicyHash = sequence(hashAlgId, octetString(policyHash));
85
- const sigPolicyQualifiers = sequence(sequence(oid(SPQ_ETS_URI_OID), ia5String(POLICY_CONFIG.URL)));
86
- const signaturePolicyId = sequence(oid(POLICY_CONFIG.OID), sigPolicyHash, sigPolicyQualifiers);
87
- return encodeDer(signaturePolicyId);
88
- }
89
- var ICP_BRASIL_OIDS = {
90
- signingCertificateV2: SIGNING_CERTIFICATE_V2_OID,
91
- signaturePolicy: SIGNATURE_POLICY_OID
92
- };
93
-
94
- class SignaturePolicyError extends Error {
95
- constructor(message) {
96
- super(message);
97
- this.name = "SignaturePolicyError";
98
- }
99
- }
100
- // src/schemas.ts
101
- import { z } from "zod";
102
- var signatureAppearanceSchema = z.object({
103
- x: z.number(),
104
- y: z.number(),
105
- width: z.number().positive(),
106
- height: z.number().positive(),
107
- page: z.number().int().min(0).optional(),
108
- showQrCode: z.boolean().optional(),
109
- showCertInfo: z.boolean().optional()
110
- });
111
- var qrCodeConfigSchema = z.object({
112
- data: z.string().optional(),
113
- size: z.number().int().positive().optional()
114
- });
115
- var pdfSignOptionsSchema = z.object({
116
- certificate: z.object({
117
- p12: z.instanceof(Uint8Array).refine((v) => v.length > 0, {
118
- message: "P12 data must not be empty"
119
- }),
120
- password: z.string(),
121
- name: z.string().optional()
122
- }),
123
- reason: z.string().optional(),
124
- location: z.string().optional(),
125
- contactInfo: z.string().optional(),
126
- policy: z.enum(["pades-ades", "pades-icp-brasil"]).optional(),
127
- timestamp: z.boolean().optional(),
128
- tsaUrl: z.string().url().optional(),
129
- appearance: z.union([signatureAppearanceSchema, z.literal(false)]).optional(),
130
- appearances: z.array(signatureAppearanceSchema).optional(),
131
- qrCode: qrCodeConfigSchema.optional(),
132
- docMdpPermission: z.union([z.literal(1), z.literal(2), z.literal(3)]).optional()
133
- });
134
4
  // src/sign-pdf.ts
135
5
  import { createSignedData, parsePkcs12 } from "@f-o-t/crypto";
136
6
  import { parseCertificate } from "@f-o-t/digital-certificate";
@@ -142,7 +12,7 @@ import {
142
12
  } from "@f-o-t/pdf/plugins/editing";
143
13
 
144
14
  // src/appearance.ts
145
- import { hash as hash2 } from "@f-o-t/crypto";
15
+ import { hash } from "@f-o-t/crypto";
146
16
  import { generateQrCode } from "@f-o-t/qrcode";
147
17
  function drawSignatureAppearance(doc, page, appearance, certInfo, options) {
148
18
  const { x, width, height } = appearance;
@@ -245,7 +115,7 @@ function drawCertInfo(page, certInfo, opts) {
245
115
  }
246
116
  }
247
117
  function createVerificationData(certInfo, pdfData) {
248
- const documentHash = toHex(hash2("sha256", pdfData));
118
+ const documentHash = toHex(hash("sha256", pdfData));
249
119
  const timestamp = new Date().toISOString();
250
120
  if (certInfo) {
251
121
  const certFingerprint = certInfo.fingerprint;
@@ -267,6 +137,142 @@ function toHex(data) {
267
137
  return chars.join("");
268
138
  }
269
139
 
140
+ // src/icp-brasil.ts
141
+ import {
142
+ contextTag,
143
+ decodeDer,
144
+ encodeDer,
145
+ ia5String,
146
+ nullValue,
147
+ octetString,
148
+ oid,
149
+ sequence
150
+ } from "@f-o-t/asn1";
151
+ import { hash as hash2 } from "@f-o-t/crypto";
152
+ var SHA256_OID = "2.16.840.1.101.3.4.2.1";
153
+ var SIGNING_CERTIFICATE_V2_OID = "1.2.840.113549.1.9.16.2.47";
154
+ var SIGNATURE_POLICY_OID = "1.2.840.113549.1.9.16.2.15";
155
+ var POLICY_CONFIG = {
156
+ OID: "2.16.76.1.7.1.11.1.1",
157
+ URL: "http://politicas.icpbrasil.gov.br/PA_PAdES_AD_RB_v1_1.der"
158
+ };
159
+ var SPQ_ETS_URI_OID = "1.2.840.113549.1.9.16.5.1";
160
+ var cachedPolicyData = null;
161
+ function clearPolicyCache() {
162
+ cachedPolicyData = null;
163
+ }
164
+ function buildSigningCertificateV2(certDer) {
165
+ const certHash = hash2("sha256", certDer);
166
+ const hashAlgId = sequence(oid(SHA256_OID), nullValue());
167
+ const cert = decodeDer(certDer);
168
+ const tbsCert = cert.value[0];
169
+ const tbs = tbsCert.value;
170
+ let idx = 0;
171
+ if (tbs[0].class === "context" && tbs[0].tag === 0) {
172
+ idx = 1;
173
+ }
174
+ const serialNumber = tbs[idx];
175
+ const issuerName = tbs[idx + 2];
176
+ const generalName = contextTag(4, [issuerName]);
177
+ const generalNames = sequence(generalName);
178
+ const issuerSerial = sequence(generalNames, serialNumber);
179
+ const essCertIdV2 = sequence(hashAlgId, octetString(certHash), issuerSerial);
180
+ const signingCertV2 = sequence(sequence(essCertIdV2));
181
+ return encodeDer(signingCertV2);
182
+ }
183
+ async function downloadAndParsePolicyDocument() {
184
+ if (cachedPolicyData) {
185
+ return cachedPolicyData;
186
+ }
187
+ const response = await fetch(POLICY_CONFIG.URL);
188
+ if (!response.ok) {
189
+ throw new SignaturePolicyError(`Failed to download signature policy: HTTP ${response.status}`);
190
+ }
191
+ const arrayBuffer = await response.arrayBuffer();
192
+ const data = new Uint8Array(arrayBuffer);
193
+ if (data.length === 0 || data[0] !== 48) {
194
+ throw new SignaturePolicyError("Invalid DER format in policy document");
195
+ }
196
+ const asn1 = decodeDer(data);
197
+ const children = asn1.value;
198
+ if (!Array.isArray(children) || children.length < 3) {
199
+ throw new SignaturePolicyError(`Unexpected policy structure: expected 3+ children, got ${children?.length}`);
200
+ }
201
+ const algIdChildren = children[0].value;
202
+ if (!Array.isArray(algIdChildren) || algIdChildren.length === 0) {
203
+ throw new SignaturePolicyError("Invalid AlgorithmIdentifier in policy");
204
+ }
205
+ const { bytesToOid } = await import("@f-o-t/asn1");
206
+ const hashAlgOid = bytesToOid(algIdChildren[0].value);
207
+ const hashNode = children[2];
208
+ if (hashNode.tag !== 4) {
209
+ throw new SignaturePolicyError(`Expected OCTET STRING at child[2], got tag 0x${hashNode.tag.toString(16)}`);
210
+ }
211
+ cachedPolicyData = {
212
+ hashAlgOid,
213
+ policyHash: hashNode.value
214
+ };
215
+ return cachedPolicyData;
216
+ }
217
+ async function buildSignaturePolicy() {
218
+ const { hashAlgOid, policyHash } = await downloadAndParsePolicyDocument();
219
+ const hashAlgId = sequence(oid(hashAlgOid));
220
+ const sigPolicyHash = sequence(hashAlgId, octetString(policyHash));
221
+ const sigPolicyQualifiers = sequence(sequence(oid(SPQ_ETS_URI_OID), ia5String(POLICY_CONFIG.URL)));
222
+ const signaturePolicyId = sequence(oid(POLICY_CONFIG.OID), sigPolicyHash, sigPolicyQualifiers);
223
+ return encodeDer(signaturePolicyId);
224
+ }
225
+ var ICP_BRASIL_OIDS = {
226
+ signingCertificateV2: SIGNING_CERTIFICATE_V2_OID,
227
+ signaturePolicy: SIGNATURE_POLICY_OID
228
+ };
229
+
230
+ class SignaturePolicyError extends Error {
231
+ constructor(message) {
232
+ super(message);
233
+ this.name = "SignaturePolicyError";
234
+ }
235
+ }
236
+
237
+ // src/schemas.ts
238
+ import { z } from "zod";
239
+ var signatureAppearanceSchema = z.object({
240
+ x: z.number(),
241
+ y: z.number(),
242
+ width: z.number().positive(),
243
+ height: z.number().positive(),
244
+ page: z.number().int().min(0).optional(),
245
+ showQrCode: z.boolean().optional(),
246
+ showCertInfo: z.boolean().optional()
247
+ });
248
+ var qrCodeConfigSchema = z.object({
249
+ data: z.string().optional(),
250
+ size: z.number().int().positive().optional()
251
+ });
252
+ var pdfSignOptionsSchema = z.object({
253
+ certificate: z.object({
254
+ p12: z.instanceof(Uint8Array).refine((v) => v.length > 0, {
255
+ message: "P12 data must not be empty"
256
+ }),
257
+ password: z.string(),
258
+ name: z.string().optional()
259
+ }),
260
+ reason: z.string().optional(),
261
+ location: z.string().optional(),
262
+ contactInfo: z.string().optional(),
263
+ policy: z.enum(["pades-ades", "pades-icp-brasil"]).optional(),
264
+ timestamp: z.boolean().optional(),
265
+ tsaUrl: z.string().url().optional(),
266
+ tsaTimeout: z.number().positive().optional(),
267
+ tsaRetries: z.number().int().min(0).optional(),
268
+ tsaFallbackUrls: z.array(z.string().url()).optional(),
269
+ onTimestampError: z.function().args(z.unknown()).returns(z.void()).optional(),
270
+ appearance: z.union([signatureAppearanceSchema, z.literal(false)]).optional(),
271
+ appearances: z.array(signatureAppearanceSchema).optional(),
272
+ qrCode: qrCodeConfigSchema.optional(),
273
+ docMdpPermission: z.union([z.literal(1), z.literal(2), z.literal(3)]).optional()
274
+ });
275
+
270
276
  // src/timestamp.ts
271
277
  import {
272
278
  boolean as asn1Boolean,
@@ -289,17 +295,51 @@ var TIMESTAMP_SERVERS = {
289
295
  CERTISIGN: "http://timestamp.certisign.com.br"
290
296
  };
291
297
  var TIMESTAMP_TOKEN_OID = "1.2.840.113549.1.9.16.2.14";
292
- async function requestTimestamp(dataToTimestamp, tsaUrl, hashAlgorithm = "sha256") {
298
+ async function requestTimestamp(dataToTimestamp, tsaUrl, hashAlgorithm = "sha256", options) {
293
299
  const messageHash = hash3(hashAlgorithm, dataToTimestamp);
294
300
  const timestampReq = buildTimestampRequest(messageHash, hashAlgorithm);
295
- const response = await fetch(tsaUrl, {
296
- method: "POST",
297
- headers: {
298
- "Content-Type": "application/timestamp-query"
299
- },
300
- body: timestampReq,
301
- signal: AbortSignal.timeout(1e4)
302
- });
301
+ const tsaTimeout = options?.tsaTimeout ?? 1e4;
302
+ const tsaRetries = options?.tsaRetries ?? 0;
303
+ const tsaFallbackUrls = options?.tsaFallbackUrls ?? [];
304
+ let lastError;
305
+ for (let attempt = 1;attempt <= 1 + tsaRetries; attempt++) {
306
+ if (attempt > 1) {
307
+ await sleep(2 ** (attempt - 2) * 1000);
308
+ }
309
+ try {
310
+ return await fetchTimestamp(tsaUrl, timestampReq, tsaTimeout);
311
+ } catch (err) {
312
+ lastError = err instanceof Error ? err : new Error(String(err));
313
+ }
314
+ }
315
+ for (const fallbackUrl of tsaFallbackUrls) {
316
+ try {
317
+ return await fetchTimestamp(fallbackUrl, timestampReq, tsaTimeout);
318
+ } catch (err) {
319
+ lastError = err instanceof Error ? err : new Error(String(err));
320
+ }
321
+ }
322
+ const fallbackList = tsaFallbackUrls.length > 0 ? `, fallbacks: [${tsaFallbackUrls.join(", ")}]` : "";
323
+ throw new TimestampError(`TSA request failed: all servers unreachable (primary: ${tsaUrl}${fallbackList}). Last error: ${lastError?.message ?? "unknown"}`);
324
+ }
325
+ function sleep(ms) {
326
+ return new Promise((resolve) => setTimeout(resolve, ms));
327
+ }
328
+ async function fetchTimestamp(url, timestampReq, timeoutMs) {
329
+ let response;
330
+ try {
331
+ response = await fetch(url, {
332
+ method: "POST",
333
+ headers: {
334
+ "Content-Type": "application/timestamp-query"
335
+ },
336
+ body: timestampReq,
337
+ signal: AbortSignal.timeout(timeoutMs)
338
+ });
339
+ } catch (err) {
340
+ const msg = err instanceof Error ? err.message : String(err);
341
+ throw new Error(`TSA server unreachable: ${url} \u2014 ${msg}`);
342
+ }
303
343
  if (!response.ok) {
304
344
  throw new TimestampError(`TSA returned HTTP ${response.status}`);
305
345
  }
@@ -346,12 +386,37 @@ class TimestampError extends Error {
346
386
 
347
387
  // src/sign-pdf.ts
348
388
  async function signPdf(pdf, options) {
389
+ let pdfBytes;
390
+ if (pdf instanceof ReadableStream) {
391
+ const chunks = [];
392
+ const reader = pdf.getReader();
393
+ try {
394
+ while (true) {
395
+ const { done, value } = await reader.read();
396
+ if (done)
397
+ break;
398
+ if (value)
399
+ chunks.push(value);
400
+ }
401
+ } finally {
402
+ reader.releaseLock();
403
+ }
404
+ const totalLength = chunks.reduce((sum, c) => sum + c.length, 0);
405
+ pdfBytes = new Uint8Array(totalLength);
406
+ let offset = 0;
407
+ for (const chunk of chunks) {
408
+ pdfBytes.set(chunk, offset);
409
+ offset += chunk.length;
410
+ }
411
+ } else {
412
+ pdfBytes = pdf;
413
+ }
349
414
  const opts = pdfSignOptionsSchema.parse(options);
350
415
  let certInfo = null;
351
416
  try {
352
417
  certInfo = parseCertificate(Buffer.from(opts.certificate.p12), opts.certificate.password);
353
418
  } catch {}
354
- const doc = loadPdf(pdf);
419
+ const doc = loadPdf(pdfBytes);
355
420
  if (opts.appearance !== false && opts.appearance) {
356
421
  const pageIndex = opts.appearance.page ?? 0;
357
422
  if (pageIndex < 0 || pageIndex >= doc.pageCount) {
@@ -362,7 +427,7 @@ async function signPdf(pdf, options) {
362
427
  reason: opts.reason,
363
428
  location: opts.location,
364
429
  qrCode: opts.qrCode,
365
- pdfData: pdf
430
+ pdfData: pdfBytes
366
431
  });
367
432
  }
368
433
  if (opts.appearances && opts.appearances.length > 0) {
@@ -376,7 +441,7 @@ async function signPdf(pdf, options) {
376
441
  reason: opts.reason,
377
442
  location: opts.location,
378
443
  qrCode: opts.qrCode,
379
- pdfData: pdf
444
+ pdfData: pdfBytes
380
445
  });
381
446
  }
382
447
  }
@@ -420,8 +485,14 @@ async function signPdf(pdf, options) {
420
485
  });
421
486
  if (opts.timestamp && opts.tsaUrl) {
422
487
  try {
423
- const tsToken = await requestTimestamp(signedData, opts.tsaUrl);
424
- } catch {}
488
+ const tsToken = await requestTimestamp(signedData, opts.tsaUrl, "sha256", {
489
+ tsaTimeout: opts.tsaTimeout,
490
+ tsaRetries: opts.tsaRetries,
491
+ tsaFallbackUrls: opts.tsaFallbackUrls
492
+ });
493
+ } catch (err) {
494
+ opts.onTimestampError?.(err);
495
+ }
425
496
  }
426
497
  return embedSignature(pdfWithPlaceholder, signedData);
427
498
  }
@@ -432,7 +503,57 @@ class PdfSignError extends Error {
432
503
  this.name = "PdfSignError";
433
504
  }
434
505
  }
506
+
507
+ // src/batch.ts
508
+ async function* signPdfBatch(files, options) {
509
+ let errorCount = 0;
510
+ let processedCount = 0;
511
+ for (let i = 0;i < files.length; i++) {
512
+ const file = files[i];
513
+ if (!file)
514
+ continue;
515
+ processedCount++;
516
+ yield { type: "file_start", fileIndex: i, filename: file.filename };
517
+ try {
518
+ const mergedOptions = { ...options, ...file.options };
519
+ const signed = await signPdf(file.pdf, mergedOptions);
520
+ yield { type: "file_complete", fileIndex: i, filename: file.filename, signed };
521
+ } catch (err) {
522
+ errorCount++;
523
+ yield {
524
+ type: "file_error",
525
+ fileIndex: i,
526
+ filename: file.filename,
527
+ error: err instanceof Error ? err.message : String(err)
528
+ };
529
+ }
530
+ await new Promise((resolve) => setTimeout(resolve, 0));
531
+ }
532
+ yield { type: "batch_complete", totalFiles: processedCount, errorCount };
533
+ }
534
+ async function signPdfBatchToArray(files, options) {
535
+ const results = files.map((f) => ({ filename: f.filename }));
536
+ for await (const event of signPdfBatch(files, options)) {
537
+ switch (event.type) {
538
+ case "file_complete": {
539
+ const r = results[event.fileIndex];
540
+ if (r)
541
+ r.signed = event.signed;
542
+ break;
543
+ }
544
+ case "file_error": {
545
+ const r = results[event.fileIndex];
546
+ if (r)
547
+ r.error = event.error;
548
+ break;
549
+ }
550
+ }
551
+ }
552
+ return results;
553
+ }
435
554
  export {
555
+ signPdfBatchToArray,
556
+ signPdfBatch,
436
557
  signPdf,
437
558
  requestTimestamp,
438
559
  pdfSignOptionsSchema,
@@ -447,4 +568,4 @@ export {
447
568
  ICP_BRASIL_OIDS
448
569
  };
449
570
 
450
- //# debugId=847A450B084A9AAE64756E2164756E21
571
+ //# debugId=AA843AB2650A666564756E2164756E21
package/dist/index.js.map CHANGED
@@ -1,14 +1,15 @@
1
1
  {
2
2
  "version": 3,
3
- "sources": ["../src/icp-brasil.ts", "../src/schemas.ts", "../src/sign-pdf.ts", "../src/appearance.ts", "../src/timestamp.ts"],
3
+ "sources": ["../src/sign-pdf.ts", "../src/appearance.ts", "../src/icp-brasil.ts", "../src/schemas.ts", "../src/timestamp.ts", "../src/batch.ts"],
4
4
  "sourcesContent": [
5
- "/**\n * ICP-Brasil Attributes for PAdES Signatures\n *\n * Implements the id-aa-signingCertificateV2 (RFC 5035) and\n * id-aa-ets-sigPolicyId attributes required by ICP-Brasil.\n *\n * Uses @f-o-t/asn1 for ASN.1 construction and @f-o-t/crypto for hashing.\n */\n\nimport {\n type Asn1Node,\n contextTag,\n decodeDer,\n encodeDer,\n ia5String,\n nullValue,\n octetString,\n oid,\n sequence,\n} from \"@f-o-t/asn1\";\nimport { hash } from \"@f-o-t/crypto\";\n\n// ---------------------------------------------------------------------------\n// Constants\n// ---------------------------------------------------------------------------\n\n/** SHA-256 Algorithm OID */\nconst SHA256_OID = \"2.16.840.1.101.3.4.2.1\";\n\n/** id-aa-signingCertificateV2 OID (RFC 5035) */\nconst SIGNING_CERTIFICATE_V2_OID = \"1.2.840.113549.1.9.16.2.47\";\n\n/** id-aa-ets-sigPolicyId OID */\nconst SIGNATURE_POLICY_OID = \"1.2.840.113549.1.9.16.2.15\";\n\n/** ICP-Brasil PAdES Policy (PA_PAdES_AD_RB_v1_1) */\nconst POLICY_CONFIG = {\n OID: \"2.16.76.1.7.1.11.1.1\",\n URL: \"http://politicas.icpbrasil.gov.br/PA_PAdES_AD_RB_v1_1.der\",\n} as const;\n\n/** id-spq-ets-uri OID */\nconst SPQ_ETS_URI_OID = \"1.2.840.113549.1.9.16.5.1\";\n\n// ---------------------------------------------------------------------------\n// Cached policy data\n// ---------------------------------------------------------------------------\n\nlet cachedPolicyData: {\n hashAlgOid: string;\n policyHash: Uint8Array;\n} | null = null;\n\n/**\n * Clear the cached signature policy data.\n * Useful for testing or forcing a re-download.\n */\nexport function clearPolicyCache(): void {\n cachedPolicyData = null;\n}\n\n// ---------------------------------------------------------------------------\n// Signing Certificate V2\n// ---------------------------------------------------------------------------\n\n/**\n * Build the id-aa-signingCertificateV2 attribute value (DER-encoded).\n *\n * This attribute links the signature to the specific certificate used to\n * create it, preventing substitution attacks.\n *\n * ASN.1 structure (RFC 5035):\n *\n * SigningCertificateV2 ::= SEQUENCE {\n * certs SEQUENCE OF ESSCertIDv2\n * }\n *\n * ESSCertIDv2 ::= SEQUENCE {\n * hashAlgorithm AlgorithmIdentifier DEFAULT {algorithm id-sha256},\n * certHash Hash,\n * issuerSerial IssuerSerial OPTIONAL\n * }\n *\n * IssuerSerial ::= SEQUENCE {\n * issuer GeneralNames,\n * serialNumber CertificateSerialNumber\n * }\n *\n * @param certDer - DER-encoded X.509 certificate\n * @returns DER-encoded SigningCertificateV2 value\n */\nexport function buildSigningCertificateV2(certDer: Uint8Array): Uint8Array {\n // 1. Hash the DER certificate with SHA-256\n const certHash = hash(\"sha256\", certDer);\n\n // 2. Build AlgorithmIdentifier for SHA-256\n const hashAlgId = sequence(oid(SHA256_OID), nullValue());\n\n // 3. Extract issuer and serial number from the certificate\n const cert = decodeDer(certDer);\n const tbsCert = (cert.value as Asn1Node[])[0]!;\n const tbs = tbsCert.value as Asn1Node[];\n\n // version is [0] EXPLICIT, so tbs[0] may be version context tag\n let idx = 0;\n if (tbs[0]!.class === \"context\" && tbs[0]!.tag === 0) {\n idx = 1;\n }\n\n const serialNumber = tbs[idx]!; // INTEGER\n const issuerName = tbs[idx + 2]!; // Name SEQUENCE\n\n // 4. Build IssuerSerial\n // IssuerSerial ::= SEQUENCE { issuer GeneralNames, serialNumber INTEGER }\n // GeneralNames ::= SEQUENCE OF GeneralName\n // GeneralName ::= directoryName [4] Name\n const generalName = contextTag(4, [issuerName]);\n const generalNames = sequence(generalName);\n const issuerSerial = sequence(generalNames, serialNumber);\n\n // 5. Build ESSCertIDv2\n const essCertIdV2 = sequence(hashAlgId, octetString(certHash), issuerSerial);\n\n // 6. Build SigningCertificateV2\n const signingCertV2 = sequence(\n // certs SEQUENCE OF ESSCertIDv2\n sequence(essCertIdV2),\n );\n\n return encodeDer(signingCertV2);\n}\n\n// ---------------------------------------------------------------------------\n// Signature Policy\n// ---------------------------------------------------------------------------\n\n/**\n * Download and parse the ICP-Brasil signature policy DER file.\n * Extracts the embedded signPolicyHash from the ASN.1 structure.\n */\nasync function downloadAndParsePolicyDocument(): Promise<{\n hashAlgOid: string;\n policyHash: Uint8Array;\n}> {\n if (cachedPolicyData) {\n return cachedPolicyData;\n }\n\n const response = await fetch(POLICY_CONFIG.URL);\n\n if (!response.ok) {\n throw new SignaturePolicyError(\n `Failed to download signature policy: HTTP ${response.status}`,\n );\n }\n\n const arrayBuffer = await response.arrayBuffer();\n const data = new Uint8Array(arrayBuffer);\n\n if (data.length === 0 || data[0] !== 0x30) {\n throw new SignaturePolicyError(\"Invalid DER format in policy document\");\n }\n\n // Parse the ASN.1 structure:\n // SignaturePolicy ::= SEQUENCE {\n // signPolicyHashAlg AlgorithmIdentifier,\n // signPolicyInfo SignaturePolicyInfo,\n // signPolicyHash OCTET STRING\n // }\n const asn1 = decodeDer(data);\n const children = asn1.value as Asn1Node[];\n\n if (!Array.isArray(children) || children.length < 3) {\n throw new SignaturePolicyError(\n `Unexpected policy structure: expected 3+ children, got ${children?.length}`,\n );\n }\n\n // Child[0] = AlgorithmIdentifier\n const algIdChildren = children[0]!.value as Asn1Node[];\n if (!Array.isArray(algIdChildren) || algIdChildren.length === 0) {\n throw new SignaturePolicyError(\"Invalid AlgorithmIdentifier in policy\");\n }\n\n const { bytesToOid } = await import(\"@f-o-t/asn1\");\n const hashAlgOid = bytesToOid(algIdChildren[0]!.value as Uint8Array);\n\n // Child[2] = signPolicyHash (OCTET STRING)\n const hashNode = children[2]!;\n if (hashNode.tag !== 0x04) {\n throw new SignaturePolicyError(\n `Expected OCTET STRING at child[2], got tag 0x${hashNode.tag.toString(16)}`,\n );\n }\n\n cachedPolicyData = {\n hashAlgOid,\n policyHash: hashNode.value as Uint8Array,\n };\n\n return cachedPolicyData;\n}\n\n/**\n * Build the id-aa-ets-sigPolicyId attribute value (DER-encoded).\n *\n * Downloads the ICP-Brasil PAdES signature policy and extracts the\n * embedded signPolicyHash to build the attribute.\n *\n * @returns DER-encoded SignaturePolicyIdentifier value\n */\nexport async function buildSignaturePolicy(): Promise<Uint8Array> {\n const { hashAlgOid, policyHash } = await downloadAndParsePolicyDocument();\n\n // AlgorithmIdentifier for hash (no NULL — matches policy encoding)\n const hashAlgId = sequence(oid(hashAlgOid));\n\n // SigPolicyHash (OtherHashAlgAndValue)\n const sigPolicyHash = sequence(hashAlgId, octetString(policyHash));\n\n // SigPolicyQualifiers with policy URL\n const sigPolicyQualifiers = sequence(\n sequence(\n // id-spq-ets-uri\n oid(SPQ_ETS_URI_OID),\n // Policy URL as IA5String\n ia5String(POLICY_CONFIG.URL),\n ),\n );\n\n // SignaturePolicyId\n const signaturePolicyId = sequence(\n // sigPolicyId (policy OID)\n oid(POLICY_CONFIG.OID),\n // sigPolicyHash\n sigPolicyHash,\n // sigPolicyQualifiers\n sigPolicyQualifiers,\n );\n\n return encodeDer(signaturePolicyId);\n}\n\n/**\n * Attribute OID constants for external use\n */\nexport const ICP_BRASIL_OIDS = {\n signingCertificateV2: SIGNING_CERTIFICATE_V2_OID,\n signaturePolicy: SIGNATURE_POLICY_OID,\n} as const;\n\n// ---------------------------------------------------------------------------\n// Errors\n// ---------------------------------------------------------------------------\n\nexport class SignaturePolicyError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"SignaturePolicyError\";\n }\n}\n",
6
- "/**\n * Zod schemas for input validation\n */\n\nimport { z } from \"zod\";\n\nconst signatureAppearanceSchema = z.object({\n x: z.number(),\n y: z.number(),\n width: z.number().positive(),\n height: z.number().positive(),\n page: z.number().int().min(0).optional(),\n showQrCode: z.boolean().optional(),\n showCertInfo: z.boolean().optional(),\n});\n\nconst qrCodeConfigSchema = z.object({\n data: z.string().optional(),\n size: z.number().int().positive().optional(),\n});\n\nexport const pdfSignOptionsSchema = z.object({\n certificate: z.object({\n p12: z.instanceof(Uint8Array).refine((v) => v.length > 0, {\n message: \"P12 data must not be empty\",\n }),\n password: z.string(),\n name: z.string().optional(),\n }),\n reason: z.string().optional(),\n location: z.string().optional(),\n contactInfo: z.string().optional(),\n policy: z.enum([\"pades-ades\", \"pades-icp-brasil\"]).optional(),\n timestamp: z.boolean().optional(),\n tsaUrl: z.string().url().optional(),\n appearance: z\n .union([signatureAppearanceSchema, z.literal(false)])\n .optional(),\n appearances: z.array(signatureAppearanceSchema).optional(),\n qrCode: qrCodeConfigSchema.optional(),\n docMdpPermission: z\n .union([z.literal(1), z.literal(2), z.literal(3)])\n .optional(),\n});\n",
7
- "/**\n * PDF Signing — Main Entry Point\n *\n * Signs a PDF document using PAdES format with optional ICP-Brasil compliance.\n *\n * Flow:\n * 1. Parse certificate for display info\n * 2. Load PDF and draw visual appearance\n * 3. Save PDF with signature placeholder\n * 4. Find byte range and extract bytes to sign\n * 5. Build CMS/PKCS#7 SignedData with ICP-Brasil attributes\n * 6. Embed signature into PDF\n */\n\nimport type { CmsAttribute } from \"@f-o-t/crypto\";\nimport { createSignedData, parsePkcs12 } from \"@f-o-t/crypto\";\nimport type { CertificateInfo } from \"@f-o-t/digital-certificate\";\nimport { parseCertificate } from \"@f-o-t/digital-certificate\";\nimport {\n embedSignature,\n extractBytesToSign,\n findByteRange,\n loadPdf,\n} from \"@f-o-t/pdf/plugins/editing\";\nimport { drawSignatureAppearance } from \"./appearance.ts\";\nimport {\n buildSignaturePolicy,\n buildSigningCertificateV2,\n ICP_BRASIL_OIDS,\n} from \"./icp-brasil.ts\";\nimport { pdfSignOptionsSchema } from \"./schemas.ts\";\nimport { requestTimestamp } from \"./timestamp.ts\";\nimport type { PdfSignOptions } from \"./types.ts\";\n\n/**\n * Sign a PDF document with a digital certificate.\n *\n * Supports PAdES-BES and PAdES with ICP-Brasil compliance\n * (signing-certificate-v2 and signature-policy attributes).\n *\n * @param pdf - The PDF document as a Uint8Array\n * @param options - Signing options\n * @returns The signed PDF as a Uint8Array\n *\n * @example\n * ```ts\n * const signedPdf = await signPdf(pdfBytes, {\n * certificate: { p12, password: \"secret\" },\n * reason: \"Document approval\",\n * location: \"Corporate Office\",\n * policy: \"pades-icp-brasil\",\n * });\n * ```\n */\nexport async function signPdf(\n pdf: Uint8Array,\n options: PdfSignOptions,\n): Promise<Uint8Array> {\n // Validate input\n const opts = pdfSignOptionsSchema.parse(options);\n\n // 1. Parse certificate for display info (uses OpenSSL, needs Buffer)\n let certInfo: CertificateInfo | null = null;\n try {\n certInfo = parseCertificate(\n Buffer.from(opts.certificate.p12),\n opts.certificate.password,\n );\n } catch {\n // If parsing fails, continue without cert info for display\n }\n\n // 2. Load PDF via editing plugin\n const doc = loadPdf(pdf);\n\n // 3. Draw visual signature appearance if requested\n if (opts.appearance !== false && opts.appearance) {\n const pageIndex = opts.appearance.page ?? 0;\n\n if (pageIndex < 0 || pageIndex >= doc.pageCount) {\n throw new PdfSignError(\n `Invalid page index: ${pageIndex}. PDF has ${doc.pageCount} pages.`,\n );\n }\n\n const page = doc.getPage(pageIndex);\n\n drawSignatureAppearance(doc, page, opts.appearance, certInfo, {\n reason: opts.reason,\n location: opts.location,\n qrCode: opts.qrCode,\n pdfData: pdf,\n });\n }\n\n // 3b. Draw multiple visual signature appearances if provided\n if (opts.appearances && opts.appearances.length > 0) {\n for (const app of opts.appearances) {\n const pageIndex = app.page ?? 0;\n\n if (pageIndex < 0 || pageIndex >= doc.pageCount) {\n throw new PdfSignError(\n `Invalid page index ${pageIndex} in appearances. PDF has ${doc.pageCount} pages.`,\n );\n }\n\n const page = doc.getPage(pageIndex);\n\n drawSignatureAppearance(doc, page, app, certInfo, {\n reason: opts.reason,\n location: opts.location,\n qrCode: opts.qrCode,\n pdfData: pdf,\n });\n }\n }\n\n // 4. Save with signature placeholder\n const signerName =\n certInfo?.subject.commonName ||\n opts.certificate.name ||\n \"Digital Signature\";\n\n const { pdf: pdfWithPlaceholder } = doc.saveWithPlaceholder({\n reason: opts.reason || \"Digitally signed\",\n name: signerName,\n location: opts.location,\n contactInfo: opts.contactInfo,\n signatureLength: 16384,\n docMdpPermission: opts.docMdpPermission ?? 2,\n });\n\n // 5. Find byte range and extract bytes to sign\n const { byteRange } = findByteRange(pdfWithPlaceholder);\n const bytesToSign = extractBytesToSign(pdfWithPlaceholder, byteRange);\n\n // 6. Parse PKCS#12 for cryptographic material\n const { certificate, privateKey, chain } = parsePkcs12(\n opts.certificate.p12,\n opts.certificate.password,\n );\n\n // 7. Build ICP-Brasil authenticated attributes if needed\n const authenticatedAttributes: CmsAttribute[] = [];\n\n if (opts.policy === \"pades-icp-brasil\") {\n // signing-certificate-v2\n const sigCertV2 = buildSigningCertificateV2(certificate);\n authenticatedAttributes.push({\n oid: ICP_BRASIL_OIDS.signingCertificateV2,\n values: [sigCertV2],\n });\n\n // signature-policy\n try {\n const sigPolicy = await buildSignaturePolicy();\n authenticatedAttributes.push({\n oid: ICP_BRASIL_OIDS.signaturePolicy,\n values: [sigPolicy],\n });\n } catch {\n // Policy download failure is non-fatal\n // The signature will still be valid PAdES-BES\n }\n }\n\n // 8. Build unauthenticated attributes\n const unauthenticatedAttributes: CmsAttribute[] = [];\n\n // 9. Create CMS/PKCS#7 SignedData\n const signedData = createSignedData({\n content: bytesToSign,\n certificate,\n privateKey,\n chain,\n hashAlgorithm: \"sha256\",\n authenticatedAttributes:\n authenticatedAttributes.length > 0\n ? authenticatedAttributes\n : undefined,\n unauthenticatedAttributes:\n unauthenticatedAttributes.length > 0\n ? unauthenticatedAttributes\n : undefined,\n detached: true,\n });\n\n // 10. Optionally request timestamp\n if (opts.timestamp && opts.tsaUrl) {\n try {\n const tsToken = await requestTimestamp(signedData, opts.tsaUrl);\n // Note: Adding the timestamp as an unauthenticated attribute\n // would require re-building the CMS structure. For now, we log\n // that timestamp was received. A future version will embed it.\n // TODO: Rebuild CMS with timestamp token as unauthenticated attribute\n void tsToken;\n } catch {\n // Timestamp failure is non-fatal\n }\n }\n\n // 11. Embed signature into PDF\n return embedSignature(pdfWithPlaceholder, signedData);\n}\n\n// ---------------------------------------------------------------------------\n// Errors\n// ---------------------------------------------------------------------------\n\nexport class PdfSignError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"PdfSignError\";\n }\n}\n",
5
+ "/**\n * PDF Signing Main Entry Point\n *\n * Signs a PDF document using PAdES format with optional ICP-Brasil compliance.\n *\n * Flow:\n * 1. Parse certificate for display info\n * 2. Load PDF and draw visual appearance\n * 3. Save PDF with signature placeholder\n * 4. Find byte range and extract bytes to sign\n * 5. Build CMS/PKCS#7 SignedData with ICP-Brasil attributes\n * 6. Embed signature into PDF\n */\n\nimport type { CmsAttribute } from \"@f-o-t/crypto\";\nimport { createSignedData, parsePkcs12 } from \"@f-o-t/crypto\";\nimport type { CertificateInfo } from \"@f-o-t/digital-certificate\";\nimport { parseCertificate } from \"@f-o-t/digital-certificate\";\nimport {\n embedSignature,\n extractBytesToSign,\n findByteRange,\n loadPdf,\n} from \"@f-o-t/pdf/plugins/editing\";\nimport { drawSignatureAppearance } from \"./appearance.ts\";\nimport {\n buildSignaturePolicy,\n buildSigningCertificateV2,\n ICP_BRASIL_OIDS,\n} from \"./icp-brasil.ts\";\nimport { pdfSignOptionsSchema } from \"./schemas.ts\";\nimport { requestTimestamp } from \"./timestamp.ts\";\nimport type { PdfSignOptions } from \"./types.ts\";\n\n/**\n * Sign a PDF document with a digital certificate.\n *\n * Supports PAdES-BES and PAdES with ICP-Brasil compliance\n * (signing-certificate-v2 and signature-policy attributes).\n *\n * @param pdf - The PDF document as a Uint8Array or ReadableStream<Uint8Array>\n * @param options - Signing options\n * @returns The signed PDF as a Uint8Array\n *\n * @example\n * ```ts\n * const signedPdf = await signPdf(pdfBytes, {\n * certificate: { p12, password: \"secret\" },\n * reason: \"Document approval\",\n * location: \"Corporate Office\",\n * policy: \"pades-icp-brasil\",\n * });\n * ```\n */\nexport async function signPdf(\n pdf: Uint8Array | ReadableStream<Uint8Array>,\n options: PdfSignOptions,\n): Promise<Uint8Array> {\n // Accumulate ReadableStream into Uint8Array if needed\n let pdfBytes: Uint8Array;\n if (pdf instanceof ReadableStream) {\n const chunks: Uint8Array[] = [];\n const reader = pdf.getReader();\n try {\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n if (value) chunks.push(value);\n }\n } finally {\n reader.releaseLock();\n }\n const totalLength = chunks.reduce((sum, c) => sum + c.length, 0);\n pdfBytes = new Uint8Array(totalLength);\n let offset = 0;\n for (const chunk of chunks) {\n pdfBytes.set(chunk, offset);\n offset += chunk.length;\n }\n } else {\n pdfBytes = pdf;\n }\n\n // Validate input\n const opts = pdfSignOptionsSchema.parse(options);\n\n // 1. Parse certificate for display info (uses OpenSSL, needs Buffer)\n let certInfo: CertificateInfo | null = null;\n try {\n certInfo = parseCertificate(\n Buffer.from(opts.certificate.p12),\n opts.certificate.password,\n );\n } catch {\n // If parsing fails, continue without cert info for display\n }\n\n // 2. Load PDF via editing plugin\n const doc = loadPdf(pdfBytes);\n\n // 3. Draw visual signature appearance if requested\n if (opts.appearance !== false && opts.appearance) {\n const pageIndex = opts.appearance.page ?? 0;\n\n if (pageIndex < 0 || pageIndex >= doc.pageCount) {\n throw new PdfSignError(\n `Invalid page index: ${pageIndex}. PDF has ${doc.pageCount} pages.`,\n );\n }\n\n const page = doc.getPage(pageIndex);\n\n drawSignatureAppearance(doc, page, opts.appearance, certInfo, {\n reason: opts.reason,\n location: opts.location,\n qrCode: opts.qrCode,\n pdfData: pdfBytes,\n });\n }\n\n // 3b. Draw multiple visual signature appearances if provided\n if (opts.appearances && opts.appearances.length > 0) {\n for (const app of opts.appearances) {\n const pageIndex = app.page ?? 0;\n\n if (pageIndex < 0 || pageIndex >= doc.pageCount) {\n throw new PdfSignError(\n `Invalid page index ${pageIndex} in appearances. PDF has ${doc.pageCount} pages.`,\n );\n }\n\n const page = doc.getPage(pageIndex);\n\n drawSignatureAppearance(doc, page, app, certInfo, {\n reason: opts.reason,\n location: opts.location,\n qrCode: opts.qrCode,\n pdfData: pdfBytes,\n });\n }\n }\n\n // 4. Save with signature placeholder\n const signerName =\n certInfo?.subject.commonName ||\n opts.certificate.name ||\n \"Digital Signature\";\n\n const { pdf: pdfWithPlaceholder } = doc.saveWithPlaceholder({\n reason: opts.reason || \"Digitally signed\",\n name: signerName,\n location: opts.location,\n contactInfo: opts.contactInfo,\n signatureLength: 16384,\n docMdpPermission: opts.docMdpPermission ?? 2,\n });\n\n // 5. Find byte range and extract bytes to sign\n const { byteRange } = findByteRange(pdfWithPlaceholder);\n const bytesToSign = extractBytesToSign(pdfWithPlaceholder, byteRange);\n\n // 6. Parse PKCS#12 for cryptographic material\n const { certificate, privateKey, chain } = parsePkcs12(\n opts.certificate.p12,\n opts.certificate.password,\n );\n\n // 7. Build ICP-Brasil authenticated attributes if needed\n const authenticatedAttributes: CmsAttribute[] = [];\n\n if (opts.policy === \"pades-icp-brasil\") {\n // signing-certificate-v2\n const sigCertV2 = buildSigningCertificateV2(certificate);\n authenticatedAttributes.push({\n oid: ICP_BRASIL_OIDS.signingCertificateV2,\n values: [sigCertV2],\n });\n\n // signature-policy\n try {\n const sigPolicy = await buildSignaturePolicy();\n authenticatedAttributes.push({\n oid: ICP_BRASIL_OIDS.signaturePolicy,\n values: [sigPolicy],\n });\n } catch {\n // Policy download failure is non-fatal\n // The signature will still be valid PAdES-BES\n }\n }\n\n // 8. Build unauthenticated attributes\n const unauthenticatedAttributes: CmsAttribute[] = [];\n\n // 9. Create CMS/PKCS#7 SignedData\n const signedData = createSignedData({\n content: bytesToSign,\n certificate,\n privateKey,\n chain,\n hashAlgorithm: \"sha256\",\n authenticatedAttributes:\n authenticatedAttributes.length > 0\n ? authenticatedAttributes\n : undefined,\n unauthenticatedAttributes:\n unauthenticatedAttributes.length > 0\n ? unauthenticatedAttributes\n : undefined,\n detached: true,\n });\n\n // 10. Optionally request timestamp\n if (opts.timestamp && opts.tsaUrl) {\n try {\n const tsToken = await requestTimestamp(signedData, opts.tsaUrl, \"sha256\", {\n tsaTimeout: opts.tsaTimeout,\n tsaRetries: opts.tsaRetries,\n tsaFallbackUrls: opts.tsaFallbackUrls,\n });\n // Note: Adding the timestamp as an unauthenticated attribute\n // would require re-building the CMS structure. For now, we log\n // that timestamp was received. A future version will embed it.\n // TODO: Rebuild CMS with timestamp token as unauthenticated attribute\n void tsToken;\n } catch (err) {\n // Timestamp failure is non-fatal\n opts.onTimestampError?.(err);\n }\n }\n\n // 11. Embed signature into PDF\n return embedSignature(pdfWithPlaceholder, signedData);\n}\n\n// ---------------------------------------------------------------------------\n// Errors\n// ---------------------------------------------------------------------------\n\nexport class PdfSignError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"PdfSignError\";\n }\n}\n",
8
6
  "/**\n * Visual Signature Appearance\n *\n * Draws certificate information and QR code on the PDF page\n * for visible digital signatures.\n */\n\nimport { hash } from \"@f-o-t/crypto\";\nimport type { CertificateInfo } from \"@f-o-t/digital-certificate\";\nimport type { PdfDocument, PdfPage } from \"@f-o-t/pdf/plugins/editing\";\nimport { generateQrCode } from \"@f-o-t/qrcode\";\nimport type { QrCodeConfig, SignatureAppearance } from \"./types.ts\";\n\n/**\n * Draw the visual signature appearance on a PDF page.\n *\n * Includes optional QR code and certificate information text.\n */\nexport function drawSignatureAppearance(\n doc: PdfDocument,\n page: PdfPage,\n appearance: SignatureAppearance,\n certInfo: CertificateInfo | null,\n options: {\n reason?: string;\n location?: string;\n qrCode?: QrCodeConfig;\n pdfData: Uint8Array;\n },\n): void {\n const { x, width, height } = appearance;\n const showQrCode = appearance.showQrCode !== false;\n const showCertInfo = appearance.showCertInfo !== false;\n\n // Convert from top-left origin (user-facing) to PDF bottom-left origin.\n // Users specify y as distance from the top of the page, but PDF coordinates\n // have y=0 at the bottom.\n const y = page.height - appearance.y - height;\n\n let qrSize = 0;\n\n // Draw QR code if requested (enabled by default)\n if (showQrCode) {\n const qrData =\n options.qrCode?.data ||\n createVerificationData(certInfo, options.pdfData);\n\n const qrPng = generateQrCode(qrData, {\n size: options.qrCode?.size || 100,\n });\n\n const qrImage = doc.embedPng(qrPng);\n qrSize = Math.min(100, height - 20);\n\n page.drawImage(qrImage, {\n x: x + 10,\n y: y + 10,\n width: qrSize,\n height: qrSize,\n });\n }\n\n // Draw certificate info text\n if (showCertInfo) {\n drawCertInfo(page, certInfo, {\n x,\n y,\n width,\n height,\n qrOffset: qrSize > 0 ? qrSize + 20 : 10,\n reason: options.reason,\n location: options.location,\n });\n }\n}\n\n/**\n * Draw certificate information text on the page\n */\nfunction drawCertInfo(\n page: PdfPage,\n certInfo: CertificateInfo | null,\n opts: {\n x: number;\n y: number;\n width: number;\n height: number;\n qrOffset: number;\n reason?: string;\n location?: string;\n },\n): void {\n const textX = opts.x + opts.qrOffset;\n let textY = opts.y + opts.height - 20;\n const fontSize = 10;\n const lineHeight = 14;\n\n // Header\n page.drawText(\"ASSINADO DIGITALMENTE\", {\n x: textX,\n y: textY,\n size: 12,\n });\n textY -= lineHeight * 1.5;\n\n if (certInfo) {\n // Signer name\n const signerName = certInfo.subject.commonName || \"N/A\";\n page.drawText(`Assinado por: ${signerName}`, {\n x: textX,\n y: textY,\n size: fontSize,\n });\n textY -= lineHeight;\n\n // CNPJ or CPF\n if (certInfo.brazilian.cnpj) {\n const cnpj = formatCnpj(certInfo.brazilian.cnpj);\n page.drawText(`CNPJ: ${cnpj}`, {\n x: textX,\n y: textY,\n size: fontSize,\n });\n textY -= lineHeight;\n } else if (certInfo.brazilian.cpf) {\n const cpf = formatCpf(certInfo.brazilian.cpf);\n page.drawText(`CPF: ${cpf}`, {\n x: textX,\n y: textY,\n size: fontSize,\n });\n textY -= lineHeight;\n }\n\n // Date and time\n const now = new Date();\n const dateStr = now.toLocaleDateString(\"pt-BR\");\n const timeStr = now.toLocaleTimeString(\"pt-BR\");\n page.drawText(`Data: ${dateStr} ${timeStr}`, {\n x: textX,\n y: textY,\n size: fontSize,\n });\n textY -= lineHeight;\n\n // Location\n if (opts.location) {\n page.drawText(`Local: ${opts.location}`, {\n x: textX,\n y: textY,\n size: fontSize - 1,\n });\n }\n } else {\n // Fallback if cert info not available\n page.drawText(`Signed: ${opts.reason || \"Digital Signature\"}`, {\n x: textX,\n y: textY,\n size: fontSize,\n });\n textY -= lineHeight;\n\n if (opts.location) {\n page.drawText(`Location: ${opts.location}`, {\n x: textX,\n y: textY,\n size: fontSize,\n });\n }\n }\n}\n\n/**\n * Generate verification data for the QR code\n */\nfunction createVerificationData(\n certInfo: CertificateInfo | null,\n pdfData: Uint8Array,\n): string {\n const documentHash = toHex(hash(\"sha256\", pdfData));\n const timestamp = new Date().toISOString();\n\n if (certInfo) {\n const certFingerprint = certInfo.fingerprint;\n return (\n `https://validar.iti.gov.br/?` +\n `doc=${documentHash.substring(0, 16)}&` +\n `cert=${certFingerprint.substring(0, 16)}&` +\n `time=${encodeURIComponent(timestamp)}`\n );\n }\n\n return `https://validar.iti.gov.br/?doc=${documentHash.substring(0, 16)}&time=${encodeURIComponent(timestamp)}`;\n}\n\n/**\n * Format a CNPJ number with punctuation\n */\nfunction formatCnpj(cnpj: string): string {\n return cnpj.replace(/(\\d{2})(\\d{3})(\\d{3})(\\d{4})(\\d{2})/, \"$1.$2.$3/$4-$5\");\n}\n\n/**\n * Format a CPF number with punctuation\n */\nfunction formatCpf(cpf: string): string {\n return cpf.replace(/(\\d{3})(\\d{3})(\\d{3})(\\d{2})/, \"$1.$2.$3-$4\");\n}\n\n/**\n * Convert bytes to hex string\n */\nfunction toHex(data: Uint8Array): string {\n const chars: string[] = [];\n for (let i = 0; i < data.length; i++) {\n chars.push(data[i]!.toString(16).padStart(2, \"0\"));\n }\n return chars.join(\"\");\n}\n",
9
- "/**\n * RFC 3161 Timestamp Client\n *\n * Requests trusted timestamps from TSA servers using native fetch.\n * Builds the TimeStampReq using @f-o-t/asn1 instead of forge.\n */\n\nimport {\n type Asn1Node,\n boolean as asn1Boolean,\n decodeDer,\n encodeDer,\n integer,\n octetString,\n oid,\n sequence,\n} from \"@f-o-t/asn1\";\nimport { hash } from \"@f-o-t/crypto\";\n\n// ---------------------------------------------------------------------------\n// Constants\n// ---------------------------------------------------------------------------\n\n/** Well-known hash algorithm OIDs */\nconst HASH_OIDS: Record<string, string> = {\n sha256: \"2.16.840.1.101.3.4.2.1\",\n sha384: \"2.16.840.1.101.3.4.2.2\",\n sha512: \"2.16.840.1.101.3.4.2.3\",\n};\n\n/** ICP-Brasil Approved Timestamp Servers */\nexport const TIMESTAMP_SERVERS = {\n VALID: \"http://timestamp.valid.com.br/tsa\",\n SAFEWEB: \"http://tsa.safeweb.com.br/tsa/tsa\",\n CERTISIGN: \"http://timestamp.certisign.com.br\",\n} as const;\n\n/** id-smime-aa-timeStampToken OID */\nexport const TIMESTAMP_TOKEN_OID = \"1.2.840.113549.1.9.16.2.14\";\n\n// ---------------------------------------------------------------------------\n// Public API\n// ---------------------------------------------------------------------------\n\n/**\n * Request a timestamp from a TSA server.\n *\n * @param dataToTimestamp - The data to timestamp (usually the signature value)\n * @param tsaUrl - URL of the timestamp server\n * @param hashAlgorithm - Hash algorithm to use (default: \"sha256\")\n * @returns DER-encoded TimeStampToken\n */\nexport async function requestTimestamp(\n dataToTimestamp: Uint8Array,\n tsaUrl: string,\n hashAlgorithm: \"sha256\" | \"sha384\" | \"sha512\" = \"sha256\",\n): Promise<Uint8Array> {\n // 1. Hash the data\n const messageHash = hash(hashAlgorithm, dataToTimestamp);\n\n // 2. Build TimeStampReq\n const timestampReq = buildTimestampRequest(messageHash, hashAlgorithm);\n\n // 3. Send to TSA\n const response = await fetch(tsaUrl, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/timestamp-query\",\n },\n body: timestampReq as unknown as BodyInit,\n signal: AbortSignal.timeout(10000),\n });\n\n if (!response.ok) {\n throw new TimestampError(`TSA returned HTTP ${response.status}`);\n }\n\n const respBuffer = new Uint8Array(await response.arrayBuffer());\n\n // 4. Validate and extract token\n return extractTimestampToken(respBuffer);\n}\n\n// ---------------------------------------------------------------------------\n// Internal\n// ---------------------------------------------------------------------------\n\n/**\n * Build a TimeStampReq (RFC 3161) as DER bytes.\n *\n * TimeStampReq ::= SEQUENCE {\n * version INTEGER { v1(1) },\n * messageImprint MessageImprint,\n * certReq BOOLEAN DEFAULT FALSE\n * }\n *\n * MessageImprint ::= SEQUENCE {\n * hashAlgorithm AlgorithmIdentifier,\n * hashedMessage OCTET STRING\n * }\n */\nfunction buildTimestampRequest(\n messageHash: Uint8Array,\n hashAlgorithm: string,\n): Uint8Array {\n const hashOid = HASH_OIDS[hashAlgorithm];\n if (!hashOid) {\n throw new TimestampError(`Unsupported hash algorithm: ${hashAlgorithm}`);\n }\n\n const timestampReq = sequence(\n // version = 1\n integer(1),\n // messageImprint\n sequence(\n // hashAlgorithm AlgorithmIdentifier\n sequence(oid(hashOid)),\n // hashedMessage OCTET STRING\n octetString(messageHash),\n ),\n // certReq = TRUE (request certificate in response)\n asn1Boolean(true),\n );\n\n return encodeDer(timestampReq);\n}\n\n/**\n * Extract the TimeStampToken from a TimeStampResp.\n *\n * TimeStampResp ::= SEQUENCE {\n * status PKIStatusInfo,\n * timeStampToken TimeStampToken OPTIONAL\n * }\n *\n * PKIStatusInfo ::= SEQUENCE {\n * status PKIStatus, -- INTEGER\n * ...\n * }\n */\nfunction extractTimestampToken(respDer: Uint8Array): Uint8Array {\n let resp: Asn1Node;\n try {\n resp = decodeDer(respDer);\n } catch {\n throw new TimestampError(\"Invalid timestamp response: not valid DER\");\n }\n\n const children = resp.value as Asn1Node[];\n if (!Array.isArray(children) || children.length < 1) {\n throw new TimestampError(\n \"Invalid timestamp response: unexpected structure\",\n );\n }\n\n // Check status\n const statusInfo = children[0]!.value as Asn1Node[];\n const statusBytes = statusInfo[0]!.value as Uint8Array;\n // Status 0 = granted, 1 = grantedWithMods\n const statusValue = statusBytes[statusBytes.length - 1]!;\n if (statusValue !== 0 && statusValue !== 1) {\n throw new TimestampError(\n `Timestamp request rejected with status: ${statusValue}`,\n );\n }\n\n // Extract token (second child)\n if (!children[1]) {\n throw new TimestampError(\"Timestamp response does not contain a token\");\n }\n\n return encodeDer(children[1]);\n}\n\n// ---------------------------------------------------------------------------\n// Errors\n// ---------------------------------------------------------------------------\n\nexport class TimestampError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"TimestampError\";\n }\n}\n"
7
+ "/**\n * ICP-Brasil Attributes for PAdES Signatures\n *\n * Implements the id-aa-signingCertificateV2 (RFC 5035) and\n * id-aa-ets-sigPolicyId attributes required by ICP-Brasil.\n *\n * Uses @f-o-t/asn1 for ASN.1 construction and @f-o-t/crypto for hashing.\n */\n\nimport {\n type Asn1Node,\n contextTag,\n decodeDer,\n encodeDer,\n ia5String,\n nullValue,\n octetString,\n oid,\n sequence,\n} from \"@f-o-t/asn1\";\nimport { hash } from \"@f-o-t/crypto\";\n\n// ---------------------------------------------------------------------------\n// Constants\n// ---------------------------------------------------------------------------\n\n/** SHA-256 Algorithm OID */\nconst SHA256_OID = \"2.16.840.1.101.3.4.2.1\";\n\n/** id-aa-signingCertificateV2 OID (RFC 5035) */\nconst SIGNING_CERTIFICATE_V2_OID = \"1.2.840.113549.1.9.16.2.47\";\n\n/** id-aa-ets-sigPolicyId OID */\nconst SIGNATURE_POLICY_OID = \"1.2.840.113549.1.9.16.2.15\";\n\n/** ICP-Brasil PAdES Policy (PA_PAdES_AD_RB_v1_1) */\nconst POLICY_CONFIG = {\n OID: \"2.16.76.1.7.1.11.1.1\",\n URL: \"http://politicas.icpbrasil.gov.br/PA_PAdES_AD_RB_v1_1.der\",\n} as const;\n\n/** id-spq-ets-uri OID */\nconst SPQ_ETS_URI_OID = \"1.2.840.113549.1.9.16.5.1\";\n\n// ---------------------------------------------------------------------------\n// Cached policy data\n// ---------------------------------------------------------------------------\n\nlet cachedPolicyData: {\n hashAlgOid: string;\n policyHash: Uint8Array;\n} | null = null;\n\n/**\n * Clear the cached signature policy data.\n * Useful for testing or forcing a re-download.\n */\nexport function clearPolicyCache(): void {\n cachedPolicyData = null;\n}\n\n// ---------------------------------------------------------------------------\n// Signing Certificate V2\n// ---------------------------------------------------------------------------\n\n/**\n * Build the id-aa-signingCertificateV2 attribute value (DER-encoded).\n *\n * This attribute links the signature to the specific certificate used to\n * create it, preventing substitution attacks.\n *\n * ASN.1 structure (RFC 5035):\n *\n * SigningCertificateV2 ::= SEQUENCE {\n * certs SEQUENCE OF ESSCertIDv2\n * }\n *\n * ESSCertIDv2 ::= SEQUENCE {\n * hashAlgorithm AlgorithmIdentifier DEFAULT {algorithm id-sha256},\n * certHash Hash,\n * issuerSerial IssuerSerial OPTIONAL\n * }\n *\n * IssuerSerial ::= SEQUENCE {\n * issuer GeneralNames,\n * serialNumber CertificateSerialNumber\n * }\n *\n * @param certDer - DER-encoded X.509 certificate\n * @returns DER-encoded SigningCertificateV2 value\n */\nexport function buildSigningCertificateV2(certDer: Uint8Array): Uint8Array {\n // 1. Hash the DER certificate with SHA-256\n const certHash = hash(\"sha256\", certDer);\n\n // 2. Build AlgorithmIdentifier for SHA-256\n const hashAlgId = sequence(oid(SHA256_OID), nullValue());\n\n // 3. Extract issuer and serial number from the certificate\n const cert = decodeDer(certDer);\n const tbsCert = (cert.value as Asn1Node[])[0]!;\n const tbs = tbsCert.value as Asn1Node[];\n\n // version is [0] EXPLICIT, so tbs[0] may be version context tag\n let idx = 0;\n if (tbs[0]!.class === \"context\" && tbs[0]!.tag === 0) {\n idx = 1;\n }\n\n const serialNumber = tbs[idx]!; // INTEGER\n const issuerName = tbs[idx + 2]!; // Name SEQUENCE\n\n // 4. Build IssuerSerial\n // IssuerSerial ::= SEQUENCE { issuer GeneralNames, serialNumber INTEGER }\n // GeneralNames ::= SEQUENCE OF GeneralName\n // GeneralName ::= directoryName [4] Name\n const generalName = contextTag(4, [issuerName]);\n const generalNames = sequence(generalName);\n const issuerSerial = sequence(generalNames, serialNumber);\n\n // 5. Build ESSCertIDv2\n const essCertIdV2 = sequence(hashAlgId, octetString(certHash), issuerSerial);\n\n // 6. Build SigningCertificateV2\n const signingCertV2 = sequence(\n // certs SEQUENCE OF ESSCertIDv2\n sequence(essCertIdV2),\n );\n\n return encodeDer(signingCertV2);\n}\n\n// ---------------------------------------------------------------------------\n// Signature Policy\n// ---------------------------------------------------------------------------\n\n/**\n * Download and parse the ICP-Brasil signature policy DER file.\n * Extracts the embedded signPolicyHash from the ASN.1 structure.\n */\nasync function downloadAndParsePolicyDocument(): Promise<{\n hashAlgOid: string;\n policyHash: Uint8Array;\n}> {\n if (cachedPolicyData) {\n return cachedPolicyData;\n }\n\n const response = await fetch(POLICY_CONFIG.URL);\n\n if (!response.ok) {\n throw new SignaturePolicyError(\n `Failed to download signature policy: HTTP ${response.status}`,\n );\n }\n\n const arrayBuffer = await response.arrayBuffer();\n const data = new Uint8Array(arrayBuffer);\n\n if (data.length === 0 || data[0] !== 0x30) {\n throw new SignaturePolicyError(\"Invalid DER format in policy document\");\n }\n\n // Parse the ASN.1 structure:\n // SignaturePolicy ::= SEQUENCE {\n // signPolicyHashAlg AlgorithmIdentifier,\n // signPolicyInfo SignaturePolicyInfo,\n // signPolicyHash OCTET STRING\n // }\n const asn1 = decodeDer(data);\n const children = asn1.value as Asn1Node[];\n\n if (!Array.isArray(children) || children.length < 3) {\n throw new SignaturePolicyError(\n `Unexpected policy structure: expected 3+ children, got ${children?.length}`,\n );\n }\n\n // Child[0] = AlgorithmIdentifier\n const algIdChildren = children[0]!.value as Asn1Node[];\n if (!Array.isArray(algIdChildren) || algIdChildren.length === 0) {\n throw new SignaturePolicyError(\"Invalid AlgorithmIdentifier in policy\");\n }\n\n const { bytesToOid } = await import(\"@f-o-t/asn1\");\n const hashAlgOid = bytesToOid(algIdChildren[0]!.value as Uint8Array);\n\n // Child[2] = signPolicyHash (OCTET STRING)\n const hashNode = children[2]!;\n if (hashNode.tag !== 0x04) {\n throw new SignaturePolicyError(\n `Expected OCTET STRING at child[2], got tag 0x${hashNode.tag.toString(16)}`,\n );\n }\n\n cachedPolicyData = {\n hashAlgOid,\n policyHash: hashNode.value as Uint8Array,\n };\n\n return cachedPolicyData;\n}\n\n/**\n * Build the id-aa-ets-sigPolicyId attribute value (DER-encoded).\n *\n * Downloads the ICP-Brasil PAdES signature policy and extracts the\n * embedded signPolicyHash to build the attribute.\n *\n * @returns DER-encoded SignaturePolicyIdentifier value\n */\nexport async function buildSignaturePolicy(): Promise<Uint8Array> {\n const { hashAlgOid, policyHash } = await downloadAndParsePolicyDocument();\n\n // AlgorithmIdentifier for hash (no NULL — matches policy encoding)\n const hashAlgId = sequence(oid(hashAlgOid));\n\n // SigPolicyHash (OtherHashAlgAndValue)\n const sigPolicyHash = sequence(hashAlgId, octetString(policyHash));\n\n // SigPolicyQualifiers with policy URL\n const sigPolicyQualifiers = sequence(\n sequence(\n // id-spq-ets-uri\n oid(SPQ_ETS_URI_OID),\n // Policy URL as IA5String\n ia5String(POLICY_CONFIG.URL),\n ),\n );\n\n // SignaturePolicyId\n const signaturePolicyId = sequence(\n // sigPolicyId (policy OID)\n oid(POLICY_CONFIG.OID),\n // sigPolicyHash\n sigPolicyHash,\n // sigPolicyQualifiers\n sigPolicyQualifiers,\n );\n\n return encodeDer(signaturePolicyId);\n}\n\n/**\n * Attribute OID constants for external use\n */\nexport const ICP_BRASIL_OIDS = {\n signingCertificateV2: SIGNING_CERTIFICATE_V2_OID,\n signaturePolicy: SIGNATURE_POLICY_OID,\n} as const;\n\n// ---------------------------------------------------------------------------\n// Errors\n// ---------------------------------------------------------------------------\n\nexport class SignaturePolicyError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"SignaturePolicyError\";\n }\n}\n",
8
+ "/**\n * Zod schemas for input validation\n */\n\nimport { z } from \"zod\";\n\nconst signatureAppearanceSchema = z.object({\n x: z.number(),\n y: z.number(),\n width: z.number().positive(),\n height: z.number().positive(),\n page: z.number().int().min(0).optional(),\n showQrCode: z.boolean().optional(),\n showCertInfo: z.boolean().optional(),\n});\n\nconst qrCodeConfigSchema = z.object({\n data: z.string().optional(),\n size: z.number().int().positive().optional(),\n});\n\nexport const pdfSignOptionsSchema = z.object({\n certificate: z.object({\n p12: z.instanceof(Uint8Array).refine((v) => v.length > 0, {\n message: \"P12 data must not be empty\",\n }),\n password: z.string(),\n name: z.string().optional(),\n }),\n reason: z.string().optional(),\n location: z.string().optional(),\n contactInfo: z.string().optional(),\n policy: z.enum([\"pades-ades\", \"pades-icp-brasil\"]).optional(),\n timestamp: z.boolean().optional(),\n tsaUrl: z.string().url().optional(),\n tsaTimeout: z.number().positive().optional(),\n tsaRetries: z.number().int().min(0).optional(),\n tsaFallbackUrls: z.array(z.string().url()).optional(),\n onTimestampError: z.function().args(z.unknown()).returns(z.void()).optional(),\n appearance: z\n .union([signatureAppearanceSchema, z.literal(false)])\n .optional(),\n appearances: z.array(signatureAppearanceSchema).optional(),\n qrCode: qrCodeConfigSchema.optional(),\n docMdpPermission: z\n .union([z.literal(1), z.literal(2), z.literal(3)])\n .optional(),\n});\n",
9
+ "/**\n * RFC 3161 Timestamp Client\n *\n * Requests trusted timestamps from TSA servers using native fetch.\n * Builds the TimeStampReq using @f-o-t/asn1 instead of forge.\n */\n\nimport {\n type Asn1Node,\n boolean as asn1Boolean,\n decodeDer,\n encodeDer,\n integer,\n octetString,\n oid,\n sequence,\n} from \"@f-o-t/asn1\";\nimport { hash } from \"@f-o-t/crypto\";\n\n// ---------------------------------------------------------------------------\n// Constants\n// ---------------------------------------------------------------------------\n\n/** Well-known hash algorithm OIDs */\nconst HASH_OIDS: Record<string, string> = {\n sha256: \"2.16.840.1.101.3.4.2.1\",\n sha384: \"2.16.840.1.101.3.4.2.2\",\n sha512: \"2.16.840.1.101.3.4.2.3\",\n};\n\n/** ICP-Brasil Approved Timestamp Servers */\nexport const TIMESTAMP_SERVERS = {\n VALID: \"http://timestamp.valid.com.br/tsa\",\n SAFEWEB: \"http://tsa.safeweb.com.br/tsa/tsa\",\n CERTISIGN: \"http://timestamp.certisign.com.br\",\n} as const;\n\n/** id-smime-aa-timeStampToken OID */\nexport const TIMESTAMP_TOKEN_OID = \"1.2.840.113549.1.9.16.2.14\";\n\n// ---------------------------------------------------------------------------\n// Public API\n// ---------------------------------------------------------------------------\n\n/**\n * Request a timestamp from a TSA server with retry and fallback support.\n *\n * @param dataToTimestamp - The data to timestamp (usually the signature value)\n * @param tsaUrl - URL of the primary timestamp server\n * @param hashAlgorithm - Hash algorithm to use (default: \"sha256\")\n * @param options - Resilience options (timeout, retries, fallback URLs)\n * @returns DER-encoded TimeStampToken\n */\nexport async function requestTimestamp(\n dataToTimestamp: Uint8Array,\n tsaUrl: string,\n hashAlgorithm: \"sha256\" | \"sha384\" | \"sha512\" = \"sha256\",\n options?: { tsaTimeout?: number; tsaRetries?: number; tsaFallbackUrls?: string[] },\n): Promise<Uint8Array> {\n // 1. Hash the data\n const messageHash = hash(hashAlgorithm, dataToTimestamp);\n\n // 2. Build TimeStampReq\n const timestampReq = buildTimestampRequest(messageHash, hashAlgorithm);\n\n const tsaTimeout = options?.tsaTimeout ?? 10000;\n const tsaRetries = options?.tsaRetries ?? 0;\n const tsaFallbackUrls = options?.tsaFallbackUrls ?? [];\n\n let lastError: Error | undefined;\n\n // 3. Try primary server: 1 initial attempt + tsaRetries retries\n for (let attempt = 1; attempt <= 1 + tsaRetries; attempt++) {\n if (attempt > 1) {\n await sleep(2 ** (attempt - 2) * 1000);\n }\n try {\n return await fetchTimestamp(tsaUrl, timestampReq, tsaTimeout);\n } catch (err) {\n lastError = err instanceof Error ? err : new Error(String(err));\n }\n }\n\n // 4. Try fallback servers (one attempt each, no delay)\n for (const fallbackUrl of tsaFallbackUrls) {\n try {\n return await fetchTimestamp(fallbackUrl, timestampReq, tsaTimeout);\n } catch (err) {\n lastError = err instanceof Error ? err : new Error(String(err));\n }\n }\n\n // 5. All servers failed\n const fallbackList = tsaFallbackUrls.length > 0\n ? `, fallbacks: [${tsaFallbackUrls.join(\", \")}]`\n : \"\";\n throw new TimestampError(\n `TSA request failed: all servers unreachable (primary: ${tsaUrl}${fallbackList}). Last error: ${lastError?.message ?? \"unknown\"}`,\n );\n}\n\n// ---------------------------------------------------------------------------\n// Internal\n// ---------------------------------------------------------------------------\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\n/**\n * Perform a single TSA fetch attempt, wrapping network errors with a descriptive message.\n */\nasync function fetchTimestamp(\n url: string,\n timestampReq: Uint8Array,\n timeoutMs: number,\n): Promise<Uint8Array> {\n let response: Response;\n try {\n response = await fetch(url, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/timestamp-query\",\n },\n body: timestampReq as unknown as BodyInit,\n signal: AbortSignal.timeout(timeoutMs),\n });\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n throw new Error(`TSA server unreachable: ${url} — ${msg}`);\n }\n\n if (!response.ok) {\n throw new TimestampError(`TSA returned HTTP ${response.status}`);\n }\n\n const respBuffer = new Uint8Array(await response.arrayBuffer());\n return extractTimestampToken(respBuffer);\n}\n\n/**\n * Build a TimeStampReq (RFC 3161) as DER bytes.\n *\n * TimeStampReq ::= SEQUENCE {\n * version INTEGER { v1(1) },\n * messageImprint MessageImprint,\n * certReq BOOLEAN DEFAULT FALSE\n * }\n *\n * MessageImprint ::= SEQUENCE {\n * hashAlgorithm AlgorithmIdentifier,\n * hashedMessage OCTET STRING\n * }\n */\nfunction buildTimestampRequest(\n messageHash: Uint8Array,\n hashAlgorithm: string,\n): Uint8Array {\n const hashOid = HASH_OIDS[hashAlgorithm];\n if (!hashOid) {\n throw new TimestampError(`Unsupported hash algorithm: ${hashAlgorithm}`);\n }\n\n const timestampReq = sequence(\n // version = 1\n integer(1),\n // messageImprint\n sequence(\n // hashAlgorithm AlgorithmIdentifier\n sequence(oid(hashOid)),\n // hashedMessage OCTET STRING\n octetString(messageHash),\n ),\n // certReq = TRUE (request certificate in response)\n asn1Boolean(true),\n );\n\n return encodeDer(timestampReq);\n}\n\n/**\n * Extract the TimeStampToken from a TimeStampResp.\n *\n * TimeStampResp ::= SEQUENCE {\n * status PKIStatusInfo,\n * timeStampToken TimeStampToken OPTIONAL\n * }\n *\n * PKIStatusInfo ::= SEQUENCE {\n * status PKIStatus, -- INTEGER\n * ...\n * }\n */\nfunction extractTimestampToken(respDer: Uint8Array): Uint8Array {\n let resp: Asn1Node;\n try {\n resp = decodeDer(respDer);\n } catch {\n throw new TimestampError(\"Invalid timestamp response: not valid DER\");\n }\n\n const children = resp.value as Asn1Node[];\n if (!Array.isArray(children) || children.length < 1) {\n throw new TimestampError(\n \"Invalid timestamp response: unexpected structure\",\n );\n }\n\n // Check status\n const statusInfo = children[0]!.value as Asn1Node[];\n const statusBytes = statusInfo[0]!.value as Uint8Array;\n // Status 0 = granted, 1 = grantedWithMods\n const statusValue = statusBytes[statusBytes.length - 1]!;\n if (statusValue !== 0 && statusValue !== 1) {\n throw new TimestampError(\n `Timestamp request rejected with status: ${statusValue}`,\n );\n }\n\n // Extract token (second child)\n if (!children[1]) {\n throw new TimestampError(\"Timestamp response does not contain a token\");\n }\n\n return encodeDer(children[1]);\n}\n\n// ---------------------------------------------------------------------------\n// Errors\n// ---------------------------------------------------------------------------\n\nexport class TimestampError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"TimestampError\";\n }\n}\n",
10
+ "import { signPdf } from \"./sign-pdf.ts\";\nimport type { PdfSignOptions } from \"./types.ts\";\n\n/**\n * Input for a single PDF in a batch signing operation.\n */\nexport type BatchSignInput = {\n /** Filename for identification in events */\n filename: string;\n /** PDF content as Uint8Array or ReadableStream */\n pdf: Uint8Array | ReadableStream<Uint8Array>;\n /** Per-file option overrides merged with base options */\n options?: Partial<PdfSignOptions>;\n};\n\n/**\n * Events emitted during batch signing.\n */\nexport type BatchSignEvent =\n | { type: \"file_start\"; fileIndex: number; filename: string }\n | { type: \"file_complete\"; fileIndex: number; filename: string; signed: Uint8Array }\n | { type: \"file_error\"; fileIndex: number; filename: string; error: string }\n | { type: \"batch_complete\"; totalFiles: number; errorCount: number };\n\n/**\n * Sign multiple PDFs sequentially, yielding progress events.\n *\n * Yields control between each signing operation to prevent blocking\n * the event loop under bulk load.\n *\n * @param files - Array of PDFs with filename and optional per-file options\n * @param options - Base signing options (per-file options override these)\n * @yields BatchSignEvent for each file start, completion, error, and batch complete\n */\nexport async function* signPdfBatch(\n files: BatchSignInput[],\n options: PdfSignOptions,\n): AsyncGenerator<BatchSignEvent> {\n let errorCount = 0;\n let processedCount = 0;\n\n for (let i = 0; i < files.length; i++) {\n const file = files[i];\n if (!file) continue;\n processedCount++;\n\n yield { type: \"file_start\", fileIndex: i, filename: file.filename };\n\n try {\n // Merge per-file options with base options (file.options takes priority)\n const mergedOptions: PdfSignOptions = { ...options, ...file.options };\n\n const signed = await signPdf(file.pdf, mergedOptions);\n\n yield { type: \"file_complete\", fileIndex: i, filename: file.filename, signed };\n } catch (err) {\n errorCount++;\n yield {\n type: \"file_error\",\n fileIndex: i,\n filename: file.filename,\n error: err instanceof Error ? err.message : String(err),\n };\n }\n\n // Yield control between files to prevent event loop blocking\n await new Promise<void>((resolve) => setTimeout(resolve, 0));\n }\n\n yield { type: \"batch_complete\", totalFiles: processedCount, errorCount };\n}\n\n/**\n * Sign multiple PDFs sequentially, collecting all results.\n *\n * Convenience wrapper around {@link signPdfBatch} that collects all events\n * into an array of results.\n *\n * @param files - Array of PDFs with filename and optional per-file options\n * @param options - Base signing options\n * @returns Array of results with signed PDF bytes or error per file\n */\nexport async function signPdfBatchToArray(\n files: BatchSignInput[],\n options: PdfSignOptions,\n): Promise<{ filename: string; signed?: Uint8Array; error?: string }[]> {\n const results: { filename: string; signed?: Uint8Array; error?: string }[] =\n files.map((f) => ({ filename: f.filename }));\n\n for await (const event of signPdfBatch(files, options)) {\n switch (event.type) {\n case \"file_complete\": {\n const r = results[event.fileIndex];\n if (r) r.signed = event.signed;\n break;\n }\n case \"file_error\": {\n const r = results[event.fileIndex];\n if (r) r.error = event.error;\n break;\n }\n }\n }\n\n return results;\n}\n"
10
11
  ],
11
- "mappings": "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",
12
- "debugId": "847A450B084A9AAE64756E2164756E21",
12
+ "mappings": "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",
13
+ "debugId": "AA843AB2650A666564756E2164756E21",
13
14
  "names": []
14
15
  }
package/dist/schemas.d.ts CHANGED
@@ -17,6 +17,10 @@ export declare const pdfSignOptionsSchema: z.ZodObject<{
17
17
  }>>;
18
18
  timestamp: z.ZodOptional<z.ZodBoolean>;
19
19
  tsaUrl: z.ZodOptional<z.ZodString>;
20
+ tsaTimeout: z.ZodOptional<z.ZodNumber>;
21
+ tsaRetries: z.ZodOptional<z.ZodNumber>;
22
+ tsaFallbackUrls: z.ZodOptional<z.ZodArray<z.ZodString>>;
23
+ onTimestampError: any;
20
24
  appearance: z.ZodOptional<z.ZodUnion<readonly [z.ZodObject<{
21
25
  x: z.ZodNumber;
22
26
  y: z.ZodNumber;
@@ -1 +1 @@
1
- {"version":3,"file":"schemas.d.ts","sourceRoot":"","sources":["../src/schemas.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAiBxB,eAAO,MAAM,oBAAoB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAsB/B,CAAC"}
1
+ {"version":3,"file":"schemas.d.ts","sourceRoot":"","sources":["../src/schemas.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAiBxB,eAAO,MAAM,oBAAoB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBA0B/B,CAAC"}
@@ -18,7 +18,7 @@ import type { PdfSignOptions } from "./types.ts";
18
18
  * Supports PAdES-BES and PAdES with ICP-Brasil compliance
19
19
  * (signing-certificate-v2 and signature-policy attributes).
20
20
  *
21
- * @param pdf - The PDF document as a Uint8Array
21
+ * @param pdf - The PDF document as a Uint8Array or ReadableStream<Uint8Array>
22
22
  * @param options - Signing options
23
23
  * @returns The signed PDF as a Uint8Array
24
24
  *
@@ -32,7 +32,7 @@ import type { PdfSignOptions } from "./types.ts";
32
32
  * });
33
33
  * ```
34
34
  */
35
- export declare function signPdf(pdf: Uint8Array, options: PdfSignOptions): Promise<Uint8Array>;
35
+ export declare function signPdf(pdf: Uint8Array | ReadableStream<Uint8Array>, options: PdfSignOptions): Promise<Uint8Array>;
36
36
  export declare class PdfSignError extends Error {
37
37
  constructor(message: string);
38
38
  }
@@ -1 +1 @@
1
- {"version":3,"file":"sign-pdf.d.ts","sourceRoot":"","sources":["../src/sign-pdf.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAoBH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAEjD;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAsB,OAAO,CAC1B,GAAG,EAAE,UAAU,EACf,OAAO,EAAE,cAAc,GACvB,OAAO,CAAC,UAAU,CAAC,CAkJrB;AAMD,qBAAa,YAAa,SAAQ,KAAK;gBACxB,OAAO,EAAE,MAAM;CAI7B"}
1
+ {"version":3,"file":"sign-pdf.d.ts","sourceRoot":"","sources":["../src/sign-pdf.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAoBH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAEjD;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAsB,OAAO,CAC1B,GAAG,EAAE,UAAU,GAAG,cAAc,CAAC,UAAU,CAAC,EAC5C,OAAO,EAAE,cAAc,GACvB,OAAO,CAAC,UAAU,CAAC,CAgLrB;AAMD,qBAAa,YAAa,SAAQ,KAAK;gBACxB,OAAO,EAAE,MAAM;CAI7B"}
@@ -13,14 +13,19 @@ export declare const TIMESTAMP_SERVERS: {
13
13
  /** id-smime-aa-timeStampToken OID */
14
14
  export declare const TIMESTAMP_TOKEN_OID = "1.2.840.113549.1.9.16.2.14";
15
15
  /**
16
- * Request a timestamp from a TSA server.
16
+ * Request a timestamp from a TSA server with retry and fallback support.
17
17
  *
18
18
  * @param dataToTimestamp - The data to timestamp (usually the signature value)
19
- * @param tsaUrl - URL of the timestamp server
19
+ * @param tsaUrl - URL of the primary timestamp server
20
20
  * @param hashAlgorithm - Hash algorithm to use (default: "sha256")
21
+ * @param options - Resilience options (timeout, retries, fallback URLs)
21
22
  * @returns DER-encoded TimeStampToken
22
23
  */
23
- export declare function requestTimestamp(dataToTimestamp: Uint8Array, tsaUrl: string, hashAlgorithm?: "sha256" | "sha384" | "sha512"): Promise<Uint8Array>;
24
+ export declare function requestTimestamp(dataToTimestamp: Uint8Array, tsaUrl: string, hashAlgorithm?: "sha256" | "sha384" | "sha512", options?: {
25
+ tsaTimeout?: number;
26
+ tsaRetries?: number;
27
+ tsaFallbackUrls?: string[];
28
+ }): Promise<Uint8Array>;
24
29
  export declare class TimestampError extends Error {
25
30
  constructor(message: string);
26
31
  }
@@ -1 +1 @@
1
- {"version":3,"file":"timestamp.d.ts","sourceRoot":"","sources":["../src/timestamp.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAyBH,4CAA4C;AAC5C,eAAO,MAAM,iBAAiB;;;;CAIpB,CAAC;AAEX,qCAAqC;AACrC,eAAO,MAAM,mBAAmB,+BAA+B,CAAC;AAMhE;;;;;;;GAOG;AACH,wBAAsB,gBAAgB,CACnC,eAAe,EAAE,UAAU,EAC3B,MAAM,EAAE,MAAM,EACd,aAAa,GAAE,QAAQ,GAAG,QAAQ,GAAG,QAAmB,GACxD,OAAO,CAAC,UAAU,CAAC,CAyBrB;AAiGD,qBAAa,cAAe,SAAQ,KAAK;gBAC1B,OAAO,EAAE,MAAM;CAI7B"}
1
+ {"version":3,"file":"timestamp.d.ts","sourceRoot":"","sources":["../src/timestamp.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAyBH,4CAA4C;AAC5C,eAAO,MAAM,iBAAiB;;;;CAIpB,CAAC;AAEX,qCAAqC;AACrC,eAAO,MAAM,mBAAmB,+BAA+B,CAAC;AAMhE;;;;;;;;GAQG;AACH,wBAAsB,gBAAgB,CACnC,eAAe,EAAE,UAAU,EAC3B,MAAM,EAAE,MAAM,EACd,aAAa,GAAE,QAAQ,GAAG,QAAQ,GAAG,QAAmB,EACxD,OAAO,CAAC,EAAE;IAAE,UAAU,CAAC,EAAE,MAAM,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAAC,eAAe,CAAC,EAAE,MAAM,EAAE,CAAA;CAAE,GAClF,OAAO,CAAC,UAAU,CAAC,CAyCrB;AAoID,qBAAa,cAAe,SAAQ,KAAK;gBAC1B,OAAO,EAAE,MAAM;CAI7B"}
package/dist/types.d.ts CHANGED
@@ -56,6 +56,14 @@ export type PdfSignOptions = {
56
56
  timestamp?: boolean;
57
57
  /** Timestamp server URL */
58
58
  tsaUrl?: string;
59
+ /** Timeout in ms per TSA attempt (default: 10000) */
60
+ tsaTimeout?: number;
61
+ /** Number of retry attempts after the initial TSA request fails (default: 0); total attempts = 1 + tsaRetries */
62
+ tsaRetries?: number;
63
+ /** Fallback TSA server URLs tried in order after primary is exhausted */
64
+ tsaFallbackUrls?: string[];
65
+ /** Called when timestamping fails (non-fatal). Receives the error for logging/metrics. */
66
+ onTimestampError?: (error: unknown) => void;
59
67
  /** Visual signature appearance (false to disable) */
60
68
  appearance?: SignatureAppearance | false;
61
69
  /** Multiple visual signature appearances — renders a stamp on each specified page */
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH;;GAEG;AACH,MAAM,MAAM,mBAAmB,GAAG;IAC/B,yCAAyC;IACzC,CAAC,EAAE,MAAM,CAAC;IACV,2CAA2C;IAC3C,CAAC,EAAE,MAAM,CAAC;IACV,yCAAyC;IACzC,KAAK,EAAE,MAAM,CAAC;IACd,0CAA0C;IAC1C,MAAM,EAAE,MAAM,CAAC;IACf,0CAA0C;IAC1C,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,qDAAqD;IACrD,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,+DAA+D;IAC/D,YAAY,CAAC,EAAE,OAAO,CAAC;CACzB,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,YAAY,GAAG;IACxB,uEAAuE;IACvE,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,mDAAmD;IACnD,IAAI,CAAC,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,cAAc,GAAG;IAC1B,8BAA8B;IAC9B,WAAW,EAAE;QACV,gCAAgC;QAChC,GAAG,EAAE,UAAU,CAAC;QAChB,oCAAoC;QACpC,QAAQ,EAAE,MAAM,CAAC;QACjB,2CAA2C;QAC3C,IAAI,CAAC,EAAE,MAAM,CAAC;KAChB,CAAC;IACF,yBAAyB;IACzB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,sCAAsC;IACtC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,0BAA0B;IAC1B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,+FAA+F;IAC/F,MAAM,CAAC,EAAE,YAAY,GAAG,kBAAkB,CAAC;IAC3C,gDAAgD;IAChD,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,2BAA2B;IAC3B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,qDAAqD;IACrD,UAAU,CAAC,EAAE,mBAAmB,GAAG,KAAK,CAAC;IACzC,qFAAqF;IACrF,WAAW,CAAC,EAAE,mBAAmB,EAAE,CAAC;IACpC,qDAAqD;IACrD,MAAM,CAAC,EAAE,YAAY,CAAC;IACtB,+GAA+G;IAC/G,gBAAgB,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;CAC/B,CAAC"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH;;GAEG;AACH,MAAM,MAAM,mBAAmB,GAAG;IAC/B,yCAAyC;IACzC,CAAC,EAAE,MAAM,CAAC;IACV,2CAA2C;IAC3C,CAAC,EAAE,MAAM,CAAC;IACV,yCAAyC;IACzC,KAAK,EAAE,MAAM,CAAC;IACd,0CAA0C;IAC1C,MAAM,EAAE,MAAM,CAAC;IACf,0CAA0C;IAC1C,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,qDAAqD;IACrD,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,+DAA+D;IAC/D,YAAY,CAAC,EAAE,OAAO,CAAC;CACzB,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,YAAY,GAAG;IACxB,uEAAuE;IACvE,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,mDAAmD;IACnD,IAAI,CAAC,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,cAAc,GAAG;IAC1B,8BAA8B;IAC9B,WAAW,EAAE;QACV,gCAAgC;QAChC,GAAG,EAAE,UAAU,CAAC;QAChB,oCAAoC;QACpC,QAAQ,EAAE,MAAM,CAAC;QACjB,2CAA2C;QAC3C,IAAI,CAAC,EAAE,MAAM,CAAC;KAChB,CAAC;IACF,yBAAyB;IACzB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,sCAAsC;IACtC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,0BAA0B;IAC1B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,+FAA+F;IAC/F,MAAM,CAAC,EAAE,YAAY,GAAG,kBAAkB,CAAC;IAC3C,gDAAgD;IAChD,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,2BAA2B;IAC3B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,qDAAqD;IACrD,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,iHAAiH;IACjH,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,yEAAyE;IACzE,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC;IAC3B,0FAA0F;IAC1F,gBAAgB,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC;IAC5C,qDAAqD;IACrD,UAAU,CAAC,EAAE,mBAAmB,GAAG,KAAK,CAAC;IACzC,qFAAqF;IACrF,WAAW,CAAC,EAAE,mBAAmB,EAAE,CAAC;IACpC,qDAAqD;IACrD,MAAM,CAAC,EAAE,YAAY,CAAC;IACtB,+GAA+G;IAC/G,gBAAgB,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;CAC/B,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@f-o-t/e-signature",
3
- "version": "1.1.0",
3
+ "version": "1.2.1",
4
4
  "description": "PAdES PDF signing with ICP-Brasil compliance",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",