@mostajs/pdf-sign 0.3.1 → 0.4.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,80 @@
1
1
  # Changelog — @mostajs/pdf-sign
2
2
 
3
+ ## 0.4.0 — 28/09/2026
4
+
5
+ **Joindre un horodateur qui authentifie — c'est-à-dire un horodateur QUALIFIÉ.**
6
+
7
+ Un horodateur qualifié (eIDAS art. 42) est un service payant : il authentifie son client. Evidency,
8
+ par exemple, exige une clé d'API dans l'en-tête `X-API-KEY`. Jusqu'en 0.3.2, ce module ne savait
9
+ transmettre qu'une adresse : seuls les horodateurs publics et gratuits — donc **non qualifiés** —
10
+ étaient joignables. Relevé le 28/09/2026, à la lecture de la réponse écrite d'Evidency.
11
+
12
+ ### Ajouté
13
+
14
+ - `timestampHeaders` (en-têtes, typiquement une clé d'API), `timestampAuth` (HTTP Basic),
15
+ `timestampTimeout` (secondes, défaut 10 — pyhanko en fixait 5 en dur).
16
+ - `.env` : `PDF_SIGN_TSA`, `PDF_SIGN_TSA_API_KEY`, `PDF_SIGN_TSA_API_KEY_HEADER`,
17
+ `PDF_SIGN_TSA_USER`, `PDF_SIGN_TSA_PASSWORD`, `PDF_SIGN_TSA_TIMEOUT`.
18
+ - CLI : `--tsa <url>`, `--tsa-timeout <s>`. Les identifiants, eux, ne passent **que** par le `.env`.
19
+ - Un refus de l'horodateur est **nommé** : 401/403 ⇒ « identifiants refusés », 429 ⇒ « débit
20
+ dépassé ». pyhanko ne regarde que le type de contenu de la réponse et présentait un 401 comme
21
+ une « réponse malformée », ce qui envoyait chercher un défaut de protocole.
22
+
23
+ ### Corrigé — un repli silencieux
24
+
25
+ **Le moteur Node ignorait `timestampUrl`.** En `auto` sur une machine sans pyhanko, un document
26
+ demandé horodaté sortait **signé sans date, sans erreur** — exactement le repli que ce module
27
+ interdit partout ailleurs. Désormais : erreur explicite, qui dit quoi installer.
28
+
29
+ ### Garde-fous
30
+
31
+ | refusé | pourquoi |
32
+ |---|---|
33
+ | identifiants vers `http://` non local | une clé envoyée en clair est une clé publiée |
34
+ | identifiants sans `timestampUrl` | une configuration à moitié posée ne doit pas passer pour complète |
35
+ | clé du `.env` vers un autre horodateur que `PDF_SIGN_TSA` | la joindre à une requête vers un tiers, c'est la lui donner — même règle que le certificat et sa phrase |
36
+
37
+ ### Essais
38
+
39
+ `test-scripts/test-horodatage-authentifie.ts` — 8 essais (T-TSA-1 à 8), par un relais local qui
40
+ EXIGE les identifiants puis transmet à l'horodateur public de DigiCert : le jeton obtenu est un vrai
41
+ jeton, dont la présence est vérifiée dans la signature. T-TSA-8 vérifie ce que le **serveur a reçu**,
42
+ pas ce que le client affirme avoir envoyé. Deux mutations (appariement retiré, refus Node retiré)
43
+ font chacune échouer l'essai qui les garde ; le détecteur de jeton répond « NON » sur un document
44
+ signé sans horodatage.
45
+
46
+ ### Compatibilité
47
+
48
+ Aucun changement pour un appelant qui ne passe pas d'identifiants. **Un seul changement de
49
+ comportement** : `timestampUrl` avec le moteur Node lève désormais au lieu de signer sans date —
50
+ un appelant qui en dépendait recevait un document faux.
51
+
52
+ ## 0.3.2 — 26/09/2026
53
+
54
+ **`modify_form` ne peut pas être refusé — et le dire vaut mieux que l'ignorer.**
55
+
56
+ 0.3.1 a ajouté `modifyForm` à la table des permissions en annonçant qu'il serait « refusé par
57
+ défaut ». Il ne l'était pas, et ne pouvait pas l'être : `python/sign_with_perms.py` écrit
58
+ `modify_form=True` en dur, avec raison. En PDF, un champ de **signature** est un champ de
59
+ **formulaire** ; le sceau étant apposé **après** le chiffrement, l'interdire reviendrait à
60
+ s'interdire de sceller.
61
+
62
+ La valeur transmise par 0.3.1 était donc **silencieusement ignorée** — la pire des trois issues
63
+ possibles, parce qu'elle laissait croire à une restriction qui n'existait pas.
64
+
65
+ Désormais : `modifyForm: false` provoque une **erreur explicite**, `modifyForm: true` et l'absence
66
+ de la clé donnent le comportement inchangé. Le type le dit, le python le dit, et l'erreur nomme la
67
+ raison. Croire un formulaire verrouillé quand il ne l'est pas est pire que le savoir.
68
+
69
+ ### Ce que cela change pour un appelant
70
+
71
+ | avant | après |
72
+ |---|---|
73
+ | `modifyForm: false` ⇒ ignoré, document scellé, formulaire remplissable | ⇒ **erreur**, nomme la contrainte |
74
+ | `modifyForm: true` / absent | inchangé |
75
+
76
+ Aucun document déjà scellé n'est concerné : leur permission était déjà celle-là.
77
+
3
78
  ## 0.3.1 — 26/09/2026
4
79
 
5
80
  **`modify_form` manquait à la table des permissions.**
@@ -12,7 +87,13 @@ Personne ne pouvait le voir : la case n'existait dans aucune interface, et le d
12
87
  manifeste que sur un document QUI A des champs de formulaire. Relevé en inspectant un document de
13
88
  production, à l'occasion d'une tout autre question.
14
89
 
15
- Il est désormais transmis, et **refusé par défaut** comme ses voisins.
90
+ Il est désormais transmis à la couche python.
91
+
92
+ > ### ⚠️ Correction — voir 0.3.2
93
+ > Cette version annonçait aussi « **refusé par défaut** comme ses voisins ». **C'était faux.**
94
+ > `python/sign_with_perms.py` force `modify_form=True` depuis l'origine, et le doit : le sceau
95
+ > est apposé après le chiffrement, et un champ de signature est un champ de formulaire. La
96
+ > valeur transmise n'avait donc aucun effet. 0.3.2 le dit au lieu de le taire.
16
97
 
17
98
  ## 0.3.0 — 26/09/2026
18
99
 
package/README.md CHANGED
@@ -108,6 +108,41 @@ await signPdf({ input: "note.pdf", p12: "cert.p12", passphrase: "•••", ope
108
108
  > elle, ses signatures sont illisibles et la réponse serait « non signé » — sur un document
109
109
  > parfaitement signé.
110
110
 
111
+ ## Horodatage — et joindre un horodateur QUALIFIÉ *(0.4.0)*
112
+
113
+ `timestampUrl` fait passer la signature de **PAdES-B** à **PAdES-T** : la date n'est plus déclarée
114
+ par le signataire, elle est attestée par un tiers. Si l'horodateur ne répond pas, la signature
115
+ **échoue** — jamais de repli sur une signature sans date.
116
+
117
+ Un horodateur **qualifié** (eIDAS art. 42, celui dont la date renverse la charge de la preuve) est
118
+ un service payant : il **authentifie** son client. Depuis 0.4.0 :
119
+
120
+ ```ts
121
+ await signPdf({
122
+ input: "in.pdf", output: "out.pdf", p12: "cachet.p12", passphraseFile: "cachet.pass",
123
+ timestampUrl: "https://api.evidency.io/v3/projects/<ID>/timestamp",
124
+ timestampHeaders: { "X-API-KEY": process.env.CLE }, // ou timestampAuth: { user, password }
125
+ timestampTimeout: 10,
126
+ });
127
+ ```
128
+
129
+ Ou, sans toucher au code, par le `.env` : `PDF_SIGN_TSA`, `PDF_SIGN_TSA_API_KEY` (voir plus bas).
130
+
131
+ **Quatre garde-fous**, chacun couvert par un essai (`test-scripts/test-horodatage-authentifie.ts`) :
132
+
133
+ | | ce qui est refusé | pourquoi |
134
+ |---|---|---|
135
+ | 1 | le moteur **Node** avec un `timestampUrl` | il ne sait pas horodater ; jusqu'en 0.3.2 il signait **sans date, sans rien dire** |
136
+ | 2 | des identifiants vers une adresse `http://` non locale | une clé envoyée en clair est une clé publiée |
137
+ | 3 | des identifiants sans adresse | une configuration à moitié posée ne doit pas passer pour complète |
138
+ | 4 | la clé du `.env` vers **un autre** horodateur que `PDF_SIGN_TSA` | joindre sa clé à une requête vers un tiers, c'est la lui donner |
139
+
140
+ Un refus d'identifiants est **nommé** : « identifiants refusés par l'horodateur (HTTP 401) ».
141
+ pyhanko, seul, l'aurait présenté comme une « réponse malformée ».
142
+
143
+ Les identifiants partent au moteur par le fichier de configuration temporaire (dossier en 0700,
144
+ effacé après usage), **jamais** par la ligne de commande — et le CLI ne les accepte qu'en `.env`.
145
+
111
146
  ## Configuration (`.env`)
112
147
 
113
148
  | Clé | Rôle |
@@ -120,6 +155,10 @@ await signPdf({ input: "note.pdf", p12: "cert.p12", passphrase: "•••", ope
120
155
  | `PDF_SIGN_STAMP_IMAGE` | image de fond du cachet visible (logo/tampon derrière le texte ; moteur pyhanko) |
121
156
  | `PDF_SIGN_RESTRICT` | `true` → permissions restrictives (pyhanko) |
122
157
  | `PDF_SIGN_TRUST_PEM` | certificat de confiance pour la vérification |
158
+ | `PDF_SIGN_TSA` | adresse de l'horodateur de la configuration — sert à **apparier** les identifiants ci-dessous *(0.4.0)* |
159
+ | `PDF_SIGN_TSA_API_KEY` / `PDF_SIGN_TSA_API_KEY_HEADER` | clé d'API de l'horodateur, et le nom de son en-tête (défaut `X-API-KEY`) *(0.4.0)* |
160
+ | `PDF_SIGN_TSA_USER` / `PDF_SIGN_TSA_PASSWORD` | identifiants HTTP Basic de l'horodateur *(0.4.0)* |
161
+ | `PDF_SIGN_TSA_TIMEOUT` | délai d'attente de l'horodateur, en secondes (défaut 10) *(0.4.0)* |
123
162
 
124
163
  ## Moteurs
125
164
 
package/dist/cli.js CHANGED
@@ -24,6 +24,12 @@ const HELP = `mosta-pdf-sign — signature numérique de PDF (moteur hybride Nod
24
24
  --restrict permissions restrictives (PAdES pyhanko requis)
25
25
  --open-password <str> mot de passe exigé à l'OUVERTURE (chiffrement, pyhanko requis)
26
26
  --reason --name --location --contact
27
+ --tsa <url> horodatage RFC 3161 (PAdES-T) ; échoue plutôt que signer sans date
28
+ --tsa-timeout <s> délai d'attente de l'horodateur (défaut 10 s)
29
+ Identifiants de l'horodateur : .env UNIQUEMENT (PDF_SIGN_TSA_API_KEY,
30
+ PDF_SIGN_TSA_USER/PASSWORD) — jamais en argument, la ligne de commande
31
+ se lit dans la table des processus. Ils ne partent que si --tsa
32
+ vaut PDF_SIGN_TSA.
27
33
  mosta-pdf-sign verify <pdf> [--trust cert.pem] [--password <str>] [--engine ...]
28
34
  mosta-pdf-sign engines état des moteurs disponibles
29
35
  `;
@@ -55,6 +61,8 @@ async function main() {
55
61
  engine: opt(argv, "engine"),
56
62
  permissions: flag(argv, "restrict") ? {} : undefined,
57
63
  openPassword: opt(argv, "open-password"),
64
+ timestampUrl: opt(argv, "tsa"),
65
+ timestampTimeout: opt(argv, "tsa-timeout") ? Number(opt(argv, "tsa-timeout")) : undefined,
58
66
  meta: {
59
67
  reason: opt(argv, "reason"), name: opt(argv, "name"),
60
68
  location: opt(argv, "location"), contact: opt(argv, "contact"),
package/dist/cli.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AACA;;;;;GAKG;AACH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACxC,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAG7C,SAAS,GAAG,CAAC,IAAc,EAAE,IAAY;IACvC,MAAM,CAAC,GAAG,IAAI,CAAC,OAAO,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC;IACpC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;AACjE,CAAC;AACD,SAAS,IAAI,CAAC,IAAc,EAAE,IAAY;IACxC,OAAO,IAAI,CAAC,QAAQ,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC;AACpC,CAAC;AAED,MAAM,IAAI,GAAG;;;;;;;;;;;;;;;;;CAiBZ,CAAC;AAEF,KAAK,UAAU,IAAI;IACjB,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IACnC,MAAM,GAAG,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;IACpB,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC;IAE9D,IAAI,CAAC,GAAG,IAAI,GAAG,KAAK,QAAQ,IAAI,GAAG,KAAK,IAAI,EAAE,CAAC;QAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QAAC,OAAO;IAAC,CAAC;IAErF,IAAI,GAAG,KAAK,SAAS,EAAE,CAAC;QACtB,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,aAAa,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;QACtD,OAAO;IACT,CAAC;IAED,IAAI,GAAG,KAAK,MAAM,EAAE,CAAC;QACnB,MAAM,KAAK,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;QACtB,MAAM,MAAM,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;QACvB,IAAI,CAAC,KAAK,EAAE,CAAC;YAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,yBAAyB,GAAG,IAAI,CAAC,CAAC;YAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAAC,CAAC;QACxF,MAAM,GAAG,GAAG,MAAM,OAAO,CAAC;YACxB,KAAK;YACL,MAAM;YACN,GAAG,EAAE,GAAG,CAAC,IAAI,EAAE,KAAK,CAAW;YAC/B,UAAU,EAAE,GAAG,CAAC,IAAI,EAAE,MAAM,CAAC;YAC7B,cAAc,EAAE,GAAG,CAAC,IAAI,EAAE,WAAW,CAAC;YACtC,MAAM,EAAE,GAAG,CAAC,IAAI,EAAE,QAAQ,CAA2B;YACrD,WAAW,EAAE,IAAI,CAAC,IAAI,EAAE,UAAU,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,SAAS;YACpD,YAAY,EAAE,GAAG,CAAC,IAAI,EAAE,eAAe,CAAC;YACxC,YAAY,EAAE,GAAG,CAAC,IAAI,EAAE,KAAK,CAAC;YAC9B,gBAAgB,EAAE,GAAG,CAAC,IAAI,EAAE,aAAa,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,EAAE,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS;YACzF,IAAI,EAAE;gBACJ,MAAM,EAAE,GAAG,CAAC,IAAI,EAAE,QAAQ,CAAC,EAAE,IAAI,EAAE,GAAG,CAAC,IAAI,EAAE,MAAM,CAAC;gBACpD,QAAQ,EAAE,GAAG,CAAC,IAAI,EAAE,UAAU,CAAC,EAAE,OAAO,EAAE,GAAG,CAAC,IAAI,EAAE,SAAS,CAAC;aAC/D;SACF,CAAC,CAAC;QACH,OAAO,CAAC,GAAG,CAAC,eAAe,GAAG,CAAC,MAAM,OAAO,GAAG,CAAC,MAAM,IAAI,UAAU,EAAE,CAAC,CAAC;QACxE,OAAO;IACT,CAAC;IAED,IAAI,GAAG,KAAK,QAAQ,EAAE,CAAC;QACrB,MAAM,KAAK,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;QACtB,IAAI,CAAC,KAAK,EAAE,CAAC;YAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,4BAA4B,CAAC,CAAC;YAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAAC,CAAC;QACpF,MAAM,GAAG,GAAG,SAAS,CAAC;YACpB,KAAK,EAAE,QAAQ,EAAE,GAAG,CAAC,IAAI,EAAE,OAAO,CAAC,EAAE,YAAY,EAAE,GAAG,CAAC,IAAI,EAAE,UAAU,CAAC;YACxE,MAAM,EAAE,GAAG,CAAC,IAAI,EAAE,QAAQ,CAA2B;SACtD,CAAC,CAAC;QACH,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;QAC1C,OAAO;IACT,CAAC;IAED,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,uBAAuB,GAAG,IAAI,GAAG,IAAI,CAAC,CAAC;IAC5D,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,EAAE,OAAO,IAAI,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC"}
package/dist/config.d.ts CHANGED
@@ -9,6 +9,15 @@ export interface PdfSignConfig {
9
9
  field: SignField;
10
10
  restrict: boolean;
11
11
  trustPem?: string;
12
+ /** Horodateur de la configuration et SES identifiants (0.4.0). */
13
+ tsa: {
14
+ url?: string;
15
+ apiKey?: string;
16
+ apiKeyHeader: string;
17
+ user?: string;
18
+ password?: string;
19
+ timeout?: number;
20
+ };
12
21
  }
13
22
  export declare function loadPdfSignConfig(): PdfSignConfig;
14
23
  //# sourceMappingURL=config.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAE,UAAU,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAElE,MAAM,WAAW,aAAa;IAC5B,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,MAAM,EAAE,UAAU,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,QAAQ,CAAC;IACf,KAAK,EAAE,SAAS,CAAC;IACjB,QAAQ,EAAE,OAAO,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAOD,wBAAgB,iBAAiB,IAAI,aAAa,CAwBjD"}
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAiBA,OAAO,KAAK,EAAE,UAAU,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAElE,MAAM,WAAW,aAAa;IAC5B,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,MAAM,EAAE,UAAU,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,QAAQ,CAAC;IACf,KAAK,EAAE,SAAS,CAAC;IACjB,QAAQ,EAAE,OAAO,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,kEAAkE;IAClE,GAAG,EAAE;QACH,GAAG,CAAC,EAAE,MAAM,CAAC;QACb,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,YAAY,EAAE,MAAM,CAAC;QACrB,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,OAAO,CAAC,EAAE,MAAM,CAAC;KAClB,CAAC;CACH;AAOD,wBAAgB,iBAAiB,IAAI,aAAa,CAiCjD"}
package/dist/config.js CHANGED
@@ -7,6 +7,9 @@
7
7
  * PDF_SIGN_REASON / PDF_SIGN_LOCATION / PDF_SIGN_NAME / PDF_SIGN_CONTACT
8
8
  * PDF_SIGN_FIELD_PAGE / PDF_SIGN_FIELD_BOX ("x1,y1,x2,y2") · PDF_SIGN_STAMP_IMAGE (logo du cachet) · PDF_SIGN_RESTRICT (bool)
9
9
  * PDF_SIGN_TRUST_PEM (validation)
10
+ * PDF_SIGN_TSA (adresse de l'horodateur — sert à APPARIER les identifiants, voir `sign.ts`)
11
+ * PDF_SIGN_TSA_API_KEY · PDF_SIGN_TSA_API_KEY_HEADER (défaut X-API-KEY)
12
+ * PDF_SIGN_TSA_USER · PDF_SIGN_TSA_PASSWORD (HTTP Basic) · PDF_SIGN_TSA_TIMEOUT (secondes)
10
13
  *
11
14
  * @author Dr Hamid MADANI <drmdh@msn.com>
12
15
  * @license AGPL-3.0-or-later
@@ -20,6 +23,7 @@ export function loadPdfSignConfig() {
20
23
  const engine = getEnv("PDF_SIGN_ENGINE", "auto");
21
24
  const box = getEnv("PDF_SIGN_FIELD_BOX", "");
22
25
  const page = getEnv("PDF_SIGN_FIELD_PAGE", "");
26
+ const timeout = getEnv("PDF_SIGN_TSA_TIMEOUT", "");
23
27
  return {
24
28
  p12: getEnv("PDF_SIGN_P12", "") || undefined,
25
29
  passphrase: getEnv("PDF_SIGN_PASSPHRASE", "") || undefined,
@@ -39,6 +43,14 @@ export function loadPdfSignConfig() {
39
43
  },
40
44
  restrict: getEnvBool("PDF_SIGN_RESTRICT", false),
41
45
  trustPem: getEnv("PDF_SIGN_TRUST_PEM", "") || undefined,
46
+ tsa: {
47
+ url: getEnv("PDF_SIGN_TSA", "") || undefined,
48
+ apiKey: getEnv("PDF_SIGN_TSA_API_KEY", "") || undefined,
49
+ apiKeyHeader: getEnv("PDF_SIGN_TSA_API_KEY_HEADER", "") || "X-API-KEY",
50
+ user: getEnv("PDF_SIGN_TSA_USER", "") || undefined,
51
+ password: getEnv("PDF_SIGN_TSA_PASSWORD", "") || undefined,
52
+ timeout: timeout && Number(timeout) > 0 ? Number(timeout) : undefined,
53
+ },
42
54
  };
43
55
  }
44
56
  //# sourceMappingURL=config.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAerD,SAAS,QAAQ,CAAC,CAAS;IACzB,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC;IACpD,OAAO,CAAC,CAAC,MAAM,KAAK,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAE,CAAsC,CAAC,CAAC,CAAC,SAAS,CAAC;AAClH,CAAC;AAED,MAAM,UAAU,iBAAiB;IAC/B,MAAM,MAAM,GAAG,MAAM,CAAC,iBAAiB,EAAE,MAAM,CAAC,CAAC;IACjD,MAAM,GAAG,GAAG,MAAM,CAAC,oBAAoB,EAAE,EAAE,CAAC,CAAC;IAC7C,MAAM,IAAI,GAAG,MAAM,CAAC,qBAAqB,EAAE,EAAE,CAAC,CAAC;IAC/C,OAAO;QACL,GAAG,EAAE,MAAM,CAAC,cAAc,EAAE,EAAE,CAAC,IAAI,SAAS;QAC5C,UAAU,EAAE,MAAM,CAAC,qBAAqB,EAAE,EAAE,CAAC,IAAI,SAAS;QAC1D,cAAc,EAAE,MAAM,CAAC,0BAA0B,EAAE,EAAE,CAAC,IAAI,SAAS;QACnE,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAe;QACtF,MAAM,EAAE,MAAM,CAAC,iBAAiB,EAAE,EAAE,CAAC,IAAI,SAAS;QAClD,IAAI,EAAE;YACJ,MAAM,EAAE,MAAM,CAAC,iBAAiB,EAAE,EAAE,CAAC,IAAI,SAAS;YAClD,QAAQ,EAAE,MAAM,CAAC,mBAAmB,EAAE,EAAE,CAAC,IAAI,SAAS;YACtD,IAAI,EAAE,MAAM,CAAC,eAAe,EAAE,EAAE,CAAC,IAAI,SAAS;YAC9C,OAAO,EAAE,MAAM,CAAC,kBAAkB,EAAE,EAAE,CAAC,IAAI,SAAS;SACrD;QACD,KAAK,EAAE;YACL,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,SAAS;YACrC,GAAG,EAAE,GAAG,CAAC,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS;YACpC,UAAU,EAAE,MAAM,CAAC,sBAAsB,EAAE,EAAE,CAAC,IAAI,SAAS;SAC5D;QACD,QAAQ,EAAE,UAAU,CAAC,mBAAmB,EAAE,KAAK,CAAC;QAChD,QAAQ,EAAE,MAAM,CAAC,oBAAoB,EAAE,EAAE,CAAC,IAAI,SAAS;KACxD,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"node-signer.d.ts","sourceRoot":"","sources":["../src/node-signer.ts"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAE1D,iEAAiE;AACjE,wBAAsB,QAAQ,CAAC,IAAI,EAAE,WAAW,GAAG,OAAO,CAAC,UAAU,CAAC,CA0BrE"}
1
+ {"version":3,"file":"node-signer.d.ts","sourceRoot":"","sources":["../src/node-signer.ts"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAE1D,iEAAiE;AACjE,wBAAsB,QAAQ,CAAC,IAAI,EAAE,WAAW,GAAG,OAAO,CAAC,UAAU,CAAC,CA6BrE"}
@@ -15,6 +15,9 @@ export async function signNode(opts) {
15
15
  if (opts.permissions) {
16
16
  throw new Error("Le cœur Node ne gère pas les permissions/PAdES — utilisez engine:'pyhanko' (python/setup-venv.sh).");
17
17
  }
18
+ if (opts.timestampUrl) {
19
+ throw new Error("Le cœur Node ne sait pas horodater — un `timestampUrl` exige engine:'pyhanko' (python/setup-venv.sh).");
20
+ }
18
21
  if (opts.openPassword) {
19
22
  throw new Error("Le cœur Node ne chiffre pas — un mot de passe d'ouverture exige engine:'pyhanko' (python/setup-venv.sh).");
20
23
  }
@@ -1 +1 @@
1
- {"version":3,"file":"node-signer.js","sourceRoot":"","sources":["../src/node-signer.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AACtD,OAAO,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAC3C,OAAO,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAChD,OAAO,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AAGjE,iEAAiE;AACjE,MAAM,CAAC,KAAK,UAAU,QAAQ,CAAC,IAAiB;IAC9C,IAAI,IAAI,CAAC,WAAW,EAAE,CAAC;QACrB,MAAM,IAAI,KAAK,CAAC,oGAAoG,CAAC,CAAC;IACxH,CAAC;IACD,IAAI,IAAI,CAAC,YAAY,EAAE,CAAC;QACtB,MAAM,IAAI,KAAK,CAAC,0GAA0G,CAAC,CAAC;IAC9H,CAAC;IACD,MAAM,SAAS,GAAG,OAAO,IAAI,CAAC,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,YAAY,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACtG,MAAM,SAAS,GAAG,OAAO,IAAI,CAAC,GAAG,KAAK,QAAQ,CAAC,CAAC,CAAC,YAAY,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAEhG,MAAM,eAAe,GAAG,mBAAmB,CAAC;QAC1C,SAAS;QACT,MAAM,EAAE,IAAI,CAAC,IAAI,EAAE,MAAM,IAAI,WAAW;QACxC,WAAW,EAAE,IAAI,CAAC,IAAI,EAAE,OAAO,IAAI,EAAE;QACrC,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,IAAI,IAAI,EAAE;QAC3B,QAAQ,EAAE,IAAI,CAAC,IAAI,EAAE,QAAQ,IAAI,EAAE;KACpC,CAAC,CAAC;IAEH,MAAM,MAAM,GAAG,IAAI,SAAS,CAAC,SAAS,EAAE,EAAE,UAAU,EAAE,IAAI,CAAC,UAAU,IAAI,EAAE,EAAE,CAAC,CAAC;IAC/E,MAAM,MAAM,GAAG,MAAM,IAAI,OAAO,EAAE,CAAC,IAAI,CAAC,eAAe,EAAE,MAAM,CAAC,CAAC;IAEjE,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;QAChB,aAAa,CAAC,IAAI,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QACnC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC;IACjD,CAAC;IACD,OAAO,EAAE,KAAK,EAAE,IAAI,UAAU,CAAC,MAAM,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC;AAC3D,CAAC"}
1
+ {"version":3,"file":"node-signer.js","sourceRoot":"","sources":["../src/node-signer.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AACtD,OAAO,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAC3C,OAAO,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAChD,OAAO,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AAGjE,iEAAiE;AACjE,MAAM,CAAC,KAAK,UAAU,QAAQ,CAAC,IAAiB;IAC9C,IAAI,IAAI,CAAC,WAAW,EAAE,CAAC;QACrB,MAAM,IAAI,KAAK,CAAC,oGAAoG,CAAC,CAAC;IACxH,CAAC;IACD,IAAI,IAAI,CAAC,YAAY,EAAE,CAAC;QACtB,MAAM,IAAI,KAAK,CAAC,uGAAuG,CAAC,CAAC;IAC3H,CAAC;IACD,IAAI,IAAI,CAAC,YAAY,EAAE,CAAC;QACtB,MAAM,IAAI,KAAK,CAAC,0GAA0G,CAAC,CAAC;IAC9H,CAAC;IACD,MAAM,SAAS,GAAG,OAAO,IAAI,CAAC,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,YAAY,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACtG,MAAM,SAAS,GAAG,OAAO,IAAI,CAAC,GAAG,KAAK,QAAQ,CAAC,CAAC,CAAC,YAAY,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAEhG,MAAM,eAAe,GAAG,mBAAmB,CAAC;QAC1C,SAAS;QACT,MAAM,EAAE,IAAI,CAAC,IAAI,EAAE,MAAM,IAAI,WAAW;QACxC,WAAW,EAAE,IAAI,CAAC,IAAI,EAAE,OAAO,IAAI,EAAE;QACrC,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,IAAI,IAAI,EAAE;QAC3B,QAAQ,EAAE,IAAI,CAAC,IAAI,EAAE,QAAQ,IAAI,EAAE;KACpC,CAAC,CAAC;IAEH,MAAM,MAAM,GAAG,IAAI,SAAS,CAAC,SAAS,EAAE,EAAE,UAAU,EAAE,IAAI,CAAC,UAAU,IAAI,EAAE,EAAE,CAAC,CAAC;IAC/E,MAAM,MAAM,GAAG,MAAM,IAAI,OAAO,EAAE,CAAC,IAAI,CAAC,eAAe,EAAE,MAAM,CAAC,CAAC;IAEjE,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;QAChB,aAAa,CAAC,IAAI,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QACnC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC;IACjD,CAAC;IACD,OAAO,EAAE,KAAK,EAAE,IAAI,UAAU,CAAC,MAAM,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC;AAC3D,CAAC"}
@@ -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;AAgD3E,gFAAgF;AAChF,wBAAgB,WAAW,CAAC,IAAI,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,GAAG,UAAU,CAkDzE"}
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"}
@@ -16,6 +16,12 @@ import { SIGN_PY } from "./engines.js";
16
16
  * Faute de reconnaître, on rend `undefined` et l'appelant garde son message générique.
17
17
  */
18
18
  function diagnostiquer(trace) {
19
+ // L'horodatage a sa propre phrase, déjà rédigée côté Python : on la rend telle quelle, sans les
20
+ // six chemins temporaires d'un « Command failed » qui enverraient chercher ailleurs. EN PREMIER :
21
+ // sa trace peut contenir des mots que les motifs suivants prendraient pour les leurs.
22
+ const h = trace.match(/ERREUR -- (horodatage[^\n]*)/);
23
+ if (h)
24
+ return h[1].charAt(0).toUpperCase() + h[1].slice(1);
19
25
  if (/Invalid password or PKCS12 data|Could not load key material/.test(trace)) {
20
26
  return "Phrase secrète invalide pour ce certificat PKCS#12.";
21
27
  }
@@ -41,11 +47,12 @@ function mapPermissions(p) {
41
47
  extract: p.extract ?? false,
42
48
  modify_annotation: p.modifyAnnotation ?? false,
43
49
  modify_assembly: p.modifyAssembly ?? false,
44
- // ⚠️ `modify_form` MANQUAIT à cette table. `pikepdf.Permissions` le connaît, donc il prenait
45
- // sa valeur par défaut — AUTORISÉ. Un document scellé « ni impression ni copie » gardait ses
46
- // champs de formulaire remplissables, et personne ne le voyait : la case n'existait nulle part.
47
- // Relevé le 26/09/2026 sur un document de production.
48
- modify_form: p.modifyForm ?? false,
50
+ // ⚠️ Le défaut est `true`, et il DOIT l'être. Un champ de signature est un champ de
51
+ // formulaire : le sceau étant apposé après le chiffrement, refuser `modify_form` empêcherait
52
+ // de sceller. 0.3.1 avait mis `?? false` ici — un appelant qui omettait la clé aurait vu
53
+ // toutes ses signatures échouer dès que le python a cessé d'ignorer la valeur.
54
+ // Un `false` EXPLICITE reste transmis : c'est le python qui le refuse, en nommant la raison.
55
+ modify_form: p.modifyForm ?? true,
49
56
  modify_other: p.modifyOther ?? false,
50
57
  print_lowres: p.printLowres ?? true,
51
58
  print_highres: p.printHighres ?? true,
@@ -77,6 +84,11 @@ export function signPyhanko(opts, python) {
77
84
  // Horodatage RFC 3161 — voir `timestampUrl` dans les types : absent, on signe en PAdES-B ;
78
85
  // présent, on exige PAdES-T ou l'échec.
79
86
  timestamp_url: opts.timestampUrl || undefined,
87
+ // Identifiants de l'horodateur (0.4.0) : par CE fichier, jamais par `argv`. Le dossier
88
+ // temporaire est créé en 0700 par `mkdtempSync`, et effacé dans le `finally`.
89
+ timestamp_headers: opts.timestampHeaders,
90
+ timestamp_auth: opts.timestampAuth,
91
+ timestamp_timeout: opts.timestampTimeout,
80
92
  };
81
93
  const cfgPath = toFile(dir, "config.json", JSON.stringify(cfg));
82
94
  // ⚠️ La sortie d'erreur est CAPTURÉE, pas seulement laissée filer vers le terminal.
@@ -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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"}
@@ -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;AAM1D,wBAAsB,OAAO,CAAC,IAAI,EAAE,WAAW,GAAG,OAAO,CAAC,UAAU,CAAC,CA0CpE"}
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"}
package/dist/sign.js CHANGED
@@ -24,9 +24,11 @@ export async function signPdf(opts) {
24
24
  permissions: opts.permissions ?? (cfg.restrict ? {} : undefined),
25
25
  openPassword: opts.openPassword,
26
26
  engine: opts.engine ?? cfg.engine,
27
+ ...identifiantsHorodateur(opts, cfg),
27
28
  };
28
29
  if (!merged.p12)
29
30
  throw new Error("Certificat PKCS#12 manquant (opts.p12 ou PDF_SIGN_P12).");
31
+ controlerHorodatage(merged);
30
32
  const avail = detectEngines(cfg.python);
31
33
  const want = merged.engine ?? "auto";
32
34
  let engine;
@@ -41,6 +43,59 @@ export async function signPdf(opts) {
41
43
  else {
42
44
  engine = avail.pyhanko ? "pyhanko" : "node"; // auto : préfère pyhanko
43
45
  }
46
+ // ⚠️ Le cœur Node NE SAIT PAS horodater. Jusqu'en 0.3.2, `auto` sur une machine sans pyhanko
47
+ // tombait sur lui et signait SANS horodatage, sans rien dire : le repli silencieux que ce module
48
+ // interdit partout ailleurs. On refuse, et on dit quoi installer.
49
+ if (engine === "node" && merged.timestampUrl) {
50
+ throw new Error("Horodatage demandé, mais le moteur retenu (node) ne sait pas horodater : aucune signature " +
51
+ "n'a été produite. Installer pyhanko (python/setup-venv.sh) ou retirer `timestampUrl`.");
52
+ }
44
53
  return engine === "pyhanko" ? signPyhanko(merged, avail.python) : signNode(merged);
45
54
  }
55
+ /**
56
+ * Les identifiants d'un horodateur VOYAGENT AVEC SON ADRESSE — même règle que le certificat et sa
57
+ * phrase, plus haut.
58
+ *
59
+ * Ceux du `.env` ne partent que vers l'horodateur du `.env` (`PDF_SIGN_TSA`). Un appelant qui
60
+ * vise une autre adresse fournit les siens, ou n'en envoie aucun : joindre notre clé d'API à une
61
+ * requête vers un tiers, c'est la lui donner.
62
+ */
63
+ function identifiantsHorodateur(opts, cfg) {
64
+ const t = cfg.tsa;
65
+ const memeHorodateur = !!opts.timestampUrl && opts.timestampUrl === t.url;
66
+ return {
67
+ timestampHeaders: opts.timestampHeaders
68
+ ?? (memeHorodateur && t.apiKey ? { [t.apiKeyHeader]: t.apiKey } : undefined),
69
+ timestampAuth: opts.timestampAuth
70
+ ?? (memeHorodateur && t.user ? { user: t.user, password: t.password ?? "" } : undefined),
71
+ timestampTimeout: opts.timestampTimeout ?? t.timeout,
72
+ };
73
+ }
74
+ const LOCALES = new Set(["localhost", "127.0.0.1", "::1", "[::1]"]);
75
+ /** Refuse, AVANT toute requête, un horodatage dont la demande est incohérente ou dangereuse. */
76
+ function controlerHorodatage(o) {
77
+ const identifie = !!o.timestampAuth || Object.keys(o.timestampHeaders ?? {}).length > 0;
78
+ if (!o.timestampUrl) {
79
+ if (identifie) {
80
+ throw new Error("Identifiants d'horodatage fournis sans adresse d'horodateur (`timestampUrl`) : " +
81
+ "rien n'a été signé. Une configuration à moitié posée ne doit pas passer pour complète.");
82
+ }
83
+ return;
84
+ }
85
+ let u;
86
+ try {
87
+ u = new URL(o.timestampUrl);
88
+ }
89
+ catch {
90
+ throw new Error(`Adresse d'horodateur invalide : ${o.timestampUrl}`);
91
+ }
92
+ // Une clé envoyée en clair est une clé publiée. On tolère la boucle locale (essais, relais).
93
+ if (identifie && u.protocol !== "https:" && !LOCALES.has(u.hostname)) {
94
+ throw new Error(`Horodatage refusé : des identifiants ne partent pas en clair vers ${u.host} — ` +
95
+ "l'adresse doit être en https://.");
96
+ }
97
+ if (o.timestampTimeout !== undefined && !(o.timestampTimeout > 0)) {
98
+ throw new Error(`Délai d'horodatage invalide : ${o.timestampTimeout} (secondes, > 0 attendu).`);
99
+ }
100
+ }
46
101
  //# sourceMappingURL=sign.js.map
package/dist/sign.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"sign.js","sourceRoot":"","sources":["../src/sign.ts"],"names":[],"mappings":"AAWA,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAC7C,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAClD,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAEhD,MAAM,CAAC,KAAK,UAAU,OAAO,CAAC,IAAiB;IAC7C,MAAM,GAAG,GAAG,iBAAiB,EAAE,CAAC;IAEhC,mDAAmD;IACnD,EAAE;IACF,8FAA8F;IAC9F,+FAA+F;IAC/F,iGAAiG;IACjG,0FAA0F;IAC1F,2FAA2F;IAC3F,+FAA+F;IAC/F,iFAAiF;IACjF,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,IAAI,IAAI,IAAI,IAAI,CAAC,GAAG,KAAK,GAAG,CAAC,GAAG,CAAC;IAE3D,MAAM,MAAM,GAAgB;QAC1B,GAAG,IAAI;QACP,GAAG,EAAE,IAAI,CAAC,GAAG,IAAK,GAAG,CAAC,GAAc;QACpC,UAAU,EAAE,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,UAAU,IAAI,GAAG,CAAC,UAAU,CAAC;QAC7E,cAAc,EAAE,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,cAAc,IAAI,GAAG,CAAC,cAAc,CAAC;QAC7F,IAAI,EAAE,EAAE,GAAG,GAAG,CAAC,IAAI,EAAE,GAAG,IAAI,CAAC,IAAI,EAAE;QACnC,KAAK,EAAE,EAAE,GAAG,GAAG,CAAC,KAAK,EAAE,GAAG,IAAI,CAAC,KAAK,EAAE;QACtC,WAAW,EAAE,IAAI,CAAC,WAAW,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC;QAChE,YAAY,EAAE,IAAI,CAAC,YAAY;QAC/B,MAAM,EAAE,IAAI,CAAC,MAAM,IAAI,GAAG,CAAC,MAAM;KAClC,CAAC;IAEF,IAAI,CAAC,MAAM,CAAC,GAAG;QAAE,MAAM,IAAI,KAAK,CAAC,yDAAyD,CAAC,CAAC;IAE5F,MAAM,KAAK,GAAG,aAAa,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;IACxC,MAAM,IAAI,GAAG,MAAM,CAAC,MAAM,IAAI,MAAM,CAAC;IAErC,IAAI,MAA0B,CAAC;IAC/B,IAAI,IAAI,KAAK,SAAS,EAAE,CAAC;QACvB,IAAI,CAAC,KAAK,CAAC,OAAO;YAAE,MAAM,IAAI,KAAK,CAAC,iFAAiF,CAAC,CAAC;QACvH,MAAM,GAAG,SAAS,CAAC;IACrB,CAAC;SAAM,IAAI,IAAI,KAAK,MAAM,EAAE,CAAC;QAC3B,MAAM,GAAG,MAAM,CAAC;IAClB,CAAC;SAAM,CAAC;QACN,MAAM,GAAG,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,yBAAyB;IACxE,CAAC;IAED,OAAO,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,WAAW,CAAC,MAAM,EAAE,KAAK,CAAC,MAAgB,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;AAC/F,CAAC"}
1
+ {"version":3,"file":"sign.js","sourceRoot":"","sources":["../src/sign.ts"],"names":[],"mappings":"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"}
package/dist/types.d.ts CHANGED
@@ -26,7 +26,14 @@ export interface SignPermissions {
26
26
  extract?: boolean;
27
27
  modifyAnnotation?: boolean;
28
28
  modifyAssembly?: boolean;
29
- /** Remplir les champs de formulaire. Absent de la table jusqu'en 0.3.1 : il restait AUTORISÉ. */
29
+ /**
30
+ * Remplir les champs de formulaire.
31
+ *
32
+ * ⚠️ **Ne peut pas être refusé sur un document SCELLÉ.** En PDF, un champ de signature EST un
33
+ * champ de formulaire, et le sceau est apposé APRÈS le chiffrement : l'interdire empêcherait de
34
+ * sceller. Le passer à `false` provoque une **erreur**, jamais une autorisation silencieuse —
35
+ * croire un formulaire verrouillé quand il ne l'est pas est pire que le savoir.
36
+ */
30
37
  modifyForm?: boolean;
31
38
  modifyOther?: boolean;
32
39
  printLowres?: boolean;
@@ -57,6 +64,25 @@ export interface SignOptions {
57
64
  * opposable, ou rien. Un repli silencieux livrerait un document que le client croit horodaté.
58
65
  */
59
66
  timestampUrl?: string;
67
+ /**
68
+ * En-têtes HTTP joints à la requête d'horodatage — typiquement une clé d'API
69
+ * (`{ "X-API-KEY": "…" }` chez Evidency). *(0.4.0)*
70
+ *
71
+ * Un horodateur **qualifié** est un service payant : il authentifie son client. Sans ce moyen,
72
+ * seuls les horodateurs publics et gratuits — donc non qualifiés — étaient joignables.
73
+ *
74
+ * ⚠️ Transmis au moteur par le fichier de configuration temporaire, **jamais** par la ligne de
75
+ * commande (lisible par toute la machine dans la table des processus). Refusé sur une adresse
76
+ * `http://` non locale : une clé envoyée en clair est une clé publiée.
77
+ */
78
+ timestampHeaders?: Record<string, string>;
79
+ /** Authentification HTTP Basic auprès de l'horodateur. Mêmes garde-fous que `timestampHeaders`. *(0.4.0)* */
80
+ timestampAuth?: {
81
+ user: string;
82
+ password: string;
83
+ };
84
+ /** Délai d'attente de l'horodateur, en secondes (défaut : 10). Dépassé, la signature ÉCHOUE. *(0.4.0)* */
85
+ timestampTimeout?: number;
60
86
  /**
61
87
  * Mot de passe exigé à l'OUVERTURE du document (chiffrement AES-256, R=6).
62
88
  *
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,6DAA6D;AAC7D,MAAM,WAAW,QAAQ;IACvB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,yFAAyF;AACzF,MAAM,WAAW,SAAS;IACxB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,0CAA0C;IAC1C,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,iDAAiD;IACjD,GAAG,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;IACvC,gGAAgG;IAChG,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,kFAAkF;AAClF,MAAM,WAAW,eAAe;IAC9B,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,iGAAiG;IACjG,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB;AAED,MAAM,MAAM,UAAU,GAAG,MAAM,GAAG,MAAM,GAAG,SAAS,CAAC;AAErD,MAAM,WAAW,WAAW;IAC1B,qCAAqC;IACrC,KAAK,EAAE,MAAM,GAAG,UAAU,CAAC;IAC3B,qEAAqE;IACrE,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,6CAA6C;IAC7C,GAAG,EAAE,MAAM,GAAG,UAAU,CAAC;IACzB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,IAAI,CAAC,EAAE,QAAQ,CAAC;IAChB,KAAK,CAAC,EAAE,SAAS,CAAC;IAClB,qGAAqG;IACrG,WAAW,CAAC,EAAE,eAAe,GAAG,KAAK,CAAC;IAEtC;;;;;;;;OAQG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB;;;;;;OAMG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,2FAA2F;IAC3F,MAAM,CAAC,EAAE,UAAU,CAAC;CACrB;AAED,MAAM,WAAW,UAAU;IACzB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,UAAU,CAAC;IACnB,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC;CAC5B;AAED,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,uGAAuG;IACvG,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,gEAAgE;IAChE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,UAAU,CAAC;CACrB;AAED,MAAM,WAAW,aAAa;IAC5B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,OAAO,CAAC;IAChB,UAAU,EAAE,aAAa,EAAE,CAAC;IAC5B,MAAM,EAAE,SAAS,GAAG,MAAM,CAAC;CAC5B;AAED,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,OAAO,CAAC;IACd,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.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.2.0 · Licence: AGPL-3.0-or-later · Auteur: Dr Hamid MADANI <drmdh@msn.com>
4
+ - Version: 0.4.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
@@ -29,6 +29,9 @@ La signature PAdES + permissions AES-256 garantit intégrité, authenticité et
29
29
  · opts.openPassword : mot de passe exigé à l'OUVERTURE (0.2.0). Seul verrou DUR : sans lui les
30
30
  permissions ne sont que déclaratives. Exige pyhanko. Seul (sans permissions), ne restreint
31
31
  rien d'autre que l'ouverture.
32
+ · opts.timestampUrl : horodatage RFC 3161 → PAdES-T (0.3.0). Horodateur muet ⇒ la signature ÉCHOUE.
33
+ · opts.timestampHeaders / opts.timestampAuth / opts.timestampTimeout (0.4.0) : joindre un
34
+ horodateur QUALIFIÉ, qui authentifie (clé d'API en en-tête, ou HTTP Basic). Exige pyhanko.
32
35
  - verifyPdf(opts): VerifyResult — validation pyhanko complète si dispo, sinon détection Node (/ByteRange)
33
36
  - detectEngines(python?): EngineAvailability — { node:true, pyhanko:bool, python }
34
37
  - resolvePython / pyhankoAvailable
@@ -41,9 +44,12 @@ PDF_SIGN_ENGINE (auto|node|pyhanko) · PDF_SIGN_PYTHON (bin du venv)
41
44
  PDF_SIGN_REASON / _LOCATION / _NAME / _CONTACT (métadonnées du cachet)
42
45
  PDF_SIGN_FIELD_PAGE / PDF_SIGN_FIELD_BOX ("x1,y1,x2,y2") · PDF_SIGN_STAMP_IMAGE (logo du cachet visible, pyhanko) · PDF_SIGN_RESTRICT (bool → permissions)
43
46
  PDF_SIGN_TRUST_PEM (certificat de confiance pour la vérification)
47
+ PDF_SIGN_TSA (adresse de l'horodateur — APPARIE les identifiants) · PDF_SIGN_TSA_API_KEY ·
48
+ PDF_SIGN_TSA_API_KEY_HEADER (défaut X-API-KEY) · PDF_SIGN_TSA_USER / _PASSWORD · PDF_SIGN_TSA_TIMEOUT (s, défaut 10)
44
49
 
45
50
  ## CLI
46
- mosta-pdf-sign sign <in.pdf> [out.pdf] --p12 c.p12 --pass s [--engine …] [--restrict] [--open-password s] [--reason …]
51
+ mosta-pdf-sign sign <in.pdf> [out.pdf] --p12 c.p12 --pass s [--engine …] [--restrict] [--open-password s] [--tsa url] [--tsa-timeout s] [--reason …]
52
+ (identifiants d'horodateur : .env UNIQUEMENT, jamais en argument)
47
53
  mosta-pdf-sign verify <pdf> [--trust cert.pem] [--password s] [--engine …]
48
54
  mosta-pdf-sign engines
49
55
 
@@ -61,3 +67,9 @@ requiert pyhanko>=0.25, pikepdf>=8.
61
67
  - box en points PDF, origine bas-gauche (A4 = 595×842) ; défaut cachet bas-droite [320,40,575,140].
62
68
  - field.stampImage / PDF_SIGN_STAMP_IMAGE : cachet visible « image de fond + texte » (pyhanko stamp.TextStampStyle, opacité 0.35). Ignoré par le cœur Node.
63
69
  - La passphrase peut passer par fichier (PASSPHRASE_FILE) pour ne jamais transiter en argv (pyhanko).
70
+ - timestampUrl + moteur node ⇒ ERREUR (0.4.0). Avant : signature SANS horodatage, silencieuse.
71
+ - Identifiants d'horodateur vers http:// non local ⇒ ERREUR (boucle locale tolérée, pour les essais).
72
+ - Identifiants sans timestampUrl ⇒ ERREUR.
73
+ - Les identifiants du .env ne partent QUE si timestampUrl === PDF_SIGN_TSA. Autre adresse ⇒ aucun
74
+ identifiant du .env n'est joint (l'appelant fournit les siens).
75
+ - HTTP 401/403 de l'horodateur ⇒ « identifiants refusés (HTTP 401) », 429 ⇒ « débit dépassé ».
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mostajs/pdf-sign",
3
- "version": "0.3.1",
3
+ "version": "0.4.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",
@@ -53,12 +53,25 @@ def do_sign(inp, outp, p12_path, p12_pass_file, config_path):
53
53
  # demande une cle ne demande pas, par la meme occasion, de perdre son imprimante.
54
54
  perms = pikepdf.Permissions(modify_form=True)
55
55
  else:
56
+ if perms_cfg.get("modify_form") is False:
57
+ raise SystemExit(
58
+ "ERREUR -- modify_form ne peut pas etre refuse : un champ de signature EST un "
59
+ "champ de formulaire, et le sceau est appose apres le chiffrement. "
60
+ "Retirez cette restriction, ou renoncez a sceller ce document."
61
+ )
56
62
  perms = pikepdf.Permissions(
57
63
  accessibility=perms_cfg.get("accessibility", True),
58
64
  extract=perms_cfg.get("extract", False),
59
65
  modify_annotation=perms_cfg.get("modify_annotation", False),
60
66
  modify_assembly=perms_cfg.get("modify_assembly", False),
61
- modify_form=True, # requis pour signer apres chiffrement
67
+ # ⚠️ TOUJOURS True, et ce n'est pas un oubli : en PDF, un champ de SIGNATURE est un
68
+ # champ de FORMULAIRE. Le sceau étant apposé APRÈS le chiffrement, refuser
69
+ # `modify_form` empêcherait de sceller.
70
+ #
71
+ # Un appelant qui le demande à False reçoit donc un REFUS plutôt qu'une
72
+ # autorisation silencieuse : croire un formulaire verrouillé quand il ne l'est pas
73
+ # est pire que le savoir.
74
+ modify_form=True,
62
75
  modify_other=perms_cfg.get("modify_other", False),
63
76
  print_lowres=perms_cfg.get("print_lowres", True),
64
77
  print_highres=perms_cfg.get("print_highres", True),
@@ -111,8 +124,18 @@ def do_sign(inp, outp, p12_path, p12_pass_file, config_path):
111
124
  tsa_url = cfg.get("timestamp_url")
112
125
  timestamper = None
113
126
  if tsa_url:
114
- print(f"-- horodatage : {tsa_url} --", flush=True)
115
- timestamper = timestamps.HTTPTimeStamper(url=tsa_url)
127
+ # Identifiants (0.4.0) : un horodateur QUALIFIE est payant, donc authentifie son client.
128
+ # Ils arrivent par le fichier de configuration, jamais par argv, et ne sont JAMAIS imprimes.
129
+ auth_cfg = cfg.get("timestamp_auth")
130
+ auth = (auth_cfg["user"], auth_cfg.get("password", "")) if auth_cfg else None
131
+ print(f"-- horodatage : {tsa_url}%s --" % (" (authentifie)" if auth or cfg.get("timestamp_headers") else ""),
132
+ flush=True)
133
+ timestamper = timestamps.HTTPTimeStamper(
134
+ url=tsa_url,
135
+ headers=cfg.get("timestamp_headers") or None,
136
+ auth=auth,
137
+ timeout=cfg.get("timestamp_timeout") or 10,
138
+ )
116
139
 
117
140
  with open(outp, "wb") as out_f:
118
141
  try:
@@ -123,13 +146,36 @@ def do_sign(inp, outp, p12_path, p12_pass_file, config_path):
123
146
  except Exception as e:
124
147
  if timestamper is not None:
125
148
  raise SystemExit(
126
- f"ERREUR -- horodatage impossible ({tsa_url}) : {e}. "
149
+ f"ERREUR -- horodatage impossible ({tsa_url}) : {_cause_horodatage(e)}. "
127
150
  "Le document n'a PAS été signé : une date non attestée vaut moins que pas de date."
128
151
  )
129
152
  raise
130
153
  print(f"OK -- PDF signé : {outp}", flush=True)
131
154
 
132
155
 
156
+ def _cause_horodatage(e):
157
+ """Nomme la VRAIE cause d'un echec d'horodatage.
158
+
159
+ pyhanko ne regarde que le type de contenu de la reponse : un 401 (cle absente ou fausse) y
160
+ devient « Timestamp server response is malformed » -- ce qui envoie chercher un defaut de
161
+ protocole quand il s'agit d'un identifiant. On remonte la chaine d'exceptions jusqu'a la
162
+ reponse HTTP, et on dit ce que son code signifie.
163
+ """
164
+ vus, x = set(), e
165
+ while x is not None and id(x) not in vus:
166
+ vus.add(id(x))
167
+ for a in getattr(x, "args", ()):
168
+ code = getattr(a, "status_code", None)
169
+ if code in (401, 403):
170
+ return f"identifiants refusés par l'horodateur (HTTP {code}) -- clé d'API ou mot de passe absent ou invalide"
171
+ if code == 429:
172
+ return "débit de l'horodateur dépassé (HTTP 429) -- réessayer plus tard"
173
+ if code is not None and code != 200:
174
+ return f"l'horodateur a répondu HTTP {code}"
175
+ x = x.__cause__ or x.__context__
176
+ return str(e)
177
+
178
+
133
179
  def _build_stamp_style(stamp_image, meta_cfg):
134
180
  """Style de cachet visible « image de fond + texte » (ou None → texte par défaut de pyhanko)."""
135
181
  if not stamp_image: