@mostajs/pdf-sign 0.2.1 → 0.3.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 +38 -0
- package/dist/pyhanko-signer.d.ts.map +1 -1
- package/dist/pyhanko-signer.js +40 -1
- package/dist/pyhanko-signer.js.map +1 -1
- package/dist/types.d.ts +10 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +1 -1
- package/python/sign_with_perms.py +28 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,9 +1,47 @@
|
|
|
1
1
|
# Changelog — @mostajs/pdf-sign
|
|
2
2
|
|
|
3
|
+
## 0.3.0 — 26/09/2026
|
|
4
|
+
|
|
5
|
+
**HORODATAGE RFC 3161 — de PAdES-B à PAdES-T.**
|
|
6
|
+
|
|
7
|
+
Sans horodatage, l'heure de signature est un attribut **déclaré par le signataire**, donc
|
|
8
|
+
modifiable par lui : le document prouve qu'il n'a pas changé, pas **quand** il a été scellé. Pour
|
|
9
|
+
une attestation, un diplôme ou un rapport d'analyse, c'est la moitié de ce qu'on attend — et rien
|
|
10
|
+
n'empêche d'antidater.
|
|
11
|
+
|
|
12
|
+
`signPdf({ …, timestampUrl: 'http://…' })` fait passer la signature en **PAdES-T** : un tiers
|
|
13
|
+
atteste de l'instant, et le jeton est embarqué comme attribut non signé du CMS
|
|
14
|
+
(`signature_time_stamp_token`).
|
|
15
|
+
|
|
16
|
+
### ⚠️ Aucun repli, et c'est délibéré
|
|
17
|
+
|
|
18
|
+
Si le service d'horodatage ne répond pas, la signature **échoue**. Elle ne se replie PAS sur une
|
|
19
|
+
signature sans horodatage.
|
|
20
|
+
|
|
21
|
+
Un repli livrerait un document que le client **croit** horodaté et qui ne l'est pas — et il ne
|
|
22
|
+
s'en apercevrait qu'au moment de s'en prévaloir, c'est-à-dire trop tard. Mieux vaut un refus tout
|
|
23
|
+
de suite qu'une preuve creuse plus tard. Le message d'erreur **nomme l'horodatage** : sans cela, on
|
|
24
|
+
chercherait la panne du côté du certificat.
|
|
25
|
+
|
|
26
|
+
L'option est absente par défaut : sans `timestampUrl`, rien ne change.
|
|
27
|
+
|
|
3
28
|
**Auteur** : Dr Hamid MADANI <drmdh@msn.com>
|
|
4
29
|
|
|
5
30
|
Le format suit [Keep a Changelog](https://keepachangelog.com/fr/) ; versionnage [SemVer](https://semver.org/lang/fr/).
|
|
6
31
|
|
|
32
|
+
## 0.2.2 — 2026-09-21
|
|
33
|
+
|
|
34
|
+
### Corrigé — la cause de l'échec revient à l'appelant
|
|
35
|
+
- Le moteur pyhanko tournait avec `stdio: "inherit"` : sa trace partait au terminal du serveur et
|
|
36
|
+
l'appelant ne recevait qu'un `Command failed:` suivi de six chemins temporaires. Une interface ne
|
|
37
|
+
pouvait donc **pas distinguer** « phrase secrète fausse » de « fichier illisible » — même message
|
|
38
|
+
flou dans les deux cas, et l'utilisateur cherchait au hasard.
|
|
39
|
+
- La sortie d'erreur est désormais **capturée, rediffusée au journal** (rien n'est perdu) et
|
|
40
|
+
**traduite** en une phrase sûre à montrer : « Phrase secrète invalide pour ce certificat
|
|
41
|
+
PKCS#12. », « Certificat PKCS#12 illisible… ». Faute de reconnaître, l'ancien message est rendu
|
|
42
|
+
tel quel — on n'invente pas de diagnostic.
|
|
43
|
+
- Aucune cause ne divulgue de chemin temporaire ni de disposition du serveur.
|
|
44
|
+
|
|
7
45
|
## 0.2.1 — 2026-09-21
|
|
8
46
|
|
|
9
47
|
### Corrigé — un certificat et sa phrase voyagent ensemble
|
|
@@ -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;AA2C3E,gFAAgF;AAChF,wBAAgB,WAAW,CAAC,IAAI,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,GAAG,UAAU,CAkDzE"}
|
package/dist/pyhanko-signer.js
CHANGED
|
@@ -9,6 +9,27 @@ import { mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs";
|
|
|
9
9
|
import { tmpdir } from "node:os";
|
|
10
10
|
import { join } from "node:path";
|
|
11
11
|
import { SIGN_PY } from "./engines.js";
|
|
12
|
+
/**
|
|
13
|
+
* Ce que dit la trace du moteur, en une phrase utilisable par une interface.
|
|
14
|
+
*
|
|
15
|
+
* On ne renvoie QUE des causes sûres à montrer : ni chemin temporaire, ni disposition du serveur.
|
|
16
|
+
* Faute de reconnaître, on rend `undefined` et l'appelant garde son message générique.
|
|
17
|
+
*/
|
|
18
|
+
function diagnostiquer(trace) {
|
|
19
|
+
if (/Invalid password or PKCS12 data|Could not load key material/.test(trace)) {
|
|
20
|
+
return "Phrase secrète invalide pour ce certificat PKCS#12.";
|
|
21
|
+
}
|
|
22
|
+
if (/MAC verification failed|mac verify failure/i.test(trace)) {
|
|
23
|
+
return "Phrase secrète invalide pour ce certificat PKCS#12.";
|
|
24
|
+
}
|
|
25
|
+
if (/Could not deserialize|Unable to load|not enough data/i.test(trace)) {
|
|
26
|
+
return "Certificat PKCS#12 illisible — le fichier n'est pas un .p12 valide.";
|
|
27
|
+
}
|
|
28
|
+
if (/EncryptedObjectError|password/i.test(trace) && /pikepdf|PdfError/i.test(trace)) {
|
|
29
|
+
return "Le PDF source est déjà protégé par un mot de passe : il ne peut pas être signé tel quel.";
|
|
30
|
+
}
|
|
31
|
+
return undefined;
|
|
32
|
+
}
|
|
12
33
|
function toFile(dir, name, data) {
|
|
13
34
|
const p = join(dir, name);
|
|
14
35
|
writeFileSync(p, data);
|
|
@@ -48,9 +69,27 @@ export function signPyhanko(opts, python) {
|
|
|
48
69
|
// Chiffrement à l'ouverture. Transmis par le fichier de configuration, jamais par `argv` :
|
|
49
70
|
// une ligne de commande se lit dans la table des processus de toute la machine.
|
|
50
71
|
open_password: opts.openPassword || undefined,
|
|
72
|
+
// Horodatage RFC 3161 — voir `timestampUrl` dans les types : absent, on signe en PAdES-B ;
|
|
73
|
+
// présent, on exige PAdES-T ou l'échec.
|
|
74
|
+
timestamp_url: opts.timestampUrl || undefined,
|
|
51
75
|
};
|
|
52
76
|
const cfgPath = toFile(dir, "config.json", JSON.stringify(cfg));
|
|
53
|
-
|
|
77
|
+
// ⚠️ La sortie d'erreur est CAPTURÉE, pas seulement laissée filer vers le terminal.
|
|
78
|
+
//
|
|
79
|
+
// Avec `stdio: "inherit"`, la cause réelle — « Invalid password or PKCS12 data » — partait au
|
|
80
|
+
// journal du serveur et ne revenait JAMAIS à l'appelant, qui ne recevait qu'un « Command
|
|
81
|
+
// failed » suivi de six chemins temporaires. Impossible, depuis une interface, de dire à
|
|
82
|
+
// quelqu'un si sa phrase est fausse ou son fichier illisible : les deux rendaient le même
|
|
83
|
+
// message. On capture donc, on rediffuse au journal (rien n'est perdu), et on REMONTE la cause.
|
|
84
|
+
try {
|
|
85
|
+
execFileSync(python, [SIGN_PY, "sign", inPath, outPath, p12Path, passFile, cfgPath], { stdio: ["ignore", "inherit", "pipe"] });
|
|
86
|
+
}
|
|
87
|
+
catch (e) {
|
|
88
|
+
const trace = String(e?.stderr ?? "");
|
|
89
|
+
if (trace)
|
|
90
|
+
process.stderr.write(trace); // le journal garde la trace entière
|
|
91
|
+
throw new Error(diagnostiquer(trace) ?? String(e?.message ?? e));
|
|
92
|
+
}
|
|
54
93
|
if (opts.output)
|
|
55
94
|
return { output: outPath, engine: "pyhanko" };
|
|
56
95
|
return { bytes: readFileSync(outPath), engine: "pyhanko" };
|
|
@@ -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/types.d.ts
CHANGED
|
@@ -45,6 +45,16 @@ export interface SignOptions {
|
|
|
45
45
|
field?: SignField;
|
|
46
46
|
/** Restrictions d'édition. `false`/absent = aucune (le cœur Node suffit) ; objet = PAdES pyhanko. */
|
|
47
47
|
permissions?: SignPermissions | false;
|
|
48
|
+
/**
|
|
49
|
+
* Adresse d'un service d'horodatage (RFC 3161). Fournie, la signature passe de **PAdES-B** à
|
|
50
|
+
* **PAdES-T** : la date cesse d'être un attribut DÉCLARÉ par le signataire — donc modifiable par
|
|
51
|
+
* lui — et devient attestée par un tiers. Sans elle, rien n'empêche d'antidater.
|
|
52
|
+
*
|
|
53
|
+
* ⚠️ Si le service ne répond pas, la signature **ÉCHOUE**. Elle ne se replie PAS sur une
|
|
54
|
+
* signature sans horodatage : celui qui a demandé une date opposable doit obtenir une date
|
|
55
|
+
* opposable, ou rien. Un repli silencieux livrerait un document que le client croit horodaté.
|
|
56
|
+
*/
|
|
57
|
+
timestampUrl?: string;
|
|
48
58
|
/**
|
|
49
59
|
* Mot de passe exigé à l'OUVERTURE du document (chiffrement AES-256, R=6).
|
|
50
60
|
*
|
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,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;
|
|
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,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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mostajs/pdf-sign",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.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",
|
|
@@ -25,7 +25,7 @@ import string
|
|
|
25
25
|
def do_sign(inp, outp, p12_path, p12_pass_file, config_path):
|
|
26
26
|
import pikepdf
|
|
27
27
|
from pyhanko.pdf_utils.incremental_writer import IncrementalPdfFileWriter
|
|
28
|
-
from pyhanko.sign import signers, fields, PdfSignatureMetadata
|
|
28
|
+
from pyhanko.sign import signers, fields, PdfSignatureMetadata, timestamps
|
|
29
29
|
from pyhanko.sign.fields import SigFieldSpec
|
|
30
30
|
|
|
31
31
|
with open(p12_pass_file, "rb") as f:
|
|
@@ -99,8 +99,34 @@ def do_sign(inp, outp, p12_path, p12_pass_file, config_path):
|
|
|
99
99
|
# Apparence du cachet visible : image de fond (logo/tampon) + texte, si une image est fournie.
|
|
100
100
|
stamp_style = _build_stamp_style(field_cfg.get("stamp_image"), meta_cfg)
|
|
101
101
|
|
|
102
|
+
# --- Horodatage RFC 3161 : PAdES-B devient PAdES-T ---
|
|
103
|
+
#
|
|
104
|
+
# Sans horodatage, l'heure de signature est un attribut DÉCLARÉ par le signataire, donc
|
|
105
|
+
# modifiable par lui : le document prouve qu'il n'a pas changé, pas QUAND il a été scellé.
|
|
106
|
+
# Avec, un tiers atteste de l'instant, et l'antidatage devient impossible.
|
|
107
|
+
#
|
|
108
|
+
# ⚠️ AUCUN REPLI. Si le service ne répond pas, on échoue. Signer quand même produirait un
|
|
109
|
+
# document que le client croit horodaté et qui ne l'est pas — et il ne s'en apercevrait qu'au
|
|
110
|
+
# moment de s'en prévaloir. Mieux vaut un refus tout de suite qu'une preuve creuse plus tard.
|
|
111
|
+
tsa_url = cfg.get("timestamp_url")
|
|
112
|
+
timestamper = None
|
|
113
|
+
if tsa_url:
|
|
114
|
+
print(f"-- horodatage : {tsa_url} --", flush=True)
|
|
115
|
+
timestamper = timestamps.HTTPTimeStamper(url=tsa_url)
|
|
116
|
+
|
|
102
117
|
with open(outp, "wb") as out_f:
|
|
103
|
-
|
|
118
|
+
try:
|
|
119
|
+
signers.PdfSigner(
|
|
120
|
+
signature_meta=meta, signer=signer, stamp_style=stamp_style,
|
|
121
|
+
timestamper=timestamper,
|
|
122
|
+
).sign_pdf(writer, output=out_f)
|
|
123
|
+
except Exception as e:
|
|
124
|
+
if timestamper is not None:
|
|
125
|
+
raise SystemExit(
|
|
126
|
+
f"ERREUR -- horodatage impossible ({tsa_url}) : {e}. "
|
|
127
|
+
"Le document n'a PAS été signé : une date non attestée vaut moins que pas de date."
|
|
128
|
+
)
|
|
129
|
+
raise
|
|
104
130
|
print(f"OK -- PDF signé : {outp}", flush=True)
|
|
105
131
|
|
|
106
132
|
|