mirror of
https://github.com/CringeStudios/element-desktop.git
synced 2025-01-18 23:44:59 +01:00
Merge commit from fork
* Check url with homeserver * Move check to where access-token is added * Do IPC comm sparingly Before, the code would fetch the hs for every request. Since this needs the whole event-handler dance, it's best we do it only for the requests that match the media endpoints. Also added some try..catch since we create URL objects that could potentially throw * Check origin instead of just hostname
This commit is contained in:
parent
60d28ca3d8
commit
2d6e087fb0
@ -33,39 +33,74 @@ async function getAccessToken(window: BrowserWindow): Promise<string | undefined
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the homeserver url
|
||||
* This requires asking the renderer process for the homeserver url.
|
||||
*/
|
||||
async function getHomeserverUrl(window: BrowserWindow): Promise<string> {
|
||||
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);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -28,6 +28,7 @@ const CHANNELS = [
|
||||
"userDownloadAction",
|
||||
"openDesktopCapturerSourcePicker",
|
||||
"userAccessToken",
|
||||
"homeserverUrl",
|
||||
"serverSupportedVersions",
|
||||
];
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user