@awacloud/pdf 0.0.0-stage → 1.0.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.
- package/CHANGELOG.md +609 -0
- package/LICENSE +661 -0
- package/NOTICE +77 -0
- package/README.md +363 -2
- package/dist/build/index.js +21 -0
- package/dist/build/pdf-full-rw.js +10972 -0
- package/dist/build/pdf-full-rw.meta.json +105 -0
- package/dist/build/pdf-full-rw.min.js +53 -0
- package/dist/build/pdf-full.js +6078 -0
- package/dist/build/pdf-full.meta.json +90 -0
- package/dist/build/pdf-full.min.js +32 -0
- package/dist/build/pdf-large-rw.js +10367 -0
- package/dist/build/pdf-large-rw.meta.json +99 -0
- package/dist/build/pdf-large-rw.min.js +53 -0
- package/dist/build/pdf-large.js +5473 -0
- package/dist/build/pdf-large.meta.json +84 -0
- package/dist/build/pdf-large.min.js +32 -0
- package/dist/build/pdf-legacy-rw.js +12402 -0
- package/dist/build/pdf-legacy-rw.meta.json +110 -0
- package/dist/build/pdf-legacy-rw.min.js +53 -0
- package/dist/build/pdf-legacy.js +7508 -0
- package/dist/build/pdf-legacy.meta.json +95 -0
- package/dist/build/pdf-legacy.min.js +32 -0
- package/dist/build/pdf-rw.js +7578 -0
- package/dist/build/pdf-rw.meta.json +77 -0
- package/dist/build/pdf-rw.min.js +53 -0
- package/dist/build/pdf.js +2684 -0
- package/dist/build/pdf.meta.json +62 -0
- package/dist/build/pdf.min.js +32 -0
- package/dist/standalone/pdf-full-rw.js +16798 -0
- package/dist/standalone/pdf-full-rw.meta.json +78 -0
- package/dist/standalone/pdf-full-rw.min.js +56 -0
- package/dist/standalone/pdf-full.js +11904 -0
- package/dist/standalone/pdf-full.meta.json +63 -0
- package/dist/standalone/pdf-full.min.js +35 -0
- package/dist/standalone/pdf-large-rw.js +16193 -0
- package/dist/standalone/pdf-large-rw.meta.json +72 -0
- package/dist/standalone/pdf-large-rw.min.js +56 -0
- package/dist/standalone/pdf-large.js +11299 -0
- package/dist/standalone/pdf-large.meta.json +57 -0
- package/dist/standalone/pdf-large.min.js +35 -0
- package/dist/standalone/pdf-legacy-rw.js +18228 -0
- package/dist/standalone/pdf-legacy-rw.meta.json +83 -0
- package/dist/standalone/pdf-legacy-rw.min.js +56 -0
- package/dist/standalone/pdf-legacy.js +13334 -0
- package/dist/standalone/pdf-legacy.meta.json +68 -0
- package/dist/standalone/pdf-legacy.min.js +35 -0
- package/dist/standalone/pdf-rw.js +13404 -0
- package/dist/standalone/pdf-rw.meta.json +50 -0
- package/dist/standalone/pdf-rw.min.js +56 -0
- package/dist/standalone/pdf.js +8510 -0
- package/dist/standalone/pdf.meta.json +35 -0
- package/dist/standalone/pdf.min.js +35 -0
- package/docs/README.md +53 -0
- package/docs/api/README.md +38 -0
- package/docs/api/_shared/README.md +91 -0
- package/docs/api/action/README.md +29 -0
- package/docs/api/action/action.md +81 -0
- package/docs/api/action/goTo.md +66 -0
- package/docs/api/action/launch.md +58 -0
- package/docs/api/action/named.md +55 -0
- package/docs/api/action/uri.md +54 -0
- package/docs/api/annot/README.md +53 -0
- package/docs/api/annot/annot.md +114 -0
- package/docs/api/annot/fileAttach.md +53 -0
- package/docs/api/annot/freeText.md +68 -0
- package/docs/api/annot/ink.md +69 -0
- package/docs/api/annot/link.md +74 -0
- package/docs/api/annot/markup.md +83 -0
- package/docs/api/annot/popup.md +52 -0
- package/docs/api/annot/projection.md +56 -0
- package/docs/api/annot/redact.md +67 -0
- package/docs/api/annot/square.md +87 -0
- package/docs/api/annot/stamp.md +54 -0
- package/docs/api/annot/text.md +69 -0
- package/docs/api/annot/widget.md +69 -0
- package/docs/api/associatedFiles/README.md +9 -0
- package/docs/api/associatedFiles/associatedFiles.md +78 -0
- package/docs/api/bundles/README.md +68 -0
- package/docs/api/bundles/dist-matrix.md +165 -0
- package/docs/api/bundles/pdf-full.md +148 -0
- package/docs/api/bundles/pdf-large.md +144 -0
- package/docs/api/bundles/pdf-legacy.md +169 -0
- package/docs/api/content/README.md +29 -0
- package/docs/api/content/color.md +99 -0
- package/docs/api/content/graphics.md +114 -0
- package/docs/api/content/images.md +124 -0
- package/docs/api/content/ops.md +100 -0
- package/docs/api/content/stream.md +107 -0
- package/docs/api/content/text.md +98 -0
- package/docs/api/crypto/README.md +29 -0
- package/docs/api/crypto/aesGcm.md +72 -0
- package/docs/api/crypto/permissions.md +79 -0
- package/docs/api/crypto/security.md +98 -0
- package/docs/api/crypto/standardV4.md +104 -0
- package/docs/api/crypto/standardV5.md +84 -0
- package/docs/api/crypto/standardV6.md +93 -0
- package/docs/api/destination/README.md +9 -0
- package/docs/api/destination/destination.md +79 -0
- package/docs/api/document/README.md +29 -0
- package/docs/api/document/builder.md +281 -0
- package/docs/api/document/catalog.md +98 -0
- package/docs/api/document/document.md +187 -0
- package/docs/api/document/encryptedWriter.md +149 -0
- package/docs/api/document/incrementalWriter.md +148 -0
- package/docs/api/document/page.md +99 -0
- package/docs/api/document/pages.md +82 -0
- package/docs/api/document/resources.md +102 -0
- package/docs/api/document/writer.md +157 -0
- package/docs/api/document/xrefStreamWriter.md +122 -0
- package/docs/api/embedded/README.md +13 -0
- package/docs/api/embedded/collection.md +80 -0
- package/docs/api/embedded/embeddedFile.md +86 -0
- package/docs/api/embedded/fileSpec.md +87 -0
- package/docs/api/errors.md +110 -0
- package/docs/api/extra/3d-richmedia.md +76 -0
- package/docs/api/extra/README.md +99 -0
- package/docs/api/extra/annot-extended.md +71 -0
- package/docs/api/extra/associated-files.md +70 -0
- package/docs/api/extra/ccitt-fax-decoder.md +74 -0
- package/docs/api/extra/color-spaces-extended.md +72 -0
- package/docs/api/extra/content-ops-extended.md +82 -0
- package/docs/api/extra/document-parts.md +69 -0
- package/docs/api/extra/embedded-files-portfolio.md +87 -0
- package/docs/api/extra/font-cid-typed.md +77 -0
- package/docs/api/extra/font-color-tagging.md +76 -0
- package/docs/api/extra/form-actions-extended.md +75 -0
- package/docs/api/extra/info-dict-deprecated.md +72 -0
- package/docs/api/extra/jbig2-read.md +80 -0
- package/docs/api/extra/legacy-deprecated-annots.md +89 -0
- package/docs/api/extra/legacy-deprecated-filters.md +78 -0
- package/docs/api/extra/legacy-rc4-read.md +74 -0
- package/docs/api/extra/legacy-xfa-read.md +65 -0
- package/docs/api/extra/linearization-write.md +71 -0
- package/docs/api/extra/misc.md +93 -0
- package/docs/api/extra/optional-content-extended.md +83 -0
- package/docs/api/extra/pdf-a-output-intent.md +65 -0
- package/docs/api/extra/pdf-sandbox.md +76 -0
- package/docs/api/extra/pdf-ua-tagged.md +63 -0
- package/docs/api/extra/pdf-x-prepress.md +65 -0
- package/docs/api/extra/redaction-iso32005.md +65 -0
- package/docs/api/extra/shading-typed.md +73 -0
- package/docs/api/extra/sig-aes-gcm.md +69 -0
- package/docs/api/extra/sig-pades.md +103 -0
- package/docs/api/extra/tagged-pdf-typed.md +78 -0
- package/docs/api/extra/transparency-typed.md +74 -0
- package/docs/api/extra/well-tagged-pdf.md +61 -0
- package/docs/api/extra/xmp-extended.md +65 -0
- package/docs/api/font/README.md +25 -0
- package/docs/api/font/embed.md +157 -0
- package/docs/api/font/encoding.md +95 -0
- package/docs/api/font/font.md +97 -0
- package/docs/api/font/type3.md +89 -0
- package/docs/api/form/README.md +35 -0
- package/docs/api/form/acroform.md +88 -0
- package/docs/api/form/appearance.md +87 -0
- package/docs/api/form/button.md +97 -0
- package/docs/api/form/choice.md +96 -0
- package/docs/api/form/fieldTree.md +93 -0
- package/docs/api/form/signature.md +90 -0
- package/docs/api/form/text.md +88 -0
- package/docs/api/linearization/README.md +11 -0
- package/docs/api/linearization/linearization.md +81 -0
- package/docs/api/main.md +116 -0
- package/docs/api/metadata/README.md +10 -0
- package/docs/api/metadata/info.md +70 -0
- package/docs/api/metadata/xmp.md +62 -0
- package/docs/api/ocg/README.md +23 -0
- package/docs/api/ocg/config.md +95 -0
- package/docs/api/ocg/ocg.md +77 -0
- package/docs/api/outline/README.md +11 -0
- package/docs/api/outline/outline.md +107 -0
- package/docs/api/pdf.md +152 -0
- package/docs/api/prepress/README.md +10 -0
- package/docs/api/prepress/outputIntent.md +79 -0
- package/docs/api/prepress/pageBoundary.md +75 -0
- package/docs/api/sig/README.md +32 -0
- package/docs/api/sig/byteRange.md +120 -0
- package/docs/api/sig/certChain.md +84 -0
- package/docs/api/sig/dss.md +111 -0
- package/docs/api/sig/oids.md +76 -0
- package/docs/api/sig/sha1.md +72 -0
- package/docs/api/sig/sign.md +317 -0
- package/docs/api/sig/signature.md +178 -0
- package/docs/api/sig/timestamp.md +84 -0
- package/docs/api/syntax/README.md +29 -0
- package/docs/api/syntax/crossRefStream.md +115 -0
- package/docs/api/syntax/filters/README.md +50 -0
- package/docs/api/syntax/filters/ascii85.md +76 -0
- package/docs/api/syntax/filters/asciiHex.md +73 -0
- package/docs/api/syntax/filters/dispatch.md +125 -0
- package/docs/api/syntax/filters/flate.md +134 -0
- package/docs/api/syntax/filters/runLength.md +78 -0
- package/docs/api/syntax/objStream.md +88 -0
- package/docs/api/syntax/parser-obj.md +97 -0
- package/docs/api/syntax/parser.md +151 -0
- package/docs/api/syntax/serializer.md +109 -0
- package/docs/api/syntax/tokenizer.md +104 -0
- package/docs/api/syntax/trailer.md +85 -0
- package/docs/api/syntax/xref.md +139 -0
- package/docs/api/tagged/README.md +25 -0
- package/docs/api/tagged/classMap.md +67 -0
- package/docs/api/tagged/markedContent.md +62 -0
- package/docs/api/tagged/parentTree.md +67 -0
- package/docs/api/tagged/roleMap.md +67 -0
- package/docs/api/tagged/structElement.md +76 -0
- package/docs/api/tagged/structTree.md +75 -0
- package/docs/guide/coverage.md +113 -0
- package/docs/guide/crypto.md +121 -0
- package/docs/guide/extending.md +76 -0
- package/docs/guide/getting-started.md +75 -0
- package/docs/guide/legacy-1.7.md +42 -0
- package/docs/guide/pades-integration.md +579 -0
- package/docs/guide/read-pdf.md +89 -0
- package/package.json +97 -4
- package/src/_shared/index.js +179 -0
- package/src/action/action.js +119 -0
- package/src/action/goTo.js +89 -0
- package/src/action/launch.js +61 -0
- package/src/action/named.js +54 -0
- package/src/action/uri.js +51 -0
- package/src/annot/annot.js +212 -0
- package/src/annot/fileAttach.js +55 -0
- package/src/annot/freeText.js +82 -0
- package/src/annot/ink.js +77 -0
- package/src/annot/link.js +77 -0
- package/src/annot/markup.js +91 -0
- package/src/annot/popup.js +53 -0
- package/src/annot/projection.js +52 -0
- package/src/annot/redact.js +87 -0
- package/src/annot/square.js +132 -0
- package/src/annot/stamp.js +48 -0
- package/src/annot/text.js +54 -0
- package/src/annot/widget.js +61 -0
- package/src/associatedFiles/associatedFiles.js +86 -0
- package/src/bundles/pdf-full.js +91 -0
- package/src/bundles/pdf-large.js +81 -0
- package/src/bundles/pdf-legacy.js +107 -0
- package/src/content/color.js +114 -0
- package/src/content/graphics.js +192 -0
- package/src/content/images.js +160 -0
- package/src/content/ops.js +137 -0
- package/src/content/stream.js +154 -0
- package/src/content/text.js +125 -0
- package/src/crypto/aesGcm.js +123 -0
- package/src/crypto/permissions.js +112 -0
- package/src/crypto/security.js +327 -0
- package/src/crypto/standardV4.js +443 -0
- package/src/crypto/standardV5.js +306 -0
- package/src/crypto/standardV6.js +334 -0
- package/src/destination/destination.js +183 -0
- package/src/document/builder.js +618 -0
- package/src/document/catalog.js +100 -0
- package/src/document/document.js +472 -0
- package/src/document/encryptedWriter.js +554 -0
- package/src/document/incrementalWriter.js +514 -0
- package/src/document/page.js +131 -0
- package/src/document/pages.js +103 -0
- package/src/document/resources.js +146 -0
- package/src/document/writer.js +211 -0
- package/src/document/xrefStreamWriter.js +353 -0
- package/src/embedded/collection.js +102 -0
- package/src/embedded/embeddedFile.js +99 -0
- package/src/embedded/fileSpec.js +137 -0
- package/src/errors.js +78 -0
- package/src/extra/3d-richmedia.js +171 -0
- package/src/extra/annot-extended.js +200 -0
- package/src/extra/associated-files.js +131 -0
- package/src/extra/ccitt-fax-decoder.js +776 -0
- package/src/extra/color-spaces-extended.js +196 -0
- package/src/extra/content-ops-extended.js +153 -0
- package/src/extra/document-parts.js +149 -0
- package/src/extra/embedded-files-portfolio.js +234 -0
- package/src/extra/font-cid-typed.js +185 -0
- package/src/extra/font-color-tagging.js +144 -0
- package/src/extra/form-actions-extended.js +196 -0
- package/src/extra/info-dict-deprecated.js +137 -0
- package/src/extra/jbig2-read.js +169 -0
- package/src/extra/legacy-deprecated-annots.js +198 -0
- package/src/extra/legacy-deprecated-filters.js +167 -0
- package/src/extra/legacy-rc4-read.js +235 -0
- package/src/extra/legacy-xfa-read.js +104 -0
- package/src/extra/linearization-write.js +97 -0
- package/src/extra/misc.js +217 -0
- package/src/extra/optional-content-extended.js +142 -0
- package/src/extra/pdf-a-output-intent.js +112 -0
- package/src/extra/pdf-sandbox.js +88 -0
- package/src/extra/pdf-ua-tagged.js +116 -0
- package/src/extra/pdf-x-prepress.js +114 -0
- package/src/extra/redaction-iso32005.js +136 -0
- package/src/extra/shading-typed.js +222 -0
- package/src/extra/sig-aes-gcm.js +135 -0
- package/src/extra/sig-pades.js +242 -0
- package/src/extra/tagged-pdf-typed.js +203 -0
- package/src/extra/transparency-typed.js +135 -0
- package/src/extra/well-tagged-pdf.js +138 -0
- package/src/extra/xmp-extended.js +190 -0
- package/src/font/embed.js +480 -0
- package/src/font/encoding.js +92 -0
- package/src/font/font.js +101 -0
- package/src/font/type3.js +75 -0
- package/src/form/acroform.js +94 -0
- package/src/form/appearance.js +90 -0
- package/src/form/button.js +105 -0
- package/src/form/choice.js +152 -0
- package/src/form/fieldTree.js +120 -0
- package/src/form/signature.js +100 -0
- package/src/form/text.js +101 -0
- package/src/linearization/linearization.js +107 -0
- package/src/main.js +411 -0
- package/src/metadata/info.js +87 -0
- package/src/metadata/xmp.js +62 -0
- package/src/ocg/config.js +156 -0
- package/src/ocg/ocg.js +124 -0
- package/src/outline/outline.js +157 -0
- package/src/pdf.js +133 -0
- package/src/prepress/outputIntent.js +118 -0
- package/src/prepress/pageBoundary.js +108 -0
- package/src/sig/byteRange.js +306 -0
- package/src/sig/certChain.js +247 -0
- package/src/sig/dss.js +317 -0
- package/src/sig/oids.js +157 -0
- package/src/sig/sha1.js +142 -0
- package/src/sig/sign.js +1899 -0
- package/src/sig/signature.js +1441 -0
- package/src/sig/timestamp.js +236 -0
- package/src/syntax/crossRefStream.js +133 -0
- package/src/syntax/filters/ascii85.js +122 -0
- package/src/syntax/filters/asciiHex.js +83 -0
- package/src/syntax/filters/dispatch.js +176 -0
- package/src/syntax/filters/flate.js +316 -0
- package/src/syntax/filters/runLength.js +96 -0
- package/src/syntax/objStream.js +99 -0
- package/src/syntax/parser-obj.js +52 -0
- package/src/syntax/parser.js +321 -0
- package/src/syntax/serializer.js +221 -0
- package/src/syntax/tokenizer.js +290 -0
- package/src/syntax/trailer.js +76 -0
- package/src/syntax/xref.js +341 -0
- package/src/tagged/classMap.js +81 -0
- package/src/tagged/markedContent.js +123 -0
- package/src/tagged/parentTree.js +126 -0
- package/src/tagged/roleMap.js +107 -0
- package/src/tagged/structElement.js +138 -0
- package/src/tagged/structTree.js +94 -0
|
@@ -0,0 +1,327 @@
|
|
|
1
|
+
// Copyright (c) 2026 AwaCloud SAS
|
|
2
|
+
// Author: Matthieu Bouilloux
|
|
3
|
+
// SPDX-License-Identifier: AGPL-3.0-only
|
|
4
|
+
// Dual-licensed; see the NOTICE file for licensing and any additional terms.
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* @fileoverview Security Handler dispatcher.
|
|
8
|
+
*
|
|
9
|
+
* The /Encrypt dictionary (ISO 32000-2:2020 §7.6.2) is parsed into a typed
|
|
10
|
+
* view via `typeEncryptDict`, then `selectHandler` dispatches to the
|
|
11
|
+
* v5/v6 Standard handler instance.
|
|
12
|
+
*
|
|
13
|
+
* @module pdf/crypto/security
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Module factory — worker-safe, self-contained.
|
|
18
|
+
*/
|
|
19
|
+
import { pdfErrors } from '../errors.js';
|
|
20
|
+
|
|
21
|
+
export const pdfSecurity = {
|
|
22
|
+
name: 'pdfSecurity',
|
|
23
|
+
dependencies: ['pdfErrors'],
|
|
24
|
+
deps: [pdfErrors],
|
|
25
|
+
factory(errors) {
|
|
26
|
+
const { EncryptionError } = errors;
|
|
27
|
+
|
|
28
|
+
function asUint8(v) {
|
|
29
|
+
if (v == null) return undefined;
|
|
30
|
+
if (v instanceof Uint8Array) return v;
|
|
31
|
+
if (typeof v === 'string') {
|
|
32
|
+
const out = new Uint8Array(v.length);
|
|
33
|
+
for (let i = 0; i < v.length; i++) out[i] = v.charCodeAt(i) & 0xff;
|
|
34
|
+
return out;
|
|
35
|
+
}
|
|
36
|
+
if (Array.isArray(v)) return new Uint8Array(v);
|
|
37
|
+
return undefined;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function typeEncryptDict(dict) {
|
|
41
|
+
if (dict == null || typeof dict !== 'object') {
|
|
42
|
+
throw new EncryptionError('pdf/crypto/encrypt-dict/bad-input',
|
|
43
|
+
'/Encrypt must be a dictionary');
|
|
44
|
+
}
|
|
45
|
+
const get = (k) => (dict instanceof Map ? dict.get(k) : dict[k]);
|
|
46
|
+
|
|
47
|
+
const V = get('V');
|
|
48
|
+
const R = get('R');
|
|
49
|
+
const Filter = get('Filter');
|
|
50
|
+
if (V === undefined || R === undefined) {
|
|
51
|
+
throw new EncryptionError('pdf/crypto/encrypt-dict/missing-V-R',
|
|
52
|
+
'/Encrypt requires both /V and /R',
|
|
53
|
+
{ context: { V, R } });
|
|
54
|
+
}
|
|
55
|
+
if (typeof V !== 'number' || typeof R !== 'number') {
|
|
56
|
+
throw new EncryptionError('pdf/crypto/encrypt-dict/bad-V-R-type',
|
|
57
|
+
'/V and /R must be integers',
|
|
58
|
+
{ context: { V, R } });
|
|
59
|
+
}
|
|
60
|
+
return {
|
|
61
|
+
V, R,
|
|
62
|
+
Filter,
|
|
63
|
+
SubFilter: get('SubFilter'),
|
|
64
|
+
Length: get('Length'),
|
|
65
|
+
CF: get('CF'),
|
|
66
|
+
StmF: get('StmF'),
|
|
67
|
+
StrF: get('StrF'),
|
|
68
|
+
EFF: get('EFF'),
|
|
69
|
+
O: asUint8(get('O')),
|
|
70
|
+
U: asUint8(get('U')),
|
|
71
|
+
OE: asUint8(get('OE')),
|
|
72
|
+
UE: asUint8(get('UE')),
|
|
73
|
+
Perms: asUint8(get('Perms')),
|
|
74
|
+
EncryptMetadata: get('EncryptMetadata') !== false,
|
|
75
|
+
P: get('P'),
|
|
76
|
+
raw: dict
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function nameValue(v) {
|
|
81
|
+
if (v == null) return null;
|
|
82
|
+
if (typeof v === 'string') return v;
|
|
83
|
+
if (typeof v === 'object' && v.type === 'name') return v.value;
|
|
84
|
+
return null;
|
|
85
|
+
}
|
|
86
|
+
function dictGet(d, key) {
|
|
87
|
+
if (d == null) return undefined;
|
|
88
|
+
if (d instanceof Map) return d.get(key);
|
|
89
|
+
if (typeof d === 'object' && d.type === 'dict' && d.entries) {
|
|
90
|
+
return d.entries[key];
|
|
91
|
+
}
|
|
92
|
+
if (typeof d === 'object') return d[key];
|
|
93
|
+
return undefined;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// Inspect `/CF /<StmF> /CFM` (StmF default name) to pick the
|
|
97
|
+
// V=4 method — either 'AESV2' or 'V2'. Also resolves /StrF and
|
|
98
|
+
// /EFF (embedded file filter, ISO 32000-1 §7.6.5).
|
|
99
|
+
function resolveV4Method(typedEncrypt) {
|
|
100
|
+
const stmFName = nameValue(typedEncrypt.StmF) || 'Identity';
|
|
101
|
+
const strFName = nameValue(typedEncrypt.StrF) || 'Identity';
|
|
102
|
+
const effName = nameValue(typedEncrypt.EFF) || stmFName;
|
|
103
|
+
let streamMethod;
|
|
104
|
+
if (stmFName === 'Identity') {
|
|
105
|
+
if (strFName === 'Identity') streamMethod = 'Identity';
|
|
106
|
+
else streamMethod = resolveCfmFor(typedEncrypt, strFName);
|
|
107
|
+
} else {
|
|
108
|
+
streamMethod = resolveCfmFor(typedEncrypt, stmFName);
|
|
109
|
+
}
|
|
110
|
+
const stringMethod = strFName === 'Identity'
|
|
111
|
+
? 'Identity'
|
|
112
|
+
: resolveCfmFor(typedEncrypt, strFName);
|
|
113
|
+
const embeddedFileMethod = effName === 'Identity'
|
|
114
|
+
? 'Identity'
|
|
115
|
+
: resolveCfmFor(typedEncrypt, effName);
|
|
116
|
+
return {
|
|
117
|
+
method: streamMethod,
|
|
118
|
+
strMethod: stringMethod,
|
|
119
|
+
effMethod: embeddedFileMethod
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
function resolveCfmFor(typedEncrypt, filterName) {
|
|
123
|
+
const cf = typedEncrypt.CF;
|
|
124
|
+
const entry = dictGet(cf, filterName);
|
|
125
|
+
if (!entry) {
|
|
126
|
+
throw new EncryptionError('pdf/crypto/v4/missing-cf-entry',
|
|
127
|
+
'V=4 requires /CF /' + filterName + ' entry',
|
|
128
|
+
{ context: { filterName } });
|
|
129
|
+
}
|
|
130
|
+
const cfm = nameValue(dictGet(entry, 'CFM'));
|
|
131
|
+
if (cfm !== 'AESV2' && cfm !== 'V2') {
|
|
132
|
+
throw new EncryptionError('pdf/crypto/v4/bad-cfm',
|
|
133
|
+
'V=4 CFM must be AESV2 or V2',
|
|
134
|
+
{ context: { cfm } });
|
|
135
|
+
}
|
|
136
|
+
return cfm;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
// For V=5 R=5/R=6: inspect /CF /<name> /CFM to detect AESV3
|
|
140
|
+
// (AES-256-CBC standard) vs AESV4 (AES-GCM, ISO/TS 32003).
|
|
141
|
+
//
|
|
142
|
+
// Identity rule (ISO 32000-2 §7.6.6, Table 20 defaults): a crypt
|
|
143
|
+
// filter named `Identity` leaves its class unencrypted, and an
|
|
144
|
+
// ABSENT /StmF or /StrF defaults to `Identity`. Each class resolves
|
|
145
|
+
// independently: streams (/StmF), strings (/StrF) and embedded
|
|
146
|
+
// files (/EFF, which defaults to /StmF when absent). An `Identity`
|
|
147
|
+
// class resolves to the method `'Identity'`, never to AESV3.
|
|
148
|
+
function resolveV5Method(typedEncrypt) {
|
|
149
|
+
const stmFName = nameValue(typedEncrypt.StmF) || 'Identity';
|
|
150
|
+
const strFName = nameValue(typedEncrypt.StrF) || 'Identity';
|
|
151
|
+
const effName = nameValue(typedEncrypt.EFF) || stmFName;
|
|
152
|
+
const streamMethod = stmFName === 'Identity'
|
|
153
|
+
? 'Identity'
|
|
154
|
+
: resolveCfmForV5(typedEncrypt, stmFName);
|
|
155
|
+
const stringMethod = strFName === 'Identity'
|
|
156
|
+
? 'Identity'
|
|
157
|
+
: resolveCfmForV5(typedEncrypt, strFName);
|
|
158
|
+
const embeddedFileMethod = effName === 'Identity'
|
|
159
|
+
? 'Identity'
|
|
160
|
+
: resolveCfmForV5(typedEncrypt, effName);
|
|
161
|
+
return {
|
|
162
|
+
method: streamMethod,
|
|
163
|
+
strMethod: stringMethod,
|
|
164
|
+
effMethod: embeddedFileMethod
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
function resolveCfmForV5(typedEncrypt, filterName) {
|
|
168
|
+
const cf = typedEncrypt.CF;
|
|
169
|
+
const entry = dictGet(cf, filterName);
|
|
170
|
+
if (!entry) {
|
|
171
|
+
// Default V=5 CFM = AESV3 when /CF is absent.
|
|
172
|
+
return 'AESV3';
|
|
173
|
+
}
|
|
174
|
+
const cfm = nameValue(dictGet(entry, 'CFM'));
|
|
175
|
+
if (cfm == null) return 'AESV3';
|
|
176
|
+
if (cfm !== 'AESV3' && cfm !== 'AESV4') {
|
|
177
|
+
throw new EncryptionError('pdf/crypto/v5/bad-cfm',
|
|
178
|
+
'V=5 CFM must be AESV3 or AESV4',
|
|
179
|
+
{ context: { cfm } });
|
|
180
|
+
}
|
|
181
|
+
return cfm;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
function selectHandler(typedEncrypt, handlers) {
|
|
185
|
+
if (!typedEncrypt || typeof typedEncrypt !== 'object') {
|
|
186
|
+
throw new EncryptionError('pdf/crypto/security/bad-typed',
|
|
187
|
+
'selectHandler requires a typed /Encrypt');
|
|
188
|
+
}
|
|
189
|
+
const { V, R } = typedEncrypt;
|
|
190
|
+
if (V < 4) {
|
|
191
|
+
throw new EncryptionError('pdf/crypto/unsupported-version',
|
|
192
|
+
'Security Handler V=' + V + ' is not supported at this level',
|
|
193
|
+
{ context: { V, R } });
|
|
194
|
+
}
|
|
195
|
+
if (V === 4) {
|
|
196
|
+
if (R !== 4) {
|
|
197
|
+
throw new EncryptionError('pdf/crypto/unsupported-version',
|
|
198
|
+
'Standard handler V=4 requires R=4',
|
|
199
|
+
{ context: { V, R } });
|
|
200
|
+
}
|
|
201
|
+
if (!handlers || !handlers.v4) {
|
|
202
|
+
throw new EncryptionError('pdf/crypto/missing-handler',
|
|
203
|
+
'no v4 handler provided');
|
|
204
|
+
}
|
|
205
|
+
const m = resolveV4Method(typedEncrypt);
|
|
206
|
+
return {
|
|
207
|
+
handler: handlers.v4, revision: 4,
|
|
208
|
+
method: m.method,
|
|
209
|
+
strMethod: m.strMethod,
|
|
210
|
+
effMethod: m.effMethod
|
|
211
|
+
};
|
|
212
|
+
}
|
|
213
|
+
if (V !== 5) {
|
|
214
|
+
throw new EncryptionError('pdf/crypto/unsupported-version',
|
|
215
|
+
'Security Handler V=' + V + ' is unknown',
|
|
216
|
+
{ context: { V, R } });
|
|
217
|
+
}
|
|
218
|
+
if (R === 5) {
|
|
219
|
+
if (!handlers || !handlers.v5) {
|
|
220
|
+
throw new EncryptionError('pdf/crypto/missing-handler',
|
|
221
|
+
'no v5 handler provided');
|
|
222
|
+
}
|
|
223
|
+
const m5 = resolveV5Method(typedEncrypt);
|
|
224
|
+
return {
|
|
225
|
+
handler: handlers.v5, revision: 5,
|
|
226
|
+
method: m5.method,
|
|
227
|
+
strMethod: m5.strMethod,
|
|
228
|
+
effMethod: m5.effMethod
|
|
229
|
+
};
|
|
230
|
+
}
|
|
231
|
+
if (R === 6) {
|
|
232
|
+
if (!handlers || !handlers.v6) {
|
|
233
|
+
throw new EncryptionError('pdf/crypto/missing-handler',
|
|
234
|
+
'no v6 handler provided');
|
|
235
|
+
}
|
|
236
|
+
const m6 = resolveV5Method(typedEncrypt);
|
|
237
|
+
return {
|
|
238
|
+
handler: handlers.v6, revision: 6,
|
|
239
|
+
method: m6.method,
|
|
240
|
+
strMethod: m6.strMethod,
|
|
241
|
+
effMethod: m6.effMethod
|
|
242
|
+
};
|
|
243
|
+
}
|
|
244
|
+
throw new EncryptionError('pdf/crypto/unsupported-version',
|
|
245
|
+
'Standard handler revision R=' + R + ' is not supported',
|
|
246
|
+
{ context: { V, R } });
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
// Read-side pipeline wire-up for /EFF (ISO 32000-1 §7.6.5).
|
|
250
|
+
//
|
|
251
|
+
// The standard handler exposes two stream wrappers:
|
|
252
|
+
// - decryptStream (uses selection.method = /StmF resolved CFM)
|
|
253
|
+
// - decryptEmbeddedFile (uses selection.effMethod = /EFF resolved CFM)
|
|
254
|
+
//
|
|
255
|
+
// `isEmbeddedFileStream(stream)` inspects the stream dict for
|
|
256
|
+
// `/Type /EmbeddedFile`. When true, the consumer MUST route via
|
|
257
|
+
// `decryptEmbeddedFile` with a typedEncrypt view whose `.method`
|
|
258
|
+
// is the resolved `effMethod`. Otherwise it routes via
|
|
259
|
+
// `decryptStream` with `.method = streamMethod`.
|
|
260
|
+
function isEmbeddedFileStream(stream) {
|
|
261
|
+
if (!stream || stream.type !== 'stream') return false;
|
|
262
|
+
const d = stream.dict;
|
|
263
|
+
if (!d || d.type !== 'dict' || !d.entries) return false;
|
|
264
|
+
const t = d.entries.Type;
|
|
265
|
+
if (!t) return false;
|
|
266
|
+
if (t.type === 'name') return t.value === 'EmbeddedFile';
|
|
267
|
+
if (typeof t === 'string') return t === 'EmbeddedFile';
|
|
268
|
+
return false;
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
// dispatchDecryptStream(selection, stream, fek, objNum, gen, ciphertext)
|
|
272
|
+
// selection : output of selectHandler({...}) — must carry
|
|
273
|
+
// { handler, method, effMethod }.
|
|
274
|
+
// stream : the typed PDF stream object (with .dict.entries),
|
|
275
|
+
// used to detect /Type /EmbeddedFile.
|
|
276
|
+
// fek, objNum, gen, ciphertext : per-object decryption inputs.
|
|
277
|
+
//
|
|
278
|
+
// Routes to handler.decryptEmbeddedFile (with method=effMethod)
|
|
279
|
+
// when the stream is an embedded file, otherwise to
|
|
280
|
+
// handler.decryptStream (with method=streamMethod).
|
|
281
|
+
//
|
|
282
|
+
// When the method about to be dispatched is `'Identity'` (the
|
|
283
|
+
// class is not encrypted, ISO 32000-2 §7.6.6), `ciphertext` is
|
|
284
|
+
// returned unchanged and no handler is called — on every revision
|
|
285
|
+
// (V=4, V=5 R=5, V=5 R=6). The standard handlers never see
|
|
286
|
+
// `'Identity'`.
|
|
287
|
+
function dispatchDecryptStream(selection, stream, fek, objNum, gen, ciphertext) {
|
|
288
|
+
if (!selection || typeof selection !== 'object'
|
|
289
|
+
|| !selection.handler) {
|
|
290
|
+
throw new EncryptionError('pdf/crypto/security/bad-selection',
|
|
291
|
+
'dispatchDecryptStream requires a selection from selectHandler');
|
|
292
|
+
}
|
|
293
|
+
const h = selection.handler;
|
|
294
|
+
const embedded = isEmbeddedFileStream(stream);
|
|
295
|
+
const active = embedded ? selection.effMethod : selection.method;
|
|
296
|
+
if (active === 'Identity') return ciphertext;
|
|
297
|
+
if (embedded) {
|
|
298
|
+
const typedView = { method: selection.effMethod };
|
|
299
|
+
// V=4 exposes a dedicated `decryptEmbeddedFile`; V=5/V=6
|
|
300
|
+
// do not — for those handlers `decryptStream` already
|
|
301
|
+
// dispatches purely on `typedView.method`, so routing
|
|
302
|
+
// through it with `method = effMethod` is equivalent.
|
|
303
|
+
if (typeof h.decryptEmbeddedFile === 'function') {
|
|
304
|
+
return h.decryptEmbeddedFile(
|
|
305
|
+
typedView, fek, objNum, gen, ciphertext);
|
|
306
|
+
}
|
|
307
|
+
if (typeof h.decryptStream === 'function') {
|
|
308
|
+
return h.decryptStream(
|
|
309
|
+
typedView, fek, objNum, gen, ciphertext);
|
|
310
|
+
}
|
|
311
|
+
throw new EncryptionError('pdf/crypto/security/no-eff',
|
|
312
|
+
'selected handler lacks decryptEmbeddedFile and decryptStream');
|
|
313
|
+
}
|
|
314
|
+
if (typeof h.decryptStream !== 'function') {
|
|
315
|
+
throw new EncryptionError('pdf/crypto/security/no-stream',
|
|
316
|
+
'selected handler lacks decryptStream');
|
|
317
|
+
}
|
|
318
|
+
const typedView = { method: selection.method };
|
|
319
|
+
return h.decryptStream(typedView, fek, objNum, gen, ciphertext);
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
return {
|
|
323
|
+
typeEncryptDict, selectHandler,
|
|
324
|
+
isEmbeddedFileStream, dispatchDecryptStream
|
|
325
|
+
};
|
|
326
|
+
}
|
|
327
|
+
};
|