feat(entries): encrypt template at rest, guided tour, import fixes, cleanup
Batched session work sharing app.js / index.html / Entries.pas, so it can't
split cleanly without interactive hunk staging.
- feat: encrypt `template` metadata at rest (template_enc/iv, added to
ENCRYPTED_META_FIELDS). withEncryptedMeta skips an absent template key so
partial re-ships (add-tag, move-to-folder) don't wipe it via LHasTemplate.
Cleartext column kept as migration fallback. +3 unit tests.
- feat: first-run guided tour ("How it works") — spotlight + bubble, no GIFs,
re-launchable from Settings, seen-flag in DPAPI prefs.
- fix(import): preserve original created_at on restore (was stamped to import
time); restore entry icons on overwrite (PUT ignores icon_b64).
- fix(settings): correct clipboard-privacy copy (already excluded from Win+V);
PIN text 4-6 -> 4-12; reorder Set-PIN above unlock-method; move tray/startup
toggles to General; dedicated backup-password button + warning status; tab icons.
- chore: remove dead legacy monolith (app-legacy.js, index-legacy.html,
style-legacy.css) + unused passkeyBtn stub.
- docs: full-source review (CODE_AUDIT 6b), template + favorite/pinned notes.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
+58
-3
@@ -86,8 +86,10 @@ Documenté mais à rappeler pour un futur modèle de menace :
|
||||
|
||||
- `entry_attachments` : `filename`, `mime`, `size_bytes` **non chiffrés**
|
||||
- `users.avatar_b64` : image **non chiffrée** (cosmétique, assumé)
|
||||
- `vault_entries` : ~~`username`, `site`, `title`, `tags`~~ **chiffrés
|
||||
(2026-07-09)** ; `folder`, `kind`, `template` encore en clair.
|
||||
- `vault_entries` : ~~`username`, `site`, `title`, `tags`, `template`~~ **chiffrés
|
||||
(username/site/title/tags 2026-07-09 ; template 2026-07-11)** ; `folder`,
|
||||
`kind` restent en clair (folder = requête serveur de réassignation ;
|
||||
kind = 2 valeurs, ~0 entropie).
|
||||
|
||||
**`username` + `site` + `title` + `tags` chiffrés au repos (✅ 2026-07-09)** :
|
||||
colonnes `<f>_enc/<f>_iv` (AES-GCM sous la clé du vault). Clé de l'approche :
|
||||
@@ -102,7 +104,15 @@ champs (username/site/title/tags) pour ce compte, `_enc` remplies, affichage/
|
||||
recherche/favicons OK. La migration est **par utilisateur** (tourne au unlock
|
||||
sur les entries du compte connecté) — un compte non connecté garde son clair
|
||||
jusqu'à sa prochaine connexion (comportement normal, pas une régression).
|
||||
Résiduel : `folder`, `kind`, `template`, métadonnées d'attachments, nombre de
|
||||
**`template` chiffré au repos (✅ 2026-07-11)** : même pattern
|
||||
(`template_enc`/`template_iv`, ajouté à `ENCRYPTED_META_FIELDS`). Colonne clair
|
||||
`template` gardée comme fallback de migration (`decryptEntryMeta` préfère `_enc`,
|
||||
retombe sur le clair). Guard dans `withEncryptedMeta` : les re-ships partiels
|
||||
(add-tag, move-to-folder) omettent `template` → le serveur le préserve via
|
||||
`LHasTemplate` (clé absente), pas de wipe. 3 tests unitaires.
|
||||
**Pièces jointes : le contenu est déjà chiffré** (AES-GCM, `encryptBlobBytes`) ;
|
||||
seuls `filename`/`mime`/`size_bytes` restent en clair (pour lister sans tout
|
||||
déchiffrer). Résiduel : `folder`, `kind`, métadonnées d'attachments, nombre de
|
||||
lignes, timestamps.
|
||||
|
||||
### 1.4 ✅ Sync password faible — corrigé (2026-07-09)
|
||||
@@ -353,6 +363,51 @@ cf. la checklist "Entry payload" de CLAUDE.md).
|
||||
|
||||
---
|
||||
|
||||
## 6b. Revue source complète (2026-07-11) — noté, NON corrigé
|
||||
|
||||
Passe manuelle JS + Delphi + HTML + CSS à la recherche d'illogismes, bugs
|
||||
invisibles, perf et code mort. Rien de bloquant ; classé par type.
|
||||
|
||||
### Code mort / nettoyage
|
||||
- ~~**`js/app-legacy.js` (1549 lignes)** + `index-legacy.html` + `css/style-legacy.css`~~
|
||||
— ✅ **supprimés (2026-07-11)**. Ancien monolithe pré-découpage §3.1 (le trio
|
||||
HTML+JS+CSS). Ni embarqués (absents du whitelist `BuildAssets.ps1`) ni
|
||||
référencés sauf entre eux. 68/68 tests OK après suppression.
|
||||
- **`#passkeyBtn` (index.html:134)** — bouton `display:none` jamais câblé en JS.
|
||||
Stub passkey/WebAuthn abandonné. → supprimer le markup (ou implémenter).
|
||||
- ~~**`#passkeyBtn`** (index.html:134)~~ — ✅ **supprimé (2026-07-11)**.
|
||||
Bouton `display:none` jamais câblé (stub passkey/WebAuthn abandonné).
|
||||
- **IDs inutilisés** `#reauthTitle`, `#historyTitle`, `#reauthConfirm` —
|
||||
**laissés volontairement** : un `id` non référencé ne coûte rien et pourrait
|
||||
servir à un titre dynamique plus tard. Les retirer = churn à bénéfice nul.
|
||||
|
||||
### Performance
|
||||
- **Search sans debounce** (app.js:8515) — **won't-do (YAGNI, 2026-07-11)**.
|
||||
Pour < 500 entries le render est instantané ; un debounce ajouterait de la
|
||||
latence au retour de recherche (régression du feel) pour un gros vault
|
||||
hypothétique. À revisiter seulement si un profiler montre du lag réel.
|
||||
- **N+1 attachments séquentiel** (buildSyncSnapshot, auto-backup, rotation) —
|
||||
**déféré (2026-07-11)** : paralléliser touche le chemin sync/rotation (zone
|
||||
la plus délicate) pour un gain spéculatif ; < 1 s sur loopback à < 500 entries.
|
||||
Trigger pour revisiter : un backup/sync perceptiblement lent.
|
||||
|
||||
### Design / cohérence (tranché)
|
||||
- **`favorite` / `pinned` device-local** — ✅ **décidé device-local (2026-07-11)**,
|
||||
comme l'avatar. Absents de `buildSyncSnapshot` → leurs toggles serveur
|
||||
(Entries.pas:804 favorite, 851 pin) ne bumpent volontairement PAS `updated_at`.
|
||||
Asymétrie assumée (favorite est dans backup/export mais pas sync). Documenté
|
||||
dans CLAUDE.md « Settings sync ».
|
||||
|
||||
### Vérifié sain (pour ne pas re-chasser)
|
||||
- `DB.Lock`/`DB.Unlock` **équilibrés** (les écarts au grep étaient des mentions
|
||||
en commentaire, pas des appels).
|
||||
- Aucun `except … end` **muet** côté Delphi (pas de swallow silencieux serveur).
|
||||
- Aucun `==` laxiste suspect en JS ; `setInterval`/`clearInterval` appariés.
|
||||
- Restore d'entry (Entries.pas:759) et set-icône (965) bumpent bien `updated_at`.
|
||||
- Soft-delete (712) ne bump pas mais sort du snapshot live → OK (trash non synced).
|
||||
|
||||
---
|
||||
|
||||
## 7. Verdict
|
||||
|
||||
Pour un usage **personnel, local, mono-utilisateur**, le produit est
|
||||
|
||||
Reference in New Issue
Block a user