ncantu 695aff4f85 api-relay DB migration, auth, service-login-verify PersistentNonceCache, UserWallet crypto settings
**Motivations:**
- Migrer api-relay vers base de données SQLite (production)
- Ajouter authentification API key pour endpoints POST (protection abus)
- PersistentNonceCache pour service-login-verify (IndexedDB/localStorage)
- Écran paramètres crypto avancés UserWallet
- Documenter options non implémentées (Merkle, évolutions api-relay)

**Root causes:**
- N/A (évolutions + correctifs)

**Correctifs:**
- N/A

**Evolutions:**
- api-relay: DatabaseStorageService (SQLite), StorageAdapter (compatibilité), ApiKeyService (génération/validation), auth middleware (Bearer/X-API-Key), endpoints admin (/admin/api-keys), migration script (migrate-to-db.ts), suppression saveToDisk périodique
- service-login-verify: PersistentNonceCache (IndexedDB avec fallback localStorage, TTL, cleanup), export dans index
- userwallet: CryptoSettingsScreen (hashAlgorithm, jsonCanonizationStrict, ecdhCurve, nonceTtlMs, timestampWindowMs), modifications LoginScreen, LoginForm, CreateIdentityScreen, ImportIdentityScreen, DataExportImportScreen, PairingDisplayScreen, RelaySettingsScreen, ServiceListScreen, MemberSelectionScreen, GlobalActionBar
- features: OPTIONS_NON_IMPLENTEES.md (analyse Merkle trees, évolutions api-relay)

**Pages affectées:**
- api-relay: package.json, index.ts, middleware/auth.ts, services/database.ts, services/storageAdapter.ts, services/apiKeyService.ts, scripts/migrate-to-db.ts
- service-login-verify: persistentNonceCache.ts, index.ts, tsconfig.json, dist/
- userwallet: App, CryptoSettingsScreen, LoginScreen, LoginForm, CreateIdentityScreen, ImportIdentityScreen, DataExportImportScreen, PairingDisplayScreen, RelaySettingsScreen, ServiceListScreen, MemberSelectionScreen, GlobalActionBar
- features: OPTIONS_NON_IMPLENTEES.md
- data: sync-utxos.log
2026-01-28 07:36:01 +01:00

92 lines
3.3 KiB
TypeScript

import {
BrowserRouter,
Routes,
Route,
useLocation,
} from 'react-router-dom';
import { PairingWordsProvider } from './contexts/PairingWordsContext';
import { GlobalActionBar } from './components/GlobalActionBar';
import { HomeScreen } from './components/HomeScreen';
import { CreateIdentityScreen } from './components/CreateIdentityScreen';
import { ImportIdentityScreen } from './components/ImportIdentityScreen';
import { PairingDisplayScreen } from './components/PairingDisplayScreen';
import { RelaySettingsScreen } from './components/RelaySettingsScreen';
import { PairManagementScreen } from './components/PairManagementScreen';
import { SyncScreen } from './components/SyncScreen';
import { LoginScreen } from './components/LoginScreen';
import { LoginSignScreen } from './components/LoginSignScreen';
import { ServiceListScreen } from './components/ServiceListScreen';
import { MemberSelectionScreen } from './components/MemberSelectionScreen';
import { DiagnosticScreen } from './components/DiagnosticScreen';
import { ServiceSyncScreen } from './components/ServiceSyncScreen';
import { CryptoSettingsScreen } from './components/CryptoSettingsScreen';
import { DataExportImportScreen } from './components/DataExportImportScreen';
import { UnlockScreen } from './components/UnlockScreen';
import { useChannel } from './hooks/useChannel';
import { useIdentity } from './hooks/useIdentity';
import './index.css';
const PAIRING_DISPLAY_PATH = '/pairing-display';
function usePairingDisplayBypass(): boolean {
const location = useLocation();
return location.pathname === PAIRING_DISPLAY_PATH;
}
function AppContent(): JSX.Element {
useChannel();
return (
<Routes>
<Route path="/" element={<HomeScreen />} />
<Route path="/create-identity" element={<CreateIdentityScreen />} />
<Route path="/import-identity" element={<ImportIdentityScreen />} />
<Route path="/login" element={<LoginScreen />} />
<Route path="/login-sign" element={<LoginSignScreen />} />
<Route path="/manage-pairs" element={<PairManagementScreen />} />
<Route path="/relay-settings" element={<RelaySettingsScreen />} />
<Route path="/sync" element={<SyncScreen />} />
<Route path="/services" element={<ServiceListScreen />} />
<Route path="/select-member" element={<MemberSelectionScreen />} />
<Route path="/diagnostic" element={<DiagnosticScreen />} />
<Route path="/service-sync" element={<ServiceSyncScreen />} />
<Route path="/crypto-settings" element={<CryptoSettingsScreen />} />
<Route path="/data" element={<DataExportImportScreen />} />
</Routes>
);
}
function AppGate(): JSX.Element {
const { identity, isProtected, isUnlocked, isLoading } = useIdentity();
if (isLoading) {
return (
<div role="status" aria-live="polite" aria-busy="true">
Chargement
</div>
);
}
if (identity !== null && isProtected && !isUnlocked) {
return <UnlockScreen />;
}
return <AppContent />;
}
function AppRoot(): JSX.Element {
const bypass = usePairingDisplayBypass();
return (
<PairingWordsProvider>
<GlobalActionBar />
{bypass ? <PairingDisplayScreen /> : <AppGate />}
</PairingWordsProvider>
);
}
export function App(): JSX.Element {
return (
<BrowserRouter>
<AppRoot />
</BrowserRouter>
);
}