# Password Manager — Architecture éclair Desktop password vault Windows. Exe Delphi FMX embarquant WebView2 qui charge un frontend HTML/JS via Indy HTTP loopback (127.0.0.1:8765). 100 % offline, multi-utilisateur, chiffrement client-side (AES-GCM, clé dérivée PBKDF2-SHA256 600 k iter). ## Stack - **Backend** : Delphi 12, FMX, TMS FNC WebBrowser (Edge WebView2) - **HTTP** : Indy `TIdHTTPServer` bindé 127.0.0.1 only - **DB** : SQLite via FireDAC (`vault.db`, gitignored) - **Frontend** : vanilla JS + CSS, pas de framework (`js/app.js` monofile ~4000 lignes) ## Build pipeline (CRITIQUE) Toute modif `index.html` / `js/` / `css/` nécessite : 1. `delphi-backend\assets\BuildAssets.cmd` → régénère `assets.res` 2. Build Delphi (F9 ou MSBuild `PMServer.dproj`) Sans étape 1, l'exe embarque l'ancienne version des assets — le bug le plus courant après modif frontend. ### Blocs embarqués brouillés Depuis 2026-09-05, `BuildAssets.ps1` **brouille** chaque fichier avant de le donner à `brcc32` (dans `assets/obf/`, gitignoré ; les sources en clair ne sont jamais touchées) et `PM.EmbeddedAssets.DeobfuscateAsset` le débrouille au moment de servir. ``` bloc i = SHA256( secret(32) || nom de ressource UTF-8 || i en 4 octets LE ) sortie = XOR( magie 'PMA1' + contenu du fichier ) ``` - **C'est de l'opacité, pas du secret.** La clé est dans l'exe : qui tient le binaire retrouve le texte. Ce que ça supprime, c'est l'onglet *Image* de Process Explorer et n'importe quel `strings` — le frontend n'est plus lisible en survolant le fichier. L'onglet *Memory*, un débogueur ou la réponse HTTP le rendent toujours : WebView2 doit recevoir du JavaScript en clair pour l'exécuter. D'où **XOR plutôt qu'AES** : à sécurité rigoureusement égale (nulle, contre qui a l'exe), dix lignes au lieu d'un appel CNG, et surtout aucune force affichée qu'on n'a pas. - Le flux dépend du **nom de la ressource** : tous les fichiers commencent par les mêmes lignes de commentaire, un flux commun rendrait ces préfixes identiques d'un bloc à l'autre. - **La magie `PMA1` préfixe le clair.** Sans elle, une clé qui a dérivé entre le script et l'exe servirait du binaire au navigateur : écran blanc, aucune trace. Avec elle, `TryServeEmbedded` refuse. **Symptôme à reconnaître : `/index.html` en 404 juste après avoir touché `AssetObfSecret` d'un seul côté** — les deux constantes (`$ObfSecret` / `AssetObfSecret`) doivent rester identiques. - **Coût mesuré : 2,45 ms** pour les 820 Ko embarqués (AES chronométré comme borne haute ; le XOR est plus rapide), une seule fois au chargement de la page. À comparer aux ~650 ms d'Argon2id au déverrouillage. - **Les tests frontend ne sont pas concernés** : ils lisent les `.js` sur le disque, jamais le `.res`. - Vérifié en comparant les flux des deux côtés bloc par bloc (ils doivent être identiques au bit près) puis en refaisant l'aller-retour sur `app.js`, `index.html` et `style.css`. ### Découpage frontend (§3.1, en cours) `app.js` (~12k lignes) est **progressivement scindé** en fichiers classic-script chargés **dans l'ordre** via des `