fix: GIFs, topic display, formatting toolbar, Copy Link in Invite, support URL

- RoomInput: GIF domain check uses endsWith('.giphy.com') — handles all
  Giphy CDN shards; all silent failure paths now show user-facing error
- RoomProfile: topic plain-text field is now HTML-stripped (no markdown
  syntax visible in header); formatting toolbar (B/I/S/code) above the
  textarea wraps selected text with correct markdown syntax
- InviteUserPrompt: Copy Link button added to dialog header with
  'Copied!' confirmation; removed Copy Link from both three-dot menus
- RoomViewHeader/RoomNavItem: unused copy-link imports removed
- nginx (live): support_page URL updated from lotusguild.org →
  matrix.lotusguild.org

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-06-02 09:55:04 -04:00
parent 16a15efe9b
commit 0bbfe17559
5 changed files with 119 additions and 70 deletions
+16 -13
View File
@@ -538,23 +538,26 @@ export const RoomInput = forwardRef<HTMLDivElement, RoomInputProps>(
async (gifUrl: string, w: number, h: number) => {
setGifUploading(true);
try {
// Only fetch from trusted Giphy CDN domains
const allowed = [
'media.giphy.com',
'i.giphy.com',
'media0.giphy.com',
'media1.giphy.com',
'media2.giphy.com',
'media3.giphy.com',
'media4.giphy.com',
];
// Only fetch from trusted Giphy CDN domains (match any *.giphy.com subdomain)
const { hostname } = new URL(gifUrl);
if (!allowed.includes(hostname)) return;
if (!hostname.endsWith('.giphy.com') && hostname !== 'giphy.com') {
setGifError('GIF source not trusted.');
setTimeout(() => setGifError(null), 4000);
return;
}
const res = await fetch(gifUrl);
if (!res.ok) return;
if (!res.ok) {
setGifError('Failed to download GIF from Giphy.');
setTimeout(() => setGifError(null), 4000);
return;
}
const contentType = res.headers.get('content-type') ?? '';
if (!contentType.startsWith('image/')) return;
if (!contentType.startsWith('image/')) {
setGifError('Unexpected GIF format. Please try another.');
setTimeout(() => setGifError(null), 4000);
return;
}
const blob = await res.blob();
if (blob.size > 20 * 1024 * 1024) {