Aller au contenu

PD-248 — Plan d'implémentation

Vue d'ensemble

Attribut Valeur
Story PD-248 — Protection screenshot native iOS
Complexité Low-Medium
Fichiers estimés 8-12
Tâches 6
Dépendance externe expo-screen-capture

Architecture technique

Composants

src/
├── hooks/
│   └── useScreenshotProtection.ts      # Hook principal (INV-248-01..08)
├── components/
│   └── ScreenshotProtectedView.tsx     # Wrapper HOC optionnel
├── services/
│   └── screenshotProtection.ts         # Service de logging/erreurs
└── __tests__/
    ├── hooks/
    │   └── useScreenshotProtection.test.ts
    └── e2e/
        └── screenshot-protection.e2e.ts

Flux de données

┌─────────────────┐
│ Navigation      │
│ (écran sensible)│
└────────┬────────┘
         │ onFocus
┌─────────────────┐
│ useScreenshot   │
│ Protection()    │
│ - useFocusEffect│
└────────┬────────┘
┌─────────────────┐     ┌─────────────────┐
│ preventScreen   │────▶│ protection_state│
│ Capture()       │     │ = ACTIVE        │
└────────┬────────┘     └─────────────────┘
         │ onBlur (écran non sensible)
┌─────────────────┐     ┌─────────────────┐
│ allowScreen     │────▶│ protection_state│
│ Capture()       │     │ = INACTIVE      │
└─────────────────┘     └─────────────────┘

Tâches d'implémentation

TASK-1 : Installation et configuration expo-screen-capture

Agent : agent-sre Fichiers : - package.json (dépendance) - app.json ou app.config.ts (plugin Expo si nécessaire)

Actions : 1. npx expo install expo-screen-capture 2. Vérifier compatibilité EAS Build 3. Ajouter au .gitignore si fichiers natifs générés

Invariants couverts : INV-248-07


TASK-2 : Hook useScreenshotProtection

Agent : agent-developer Fichiers : - src/hooks/useScreenshotProtection.ts

Contrat de code : CC-248-01

Actions : 1. Implémenter le hook avec useFocusEffect 2. Appeler preventScreenCapture() sur focus 3. Appeler allowScreenCapture() sur blur (sauf transition sensible→sensible) 4. Gérer les erreurs avec fallback (ERR-248-001, ERR-248-002)

Invariants couverts : INV-248-01, INV-248-02, INV-248-03, INV-248-04, INV-248-08


TASK-3 : Intégration dans les écrans sensibles

Agent : agent-developer Fichiers : - src/screens/recovery/MnemonicDisplay.tsx (SCR-248-01) - src/screens/settings/MFASetupScreen.tsx (SCR-248-02) - src/components/mfa/TOTPCodeDisplay.tsx (SCR-248-03) - src/screens/settings/APIKeyDisplay.tsx (SCR-248-04, si existant)

Contrat de code : CC-248-02

Actions : 1. Ajouter useScreenshotProtection() à chaque composant 2. Vérifier que l'appel est au niveau du composant racine de l'écran 3. Pas de props/configuration — comportement automatique

Invariants couverts : INV-248-02, INV-248-05


TASK-4 : Service de logging technique

Agent : agent-developer Fichiers : - src/services/screenshotProtection.ts

Contrat de code : CC-248-03

Actions : 1. Créer fonctions de logging pour ERR-248-001..004 2. Pas d'alerte utilisateur (INV-248-04) 3. Compatible avec système de télémétrie existant

Invariants couverts : INV-248-04, ERR-248-001..004


TASK-5 : Tests unitaires

Agent : agent-qa-unit-integration Fichiers : - src/__tests__/hooks/useScreenshotProtection.test.ts

Contrat de code : CC-248-04

Actions : 1. Tester activation sur focus 2. Tester désactivation sur blur 3. Tester maintien en transition sensible→sensible 4. Mocker expo-screen-capture

Tests couverts : TC-248-NOM-01..07, TC-248-SIL-01


TASK-6 : Tests E2E avec OCR

