6869b7c692
- Sync (WebDAV, auto-merge): UUID + tombstones foundations (server + JS), THTTPClient bridge cmds (get/put/test), runSyncNow engine with pull/merge/push flow, Settings UI, pre-sync backup option. Test connection now treats 404 as OK (snapshot not yet created) and 401/ 403 as auth failure with dedicated toast. - Batch drag-drop: cards + table rows carry checked-set ids (CSV) when dragged from an active selection; folder + trash drop handlers parse and apply in batch via new moveEntriesToFolder helper that preserves TOTP / custom_fields / kind in the full PUT payload. - Clean shutdown: WM_QUERYENDSESSION / WM_ENDSESSION captured in the bridge message-only window; FormCloseQuery bypasses the tray-minimize intercept on system shutdown / restart / logoff so FireDAC closes the SQLite WAL cleanly instead of leaving -shm / -wal residue after a force-kill. - Center-mode modal: blur+dim backdrop via body::before pseudo-element in editor-position=center, swallows clicks below the panel so the existing outside-click handlers reliably dismiss the slideover / settings panel. - Batch bar state fixes: state.checked cleared before render in moveEntriesToFolder, emptyTrash, and per-card restoreEntry / permanentDelete / deleteEntry so the action bar disappears once the selection is fully processed. - Save-then-discard duplicate fix: soState reset to null before openSlideOver re-opens the freshly saved entry, otherwise the dirty check fired on the soState.id=null → newId switch and a Cancel left the form in new-entry mode (second Save → POST duplicate). - TEST_SYNC.md: end-to-end checklist for validating the WebDAV sync with 2 real instances. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
6.7 KiB
6.7 KiB
Test plan — WebDAV sync (auto-merge)
Server : wsgidav --host=127.0.0.1 --port=8080 --root=E:\webdav-test --auth=anonymous
URL Settings : http://127.0.0.1:8080/vault-sync.json
User/pwd Settings : vides (anonymous)
Sync password : choisir une fois, identique sur les 2 devices
0. Setup deux devices RÉELLEMENT séparés
Le sync est par-vault. Un même vault.db avec 2 comptes user ≠ 2 devices.
- Device A : exe actuel
Z:\password-manager\delphi-backend\Win32\Debug\PMServer.exe - Device B :
- Copier uniquement le
.exedansD:\PMServer-B\(assets.res est déjà embarqué dedans) - Lancer → crée un user
userBavec un nouveau master pw vault.dbde B est créé à côté de l'exe B (séparé de A)
- Copier uniquement le
- Vérifier les 2 lancent sur des ports différents (chacun écrit son port au boot dans le log)
1. Connexion server
- wsgidav tourne (logs visibles, "Serving on http://127.0.0.1:8080")
- A : Settings → Sync → URL + Set sync password (
testsync) → Test connection → toastConnection OK · snapshot not created yet - B : idem mais même sync password
testsync→ Test connection → toast OK aussi
2. Premier push (A vide → server)
- A : créer 3 entries distinctes (
gmail,bank,githubpar ex.) + 1 note + 1 folder customWork - A : Sync now → wsgidav log
GET 404+PUT 201→ toastSync complete — 0 added · 0 updated · 0 deleted - Vérifier
Get-ChildItem E:\webdav-test→vault-sync.jsonexiste (~quelques KB)
3. Premier pull (B vide ← server)
- B : Sync now → wsgidav log
GET 200+PUT 201→ toastSync complete — 5 added · 0 updated · 0 deleted(3 logins + note + ??? folder ne compte pas dansadded) - B : vérifier que les 3 entries + la note sont visibles dans la grille
- B : ouvrir
gmail→ password déchiffrable - B : ouvrir la note → texte lisible
- B : sidebar Folders →
Workprésent avec sa couleur+icône
4. Auto-merge ajout des deux côtés
- A : créer entry
slack - B : créer entry
discord - A : Sync now → toast
1 added(récupèrediscord) - B : Sync now → toast
1 added(récupèreslack) - Les deux devices ont maintenant 5 + 2 = 7 entries
5. Last-write-wins
- A : éditer
gmail→ changer username enuser-from-A→ Save - B (sans sync entre temps) : éditer
gmail→ changer username enuser-from-B→ Save (B aupdated_atplus récent) - A : Sync now → toast
0 added · 1 updated · 0 deleted→gmail.usernamedevientuser-from-B - Inverse pour confirmer : édit A puis édit B puis sync B en premier → B garde sa version (rien à update côté B), puis sync A → A bascule sur B
6. Tombstones (delete propagation)
- A : delete
slack(soft) → Trash → Empty trash (hard-delete = tombstone créé) - A : Sync now → push tombstone
- B : Sync now → toast inclut
1 deleted→slackdisparait côté B - Recréer
slackcôté B → Sync now → vérifier qu'il ne ressuscite pas côté A (tombstone réutilisé sauf si nouveau uuid mint → vérifier ce comportement)
7. Custom fields + TOTP préservés
- A : créer entry
awsavec TOTP secret valide + 2 custom fields (access_key,secret_keyis_secret=true) - A : Sync now
- B : Sync now →
awsapparaît - B : ouvrir
aws→ TOTP code visible et tick · les 2 custom fields visibles ·secret_keymasqué (is_secret) - B : éditer un custom field → Save → Sync now
- A : Sync now → modif reflétée
8. Attachments round-trip
- A : ouvrir une entry → Attach file → upload PDF < 1 MB
- A : Sync now (wsgidav log → file size augmente sensiblement)
- B : Sync now → ouvrir la même entry → attachment visible → Download → fichier décrypté identique
9. Pre-sync backup
- A : Settings → cocher "Create a local backup before each sync"
- A : Sync now →
Get-ChildItem "C:\Users\zakar\Desktop\backup test\vault-presync-*.json"→ fichier daté du jour existe - Tester restore : Import vault → choisir le
.json→ tapetestsync→ entries restaurées
10. Auth WebDAV (optionnel)
Si tu veux tester avec un vrai user/pwd (au lieu d'anonymous) :
wsgidav --host=127.0.0.1 --port=8080 --root=E:\webdav-test ^
--auth=basic --user-mapping={"/":{"alice":{"password":"s3cret","roles":["editor"]}}}
- A : Username
alice+ Passwords3cret→ Test connection OK - A : vider user/pwd → Test connection → toast
Auth failed (401)
11. Erreurs réseau
- Tuer wsgidav (Ctrl+C dans son terminal)
- A : Test connection → toast
Network error: ... - A : Sync now → toast
Sync pull failed: ...(pas d'écrasement local) - Relancer wsgidav → re-Sync now → reprend normalement
12. Conflict — édit + delete sur le même entry
- A : delete
github→ hard-delete (Empty trash) → Sync now (push tombstone) - B (sans sync entre) : édite
github(la version locale a unupdated_atplus récent que la deletion) - B : Sync now → comportement attendu = entry deletée (tombstones gagnent toujours sur update — vérifier que c'est bien ça)
13. Vault locked pendant sync
- A : Lock vault
- A : (pas accès Settings — locked) — vérifier qu'il n'y a pas d'auto-sync silencieux qui tenterait quand même
- Unlock → Sync now → fonctionne
14. Master pw rotation + sync
- A : change master password → re-encrypte toutes les entries localement avec nouvelle clé
- A : Sync now → push avec même sync password (encPwd indépendant du master) → toast OK
- B : Sync now → toast
0 added · 0 updated · 0 deleted(les uuids n'ont pas changé, lesupdated_atnon plus pour la plupart)
Critères de réussite
- ✅ Pull récupère systématiquement les entries manquantes (added > 0 quand attendu)
- ✅ Push ne supprime jamais silencieusement de données (sauf via tombstone explicite)
- ✅ Pre-sync backup créé si dossier configuré (sinon skip silencieux, OK)
- ✅ Erreur réseau ou auth → toast clair, pas d'écrasement
- ✅ Sync password divergent → toast
Remote decrypt failed — wrong sync password?+ pas de push - ✅ Tombstones propagent les deletes hard
Gotchas connus
- Tester avec 2 vraies instances séparées, pas 2 users dans la même DB
- Sync password ≠ master password ; doit être identique sur tous les devices
- Pre-sync backup réutilise le dossier auto-backup (pas de dossier dédié actuellement)
- Le snapshot WebDAV contient TOUTES les entries en plaintext sous le sync password — ne pas confondre avec la sécurité par master (qui reste pour les blobs DB locaux)