@paniniapi/forensics 0.0.0-stage → 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.
@@ -0,0 +1 @@
1
+ {"version":3,"file":"content.js","sourceRoot":"","sources":["../../src/pdf/content.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,40 @@
1
+ /**
2
+ * Copyright 2026 Kapil — Project Panini Contributors
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+ /**
17
+ * PDF digital-signature validation (ISO 32000 / RFC 5652 CMS).
18
+ *
19
+ * For every `/ByteRange`+`/Contents` signature field:
20
+ * 1. bytes outside the signed ranges → post-sign modification;
21
+ * 2. hash the signed byte ranges → compare to the CMS `messageDigest`
22
+ * signed attribute → proves the exact bytes the signer saw;
23
+ * 3. verify the signerInfo signature over signedAttrs with the
24
+ * signer's certificate public key (node:crypto, PKCS#1 v1.5 RSA or
25
+ * ECDSA-DER);
26
+ * 4. walk the embedded certificate chain to a caller-supplied trust
27
+ * anchor (CCA-India roots or a bank CA loaded by the integrator).
28
+ */
29
+ import * as crypto from 'node:crypto';
30
+ import type { SignatureCheck } from '../types';
31
+ export interface SignatureOptions {
32
+ /** Trust anchors as PEM strings or X509Certificate objects. */
33
+ readonly trustStore?: readonly (string | crypto.X509Certificate)[];
34
+ }
35
+ /**
36
+ * Validate every signature in the PDF. Never throws — errors land in
37
+ * `check.errors` and the check's validity fields stay null.
38
+ */
39
+ export declare function verifyPdfSignatures(pdf: Uint8Array, opts?: SignatureOptions): readonly SignatureCheck[];
40
+ //# sourceMappingURL=signature.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"signature.d.ts","sourceRoot":"","sources":["../../src/pdf/signature.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,MAAM,MAAM,aAAa,CAAC;AAStC,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AAoK/C,MAAM,WAAW,gBAAgB;IAC/B,+DAA+D;IAC/D,QAAQ,CAAC,UAAU,CAAC,EAAE,SAAS,CAAC,MAAM,GAAG,MAAM,CAAC,eAAe,CAAC,EAAE,CAAC;CACpE;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CACjC,GAAG,EAAE,UAAU,EACf,IAAI,GAAE,gBAAqB,GAC1B,SAAS,cAAc,EAAE,CAI3B"}
@@ -0,0 +1,351 @@
1
+ "use strict";
2
+ /**
3
+ * Copyright 2026 Kapil — Project Panini Contributors
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ *
9
+ * http://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */
17
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
18
+ if (k2 === undefined) k2 = k;
19
+ var desc = Object.getOwnPropertyDescriptor(m, k);
20
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
21
+ desc = { enumerable: true, get: function() { return m[k]; } };
22
+ }
23
+ Object.defineProperty(o, k2, desc);
24
+ }) : (function(o, m, k, k2) {
25
+ if (k2 === undefined) k2 = k;
26
+ o[k2] = m[k];
27
+ }));
28
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
29
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
30
+ }) : function(o, v) {
31
+ o["default"] = v;
32
+ });
33
+ var __importStar = (this && this.__importStar) || (function () {
34
+ var ownKeys = function(o) {
35
+ ownKeys = Object.getOwnPropertyNames || function (o) {
36
+ var ar = [];
37
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
38
+ return ar;
39
+ };
40
+ return ownKeys(o);
41
+ };
42
+ return function (mod) {
43
+ if (mod && mod.__esModule) return mod;
44
+ var result = {};
45
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
46
+ __setModuleDefault(result, mod);
47
+ return result;
48
+ };
49
+ })();
50
+ Object.defineProperty(exports, "__esModule", { value: true });
51
+ exports.verifyPdfSignatures = verifyPdfSignatures;
52
+ /**
53
+ * PDF digital-signature validation (ISO 32000 / RFC 5652 CMS).
54
+ *
55
+ * For every `/ByteRange`+`/Contents` signature field:
56
+ * 1. bytes outside the signed ranges → post-sign modification;
57
+ * 2. hash the signed byte ranges → compare to the CMS `messageDigest`
58
+ * signed attribute → proves the exact bytes the signer saw;
59
+ * 3. verify the signerInfo signature over signedAttrs with the
60
+ * signer's certificate public key (node:crypto, PKCS#1 v1.5 RSA or
61
+ * ECDSA-DER);
62
+ * 4. walk the embedded certificate chain to a caller-supplied trust
63
+ * anchor (CCA-India roots or a bank CA loaded by the integrator).
64
+ */
65
+ const crypto = __importStar(require("node:crypto"));
66
+ const asn1_1 = require("../asn1");
67
+ const LATIN1 = 'latin1';
68
+ const OID = {
69
+ signedData: '1.2.840.113549.1.2.1',
70
+ messageDigest: '1.2.840.113549.1.9.4',
71
+ signingTime: '1.2.840.113549.1.9.5',
72
+ };
73
+ const DIGEST_OID_TO_NODE = {
74
+ '1.3.14.3.2.26': 'sha1',
75
+ '2.16.840.1.101.3.4.2.1': 'sha256',
76
+ '2.16.840.1.101.3.4.2.2': 'sha384',
77
+ '2.16.840.1.101.3.4.2.3': 'sha512',
78
+ '2.16.840.1.101.3.4.2.4': 'sha224',
79
+ };
80
+ const SIG_OID = {
81
+ '1.2.840.113549.1.1.5': { hash: 'sha1', kind: 'rsa' },
82
+ '1.2.840.113549.1.1.11': { hash: 'sha256', kind: 'rsa' },
83
+ '1.2.840.113549.1.1.12': { hash: 'sha384', kind: 'rsa' },
84
+ '1.2.840.113549.1.1.13': { hash: 'sha512', kind: 'rsa' },
85
+ '1.2.840.10045.4.3.2': { hash: 'sha256', kind: 'ecdsa' },
86
+ '1.2.840.10045.4.3.3': { hash: 'sha384', kind: 'ecdsa' },
87
+ '1.2.840.10045.4.3.4': { hash: 'sha512', kind: 'ecdsa' },
88
+ };
89
+ function findSigFields(latin) {
90
+ const out = [];
91
+ const re = /\/ByteRange\s*\[\s*(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s*\]/g;
92
+ let m;
93
+ while ((m = re.exec(latin)) !== null) {
94
+ // /Contents is the nearest hex string after ByteRange within the sig
95
+ // dict. CMS blobs are zero-padded — the hex span can be tens of KB.
96
+ const after = latin.slice(m.index, m.index + (1 << 18));
97
+ const cm = /\/Contents\s*<([0-9a-fA-F\s]*)>/.exec(after);
98
+ if (cm === null)
99
+ continue;
100
+ const contents = Buffer.from(cm[1].replace(/\s/g, ''), 'hex');
101
+ const nm = /\/Name\s*\(([^)]*)\)/.exec(after);
102
+ out.push({
103
+ byteRange: [Number(m[1]), Number(m[2]), Number(m[3]), Number(m[4])],
104
+ contents,
105
+ name: nm !== null ? nm[1] : null,
106
+ });
107
+ }
108
+ return out;
109
+ }
110
+ /** SET OF header (universal 17, constructed) wrapping signedAttrs content —
111
+ * CMS signs the attrs re-tagged as SET OF, not the [0] context form. */
112
+ function setOfWrap(content) {
113
+ const len = content.length;
114
+ let header;
115
+ if (len < 0x80)
116
+ header = Buffer.from([0x31, len]);
117
+ else if (len < 0x100)
118
+ header = Buffer.from([0x31, 0x81, len]);
119
+ else
120
+ header = Buffer.from([0x31, 0x82, len >> 8, len & 0xff]);
121
+ return Buffer.concat([header, Buffer.from(content)]);
122
+ }
123
+ function parseSignerInfo(si) {
124
+ let cursor = 1; // skip version
125
+ const sid = si.children[cursor];
126
+ let issuerName = null;
127
+ let serial = null;
128
+ if (sid.tagClass === 0 && sid.tagNumber === 16) {
129
+ // issuerAndSerialNumber
130
+ issuerName = (0, asn1_1.stringValue)(sid.children[0] ?? sid).slice(0, 200);
131
+ const serialNode = (0, asn1_1.universal)(sid, 2);
132
+ serial = serialNode ? intLike(serialNode) : null;
133
+ }
134
+ cursor++;
135
+ const digestOid = (0, asn1_1.oidValue)((0, asn1_1.universal)(si.children[cursor], 6) ?? si.children[cursor]);
136
+ const digestAlg = DIGEST_OID_TO_NODE[digestOid] ?? digestOid;
137
+ cursor++;
138
+ // optional signedAttrs [0]
139
+ let signedAttrsRaw = null;
140
+ let messageDigest = null;
141
+ let signingTime = null;
142
+ if (si.children[cursor].tagClass === 2 && si.children[cursor].tagNumber === 0) {
143
+ const attrs = si.children[cursor];
144
+ signedAttrsRaw = setOfWrap(attrs.content);
145
+ for (const attr of attrs.children) {
146
+ const oid = attr.children[0] ? (0, asn1_1.oidValue)(attr.children[0]) : '';
147
+ const valSet = attr.children[1];
148
+ const first = valSet?.children[0];
149
+ if (oid === OID.messageDigest && first !== undefined)
150
+ messageDigest = Buffer.from(first.content);
151
+ if (oid === OID.signingTime && first !== undefined)
152
+ signingTime = (0, asn1_1.stringValue)(first);
153
+ }
154
+ cursor++;
155
+ }
156
+ const sigAlgOid = (0, asn1_1.oidValue)((0, asn1_1.universal)(si.children[cursor], 6) ?? si.children[cursor]);
157
+ cursor++;
158
+ const signature = Buffer.from(si.children[cursor].content);
159
+ if (signedAttrsRaw === null)
160
+ throw new asn1_1.Asn1Error('signerInfo has no signedAttrs — non-CMS form');
161
+ return {
162
+ digestAlg,
163
+ sigAlgOid,
164
+ signature,
165
+ signedAttrsRaw,
166
+ messageDigest,
167
+ signingTime,
168
+ issuerName,
169
+ serial,
170
+ };
171
+ }
172
+ function intLike(node) {
173
+ let v = 0n;
174
+ for (const b of node.content)
175
+ v = (v << 8n) | BigInt(b);
176
+ return v;
177
+ }
178
+ function parseCms(der) {
179
+ const contentInfo = (0, asn1_1.parseDerPadded)(der);
180
+ const typeOid = (0, asn1_1.oidValue)(contentInfo.children[0]);
181
+ if (typeOid !== OID.signedData) {
182
+ throw new asn1_1.Asn1Error(`content type ${typeOid} — not signedData (timestamp-only or enveloped)`);
183
+ }
184
+ const signedData = contentInfo.children[1].children[0]; // [0] EXPLICIT
185
+ const certs = [];
186
+ let signerInfos;
187
+ for (const c of signedData.children) {
188
+ if (c.tagClass === 2 && c.tagNumber === 0) {
189
+ // certificates [0] IMPLICIT SET — children are cert SEQUENCES
190
+ for (const certNode of c.children) {
191
+ try {
192
+ certs.push(new crypto.X509Certificate(Buffer.from(certNode.tlv)));
193
+ }
194
+ catch {
195
+ /* attribute certs / non-X509 entries — skip */
196
+ }
197
+ }
198
+ }
199
+ if (c.tagClass === 0 && c.tagNumber === 17)
200
+ signerInfos = c; // SET OF SignerInfo
201
+ }
202
+ if (signerInfos === undefined || signerInfos.children.length === 0) {
203
+ throw new asn1_1.Asn1Error('CMS signedData carries no signerInfos');
204
+ }
205
+ return { signer: parseSignerInfo(signerInfos.children[0]), certs };
206
+ }
207
+ /**
208
+ * Validate every signature in the PDF. Never throws — errors land in
209
+ * `check.errors` and the check's validity fields stay null.
210
+ */
211
+ function verifyPdfSignatures(pdf, opts = {}) {
212
+ const latin = Buffer.from(pdf).toString(LATIN1);
213
+ const fields = findSigFields(latin);
214
+ return fields.map((f) => checkOne(pdf, f, opts));
215
+ }
216
+ function checkOne(pdf, f, opts) {
217
+ const errors = [];
218
+ let postSignBytes = false;
219
+ let digestValid = null;
220
+ let signatureValid = null;
221
+ let chainTrusted = null;
222
+ const [o1, l1, o2, l2] = f.byteRange;
223
+ if (o2 + l2 < pdf.length) {
224
+ postSignBytes = true;
225
+ errors.push(`${pdf.length - (o2 + l2)} byte(s) after the signed ByteRange`);
226
+ }
227
+ let cms;
228
+ try {
229
+ cms = parseCms(new Uint8Array(f.contents));
230
+ }
231
+ catch (e) {
232
+ errors.push(`CMS parse failed: ${e instanceof Error ? e.message : String(e)}`);
233
+ return {
234
+ present: true,
235
+ fieldName: f.name,
236
+ signer: null,
237
+ signTime: null,
238
+ digestValid,
239
+ signatureValid,
240
+ chainTrusted,
241
+ postSignBytes,
242
+ errors,
243
+ };
244
+ }
245
+ const { signer, certs } = cms;
246
+ const signTime = signer.signingTime;
247
+ const signerCert = pickSignerCert(certs, signer);
248
+ const signerName = signerCert?.subject?.match(/CN=([^\n]+)/)?.[1]?.trim() ?? null;
249
+ // (b) byte-range digest vs messageDigest signed attribute.
250
+ const nodeHash = DIGEST_OID_TO_NODE[signer.digestAlg] ?? signer.digestAlg;
251
+ try {
252
+ const h = crypto.createHash(nodeHash);
253
+ h.update(pdf.subarray(o1, o1 + l1));
254
+ h.update(pdf.subarray(o2, o2 + l2));
255
+ const computed = h.digest();
256
+ if (signer.messageDigest === null) {
257
+ errors.push('signedAttrs carry no messageDigest — cannot bind signature to bytes');
258
+ }
259
+ else {
260
+ digestValid = computed.equals(signer.messageDigest);
261
+ if (!digestValid)
262
+ errors.push('messageDigest mismatch — signed bytes were altered');
263
+ }
264
+ }
265
+ catch (e) {
266
+ errors.push(`digest failed (${nodeHash}): ${e instanceof Error ? e.message : String(e)}`);
267
+ }
268
+ // (c) cryptographic signature over signedAttrs.
269
+ if (signerCert === null) {
270
+ errors.push('no signer certificate embedded');
271
+ }
272
+ else {
273
+ const alg = SIG_OID[signer.sigAlgOid];
274
+ if (alg === undefined) {
275
+ errors.push(`unsupported signature algorithm ${signer.sigAlgOid} (e.g. RSA-PSS)`);
276
+ }
277
+ else {
278
+ try {
279
+ const key = alg.kind === 'ecdsa'
280
+ ? { key: signerCert.publicKey, dsaEncoding: 'der' }
281
+ : { key: signerCert.publicKey };
282
+ signatureValid = crypto.verify(alg.hash, signer.signedAttrsRaw, key, signer.signature);
283
+ if (!signatureValid)
284
+ errors.push('signature does not verify over signedAttrs');
285
+ }
286
+ catch (e) {
287
+ errors.push(`verify failed: ${e instanceof Error ? e.message : String(e)}`);
288
+ }
289
+ }
290
+ }
291
+ // (d) chain to caller trust anchor.
292
+ if (opts.trustStore !== undefined && opts.trustStore.length > 0 && signerCert !== null) {
293
+ chainTrusted = chainToAnchor(signerCert, certs, opts.trustStore, errors);
294
+ }
295
+ return {
296
+ present: true,
297
+ fieldName: f.name,
298
+ signer: signerName,
299
+ signTime,
300
+ digestValid,
301
+ signatureValid,
302
+ chainTrusted,
303
+ postSignBytes,
304
+ errors,
305
+ };
306
+ }
307
+ function pickSignerCert(certs, signer) {
308
+ if (certs.length === 0)
309
+ return null;
310
+ // Match issuerAndSerialNumber when present; else the only leaf.
311
+ if (signer.serial !== null) {
312
+ const hit = certs.find((c) => c.serialNumber !== '' && BigInt(`0x${c.serialNumber}`) === signer.serial);
313
+ if (hit !== undefined)
314
+ return hit;
315
+ }
316
+ return certs[0] ?? null;
317
+ }
318
+ /** Walk issuer links among embedded certs; anchor must be in trustStore. */
319
+ function chainToAnchor(leaf, pool, trustStore, errors) {
320
+ const anchors = [];
321
+ for (const t of trustStore) {
322
+ try {
323
+ anchors.push(typeof t === 'string' ? new crypto.X509Certificate(t) : t);
324
+ }
325
+ catch {
326
+ errors.push('unparsable trust anchor skipped');
327
+ }
328
+ }
329
+ const trustedFp = new Set(anchors.map((a) => a.fingerprint256));
330
+ let cur = leaf;
331
+ for (let depth = 0; depth < 8; depth++) {
332
+ if (trustedFp.has(cur.fingerprint256))
333
+ return true;
334
+ const issuer = pool.find((c) => c.subject === cur.issuer && c !== cur) ?? cur;
335
+ if (issuer === cur)
336
+ break; // self-signed, not trusted
337
+ try {
338
+ if (!cur.verify(issuer.publicKey)) {
339
+ errors.push(`chain link failed: ${cur.subject.slice(0, 60)} not signed by issuer`);
340
+ return false;
341
+ }
342
+ }
343
+ catch (e) {
344
+ errors.push(`chain verify error: ${e instanceof Error ? e.message : String(e)}`);
345
+ return false;
346
+ }
347
+ cur = issuer;
348
+ }
349
+ return false;
350
+ }
351
+ //# sourceMappingURL=signature.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"signature.js","sourceRoot":"","sources":["../../src/pdf/signature.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,31 @@
1
+ /**
2
+ * Copyright 2026 Kapil — Project Panini Contributors
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+ /**
17
+ * Raw-byte structural forensics for PDF statement files. Everything here
18
+ * works on the container — no content trust required. Each check emits
19
+ * explainable signals; none of them auto-proves fraud alone.
20
+ */
21
+ import type { IntegritySignal } from '../types';
22
+ export interface StructureOptions {
23
+ /** Statement period end (YYYY-MM-DD) when known — dates after it on ModDate are suspicious. */
24
+ readonly statementPeriodEnd?: string | null;
25
+ }
26
+ /**
27
+ * Structural signals from raw PDF bytes. Never throws — malformed input
28
+ * yields a `structure_unreadable` warning signal, not an exception.
29
+ */
30
+ export declare function inspectPdfStructure(pdf: Uint8Array, opts?: StructureOptions): IntegritySignal[];
31
+ //# sourceMappingURL=structure.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"structure.d.ts","sourceRoot":"","sources":["../../src/pdf/structure.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH;;;;GAIG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,UAAU,CAAC;AA4DhD,MAAM,WAAW,gBAAgB;IAC/B,+FAA+F;IAC/F,QAAQ,CAAC,kBAAkB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC7C;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CACjC,GAAG,EAAE,UAAU,EACf,IAAI,GAAE,gBAAqB,GAC1B,eAAe,EAAE,CA6GnB"}
@@ -0,0 +1,172 @@
1
+ "use strict";
2
+ /**
3
+ * Copyright 2026 Kapil — Project Panini Contributors
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ *
9
+ * http://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */
17
+ Object.defineProperty(exports, "__esModule", { value: true });
18
+ exports.inspectPdfStructure = inspectPdfStructure;
19
+ const LATIN1 = 'latin1';
20
+ /** Producer/Creator strings strongly associated with interactive PDF editors. */
21
+ const EDITOR_SIGNATURES = [
22
+ /ilovepdf/i,
23
+ /pdfescape/i,
24
+ /smallpdf/i,
25
+ /sejda/i,
26
+ /pdf-xchange/i,
27
+ /foxit\s+(?:phantompdf|editor)/i,
28
+ /nitro/i,
29
+ /wkhtmltopdf/i, // HTML→PDF — statements must not be regenerated
30
+ /weasyprint/i,
31
+ /cairosvg/i,
32
+ /reportlab/i,
33
+ /fpdf/i,
34
+ /tcpdf/i,
35
+ /dompdf/i,
36
+ /itext(?!.*(?:bank|rbi))/i, // iText is also a legit bank generator — warning only
37
+ ];
38
+ const PDF_DATE_RE = /D:?(\d{4})(\d{2})(\d{2})(\d{2})?(\d{2})?(\d{2})?/;
39
+ function pdfDateToIso(raw) {
40
+ const m = PDF_DATE_RE.exec(raw);
41
+ if (m === null)
42
+ return null;
43
+ return `${m[1]}-${m[2]}-${m[3]}`;
44
+ }
45
+ function infoString(dict, key) {
46
+ // /Key (literal) or /Key <hex>
47
+ const lit = new RegExp(`/${key}\\s*\\(([^)]*)\\)`).exec(dict);
48
+ if (lit !== null)
49
+ return lit[1];
50
+ const hex = new RegExp(`/${key}\\s*<([0-9a-fA-F]*)>`).exec(dict);
51
+ if (hex !== null) {
52
+ const raw = Buffer.from(hex[1] ?? '', 'hex');
53
+ if (raw.length % 2 === 1)
54
+ return raw.toString('latin1');
55
+ return Buffer.from(raw).swap16().toString('utf16le');
56
+ }
57
+ return undefined;
58
+ }
59
+ function findInfoDict(latin) {
60
+ const ref = /\/Info\s+(\d+)\s+(\d+)\s+R/.exec(latin);
61
+ if (ref === null)
62
+ return null;
63
+ const objRe = new RegExp(`${ref[1]}\\s+${ref[2]}\\s+obj\\s*<<([\\s\\S]*?)>>`, 'm');
64
+ const m = objRe.exec(latin);
65
+ return m ? `<<${m[1]}>>` : null;
66
+ }
67
+ /**
68
+ * Structural signals from raw PDF bytes. Never throws — malformed input
69
+ * yields a `structure_unreadable` warning signal, not an exception.
70
+ */
71
+ function inspectPdfStructure(pdf, opts = {}) {
72
+ const signals = [];
73
+ const latin = Buffer.from(pdf).toString(LATIN1);
74
+ // ── Incremental updates ──────────────────────────────────────────────
75
+ const eofCount = (latin.match(/%%EOF/g) ?? []).length;
76
+ const xrefCount = (latin.match(/startxref/g) ?? []).length;
77
+ if (eofCount > 1 || xrefCount > 1) {
78
+ signals.push({
79
+ ruleId: 'pdf.incremental_update',
80
+ severity: 'warning',
81
+ message: `document carries ${Math.max(eofCount, xrefCount)} revision(s) — content was appended after generation`,
82
+ evidence: `%%EOF×${eofCount} startxref×${xrefCount}`,
83
+ });
84
+ }
85
+ // ── Producer / Creator / dates ───────────────────────────────────────
86
+ const infoDict = findInfoDict(latin);
87
+ const info = {
88
+ producer: undefined,
89
+ creator: undefined,
90
+ creationDate: undefined,
91
+ modDate: undefined,
92
+ };
93
+ if (infoDict !== null) {
94
+ info.producer = infoString(infoDict, 'Producer');
95
+ info.creator = infoString(infoDict, 'Creator');
96
+ info.creationDate = infoString(infoDict, 'CreationDate');
97
+ info.modDate = infoString(infoDict, 'ModDate');
98
+ }
99
+ for (const [key, value] of [
100
+ ['Producer', info.producer],
101
+ ['Creator', info.creator],
102
+ ]) {
103
+ if (value === undefined)
104
+ continue;
105
+ const editor = EDITOR_SIGNATURES.find((re) => re.test(value));
106
+ if (editor !== undefined) {
107
+ signals.push({
108
+ ruleId: 'pdf.editor_producer',
109
+ severity: 'critical',
110
+ message: `/${key} '${value}' is a consumer PDF editor — bank-generated statements do not carry this`,
111
+ evidence: `/${key} (${value})`,
112
+ });
113
+ }
114
+ }
115
+ // ModDate implies a post-generation save.
116
+ const createdIso = info.creationDate !== undefined ? pdfDateToIso(info.creationDate) : null;
117
+ const modifiedIso = info.modDate !== undefined ? pdfDateToIso(info.modDate) : null;
118
+ if (modifiedIso !== null && createdIso !== null && modifiedIso > createdIso) {
119
+ signals.push({
120
+ ruleId: 'pdf.modified_after_creation',
121
+ severity: 'warning',
122
+ message: `ModDate ${modifiedIso} is after CreationDate ${createdIso} — file was re-saved after generation`,
123
+ evidence: `CreationDate=${createdIso} ModDate=${modifiedIso}`,
124
+ });
125
+ }
126
+ if (opts.statementPeriodEnd != null &&
127
+ modifiedIso !== null &&
128
+ modifiedIso > opts.statementPeriodEnd &&
129
+ createdIso !== null &&
130
+ modifiedIso > createdIso) {
131
+ signals.push({
132
+ ruleId: 'pdf.modified_after_period',
133
+ severity: 'critical',
134
+ message: `file modified ${modifiedIso}, after the statement period ended ${opts.statementPeriodEnd}`,
135
+ evidence: `ModDate=${modifiedIso} periodEnd=${opts.statementPeriodEnd}`,
136
+ });
137
+ }
138
+ // ── Interactive overlays ─────────────────────────────────────────────
139
+ // AcroForm + signature fields are the normal carrier for signed
140
+ // statements — only suspicious when interactive fields exist with NO
141
+ // signature dict at all (fill-in overlays without signer evidence).
142
+ const sigFieldCount = (latin.match(/\/FT\s*\/Sig\b/g) ?? []).length;
143
+ const hasAcroForm = /\/AcroForm\b/.test(latin) || /\/SigFlags\s*\d/.test(latin);
144
+ if (hasAcroForm && sigFieldCount === 0 && !/\/Type\s*\/Sig\b/.test(latin)) {
145
+ signals.push({
146
+ ruleId: 'pdf.acroform_overlay',
147
+ severity: 'warning',
148
+ message: 'document carries interactive form fields but no signature — values can overlay or replace rendered text',
149
+ evidence: '/AcroForm present, /FT /Sig absent',
150
+ });
151
+ }
152
+ const annotCount = (latin.match(/\/Subtype\s*\/(?:FreeText|Stamp|Highlight|Squiggly|StrikeOut)/g) ?? []).length;
153
+ if (annotCount > 0) {
154
+ signals.push({
155
+ ruleId: 'pdf.covering_annotations',
156
+ severity: 'warning',
157
+ message: `${annotCount} markup annotation(s) can visually cover underlying statement text`,
158
+ evidence: `annotation subtypes ×${annotCount}`,
159
+ });
160
+ }
161
+ // ── Header sanity ────────────────────────────────────────────────────
162
+ if (!latin.startsWith('%PDF-')) {
163
+ signals.push({
164
+ ruleId: 'pdf.bad_header',
165
+ severity: 'warning',
166
+ message: 'file does not open with a %PDF- header',
167
+ evidence: `first bytes: ${latin.slice(0, 8)}`,
168
+ });
169
+ }
170
+ return signals;
171
+ }
172
+ //# sourceMappingURL=structure.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"structure.js","sourceRoot":"","sources":["../../src/pdf/structure.ts"],"names":[],"mappings":"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"}