From 3240c6c25ba5bbc55ac355a72e6b8c42903c8a8e Mon Sep 17 00:00:00 2001 From: Zack Rauen Date: Sun, 28 Feb 2021 19:19:25 -0500 Subject: [PATCH] Enable loading in context isolation --- .eslintrc | 5 +-- src/builtins/developer/reactdevtools.js | 54 ++++++++++++------------- src/builtins/windowprefs.js | 5 +-- src/data/config.js | 9 ++++- src/modules/addonmanager.js | 29 ++++++++----- src/modules/core.js | 15 +++---- src/modules/datastore.js | 10 ++--- src/modules/domtools.js | 9 ----- src/modules/pluginapi.js | 4 +- src/modules/pluginmanager.js | 47 ++++++++++++++++----- src/modules/thememanager.js | 10 ++--- src/structs/psconnection.js | 22 +++++----- 12 files changed, 122 insertions(+), 97 deletions(-) diff --git a/.eslintrc b/.eslintrc index c7e3905e..df48c00e 100644 --- a/.eslintrc +++ b/.eslintrc @@ -10,11 +10,10 @@ }, "env": { "browser": true, - "node": true, - "jquery": true + "node": true }, "parserOptions": { - "ecmaVersion": 2017, + "ecmaVersion": 2020, "sourceType": "module", "ecmaFeatures": { "jsx": true diff --git a/src/builtins/developer/reactdevtools.js b/src/builtins/developer/reactdevtools.js index e2631b3e..e16a1ceb 100644 --- a/src/builtins/developer/reactdevtools.js +++ b/src/builtins/developer/reactdevtools.js @@ -6,7 +6,7 @@ const electron = require("electron"); const fs = require("fs"); const path = require("path"); -const BrowserWindow = electron.remote.BrowserWindow; +// const BrowserWindow = electron.remote.BrowserWindow; export default new class ReactDevTools extends Builtin { get name() {return "ReactDevTools";} @@ -14,41 +14,41 @@ export default new class ReactDevTools extends Builtin { get id() {return "reactDevTools";} initialize() { - super.initialize(); - this.findExtension(); + // super.initialize(); + // this.findExtension(); } findExtension() { - let extensionPath = ""; - if (process.platform === "win32") extensionPath = path.resolve(process.env.LOCALAPPDATA, "Google/Chrome/User Data"); - else if (process.platform === "linux") extensionPath = path.resolve(process.env.HOME, ".config/google-chrome"); - else if (process.platform === "darwin") extensionPath = path.resolve(process.env.HOME, "Library/Application Support/Google/Chrome"); - else extensionPath = path.resolve(process.env.HOME, ".config/chromium"); - extensionPath += "/Default/Extensions/fmkadmapgofadopljbjfkapdkoienihi/"; - if (fs.existsSync(extensionPath)) { - const versions = fs.readdirSync(extensionPath); - extensionPath = path.resolve(extensionPath, versions[versions.length - 1]); - } - this.extensionPath = extensionPath; - this.isExtensionInstalled = fs.existsSync(extensionPath); + // let extensionPath = ""; + // if (process.platform === "win32") extensionPath = path.resolve(process.env.LOCALAPPDATA, "Google/Chrome/User Data"); + // else if (process.platform === "linux") extensionPath = path.resolve(process.env.HOME, ".config/google-chrome"); + // else if (process.platform === "darwin") extensionPath = path.resolve(process.env.HOME, "Library/Application Support/Google/Chrome"); + // else extensionPath = path.resolve(process.env.HOME, ".config/chromium"); + // extensionPath += "/Default/Extensions/fmkadmapgofadopljbjfkapdkoienihi/"; + // if (fs.existsSync(extensionPath)) { + // const versions = fs.readdirSync(extensionPath); + // extensionPath = path.resolve(extensionPath, versions[versions.length - 1]); + // } + // this.extensionPath = extensionPath; + // this.isExtensionInstalled = fs.existsSync(extensionPath); } enabled() { - if (!this.isExtensionInstalled) this.findExtension(); - if (!this.isExtensionInstalled) return Modals.alert(Strings.ReactDevTools.notFound, Strings.ReactDevTools.notFoundDetails); + // if (!this.isExtensionInstalled) this.findExtension(); + // if (!this.isExtensionInstalled) return Modals.alert(Strings.ReactDevTools.notFound, Strings.ReactDevTools.notFoundDetails); - try { - const didInstall = BrowserWindow.addDevToolsExtension(this.extensionPath); - if (didInstall) this.log("Successfully installed react devtools."); - else this.error("Couldn't find react devtools in chrome extensions!"); - } - catch (err) { - this.error("Couldn't add the extension!"); - } + // try { + // const didInstall = BrowserWindow.addDevToolsExtension(this.extensionPath); + // if (didInstall) this.log("Successfully installed react devtools."); + // else this.error("Couldn't find react devtools in chrome extensions!"); + // } + // catch (err) { + // this.error("Couldn't add the extension!"); + // } } disabled() { - if (!this.isExtensionInstalled) return; - BrowserWindow.removeDevToolsExtension("React Developer Tools"); + // if (!this.isExtensionInstalled) return; + // BrowserWindow.removeDevToolsExtension("React Developer Tools"); } }; \ No newline at end of file diff --git a/src/builtins/windowprefs.js b/src/builtins/windowprefs.js index c828158c..1aa956f4 100644 --- a/src/builtins/windowprefs.js +++ b/src/builtins/windowprefs.js @@ -25,9 +25,8 @@ export default new class WindowPrefs extends Builtin { confirmText: Strings.Modals.restartNow, cancelText: Strings.Modals.restartLater, onConfirm: () => { - const app = require("electron").remote.app; - app.relaunch(); - app.exit(); + const ipc = require("electron").ipcRenderer; + ipc.send("RELAUNCH"); } }); } diff --git a/src/data/config.js b/src/data/config.js index 20e0a2b2..8670ff52 100644 --- a/src/data/config.js +++ b/src/data/config.js @@ -2,9 +2,14 @@ export default { local: false, localPath: "", minified: true, - version: "0.6.0", branch: "stable", repo: "rauenzi", minSupportedVersion: "0.3.0", - bdVersion: "1.0.0" + bdVersion: "1.0.0", + + // Get from main process + version: "0.6.0", + path: "", + appPath: "", + userData: "" }; \ No newline at end of file diff --git a/src/modules/addonmanager.js b/src/modules/addonmanager.js index e4887c8b..20f64bdd 100644 --- a/src/modules/addonmanager.js +++ b/src/modules/addonmanager.js @@ -16,7 +16,7 @@ const React = DiscordModules.React; const path = require("path"); const fs = require("fs"); const Module = require("module").Module; -Module.globalPaths.push(path.resolve(require("electron").remote.app.getAppPath(), "node_modules")); +// Module.globalPaths.push(path.resolve(require("electron").remote.app.getAppPath(), "node_modules")); const splitRegex = /[^\S\r\n]*?\r?(?:\r\n|\n)[^\S\r\n]*?\*[^\S\r\n]?/; const escapedAtRegex = /^\\@/; @@ -49,14 +49,14 @@ export default class AddonManager { this.windows = new Set(); } - initialize() { + async initialize() { this.originalRequire = Module._extensions[this.moduleExtension]; Module._extensions[this.moduleExtension] = this.getAddonRequire(); Settings.on(this.collection, this.category, this.id, (enabled) => { if (enabled) this.watchAddons(); else this.unwatchAddons(); }); - return this.loadAllAddons(); + return await this.loadAllAddons(); } // Subclasses should overload this and modify the addon object as needed to fully load it @@ -196,12 +196,21 @@ export default class AddonManager { } // Subclasses should use the return (if not AddonError) and push to this.addonList - loadAddon(filename, shouldToast = false) { + async loadAddon(filename, shouldToast = false) { if (typeof(filename) === "undefined") return; - try {__non_webpack_require__(path.resolve(this.addonFolder, filename));} - catch (error) {return new AddonError(filename, filename, Strings.Addons.compileError, {message: error.message, stack: error.stack});} + try { + const addon = __non_webpack_require__(path.resolve(this.addonFolder, filename)); + await Promise.resolve(addon); + } + catch (error) { + return new AddonError(filename, filename, Strings.Addons.compileError, {message: error.message, stack: error.stack}); + } const addon = __non_webpack_require__(path.resolve(this.addonFolder, filename)); + // console.log(addon); + // await Promise.resolve(addon); + // addon = __non_webpack_require__(path.resolve(this.addonFolder, filename)); + // console.log(addon); if (this.addonList.find(c => c.id == addon.id)) return new AddonError(addon.name, filename, Strings.Addons.alreadyExists.format({type: this.prefix, name: addon.name})); const error = this.initializeAddon(addon); @@ -226,11 +235,11 @@ export default class AddonManager { return true; } - reloadAddon(idOrFileOrAddon, shouldToast = true) { + async reloadAddon(idOrFileOrAddon, shouldToast = true) { const addon = typeof(idOrFileOrAddon) == "string" ? this.addonList.find(c => c.id == idOrFileOrAddon || c.filename == idOrFileOrAddon) : idOrFileOrAddon; const didUnload = this.unloadAddon(addon, shouldToast, true); if (addon && !didUnload) return didUnload; - return this.loadAddon(addon ? addon.filename : idOrFileOrAddon, shouldToast); + return await this.loadAddon(addon ? addon.filename : idOrFileOrAddon, shouldToast); } isLoaded(idOrFile) { @@ -285,7 +294,7 @@ export default class AddonManager { for (const name of results.removed) this.unloadAddon(name); } - loadAllAddons() { + async loadAllAddons() { this.loadState(); const errors = []; const files = fs.readdirSync(this.addonFolder); @@ -313,7 +322,7 @@ export default class AddonManager { // Rename the file and let it go on fs.renameSync(absolutePath, path.resolve(this.addonFolder, newFilename)); } - const addon = this.loadAddon(filename, false); + const addon = await this.loadAddon(filename, false); if (addon instanceof AddonError) errors.push(addon); } diff --git a/src/modules/core.js b/src/modules/core.js index c443bae3..07473a55 100644 --- a/src/modules/core.js +++ b/src/modules/core.js @@ -31,18 +31,15 @@ export default new class Core { }); ipcRenderer.invoke("bd-injector-info").then(injectorInfo => { Config.version = injectorInfo.version; + Config.path = injectorInfo.path; + Config.appPath = injectorInfo.appPath; + Config.userData = injectorInfo.userData; this.checkInjectorUpdate(); }); } get dependencies() { return [ - { - name: "jquery", - type: "script", - url: "https://ajax.googleapis.com/ajax/libs/jquery/2.0.0/jquery.min.js", - backup: "https://cdn.jsdelivr.net/gh/jquery/jquery@2.0.0/jquery.min.js" - }, { name: "bd-stylesheet", type: "style", @@ -85,6 +82,7 @@ export default new class Core { await dependencyPromise; Logger.log("Startup", "Loading Plugins"); + // const pluginErrors = []; const pluginErrors = PluginManager.initialize(); Logger.log("Startup", "Loading Themes"); @@ -175,9 +173,8 @@ export default new class Core { try { const didUpdate = await this.updateInjector(); if (!didUpdate) return onUpdateFailed(); - const app = require("electron").remote.app; - app.relaunch(); - app.exit(); + const ipc = require("electron").ipcRenderer; + ipc.send("RELAUNCH"); } catch (err) { onUpdateFailed(); diff --git a/src/modules/datastore.js b/src/modules/datastore.js index 6516bb98..e7acb8a6 100644 --- a/src/modules/datastore.js +++ b/src/modules/datastore.js @@ -3,7 +3,8 @@ import Utilities from "./utilities"; import Logger from "./logger"; const fs = require("fs"); const path = require("path"); -const releaseChannel = DiscordNative.globals ? DiscordNative.globals.releaseChannel : DiscordNative.app ? DiscordNative.app.getReleaseChannel() : "stable"; +const releaseChannel = window?.DiscordNative?.app?.getReleaseChannel?.() ?? "stable"; +const discordVersion = window?.DiscordNative?.remoteApp?.getVersion?.() ?? "0.0.309"; // Schema // ======================= @@ -82,10 +83,9 @@ export default new class DataStore { get injectionPath() { if (this._injectionPath) return this._injectionPath; - const electron = require("electron").remote.app; - const base = electron.getAppPath(); - const roamingBase = electron.getPath("userData"); - const roamingLocation = path.resolve(roamingBase, electron.getVersion(), "modules", "discord_desktop_core", "injector"); + const base = Config.appPath; + const roamingBase = Config.userData; + const roamingLocation = path.resolve(roamingBase, discordVersion, "modules", "discord_desktop_core", "injector"); const location = path.resolve(base, "..", "app"); const realLocation = fs.existsSync(location) ? location : fs.existsSync(roamingLocation) ? roamingLocation : null; if (!realLocation) return this._injectionPath = null; diff --git a/src/modules/domtools.js b/src/modules/domtools.js index 8af3c0f0..f66d8551 100644 --- a/src/modules/domtools.js +++ b/src/modules/domtools.js @@ -744,13 +744,4 @@ export default class DOMTools { for (let e = 0; e < elements.length; e++) domWrapper.appendChild(elements[e]); return domWrapper; } - - /** - * Resolves the node to an HTMLElement. This is mainly used by library modules. - * @param {(jQuery|Element)} node - node to resolve - */ - static resolveElement(node) { - if (!(node instanceof jQuery) && !(node instanceof Element)) return undefined; - return node instanceof jQuery ? node[0] : node; - } } \ No newline at end of file diff --git a/src/modules/pluginapi.js b/src/modules/pluginapi.js index 4bbbcaa2..0b6cf6e9 100644 --- a/src/modules/pluginapi.js +++ b/src/modules/pluginapi.js @@ -137,8 +137,8 @@ BdApi.findModuleByDisplayName = function(name) { // Gets react instance BdApi.getInternalInstance = function(node) { - if (!(node instanceof window.jQuery) && !(node instanceof Element)) return undefined; - if (node instanceof jQuery) node = node[0]; + // if (!(node instanceof window.jQuery) && !(node instanceof Element)) return undefined; + // if (node instanceof jQuery) node = node[0]; return Utilities.getReactInstance(node); }; diff --git a/src/modules/pluginmanager.js b/src/modules/pluginmanager.js index 185d492e..827f2123 100644 --- a/src/modules/pluginmanager.js +++ b/src/modules/pluginmanager.js @@ -10,7 +10,12 @@ import Modals from "../ui/modals"; import SettingsRenderer from "../ui/settings"; const path = require("path"); -const electronRemote = require("electron").remote; +const electron = require("electron"); +const ipc = electron.ipcRenderer; +const vm = require("vm"); +// const electronRemote = require("electron").remote; + +// window.$ = window.jQuery = function() {} export default new class PluginManager extends AddonManager { get name() {return "PluginManager";} @@ -23,6 +28,7 @@ export default new class PluginManager extends AddonManager { constructor() { super(); + this.promises = {}; this.onSwitch = this.onSwitch.bind(this); this.observer = new MutationObserver((mutations) => { for (let i = 0, mlen = mutations.length; i < mlen; i++) { @@ -31,8 +37,8 @@ export default new class PluginManager extends AddonManager { }); } - initialize() { - const errors = super.initialize(); + async initialize() { + const errors = await super.initialize(); this.setupFunctions(); Settings.registerPanel("plugins", Strings.Panels.plugins, {element: () => SettingsRenderer.getAddonPanel(Strings.Panels.plugins, this.addonList, this.state, { type: this.prefix, @@ -59,13 +65,13 @@ export default new class PluginManager extends AddonManager { unloadPlugin(idOrFileOrAddon) {return this.unloadAddon(idOrFileOrAddon);} loadPlugin(filename) {return this.loadAddon(filename);} - loadAddon(filename) { - const error = super.loadAddon(filename); + async loadAddon(filename) { + const error = await super.loadAddon(filename); if (error) Modals.showAddonErrors({plugins: [error]}); } - reloadPlugin(idOrFileOrAddon) { - const error = this.reloadAddon(idOrFileOrAddon); + async reloadPlugin(idOrFileOrAddon) { + const error = await this.reloadAddon(idOrFileOrAddon); if (error) Modals.showAddonErrors({plugins: [error]}); return typeof(idOrFileOrAddon) == "string" ? this.addonList.find(c => c.id == idOrFileOrAddon || c.filename == idOrFileOrAddon) : idOrFileOrAddon; } @@ -94,9 +100,27 @@ export default new class PluginManager extends AddonManager { getFileModification(module, fileContent, meta) { fileContent += `\nif (module.exports.default) {module.exports = module.exports.default;}\nif (!module.exports.prototype || !module.exports.prototype.start) {module.exports = ${meta.exports || meta.name};}`; - module._compile(fileContent, module.filename); - meta.exports = module.exports; - module.exports = meta; + + window.global = window; + window.module = module; + window.__filename = path.basename(module.filename); + window.__dirname = this.addonFolder; + const wrapped = `(${vm.compileFunction(fileContent, ["exports", "require", "module", "__filename", "__dirname"])})`; + // console.log(module); + module.exports = new Promise(resolve => { + ipc.invoke("EXEC_JS", `${wrapped}(window.module.exports, window.require, window.module, window.__filename, window.__dirname)`).then(() => { + // console.log(window.module); + meta.exports = module.exports; + module.exports = meta; + delete window.module; + delete window.__filename; + delete window.__dirname; + resolve(); + }); + }); + // module._compile(fileContent, module.filename); + // meta.exports = module.exports; + // module.exports = meta; return ""; } @@ -145,7 +169,8 @@ export default new class PluginManager extends AddonManager { } setupFunctions() { - electronRemote.getCurrentWebContents().on("did-navigate-in-page", this.onSwitch.bind(this)); + // electronRemote.getCurrentWebContents().on("did-navigate-in-page", this.onSwitch.bind(this)); + ipc.on("DID_NAVIGATE_IN_PAGE", this.onSwitch); this.observer.observe(document, { childList: true, subtree: true diff --git a/src/modules/thememanager.js b/src/modules/thememanager.js index 0a1c36b7..47abdf8d 100644 --- a/src/modules/thememanager.js +++ b/src/modules/thememanager.js @@ -19,8 +19,8 @@ export default new class ThemeManager extends AddonManager { get prefix() {return "theme";} get language() {return "css";} - initialize() { - const errors = super.initialize(); + async initialize() { + const errors = await super.initialize(); Settings.registerPanel("themes", Strings.Panels.themes, {element: () => SettingsRenderer.getAddonPanel(Strings.Panels.themes, this.addonList, this.state, { type: this.prefix, folder: this.addonFolder, @@ -45,10 +45,10 @@ export default new class ThemeManager extends AddonManager { unloadTheme(idOrFileOrAddon) {return this.unloadAddon(idOrFileOrAddon);} loadTheme(filename) {return this.loadAddon(filename);} - reloadTheme(idOrFileOrAddon) {return this.reloadAddon(idOrFileOrAddon);} + async reloadTheme(idOrFileOrAddon) {return await this.reloadAddon(idOrFileOrAddon);} - loadAddon(filename) { - const error = super.loadAddon(filename); + async loadAddon(filename) { + const error = await super.loadAddon(filename); if (error) Modals.showAddonErrors({themes: [error]}); } diff --git a/src/structs/psconnection.js b/src/structs/psconnection.js index 74227fe7..e55bed93 100644 --- a/src/structs/psconnection.js +++ b/src/structs/psconnection.js @@ -4,7 +4,7 @@ const SortedGuildStore = WebpackModules.getByProps("getSortedGuilds"); const AvatarDefaults = WebpackModules.getByProps("getUserAvatarURL", "DEFAULT_AVATARS"); const InviteActions = WebpackModules.getByProps("acceptInvite"); -const BrowserWindow = require("electron").remote.BrowserWindow; +// const BrowserWindow = require("electron").remote.BrowserWindow; const betterDiscordServer = { name: "BetterDiscord", @@ -140,16 +140,16 @@ export default new class PublicServersConnection { } connect() { - return new Promise(resolve => { - const joinWindow = new BrowserWindow(this.windowOptions); - const url = `https://auth.discordservers.com/connect?scopes=guilds.join&previousUrl=${this.connectEndPoint}`; - joinWindow.webContents.on("did-navigate", (event, navUrl) => { - if (navUrl != this.connectEndPoint) return; - joinWindow.close(); - resolve(); - }); - joinWindow.loadURL(url); - }); + // return new Promise(resolve => { + // const joinWindow = new BrowserWindow(this.windowOptions); + // const url = `https://auth.discordservers.com/connect?scopes=guilds.join&previousUrl=${this.connectEndPoint}`; + // joinWindow.webContents.on("did-navigate", (event, navUrl) => { + // if (navUrl != this.connectEndPoint) return; + // joinWindow.close(); + // resolve(); + // }); + // joinWindow.loadURL(url); + // }); } get windowOptions() {