From 3d959aaadfa12e4ca013c39b08631e7db768a314 Mon Sep 17 00:00:00 2001 From: byGalax Date: Mon, 18 May 2026 14:03:35 +0200 Subject: [PATCH] fix(chat): auto-rotate stuck conv-keys on chat open (receive-side recovery) --- apps/desktop/src/lib/messageCache.ts | Bin 8015 -> 8545 bytes .../src/lib/useConversationMessages.ts | 22 +++++++++++++++--- 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/apps/desktop/src/lib/messageCache.ts b/apps/desktop/src/lib/messageCache.ts index 5a3fe417ff4a2f753b296cdc611eda0142ad565f..410be6210145007fa0e1be008612bacc52d1c0d4 100644 GIT binary patch delta 543 zcmZ9Ju};G<5QZlPKw|2QPF-jv+A<@Rfq@AjBwirKz9v>2J33!lJcW0FomW8OL3jpu z63#7E5FR2+R=)qc|30t2uHR2b{bB(RwQYgICc*|mht3&)#$ZrWY8kk)QC>T5V8Wz) zwCEW~X@o!!xzqI#Y>%KEmP#jq`1P#D1Z$*dgP+dfKHnl+UqaD3Wj*5)!?Fk8Iak0Y z#}1qpsZm~nT!J>(7`%97IcH{(6){xFkYa>Zadink!<_28uKuH3P-gpc4%!RBib4a% z#=Zt6lM#A@1mioUE3&#`@Y}D$_^4<+h~XNuO6baJ2hG6+;fgR;lWDQ*PinCeHdKhY z-}!*K#nQ5E6!+-T%%DR?vB*2niYSQ`VAFCE66MZXmGU6x;Dfm3Nxq+72c8&3{7sea oa?@f$gjyQh=h_uan)#pdmrFRwtZ81Dtfs@4w}Xq1o6+I%4^e@+MF0Q* delta 16 XcmaFpblz@*oXF(mtQwmm#5lPDJA4JN diff --git a/apps/desktop/src/lib/useConversationMessages.ts b/apps/desktop/src/lib/useConversationMessages.ts index 4ae88bd..c80779d 100644 --- a/apps/desktop/src/lib/useConversationMessages.ts +++ b/apps/desktop/src/lib/useConversationMessages.ts @@ -5,12 +5,12 @@ import { decryptMessages, encryptAndUploadAttachment, fetchConversationMessages, + getOrCreateConvKey, insertAttachmentRow, MAX_ATTACHMENT_BYTES, type MessageWithCipher, sendEncryptedMessage, shareConvKeyToUser, - tryGetConvKey, } from '@chat-app/shared/chat'; import { bytesToPgHex, pgBytesToBytes } from '@chat-app/shared/supabase'; import { useCallback, useEffect, useMemo, useRef, useState } from 'react'; @@ -154,8 +154,24 @@ export function useConversationMessages({ conversationId, userId, deviceId }: Ar // db-types snapshot predates the active_key_version column; cast via unknown. const version = (convRow as unknown as { active_key_version: number }).active_key_version; - const handle = await tryGetConvKey(supabase, conversationId, userId, priv, version); - if (!handle || cancelled) return; + // Use `getOrCreateConvKey` rather than `tryGetConvKey` so that if we + // can't unwrap our bundle at the active version (we lost the device + // key, or the bundle was wiped by the 0.18.0 reset_user_key bug, or + // we only ever had a legacy `recipient_device_id` row), the helper + // auto-rotates the conv-key to version+1 and wraps fresh bundles + // for every member with a `user_keys` row. This is the only path + // that recovers stuck-legacy conversations on the receive side — + // `tryGetConvKey` just returned null and left the chat permanently + // un-decryptable for the locked-out party. + const handle = await getOrCreateConvKey(supabase, conversationId, { + userId, + privateKey: priv, + }); + if (cancelled) return; + // If the helper rotated, all current members with a `user_keys` + // public key were already wrapped by `rotateConvKey`. No further + // sweep work is needed. + if (handle.keyVersion > version) return; const { data: members, error: mErr } = await supabase .from('conversation_members')