fix: GIF CSP + edit history HTML rendering + unhandled rejection cleanup
- nginx (LXC 106, live): added https://*.giphy.com to connect-src CSP — browser was blocking fetch() to media2.giphy.com CDN with CSP violation - EditHistoryModal: render formatted_body as sanitized HTML (via html-react-parser + sanitizeCustomHtml) with linkification for plain text, matching how messages render in the timeline - useAsyncCallback + ThumbnailContent + ImageContent + VideoContent + ClientConfigLoader: use .catch(() => undefined) instead of void to silence unhandled promise rejections from fire-and-forget useEffect calls — errors already captured in AsyncState.Error for UI display Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,4 +1,6 @@
|
||||
import React, { useCallback, useEffect } from 'react';
|
||||
import React, { ReactNode, useCallback, useEffect } from 'react';
|
||||
import parse from 'html-react-parser';
|
||||
import Linkify from 'linkify-react';
|
||||
import FocusTrap from 'focus-trap-react';
|
||||
import {
|
||||
Box,
|
||||
@@ -18,6 +20,8 @@ import {
|
||||
import { MatrixEvent, Room } from 'matrix-js-sdk';
|
||||
import { useMatrixClient } from '../../../hooks/useMatrixClient';
|
||||
import { stopPropagation } from '../../../utils/keyboard';
|
||||
import { sanitizeCustomHtml } from '../../../utils/sanitize';
|
||||
import { LINKIFY_OPTS } from '../../../plugins/react-custom-html-parser';
|
||||
import { AsyncStatus, useAsyncCallback } from '../../../hooks/useAsyncCallback';
|
||||
import { timeDayMonYear, timeHourMinute } from '../../../utils/time';
|
||||
import { useSetting } from '../../../state/hooks/settings';
|
||||
@@ -52,17 +56,24 @@ function isRawEditEvent(raw: unknown): raw is RawEditEvent {
|
||||
return typeof r.event_id === 'string' && typeof r.origin_server_ts === 'number';
|
||||
}
|
||||
|
||||
function getVersionBody(evt: MatrixEvent): string {
|
||||
function getVersionContent(evt: MatrixEvent): ReactNode {
|
||||
const content = evt.getContent();
|
||||
const newContent = content['m.new_content'] as Record<string, unknown> | undefined;
|
||||
const source = newContent ?? content;
|
||||
|
||||
const format = source.format;
|
||||
const formattedBody = source.formatted_body;
|
||||
if (typeof formattedBody === 'string') {
|
||||
return formattedBody.replace(/<[^>]+>/g, '').trim() || '(no text)';
|
||||
if (
|
||||
format === 'org.matrix.custom.html' &&
|
||||
typeof formattedBody === 'string' &&
|
||||
formattedBody.trim()
|
||||
) {
|
||||
return parse(sanitizeCustomHtml(formattedBody));
|
||||
}
|
||||
|
||||
const body = source.body;
|
||||
return typeof body === 'string' ? body : '(no text)';
|
||||
const text = typeof body === 'string' ? body : '(no text)';
|
||||
return <Linkify options={LINKIFY_OPTS}>{text}</Linkify>;
|
||||
}
|
||||
|
||||
export function EditHistoryModal({ room, mEvent, onClose }: EditHistoryModalProps) {
|
||||
@@ -106,7 +117,7 @@ export function EditHistoryModal({ room, mEvent, onClose }: EditHistoryModalProp
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
void fetchHistory().catch(() => undefined);
|
||||
fetchHistory().catch(() => undefined);
|
||||
}, [fetchHistory]);
|
||||
|
||||
const formatTs = (ts: number): string => {
|
||||
@@ -115,11 +126,7 @@ export function EditHistoryModal({ room, mEvent, onClose }: EditHistoryModalProp
|
||||
return `${date} at ${time}`;
|
||||
};
|
||||
|
||||
const originalBody = (() => {
|
||||
const content = mEvent.getContent();
|
||||
const body = content.body;
|
||||
return typeof body === 'string' ? body : '(no text)';
|
||||
})();
|
||||
const originalContent = getVersionContent(mEvent);
|
||||
|
||||
const originalTs = mEvent.getTs();
|
||||
|
||||
@@ -189,7 +196,7 @@ export function EditHistoryModal({ room, mEvent, onClose }: EditHistoryModalProp
|
||||
</Text>
|
||||
</Box>
|
||||
<Text size="T300" style={{ whiteSpace: 'pre-wrap', wordBreak: 'break-word' }}>
|
||||
{originalBody}
|
||||
{originalContent}
|
||||
</Text>
|
||||
</Box>
|
||||
|
||||
@@ -209,7 +216,7 @@ export function EditHistoryModal({ room, mEvent, onClose }: EditHistoryModalProp
|
||||
size="T300"
|
||||
style={{ whiteSpace: 'pre-wrap', wordBreak: 'break-word' }}
|
||||
>
|
||||
{getVersionBody(editEvt)}
|
||||
{getVersionContent(editEvt)}
|
||||
</Text>
|
||||
</Box>
|
||||
))}
|
||||
|
||||
Reference in New Issue
Block a user