espace-paie-odentas/SIGNATURE_VERIFICATION_SYSTEM.md
odentas d5a110484b feat: Système de vérification de signature électronique avec QR code
- Page publique /verify/[id] affichant Odentas Seal, TSA, certificat
- API /api/signatures/create-verification pour créer preuves
- Générateur PDF de preuve avec QR code (jsPDF)
- Hook useSignatureProof() pour intégration facile
- Table Supabase signature_verifications avec RLS public
- Page de test /test-signature-verification
- Documentation complète du système

Les signataires peuvent scanner le QR code ou visiter l'URL pour vérifier l'authenticité et l'intégrité de leur document signé.
2025-10-29 09:22:01 +01:00

289 lines
8.2 KiB
Markdown

# Système de Vérification de Signature Électronique
## Vue d'ensemble
Ce système permet aux signataires de **vérifier l'authenticité et l'intégrité** de leurs documents signés électroniquement via une page web publique accessible par **URL ou QR code**.
## Architecture
### 1. Page de Vérification Publique
**Fichier**: `app/verify/[id]/page.tsx`
- Route dynamique: `https://espace-paie.odentas.com/verify/{uuid}`
- Accessible sans authentification (RLS public en lecture)
- Affiche tous les détails techniques de la signature
### 2. Table Supabase
**Fichier**: `supabase/migrations/20251028_signature_verifications.sql`
```sql
signature_verifications
├── id (UUID) Identifiant unique de vérification
├── document_name Nom du document signé
├── pdf_url URL du PDF signé
├── signed_at Date/heure de signature
├── signer_name Nom du signataire
├── signer_email Email du signataire
├── signature_hash Hash SHA-256 du contenu signé
├── signature_hex Signature complète en hexadécimal
├── certificate_info (JSONB) Infos du certificat
├── timestamp (JSONB) Horodatage TSA
├── verification_status (JSONB) Statuts de validation
├── contract_id Lien vers le contrat
└── organization_id Lien vers l'organisation
```
### 3. API de Création
**Fichier**: `app/api/signatures/create-verification/route.ts`
```typescript
POST /api/signatures/create-verification
Body: {
document_name: string,
pdf_url: string,
signer_name: string,
signer_email: string,
signature_hash: string,
organization_id: string,
// Optionnel:
signature_hex?: string,
certificate_info?: object,
timestamp?: object,
contract_id?: string
}
Returns: {
verification_id: string,
verification_url: string,
qr_code_data_url: string (PNG en base64)
}
```
### 4. Générateur de PDF de Preuve
**Fichier**: `lib/signature-proof-pdf.ts`
Génère un PDF A4 professionnel contenant:
- En-tête Odentas Sign
- Informations du document signé
- **QR code** (70x70mm, centré)
- URL de vérification
- Détails techniques (hash, algorithme, certificat)
- Note explicative sur le certificat auto-signé
### 5. Hook React
**Fichier**: `hooks/useSignatureProof.ts`
```typescript
const { createSignatureProof, isCreating } = useSignatureProof();
const proof = await createSignatureProof({
document_name: "Contrat CDDU",
pdf_url: "https://...",
signer_name: "Jean Dupont",
signer_email: "jean@example.com",
signature_hash: "dafe9a5e...",
organization_id: "uuid"
});
// Retourne:
// - verification_url
// - qr_code_data_url
// - proof_pdf_blob
```
## Workflow d'Utilisation
### Lors de la Signature d'un Document
1. **Le document est signé** avec Odentas Sign (Lambda PAdES)
2. **Extraction des données** :
- Hash SHA-256 du contenu signé
- Certificat de signature
- Horodatage TSA (si présent)
3. **Appel API** `/api/signatures/create-verification`
4. **Génération** :
- Entrée dans `signature_verifications`
- QR code pointant vers `/verify/{id}`
- PDF de preuve avec QR code
5. **Téléchargement** :
- Document signé (PDF avec signature PAdES)
- Preuve de signature (PDF avec QR code)
### Vérification par le Signataire
1. **Scanner le QR code** ou visiter l'URL
2. **Page publique** affiche :
- ✅ Statut global (Valide / Techniquement Valide)
- 📄 Informations du document
- 🛡️ **Odentas Seal** (sceau électronique)
- Format PAdES-BASELINE-B
- Intégrité vérifiée (hash SHA-256)
- Algorithme RSASSA-PSS
- Détails du certificat
- 🕐 **Odentas TSA** (horodatage)
- RFC 3161 conforme
- Autorité de temps
- Empreinte horodatée
- 🔍 **Vérification technique**
- Structure PAdES valide
- ByteRange correct
- signing-certificate-v2 présent
- MessageDigest intact
- Statut du certificat (auto-signé ou qualifié)
## Éléments Affichés
### Odentas Seal
- **Format** : PAdES-BASELINE-B (ETSI TS 102 778)
- **Intégrité** : Hash SHA-256 du document
- **Algorithme** : RSASSA-PSS avec SHA-256
- **Certificat** :
- Émetteur
- Sujet
- Période de validité
- Numéro de série
### Odentas TSA (si présent)
- **Standard** : RFC 3161
- **Autorité** : URL du TSA
- **Timestamp** : Date/heure certifiée
- **Empreinte** : Hash horodaté
### Vérification Technique
- ✅ Structure PAdES valide
- ✅ ByteRange correct et complet
- ✅ Attribut signing-certificate-v2 présent
- ✅ MessageDigest intact
- ⚠️ Certificat auto-signé (ou ✅ si qualifié)
## Statuts de Validation
### "Signature Valide" ✅
- Certificat **qualifié** reconnu par les autorités européennes
- Tous les contrôles techniques passent
- **Valeur légale** : QES (Qualified Electronic Signature)
### "Signature Techniquement Valide" ⚠️
- Certificat **auto-signé** (Odentas Media SAS)
- Tous les contrôles techniques passent
- **Valeur légale** : SES (Simple Electronic Signature)
- Note explicative affichée
## Sécurité
### Row Level Security (RLS)
```sql
-- Lecture publique (vérification accessible à tous)
CREATE POLICY "Vérifications publiques" ON signature_verifications
FOR SELECT USING (true);
-- Seul le système peut créer/modifier
CREATE POLICY "Système peut gérer" ON signature_verifications
FOR ALL USING (auth.uid() IS NOT NULL);
```
### Données Publiques
Les informations exposées sont **volontairement publiques** :
- Nom du signataire
- Email du signataire
- Nom du document
- Hash SHA-256
- Certificat de signature
**Aucune donnée sensible** (contenu du document, IBAN, etc.) n'est stockée.
## Intégration dans l'Application
### Dans les Contrats CDDU/RG
Après signature via Docuseal + Odentas Sign :
```typescript
import { useSignatureProof } from "@/hooks/useSignatureProof";
const { createSignatureProof } = useSignatureProof();
// Après réception du document signé
const proof = await createSignatureProof({
document_name: `Contrat ${employee.prenom} ${employee.nom}`,
pdf_url: signedPdfUrl,
signer_name: `${employee.prenom} ${employee.nom}`,
signer_email: employee.email,
signature_hash: extractedHash,
contract_id: contract.id,
organization_id: contract.organization_id,
});
// Télécharger les deux fichiers:
// 1. Document signé (PDF PAdES)
// 2. Preuve de signature (PDF avec QR code)
downloadFile(signedPdfUrl, "contrat-signe.pdf");
downloadFile(URL.createObjectURL(proof.proof_pdf_blob), "preuve-signature.pdf");
```
## Design
### Page de Vérification
- **Layout** : Gradient slate 50→100
- **Cards** : Blanc avec shadow-xl et border-radius 16px
- **Statuts** :
- ✅ Vert (green-600) pour valide
- ⚠️ Orange (orange-600) pour techniquement valide
- ❌ Rouge (red-600) pour invalide
- **Icônes** : Lucide React (CheckCircle2, Shield, Clock, FileText)
### PDF de Preuve
- **Format** : A4 portrait
- **En-tête** : Indigo (Odentas branding)
- **QR Code** : 70x70mm, centré, haute qualité
- **Sections** :
- Document signé (fond slate-100)
- QR code avec URL
- Détails techniques
- Note importante (fond orange-50)
## Variables d'Environnement
```env
NEXT_PUBLIC_APP_URL=https://espace-paie.odentas.com
```
Utilisée pour générer les URLs de vérification.
## Migration Supabase
```bash
# Appliquer la migration
supabase db push
# Ou manuellement
psql -h db.xxx.supabase.co -U postgres -d postgres -f supabase/migrations/20251028_signature_verifications.sql
```
## Exemples d'URLs
```
https://espace-paie.odentas.com/verify/550e8400-e29b-41d4-a716-446655440000
```
## TODO / Améliorations Futures
- [ ] Support multi-signatures (plusieurs signataires)
- [ ] Historique de vérifications (analytics)
- [ ] Notifications email avec lien de vérification
- [ ] API publique de vérification (pour intégrations tierces)
- [ ] Support certificats qualifiés (badge "Qualifié eIDAS")
- [ ] Archivage long terme (LTV avec DSS/LTA)
- [ ] Export PDF/A pour archivage légal
## Conformité
-**PAdES-BASELINE-B** : ETSI TS 102 778
-**RFC 3161** : Horodatage électronique
-**RFC 5035** : signing-certificate-v2
-**RGPD** : Données publiques consenties
- ⚠️ **eIDAS** : SES (auto-signé) ou QES (avec certificat qualifié)
---
**Odentas Media SAS** - Signature électronique sécurisée