From 773492d4581b210bd2acf6894f15c7a43fdff93c Mon Sep 17 00:00:00 2001 From: Will Hunt Date: Mon, 2 Dec 2024 13:54:00 +0000 Subject: [PATCH] Load authenicated media --- src/Avatar.tsx | 51 +++++++++++++++++++++++++++++++++++++++------ src/utils/matrix.ts | 14 +------------ 2 files changed, 46 insertions(+), 19 deletions(-) diff --git a/src/Avatar.tsx b/src/Avatar.tsx index 29ab5236..f1d783f3 100644 --- a/src/Avatar.tsx +++ b/src/Avatar.tsx @@ -5,11 +5,11 @@ SPDX-License-Identifier: AGPL-3.0-only Please see LICENSE in the repository root for full details. */ -import { useMemo, FC, CSSProperties } from "react"; +import { useMemo, FC, CSSProperties, useState, useEffect } from "react"; import { Avatar as CompoundAvatar } from "@vector-im/compound-web"; -import { getAvatarUrl } from "./utils/matrix"; import { useClient } from "./ClientContext"; +import { MatrixClient } from "matrix-js-sdk/src/client"; export enum Size { XS = "xs", @@ -36,6 +36,18 @@ interface Props { style?: CSSProperties; } +export function getAvatarUrl( + client: MatrixClient, + mxcUrl: string|null, + avatarSize = 96, +): string|null { + const width = Math.floor(avatarSize * window.devicePixelRatio); + const height = Math.floor(avatarSize * window.devicePixelRatio); + // scale is more suitable for larger sizes + const resizeMethod = avatarSize <= 96 ? "crop" : "scale"; + return mxcUrl ? client.mxcUrlToHttp(mxcUrl, width, height, resizeMethod, false, true, true) : null; +} + export const Avatar: FC = ({ className, id, @@ -55,9 +67,36 @@ export const Avatar: FC = ({ [size], ); - const resolvedSrc = useMemo(() => { - if (!client || !src || !sizePx) return undefined; - return src.startsWith("mxc://") ? getAvatarUrl(client, src, sizePx) : src; + const [avatarUrl, setAvatarUrl] = useState(undefined); + + useEffect(() => { + if (!client || !src || !sizePx) { + return; + }; + const token = client.getAccessToken(); + if (!token) { + return; + } + const resolveSrc = getAvatarUrl(client, src, sizePx); + if (!resolveSrc) { + setAvatarUrl(undefined); + return; + } + + let objectUrl: string|undefined; + fetch(resolveSrc, { + headers: { + 'Authorization': `Bearer ${token}` + } + }).then((req) => req.blob()).then((res) => { + objectUrl = URL.createObjectURL(res); + setAvatarUrl(objectUrl); + }).catch((ex) => { + console.warn("Failed to get avatar URL", ex); + setAvatarUrl(undefined); + }); + + () => objectUrl && URL.revokeObjectURL(objectUrl); }, [client, src, sizePx]); return ( @@ -66,7 +105,7 @@ export const Avatar: FC = ({ id={id} name={name} size={`${sizePx}px`} - src={resolvedSrc} + src={avatarUrl} style={style} {...props} /> diff --git a/src/utils/matrix.ts b/src/utils/matrix.ts index d3821a3f..46b26528 100644 --- a/src/utils/matrix.ts +++ b/src/utils/matrix.ts @@ -332,16 +332,4 @@ export function getRelativeRoomUrl( ? "/" + roomAliasLocalpartFromRoomName(roomName) : ""; return `/room/#${roomPart}?${generateUrlSearchParams(roomId, encryptionSystem, viaServers).toString()}`; -} - -export function getAvatarUrl( - client: MatrixClient, - mxcUrl: string, - avatarSize = 96, -): string { - const width = Math.floor(avatarSize * window.devicePixelRatio); - const height = Math.floor(avatarSize * window.devicePixelRatio); - // scale is more suitable for larger sizes - const resizeMethod = avatarSize <= 96 ? "crop" : "scale"; - return mxcUrl && client.mxcUrlToHttp(mxcUrl, width, height, resizeMethod)!; -} +} \ No newline at end of file