- 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é.
8.2 KiB
8.2 KiB
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
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
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
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
- Le document est signé avec Odentas Sign (Lambda PAdES)
- Extraction des données :
- Hash SHA-256 du contenu signé
- Certificat de signature
- Horodatage TSA (si présent)
- Appel API
/api/signatures/create-verification - Génération :
- Entrée dans
signature_verifications - QR code pointant vers
/verify/{id} - PDF de preuve avec QR code
- Entrée dans
- Téléchargement :
- Document signé (PDF avec signature PAdES)
- Preuve de signature (PDF avec QR code)
Vérification par le Signataire
- Scanner le QR code ou visiter l'URL
- 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)
-- 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 :
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
NEXT_PUBLIC_APP_URL=https://espace-paie.odentas.com
Utilisée pour générer les URLs de vérification.
Migration Supabase
# 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