fix(messages): re-review — degrade gracefully when partner has no key

The decrypt-pass refactor hoisted partnerPub() above the loop and outside the
try, so a keyless partner (one who reset and hasn't re-set-up) or a fetch error
rejected the whole pass unhandled (setPlain never ran). Fetch the key lazily
inside the try and once, so an empty thread never fetches and a fetch failure
degrades to "can't decrypt" as before. Document the send-path staleness (a first
proactive send after a partner's key rotation uses the stale cached key) as a
known limitation alongside refreshPartnerPub.
This commit is contained in:
2026-07-23 03:21:44 +02:00
parent 26e6562921
commit dce191f1c0
2 changed files with 12 additions and 1 deletions
+5 -1
View File
@@ -49,11 +49,15 @@ export default function ChatThread({
let cancelled = false;
(async () => {
const out: Record<number, string> = {};
let pub = await partnerPub(partnerId);
// Fetch the partner key lazily inside the try (only when there's a ciphertext message) and
// once — so an empty thread never fetches, and a fetch failure (e.g. a partner who reset and
// hasn't re-set-up, so has no key) degrades to "can't decrypt" instead of rejecting the pass.
let pub: string | null = null;
let refreshed = false;
for (const m of q.data?.items ?? []) {
if (!m.ciphertext || !m.iv) continue;
try {
if (!pub) pub = await partnerPub(partnerId);
out[m.id] = await e2ee.decryptFrom(partnerId, pub, m.ciphertext, m.iv);
} catch {
// A decrypt failure can mean the partner rotated their keypair (a passphrase reset), so