|
| 1 | +# signApp |
| 2 | + |
| 3 | +Signature **par lot** de fichiers PDF avec la **carte d'identité électronique |
| 4 | +belge (eID)**, ou apposition d'une **image** de signature — avec validation des |
| 5 | +entrées par rapport à un modèle, en **ligne de commande** comme en **interface |
| 6 | +graphique** (CustomTkinter). |
| 7 | + |
| 8 | +> ⚖️ Le mode eID utilise le certificat de **non-répudiation** de la carte, |
| 9 | +> juridiquement équivalent à une signature manuscrite. Le **numéro de registre |
| 10 | +> national** est inscrit dans chaque signature produite — attention à la |
| 11 | +> diffusion des PDF signés. |
| 12 | +
|
| 13 | +--- |
| 14 | + |
| 15 | +## Deux modes de signature |
| 16 | + |
| 17 | +| Mode | Carte requise | Nature | Rendu | |
| 18 | +|---|---|---|---| |
| 19 | +| **`beid`** | oui (lecteur + carte + PIN par document) | signature **cryptographique** eID (pyHanko via le middleware PKCS#11) | **vignette** visible : photo du titulaire + « Signed by: » / nom / date | |
| 20 | +| **`image`** | non | **tampon d'image** (ce n'est *pas* une signature cryptographique) | l'image fournie, posée à une position choisie | |
| 21 | + |
| 22 | +Dans les deux modes, la même vignette/image + page + position est appliquée à |
| 23 | +**tous** les documents du lot — la validation par modèle garantit que les |
| 24 | +fichiers sont géométriquement identiques. |
| 25 | + |
| 26 | +## Validation par modèle (`--template`) |
| 27 | + |
| 28 | +Si un PDF modèle est fourni, chaque entrée est acceptée **uniquement** si elle a |
| 29 | +le **même nombre de pages** ET des **dimensions par page exactement identiques** |
| 30 | +(égalité stricte, sans tolérance). Les fichiers rejetés ne sont jamais signés ; |
| 31 | +le motif du rejet est affiché (récapitulatif CLI / tableau GUI). |
| 32 | + |
| 33 | +## Sortie |
| 34 | + |
| 35 | +Les fichiers sont écrits `{nom}_signe.pdf` dans le dossier de sortie et **ne |
| 36 | +sont jamais écrasés** : en cas de collision, ` - 1`, ` - 2`, … sont ajoutés. |
| 37 | + |
| 38 | +--- |
| 39 | + |
| 40 | +## Prérequis (runtime) |
| 41 | + |
| 42 | +- **Mode `beid`** : le **middleware eID belge** installé |
| 43 | + (<https://eid.belgium.be>), qui fournit la bibliothèque PKCS#11 |
| 44 | + (`libbeidpkcs11.so` / `beidpkcs11.dll` / `…dylib`), un **lecteur + carte eID |
| 45 | + insérée**, et le service **PC/SC** (`pcscd`) en marche. Le PIN est demandé |
| 46 | + pour **chaque** document. |
| 47 | +- **Mode `image`** : rien de particulier — tampon PDF pur. |
| 48 | +- **Interface graphique** : `customtkinter` + un Python avec `tkinter` et un |
| 49 | + affichage. L'aperçu de page (étape 6) utilise **poppler** (`pdftoppm`) ; |
| 50 | + absent ⇒ cadre blanc (dégradation propre). |
| 51 | + |
| 52 | +## Installation (depuis les sources) |
| 53 | + |
| 54 | +```bash |
| 55 | +python3 -m venv venv |
| 56 | +./venv/bin/pip install -r requirements.txt |
| 57 | +# GUI sous Ubuntu/Debian, si tkinter manque : sudo apt install python3-tk |
| 58 | +``` |
| 59 | + |
| 60 | +--- |
| 61 | + |
| 62 | +## Utilisation — ligne de commande |
| 63 | + |
| 64 | +```bash |
| 65 | +# Signature eID (vignette en bas à droite de la dernière page) : |
| 66 | +./venv/bin/python sign_pdfs_beid.py --input ../pdfs --output ../signes --mode beid --pades |
| 67 | + |
| 68 | +# Tampon d'image (sans carte), validé contre un modèle : |
| 69 | +./venv/bin/python sign_pdfs_beid.py --mode image \ |
| 70 | + --template ../pdfs/MODELE.pdf --input ../pdfs --output ../signes \ |
| 71 | + --image-path signature.png --page 1 --x 360 --y 150 |
| 72 | + |
| 73 | +# Interface graphique : |
| 74 | +./venv/bin/python sign_pdfs_beid.py --gui |
| 75 | +``` |
| 76 | + |
| 77 | +### Options |
| 78 | + |
| 79 | +| Drapeau | Signification | |
| 80 | +|---|---| |
| 81 | +| `--gui` | lance l'interface graphique ; sinon exécution en mode console. | |
| 82 | +| `--input <chemins…>` | fichiers et/ou dossiers à traiter (les dossiers sont parcourus pour `*.pdf`). | |
| 83 | +| `--output <dossier>` | dossier de sortie (`{nom}_signe.pdf`, jamais écrasé). | |
| 84 | +| `--template <pdf>` | PDF modèle ; si fourni, les entrées sont validées contre lui. | |
| 85 | +| `--mode beid\|image` | mode de signature (défaut `beid`). | |
| 86 | +| `--image-path <img>` | image à apposer (**requis** en `--mode image`). | |
| 87 | +| `--page <N>` | page cible, **1-based**. Image : page d'insertion. beID : page de la vignette. | |
| 88 | +| `--x <pt> --y <pt>` | coin inférieur gauche, en points depuis le bas-gauche de la page. beID : **omettre les deux ⇒ bas-droite de la dernière page**. | |
| 89 | +| `--pades` | signature **PAdES** (archivage long terme). | |
| 90 | +| `--lib <chemin>` | chemin vers la bibliothèque PKCS#11 eID (sinon valeur par défaut selon l'OS). | |
| 91 | +| `--field <nom>` | nom de base du champ de signature (mode beid). | |
| 92 | + |
| 93 | +> Compatibilité ascendante : l'ancienne forme positionnelle `entrées… dossier_sortie` |
| 94 | +> reste acceptée si `--input`/`--output` sont absents. |
| 95 | +
|
| 96 | +## Utilisation — interface graphique |
| 97 | + |
| 98 | +Un assistant vertical déroule le flux : **1.** modèle → **2.** fichiers → |
| 99 | +**3.** dossier de sortie → **4.** validation (tableau pass/échec) → **5.** mode |
| 100 | +(eID/image + PAdES) → **6.** page + position (aperçu réel de la page, clic pour |
| 101 | +placer) → **7.** lancer → **8.** récapitulatif par document. |
| 102 | + |
| 103 | +--- |
| 104 | + |
| 105 | +## Exécutables autonomes (Linux & Windows) |
| 106 | + |
| 107 | +Le projet se compile en **deux binaires autonomes** par OS (un GUI fenêtré |
| 108 | +`signApp`, un CLI console `signApp-cli`) — aucun Python requis sur la machine |
| 109 | +cible. Voir **[BUILD.md](BUILD.md)** pour toutes les routes (natif Linux, |
| 110 | +Windows natif, Wine, et CI GitHub Actions). |
| 111 | + |
| 112 | +```bash |
| 113 | +./build_linux.sh # Linux -> dist/signApp , dist/signApp-cli |
| 114 | +build_windows.bat # Windows -> dist\signApp.exe , dist\signApp-cli.exe |
| 115 | +``` |
| 116 | + |
| 117 | +Le middleware eID et poppler restent des **dépendances runtime** et ne sont |
| 118 | +jamais embarqués. |
| 119 | + |
| 120 | +## Tests |
| 121 | + |
| 122 | +Suite `unittest` headless (sans carte ni tkinter) : |
| 123 | + |
| 124 | +```bash |
| 125 | +./venv/bin/python -m unittest -v |
| 126 | +``` |
| 127 | + |
| 128 | +## Structure du projet |
| 129 | + |
| 130 | +| Fichier | Rôle | |
| 131 | +|---|---| |
| 132 | +| `sign_pdfs_beid.py` | cœur + point d'entrée CLI (logique métier, importable sans tkinter). | |
| 133 | +| `gui.py` | interface CustomTkinter (façade au-dessus du cœur). | |
| 134 | +| `gui_main.py` | point d'entrée du binaire fenêtré (ouvre la GUI). | |
| 135 | +| `test_sign_pdfs_beid.py` | suite de tests `unittest`. | |
| 136 | +| `signApp.spec` | recette PyInstaller (deux binaires). | |
| 137 | +| `build_*.sh` / `build_windows.bat` | scripts de build. | |
| 138 | +| `.github/workflows/build.yml` | CI : binaires Windows + Linux en artefacts. | |
| 139 | +| `BUILD.md` | guide d'empaquetage détaillé. | |
0 commit comments