@mostajs/pdf-sign 0.4.1 → 0.6.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 CHANGED
@@ -1,5 +1,45 @@
1
1
  # Changelog — @mostajs/pdf-sign
2
2
 
3
+ ## 0.6.0 — 11/10/2026
4
+
5
+ **`timestampPdf` : un horodatage de DOCUMENT ajouté à un PDF déjà signé, sans toucher à sa signature.**
6
+
7
+ ### Ajouté
8
+ - `timestampPdf({ input, output?, timestampUrl, timestampHeaders?, timestampAuth?, timestampTimeout?, openPassword? })`
9
+ pose un jeton RFC 3161 (PAdES « DocTimeStamp ») par **mise à jour incrémentale** : les octets d'origine sont
10
+ gardés, les signatures déjà présentes restent intactes. Un document chiffré par des permissions (sans mot de passe
11
+ d'ouverture) s'horodate aussi. `verifyPdf` le lit comme `type: "horodatage-document"`.
12
+ - Mêmes garde-fous que `signPdf`, par les mêmes fonctions (désormais exportées de `sign.ts`) : les identifiants du
13
+ `.env` ne partent que vers `PDF_SIGN_TSA` ; jamais en clair hors de la boucle locale ; aucun repli — un horodateur
14
+ muet ou qui refuse la clé fait échouer, cause nommée (« identifiants refusés… (HTTP 401) »). Exige pyhanko.
15
+ - Types `TimestampOptions`, `HorodateurOptions`. Python : `sign_with_perms.py timestamp IN OUT CONFIG`.
16
+ - Raison : qatrax-cra (D4, doc 26) vend « une signature » = un horodatage **qualifié** posé sur le certificat déjà
17
+ scellé par le cachet de service ; le certificat reste un seul document, son sceau d'origine intact.
18
+
19
+ ### Essais
20
+ T-DTS-1..6 (`test-scripts/test-horodatage-document.ts`). Sabotages relevés : réécriture non incrémentale (T-DTS-1,
21
+ 2, 3), document chiffré non ouvert (T-DTS-3), repli silencieux sur l'original (T-DTS-4, 6).
22
+
23
+ ## 0.5.0 — 07/10/2026
24
+
25
+ **`verifyPdf` dit QUAND et QUI, plus seulement « valide ».**
26
+
27
+ ### Ajouté (additif : les champs existants ne changent pas)
28
+ - Par signature (moteur pyhanko) : `type` (signature ou horodatage de document), `level` (PAdES-B-B,
29
+ B-T, B-LT, horodatage de document), `claimedSigningTime` (la date DÉCLARÉE par le signataire),
30
+ `timestamp` (date ATTESTÉE `genTime`, politique `policy` (OID), numéro, autorité `tsa`, chaîne
31
+ embarquée, intact/valid/trusted du jeton), `signerCertificate` (titulaire, émetteur, numéro,
32
+ validité, `selfSigned`), `name` (nom affiché par les lecteurs), `reason`, `location`, `subFilter`,
33
+ `coverage`, `digestAlgorithm`. Au niveau du document : `dss`.
34
+ - Raison : la date déclarée (antidatable) et la date attestée par un horodateur étaient
35
+ indiscernables ; aucun écran de vérification ne pouvait les opposer.
36
+
37
+ ### Corrigé
38
+ - Une signature que pyhanko REFUSE de valider (CMS abîmé, certificat de signature qui ne
39
+ correspond plus) est désormais rendue **invalide** (`intact: false, valid: false, error`) au lieu
40
+ de faire échouer toute la vérification. Jusqu'en 0.4.1, un document altéré de cette façon ne
41
+ rendait plus rien. T-DET-1..4.
42
+
3
43
  ## 0.4.1 — 29/09/2026
4
44
 
5
45
  **pyhanko 0.37 taisait le diagnostic « identifiants refusés » — et rien ne fixait les versions.**
package/README.md CHANGED
@@ -147,6 +147,24 @@ pyhanko, seul, l'aurait présenté comme une « réponse malformée ».
147
147
  Les identifiants partent au moteur par le fichier de configuration temporaire (dossier en 0700,
148
148
  effacé après usage), **jamais** par la ligne de commande — et le CLI ne les accepte qu'en `.env`.
149
149
 
150
+ ## Horodatage d'un document déjà signé *(0.6.0)*
151
+
152
+ `timestampPdf` ajoute un jeton RFC 3161 (PAdES « DocTimeStamp ») à un PDF, **sans toucher** aux signatures qu'il
153
+ porte déjà : mise à jour incrémentale, octets d'origine gardés. Usage type : poser un horodatage **qualifié** sur un
154
+ document scellé par un cachet de service.
155
+
156
+ ```ts
157
+ import { timestampPdf } from "@mostajs/pdf-sign";
158
+ const { bytes } = await timestampPdf({
159
+ input: pdfScelle, // octets ou chemin
160
+ timestampUrl: "https://api.evidency.io/v3/projects/<ID>/timestamp",
161
+ timestampHeaders: { "X-API-KEY": process.env.CLE },
162
+ });
163
+ ```
164
+
165
+ Mêmes garde-fous que la signature (tableau ci-dessus), aucun repli : si l'horodateur ne répond pas ou refuse la clé,
166
+ rien n'est rendu. Exige pyhanko. Essais : `test-scripts/test-horodatage-document.ts`.
167
+
150
168
  ## Configuration (`.env`)
151
169
 
152
170
  | Clé | Rôle |
package/dist/index.d.ts CHANGED
@@ -8,8 +8,9 @@
8
8
  * @license AGPL-3.0-or-later
9
9
  */
10
10
  export { signPdf } from "./sign.js";
11
+ export { timestampPdf } from "./timestamp.js";
11
12
  export { verifyPdf } from "./verify.js";
12
13
  export { detectEngines, resolvePython, pyhankoAvailable } from "./engines.js";
13
14
  export { loadPdfSignConfig, type PdfSignConfig } from "./config.js";
14
- export type { SignOptions, SignResult, SignMeta, SignField, SignPermissions, SignEngine, VerifyOptions, VerifyResult, SignatureInfo, EngineAvailability, } from "./types.js";
15
+ export type { SignOptions, SignResult, SignMeta, SignField, SignPermissions, SignEngine, VerifyOptions, VerifyResult, SignatureInfo, EngineAvailability, TimestampOptions, HorodateurOptions, } from "./types.js";
15
16
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACxC,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAC9E,OAAO,EAAE,iBAAiB,EAAE,KAAK,aAAa,EAAE,MAAM,aAAa,CAAC;AACpE,YAAY,EACV,WAAW,EAAE,UAAU,EAAE,QAAQ,EAAE,SAAS,EAAE,eAAe,EAAE,UAAU,EACzE,aAAa,EAAE,YAAY,EAAE,aAAa,EAAE,kBAAkB,GAC/D,MAAM,YAAY,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACxC,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAC9E,OAAO,EAAE,iBAAiB,EAAE,KAAK,aAAa,EAAE,MAAM,aAAa,CAAC;AACpE,YAAY,EACV,WAAW,EAAE,UAAU,EAAE,QAAQ,EAAE,SAAS,EAAE,eAAe,EAAE,UAAU,EACzE,aAAa,EAAE,YAAY,EAAE,aAAa,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,iBAAiB,GACpG,MAAM,YAAY,CAAC"}
package/dist/index.js CHANGED
@@ -8,6 +8,7 @@
8
8
  * @license AGPL-3.0-or-later
9
9
  */
10
10
  export { signPdf } from "./sign.js";
11
+ export { timestampPdf } from "./timestamp.js";
11
12
  export { verifyPdf } from "./verify.js";
12
13
  export { detectEngines, resolvePython, pyhankoAvailable } from "./engines.js";
13
14
  export { loadPdfSignConfig } from "./config.js";
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACxC,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAC9E,OAAO,EAAE,iBAAiB,EAAsB,MAAM,aAAa,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACxC,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAC9E,OAAO,EAAE,iBAAiB,EAAsB,MAAM,aAAa,CAAC"}
@@ -1,4 +1,10 @@
1
- import type { SignOptions, SignResult } from "./types.js";
1
+ import type { SignOptions, SignResult, TimestampOptions } from "./types.js";
2
2
  /** Signe via pyhanko (PAdES visible + éventuelles permissions restrictives). */
3
3
  export declare function signPyhanko(opts: SignOptions, python: string): SignResult;
4
+ /**
5
+ * 0.6.0 — horodatage de DOCUMENT via pyhanko (`PdfTimeStamper`) : mise à jour incrémentale, les signatures déjà
6
+ * présentes restent intactes. Mêmes règles que la signature : identifiants par fichier, jamais par `argv` ; aucun
7
+ * repli — un horodateur qui ne répond pas fait échouer, et la cause est remontée.
8
+ */
9
+ export declare function timestampPyhanko(opts: TimestampOptions, python: string): SignResult;
4
10
  //# sourceMappingURL=pyhanko-signer.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"pyhanko-signer.d.ts","sourceRoot":"","sources":["../src/pyhanko-signer.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,WAAW,EAAmB,UAAU,EAAE,MAAM,YAAY,CAAC;AAsD3E,gFAAgF;AAChF,wBAAgB,WAAW,CAAC,IAAI,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,GAAG,UAAU,CAuDzE"}
1
+ {"version":3,"file":"pyhanko-signer.d.ts","sourceRoot":"","sources":["../src/pyhanko-signer.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,WAAW,EAAmB,UAAU,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAsD7F,gFAAgF;AAChF,wBAAgB,WAAW,CAAC,IAAI,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,GAAG,UAAU,CAuDzE;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,gBAAgB,EAAE,MAAM,EAAE,MAAM,GAAG,UAAU,CAwBnF"}
@@ -115,4 +115,38 @@ export function signPyhanko(opts, python) {
115
115
  rmSync(dir, { recursive: true, force: true });
116
116
  }
117
117
  }
118
+ /**
119
+ * 0.6.0 — horodatage de DOCUMENT via pyhanko (`PdfTimeStamper`) : mise à jour incrémentale, les signatures déjà
120
+ * présentes restent intactes. Mêmes règles que la signature : identifiants par fichier, jamais par `argv` ; aucun
121
+ * repli — un horodateur qui ne répond pas fait échouer, et la cause est remontée.
122
+ */
123
+ export function timestampPyhanko(opts, python) {
124
+ const dir = mkdtempSync(join(tmpdir(), "mosta-pdf-sign-"));
125
+ try {
126
+ const inPath = typeof opts.input === "string" ? opts.input : toFile(dir, "in.pdf", opts.input);
127
+ const outPath = opts.output ?? join(dir, "out.pdf");
128
+ const cfgPath = toFile(dir, "config.json", JSON.stringify({
129
+ open_password: opts.openPassword || undefined,
130
+ timestamp_url: opts.timestampUrl,
131
+ timestamp_headers: opts.timestampHeaders,
132
+ timestamp_auth: opts.timestampAuth,
133
+ timestamp_timeout: opts.timestampTimeout,
134
+ }));
135
+ try {
136
+ execFileSync(python, [SIGN_PY, "timestamp", inPath, outPath, cfgPath], { stdio: ["ignore", "inherit", "pipe"] });
137
+ }
138
+ catch (e) {
139
+ const trace = String(e?.stderr ?? "");
140
+ if (trace)
141
+ process.stderr.write(trace);
142
+ throw new Error(diagnostiquer(trace) ?? "Horodatage du document impossible (voir le journal du serveur).");
143
+ }
144
+ if (opts.output)
145
+ return { output: outPath, engine: "pyhanko" };
146
+ return { bytes: readFileSync(outPath), engine: "pyhanko" };
147
+ }
148
+ finally {
149
+ rmSync(dir, { recursive: true, force: true });
150
+ }
151
+ }
118
152
  //# sourceMappingURL=pyhanko-signer.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"pyhanko-signer.js","sourceRoot":"","sources":["../src/pyhanko-signer.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"pyhanko-signer.js","sourceRoot":"","sources":["../src/pyhanko-signer.ts"],"names":[],"mappings":"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"}
package/dist/sign.d.ts CHANGED
@@ -8,6 +8,18 @@
8
8
  * @author Dr Hamid MADANI <drmdh@msn.com>
9
9
  * @license AGPL-3.0-or-later
10
10
  */
11
- import type { SignOptions, SignResult } from "./types.js";
11
+ import type { HorodateurOptions, SignOptions, SignResult } from "./types.js";
12
+ import type { PdfSignConfig } from "./config.js";
12
13
  export declare function signPdf(opts: SignOptions): Promise<SignResult>;
14
+ /**
15
+ * Les identifiants d'un horodateur VOYAGENT AVEC SON ADRESSE — même règle que le certificat et sa
16
+ * phrase, plus haut.
17
+ *
18
+ * Ceux du `.env` ne partent que vers l'horodateur du `.env` (`PDF_SIGN_TSA`). Un appelant qui
19
+ * vise une autre adresse fournit les siens, ou n'en envoie aucun : joindre notre clé d'API à une
20
+ * requête vers un tiers, c'est la lui donner.
21
+ */
22
+ export declare function identifiantsHorodateur(opts: HorodateurOptions, cfg: PdfSignConfig): HorodateurOptions;
23
+ /** Refuse, AVANT toute requête, un horodatage dont la demande est incohérente ou dangereuse. */
24
+ export declare function controlerHorodatage(o: HorodateurOptions): void;
13
25
  //# sourceMappingURL=sign.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"sign.d.ts","sourceRoot":"","sources":["../src/sign.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,KAAK,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAO1D,wBAAsB,OAAO,CAAC,IAAI,EAAE,WAAW,GAAG,OAAO,CAAC,UAAU,CAAC,CAqDpE"}
1
+ {"version":3,"file":"sign.d.ts","sourceRoot":"","sources":["../src/sign.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,KAAK,EAAE,iBAAiB,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAC7E,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAMjD,wBAAsB,OAAO,CAAC,IAAI,EAAE,WAAW,GAAG,OAAO,CAAC,UAAU,CAAC,CAqDpE;AAED;;;;;;;GAOG;AACH,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,iBAAiB,EAAE,GAAG,EAAE,aAAa,GAAG,iBAAiB,CAUrG;AAID,gGAAgG;AAChG,wBAAgB,mBAAmB,CAAC,CAAC,EAAE,iBAAiB,GAAG,IAAI,CAqB9D"}
package/dist/sign.js CHANGED
@@ -60,7 +60,7 @@ export async function signPdf(opts) {
60
60
  * vise une autre adresse fournit les siens, ou n'en envoie aucun : joindre notre clé d'API à une
61
61
  * requête vers un tiers, c'est la lui donner.
62
62
  */
63
- function identifiantsHorodateur(opts, cfg) {
63
+ export function identifiantsHorodateur(opts, cfg) {
64
64
  const t = cfg.tsa;
65
65
  const memeHorodateur = !!opts.timestampUrl && opts.timestampUrl === t.url;
66
66
  return {
@@ -73,7 +73,7 @@ function identifiantsHorodateur(opts, cfg) {
73
73
  }
74
74
  const LOCALES = new Set(["localhost", "127.0.0.1", "::1", "[::1]"]);
75
75
  /** Refuse, AVANT toute requête, un horodatage dont la demande est incohérente ou dangereuse. */
76
- function controlerHorodatage(o) {
76
+ export function controlerHorodatage(o) {
77
77
  const identifie = !!o.timestampAuth || Object.keys(o.timestampHeaders ?? {}).length > 0;
78
78
  if (!o.timestampUrl) {
79
79
  if (identifie) {
package/dist/sign.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"sign.js","sourceRoot":"","sources":["../src/sign.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"sign.js","sourceRoot":"","sources":["../src/sign.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import type { SignResult, TimestampOptions } from "./types.js";
2
+ export declare function timestampPdf(opts: TimestampOptions): Promise<SignResult>;
3
+ //# sourceMappingURL=timestamp.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"timestamp.d.ts","sourceRoot":"","sources":["../src/timestamp.ts"],"names":[],"mappings":"AAeA,OAAO,KAAK,EAAE,UAAU,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAiB/D,wBAAsB,YAAY,CAAC,IAAI,EAAE,gBAAgB,GAAG,OAAO,CAAC,UAAU,CAAC,CAW9E"}
@@ -0,0 +1,53 @@
1
+ /**
2
+ * @mostajs/pdf-sign — HORODATAGE DE DOCUMENT (0.6.0).
3
+ *
4
+ * Ajoute un jeton RFC 3161 (PAdES « DocTimeStamp ») à un PDF, signé ou non, par mise à jour incrémentale : les
5
+ * signatures déjà présentes restent intactes. Premier usage : qatrax-cra (D4, doc 26, 11/10/2026) — l'horodatage
6
+ * QUALIFIÉ posé sur un certificat déjà scellé par le cachet de service.
7
+ *
8
+ * Mêmes règles que `signPdf` : les identifiants du `.env` ne partent que vers l'horodateur du `.env` ; pas
9
+ * d'identifiants en clair hors de la boucle locale ; aucun repli. Le cœur Node ne sait pas horodater : pyhanko est
10
+ * exigé.
11
+ *
12
+ * @author Dr Hamid MADANI <drmdh@msn.com>
13
+ * @license AGPL-3.0-or-later
14
+ */
15
+ import { openSync, readSync, closeSync } from "node:fs";
16
+ import { detectEngines } from "./engines.js";
17
+ import { loadPdfSignConfig } from "./config.js";
18
+ import { controlerHorodatage, identifiantsHorodateur } from "./sign.js";
19
+ import { timestampPyhanko } from "./pyhanko-signer.js";
20
+ const ENTETE_PDF = Buffer.from("%PDF-");
21
+ function estPdf(input) {
22
+ if (typeof input !== "string")
23
+ return Buffer.from(input.subarray(0, 5)).equals(ENTETE_PDF);
24
+ const tampon = Buffer.alloc(5);
25
+ let fd = null;
26
+ try {
27
+ fd = openSync(input, "r");
28
+ readSync(fd, tampon, 0, 5, 0);
29
+ return tampon.equals(ENTETE_PDF);
30
+ }
31
+ catch {
32
+ return false;
33
+ }
34
+ finally {
35
+ if (fd !== null)
36
+ closeSync(fd);
37
+ }
38
+ }
39
+ export async function timestampPdf(opts) {
40
+ if (!String(opts.timestampUrl ?? "").trim()) {
41
+ throw new Error("Horodatage de document : l'adresse de l'horodateur (`timestampUrl`) est requise.");
42
+ }
43
+ if (!estPdf(opts.input))
44
+ throw new Error("Horodatage de document : l'entrée n'est pas un PDF.");
45
+ const cfg = loadPdfSignConfig();
46
+ const o = { ...opts, ...identifiantsHorodateur(opts, cfg) };
47
+ controlerHorodatage(o);
48
+ const avail = detectEngines(cfg.python);
49
+ if (!avail.pyhanko)
50
+ throw new Error("Horodatage de document : moteur pyhanko indisponible — lancer python/setup-venv.sh (ou PDF_SIGN_PYTHON).");
51
+ return timestampPyhanko(o, avail.python);
52
+ }
53
+ //# sourceMappingURL=timestamp.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"timestamp.js","sourceRoot":"","sources":["../src/timestamp.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AACH,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AAExD,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAC7C,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAChD,OAAO,EAAE,mBAAmB,EAAE,sBAAsB,EAAE,MAAM,WAAW,CAAC;AACxE,OAAO,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAEvD,MAAM,UAAU,GAAG,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;AAExC,SAAS,MAAM,CAAC,KAA0B;IACxC,IAAI,OAAO,KAAK,KAAK,QAAQ;QAAE,OAAO,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;IAC3F,MAAM,MAAM,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IAC/B,IAAI,EAAE,GAAkB,IAAI,CAAC;IAC7B,IAAI,CAAC;QAAC,EAAE,GAAG,QAAQ,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;QAAC,QAAQ,CAAC,EAAE,EAAE,MAAM,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;QAAC,OAAO,MAAM,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;IAAC,CAAC;IACnG,MAAM,CAAC;QAAC,OAAO,KAAK,CAAC;IAAC,CAAC;YACf,CAAC;QAAC,IAAI,EAAE,KAAK,IAAI;YAAE,SAAS,CAAC,EAAE,CAAC,CAAC;IAAC,CAAC;AAC7C,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,IAAsB;IACvD,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,YAAY,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC;QAC5C,MAAM,IAAI,KAAK,CAAC,kFAAkF,CAAC,CAAC;IACtG,CAAC;IACD,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,qDAAqD,CAAC,CAAC;IAChG,MAAM,GAAG,GAAG,iBAAiB,EAAE,CAAC;IAChC,MAAM,CAAC,GAAqB,EAAE,GAAG,IAAI,EAAE,GAAG,sBAAsB,CAAC,IAAI,EAAE,GAAG,CAAC,EAAE,CAAC;IAC9E,mBAAmB,CAAC,CAAC,CAAC,CAAC;IACvB,MAAM,KAAK,GAAG,aAAa,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;IACxC,IAAI,CAAC,KAAK,CAAC,OAAO;QAAE,MAAM,IAAI,KAAK,CAAC,0GAA0G,CAAC,CAAC;IAChJ,OAAO,gBAAgB,CAAC,CAAC,EAAE,KAAK,CAAC,MAAgB,CAAC,CAAC;AACrD,CAAC"}
package/dist/types.d.ts CHANGED
@@ -94,6 +94,22 @@ export interface SignOptions {
94
94
  /** `auto` (défaut) = pyhanko si dispo sinon Node ; `node` = PKCS#7 ; `pyhanko` = PAdES. */
95
95
  engine?: SignEngine;
96
96
  }
97
+ /** Ce qui désigne un horodateur RFC 3161 et ses identifiants — commun à la signature et à l'horodatage de document. */
98
+ export type HorodateurOptions = Pick<SignOptions, "timestampUrl" | "timestampHeaders" | "timestampAuth" | "timestampTimeout">;
99
+ /**
100
+ * 0.6.0 — horodatage de DOCUMENT (PAdES « DocTimeStamp ») : un jeton RFC 3161 ajouté, par mise à jour incrémentale, à
101
+ * un PDF qui peut déjà porter des signatures. Elles restent intactes : les octets d'origine ne sont pas réécrits.
102
+ */
103
+ export interface TimestampOptions extends HorodateurOptions {
104
+ /** PDF source : chemin ou octets. */
105
+ input: string | Uint8Array;
106
+ /** Chemin de sortie ; si absent, les octets horodatés sont renvoyés. */
107
+ output?: string;
108
+ /** L'horodateur (obligatoire : un horodatage de document sans horodateur n'a pas de sens). */
109
+ timestampUrl: string;
110
+ /** Mot de passe d'ouverture, si le document en porte un. */
111
+ openPassword?: string;
112
+ }
97
113
  export interface SignResult {
98
114
  output?: string;
99
115
  bytes?: Uint8Array;
@@ -107,17 +123,60 @@ export interface VerifyOptions {
107
123
  trustPem?: string;
108
124
  engine?: SignEngine;
109
125
  }
126
+ /** Ce qu'un vérificateur doit voir d'un certificat (0.5.0) — jamais sa clé. */
127
+ export interface CertificateInfo {
128
+ subject: string;
129
+ issuer?: string;
130
+ serial?: string;
131
+ notBefore?: string | null;
132
+ notAfter?: string | null;
133
+ /** Émetteur = titulaire : personne d'autre ne s'en porte garant. */
134
+ selfSigned?: boolean;
135
+ }
136
+ /** Le jeton d'horodatage RFC 3161 attaché à une signature, ou l'horodatage de document (0.5.0). */
137
+ export interface TimestampInfo {
138
+ /** La date ATTESTÉE par l'horodateur (ISO 8601) — à opposer à `claimedSigningTime`. */
139
+ genTime: string | null;
140
+ /** Politique d'horodatage (OID), celle que publie le prestataire. */
141
+ policy: string;
142
+ serial?: string;
143
+ hashAlgorithm?: string;
144
+ tsa: CertificateInfo | null;
145
+ /** Sujets des certificats embarqués dans le jeton. */
146
+ chain: string[];
147
+ intact: boolean | null;
148
+ valid: boolean | null;
149
+ trusted: boolean | null;
150
+ }
110
151
  export interface SignatureInfo {
111
152
  field?: string;
112
153
  intact?: boolean;
113
154
  valid?: boolean;
114
155
  trusted?: boolean;
115
156
  signer?: string;
157
+ type?: "signature" | "horodatage-document";
158
+ /** Nom AFFICHÉ par les lecteurs (« signé par … ») : déclaratif, à ne pas confondre avec le certificat. */
159
+ name?: string | null;
160
+ reason?: string | null;
161
+ location?: string | null;
162
+ subFilter?: string | null;
163
+ /** L'heure DÉCLARÉE par le signataire : sans horodatage, elle est antidatable. */
164
+ claimedSigningTime?: string | null;
165
+ coverage?: string | null;
166
+ digestAlgorithm?: string | null;
167
+ signerCertificate?: CertificateInfo | null;
168
+ timestamp?: TimestampInfo | null;
169
+ /** Cause, quand le moteur refuse de valider la signature (rendue invalide, jamais en panne). */
170
+ error?: string;
171
+ /** PAdES-B-B (aucune date attestée), B-T (jeton), B-LT (+ DSS), ou horodatage de document (B-LTA). */
172
+ level?: string;
116
173
  }
117
174
  export interface VerifyResult {
118
175
  signed: boolean;
119
176
  signatures: SignatureInfo[];
120
177
  engine: "pyhanko" | "node";
178
+ /** Données de validation à long terme (DSS) présentes dans le document (0.5.0). */
179
+ dss?: boolean;
121
180
  }
122
181
  export interface EngineAvailability {
123
182
  node: boolean;
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
package/dist/verify.js CHANGED
@@ -39,7 +39,7 @@ export function verifyPdf(opts) {
39
39
  }
40
40
  const line = out.trim().split("\n").pop() ?? "{}";
41
41
  const parsed = JSON.parse(line);
42
- return { signed: !!parsed.signed, signatures: parsed.signatures ?? [], engine: "pyhanko" };
42
+ return { signed: !!parsed.signed, signatures: parsed.signatures ?? [], engine: "pyhanko", dss: !!parsed.dss };
43
43
  }
44
44
  // Détection Node basique : présence d'un /ByteRange + dictionnaire de signature.
45
45
  const s = readFileSync(opts.input).toString("latin1");
@@ -1 +1 @@
1
- {"version":3,"file":"verify.js","sourceRoot":"","sources":["../src/verify.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"verify.js","sourceRoot":"","sources":["../src/verify.ts"],"names":[],"mappings":"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"}
package/llms.txt CHANGED
@@ -1,7 +1,7 @@
1
1
  # @mostajs/pdf-sign — fiche LLM
2
2
  > Signature numérique de PDF, moteur HYBRIDE : cœur Node (PKCS#7 détaché via @signpdf, zéro Python) + bascule pyhanko (PAdES visible + permissions AES-256 + MOT DE PASSE d'ouverture) quand un venv est disponible. Config 100 % `.env`, CLI + API. Portage générique du pipeline pyhanko+pikepdf éprouvé. IMPLÉMENTÉ 0.1.0.
3
3
 
4
- - Version: 0.4.1 · Licence: AGPL-3.0-or-later · Auteur: Dr Hamid MADANI <drmdh@msn.com>
4
+ - Version: 0.5.0 · Licence: AGPL-3.0-or-later · Auteur: Dr Hamid MADANI <drmdh@msn.com>
5
5
  - Chemin: mostajs/mosta-pdf-sign-stack/mosta-pdf-sign · UI: ../mosta-pdf-sign-ui
6
6
 
7
7
  ## RÔLE
@@ -32,7 +32,15 @@ La signature PAdES + permissions AES-256 garantit intégrité, authenticité et
32
32
  · opts.timestampUrl : horodatage RFC 3161 → PAdES-T (0.3.0). Horodateur muet ⇒ la signature ÉCHOUE.
33
33
  · opts.timestampHeaders / opts.timestampAuth / opts.timestampTimeout (0.4.0) : joindre un
34
34
  horodateur QUALIFIÉ, qui authentifie (clé d'API en en-tête, ou HTTP Basic). Exige pyhanko.
35
+ - timestampPdf(opts): Promise<SignResult> (0.6.0) — horodatage de DOCUMENT (DocTimeStamp) ajouté par mise à jour
36
+ incrémentale à un PDF déjà signé : signatures existantes intactes. opts : input, output?, timestampUrl (requis),
37
+ timestampHeaders?/timestampAuth?/timestampTimeout?, openPassword?. Mêmes garde-fous que signPdf, aucun repli.
38
+ Exige pyhanko.
35
39
  - verifyPdf(opts): VerifyResult — validation pyhanko complète si dispo, sinon détection Node (/ByteRange)
40
+ 0.5.0 : + par signature type, level (PAdES-B-B/B-T/B-LT), claimedSigningTime (DÉCLARÉE), timestamp
41
+ {genTime (ATTESTÉE), policy OID, tsa, chain, intact/valid/trusted}, signerCertificate {subject, issuer,
42
+ notBefore, notAfter, selfSigned}, name/reason/location, coverage ; document : dss. Signature que
43
+ pyhanko refuse = invalide avec `error`, jamais une exception.
36
44
  - detectEngines(python?): EngineAvailability — { node:true, pyhanko:bool, python }
37
45
  - resolvePython / pyhankoAvailable
38
46
  - loadPdfSignConfig(): PdfSignConfig — lecture `.env` via @mostajs/config
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mostajs/pdf-sign",
3
- "version": "0.4.1",
3
+ "version": "0.6.0",
4
4
  "description": "Signature numérique de PDF pour @mostajs — moteur HYBRIDE : cœur Node (PKCS#7 via @signpdf) + bascule pyhanko (PAdES + permissions AES-256) si disponible. Config .env, CLI, API. Réutilise le pipeline éprouvé pyhanko+pikepdf.",
5
5
  "author": "Dr Hamid MADANI <drmdh@msn.com>",
6
6
  "license": "AGPL-3.0-or-later",
@@ -9,6 +9,7 @@ ET la validité cryptographique de la signature.
9
9
  Usage :
10
10
  sign_with_perms.py sign INPUT.pdf OUTPUT.pdf CERT.p12 PASSFILE CONFIG.json
11
11
  sign_with_perms.py verify PDF [CERT.pem] [MOT_DE_PASSE]
12
+ sign_with_perms.py timestamp INPUT.pdf OUTPUT.pdf CONFIG.json (0.6.0 : horodatage de document)
12
13
 
13
14
  Le moteur Node (@mostajs/pdf-sign) écrit CONFIG.json puis appelle ce script.
14
15
 
@@ -212,6 +213,112 @@ def _cert_name(cert):
212
213
  return str(cert) if cert else ""
213
214
 
214
215
 
216
+ def _iso(d):
217
+ try:
218
+ return d.isoformat() if d is not None else None
219
+ except Exception:
220
+ return None
221
+
222
+
223
+ def _cert_info(c):
224
+ """Ce qu'un vérificateur doit voir d'un certificat — jamais sa clé."""
225
+ if c is None:
226
+ return None
227
+ try:
228
+ v = c["tbs_certificate"]["validity"]
229
+ return {
230
+ "subject": c.subject.human_friendly,
231
+ "issuer": c.issuer.human_friendly,
232
+ "serial": format(c.serial_number, "x"),
233
+ "notBefore": _iso(v["not_before"].native),
234
+ "notAfter": _iso(v["not_after"].native),
235
+ "selfSigned": c.subject == c.issuer,
236
+ }
237
+ except Exception:
238
+ return {"subject": _cert_name(c)}
239
+
240
+
241
+ def _jeton(token):
242
+ """Le jeton RFC 3161 : date, politique, autorité, chaîne embarquée."""
243
+ try:
244
+ sd = token["content"]
245
+ tst = sd["encap_content_info"]["content"].parsed
246
+ certs = [c.chosen for c in (sd["certificates"] or [])]
247
+ tsa = certs[0] if certs else None
248
+ sid = sd["signer_infos"][0]["sid"]
249
+ for c in certs: # le certificat qui a SIGNÉ le jeton, pas le premier venu
250
+ if sid.name == "issuer_and_serial_number" and c.serial_number == sid.chosen["serial_number"].native:
251
+ tsa = c
252
+ return {
253
+ "genTime": _iso(tst["gen_time"].native),
254
+ "policy": tst["policy"].dotted,
255
+ "serial": format(tst["serial_number"].native, "x"),
256
+ "hashAlgorithm": tst["message_imprint"]["hash_algorithm"]["algorithm"].native,
257
+ "tsa": _cert_info(tsa),
258
+ "chain": [c.subject.human_friendly for c in certs],
259
+ }
260
+ except Exception:
261
+ return None
262
+
263
+
264
+ def _details(s, status, est_horodatage, dss):
265
+ d = {"type": "horodatage-document" if est_horodatage else "signature"}
266
+ so = s.sig_object
267
+ for cle, nom in (("/Name", "name"), ("/Reason", "reason"), ("/Location", "location"), ("/SubFilter", "subFilter")):
268
+ try:
269
+ v = so.get(cle)
270
+ d[nom] = str(v).lstrip("/") if v is not None else None
271
+ except Exception:
272
+ d[nom] = None
273
+ try:
274
+ d["claimedSigningTime"] = _iso(s.self_reported_timestamp) # DÉCLARÉE par le signataire
275
+ except Exception:
276
+ d["claimedSigningTime"] = None
277
+ try:
278
+ d["coverage"] = status.coverage.name
279
+ except Exception:
280
+ d["coverage"] = None
281
+ try:
282
+ d["digestAlgorithm"] = status.md_algorithm
283
+ except Exception:
284
+ d["digestAlgorithm"] = None
285
+ try:
286
+ cert = getattr(status, "signing_cert", None) if status is not None else s.signer_cert
287
+ except Exception:
288
+ cert = None
289
+ d["signerCertificate"] = _cert_info(cert)
290
+ jeton = None
291
+ if est_horodatage:
292
+ try:
293
+ jeton = _jeton(s.signed_data_obj if hasattr(s, "signed_data_obj") else None) or None
294
+ except Exception:
295
+ jeton = None
296
+ if jeton is None:
297
+ try:
298
+ from asn1crypto import cms
299
+ jeton = _jeton(cms.ContentInfo({"content_type": "signed_data", "content": s.signed_data}))
300
+ except Exception:
301
+ jeton = None
302
+ else:
303
+ try:
304
+ attrs = s.signer_info["unsigned_attrs"] or []
305
+ toks = [a["values"][0] for a in attrs if a["type"].native == "signature_time_stamp_token"]
306
+ jeton = _jeton(toks[0]) if toks else None
307
+ except Exception:
308
+ jeton = None
309
+ if jeton is not None:
310
+ tv = getattr(status, "timestamp_validity", None) if not est_horodatage else status
311
+ jeton["intact"] = bool(getattr(tv, "intact", False)) if tv is not None else None
312
+ jeton["valid"] = bool(getattr(tv, "valid", False)) if tv is not None else None
313
+ jeton["trusted"] = bool(getattr(tv, "trusted", False)) if tv is not None else None
314
+ d["timestamp"] = jeton
315
+ if est_horodatage:
316
+ d["level"] = "horodatage de document (PAdES-B-LTA)"
317
+ else:
318
+ d["level"] = "PAdES-B-LT" if (jeton and dss) else ("PAdES-B-T" if jeton else "PAdES-B-B")
319
+ return d
320
+
321
+
215
322
  def do_verify(pdf_path, cert_pem, open_password=None):
216
323
  import logging
217
324
  # Silence les logs internes (tracebacks de chaîne de confiance) : on renvoie le verdict en JSON.
@@ -262,21 +369,85 @@ def do_verify(pdf_path, cert_pem, open_password=None):
262
369
  print(json.dumps({"signed": False, "signatures": []}))
263
370
  return
264
371
  out = []
372
+ dss = "/DSS" in r.root
265
373
  for s in sigs:
266
- status = validate_pdf_signature(s, vc)
267
- out.append({
268
- "field": s.field_name,
269
- "intact": bool(status.intact),
270
- "valid": bool(status.valid),
271
- "trusted": bool(getattr(status, "trusted", False)),
272
- "signer": _cert_name(getattr(status, "signing_cert", None)),
273
- })
274
- print(json.dumps({"signed": True, "signatures": out}))
374
+ est_horodatage = str(s.sig_object.get("/Type", "")) == "/DocTimeStamp"
375
+ # 0.5.0 : une signature que pyhanko REFUSE de valider (structure CMS abîmée, certificat
376
+ # qui ne correspond plus…) est un verdict — invalide —, pas une panne de la vérification.
377
+ # Jusqu'en 0.4.1, l'exception remontait et l'appelant ne lisait plus RIEN du document.
378
+ try:
379
+ if est_horodatage:
380
+ from pyhanko.sign.validation import validate_pdf_timestamp
381
+ status = validate_pdf_timestamp(s, vc)
382
+ else:
383
+ status = validate_pdf_signature(s, vc)
384
+ base = {
385
+ "field": s.field_name,
386
+ "intact": bool(status.intact),
387
+ "valid": bool(status.valid),
388
+ "trusted": bool(getattr(status, "trusted", False)),
389
+ "signer": _cert_name(getattr(status, "signing_cert", None)),
390
+ }
391
+ except Exception as e:
392
+ status = None
393
+ try:
394
+ signataire = s.signer_cert
395
+ except Exception:
396
+ signataire = None
397
+ base = {"field": s.field_name, "intact": False, "valid": False, "trusted": False,
398
+ "signer": _cert_name(signataire), "error": str(e).split("\n")[0][:300]}
399
+ # 0.5.0 — le DÉTAIL, additif : chaque champ est lu à part, et un champ illisible vaut
400
+ # null plutôt que de faire échouer la vérification entière.
401
+ base.update(_details(s, status, est_horodatage, dss))
402
+ out.append(base)
403
+ print(json.dumps({"signed": True, "signatures": out, "dss": dss}, default=str))
404
+
405
+
406
+ def do_timestamp(inp, outp, config_path):
407
+ """0.6.0 -- HORODATAGE DE DOCUMENT (PAdES DocTimeStamp), par mise a jour incrementale.
408
+
409
+ Les signatures deja presentes restent intactes : les octets d'origine ne sont pas reecrits. Un document chiffre
410
+ par des permissions (sans mot de passe d'ouverture) s'ouvre avec la chaine vide -- les permissions posees a la
411
+ signature laissent toujours `modify_form`. Aucun repli : un horodateur qui ne repond pas fait echouer.
412
+ """
413
+ from pyhanko.pdf_utils.incremental_writer import IncrementalPdfFileWriter
414
+ from pyhanko.sign import signers, timestamps
415
+
416
+ with open(config_path, "r", encoding="utf-8") as f:
417
+ cfg = json.load(f)
418
+ tsa_url = cfg.get("timestamp_url")
419
+ if not tsa_url:
420
+ raise SystemExit("ERREUR -- horodatage impossible : aucune adresse d'horodateur.")
421
+ auth_cfg = cfg.get("timestamp_auth")
422
+ auth = (auth_cfg["user"], auth_cfg.get("password", "")) if auth_cfg else None
423
+ print(f"-- horodatage de document : {tsa_url}%s --" % (" (authentifie)" if auth or cfg.get("timestamp_headers") else ""),
424
+ flush=True)
425
+ timestamper = timestamps.HTTPTimeStamper(
426
+ url=tsa_url, headers=cfg.get("timestamp_headers") or None, auth=auth,
427
+ timeout=cfg.get("timestamp_timeout") or 10,
428
+ )
429
+ with open(inp, "rb") as src:
430
+ writer = IncrementalPdfFileWriter(src)
431
+ if getattr(writer.prev, "encrypted", False):
432
+ from pyhanko.pdf_utils.crypt import AuthStatus
433
+ if writer.encrypt(cfg.get("open_password") or "").status == AuthStatus.FAILED:
434
+ raise SystemExit("ERREUR -- document verrouillé : son mot de passe d'ouverture est requis pour l'horodater.")
435
+ with open(outp, "wb") as out_f:
436
+ try:
437
+ signers.PdfTimeStamper(timestamper).timestamp_pdf(writer, md_algorithm="sha256", output=out_f)
438
+ except Exception as e:
439
+ raise SystemExit(
440
+ f"ERREUR -- horodatage impossible ({tsa_url}) : {_cause_horodatage(e)}. "
441
+ "Le document n'a PAS été horodaté."
442
+ )
443
+ print(f"OK -- PDF horodaté : {outp}", flush=True)
275
444
 
276
445
 
277
446
  if __name__ == "__main__":
278
447
  if len(sys.argv) >= 2 and sys.argv[1] == "sign" and len(sys.argv) == 7:
279
448
  do_sign(sys.argv[2], sys.argv[3], sys.argv[4], sys.argv[5], sys.argv[6])
449
+ elif len(sys.argv) == 5 and sys.argv[1] == "timestamp":
450
+ do_timestamp(sys.argv[2], sys.argv[3], sys.argv[4])
280
451
  elif len(sys.argv) >= 2 and sys.argv[1] == "verify" and len(sys.argv) >= 3:
281
452
  do_verify(sys.argv[2],
282
453
  sys.argv[3] if len(sys.argv) > 3 and sys.argv[3] else None,