fix(chat): auto-rotate stuck conv-keys on chat open (receive-side recovery)

This commit is contained in:
byGalax
2026-05-18 14:03:35 +02:00
parent 787437c3f1
commit 3d959aaadf
2 changed files with 19 additions and 3 deletions
Binary file not shown.
@@ -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')