diff options
Diffstat (limited to 'scripts/patcher')
-rw-r--r-- | scripts/patcher/common.js | 357 | ||||
-rwxr-xr-x | scripts/patcher/install.js | 219 | ||||
-rwxr-xr-x | scripts/patcher/uninstall.js | 116 |
3 files changed, 0 insertions, 692 deletions
diff --git a/scripts/patcher/common.js b/scripts/patcher/common.js deleted file mode 100644 index 05523e5..0000000 --- a/scripts/patcher/common.js +++ /dev/null @@ -1,357 +0,0 @@ -/* - * Vencord, a modification for Discord's desktop app - * Copyright (c) 2022 Vendicated and contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <https://www.gnu.org/licenses/>. -*/ - -const path = require("path"); -const readline = require("readline"); -const fs = require("fs"); -const menu = require("console-menu"); - -function pathToBranch(dir) { - dir = dir.toLowerCase(); - if (dir.endsWith("development")) { - return "development"; - } - if (dir.endsWith("canary")) { - return "canary"; - } - if (dir.endsWith("ptb")) { - return "ptb"; - } - return "stable"; -} - -const BRANCH_NAMES = [ - "Discord", - "DiscordPTB", - "DiscordCanary", - "DiscordDevelopment", - "discord", - "discordptb", - "discordcanary", - "discorddevelopment", - "discord-ptb", - "discord-canary", - "discord-development", - // Flatpak - "com.discordapp.Discord", - "com.discordapp.DiscordPTB", - "com.discordapp.DiscordCanary", - "com.discordapp.DiscordDevelopment", -]; - -const MACOS_DISCORD_DIRS = [ - "Discord.app", - "Discord PTB.app", - "Discord Canary.app", - "Discord Development.app", -]; - -if (process.platform === "linux" && process.env.SUDO_USER) { - process.env.HOME = fs - .readFileSync("/etc/passwd", "utf-8") - .match(new RegExp(`^${process.env.SUDO_USER}.+$`, "m"))[0] - .split(":")[5]; -} - -const LINUX_DISCORD_DIRS = [ - "/usr/share", - "/usr/lib64", - "/opt", - `${process.env.HOME}/.local/share`, - `${process.env.HOME}/.dvm`, - "/var/lib/flatpak/app", - `${process.env.HOME}/.local/share/flatpak/app`, -]; - -const FLATPAK_NAME_MAPPING = { - DiscordCanary: "discord-canary", - DiscordPTB: "discord-ptb", - DiscordDevelopment: "discord-development", - Discord: "discord", -}; - -const ENTRYPOINT = path - .join(process.cwd(), "dist", "patcher.js") - .replace(/\\/g, "/"); - -function question(question) { - const rl = readline.createInterface({ - input: process.stdin, - output: process.stdout, - terminal: false, - }); - - return new Promise(resolve => { - rl.question(question, answer => { - rl.close(); - resolve(answer); - }); - }); -} - -async function getMenuItem(installations) { - const menuItems = installations.map(info => ({ - title: info.patched ? "[MODIFIED] " + info.location : info.location, - info, - })); - - const result = await menu( - [ - ...menuItems, - { title: "Specify custom path", info: "custom" }, - { title: "Exit without patching", exit: true } - ], - { - header: "Select a Discord installation to patch:", - border: true, - helpMessage: - "Use the up/down arrow keys to select an option. " + - "Press ENTER to confirm.", - } - ); - - if (!result || !result.info || result.exit) { - console.log("No installation selected."); - process.exit(0); - } - - if (result.info === "custom") { - const customPath = await question("Please enter the path: "); - if (!customPath || !fs.existsSync(customPath)) { - console.log("No such Path or not specifed."); - process.exit(); - } - - const resourceDir = path.join(customPath, "resources"); - if (!fs.existsSync(path.join(resourceDir, "app.asar"))) { - console.log("Unsupported Install. resources/app.asar not found"); - process.exit(); - } - - const appDir = path.join(resourceDir, "app"); - result.info = { - branch: "unknown", - patched: fs.existsSync(appDir), - location: customPath, - versions: [{ - path: appDir, - name: null - }], - arch: process.platform === "linux" ? "linux" : "win32", - isFlatpak: false, - }; - } - - if (result.info.patched) { - const answer = await question( - "This installation has already been modified. Overwrite? [Y/n]: " - ); - - if (!["y", "yes", "yeah", ""].includes(answer.toLowerCase())) { - console.log("Not patching."); - process.exit(0); - } - } - - return result.info; -} - -function getWindowsDirs() { - const dirs = []; - for (const dir of fs.readdirSync(process.env.LOCALAPPDATA)) { - if (!BRANCH_NAMES.includes(dir)) continue; - - const location = path.join(process.env.LOCALAPPDATA, dir); - if (!fs.statSync(location).isDirectory()) continue; - - const appDirs = fs - .readdirSync(location, { withFileTypes: true }) - .filter(file => file.isDirectory()) - .filter(file => file.name.startsWith("app-")) - .map(file => path.join(location, file.name)); - - const versions = []; - let patched = false; - - for (const fqAppDir of appDirs) { - const resourceDir = path.join(fqAppDir, "resources"); - if (!fs.existsSync(path.join(resourceDir, "app.asar"))) { - continue; - } - const appDir = path.join(resourceDir, "app"); - if (fs.existsSync(appDir)) { - patched = true; - } - versions.push({ - path: appDir, - name: /app-([0-9.]+)/.exec(fqAppDir)[1], - }); - } - - if (appDirs.length) { - dirs.push({ - branch: dir, - patched, - location, - versions, - arch: "win32", - flatpak: false, - }); - } - } - return dirs; -} - -function getDarwinDirs() { - const dirs = []; - for (const dir of fs.readdirSync("/Applications")) { - if (!MACOS_DISCORD_DIRS.includes(dir)) continue; - - const location = path.join("/Applications", dir, "Contents"); - if (!fs.existsSync(location)) continue; - if (!fs.statSync(location).isDirectory()) continue; - - const appDirs = fs - .readdirSync(location, { withFileTypes: true }) - .filter(file => file.isDirectory()) - .filter(file => file.name.startsWith("Resources")) - .map(file => path.join(location, file.name)); - - const versions = []; - let patched = false; - - for (const resourceDir of appDirs) { - if (!fs.existsSync(path.join(resourceDir, "app.asar"))) { - continue; - } - const appDir = path.join(resourceDir, "app"); - if (fs.existsSync(appDir)) { - patched = true; - } - - versions.push({ - path: appDir, - name: null, // MacOS installs have no version number - }); - } - - if (appDirs.length) { - dirs.push({ - branch: dir, - patched, - location, - versions, - arch: "win32", - }); - } - } - return dirs; -} - -function getLinuxDirs() { - const dirs = []; - for (const dir of LINUX_DISCORD_DIRS) { - if (!fs.existsSync(dir)) continue; - for (const branch of fs.readdirSync(dir)) { - if (!BRANCH_NAMES.includes(branch)) continue; - - const location = path.join(dir, branch); - if (!fs.statSync(location).isDirectory()) continue; - - const isFlatpak = location.includes("/flatpak/"); - - let appDirs = []; - - if (isFlatpak) { - const fqDir = path.join(location, "current", "active", "files"); - if (!/com\.discordapp\.(\w+)\//.test(fqDir)) continue; - const branchName = /com\.discordapp\.(\w+)\//.exec(fqDir)[1]; - if (!Object.keys(FLATPAK_NAME_MAPPING).includes(branchName)) { - continue; - } - const appDir = path.join( - fqDir, - FLATPAK_NAME_MAPPING[branchName] - ); - - if (!fs.existsSync(appDir)) continue; - if (!fs.statSync(appDir).isDirectory()) continue; - - const resourceDir = path.join(appDir, "resources"); - - appDirs.push(resourceDir); - } else { - appDirs = fs - .readdirSync(location, { withFileTypes: true }) - .filter(file => file.isDirectory()) - .filter( - file => - file.name.startsWith("app-") || - file.name === "resources" - ) - .map(file => path.join(location, file.name)); - } - - const versions = []; - let patched = false; - - for (const resourceDir of appDirs) { - if (!fs.existsSync(path.join(resourceDir, "app.asar"))) { - continue; - } - const appDir = path.join(resourceDir, "app"); - if (fs.existsSync(appDir)) { - patched = true; - } - - const version = /app-([0-9.]+)/.exec(resourceDir); - - versions.push({ - path: appDir, - name: version && version.length > 1 ? version[1] : null, - }); - } - - if (appDirs.length) { - dirs.push({ - branch, - patched, - location, - versions, - arch: "linux", - isFlatpak, - }); - } - } - } - return dirs; -} - -module.exports = { - pathToBranch, - BRANCH_NAMES, - MACOS_DISCORD_DIRS, - LINUX_DISCORD_DIRS, - FLATPAK_NAME_MAPPING, - ENTRYPOINT, - question, - getMenuItem, - getWindowsDirs, - getDarwinDirs, - getLinuxDirs, -}; diff --git a/scripts/patcher/install.js b/scripts/patcher/install.js deleted file mode 100755 index 3d744a6..0000000 --- a/scripts/patcher/install.js +++ /dev/null @@ -1,219 +0,0 @@ -#!/usr/bin/node -/* - * Vencord, a modification for Discord's desktop app - * Copyright (c) 2022 Vendicated and contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <https://www.gnu.org/licenses/>. -*/ - -const path = require("path"); -const fs = require("fs"); -const { execSync } = require("child_process"); - -console.log("\nVencord Installer\n"); - -if (!fs.existsSync(path.join(process.cwd(), "node_modules"))) { - console.log("You need to install dependencies first. Run:", "pnpm install --frozen-lockfile"); - process.exit(1); -} - -if (!fs.existsSync(path.join(process.cwd(), "dist", "patcher.js"))) { - console.log("You need to build the project first. Run:", "pnpm build"); - process.exit(1); -} - -const { - getMenuItem, - getWindowsDirs, - getDarwinDirs, - getLinuxDirs, - ENTRYPOINT, - question, - pathToBranch -} = require("./common"); - -switch (process.platform) { - case "win32": - install(getWindowsDirs()); - break; - case "darwin": - install(getDarwinDirs()); - break; - case "linux": - install(getLinuxDirs()); - break; - default: - console.log("Unknown OS"); - break; -} - -async function install(installations) { - const selected = await getMenuItem(installations); - - // Attempt to give flatpak perms - if (selected.isFlatpak) { - try { - const cwd = process.cwd(); - const globalCmd = `flatpak override ${selected.branch} --filesystem=${cwd}`; - const userCmd = `flatpak override --user ${selected.branch} --filesystem=${cwd}`; - const cmd = selected.location.startsWith("/home") - ? userCmd - : globalCmd; - execSync(cmd); - console.log("Gave write perms to Discord Flatpak."); - } catch (e) { - console.log("Failed to give write perms to Discord Flatpak."); - console.log( - "Try running this script as an administrator:", - "sudo pnpm inject" - ); - process.exit(1); - } - - const answer = await question( - `Would you like to allow ${selected.branch} to talk to org.freedesktop.Flatpak?\n` + - "This is essentially full host access but necessary to spawn git. Without it, the updater will not work\n" + - "Consider using the http based updater (using the gui installer) instead if you want to maintain the sandbox.\n" + - "[y/N]: " - ); - - if (["y", "yes", "yeah"].includes(answer.toLowerCase())) { - try { - const globalCmd = `flatpak override ${selected.branch} --talk-name=org.freedesktop.Flatpak`; - const userCmd = `flatpak override --user ${selected.branch} --talk-name=org.freedesktop.Flatpak`; - const cmd = selected.location.startsWith("/home") - ? userCmd - : globalCmd; - execSync(cmd); - console.log("Sucessfully gave talk permission"); - } catch (err) { - console.error("Failed to give talk permission\n", err); - } - } else { - console.log(`Not giving full host access. If you change your mind later, you can run:\nflatpak override ${selected.branch} --talk-name=org.freedesktop.Flatpak`); - } - } - - const useNewMethod = pathToBranch(selected.branch) !== "stable"; - - for (const version of selected.versions) { - - const dir = useNewMethod ? path.join(version.path, "..") : version.path; - - // Check if we have write perms to the install directory... - try { - fs.accessSync(selected.location, fs.constants.W_OK); - } catch (e) { - console.error("No write access to", selected.location); - console.error( - "Make sure Discord isn't running. If that doesn't work,", - "try running this script as an administrator:", - "sudo pnpm inject" - ); - process.exit(1); - } - if (useNewMethod) { - const appAsar = path.join(dir, "app.asar"); - const _appAsar = path.join(dir, "_app.asar"); - - if (fs.existsSync(_appAsar) && fs.existsSync(appAsar)) { - console.log("This copy of Discord already seems to be patched..."); - console.log("Try running `pnpm uninject` first."); - process.exit(1); - } - - try { - fs.renameSync(appAsar, _appAsar); - } catch (err) { - if (err.code === "EBUSY") { - console.error(selected.branch, "is still running. Make sure you fully close it before running this script."); - process.exit(1); - } - console.error("Failed to rename app.asar to _app.asar"); - throw err; - } - - try { - fs.mkdirSync(appAsar); - } catch (err) { - if (err.code === "EBUSY") { - console.error(selected.branch, "is still running. Make sure you fully close it before running this script."); - process.exit(1); - } - console.error("Failed to create app.asar folder"); - throw err; - } - - fs.writeFileSync( - path.join(appAsar, "index.js"), - `require("${ENTRYPOINT}");` - ); - fs.writeFileSync( - path.join(appAsar, "package.json"), - JSON.stringify({ - name: "discord", - main: "index.js", - }) - ); - - const requiredFiles = ["index.js", "package.json"]; - - if (requiredFiles.every(f => fs.existsSync(path.join(appAsar, f)))) { - console.log( - "Successfully patched", - version.name - ? `${selected.branch} ${version.name}` - : selected.branch - ); - } else { - console.log("Failed to patch", dir); - console.log("Files in directory:", fs.readdirSync(appAsar)); - } - - return; - } - if (fs.existsSync(dir) && fs.lstatSync(dir).isDirectory()) { - fs.rmSync(dir, { recursive: true }); - } - if (!fs.existsSync(dir)) { - fs.mkdirSync(dir, { recursive: true }); - } - - fs.writeFileSync( - path.join(dir, "index.js"), - `require("${ENTRYPOINT}");` - ); - fs.writeFileSync( - path.join(dir, "package.json"), - JSON.stringify({ - name: "discord", - main: "index.js", - }) - ); - - const requiredFiles = ["index.js", "package.json"]; - - if (requiredFiles.every(f => fs.existsSync(path.join(dir, f)))) { - console.log( - "Successfully patched", - version.name - ? `${selected.branch} ${version.name}` - : selected.branch - ); - } else { - console.log("Failed to patch", dir); - console.log("Files in directory:", fs.readdirSync(dir)); - } - } -} diff --git a/scripts/patcher/uninstall.js b/scripts/patcher/uninstall.js deleted file mode 100755 index ded6cf9..0000000 --- a/scripts/patcher/uninstall.js +++ /dev/null @@ -1,116 +0,0 @@ -#!/usr/bin/node -/* - * Vencord, a modification for Discord's desktop app - * Copyright (c) 2022 Vendicated and contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <https://www.gnu.org/licenses/>. -*/ - -const path = require("path"); -const fs = require("fs"); - -console.log("\nVencord Uninstaller\n"); - -if (!fs.existsSync(path.join(process.cwd(), "node_modules"))) { - console.log("You need to install dependencies first. Run:", "pnpm install --frozen-lockfile"); - process.exit(1); -} - -const { - getMenuItem, - getWindowsDirs, - getDarwinDirs, - getLinuxDirs, - pathToBranch, -} = require("./common"); - -switch (process.platform) { - case "win32": - uninstall(getWindowsDirs()); - break; - case "darwin": - uninstall(getDarwinDirs()); - break; - case "linux": - uninstall(getLinuxDirs()); - break; - default: - console.log("Unknown OS"); - break; -} - -async function uninstall(installations) { - const selected = await getMenuItem(installations); - - const useNewMethod = pathToBranch(selected.branch) !== "stable"; - - for (const version of selected.versions) { - const dir = useNewMethod ? path.join(version.path, "..") : version.path; - - // Check if we have write perms to the install directory... - try { - fs.accessSync(selected.location, fs.constants.W_OK); - } catch (e) { - console.error("No write access to", selected.location); - console.error( - "Make sure Discord isn't running. If that doesn't work,", - "try running this script as an administrator:", - "sudo pnpm uninject" - ); - process.exit(1); - } - if (useNewMethod) { - if (!fs.existsSync(path.join(dir, "_app.asar"))) { - console.error( - "Original app.asar (_app.asar) doesn't exist.", - "Is your Discord installation corrupt? Try reinstalling Discord." - ); - process.exit(1); - } - if (fs.existsSync(path.join(dir, "app.asar"))) { - try { - fs.rmSync(path.join(dir, "app.asar"), { force: true, recursive: true }); - } catch (err) { - console.error("Failed to delete app.asar folder"); - throw err; - } - } - try { - fs.renameSync( - path.join(dir, "_app.asar"), - path.join(dir, "app.asar") - ); - } catch (err) { - console.error("Failed to rename _app.asar to app.asar"); - throw err; - } - console.log( - "Successfully unpatched", - version.name - ? `${selected.branch} ${version.name}` - : selected.branch - ); - return; - } - if (fs.existsSync(dir)) { - fs.rmSync(dir, { recursive: true }); - } - console.log( - "Successfully unpatched", - version.name - ? `${selected.branch} ${version.name}` - : selected.branch - ); - } -} |