@mostajs/pdf-sign 0.3.2 → 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 +49 -0
- package/README.md +39 -0
- package/dist/cli.js +8 -0
- package/dist/cli.js.map +1 -1
- package/dist/config.d.ts +9 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +12 -0
- package/dist/config.js.map +1 -1
- package/dist/node-signer.d.ts.map +1 -1
- package/dist/node-signer.js +3 -0
- package/dist/node-signer.js.map +1 -1
- package/dist/pyhanko-signer.d.ts.map +1 -1
- package/dist/pyhanko-signer.js +11 -0
- package/dist/pyhanko-signer.js.map +1 -1
- package/dist/sign.d.ts.map +1 -1
- package/dist/sign.js +55 -0
- package/dist/sign.js.map +1 -1
- package/dist/types.d.ts +19 -0
- package/dist/types.d.ts.map +1 -1
- package/llms.txt +14 -2
- package/package.json +1 -1
- package/python/sign_with_perms.py +36 -3
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,54 @@
|
|
|
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
|
+
|
|
3
52
|
## 0.3.2 — 26/09/2026
|
|
4
53
|
|
|
5
54
|
**`modify_form` ne peut pas être refusé — et le dire vaut mieux que l'ignorer.**
|
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":";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
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
|
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
|
package/dist/config.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"
|
|
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
|
package/dist/config.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AACH,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAwBrD,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,MAAM,OAAO,GAAG,MAAM,CAAC,sBAAsB,EAAE,EAAE,CAAC,CAAC;IACnD,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;QACvD,GAAG,EAAE;YACH,GAAG,EAAE,MAAM,CAAC,cAAc,EAAE,EAAE,CAAC,IAAI,SAAS;YAC5C,MAAM,EAAE,MAAM,CAAC,sBAAsB,EAAE,EAAE,CAAC,IAAI,SAAS;YACvD,YAAY,EAAE,MAAM,CAAC,6BAA6B,EAAE,EAAE,CAAC,IAAI,WAAW;YACtE,IAAI,EAAE,MAAM,CAAC,mBAAmB,EAAE,EAAE,CAAC,IAAI,SAAS;YAClD,QAAQ,EAAE,MAAM,CAAC,uBAAuB,EAAE,EAAE,CAAC,IAAI,SAAS;YAC1D,OAAO,EAAE,OAAO,IAAI,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,SAAS;SACtE;KACF,CAAC;AACJ,CAAC"}
|
|
@@ -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,
|
|
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"}
|
package/dist/node-signer.js
CHANGED
|
@@ -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
|
}
|
package/dist/node-signer.js.map
CHANGED
|
@@ -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;
|
|
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"}
|
package/dist/pyhanko-signer.js
CHANGED
|
@@ -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
|
}
|
|
@@ -78,6 +84,11 @@ export function signPyhanko(opts, python) {
|
|
|
78
84
|
// Horodatage RFC 3161 — voir `timestampUrl` dans les types : absent, on signe en PAdES-B ;
|
|
79
85
|
// présent, on exige PAdES-T ou l'échec.
|
|
80
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,
|
|
81
92
|
};
|
|
82
93
|
const cfgPath = toFile(dir, "config.json", JSON.stringify(cfg));
|
|
83
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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"}
|
package/dist/sign.d.ts.map
CHANGED
|
@@ -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;
|
|
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":"
|
|
1
|
+
{"version":3,"file":"sign.js","sourceRoot":"","sources":["../src/sign.ts"],"names":[],"mappings":"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"}
|
package/dist/types.d.ts
CHANGED
|
@@ -64,6 +64,25 @@ export interface SignOptions {
|
|
|
64
64
|
* opposable, ou rien. Un repli silencieux livrerait un document que le client croit horodaté.
|
|
65
65
|
*/
|
|
66
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;
|
|
67
86
|
/**
|
|
68
87
|
* Mot de passe exigé à l'OUVERTURE du document (chiffrement AES-256, R=6).
|
|
69
88
|
*
|
package/dist/types.d.ts.map
CHANGED
|
@@ -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;;;;;;;OAOG;IACH,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.
|
|
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
|
+
"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",
|
|
@@ -124,8 +124,18 @@ def do_sign(inp, outp, p12_path, p12_pass_file, config_path):
|
|
|
124
124
|
tsa_url = cfg.get("timestamp_url")
|
|
125
125
|
timestamper = None
|
|
126
126
|
if tsa_url:
|
|
127
|
-
|
|
128
|
-
|
|
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
|
+
)
|
|
129
139
|
|
|
130
140
|
with open(outp, "wb") as out_f:
|
|
131
141
|
try:
|
|
@@ -136,13 +146,36 @@ def do_sign(inp, outp, p12_path, p12_pass_file, config_path):
|
|
|
136
146
|
except Exception as e:
|
|
137
147
|
if timestamper is not None:
|
|
138
148
|
raise SystemExit(
|
|
139
|
-
f"ERREUR -- horodatage impossible ({tsa_url}) : {e}. "
|
|
149
|
+
f"ERREUR -- horodatage impossible ({tsa_url}) : {_cause_horodatage(e)}. "
|
|
140
150
|
"Le document n'a PAS été signé : une date non attestée vaut moins que pas de date."
|
|
141
151
|
)
|
|
142
152
|
raise
|
|
143
153
|
print(f"OK -- PDF signé : {outp}", flush=True)
|
|
144
154
|
|
|
145
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
|
+
|
|
146
179
|
def _build_stamp_style(stamp_image, meta_cfg):
|
|
147
180
|
"""Style de cachet visible « image de fond + texte » (ou None → texte par défaut de pyhanko)."""
|
|
148
181
|
if not stamp_image:
|