feat: implement centralized access token management for media downloads and user authentication

This commit is contained in:
2026-03-23 21:53:27 +11:00
parent f76fee23bf
commit 75a9b4ca1e
16 changed files with 183 additions and 54 deletions

View File

@@ -12,6 +12,7 @@ import {
downloadMedia,
mxcUrlToHttp,
} from '../../utils/matrix';
import { getCurrentAccessToken } from '../../utils/auth';
const badgeStyles = { maxWidth: toRem(100) };
@@ -28,7 +29,8 @@ export function FileDownloadButton({ filename, url, mimeType, encInfo }: FileDow
const [downloadState, download] = useAsyncCallback(
useCallback(async () => {
const mediaUrl = mxcUrlToHttp(mx, url, useAuthentication) ?? url;
const accessToken = mx.getAccessToken();
// Always use current session's token to avoid stale tokens during account switches
const accessToken = getCurrentAccessToken();
const fileContent = encInfo
? await downloadEncryptedMedia(mediaUrl, (encBuf) => decryptFile(encBuf, mimeType, encInfo), accessToken)
: await downloadMedia(mediaUrl, accessToken);

View File

@@ -55,7 +55,8 @@ export function AudioContent({
const [srcState, loadSrc] = useAsyncCallback(
useCallback(async () => {
const mediaUrl = mxcUrlToHttp(mx, url, useAuthentication) ?? url;
const accessToken = mx.getAccessToken();
// Always use current session's token to avoid stale tokens during account switches
const accessToken = getCurrentAccessToken();
const fileContent = encInfo
? await downloadEncryptedMedia(mediaUrl, (encBuf) => decryptFile(encBuf, mimeType, encInfo), accessToken)
: await downloadMedia(mediaUrl, accessToken);

View File

@@ -35,6 +35,7 @@ import {
mxcUrlToHttp,
} from '../../../utils/matrix';
import { useMediaAuthentication } from '../../../hooks/useMediaAuthentication';
import { getCurrentAccessToken } from '../../../utils/auth';
import { ModalWide } from '../../../styles/Modal.css';
const renderErrorButton = (retry: () => void, text: string) => (
@@ -87,7 +88,8 @@ export function ReadTextFile({ body, mimeType, url, encInfo, renderViewer }: Rea
const [textState, loadText] = useAsyncCallback(
useCallback(async () => {
const mediaUrl = mxcUrlToHttp(mx, url, useAuthentication) ?? url;
const accessToken = mx.getAccessToken();
// Always use current session's token to avoid stale tokens during account switches
const accessToken = getCurrentAccessToken();
const fileContent = encInfo
? await downloadEncryptedMedia(mediaUrl, (encBuf) => decryptFile(encBuf, mimeType, encInfo), accessToken)
: await downloadMedia(mediaUrl, accessToken);
@@ -178,7 +180,8 @@ export function ReadPdfFile({ body, mimeType, url, encInfo, renderViewer }: Read
const [pdfState, loadPdf] = useAsyncCallback(
useCallback(async () => {
const mediaUrl = mxcUrlToHttp(mx, url, useAuthentication) ?? url;
const accessToken = mx.getAccessToken();
// Always use current session's token to avoid stale tokens during account switches
const accessToken = getCurrentAccessToken();
const fileContent = encInfo
? await downloadEncryptedMedia(mediaUrl, (encBuf) => decryptFile(encBuf, mimeType, encInfo), accessToken)
: await downloadMedia(mediaUrl, accessToken);
@@ -256,7 +259,8 @@ export function DownloadFile({ body, mimeType, url, info, encInfo }: DownloadFil
const [downloadState, download] = useAsyncCallback(
useCallback(async () => {
const mediaUrl = mxcUrlToHttp(mx, url, useAuthentication) ?? url;
const accessToken = mx.getAccessToken();
// Always use current session's token to avoid stale tokens during account switches
const accessToken = getCurrentAccessToken();
const fileContent = encInfo
? await downloadEncryptedMedia(mediaUrl, (encBuf) => decryptFile(encBuf, mimeType, encInfo), accessToken)
: await downloadMedia(mediaUrl, accessToken);

View File

@@ -31,6 +31,7 @@ import { decryptFile, downloadEncryptedMedia, mxcUrlToHttp } from '../../../util
import { useMediaAuthentication } from '../../../hooks/useMediaAuthentication';
import { ModalWide } from '../../../styles/Modal.css';
import { validBlurHash } from '../../../utils/blurHash';
import { getCurrentAccessToken } from '../../../utils/auth';
/**
* Fetches media with authentication headers and returns a blob URL.
@@ -129,7 +130,8 @@ export const ImageContent = as<'div', ImageContentProps>(
const [srcState, loadSrc] = useAsyncCallback(
useCallback(async () => {
const mediaUrl = mxcUrlToHttp(mx, url, useAuthentication) ?? url;
const accessToken = mx.getAccessToken();
// Always use current session's token to avoid stale tokens during account switches
const accessToken = getCurrentAccessToken();
if (encInfo) {
const fileContent = await downloadEncryptedMedia(
mediaUrl,

View File

@@ -5,6 +5,7 @@ import { AsyncStatus, useAsyncCallback } from '../../../hooks/useAsyncCallback';
import { decryptFile, downloadEncryptedMedia, isAuthenticatedMediaUrl, mxcUrlToHttp } from '../../../utils/matrix';
import { useMediaAuthentication } from '../../../hooks/useMediaAuthentication';
import { FALLBACK_MIMETYPE } from '../../../utils/mimeTypes';
import { getCurrentAccessToken } from '../../../utils/auth';
/**
* Fetches media with authentication headers and returns a blob URL.
@@ -57,7 +58,8 @@ export function ThumbnailContent({ info, renderImage }: ThumbnailContentProps) {
}
const mediaUrl = mxcUrlToHttp(mx, thumbMxcUrl, useAuthentication) ?? thumbMxcUrl;
const accessToken = mx.getAccessToken();
// Always use current session's token to avoid stale tokens during account switches
const accessToken = getCurrentAccessToken();
if (encInfo) {
const fileContent = await downloadEncryptedMedia(
mediaUrl,

View File

@@ -82,7 +82,8 @@ export const VideoContent = as<'div', VideoContentProps>(
const [srcState, loadSrc] = useAsyncCallback(
useCallback(async () => {
const mediaUrl = mxcUrlToHttp(mx, url, useAuthentication) ?? url;
const accessToken = mx.getAccessToken();
// Always use current session's token to avoid stale tokens during account switches
const accessToken = getCurrentAccessToken();
const fileContent = encInfo
? await downloadEncryptedMedia(mediaUrl, (encBuf) =>
decryptFile(encBuf, mimeType, encInfo), accessToken