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
+7
View File
@@ -24,6 +24,13 @@ export async function partnerPub(partnerId: number): Promise<string> {
// Drop a partner's cached public key + derived conversation key and refetch. Called after a decrypt
// fails, which can mean the partner reset their passphrase and published a NEW keypair; refetching
// lets this device both read their new messages and encrypt future ones under the current key.
//
// KNOWN LIMITATION: this refresh is wired only to the DECRYPT path. If you send a partner a message
// AFTER they rotated their key but BEFORE any of their messages arrived to trigger a refresh, that
// one send is encrypted under the stale cached key and is undecryptable for them (subsequent sends
// self-heal once an incoming message refreshes the cache). Accepted for now — same cross-user
// staleness envelope as the multi-device note in useKeyState; a fuller fix needs a key TTL / a
// send-time freshness check, which is out of the current no-forward-secrecy scope.
export async function refreshPartnerPub(partnerId: number): Promise<string> {
pubCache.delete(partnerId);
forgetConv(partnerId);