Files
Password-Manager/TEST_SYNC.md
T
r-zakarya 6869b7c692 feat: WebDAV sync + batch DnD + clean shutdown + center-modal UX bundle
- 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>
2026-06-30 00:32:12 +01:00

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 .exe dans D:\PMServer-B\ (assets.res est déjà embarqué dedans)
    • Lancer → crée un user userB avec un nouveau master pw
    • vault.db de B est créé à côté de l'exe B (séparé de A)
  • 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 → toast Connection 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, github par ex.) + 1 note + 1 folder custom Work
  • A : Sync now → wsgidav log GET 404 + PUT 201 → toast Sync complete — 0 added · 0 updated · 0 deleted
  • Vérifier Get-ChildItem E:\webdav-testvault-sync.json existe (~quelques KB)

3. Premier pull (B vide ← server)

  • B : Sync now → wsgidav log GET 200 + PUT 201 → toast Sync complete — 5 added · 0 updated · 0 deleted (3 logins + note + ??? folder ne compte pas dans added)
  • 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 → Work pré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ère discord)
  • B : Sync now → toast 1 added (récupère slack)
  • Les deux devices ont maintenant 5 + 2 = 7 entries

5. Last-write-wins

  • A : éditer gmail → changer username en user-from-A → Save
  • B (sans sync entre temps) : éditer gmail → changer username en user-from-B → Save (B a updated_at plus récent)
  • A : Sync now → toast 0 added · 1 updated · 0 deletedgmail.username devient user-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 deletedslack disparait côté B
  • Recréer slack cô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 aws avec TOTP secret valide + 2 custom fields (access_key, secret_key is_secret=true)
  • A : Sync now
  • B : Sync now → aws apparaît
  • B : ouvrir aws → TOTP code visible et tick · les 2 custom fields visibles · secret_key masqué (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 → tape testsync → 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 + Password s3cret → 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 un updated_at plus 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é, les updated_at non 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)