Aller au contenu

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-file avec proofIds[].
  • 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 .pvproof en 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}.pvproofexportId8 = 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

  1. Entrée utilisateur : sélection de preuves valides (proofIds[]).
  2. Appel POST /exports/complaint-file.
  3. Réception artefacts backend + URLs signées.
  4. Pour chaque preuve valide : téléchargement chiffré -> déchiffrement local -> ajout dans preuves/ + enveloppe dans enveloppes/.
  5. Ajout des artefacts racine (pvproof.json, manifest.json, chronology.json, README_VERIFICATION.txt, guide_plainte_france.pdf).
  6. Finalisation archive .pvproof.
  7. Calcul SHA3-256 final et affichage.
  8. Actions utilisateur : partager / sauvegarder / supprimer.

5.2 Flux F-02 — Export partiel avec rejectedProofs

  1. Backend retourne rejectedProofs[] non vide.
  2. App affiche liste + motifs.
  3. Décision utilisateur :
  4. continuer avec valides -> reprise F-01 sur sous-ensemble ;
  5. annuler -> retour IDLE.
  6. Si 100% rejet (422) : arrêt, aucune archive produite.

5.3 Flux F-03 — URL expirée

  1. Détection échec lié expiration URL.
  2. Nouvel appel API pour rafraîchir URLs.
  3. Reprise téléchargement au prochain artefact non finalisé.
  4. 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 proofIds valides et backend disponible
  • When l’utilisateur lance l’export
  • Then un .pvproof conforme 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é à T0 et permission notification iOS accordée
  • When T0+24h ±5min est atteint
  • Then une notification locale de rappel est délivrée.

  • ST-08b Notification 24h (permission refusée)

  • Given un export finalisé à T0 et 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

  1. 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.
  2. Règle exacte de dérivation exportId-8 — RÉSOLU : 8 premiers caractères alphanumériques de exportId (cf. §3.3). Si exportId contient moins de 8 alphanumériques, utiliser tous les alphanumériques disponibles complétés par des zéros à droite.
  3. Politique collision noms sanitizés — RÉSOLU : suffixe incrémental _2, _3, etc. (cf. ERR-09 §6).
  4. Comportement contractuel si permissions notifications refusées — RÉSOLU : bandeau in-app persistant (cf. INV-283-04 §4).
  5. Borne max du nombre de preuves sélectionnables (non contractualisée dans le besoin) — limité par la borne de taille 1024 MB max.
  6. 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.