From 8905599214f2dd7e364521d9c6d5dd64e3e73789 Mon Sep 17 00:00:00 2001 From: r-zakarya <82443831+r-zakarya@users.noreply.github.com> Date: Fri, 28 Aug 2026 23:33:21 +0100 Subject: [PATCH] fix(sync): la synchronisation dupliquait l'historique des mots de passe L'instantane transporte le mot de passe EN CLAIR, et encryptImportEntry le re-chiffre avec un IV neuf : le chiffre differe donc toujours, meme quand le mot de passe n'a pas bouge. Or le serveur decide d'ecrire une version dans l'historique en comparant les chiffres (`encrypted_password <> :newenc`) - il voyait une difference la ou il n'y en avait aucune, et chaque synchronisation qui redescendait une entree y deposait un doublon date du jour. L'historique montrait la meme valeur deux fois, a des jours d'ecart. Le serveur ne peut pas trancher, il ne voit que du chiffre. Seul le client connait les deux clairs : il compare, et rend le chiffre d'origine quand ils sont egaux - ce que le commentaire du handler appelle deja "JS reuses originalEncrypted bit-for-bit". Trouve en deroulant la serie H sur le telephone. Co-Authored-By: Claude Opus 5 --- js/app.sync.js | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/js/app.sync.js b/js/app.sync.js index 6fbdc4a..8c9e020 100644 --- a/js/app.sync.js +++ b/js/app.sync.js @@ -540,6 +540,29 @@ async function applyRemoteSnapshot(remote) { if (!remoteWins) continue; try { const enc = await encryptImportEntry(r); + // LE MOT DE PASSE INCHANGÉ GARDE SON CHIFFRÉ, BIT POUR BIT. + // + // L'instantané transporte le clair, et encryptImportEntry le + // re-chiffre avec un IV neuf : le chiffré diffère donc TOUJOURS, + // même quand le mot de passe n'a pas bougé. Or le serveur décide + // d'écrire une version dans l'historique en comparant les + // chiffrés (`encrypted_password <> :newenc`) — il voyait une + // différence là où il n'y en avait aucune, et chaque + // synchronisation qui redescendait une entrée y déposait un + // doublon daté du jour. + // + // Le serveur ne peut pas trancher : il ne voit que du chiffré. + // Seul le client connaît les deux clairs. On compare ici, et on + // rend son chiffré d'origine quand ils sont égaux — ce que le + // commentaire du handler appelle déjà « JS reuses + // originalEncrypted bit-for-bit ». + if (local.encrypted_password && local.iv) { + const before = await decryptPwd(local.encrypted_password, local.iv); + if (before !== '[ERROR]' && before === (r.password || '')) { + enc.encrypted_password = local.encrypted_password; + enc.iv = local.iv; + } + } // PUT keeps the existing id but accepts the encrypted blobs. // template + uuid not touched here (server preserves columns // when fields aren't in body — uuid is immutable anyway).