PD-283 — Assemblage local Zero-Knowledge du dossier probatoire .pvproof (iOS)¶
1. Objectif¶
Contractualiser la génération côté client d’un dossier probatoire auto-porteur au format .pvproof, à partir des artefacts fournis par POST /exports/complaint-file, avec déchiffrement local et sans exposition serveur des contenus en clair.
Le résultat attendu est un fichier unique .pvproof : - structurellement conforme au RFC PV-PACK-001 v1.0.0 ; - partageable/sauvegardable/supprimable par l’utilisateur ; - accompagné d’un hash SHA3-256 informatif calculé sur le conteneur final.
2. Périmètre / Hors périmètre¶
Inclus¶
- Appel backend
POST /exports/complaint-fileavecproofIds[]. - Traitement de
manifest.json,chronology.json,signedUrls[],guideUrl,readmeVerification,rejectedProofs[]. - Téléchargement séquentiel des artefacts chiffrés via URLs signées.
- Déchiffrement local (Zero-Knowledge) et assemblage
.pvproofen streaming disque. - Écran de progression multi-étapes avec compteurs.
- Gestion rejets partiels et continuation explicite utilisateur.
- Calcul SHA3-256 final (informatif), affichage et copie.
- Actions post-génération : Partager, Sauvegarder, Supprimer.
- Notification locale de rappel à 24h.
- Gestion erreurs 403/422/expiration URL/échec réseau/fichier introuvable.
Exclu¶
- Android.
- Web/PWA.
- Export en background.
- Chiffrement du conteneur
.pvproof. - Outil CLI
pv verify. - Enregistrement MIME OS dédié.
- Génération PDF timeline riche.
- Toute modification des artefacts backend (hors périmètre fonctionnel et interdite).
3. Définitions¶
3.1 Glossaire¶
.pvproof: conteneur ZIP avec extension dédiée ProbatioVault.- ProofEnvelope : enveloppe de preuve RFC PV-PROOF-001.
- Zero-Knowledge (contexte export) : le backend n’accède pas aux données en clair exportées.
- Passthrough strict : les artefacts backend sont injectés dans le conteneur sans altération de contenu.
- K_doc : clé de document dérivée côté client depuis
kmaster(PD-34).
3.2 États métier d’export (machine à états)¶
États : IDLE, PREPARING, DOWNLOADING, DECRYPTING, ASSEMBLING, HASHING, READY, FAILED, DELETED.
3.3 Modèle de données et formats contractuels (source unique)¶
| Donnée | Format/encodage | Taille | Charset / casse | Regex / validation | Si invalide |
|---|---|---|---|---|---|
proofId (entrée) | UUID v4 texte | 36 chars | ASCII, case-insensitive en entrée, normalisé lowercase | ^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}$ | 400 côté API ; côté app blocage avant appel + message |
exportId (réponse) | identifiant opaque texte | 8..128 chars | ASCII printable, case-sensitive | ^[A-Za-z0-9_-]{8,128}$ | abort export + message “identifiant export invalide” |
signedUrl | URL HTTPS RFC3986 | 1..2048 chars | UTF-8 URL, case-sensitive path/query | schéma https obligatoire | URL rejetée, refresh API obligatoire |
manifest.json | JSON UTF-8 | 1 B..10 MB | UTF-8 | JSON valide obligatoire | abort export |
chronology.json | JSON UTF-8 | 1 B..10 MB | UTF-8 | JSON valide obligatoire | abort export |
readmeVerification | texte UTF-8 | 1..200 KB | UTF-8 | non vide | abort export |
integrityHash (manifest) | SHA3-256 hex | 64 chars | [a-f0-9], case-sensitive | ^[a-f0-9]{64}$ | export marqué invalide, abort |
hashFinal (.pvproof) | SHA3-256 hex | 64 chars | [a-f0-9], case-sensitive | ^[a-f0-9]{64}$ | erreur finalisation |
| Nom fichier preuve (archive) | nom sanitizé | 1..120 chars | UTF-8 normalisé NFC | interdit .., /, \, contrôle ASCII | remplacement + suffixe collision ; si vide après sanitization => rejet fichier |
| Nom archive finale | PV-Dossier-Plainte_{YYYY-MM-DD}_{exportId8}.pvproof — exportId8 = 8 premiers caractères alphanumériques de exportId | 36..80 chars | ASCII, case-sensitive | ^PV-Dossier-Plainte_[0-9]{4}-[0-9]{2}-[0-9]{2}_[A-Za-z0-9]{8}\.pvproof$ | renommage bloqué + erreur explicite |
Notes contractuelles : - Les formats définis ici font foi pour toutes les sections suivantes. - Les artefacts backend (manifest, chronology, enveloppes) sont traités en passthrough strict (aucune réécriture sémantique).
3.4 Bornes numériques et SLA temporels¶
| Paramètre | Défaut | Min | Max | Unité | Contexte | Hors bornes |
|---|---|---|---|---|---|---|
maxRetries téléchargement | 3 | 0 | 3 | tentatives | réseau mobile/Wi-Fi | >3 interdit (clamp à 3), <0 rejet config |
| Backoff | 1,2,4 | 1 | 4 | secondes | retry #1..#3 | séquence non conforme => erreur logique + arrêt |
| TTL URL signée | 30 | 1 | 30 | minutes | backend PD-85 | expirée => refresh API ; >30 non conforme contrat backend |
| Rappel suppression | 24 | 24 | 24 | heures | notification locale | valeur différente interdite V1 |
| Taille export supportée | — | 1 | 1024 | MB | fichier final .pvproof | >1024 MB : refus export ; 500..1024 MB : warning |
| Perf 12 preuves/50MB | P95 < 30 | — | 30 | secondes | iPhone 12, iOS 16+, Wi-Fi stable | au-delà : non-conformité NFR |
| Perf 50 preuves/200MB | P95 < 60 | — | 60 | secondes | iPhone 12, iOS 16+, Wi-Fi stable | au-delà : non-conformité NFR |
| Pic mémoire assemblage | < 50 | — | 50 | MB | iPhone 12, iOS 16+ | >50 MB : non-conformité NFR |
4. Invariants (non négociables)¶
| ID | Règle | Justification |
|---|---|---|
| INV-283-01 | Aucun contenu probatoire en clair ne persiste hors du .pvproof final. | Exigence Zero-Knowledge et minimisation d’exposition. |
| INV-283-02 | Assemblage du .pvproof en streaming disque ; au plus un fichier clair en mémoire à la fois. | Prévention OOM mobile. |
| INV-283-03 | Le hash SHA3-256 est calculé en streaming sur le conteneur final complet. | Intégrité de transmission sans charger tout en RAM. |
| INV-283-04 | Notification locale de rappel programmée à 24h (±5min) après génération. Si permission notification refusée par l'OS, un bandeau in-app persistant informe l'utilisateur que le rappel automatique n'est pas actif. | Privacy sans perte automatique de preuve. |
| INV-283-05 | Tout fichier temporaire (chiffré ou clair transitoire) est supprimé immédiatement après usage. | Réduction surface d’attaque. |
| INV-283-06 | Retry réseau borné à 3 tentatives max avec backoff 1s/2s/4s. | Résilience contrôlée, pas de boucle infinie. |
| INV-283-07 | manifest.json, chronology.json, enveloppes et README sont en passthrough strict. | Intégrité probatoire. |
| INV-283-08 | pvproof.json est la première entrée archive, mode STORED sans compression. | Conformité RFC PV-PACK-001. |
| INV-283-09 | Extension finale strictement .pvproof (jamais .zip). | Identité protocolaire du conteneur. |
| INV-283-10 | Sanitization obligatoire des noms avant insertion archive (anti path traversal/zip slip). | Sécurité archive. |
| INV-283-11 | kmaster n’est jamais utilisée directement pour déchiffrer un fichier ; seule K_doc dérivée est autorisée. | Cloisonnement cryptographique (PD-34). |
| INV-283-12 | Machine à états contractuelle : toute transition non listée est interdite explicitement. | Élimination des ambiguïtés de cycle de vie. |
| INV-283-13 | Tout artefact cryptographique temporaire (clé en mémoire, fragment, K_doc) est protégé au repos via iOS Keychain/Data Protection ; aucun secret en clair persistant en stockage durable app. | Sécurité mobile — applicable car l'app manipule K_doc et déchiffre localement. |
5. Flux nominaux¶
5.1 Flux F-01 — Export nominal complet¶
- Entrée utilisateur : sélection de preuves valides (
proofIds[]). - Appel
POST /exports/complaint-file. - Réception artefacts backend + URLs signées.
- Pour chaque preuve valide : téléchargement chiffré -> déchiffrement local -> ajout dans
preuves/+ enveloppe dansenveloppes/. - Ajout des artefacts racine (
pvproof.json,manifest.json,chronology.json,README_VERIFICATION.txt,guide_plainte_france.pdf). - Finalisation archive
.pvproof. - Calcul SHA3-256 final et affichage.
- Actions utilisateur : partager / sauvegarder / supprimer.
5.2 Flux F-02 — Export partiel avec rejectedProofs¶
- Backend retourne
rejectedProofs[]non vide. - App affiche liste + motifs.
- Décision utilisateur :
- continuer avec valides -> reprise F-01 sur sous-ensemble ;
- annuler -> retour
IDLE. - Si 100% rejet (
422) : arrêt, aucune archive produite.
5.3 Flux F-03 — URL expirée¶
- Détection échec lié expiration URL.
- Nouvel appel API pour rafraîchir URLs.
- Reprise téléchargement au prochain artefact non finalisé.
- Contrainte : pas de duplication d’entrée archive déjà validée.
5.4 Flux F-04 — Gestion progression UX obligatoire¶
Affichage minimal contractuel : - Téléchargement n/N - Déchiffrement n/N - Assemblage - Finalisation
Spinner seul interdit.
5.5 Transitions d’état (avec transitions retour)¶
| État source | Sorties autorisées | Sorties interdites |
|---|---|---|
IDLE | PREPARING | DECRYPTING,ASSEMBLING,HASHING,READY,DELETED |
PREPARING | DOWNLOADING,FAILED,IDLE (annulation) | autres |
DOWNLOADING | DECRYPTING,FAILED,IDLE (annulation) | READY,DELETED |
DECRYPTING | ASSEMBLING,FAILED,IDLE (annulation) | READY,DELETED |
ASSEMBLING | DOWNLOADING (preuve suivante), HASHING,FAILED,IDLE (annulation) | READY direct |
HASHING | READY,FAILED | DOWNLOADING,DECRYPTING |
READY | DELETED,IDLE (sortie écran sans suppression) | DOWNLOADING,DECRYPTING,ASSEMBLING,HASHING |
FAILED | PREPARING (retry explicite), IDLE | READY,DELETED direct |
DELETED | IDLE (retour explicite après suppression confirmée) | DOWNLOADING,DECRYPTING,ASSEMBLING,HASHING,READY,PREPARING |
Règles retour/downgrade : - Retour FAILED -> PREPARING : autorisé uniquement SI tous les fichiers temporaires ont été purgés avec succès (garde purge_ok). Redémarrage sur un nouveau cycle d’export ; aucun artefact partiel en clair conservé. - Retour READY -> IDLE : fichier conservé tant que non supprimé. - READY -> DELETED : suppression irréversible du fichier local. - DELETED -> IDLE : retour explicite après confirmation de suppression réussie. L’écran revient à l’état initial. - Aucun “resume implicite” après FAILED sans action explicite utilisateur.
5bis. Diagrammes Mermaid¶
5bis.1 Diagramme d’états — Machine à états d’export (INV-283-12)¶
Toute transition non représentée est interdite (INV-283-12). Les transitions retour sont incluses conformément au §5.5.
stateDiagram-v2
[*] --> IDLE
IDLE --> PREPARING
PREPARING --> DOWNLOADING
PREPARING --> FAILED
PREPARING --> IDLE : annulation
DOWNLOADING --> DECRYPTING
DOWNLOADING --> FAILED
DOWNLOADING --> IDLE : annulation
DECRYPTING --> ASSEMBLING
DECRYPTING --> FAILED
DECRYPTING --> IDLE : annulation
ASSEMBLING --> DOWNLOADING : preuve suivante
ASSEMBLING --> HASHING
ASSEMBLING --> FAILED
ASSEMBLING --> IDLE : annulation
HASHING --> READY
HASHING --> FAILED
READY --> DELETED
READY --> IDLE : sortie écran
FAILED --> PREPARING : retry [purge_ok]
FAILED --> IDLE
DELETED --> IDLE : confirmation suppression
note right of FAILED
Retour PREPARING uniquement
si purge fichiers temp OK
(INV-283-05)
end note
note right of READY
Fichier conservé tant
que non supprimé
(INV-283-01)
end note 5bis.2 Diagramme de séquence — Flux nominal F-01 (export complet)¶
Couvre le flux multi-service avec déchiffrement Zero-Knowledge côté client (INV-283-01, INV-283-02, INV-283-03, INV-283-07, INV-283-11).
sequenceDiagram
actor User
participant App as ProbatioVault App (iOS)
participant Crypto as Module Crypto (PD-34)
participant Backend as Backend API (PD-85)
participant S3 as Stockage chiffré (URLs signées)
User->>App: Sélection proofIds[] + lancement export
activate App
Note over App: État IDLE → PREPARING
App->>Backend: POST /exports/complaint-file {proofIds[]}
Backend-->>App: {exportId, manifest, chronology,<br/>signedUrls[], guideUrl, readmeVerification,<br/>rejectedProofs[]}
alt rejectedProofs non vide
App->>User: Affiche liste rejets + motifs
User-->>App: Confirme continuation / annule
end
Note over App: État PREPARING → DOWNLOADING
loop Pour chaque preuve valide (séquentiel, INV-283-02)
App->>S3: GET signedUrl[i] (artefact chiffré)
S3-->>App: Fichier chiffré (streaming disque)
Note over App: État DOWNLOADING → DECRYPTING
App->>Crypto: Dériver K_doc depuis kmaster (INV-283-11)
Crypto-->>App: K_doc
App->>App: Déchiffrement local avec K_doc (INV-283-01)
App->>App: Ajout preuve dans archive preuves/ (streaming)
App->>App: Ajout enveloppe dans archive enveloppes/
Note over App: État DECRYPTING → ASSEMBLING
App->>App: Suppression fichier temp (INV-283-05)
Note over App: État ASSEMBLING → DOWNLOADING (preuve suivante)
end
Note over App: Ajout artefacts racine (passthrough strict, INV-283-07)
App->>App: pvproof.json (1ère entrée STORED, INV-283-08)
App->>App: manifest.json, chronology.json
App->>App: README_VERIFICATION.txt
App->>App: guide_plainte_france.pdf
Note over App: État ASSEMBLING → HASHING
App->>App: SHA3-256 streaming sur .pvproof (INV-283-03)
Note over App: État HASHING → READY
App-->>User: Hash affiché (64 hex lowercase)
App->>App: Programmation notification 24h (INV-283-04)
User->>App: Partager / Sauvegarder / Supprimer
deactivate App 5bis.3 Diagramme de séquence — Flux F-03 (URL expirée + refresh)¶
Couvre le mécanisme de retry borné (INV-283-06) et le rafraîchissement d’URL.
sequenceDiagram
participant App as ProbatioVault App
participant S3 as Stockage (URL signée)
participant Backend as Backend API
App->>S3: GET signedUrl[i]
S3-->>App: 403 Forbidden (URL expirée)
Note over App: Détection expiration URL
App->>Backend: POST /exports/complaint-file (refresh)
Backend-->>App: {nouvelles signedUrls[]}
App->>S3: GET nouvelleSignedUrl[i]
S3-->>App: Fichier chiffré (OK)
Note over App: Reprise flux au prochain artefact<br/>non finalisé (pas de duplication) 6. Cas d’erreur¶
| ID | Condition | Réponse attendue |
|---|---|---|
| ERR-01 | 403 plan FREE | Message blocant + CTA Premium ; export non lancé. |
| ERR-02 | 422 toutes preuves rejetées | Message explicite ; aucun assemblage. |
| ERR-03 | URL expirée | Refresh API automatique puis reprise. |
| ERR-04 | 404/410 fichier introuvable | Abort export + message cause et preuve concernée. |
| ERR-05 | Timeout/réseau transitoire | Retry 1s/2s/4s puis demande “Réessayer ?”. |
| ERR-06 | Hash/format invalide artefact | Abort export ; signaler artefact corrompu/non conforme. |
| ERR-07 | Espace disque insuffisant | Abort export ; message capacité requise. |
| ERR-08 | Échec suppression temp | Export marqué en échec sécurité ; purge forcée avant nouvelle tentative. |
| ERR-09 | Nom de fichier non sanitizable (vide après sanitization) | Fichier rejeté avec motif dans rejectedFiles[] ; export continue avec les fichiers restants. Si collision post-sanitization, suffixe incrémental _2, _3, etc. |
7. Critères d’acceptation (testables)¶
| ID | Critère | Observable |
|---|---|---|
| CA-01 | Appel API export effectué avec proofIds[] valides | Requête sortante conforme + réponse traitée. |
| CA-02 | Retry réseau borné 3 tentatives max | Journaux/trace montrent 1,2,4s puis arrêt. |
| CA-03 | URL expirée déclenche refresh automatique | Nouvelle requête API + reprise sans crash. |
| CA-04 | Déchiffrement local uniquement avec K_doc dérivée | Trace crypto sans usage direct kmaster pour payload. |
| CA-05 | Assemblage streaming disque (pas ZIP RAM complet) | Pic mémoire < 50MB en test référence. |
| CA-06 | pvproof.json première entrée STORED | Inspection archive conforme RFC. |
| CA-07 | Arborescence archive conforme | preuves/, enveloppes/, fichiers racine présents. |
| CA-08 | Hash SHA3-256 final calculé et affiché | 64 hex lowercase copiable. |
| CA-09 | Extension finale .pvproof | Nom export respecte regex contractuelle. |
| CA-10 | Progression multi-étapes visible | UI montre étapes + compteurs n/N. |
| CA-11 | Rejets partiels gérés avec confirmation utilisateur | Liste motifs + choix continuer/annuler. |
| CA-12 | Notification locale à 24h (±5min) programmée, ou bandeau in-app si permission refusée | Notification présente à T0+24h ±5min OU bandeau visible si permission absente. |
| CA-13 | Aucune persistance clair hors .pvproof final | Audit fichiers sandbox : aucun artefact clair résiduel. |
| CA-14 | Sanitization anti zip-slip appliquée | Noms dangereux neutralisés ; pas d’écrasement racine. |
| CA-15 | Perf 50MB/12 preuves | P95 < 30s (iPhone 12, Wi-Fi). |
| CA-16 | Perf 200MB/50 preuves | P95 < 60s (iPhone 12, Wi-Fi). |
8. Scénarios de test (Given / When / Then)¶
- ST-01 Nominal
- Given 5
proofIdsvalides et backend disponible - When l’utilisateur lance l’export
-
Then un
.pvproofconforme est généré, hash affiché, actions post-export disponibles. -
ST-02 Partiel
- Given 10 preuves dont 2 rejetées par backend
- When l’utilisateur confirme la continuation
-
Then l’archive contient uniquement 8 preuves valides et leurs enveloppes.
-
ST-03 Rejet total
- Given toutes les preuves rejetées (
422) - When l’utilisateur lance l’export
-
Then aucun fichier n’est généré et un message explicite s’affiche.
-
ST-04 Expiration URL
- Given une URL signée expirée en cours de flux
- When le téléchargement échoue pour expiration
-
Then l’app rafraîchit les URLs et reprend le flux.
-
ST-05 Réseau instable
- Given une perte réseau intermittente
- When le téléchargement échoue
-
Then retries 1s/2s/4s sont appliqués puis proposition de réessai.
-
ST-06 Sécurité fichiers
- Given un nom source
../../manifest.json - When insertion dans archive
-
Then le nom est sanitizé et aucun fichier racine n’est écrasé.
-
ST-07 Confidentialité
- Given un export terminé
- When audit sandbox est exécuté
-
Then aucun fichier clair temporaire n’est présent hors
.pvproof. -
ST-08a Notification 24h (permission accordée)
- Given un export finalisé à
T0et permission notification iOS accordée - When
T0+24h ±5minest atteint -
Then une notification locale de rappel est délivrée.
-
ST-08b Notification 24h (permission refusée)
- Given un export finalisé à
T0et permission notification iOS refusée - When l'écran d'export est affiché
- Then un bandeau in-app persistant informe que le rappel automatique n'est pas actif.
9. Hypothèses explicites¶
| ID | Hypothèse | Impact si faux |
|---|---|---|
| H-01 | Le backend renvoie un exportId stable et exploitable pour le nommage. | Nommage final non déterministe, risque non-conformité format. |
| H-02 | Les schémas JSON détaillés de manifest/chronology sont définis en PD-85/RFC. | Validation structurelle incomplète côté app. |
| H-03 | Le module crypto PD-34 expose une dérivation K_doc testable pour chaque preuve. | Impossible de vérifier CA-04. |
| H-04 | Les permissions notification locale iOS sont disponibles/accordées. | Rappel 24h non garanti ; CA-12 partiellement non atteignable. |
| H-05 | Le backend fournit des URLs HTTPS toujours téléchargeables dans TTL contractuel. | Dégradation forte du taux de succès export. |
10. Points à clarifier¶
- Schéma exact des payloads PD-85 (
manifest,chronology,rejectedProofs, codes erreur) : non fourni ici — validation structurelle côté app limitée à JSON valide + champs obligatoires de premier niveau. Règle exacte de dérivation— RÉSOLU : 8 premiers caractères alphanumériques deexportId-8exportId(cf. §3.3). SiexportIdcontient moins de 8 alphanumériques, utiliser tous les alphanumériques disponibles complétés par des zéros à droite.Politique collision noms sanitizés— RÉSOLU : suffixe incrémental_2,_3, etc. (cf. ERR-09 §6).Comportement contractuel si permissions notifications refusées— RÉSOLU : bandeau in-app persistant (cf. INV-283-04 §4).- Borne max du nombre de preuves sélectionnables (non contractualisée dans le besoin) — limité par la borne de taille 1024 MB max.
- Critère légal exact du représentant légal côté app (champ/attestation visible ou implicite backend) — hors périmètre PD-283, couvert par le flux backend PD-85.
Contraintes techniques (stack projet cible)¶
- Projet cible : ProbatioVault-app.
- Stack contractuelle : React Native + Expo SDK 54 + TypeScript.
- Plateforme V1 : iOS uniquement (foreground).
- Contrainte : aucune référence Swift/SwiftUI comme stack applicative principale dans cette US.
Applicabilité des clauses obligatoires complémentaires¶
- Transitions retour : applicables (machine à états spécifiée).
- SLA temporels : applicables (TTL URLs, rappel 24h).
- Formats de données : applicables (table §3.3).
- Migration DDL : non applicable (pas de modification schéma DB côté app).
- Atomicité DB + queue/append-only : non applicable (scope client mobile).
- Contraintes inter-modules : Aucune contrainte inter-module applicable côté app dans ce périmètre V1.
Références¶
- Epic : Référence épique non fournie (à renseigner).
- JIRA :
PD-283. - Repos concernés :
ProbatioVault-app(principal),ProbatioVault-backend(API dépendante). - Documents associés :
ProbatioVault-doc/docs/normes/pv-pack/RFC-PV-PACK.md- RFC PV-PROOF-001 v1.2.0
- PD-85, PD-34, PD-242, PD-282, PD-84, PD-4/44
- Art. 1366 Code civil.