Agent : agent-qa-e2e Fichiers : - src/__tests__/e2e/screenshot-protection.e2e.ts - Scripts OCR Tesseract (si nécessaire)

Contrat de code : CC-248-05

Actions : 1. Capturer screenshot de chaque écran sensible 2. Exécuter OCR Tesseract sur les captures 3. Vérifier absence des données sensibles 4. Test de performance (< 10ms activation)

Tests couverts : CA-248-01..08, TC-248-PERF-01


Code Contracts

CC-248-01 : useScreenshotProtection

/**
 * Hook de protection screenshot pour écrans sensibles.
 *
 * @invariants
 * - INV-248-01: Si protection active, capture = BLOCKED
 * - INV-248-02: Activation automatique sur focus
 * - INV-248-03: Désactivation sur blur (sauf sensible→sensible)
 * - INV-248-04: Silencieux (pas d'alerte utilisateur)
 * - INV-248-08: Activation < 10ms
 *
 * @usage
 * ```tsx
 * function MnemonicDisplay() {
 *   useScreenshotProtection();
 *   return <View>...</View>;
 * }
 * ```
 */
export function useScreenshotProtection(): void;

Signature : - Pas de paramètres - Pas de retour (effet de bord uniquement) - Doit utiliser useFocusEffect de React Navigation


CC-248-02 : Intégration écrans sensibles

/**
 * Chaque écran sensible DOIT appeler useScreenshotProtection()
 * au niveau racine du composant.
 *
 * @screens SCR-248-01..04
 */

// Pattern d'intégration
function SensitiveScreen() {
  useScreenshotProtection(); // OBLIGATOIRE, première ligne

  // ... reste du composant
}

Règles : - Appel en première ligne après les autres hooks - Pas de condition (toujours actif pour écrans sensibles) - Pas de props de configuration


CC-248-03 : Service de logging

/**
 * Service de logging technique pour erreurs de protection.
 *
 * @invariant INV-248-04: Aucune alerte utilisateur
 */
export interface ScreenshotProtectionLogger {
  logActivationError(screen: ScreenId, error: Error): void;  // ERR-248-001
  logMaintainError(from: ScreenId, to: ScreenId, error: Error): void;  // ERR-248-002
  logUnregisteredComponent(component: string): void;  // ERR-248-003
  logIncompatibleEnvironment(): void;  // ERR-248-004
}

Règles : - Logging technique uniquement (console, Sentry, etc.) - Jamais d'UI visible utilisateur - Format structuré avec error_code


CC-248-04 : Tests unitaires

/**
 * Tests unitaires du hook useScreenshotProtection.
 *
 * @coverage INV-248-01..08
 */
describe('useScreenshotProtection', () => {
  it('should call preventScreenCapture on focus', () => {});
  it('should call allowScreenCapture on blur to non-sensitive', () => {});
  it('should maintain protection on sensitive→sensitive transition', () => {});
  it('should not show any UI alert', () => {});
  it('should activate in less than 10ms', () => {});
});

CC-248-05 : Tests E2E avec OCR

/**
 * Tests E2E avec vérification OCR.
 *
 * @tool Tesseract 5.x
 * @coverage CA-248-01..04
 */
describe('Screenshot protection E2E', () => {
  it('should block screenshot on MnemonicDisplay (OCR verification)', async () => {
    // 1. Navigate to MnemonicDisplay
    // 2. Take screenshot
    // 3. Run Tesseract OCR
    // 4. Assert no mnemonic word detected
  });
  // ... repeat for SCR-248-02..04
});

Contraintes techniques

Dépendances inter-PD

Story Statut Nature de la dépendance
PD-242 DONE MnemonicDisplay (composant cible)
PD-106 DONE MFASetupScreen, TOTPCodeDisplay (composants cibles)

Framework de test

  • Runner : Vitest (compatible ESM)
  • E2E : Detox (si disponible) ou tests manuels simulateur
  • OCR : Tesseract 5.x via script shell ou intégration CI

