fix(privacy): generate invite QR locally instead of api.qrserver.com (H5)
The Share Room QR was fetched from the third-party api.qrserver.com, leaking which rooms a user shares (and failing offline / under strict CSP). Now rendered locally via qrcode.react (QRCodeSVG) — no network request, works offline. Added a white quiet-zone container so the code scans on any theme; dropped the qrError fallback (local generation can't fail the same way). Removed api.qrserver.com from the prod CSP img-src (matrix repo). Build verified (rolldown interop OK). Verification steps added to LOTUS_TESTING. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
import React, { useCallback, useState } from 'react';
|
||||
import { Box, Button, color, config, Icon, Icons, Text } from 'folds';
|
||||
import { Box, Button, config, Icon, Icons, Text } from 'folds';
|
||||
import { QRCodeSVG } from 'qrcode.react';
|
||||
import { SequenceCard } from '../../../components/sequence-card';
|
||||
import { SequenceCardStyle } from '../../room-settings/styles.css';
|
||||
import { SettingTile } from '../../../components/setting-tile';
|
||||
@@ -12,11 +13,9 @@ export function RoomShareInvite() {
|
||||
const mx = useMatrixClient();
|
||||
const room = useRoom();
|
||||
const [copied, setCopied] = useState(false);
|
||||
const [qrError, setQrError] = useState(false);
|
||||
|
||||
const domain = mx.getDomain() ?? undefined;
|
||||
const inviteUrl = getMatrixToRoom(room.roomId, domain ? [domain] : undefined);
|
||||
const qrSrc = `https://api.qrserver.com/v1/create-qr-code/?size=160x160&data=${encodeURIComponent(inviteUrl)}`;
|
||||
|
||||
const handleCopy = useCallback(() => {
|
||||
navigator.clipboard.writeText(inviteUrl).then(() => {
|
||||
@@ -64,35 +63,19 @@ export function RoomShareInvite() {
|
||||
</Box>
|
||||
</Box>
|
||||
<Box justifyContent="Center">
|
||||
{qrError ? (
|
||||
<Box
|
||||
direction="Column"
|
||||
alignItems="Center"
|
||||
justifyContent="Center"
|
||||
gap="100"
|
||||
style={{
|
||||
width: 160,
|
||||
height: 160,
|
||||
borderRadius: config.radii.R300,
|
||||
background: color.SurfaceVariant.Container,
|
||||
}}
|
||||
>
|
||||
<Icon size="400" src={Icons.Warning} />
|
||||
<Text size="T200" priority="300" align="Center">
|
||||
QR code unavailable
|
||||
</Text>
|
||||
</Box>
|
||||
) : (
|
||||
<img
|
||||
src={qrSrc}
|
||||
alt="QR code for room invite link"
|
||||
width={160}
|
||||
height={160}
|
||||
loading="lazy"
|
||||
onError={() => setQrError(true)}
|
||||
style={{ display: 'block', borderRadius: config.radii.R300 }}
|
||||
/>
|
||||
)}
|
||||
{/* Generated locally (qrcode.react) — no third-party service, works
|
||||
offline + under strict CSP. White padded quiet-zone so the
|
||||
default black-on-white code scans on any theme. */}
|
||||
<Box
|
||||
style={{
|
||||
padding: config.space.S200,
|
||||
background: '#ffffff',
|
||||
borderRadius: config.radii.R300,
|
||||
lineHeight: 0,
|
||||
}}
|
||||
>
|
||||
<QRCodeSVG value={inviteUrl} size={160} level="M" title="Room invite QR code" />
|
||||
</Box>
|
||||
</Box>
|
||||
</Box>
|
||||
</CutoutCard>
|
||||
|
||||
Reference in New Issue
Block a user