security: make ipc only allow discord origins

This commit is contained in:
V 2023-08-25 15:32:06 +02:00
parent c76d7195a5
commit 9bb02f8581
No known key found for this signature in database
GPG key ID: A1DC0CFB5615D905
4 changed files with 74 additions and 48 deletions

View file

@ -4,7 +4,7 @@
* Copyright (c) 2023 Vendicated and Vencord contributors * Copyright (c) 2023 Vendicated and Vencord contributors
*/ */
import { app, dialog, ipcMain, session, shell } from "electron"; import { app, dialog, session, shell } from "electron";
import { mkdirSync, readFileSync, watch } from "fs"; import { mkdirSync, readFileSync, watch } from "fs";
import { open, readFile } from "fs/promises"; import { open, readFile } from "fs/promises";
import { release } from "os"; import { release } from "os";
@ -17,71 +17,58 @@ import { autoStart } from "./autoStart";
import { VENCORD_FILES_DIR, VENCORD_QUICKCSS_FILE, VENCORD_THEMES_DIR } from "./constants"; import { VENCORD_FILES_DIR, VENCORD_QUICKCSS_FILE, VENCORD_THEMES_DIR } from "./constants";
import { mainWin } from "./mainWindow"; import { mainWin } from "./mainWindow";
import { Settings } from "./settings"; import { Settings } from "./settings";
import { handle, handleSync } from "./utils/ipcWrappers";
import { isValidVencordInstall } from "./utils/vencordLoader"; import { isValidVencordInstall } from "./utils/vencordLoader";
ipcMain.on(IpcEvents.GET_VENCORD_PRELOAD_FILE, e => { handleSync(IpcEvents.GET_VENCORD_PRELOAD_FILE, () => join(VENCORD_FILES_DIR, "vencordDesktopPreload.js"));
e.returnValue = join(VENCORD_FILES_DIR, "vencordDesktopPreload.js"); handleSync(IpcEvents.GET_VENCORD_RENDERER_SCRIPT, () =>
}); readFileSync(join(VENCORD_FILES_DIR, "vencordDesktopRenderer.js"), "utf-8")
);
ipcMain.on(IpcEvents.GET_VENCORD_RENDERER_SCRIPT, e => { handleSync(IpcEvents.GET_RENDERER_SCRIPT, () => readFileSync(join(__dirname, "renderer.js"), "utf-8"));
e.returnValue = readFileSync(join(VENCORD_FILES_DIR, "vencordDesktopRenderer.js"), "utf-8"); handleSync(IpcEvents.GET_RENDERER_CSS_FILE, () => join(__dirname, "renderer.css"));
});
ipcMain.on(IpcEvents.GET_RENDERER_SCRIPT, e => { handleSync(IpcEvents.GET_SETTINGS, () => Settings.plain);
e.returnValue = readFileSync(join(__dirname, "renderer.js"), "utf-8"); handleSync(IpcEvents.GET_VERSION, () => app.getVersion());
});
ipcMain.on(IpcEvents.GET_RENDERER_CSS_FILE, e => { handleSync(
e.returnValue = join(__dirname, "renderer.css"); IpcEvents.SUPPORTS_WINDOWS_TRANSPARENCY,
}); () => process.platform === "win32" && Number(release().split(".").pop()) >= 22621
);
ipcMain.on(IpcEvents.GET_SETTINGS, e => { handleSync(IpcEvents.AUTOSTART_ENABLED, () => autoStart.isEnabled());
e.returnValue = Settings.plain; handle(IpcEvents.ENABLE_AUTOSTART, autoStart.enable);
}); handle(IpcEvents.DISABLE_AUTOSTART, autoStart.disable);
ipcMain.on(IpcEvents.GET_VERSION, e => { handle(IpcEvents.SET_SETTINGS, (_, settings: typeof Settings.store, path?: string) => {
e.returnValue = app.getVersion();
});
ipcMain.on(IpcEvents.SUPPORTS_WINDOWS_TRANSPARENCY, e => {
e.returnValue = process.platform === "win32" && Number(release().split(".").pop()) >= 22621;
});
ipcMain.on(IpcEvents.AUTOSTART_ENABLED, e => {
e.returnValue = autoStart.isEnabled();
});
ipcMain.handle(IpcEvents.ENABLE_AUTOSTART, autoStart.enable);
ipcMain.handle(IpcEvents.DISABLE_AUTOSTART, autoStart.disable);
ipcMain.handle(IpcEvents.SET_SETTINGS, (_, settings: typeof Settings.store, path?: string) => {
Settings.setData(settings, path); Settings.setData(settings, path);
}); });
ipcMain.handle(IpcEvents.RELAUNCH, () => { handle(IpcEvents.RELAUNCH, () => {
app.relaunch(); app.relaunch();
app.exit(); app.exit();
}); });
ipcMain.handle(IpcEvents.SHOW_ITEM_IN_FOLDER, (_, path) => { handle(IpcEvents.SHOW_ITEM_IN_FOLDER, (_, path) => {
shell.showItemInFolder(path); shell.showItemInFolder(path);
}); });
ipcMain.handle(IpcEvents.FOCUS, () => { handle(IpcEvents.FOCUS, () => {
if (process.platform === "win32") mainWin.minimize(); // Windows is weird if (process.platform === "win32") mainWin.minimize(); // Windows is weird
mainWin.restore(); mainWin.restore();
mainWin.show(); mainWin.show();
}); });
ipcMain.handle(IpcEvents.CLOSE, e => { handle(IpcEvents.CLOSE, e => {
mainWin.close(); mainWin.close();
}); });
ipcMain.handle(IpcEvents.MINIMIZE, e => { handle(IpcEvents.MINIMIZE, e => {
mainWin.minimize(); mainWin.minimize();
}); });
ipcMain.handle(IpcEvents.MAXIMIZE, e => { handle(IpcEvents.MAXIMIZE, e => {
if (mainWin.isMaximized()) { if (mainWin.isMaximized()) {
mainWin.unmaximize(); mainWin.unmaximize();
} else { } else {
@ -89,7 +76,7 @@ ipcMain.handle(IpcEvents.MAXIMIZE, e => {
} }
}); });
ipcMain.handle(IpcEvents.SPELLCHECK_SET_LANGUAGES, (_, languages: string[]) => { handle(IpcEvents.SPELLCHECK_SET_LANGUAGES, (_, languages: string[]) => {
const ses = session.defaultSession; const ses = session.defaultSession;
const available = ses.availableSpellCheckerLanguages; const available = ses.availableSpellCheckerLanguages;
@ -97,15 +84,15 @@ ipcMain.handle(IpcEvents.SPELLCHECK_SET_LANGUAGES, (_, languages: string[]) => {
if (applicable.length) ses.setSpellCheckerLanguages(applicable); if (applicable.length) ses.setSpellCheckerLanguages(applicable);
}); });
ipcMain.handle(IpcEvents.SPELLCHECK_REPLACE_MISSPELLING, (e, word: string) => { handle(IpcEvents.SPELLCHECK_REPLACE_MISSPELLING, (e, word: string) => {
e.sender.replaceMisspelling(word); e.sender.replaceMisspelling(word);
}); });
ipcMain.handle(IpcEvents.SPELLCHECK_ADD_TO_DICTIONARY, (e, word: string) => { handle(IpcEvents.SPELLCHECK_ADD_TO_DICTIONARY, (e, word: string) => {
e.sender.session.addWordToSpellCheckerDictionary(word); e.sender.session.addWordToSpellCheckerDictionary(word);
}); });
ipcMain.handle(IpcEvents.SELECT_VENCORD_DIR, async () => { handle(IpcEvents.SELECT_VENCORD_DIR, async () => {
const res = await dialog.showOpenDialog(mainWin!, { const res = await dialog.showOpenDialog(mainWin!, {
properties: ["openDirectory"] properties: ["openDirectory"]
}); });
@ -117,7 +104,7 @@ ipcMain.handle(IpcEvents.SELECT_VENCORD_DIR, async () => {
return dir; return dir;
}); });
ipcMain.handle(IpcEvents.SET_BADGE_COUNT, (_, count: number) => setBadgeCount(count)); handle(IpcEvents.SET_BADGE_COUNT, (_, count: number) => setBadgeCount(count));
function readCss() { function readCss() {
return readFile(VENCORD_QUICKCSS_FILE, "utf-8").catch(() => ""); return readFile(VENCORD_QUICKCSS_FILE, "utf-8").catch(() => "");

View file

@ -4,12 +4,14 @@
* Copyright (c) 2023 Vendicated and Vencord contributors * Copyright (c) 2023 Vendicated and Vencord contributors
*/ */
import { desktopCapturer, ipcMain, session, Streams } from "electron"; import { desktopCapturer, session, Streams } from "electron";
import type { StreamPick } from "renderer/components/ScreenSharePicker"; import type { StreamPick } from "renderer/components/ScreenSharePicker";
import { IpcEvents } from "shared/IpcEvents"; import { IpcEvents } from "shared/IpcEvents";
import { handle } from "./utils/ipcWrappers";
export function registerScreenShareHandler() { export function registerScreenShareHandler() {
ipcMain.handle(IpcEvents.CAPTURER_GET_LARGE_THUMBNAIL, async (_, id: string) => { handle(IpcEvents.CAPTURER_GET_LARGE_THUMBNAIL, async (_, id: string) => {
const sources = await desktopCapturer.getSources({ const sources = await desktopCapturer.getSources({
types: ["window", "screen"], types: ["window", "screen"],
thumbnailSize: { thumbnailSize: {

View file

@ -0,0 +1,36 @@
/*
* SPDX-License-Identifier: GPL-3.0
* Vesktop, a desktop app aiming to give you a snappier Discord Experience
* Copyright (c) 2023 Vendicated and Vencord contributors
*/
import { ipcMain, IpcMainEvent, IpcMainInvokeEvent, WebFrameMain } from "electron";
import { IpcEvents } from "shared/IpcEvents";
export function validateSender(frame: WebFrameMain) {
const { hostname, protocol } = new URL(frame.url);
if (protocol === "file:") return;
switch (hostname) {
case "discord.com":
case "ptb.discord.com":
case "canary.discord.com":
break;
default:
throw new Error("ipc: Disallowed host " + hostname);
}
}
export function handleSync(event: IpcEvents, cb: (e: IpcMainEvent, ...args: any[]) => any) {
ipcMain.on(event, (e, ...args) => {
validateSender(e.senderFrame);
e.returnValue = cb(e, ...args);
});
}
export function handle(event: IpcEvents, cb: (e: IpcMainInvokeEvent, ...args: any[]) => any) {
ipcMain.handle(event, (e, ...args) => {
validateSender(e.senderFrame);
return cb(e, ...args);
});
}

View file

@ -4,8 +4,9 @@
* Copyright (c) 2023 Vendicated and Vencord contributors * Copyright (c) 2023 Vendicated and Vencord contributors
*/ */
import { app, BrowserWindow, ipcMain, shell } from "electron"; import { app, BrowserWindow, shell } from "electron";
import { Settings } from "main/settings"; import { Settings } from "main/settings";
import { handle } from "main/utils/ipcWrappers";
import { makeLinksOpenExternally } from "main/utils/makeLinksOpenExternally"; import { makeLinksOpenExternally } from "main/utils/makeLinksOpenExternally";
import { githubGet, ReleaseData } from "main/utils/vencordLoader"; import { githubGet, ReleaseData } from "main/utils/vencordLoader";
import { join } from "path"; import { join } from "path";
@ -20,8 +21,8 @@ export interface UpdateData {
let updateData: UpdateData; let updateData: UpdateData;
ipcMain.handle(IpcEvents.UPDATER_GET_DATA, () => updateData); handle(IpcEvents.UPDATER_GET_DATA, () => updateData);
ipcMain.handle(IpcEvents.UPDATER_DOWNLOAD, () => { handle(IpcEvents.UPDATER_DOWNLOAD, () => {
const portable = !!process.env.PORTABLE_EXECUTABLE_FILE; const portable = !!process.env.PORTABLE_EXECUTABLE_FILE;
const { assets } = updateData.release; const { assets } = updateData.release;
@ -50,7 +51,7 @@ ipcMain.handle(IpcEvents.UPDATER_DOWNLOAD, () => {
shell.openExternal(url); shell.openExternal(url);
}); });
ipcMain.handle(IpcEvents.UPDATE_IGNORE, () => { handle(IpcEvents.UPDATE_IGNORE, () => {
Settings.store.skippedUpdate = updateData.latestVersion; Settings.store.skippedUpdate = updateData.latestVersion;
}); });