PD-174 : Auto-lock Configurable + Effacement Cache¶
Vue d'ensemble¶
Cette fonctionnalité implémente un système de verrouillage automatique de l'application ProbatioVault après une période d'inactivité configurable, avec effacement automatique des données sensibles en mémoire.
Objectifs de sécurité¶
- Protéger les données sensibles en cas d'abandon de l'appareil
- Effacer les clés cryptographiques et mots de passe de la mémoire
- Permettre un déverrouillage rapide par mot de passe ou biométrie
- Offrir une expérience utilisateur configurable
Architecture¶
┌─────────────────────────────────────────────────────────────┐
│ AppNavigator.tsx │
│ ┌────────────────────────────────────────────────────────┐ │
│ │ useAutoLock() hook │ │
│ │ ┌─────────────┐ ┌──────────────┐ │ │
│ │ │ Timer │ │ AppState │ │ │
│ │ │ Inactivité │ │ Listener │ │ │
│ │ └──────┬──────┘ └──────┬───────┘ │ │
│ │ │ │ │ │
│ │ └───────┬───────────┘ │ │
│ │ ▼ │ │
│ │ ┌──────────────────┐ │ │
│ │ │ performLock() │ │ │
│ │ └────────┬─────────┘ │ │
│ │ ▼ │ │
│ │ ┌──────────────────┐ │ │
│ │ │ clearSensitive │ │ │
│ │ │ Cache() │ │ │
│ │ └────────┬─────────┘ │ │
│ │ ▼ │ │
│ │ ┌──────────────────┐ │ │
│ │ │ useSecurityStore │ │ │
│ │ │ .lock() │ │ │
│ │ └──────────────────┘ │ │
│ └────────────────────────────────────────────────────────┘ │
│ │
│ ┌────────────────────────────────────────────────────────┐ │
│ │ LockScreen Overlay │ │
│ │ (affiché quand isLocked === true) │ │
│ └────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
Composants¶
1. Constants (src/constants/security.ts)¶
Définit les constantes de sécurité :
// Options de délai disponibles
export type AutoLockTimeout = 30 | 60 | 120 | 300 | 600; // secondes
// Configuration par défaut
export const SECURITY_DEFAULTS = {
AUTO_LOCK_TIMEOUT: 60, // 1 minute
LOCK_ON_BACKGROUND: true, // Verrouiller immédiatement en background
AUTO_LOCK_ENABLED: true, // Actif par défaut
PIN_LENGTH: 6,
MAX_FAILED_ATTEMPTS: 5,
LOCKOUT_DURATION_MS: 300000, // 5 minutes
};
2. Security Store (src/store/useSecurityStore.ts)¶
Store Zustand persisté avec expo-secure-store :
interface SecurityState {
autoLockEnabled: boolean;
autoLockTimeout: AutoLockTimeout;
lockOnBackground: boolean;
isLocked: boolean;
lastActivityTimestamp: number | null;
// Actions
setAutoLockEnabled(enabled: boolean): Promise<void>;
setAutoLockTimeout(timeout: AutoLockTimeout): Promise<void>;
setLockOnBackground(enabled: boolean): Promise<void>;
lock(): void;
unlock(): void;
hydrate(): Promise<void>;
}
3. Cache Cleaner (src/services/cacheCleaner.ts)¶
Service d'effacement des données sensibles :
// Efface uniquement les données en mémoire (sur lock)
clearSensitiveCache(): Promise<ClearResult>
- Mot de passe en mémoire (AuthStore)
- Cache du vault (VaultStore)
- Fichiers temporaires
// Efface tout (sur logout)
clearAllOnLogout(): Promise<ClearResult>
- Tout ce qui précède
- Mot de passe biométrique stocké
- Clés cryptographiques persistées
// Recharge après déverrouillage
rehydrateVaultAfterUnlock(): Promise<RehydrateResult>
4. Auto-Lock Hook (src/hooks/useAutoLock.ts)¶
Hook principal orchestrant le verrouillage :
useAutoLock(options?: {
disabled?: boolean;
onBeforeLock?: () => void;
onAfterLock?: () => void;
}): {
isLocked: boolean;
timeRemainingSeconds: number;
handleTouch: () => void; // Reset le timer
handleScroll: () => void; // Reset le timer
resetTimer: () => void;
lockNow: () => Promise<void>;
unlock: () => void;
}
5. Composants UI¶
PinInput (src/components/security/PinInput.tsx)¶
- Clavier numérique personnalisé
- Animation shake sur erreur
- Support biométrie optionnel
- Accessibilité complète
AutoLockPicker (src/components/security/AutoLockPicker.tsx)¶
- Sélection du délai d'inactivité
- Liste des options avec indicateur de sélection
LockScreen (src/screens/security/LockScreen.tsx)¶
- Écran de verrouillage complet
- Saisie mot de passe
- Bouton biométrie
- Gestion du lockout après X tentatives
SecuritySettingsScreen (src/screens/profile/SecuritySettingsScreen.tsx)¶
- Toggle auto-lock
- Sélection du délai
- Toggle lock on background
- État biométrie
Flux de données¶
Verrouillage automatique¶
1. useAutoLock démarre un timer (setTimeout)
2. À chaque activité utilisateur (touch/scroll), le timer est reset
3. Si le timer expire :
- clearSensitiveCache() est appelé
- useSecurityStore.lock() est appelé
- isLocked devient true
- LockScreen est affiché en overlay
Verrouillage sur background¶
1. AppState change de "active" à "background"
2. Si lockOnBackground === true :
- Verrouillage immédiat (même flux que ci-dessus)
Déverrouillage¶
1. Utilisateur saisit mot de passe / utilise biométrie
2. Vérification du mot de passe
3. Si OK :
- useSecurityStore.unlock()
- rehydrateVaultAfterUnlock()
- Timer redémarre
4. Si KO :
- Compteur tentatives++
- Si max atteint → lockout temporaire
Configuration i18n¶
Trois nouveaux namespaces de traduction :
profile.json: Écran profilsecurity.json: Paramètres de sécuritélock.json: Écran de verrouillage
Tests¶
Les tests unitaires couvrent :
useAutoLock.test.ts: Hook principal (27 tests - timer, AppState, callbacks, cache clearing)useSecurityStore.test.ts: Store de sécuritécacheCleaner.test.ts: Service d'effacementPinInput.test.tsx: Composant de saisie PINAutoLockPicker.test.tsx: Sélection du délai
Navigation¶
Nouvelles routes ajoutées à RootStackParamList :
Accessibles depuis HomeScreen → icône profil.
Considérations de sécurité¶
- Le mot de passe n'est JAMAIS persisté - Stocké uniquement en mémoire et effacé au lock
- Clés dérivées effacées -
K_master,K_files, etc. sont purgées - Données vault en cache effacées - Liste dossiers/documents purgée
- Fichiers temporaires supprimés - Cache filesystem nettoyé
- Pas de persistence de l'état verrouillé - Évite les attaques par manipulation du storage
Fichiers créés¶
src/
├── constants/
│ └── security.ts
├── store/
│ └── useSecurityStore.ts
├── services/
│ └── cacheCleaner.ts
├── hooks/
│ ├── useAutoLock.ts
│ └── useUserActivity.ts
├── components/
│ └── security/
│ ├── PinInput.tsx
│ └── AutoLockPicker.tsx
├── screens/
│ ├── profile/
│ │ ├── ProfileScreen.tsx
│ │ └── SecuritySettingsScreen.tsx
│ └── security/
│ └── LockScreen.tsx
└── i18n/
└── locales/
├── fr/
│ ├── profile.json
│ ├── security.json
│ └── lock.json
└── en/
├── profile.json
├── security.json
└── lock.json
__tests__/
├── store/
│ └── useSecurityStore.test.ts
├── components/
│ └── security/
│ └── PinInput.test.tsx
└── services/
└── cacheCleaner.test.ts
Fichiers modifiés¶
src/navigation/AppNavigator.tsx: Intégration du lock overlaysrc/i18n/index.ts: Ajout des namespaces profile, security, locksrc/i18n/locales/*/navigation.json: Ajout des clés profile/securitySettings
Utilisation¶
// Dans AppNavigator ou tout composant racine
function AppNavigator() {
const { isLocked, handleTouch } = useAutoLock();
const { hydrate, _hasHydrated } = useSecurityStore();
useEffect(() => {
if (!_hasHydrated) hydrate();
}, []);
return (
<View onTouchStart={handleTouch}>
<Stack.Navigator>
{/* ... routes ... */}
</Stack.Navigator>
{isLocked && (
<View style={StyleSheet.absoluteFillObject}>
<LockScreen />
</View>
)}
</View>
);
}