Fix device verification UX: show request card, enable cross-user SAS

- RenderMessageContent: add case for m.key.verification.request msgtype
  so it renders an informational card instead of "Unsupported message"
- MsgTypeRenderers/FallbackContent: add VerificationRequestContent and
  MessageVerificationRequestContent components (lock icon + instructional text)
- DeviceVerification: remove isSelfVerification guard from
  ReceiveSelfDeviceVerification so cross-user verification requests also
  trigger the SAS emoji dialog (was silently dropped before)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-05-23 11:15:49 -04:00
parent 37e68e906b
commit 8740752aec
4 changed files with 23 additions and 4 deletions
@@ -316,9 +316,5 @@ export function ReceiveSelfDeviceVerification() {
if (!request) return null; if (!request) return null;
if (!request.isSelfVerification) {
return null;
}
return <DeviceVerification request={request} onExit={handleExit} />; return <DeviceVerification request={request} onExit={handleExit} />;
} }
@@ -22,6 +22,7 @@ import {
RenderBody, RenderBody,
ThumbnailContent, ThumbnailContent,
UnsupportedContent, UnsupportedContent,
VerificationRequestContent,
VideoContent, VideoContent,
} from './message'; } from './message';
import { UrlPreviewCard, UrlPreviewHolder } from './url-preview'; import { UrlPreviewCard, UrlPreviewHolder } from './url-preview';
@@ -264,5 +265,9 @@ export function RenderMessageContent({
return <MBadEncrypted />; return <MBadEncrypted />;
} }
if (msgType === 'm.key.verification.request') {
return <VerificationRequestContent />;
}
return <UnsupportedContent />; return <UnsupportedContent />;
} }
@@ -10,6 +10,7 @@ import {
MessageDeletedContent, MessageDeletedContent,
MessageEditedContent, MessageEditedContent,
MessageUnsupportedContent, MessageUnsupportedContent,
MessageVerificationRequestContent,
} from './content'; } from './content';
import { import {
IAudioContent, IAudioContent,
@@ -57,6 +58,14 @@ export function UnsupportedContent() {
); );
} }
export function VerificationRequestContent() {
return (
<Text>
<MessageVerificationRequestContent />
</Text>
);
}
export function BrokenContent() { export function BrokenContent() {
return ( return (
<Text> <Text>
@@ -57,6 +57,15 @@ export const MessageEmptyContent = as<'div', { children?: never }>(({ ...props }
</Box> </Box>
)); ));
export const MessageVerificationRequestContent = as<'div', { children?: never }>(
({ ...props }, ref) => (
<Box as="span" alignItems="Center" gap="100" style={warningStyle} {...props} ref={ref}>
<Icon size="50" src={Icons.Lock} />
<i>Device verification request open another Matrix client to accept</i>
</Box>
),
);
export const MessageEditedContent = as<'span', { children?: never }>(({ ...props }, ref) => ( export const MessageEditedContent = as<'span', { children?: never }>(({ ...props }, ref) => (
<Text as="span" size="T200" priority="300" {...props} ref={ref}> <Text as="span" size="T200" priority="300" {...props} ref={ref}>
{' (edited)'} {' (edited)'}