Compatibilité

  • iOS : 15.0+
  • Expo SDK : Compatible version courante
  • EAS Build : Profil production requis pour validation finale

Diagrammes Mermaid

Graphe de dépendances des tâches

graph TD
    T1["TASK-1<br/>Installation expo-screen-capture<br/>(agent-sre)"]
    T2["TASK-2<br/>Hook useScreenshotProtection<br/>(agent-developer)"]
    T3["TASK-3<br/>Intégration écrans sensibles<br/>(agent-developer)"]
    T4["TASK-4<br/>Service de logging<br/>(agent-developer)"]
    T5["TASK-5<br/>Tests unitaires<br/>(agent-qa-unit-integration)"]
    T6["TASK-6<br/>Tests E2E + OCR<br/>(agent-qa-e2e)"]

    T1 --> T2
    T2 --> T3
    T2 --> T4
    T1 --> T4
    T3 --> T5
    T4 --> T5
    T3 --> T6
    T4 --> T6
    T5 --> T6

    classDef sre fill:#e1f5fe,stroke:#0288d1
    classDef dev fill:#e8f5e9,stroke:#388e3c
    classDef qa fill:#fff3e0,stroke:#f57c00

    class T1 sre
    class T2,T3,T4 dev
    class T5 qa
    class T6 qa

Diagramme de séquence — Activation / désactivation de la protection

sequenceDiagram
    participant Nav as Navigation<br/>(React Navigation)
    participant Hook as useScreenshotProtection
    participant ESC as expo-screen-capture
    participant Log as ScreenshotProtectionLogger

    Note over Nav: Utilisateur navigue vers<br/>écran sensible (MnemonicDisplay)

    Nav->>Hook: useFocusEffect (focus)
    Hook->>ESC: preventScreenCapture()
    alt Activation OK
        ESC-->>Hook: void (protection ACTIVE)
    else Erreur native
        ESC-->>Hook: Error
        Hook->>Log: logActivationError(SCR-248-01, err)
        Note over Log: ERR-248-001<br/>Log technique uniquement,<br/>pas d'alerte utilisateur
    end

    Note over Nav: Utilisateur navigue vers<br/>écran sensible (MFASetupScreen)

    Nav->>Hook: useFocusEffect (focus)
    Hook->>Hook: Transition sensible→sensible<br/>maintien protection (INV-248-03)
    Note over ESC: preventScreenCapture()<br/>reste actif, pas de toggle

    Note over Nav: Utilisateur navigue vers<br/>écran NON sensible

    Nav->>Hook: useFocusEffect cleanup (blur)
    Hook->>ESC: allowScreenCapture()
    ESC-->>Hook: void (protection INACTIVE)

Mapping INV/CA → TASK

Invariant/CA Tâche couvrant Test couvrant
INV-248-01 TASK-2 TC-248-NOM-01..04
INV-248-02 TASK-2, TASK-3 TC-248-NOM-01..04
INV-248-03 TASK-2 TC-248-NOM-05, TC-248-NOM-06
INV-248-04 TASK-2, TASK-4 TC-248-SIL-01
INV-248-05 TASK-3 TC-248-NOM-07, TC-248-REG-01
INV-248-06 TASK-6 TC-248-ENV-02
INV-248-07 TASK-1 TC-248-CFG-01
INV-248-08 TASK-2, TASK-6 TC-248-PERF-01
CA-248-01 TASK-3, TASK-6 TC-248-NOM-01
CA-248-02 TASK-3, TASK-6 TC-248-NOM-02
CA-248-03 TASK-3, TASK-6 TC-248-NOM-03
CA-248-04 TASK-3, TASK-6 TC-248-NOM-04
CA-248-05 TASK-3 TC-248-NOM-05, TC-248-NOM-07
CA-248-06 TASK-6 TC-248-PERF-01
CA-248-07 TASK-4 TC-248-SIL-01
CA-248-08 TASK-6 TC-248-ENV-02
CA-248-09 TASK-1 TC-248-CFG-01
CA-248-10 TASK-5, TASK-6 TC-248-ENV-01

Références