@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.
Files changed (345) hide show
  1. package/CHANGELOG.md +609 -0
  2. package/LICENSE +661 -0
  3. package/NOTICE +77 -0
  4. package/README.md +363 -2
  5. package/dist/build/index.js +21 -0
  6. package/dist/build/pdf-full-rw.js +10972 -0
  7. package/dist/build/pdf-full-rw.meta.json +105 -0
  8. package/dist/build/pdf-full-rw.min.js +53 -0
  9. package/dist/build/pdf-full.js +6078 -0
  10. package/dist/build/pdf-full.meta.json +90 -0
  11. package/dist/build/pdf-full.min.js +32 -0
  12. package/dist/build/pdf-large-rw.js +10367 -0
  13. package/dist/build/pdf-large-rw.meta.json +99 -0
  14. package/dist/build/pdf-large-rw.min.js +53 -0
  15. package/dist/build/pdf-large.js +5473 -0
  16. package/dist/build/pdf-large.meta.json +84 -0
  17. package/dist/build/pdf-large.min.js +32 -0
  18. package/dist/build/pdf-legacy-rw.js +12402 -0
  19. package/dist/build/pdf-legacy-rw.meta.json +110 -0
  20. package/dist/build/pdf-legacy-rw.min.js +53 -0
  21. package/dist/build/pdf-legacy.js +7508 -0
  22. package/dist/build/pdf-legacy.meta.json +95 -0
  23. package/dist/build/pdf-legacy.min.js +32 -0
  24. package/dist/build/pdf-rw.js +7578 -0
  25. package/dist/build/pdf-rw.meta.json +77 -0
  26. package/dist/build/pdf-rw.min.js +53 -0
  27. package/dist/build/pdf.js +2684 -0
  28. package/dist/build/pdf.meta.json +62 -0
  29. package/dist/build/pdf.min.js +32 -0
  30. package/dist/standalone/pdf-full-rw.js +16798 -0
  31. package/dist/standalone/pdf-full-rw.meta.json +78 -0
  32. package/dist/standalone/pdf-full-rw.min.js +56 -0
  33. package/dist/standalone/pdf-full.js +11904 -0
  34. package/dist/standalone/pdf-full.meta.json +63 -0
  35. package/dist/standalone/pdf-full.min.js +35 -0
  36. package/dist/standalone/pdf-large-rw.js +16193 -0
  37. package/dist/standalone/pdf-large-rw.meta.json +72 -0
  38. package/dist/standalone/pdf-large-rw.min.js +56 -0
  39. package/dist/standalone/pdf-large.js +11299 -0
  40. package/dist/standalone/pdf-large.meta.json +57 -0
  41. package/dist/standalone/pdf-large.min.js +35 -0
  42. package/dist/standalone/pdf-legacy-rw.js +18228 -0
  43. package/dist/standalone/pdf-legacy-rw.meta.json +83 -0
  44. package/dist/standalone/pdf-legacy-rw.min.js +56 -0
  45. package/dist/standalone/pdf-legacy.js +13334 -0
  46. package/dist/standalone/pdf-legacy.meta.json +68 -0
  47. package/dist/standalone/pdf-legacy.min.js +35 -0
  48. package/dist/standalone/pdf-rw.js +13404 -0
  49. package/dist/standalone/pdf-rw.meta.json +50 -0
  50. package/dist/standalone/pdf-rw.min.js +56 -0
  51. package/dist/standalone/pdf.js +8510 -0
  52. package/dist/standalone/pdf.meta.json +35 -0
  53. package/dist/standalone/pdf.min.js +35 -0
  54. package/docs/README.md +53 -0
  55. package/docs/api/README.md +38 -0
  56. package/docs/api/_shared/README.md +91 -0
  57. package/docs/api/action/README.md +29 -0
  58. package/docs/api/action/action.md +81 -0
  59. package/docs/api/action/goTo.md +66 -0
  60. package/docs/api/action/launch.md +58 -0
  61. package/docs/api/action/named.md +55 -0
  62. package/docs/api/action/uri.md +54 -0
  63. package/docs/api/annot/README.md +53 -0
  64. package/docs/api/annot/annot.md +114 -0
  65. package/docs/api/annot/fileAttach.md +53 -0
  66. package/docs/api/annot/freeText.md +68 -0
  67. package/docs/api/annot/ink.md +69 -0
  68. package/docs/api/annot/link.md +74 -0
  69. package/docs/api/annot/markup.md +83 -0
  70. package/docs/api/annot/popup.md +52 -0
  71. package/docs/api/annot/projection.md +56 -0
  72. package/docs/api/annot/redact.md +67 -0
  73. package/docs/api/annot/square.md +87 -0
  74. package/docs/api/annot/stamp.md +54 -0
  75. package/docs/api/annot/text.md +69 -0
  76. package/docs/api/annot/widget.md +69 -0
  77. package/docs/api/associatedFiles/README.md +9 -0
  78. package/docs/api/associatedFiles/associatedFiles.md +78 -0
  79. package/docs/api/bundles/README.md +68 -0
  80. package/docs/api/bundles/dist-matrix.md +165 -0
  81. package/docs/api/bundles/pdf-full.md +148 -0
  82. package/docs/api/bundles/pdf-large.md +144 -0
  83. package/docs/api/bundles/pdf-legacy.md +169 -0
  84. package/docs/api/content/README.md +29 -0
  85. package/docs/api/content/color.md +99 -0
  86. package/docs/api/content/graphics.md +114 -0
  87. package/docs/api/content/images.md +124 -0
  88. package/docs/api/content/ops.md +100 -0
  89. package/docs/api/content/stream.md +107 -0
  90. package/docs/api/content/text.md +98 -0
  91. package/docs/api/crypto/README.md +29 -0
  92. package/docs/api/crypto/aesGcm.md +72 -0
  93. package/docs/api/crypto/permissions.md +79 -0
  94. package/docs/api/crypto/security.md +98 -0
  95. package/docs/api/crypto/standardV4.md +104 -0
  96. package/docs/api/crypto/standardV5.md +84 -0
  97. package/docs/api/crypto/standardV6.md +93 -0
  98. package/docs/api/destination/README.md +9 -0
  99. package/docs/api/destination/destination.md +79 -0
  100. package/docs/api/document/README.md +29 -0
  101. package/docs/api/document/builder.md +281 -0
  102. package/docs/api/document/catalog.md +98 -0
  103. package/docs/api/document/document.md +187 -0
  104. package/docs/api/document/encryptedWriter.md +149 -0
  105. package/docs/api/document/incrementalWriter.md +148 -0
  106. package/docs/api/document/page.md +99 -0
  107. package/docs/api/document/pages.md +82 -0
  108. package/docs/api/document/resources.md +102 -0
  109. package/docs/api/document/writer.md +157 -0
  110. package/docs/api/document/xrefStreamWriter.md +122 -0
  111. package/docs/api/embedded/README.md +13 -0
  112. package/docs/api/embedded/collection.md +80 -0
  113. package/docs/api/embedded/embeddedFile.md +86 -0
  114. package/docs/api/embedded/fileSpec.md +87 -0
  115. package/docs/api/errors.md +110 -0
  116. package/docs/api/extra/3d-richmedia.md +76 -0
  117. package/docs/api/extra/README.md +99 -0
  118. package/docs/api/extra/annot-extended.md +71 -0
  119. package/docs/api/extra/associated-files.md +70 -0
  120. package/docs/api/extra/ccitt-fax-decoder.md +74 -0
  121. package/docs/api/extra/color-spaces-extended.md +72 -0
  122. package/docs/api/extra/content-ops-extended.md +82 -0
  123. package/docs/api/extra/document-parts.md +69 -0
  124. package/docs/api/extra/embedded-files-portfolio.md +87 -0
  125. package/docs/api/extra/font-cid-typed.md +77 -0
  126. package/docs/api/extra/font-color-tagging.md +76 -0
  127. package/docs/api/extra/form-actions-extended.md +75 -0
  128. package/docs/api/extra/info-dict-deprecated.md +72 -0
  129. package/docs/api/extra/jbig2-read.md +80 -0
  130. package/docs/api/extra/legacy-deprecated-annots.md +89 -0
  131. package/docs/api/extra/legacy-deprecated-filters.md +78 -0
  132. package/docs/api/extra/legacy-rc4-read.md +74 -0
  133. package/docs/api/extra/legacy-xfa-read.md +65 -0
  134. package/docs/api/extra/linearization-write.md +71 -0
  135. package/docs/api/extra/misc.md +93 -0
  136. package/docs/api/extra/optional-content-extended.md +83 -0
  137. package/docs/api/extra/pdf-a-output-intent.md +65 -0
  138. package/docs/api/extra/pdf-sandbox.md +76 -0
  139. package/docs/api/extra/pdf-ua-tagged.md +63 -0
  140. package/docs/api/extra/pdf-x-prepress.md +65 -0
  141. package/docs/api/extra/redaction-iso32005.md +65 -0
  142. package/docs/api/extra/shading-typed.md +73 -0
  143. package/docs/api/extra/sig-aes-gcm.md +69 -0
  144. package/docs/api/extra/sig-pades.md +103 -0
  145. package/docs/api/extra/tagged-pdf-typed.md +78 -0
  146. package/docs/api/extra/transparency-typed.md +74 -0
  147. package/docs/api/extra/well-tagged-pdf.md +61 -0
  148. package/docs/api/extra/xmp-extended.md +65 -0
  149. package/docs/api/font/README.md +25 -0
  150. package/docs/api/font/embed.md +157 -0
  151. package/docs/api/font/encoding.md +95 -0
  152. package/docs/api/font/font.md +97 -0
  153. package/docs/api/font/type3.md +89 -0
  154. package/docs/api/form/README.md +35 -0
  155. package/docs/api/form/acroform.md +88 -0
  156. package/docs/api/form/appearance.md +87 -0
  157. package/docs/api/form/button.md +97 -0
  158. package/docs/api/form/choice.md +96 -0
  159. package/docs/api/form/fieldTree.md +93 -0
  160. package/docs/api/form/signature.md +90 -0
  161. package/docs/api/form/text.md +88 -0
  162. package/docs/api/linearization/README.md +11 -0
  163. package/docs/api/linearization/linearization.md +81 -0
  164. package/docs/api/main.md +116 -0
  165. package/docs/api/metadata/README.md +10 -0
  166. package/docs/api/metadata/info.md +70 -0
  167. package/docs/api/metadata/xmp.md +62 -0
  168. package/docs/api/ocg/README.md +23 -0
  169. package/docs/api/ocg/config.md +95 -0
  170. package/docs/api/ocg/ocg.md +77 -0
  171. package/docs/api/outline/README.md +11 -0
  172. package/docs/api/outline/outline.md +107 -0
  173. package/docs/api/pdf.md +152 -0
  174. package/docs/api/prepress/README.md +10 -0
  175. package/docs/api/prepress/outputIntent.md +79 -0
  176. package/docs/api/prepress/pageBoundary.md +75 -0
  177. package/docs/api/sig/README.md +32 -0
  178. package/docs/api/sig/byteRange.md +120 -0
  179. package/docs/api/sig/certChain.md +84 -0
  180. package/docs/api/sig/dss.md +111 -0
  181. package/docs/api/sig/oids.md +76 -0
  182. package/docs/api/sig/sha1.md +72 -0
  183. package/docs/api/sig/sign.md +317 -0
  184. package/docs/api/sig/signature.md +178 -0
  185. package/docs/api/sig/timestamp.md +84 -0
  186. package/docs/api/syntax/README.md +29 -0
  187. package/docs/api/syntax/crossRefStream.md +115 -0
  188. package/docs/api/syntax/filters/README.md +50 -0
  189. package/docs/api/syntax/filters/ascii85.md +76 -0
  190. package/docs/api/syntax/filters/asciiHex.md +73 -0
  191. package/docs/api/syntax/filters/dispatch.md +125 -0
  192. package/docs/api/syntax/filters/flate.md +134 -0
  193. package/docs/api/syntax/filters/runLength.md +78 -0
  194. package/docs/api/syntax/objStream.md +88 -0
  195. package/docs/api/syntax/parser-obj.md +97 -0
  196. package/docs/api/syntax/parser.md +151 -0
  197. package/docs/api/syntax/serializer.md +109 -0
  198. package/docs/api/syntax/tokenizer.md +104 -0
  199. package/docs/api/syntax/trailer.md +85 -0
  200. package/docs/api/syntax/xref.md +139 -0
  201. package/docs/api/tagged/README.md +25 -0
  202. package/docs/api/tagged/classMap.md +67 -0
  203. package/docs/api/tagged/markedContent.md +62 -0
  204. package/docs/api/tagged/parentTree.md +67 -0
  205. package/docs/api/tagged/roleMap.md +67 -0
  206. package/docs/api/tagged/structElement.md +76 -0
  207. package/docs/api/tagged/structTree.md +75 -0
  208. package/docs/guide/coverage.md +113 -0
  209. package/docs/guide/crypto.md +121 -0
  210. package/docs/guide/extending.md +76 -0
  211. package/docs/guide/getting-started.md +75 -0
  212. package/docs/guide/legacy-1.7.md +42 -0
  213. package/docs/guide/pades-integration.md +579 -0
  214. package/docs/guide/read-pdf.md +89 -0
  215. package/package.json +97 -4
  216. package/src/_shared/index.js +179 -0
  217. package/src/action/action.js +119 -0
  218. package/src/action/goTo.js +89 -0
  219. package/src/action/launch.js +61 -0
  220. package/src/action/named.js +54 -0
  221. package/src/action/uri.js +51 -0
  222. package/src/annot/annot.js +212 -0
  223. package/src/annot/fileAttach.js +55 -0
  224. package/src/annot/freeText.js +82 -0
  225. package/src/annot/ink.js +77 -0
  226. package/src/annot/link.js +77 -0
  227. package/src/annot/markup.js +91 -0
  228. package/src/annot/popup.js +53 -0
  229. package/src/annot/projection.js +52 -0
  230. package/src/annot/redact.js +87 -0
  231. package/src/annot/square.js +132 -0
  232. package/src/annot/stamp.js +48 -0
  233. package/src/annot/text.js +54 -0
  234. package/src/annot/widget.js +61 -0
  235. package/src/associatedFiles/associatedFiles.js +86 -0
  236. package/src/bundles/pdf-full.js +91 -0
  237. package/src/bundles/pdf-large.js +81 -0
  238. package/src/bundles/pdf-legacy.js +107 -0
  239. package/src/content/color.js +114 -0
  240. package/src/content/graphics.js +192 -0
  241. package/src/content/images.js +160 -0
  242. package/src/content/ops.js +137 -0
  243. package/src/content/stream.js +154 -0
  244. package/src/content/text.js +125 -0
  245. package/src/crypto/aesGcm.js +123 -0
  246. package/src/crypto/permissions.js +112 -0
  247. package/src/crypto/security.js +327 -0
  248. package/src/crypto/standardV4.js +443 -0
  249. package/src/crypto/standardV5.js +306 -0
  250. package/src/crypto/standardV6.js +334 -0
  251. package/src/destination/destination.js +183 -0
  252. package/src/document/builder.js +618 -0
  253. package/src/document/catalog.js +100 -0
  254. package/src/document/document.js +472 -0
  255. package/src/document/encryptedWriter.js +554 -0
  256. package/src/document/incrementalWriter.js +514 -0
  257. package/src/document/page.js +131 -0
  258. package/src/document/pages.js +103 -0
  259. package/src/document/resources.js +146 -0
  260. package/src/document/writer.js +211 -0
  261. package/src/document/xrefStreamWriter.js +353 -0
  262. package/src/embedded/collection.js +102 -0
  263. package/src/embedded/embeddedFile.js +99 -0
  264. package/src/embedded/fileSpec.js +137 -0
  265. package/src/errors.js +78 -0
  266. package/src/extra/3d-richmedia.js +171 -0
  267. package/src/extra/annot-extended.js +200 -0
  268. package/src/extra/associated-files.js +131 -0
  269. package/src/extra/ccitt-fax-decoder.js +776 -0
  270. package/src/extra/color-spaces-extended.js +196 -0
  271. package/src/extra/content-ops-extended.js +153 -0
  272. package/src/extra/document-parts.js +149 -0
  273. package/src/extra/embedded-files-portfolio.js +234 -0
  274. package/src/extra/font-cid-typed.js +185 -0
  275. package/src/extra/font-color-tagging.js +144 -0
  276. package/src/extra/form-actions-extended.js +196 -0
  277. package/src/extra/info-dict-deprecated.js +137 -0
  278. package/src/extra/jbig2-read.js +169 -0
  279. package/src/extra/legacy-deprecated-annots.js +198 -0
  280. package/src/extra/legacy-deprecated-filters.js +167 -0
  281. package/src/extra/legacy-rc4-read.js +235 -0
  282. package/src/extra/legacy-xfa-read.js +104 -0
  283. package/src/extra/linearization-write.js +97 -0
  284. package/src/extra/misc.js +217 -0
  285. package/src/extra/optional-content-extended.js +142 -0
  286. package/src/extra/pdf-a-output-intent.js +112 -0
  287. package/src/extra/pdf-sandbox.js +88 -0
  288. package/src/extra/pdf-ua-tagged.js +116 -0
  289. package/src/extra/pdf-x-prepress.js +114 -0
  290. package/src/extra/redaction-iso32005.js +136 -0
  291. package/src/extra/shading-typed.js +222 -0
  292. package/src/extra/sig-aes-gcm.js +135 -0
  293. package/src/extra/sig-pades.js +242 -0
  294. package/src/extra/tagged-pdf-typed.js +203 -0
  295. package/src/extra/transparency-typed.js +135 -0
  296. package/src/extra/well-tagged-pdf.js +138 -0
  297. package/src/extra/xmp-extended.js +190 -0
  298. package/src/font/embed.js +480 -0
  299. package/src/font/encoding.js +92 -0
  300. package/src/font/font.js +101 -0
  301. package/src/font/type3.js +75 -0
  302. package/src/form/acroform.js +94 -0
  303. package/src/form/appearance.js +90 -0
  304. package/src/form/button.js +105 -0
  305. package/src/form/choice.js +152 -0
  306. package/src/form/fieldTree.js +120 -0
  307. package/src/form/signature.js +100 -0
  308. package/src/form/text.js +101 -0
  309. package/src/linearization/linearization.js +107 -0
  310. package/src/main.js +411 -0
  311. package/src/metadata/info.js +87 -0
  312. package/src/metadata/xmp.js +62 -0
  313. package/src/ocg/config.js +156 -0
  314. package/src/ocg/ocg.js +124 -0
  315. package/src/outline/outline.js +157 -0
  316. package/src/pdf.js +133 -0
  317. package/src/prepress/outputIntent.js +118 -0
  318. package/src/prepress/pageBoundary.js +108 -0
  319. package/src/sig/byteRange.js +306 -0
  320. package/src/sig/certChain.js +247 -0
  321. package/src/sig/dss.js +317 -0
  322. package/src/sig/oids.js +157 -0
  323. package/src/sig/sha1.js +142 -0
  324. package/src/sig/sign.js +1899 -0
  325. package/src/sig/signature.js +1441 -0
  326. package/src/sig/timestamp.js +236 -0
  327. package/src/syntax/crossRefStream.js +133 -0
  328. package/src/syntax/filters/ascii85.js +122 -0
  329. package/src/syntax/filters/asciiHex.js +83 -0
  330. package/src/syntax/filters/dispatch.js +176 -0
  331. package/src/syntax/filters/flate.js +316 -0
  332. package/src/syntax/filters/runLength.js +96 -0
  333. package/src/syntax/objStream.js +99 -0
  334. package/src/syntax/parser-obj.js +52 -0
  335. package/src/syntax/parser.js +321 -0
  336. package/src/syntax/serializer.js +221 -0
  337. package/src/syntax/tokenizer.js +290 -0
  338. package/src/syntax/trailer.js +76 -0
  339. package/src/syntax/xref.js +341 -0
  340. package/src/tagged/classMap.js +81 -0
  341. package/src/tagged/markedContent.js +123 -0
  342. package/src/tagged/parentTree.js +126 -0
  343. package/src/tagged/roleMap.js +107 -0
  344. package/src/tagged/structElement.js +138 -0
  345. 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
+ };