@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,135 @@
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 Opt-in: AES-GCM crypt filter wrapper for `/Encrypt`
8
+ * dictionaries — ISO/TS 32003.
9
+ *
10
+ * @module pdf/extra/sig-aes-gcm
11
+ */
12
+
13
+ /**
14
+ * Module factory.
15
+ */
16
+ import { pdfErrors } from '../errors.js';
17
+ import { pdfParser } from '../syntax/parser.js';
18
+
19
+ export const pdfSigAesGcm = {
20
+ name: 'pdfSigAesGcm',
21
+ dependencies: ['pdfErrors', 'pdfParser'],
22
+ deps: [pdfErrors, pdfParser],
23
+ factory(errors, parser) {
24
+ const { ParseError, EncryptionError } = errors;
25
+ const { isType } = parser;
26
+
27
+ /** Frozen catalog of known Crypt Filter Methods (CFM names). */
28
+ const CFM_CATALOG = Object.freeze({
29
+ None: { cipher: 'none', keyBits: 0, notes: 'identity / stream-as-is' },
30
+ V2: { cipher: 'rc4', keyBits: 40, notes: 'legacy RC4 (deprecated)' },
31
+ AESV2: { cipher: 'aes', keyBits: 128, mode: 'cbc',
32
+ notes: 'AES-128 CBC (R4)' },
33
+ AESV3: { cipher: 'aes', keyBits: 256, mode: 'cbc',
34
+ notes: 'AES-256 CBC (R6, ISO 32000-2)' },
35
+ AESV4: { cipher: 'aes', keyBits: 256, mode: 'gcm',
36
+ notes: 'AES-256 GCM (ISO/TS 32003)' }
37
+ });
38
+
39
+ const ENCRYPT_KNOWN = new Set([
40
+ 'Filter', 'SubFilter', 'V', 'Length', 'CF', 'StmF', 'StrF', 'EFF',
41
+ 'R', 'O', 'U', 'OE', 'UE', 'Perms', 'P', 'EncryptMetadata'
42
+ ]);
43
+ const CF_ENTRY_KNOWN = new Set(['Type', 'CFM', 'AuthEvent', 'Length']);
44
+
45
+ function typeEncryptForGcm(dict) {
46
+ if (!isType(dict, 'dict')) {
47
+ throw new ParseError('pdf/extra/sig-aes-gcm/not-dict',
48
+ '/Encrypt must be a dictionary',
49
+ { context: { type: dict && dict.type } });
50
+ }
51
+ const e = dict.entries;
52
+ const out = {
53
+ v: isType(e.V, 'int') ? e.V.value : null,
54
+ r: isType(e.R, 'int') ? e.R.value : null,
55
+ length: isType(e.Length, 'int') ? e.Length.value : null,
56
+ stmF: isType(e.StmF, 'name') ? e.StmF.value : null,
57
+ strF: isType(e.StrF, 'name') ? e.StrF.value : null,
58
+ eff: isType(e.EFF, 'name') ? e.EFF.value : null,
59
+ cf: {},
60
+ hasAesGcm: false,
61
+ raw: dict,
62
+ _extras: {}
63
+ };
64
+ if (e.CF !== undefined) {
65
+ if (!isType(e.CF, 'dict')) {
66
+ throw new ParseError('pdf/extra/sig-aes-gcm/bad-cf',
67
+ '/CF must be a dictionary',
68
+ { context: { type: e.CF.type } });
69
+ }
70
+ for (const name of Object.keys(e.CF.entries)) {
71
+ const entry = e.CF.entries[name];
72
+ if (!isType(entry, 'dict')) {
73
+ throw new ParseError('pdf/extra/sig-aes-gcm/bad-cf-entry',
74
+ '/CF entry must be a dictionary',
75
+ { context: { name } });
76
+ }
77
+ out.cf[name] = typeCfEntry(entry);
78
+ if (out.cf[name].cfm === 'AESV4') out.hasAesGcm = true;
79
+ }
80
+ }
81
+ for (const k of Object.keys(e)) {
82
+ if (!ENCRYPT_KNOWN.has(k)) out._extras[k] = e[k];
83
+ }
84
+ return out;
85
+ }
86
+
87
+ function typeCfEntry(dict) {
88
+ if (!isType(dict, 'dict')) {
89
+ throw new ParseError('pdf/extra/sig-aes-gcm/cf-entry-not-dict',
90
+ 'CF entry must be a dictionary',
91
+ { context: { type: dict && dict.type } });
92
+ }
93
+ const e = dict.entries;
94
+ const cfm = isType(e.CFM, 'name') ? e.CFM.value : null;
95
+ const out = {
96
+ cfm,
97
+ authEvent: isType(e.AuthEvent, 'name') ? e.AuthEvent.value : null,
98
+ length: isType(e.Length, 'int') ? e.Length.value : null,
99
+ catalog: cfm && CFM_CATALOG[cfm] ? CFM_CATALOG[cfm] : null,
100
+ raw: dict,
101
+ _extras: {}
102
+ };
103
+ for (const k of Object.keys(e)) {
104
+ if (!CF_ENTRY_KNOWN.has(k)) out._extras[k] = e[k];
105
+ }
106
+ return out;
107
+ }
108
+
109
+ function validateGcmFraming(framed) {
110
+ if (!(framed instanceof Uint8Array)) {
111
+ throw new EncryptionError('pdf/extra/sig-aes-gcm/bad-input',
112
+ 'framed input must be a Uint8Array',
113
+ { context: { type: typeof framed } });
114
+ }
115
+ if (framed.length < 12 + 16) {
116
+ throw new EncryptionError('pdf/extra/sig-aes-gcm/too-short',
117
+ 'AES-GCM framed blob must be at least 28 bytes (IV+tag)',
118
+ { context: { length: framed.length } });
119
+ }
120
+ return {
121
+ iv: framed.subarray(0, 12),
122
+ ciphertext: framed.subarray(12, framed.length - 16),
123
+ tag: framed.subarray(framed.length - 16)
124
+ };
125
+ }
126
+
127
+ return {
128
+ typeEncryptForGcm,
129
+ typeCfEntry,
130
+ validateGcmFraming,
131
+ CFM_CATALOG
132
+ };
133
+ }
134
+ };
135
+
@@ -0,0 +1,242 @@
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 Opt-in: PAdES (ETSI EN 319 142-1) profile detection
8
+ * for signature dicts, `/Reference` array typing, and DSS (Document
9
+ * Security Store) dict typing per ISO 32000-2:2020 §12.8.4.3.
10
+ *
11
+ * @module pdf/extra/sig-pades
12
+ */
13
+
14
+ /**
15
+ * Module factory.
16
+ */
17
+ import { pdfErrors } from '../errors.js';
18
+ import { pdfParser } from '../syntax/parser.js';
19
+
20
+ export const pdfSigPades = {
21
+ name: 'pdfSigPades',
22
+ dependencies: ['pdfErrors', 'pdfParser'],
23
+ deps: [pdfErrors, pdfParser],
24
+ factory(errors, parser) {
25
+ const { ParseError } = errors;
26
+ const { isType } = parser;
27
+
28
+ /** Frozen catalog of recognized signature SubFilter names. */
29
+ const SIG_SUBFILTERS = Object.freeze({
30
+ 'adbe.x509.rsa_sha1': { pades: false, kind: 'legacy' },
31
+ 'adbe.pkcs7.sha1': { pades: false, kind: 'legacy' },
32
+ 'adbe.pkcs7.detached': { pades: false, kind: 'pkcs7-detached' },
33
+ 'ETSI.CAdES.detached': { pades: true, kind: 'pades-cades' },
34
+ 'ETSI.RFC3161': { pades: true, kind: 'doc-timestamp' }
35
+ });
36
+
37
+ function detectPadesProfile(sigDict, ctx) {
38
+ if (!isType(sigDict, 'dict')) {
39
+ throw new ParseError('pdf/extra/pades/not-dict',
40
+ 'signature dict must be a dictionary',
41
+ { context: { type: sigDict && sigDict.type } });
42
+ }
43
+ const e = sigDict.entries;
44
+ const sf = isType(e.SubFilter, 'name') ? e.SubFilter.value : null;
45
+ const info = sf ? SIG_SUBFILTERS[sf] : null;
46
+ const isPades = !!(info && info.pades);
47
+ const hasTimestamp = !!(
48
+ sf === 'ETSI.RFC3161' ||
49
+ (e.M && isType(e.M, 'string')) ||
50
+ (ctx && ctx.hasSignatureTimestamp)
51
+ );
52
+ let level = null;
53
+ if (isPades) {
54
+ const hasDss = !!(ctx && ctx.dss);
55
+ const ltaTs = !!(ctx && ctx.hasDocTimestampOverDss);
56
+ if (ltaTs) level = 'B-LTA';
57
+ else if (hasDss) level = 'B-LT';
58
+ else if (hasTimestamp) level = 'B-T';
59
+ else level = 'B-B';
60
+ }
61
+ return { subFilter: sf, isPades, level, hasTimestamp };
62
+ }
63
+
64
+ function typeReferenceArray(arr) {
65
+ if (!isType(arr, 'array')) {
66
+ throw new ParseError('pdf/extra/pades/bad-reference',
67
+ '/Reference must be an array',
68
+ { context: { type: arr && arr.type } });
69
+ }
70
+ const out = [];
71
+ for (const it of arr.items) {
72
+ if (!isType(it, 'dict')) {
73
+ throw new ParseError('pdf/extra/pades/bad-reference-item',
74
+ '/Reference items must be dicts');
75
+ }
76
+ const e = it.entries;
77
+ if (e.Type && (e.Type.type !== 'name' || e.Type.value !== 'SigRef')) {
78
+ throw new ParseError('pdf/extra/pades/bad-reference-type',
79
+ '/Type of /Reference item must be /SigRef',
80
+ { context: { actual: e.Type.value } });
81
+ }
82
+ out.push({
83
+ transformMethod: isType(e.TransformMethod, 'name') ? e.TransformMethod.value : null,
84
+ transformParams: isType(e.TransformParams, 'dict') ? e.TransformParams : null,
85
+ data: e.Data || null,
86
+ digestMethod: isType(e.DigestMethod, 'name') ? e.DigestMethod.value : null,
87
+ raw: it
88
+ });
89
+ }
90
+ return out;
91
+ }
92
+
93
+ function typeDSS(dict) {
94
+ if (!isType(dict, 'dict')) {
95
+ throw new ParseError('pdf/extra/pades/dss-not-dict',
96
+ 'DSS must be a dictionary',
97
+ { context: { type: dict && dict.type } });
98
+ }
99
+ const e = dict.entries;
100
+ if (e.Type && (e.Type.type !== 'name' || e.Type.value !== 'DSS')) {
101
+ throw new ParseError('pdf/extra/pades/dss-bad-type',
102
+ '/Type of DSS dict must be /DSS',
103
+ { context: { actual: e.Type.value } });
104
+ }
105
+ const out = {
106
+ certs: refsArray(e.Certs, 'DSS /Certs'),
107
+ crls: refsArray(e.CRLs, 'DSS /CRLs'),
108
+ ocsps: refsArray(e.OCSPs, 'DSS /OCSPs'),
109
+ vri: isType(e.VRI, 'dict') ? typeVRI(e.VRI) : null,
110
+ raw: dict,
111
+ _extras: {}
112
+ };
113
+ const known = new Set(['Type', 'Certs', 'CRLs', 'OCSPs', 'VRI']);
114
+ for (const k of Object.keys(e)) if (!known.has(k)) out._extras[k] = e[k];
115
+ return out;
116
+ }
117
+
118
+ function typeVRI(dict) {
119
+ const out = {};
120
+ for (const k of Object.keys(dict.entries)) {
121
+ const v = dict.entries[k];
122
+ if (!isType(v, 'dict')) continue;
123
+ const ve = v.entries;
124
+ out[k] = {
125
+ cert: refsArray(ve.Cert, 'VRI /Cert'),
126
+ crl: refsArray(ve.CRL, 'VRI /CRL'),
127
+ ocsp: refsArray(ve.OCSP, 'VRI /OCSP'),
128
+ tu: isType(ve.TU, 'string') ? ve.TU.value : null,
129
+ ts: ve.TS || null
130
+ };
131
+ }
132
+ return out;
133
+ }
134
+
135
+ function refsArray(v, ctxLabel) {
136
+ if (!v) return null;
137
+ if (!isType(v, 'array')) {
138
+ throw new ParseError('pdf/extra/pades/dss-bad-array',
139
+ `${ctxLabel} must be an array`,
140
+ { context: { type: v.type } });
141
+ }
142
+ return v.items;
143
+ }
144
+
145
+ function validateDocMdp(ref) {
146
+ const issues = [];
147
+ if (!ref || ref.transformMethod !== 'DocMDP') {
148
+ issues.push({
149
+ code: 'pdf/extra/pades/mdp/wrong-transform',
150
+ message: 'reference is not a DocMDP transform',
151
+ context: { transformMethod: ref && ref.transformMethod }
152
+ });
153
+ return { valid: false, level: null, issues };
154
+ }
155
+ if (!ref.transformParams || !isType(ref.transformParams, 'dict')) {
156
+ issues.push({
157
+ code: 'pdf/extra/pades/mdp/missing-params',
158
+ message: 'DocMDP missing /TransformParams dict'
159
+ });
160
+ return { valid: false, level: null, issues };
161
+ }
162
+ const params = ref.transformParams.entries;
163
+ let level = null;
164
+ if (params.P) {
165
+ if (params.P.type !== 'int') {
166
+ issues.push({
167
+ code: 'pdf/extra/pades/mdp/bad-p-type',
168
+ message: '/P must be an integer',
169
+ context: { type: params.P.type }
170
+ });
171
+ } else if (params.P.value < 1 || params.P.value > 3) {
172
+ issues.push({
173
+ code: 'pdf/extra/pades/mdp/bad-p-value',
174
+ message: '/P must be 1, 2 or 3',
175
+ context: { value: params.P.value }
176
+ });
177
+ } else {
178
+ level = params.P.value;
179
+ }
180
+ } else {
181
+ level = 2;
182
+ }
183
+ if (params.V && params.V.type === 'name'
184
+ && params.V.value !== '1.2'
185
+ && params.V.value !== '2.2') {
186
+ issues.push({
187
+ code: 'pdf/extra/pades/mdp/bad-version',
188
+ message: 'unknown DocMDP /V',
189
+ context: { v: params.V.value }
190
+ });
191
+ }
192
+ if (!ref.digestMethod) {
193
+ issues.push({
194
+ code: 'pdf/extra/pades/mdp/missing-digest',
195
+ message: 'DocMDP reference missing /DigestMethod'
196
+ });
197
+ }
198
+ return { valid: issues.length === 0, level, issues };
199
+ }
200
+
201
+ function validateBLtaChain(steps) {
202
+ if (!Array.isArray(steps)) {
203
+ throw new ParseError('pdf/extra/pades/chain/bad-input',
204
+ 'validateBLtaChain expects an array of steps',
205
+ { context: { type: typeof steps } });
206
+ }
207
+ const trace = [];
208
+ let sawDss = false;
209
+ let sawDocTsOverDss = false;
210
+ for (let i = 0; i < steps.length; i++) {
211
+ const step = steps[i];
212
+ if (!step || !step.sigDict) {
213
+ throw new ParseError('pdf/extra/pades/chain/missing-sig',
214
+ 'step missing sigDict',
215
+ { context: { index: i } });
216
+ }
217
+ if (step.hasDss) sawDss = true;
218
+ if (step.hasDocTimestamp && sawDss) sawDocTsOverDss = true;
219
+ const ctx = {
220
+ dss: sawDss ? {} : undefined,
221
+ hasDocTimestampOverDss: sawDocTsOverDss,
222
+ hasSignatureTimestamp: !!step.hasSignatureTimestamp
223
+ };
224
+ const detected = detectPadesProfile(step.sigDict, ctx);
225
+ trace.push({ index: i, level: detected.level,
226
+ isPades: detected.isPades });
227
+ }
228
+ const last = trace[trace.length - 1];
229
+ return { chainLevel: last ? last.level : null, trace };
230
+ }
231
+
232
+ return {
233
+ detectPadesProfile,
234
+ typeReferenceArray,
235
+ typeDSS,
236
+ validateDocMdp,
237
+ validateBLtaChain,
238
+ SIG_SUBFILTERS
239
+ };
240
+ }
241
+ };
242
+
@@ -0,0 +1,203 @@
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 Opt-in: typed StructElem attribute objects per
8
+ * ISO 32000-2:2020 §14.8.5 (standard structure attribute owners) —
9
+ * Layout (§14.8.5.4), List (§14.8.5.5), Table (§14.8.5.7),
10
+ * PrintField (§14.8.5.6), Artifact (§14.8.2.2), UserProperties
11
+ * (§14.8.5.10).
12
+ *
13
+ * Attribute classes appear as dicts with an `/O` (Owner) name. We
14
+ * dispatch by `/O` and apply a typed reader that returns plain JS
15
+ * values for the well-defined keys, preserving unknowns in `_extras`.
16
+ *
17
+ * @module pdf/extra/tagged-pdf-typed
18
+ */
19
+
20
+ /**
21
+ * Module factory.
22
+ */
23
+ import { pdfErrors } from '../errors.js';
24
+ import { pdfParserObj } from '../syntax/parser-obj.js';
25
+
26
+ export const pdfTaggedPdfTyped = {
27
+ name: 'pdfTaggedPdfTyped',
28
+ dependencies: ['pdfErrors', 'pdfParserObj'],
29
+ deps: [pdfErrors, pdfParserObj],
30
+ factory(errors, parserObj) {
31
+ const { ParseError } = errors;
32
+ const { isType } = parserObj;
33
+
34
+ const OWNERS = new Set([
35
+ 'Layout', 'List', 'Table', 'PrintField', 'Artifact', 'UserProperties'
36
+ ]);
37
+
38
+ const KNOWN_BY_OWNER = {
39
+ Layout: new Set(['O', 'Placement', 'WritingMode', 'BackgroundColor',
40
+ 'BorderColor', 'BorderStyle', 'BorderThickness', 'Color',
41
+ 'Padding', 'SpaceBefore', 'SpaceAfter', 'StartIndent', 'EndIndent',
42
+ 'TextIndent', 'TextAlign', 'BBox', 'Width', 'Height', 'BlockAlign',
43
+ 'InlineAlign', 'TBorderStyle', 'TPadding', 'LineHeight',
44
+ 'BaselineShift', 'TextPosition', 'TextDecorationType',
45
+ 'TextDecorationColor', 'TextDecorationThickness',
46
+ 'RubyAlign', 'RubyPosition', 'GlyphOrientationVertical',
47
+ 'ColumnCount', 'ColumnGap', 'ColumnWidths']),
48
+ List: new Set(['O', 'ListNumbering', 'ContinuedList', 'ContinuedFrom']),
49
+ Table: new Set(['O', 'RowSpan', 'ColSpan', 'Headers', 'Scope', 'Summary']),
50
+ PrintField: new Set(['O', 'Role', 'checked', 'Desc']),
51
+ Artifact: new Set(['O', 'Type', 'BBox', 'Attached', 'Subtype']),
52
+ UserProperties: new Set(['O', 'P'])
53
+ };
54
+
55
+ function knownFor(owner) {
56
+ return KNOWN_BY_OWNER[owner] || new Set(['O']);
57
+ }
58
+
59
+ function typeStructAttribute(dict) {
60
+ if (!isType(dict, 'dict')) {
61
+ throw new ParseError('pdf/extra/tagged/not-dict',
62
+ 'attribute class must be a dictionary',
63
+ { context: { type: dict && dict.type } });
64
+ }
65
+ const e = dict.entries;
66
+ if (!isType(e.O, 'name')) {
67
+ throw new ParseError('pdf/extra/tagged/missing-owner',
68
+ 'attribute class missing /O owner name',
69
+ { context: { type: e.O && e.O.type } });
70
+ }
71
+ const owner = e.O.value;
72
+ let typed;
73
+ switch (owner) {
74
+ case 'Layout': typed = readLayout(e); break;
75
+ case 'List': typed = readList(e); break;
76
+ case 'Table': typed = readTable(e); break;
77
+ case 'PrintField': typed = readPrintField(e); break;
78
+ case 'Artifact': typed = readArtifact(e); break;
79
+ case 'UserProperties': typed = readUserProperties(e); break;
80
+ default:
81
+ typed = { owner, vendor: true };
82
+ }
83
+ typed.owner = owner;
84
+ typed.raw = dict;
85
+ typed._extras = collectExtras(e, knownFor(owner));
86
+ return typed;
87
+ }
88
+
89
+ function readLayout(e) {
90
+ return {
91
+ placement: nameVal(e.Placement),
92
+ writingMode: nameVal(e.WritingMode),
93
+ backgroundColor: numArr(e.BackgroundColor),
94
+ borderColor: e.BorderColor || null,
95
+ borderStyle: e.BorderStyle || null,
96
+ borderThickness: e.BorderThickness || null,
97
+ color: numArr(e.Color),
98
+ padding: e.Padding || null,
99
+ spaceBefore: numVal(e.SpaceBefore, null),
100
+ spaceAfter: numVal(e.SpaceAfter, null),
101
+ startIndent: numVal(e.StartIndent, null),
102
+ endIndent: numVal(e.EndIndent, null),
103
+ textIndent: numVal(e.TextIndent, null),
104
+ textAlign: nameVal(e.TextAlign),
105
+ bbox: numArr(e.BBox),
106
+ width: numVal(e.Width, null),
107
+ height: numVal(e.Height, null),
108
+ blockAlign: nameVal(e.BlockAlign),
109
+ inlineAlign: nameVal(e.InlineAlign),
110
+ lineHeight: numVal(e.LineHeight, null),
111
+ baselineShift: numVal(e.BaselineShift, null),
112
+ textPosition: nameVal(e.TextPosition),
113
+ textDecorationType: nameVal(e.TextDecorationType),
114
+ textDecorationColor: numArr(e.TextDecorationColor),
115
+ textDecorationThickness: numVal(e.TextDecorationThickness, null),
116
+ columnCount: numVal(e.ColumnCount, null),
117
+ columnGap: e.ColumnGap || null,
118
+ columnWidths: e.ColumnWidths || null
119
+ };
120
+ }
121
+
122
+ function readList(e) {
123
+ return {
124
+ listNumbering: nameVal(e.ListNumbering),
125
+ continuedList: isType(e.ContinuedList, 'bool') ? e.ContinuedList.value : null,
126
+ continuedFrom: e.ContinuedFrom || null
127
+ };
128
+ }
129
+
130
+ function readTable(e) {
131
+ return {
132
+ rowSpan: numVal(e.RowSpan, null),
133
+ colSpan: numVal(e.ColSpan, null),
134
+ headers: e.Headers || null,
135
+ scope: nameVal(e.Scope),
136
+ summary: isType(e.Summary, 'string') ? e.Summary.value : null
137
+ };
138
+ }
139
+
140
+ function readPrintField(e) {
141
+ return {
142
+ role: nameVal(e.Role),
143
+ checked: nameVal(e.checked) || nameVal(e.Checked),
144
+ desc: isType(e.Desc, 'string') ? e.Desc.value : null
145
+ };
146
+ }
147
+
148
+ function readArtifact(e) {
149
+ return {
150
+ artifactType: nameVal(e.Type),
151
+ bbox: numArr(e.BBox),
152
+ attached: e.Attached || null,
153
+ artifactSubtype: nameVal(e.Subtype)
154
+ };
155
+ }
156
+
157
+ function readUserProperties(e) {
158
+ const out = { properties: [] };
159
+ if (isType(e.P, 'array')) {
160
+ for (const it of e.P.items) {
161
+ if (!isType(it, 'dict')) {
162
+ throw new ParseError('pdf/extra/tagged/bad-user-property',
163
+ '/P items must be dicts');
164
+ }
165
+ const pe = it.entries;
166
+ out.properties.push({
167
+ name: isType(pe.N, 'string') ? pe.N.value : null,
168
+ value: pe.V || null,
169
+ formatted: isType(pe.F, 'string') ? pe.F.value : null,
170
+ hidden: isType(pe.H, 'bool') ? pe.H.value : false
171
+ });
172
+ }
173
+ }
174
+ return out;
175
+ }
176
+
177
+ function nameVal(v) { return isType(v, 'name') ? v.value : null; }
178
+ function numVal(v, dflt) {
179
+ if (!v) return dflt;
180
+ return (v.type === 'int' || v.type === 'real') ? v.value : dflt;
181
+ }
182
+ function numArr(v) {
183
+ if (!isType(v, 'array')) return null;
184
+ const out = [];
185
+ for (const it of v.items) {
186
+ if (!it || (it.type !== 'int' && it.type !== 'real')) return null;
187
+ out.push(it.value);
188
+ }
189
+ return out;
190
+ }
191
+
192
+ function collectExtras(entries, known) {
193
+ const out = {};
194
+ for (const k of Object.keys(entries)) {
195
+ if (!known.has(k)) out[k] = entries[k];
196
+ }
197
+ return out;
198
+ }
199
+
200
+ return { typeStructAttribute, ATTRIBUTE_OWNERS: OWNERS };
201
+ }
202
+ };
203
+