diff --git a/src/media-auth.ts b/src/media-auth.ts index 4560a92ef..ba25a4873 100644 --- a/src/media-auth.ts +++ b/src/media-auth.ts @@ -33,39 +33,74 @@ async function getAccessToken(window: BrowserWindow): Promise { + return new Promise((resolve) => { + ipcMain.once("homeserverUrl", (_, homeserver) => { + resolve(homeserver); + }); + window.webContents.send("homeserverUrl"); // ping now that the listener exists + }); +} + export function setupMediaAuth(window: BrowserWindow): void { session.defaultSession.webRequest.onBeforeRequest(async (req, callback) => { // This handler emulates the element-web service worker, where URLs are rewritten late in the request // for backwards compatibility. As authenticated media becomes more prevalent, this should be replaced // by the app using authenticated URLs from the outset. - let url = req.url; - if (!url.includes("/_matrix/media/v3/download") && !url.includes("/_matrix/media/v3/thumbnail")) { - return callback({}); // not a URL we care about - } + try { + const url = new URL(req.url); + if ( + !url.pathname.startsWith("/_matrix/media/v3/download") && + !url.pathname.startsWith("/_matrix/media/v3/thumbnail") + ) { + return callback({}); // not a URL we care about + } - const supportedVersions = await getSupportedVersions(window); - // We have to check that the access token is truthy otherwise we'd be intercepting pre-login media request too, - // e.g. those required for SSO button icons. - const accessToken = await getAccessToken(window); - if (supportedVersions.includes("v1.11") && accessToken) { - url = url.replace(/\/media\/v3\/(.*)\//, "/client/v1/media/$1/"); - return callback({ redirectURL: url }); - } else { - return callback({}); // no support == no modification + const supportedVersions = await getSupportedVersions(window); + // We have to check that the access token is truthy otherwise we'd be intercepting pre-login media request too, + // e.g. those required for SSO button icons. + const accessToken = await getAccessToken(window); + if (supportedVersions.includes("v1.11") && accessToken) { + url.href = url.href.replace(/\/media\/v3\/(.*)\//, "/client/v1/media/$1/"); + return callback({ redirectURL: url.toString() }); + } else { + return callback({}); // no support == no modification + } + } catch (e) { + console.error(e); } }); session.defaultSession.webRequest.onBeforeSendHeaders(async (req, callback) => { - if (!req.url.includes("/_matrix/client/v1/media")) { - return callback({}); // invoke unmodified - } + try { + const url = new URL(req.url); + if (!url.pathname.startsWith("/_matrix/client/v1/media")) { + return callback({}); // invoke unmodified + } - // Only add authorization header to authenticated media URLs. This emulates the service worker - // behaviour in element-web. - const accessToken = await getAccessToken(window); - // `accessToken` can be falsy, but if we're trying to download media without authentication - // then we should expect failure anyway. - const headers = { ...req.requestHeaders, Authorization: `Bearer ${accessToken}` }; - return callback({ requestHeaders: headers }); + // Is this request actually going to the homeserver? + // We don't combine this check with the one above on purpose. + // We're fetching the homeserver url through IPC and should do so + // as sparingly as possible. + const homeserver = await getHomeserverUrl(window); + const isRequestToHomeServer = homeserver && url.origin === new URL(homeserver).origin; + if (!isRequestToHomeServer) { + return callback({}); // invoke unmodified + } + + // Only add authorization header to authenticated media URLs. This emulates the service worker + // behaviour in element-web. + const accessToken = await getAccessToken(window); + // `accessToken` can be falsy, but if we're trying to download media without authentication + // then we should expect failure anyway. + const headers = { ...req.requestHeaders, Authorization: `Bearer ${accessToken}` }; + return callback({ requestHeaders: headers }); + } catch (e) { + console.error(e); + } }); } diff --git a/src/preload.ts b/src/preload.ts index 398f94422..faa86a4d5 100644 --- a/src/preload.ts +++ b/src/preload.ts @@ -28,6 +28,7 @@ const CHANNELS = [ "userDownloadAction", "openDesktopCapturerSourcePicker", "userAccessToken", + "homeserverUrl", "serverSupportedVersions", ];