Skip to content
This repository has been archived by the owner on Jun 27, 2021. It is now read-only.

Commit

Permalink
Merge pull request #155 from MasicoreLord/beta-patch
Browse files Browse the repository at this point in the history
Patch for Discord Electron Security Update (e.g. Canary currently)
  • Loading branch information
joe27g committed Feb 9, 2021
2 parents fa388d3 + f14309e commit 8acb2a0
Show file tree
Hide file tree
Showing 8 changed files with 107 additions and 67 deletions.
11 changes: 7 additions & 4 deletions bd_shit.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,13 @@ const fs = require('fs');
const Module = require('module').Module;
const originalRequire = Module._extensions['.js'];
const EDPlugin = require('./plugin');
const electron = require('electron');

const splitRegex = /[^\S\r\n]*?(?:\r\n|\n)[^\S\r\n]*?\*[^\S\r\n]?/;
const escapedAtRegex = /^\\@/;
module.exports = class BDManager {

static async setup(currentWindow) {
this.currentWindow = currentWindow;
static async setup() {
this.defineGlobals();
this.jqueryElement = document.createElement('script');
this.jqueryElement.src = `//ajax.googleapis.com/ajax/libs/jquery/2.0.0/jquery.min.js`;
Expand All @@ -23,7 +23,9 @@ module.exports = class BDManager {
});
this.observer.observe(document, {childList: true, subtree: true});

this.currentWindow.webContents.on('did-navigate-in-page', BDManager.onSwitch);
//this.currentWindow.webContents.on('did-navigate-in-page', BDManager.onSwitch);
electron.ipcRenderer.invoke('bd-navigate-page-listener', BDManager.onSwitch);


fs.readFile(path.join(process.env.injDir, 'bd.css'), (err, text) => {
if (err) return console.error(err);
Expand All @@ -36,7 +38,8 @@ module.exports = class BDManager {
static destroy() {
EDApi.clearCSS('BDManager');
this.observer.disconnect();
this.currentWindow.webContents.removeEventListener('did-navigate-in-page', BDManager.onSwitch);
//this.currentWindow.webContents.removeEventListener('did-navigate-in-page', BDManager.onSwitch);
electron.ipcRenderer.invoke('remove-bd-navigate-page-listener', BDManager.onSwitch);
this.jqueryElement.remove();
Module._extensions['.js'] = originalRequire;
}
Expand Down
91 changes: 47 additions & 44 deletions dom_shit.js
Original file line number Diff line number Diff line change
@@ -1,15 +1,19 @@
const path = window.require('path');
const fs = window.require('fs');
const electron = window.require('electron');
const Module = window.require('module').Module;
Module.globalPaths.push(path.resolve(electron.remote.app.getAppPath(), 'node_modules'));
const currentWindow = electron.remote.getCurrentWindow();
if (currentWindow.__preload) {
process.electronBinding('command_line').appendSwitch('preload', currentWindow.__preload);
electron.contextBridge.exposeInMainWorld = (key, val) => window[key] = val; // Expose DiscordNative
require(currentWindow.__preload);
const path = require('path');
const fs = require('fs');
const electron = require('electron');

const mainProcessInfo = JSON.parse(electron.ipcRenderer.sendSync('main-process-info'));
const Module = require('module');
Module.globalPaths.push(mainProcessInfo.originalNodeModulesPath);
if (mainProcessInfo.originalPreloadScript) {
process.electronBinding('command_line').appendSwitch('preload', mainProcessInfo.originalPreloadScript);
// This hack is no longer needed due to context isolation having to be on
//electron.contextBridge.exposeInMainWorld = (key, val) => window[key] = val; // Expose DiscordNative
require(mainProcessInfo.originalPreloadScript);
}

//electron.ipcRenderer.sendSync('current-web-contents');

//Get inject directory
if (!process.env.injDir) process.env.injDir = __dirname;

Expand Down Expand Up @@ -122,13 +126,16 @@ process.once('loaded', async () => {
ED.plugins = plugins;
c.log(`Plugins validated.`);

while (!window.webpackJsonp)
await c.sleep(100); // wait until this is loaded in order to use it for modules

// work-around to wait for webpack
while (true) {
await c.sleep(100);
if(electron.webFrame.top.context.window && electron.webFrame.top.context.window.webpackJsonp) break;
};

ED.webSocket = window._ws;

/* Add helper functions that make plugins easy to create */
window.req = window.webpackJsonp.push([[], {
/* Add helper functions that make plugins easy to create */
window.req = electron.webFrame.top.context.window.webpackJsonp.push([[], {
'__extra_id__': (module, exports, req) => module.exports = req
}, [['__extra_id__']]]);
delete window.req.m['__extra_id__'];
Expand Down Expand Up @@ -164,27 +171,32 @@ process.once('loaded', async () => {
c.log(`Modules done loading (${Object.keys(window.req.c).length})`);

if (ED.config.bdPlugins) {
await require('./bd_shit').setup(currentWindow);
c.log(`Preparing BD plugins...`);
for (const i in pluginFiles) {
if (!pluginFiles[i].endsWith('.js') || !pluginFiles[i].endsWith('.plugin.js')) continue;
let p;
const pName = pluginFiles[i].replace(/\.js$/, '');
try {
p = require(path.join(process.env.injDir, 'plugins', pName));
if (typeof p.name !== 'string' || typeof p.load !== 'function') {
throw new Error('Plugin must have a name and load() function.');
try {
await require('./bd_shit').setup();
c.log(`Preparing BD plugins...`);
for (const i in pluginFiles) {
if (!pluginFiles[i].endsWith('.js') || !pluginFiles[i].endsWith('.plugin.js')) continue;
let p;
const pName = pluginFiles[i].replace(/\.js$/, '');
try {
p = require(path.join(process.env.injDir, 'plugins', pName));
if (typeof p.name !== 'string' || typeof p.load !== 'function') {
throw new Error('Plugin must have a name and load() function.');
}
plugins[pName] = Object.assign(p, {id: pName});
}
catch (err) {
c.warn(`Failed to load ${pluginFiles[i]}: ${err}\n${err.stack}`, p);
}
plugins[pName] = Object.assign(p, {id: pName});
}
catch (err) {
c.warn(`Failed to load ${pluginFiles[i]}: ${err}\n${err.stack}`, p);
for (const id in plugins) {
if (!plugins[id] || !plugins[id].name || typeof plugins[id].load !== 'function') {
c.info(`Skipping invalid plugin: ${id}`); delete plugins[id]; continue;
}
}
}
for (const id in plugins) {
if (!plugins[id] || !plugins[id].name || typeof plugins[id].load !== 'function') {
c.info(`Skipping invalid plugin: ${id}`); delete plugins[id]; continue;
}
catch (err) {
c.warn(`Failed to load BD plugins support: ${err}\n${err.stack}`);
}
}

Expand All @@ -210,17 +222,8 @@ process.once('loaded', async () => {
EDApi.monkeyPatch(ht, 'showToken', window.fixedShowToken);
if (!ED.localStorage.getItem('token') && ht.getToken())
window.fixedShowToken(); // prevent you from being logged out for no reason

// change the console warning to be more fun
const wc = require('electron').remote.getCurrentWebContents();
wc.removeAllListeners('devtools-opened');
wc.on('devtools-opened', () => {
console.log('%cHold Up!', 'color: #FF5200; -webkit-text-stroke: 2px black; font-size: 72px; font-weight: bold;');
console.log('%cIf you\'re reading this, you\'re probably smarter than most Discord developers.', 'font-size: 16px;');
console.log('%cPasting anything in here could actually improve the Discord client.', 'font-size: 18px; font-weight: bold; color: red;');
console.log('%cUnless you understand exactly what you\'re doing, keep this window open to browse our bad code.', 'font-size: 16px;');
console.log('%cIf you don\'t understand exactly what you\'re doing, you should come work with us: https://discordapp.com/jobs', 'font-size: 16px;');
});
// expose stuff for devtools
Object.assign(electron.webFrame.top.context.window, {ED, EDApi, BdApi});
});


Expand Down Expand Up @@ -577,4 +580,4 @@ window.BdApi.Themes = new class AddonAPI {
reload() {}
get() {return null;}
getAll() {return [];}
};
};
25 changes: 16 additions & 9 deletions injection.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
require('./main_process_shit');
const electron = require('electron');
const path = require('path');
electron.app.commandLine.appendSwitch("no-force-async-hooks-checks");
Expand All @@ -11,23 +12,29 @@ electron.session.defaultSession.webRequest.onHeadersReceived(function(details, c

class BrowserWindow extends electron.BrowserWindow {
constructor(originalOptions) {
if (!originalOptions || !originalOptions.webPreferences || !originalOptions.title) return super(originalOptions); // eslint-disable-line constructor-super
let win = new electron.BrowserWindow(originalOptions);
if (!originalOptions || !originalOptions.webPreferences || !originalOptions.title) return win; // eslint-disable-line constructor-super
const originalPreloadScript = originalOptions.webPreferences.preload;

// Make sure Node integration is enabled
originalOptions.webPreferences.nodeIntegration = true;
// Make sure remote module is enabled
originalOptions.webPreferences.enableRemoteModule = true;
// Make sure context isolation is disabled
originalOptions.webPreferences.contextIsolation = false;
originalOptions.webPreferences.preload = path.join(process.env.injDir, 'dom_shit.js');
originalOptions.webPreferences.transparency = true;

super(originalOptions);
this.__preload = originalPreloadScript;
// change the console warning to be more fun
win.webContents.on('devtools-opened', (event) => {
console.log('%cHold Up!', 'color: #FF5200; -webkit-text-stroke: 2px black; font-size: 72px; font-weight: bold;');
console.log('%cIf you\'re reading this, you\'re probably smarter than most Discord developers.', 'font-size: 16px;');
console.log('%cPasting anything in here could actually improve the Discord client.', 'font-size: 18px; font-weight: bold; color: red;');
console.log('%cUnless you understand exactly what you\'re doing, keep this window open to browse our bad code.', 'font-size: 16px;');
console.log('%cIf you don\'t understand exactly what you\'re doing, you should come work with us: https://discordapp.com/jobs', 'font-size: 16px;');
});
win = new electron.BrowserWindow(originalOptions);
win.webContents.__preload = originalPreloadScript;
return win;
}
}

BrowserWindow.webContents;

const electron_path = require.resolve('electron');
Object.assign(BrowserWindow, electron.BrowserWindow); // Assigns the new chrome-specific ones

Expand Down
24 changes: 24 additions & 0 deletions main_process_shit.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
const electron = require('electron');
const ipcMain = require('electron').ipcMain;
const path = require('path');

ipcMain.on('main-process-info', (event, arg) => {
event.returnValue = `{
"originalNodeModulesPath": "${path.resolve(electron.app.getAppPath(), 'node_modules')}",
"originalPreloadScript": "${event.sender.__preload}"
}`
});

ipcMain.on('main-process-utils', (event, arg) => {
event.returnValue = `{
"dialog": "${electron.dialog}"
}`
});

ipcMain.handle('bd-navigate-page-listener', (event, arg) => {
event.sender.getOwnerBrowserWindow().webContents.on('did-navigate-in-page', arg);
})

ipcMain.handle('remove-bd-navigate-page-listener', (event, arg) => {
event.sender.getOwnerBrowserWindow().webContents.removeEventListener('did-navigate-in-page', arg);
})
3 changes: 2 additions & 1 deletion plugins/avatar_links.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@ module.exports = new Plugin({
// Make sure it's already in the DOM
await new Promise(r => {setTimeout(r, 5)});
const theMenu = document.querySelector('.'+cm.menu);
const reactData = theMenu.__reactInternalInstance$;

const reactData = theMenu[Object.keys(theMenu).find(key => key.startsWith("__reactInternalInstance") || key.startsWith("__reactFiber"))];

let label = "";
let url = "";
Expand Down
12 changes: 7 additions & 5 deletions plugins/direct_download.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
const Plugin = require('../plugin');

// contains modified code from https://stackoverflow.com/a/47820271
const { dialog } = require('electron').remote;
const ipcRenderer = require('electron').ipcRenderer;
const { dialog } = JSON.parse(ipcRenderer.sendSync('main-process-utils'));
const http = require('https');
const fs = require('fs');
let ttM = {}, iteM = {};
Expand Down Expand Up @@ -76,20 +77,21 @@ module.exports = new Plugin({
this._contClass = EDApi.findModule('embedWrapper').container;
ttM = EDApi.findModule('tooltipPointer');
iteM = EDApi.findModule('hideInteraction');
document.addEventListener('contextmenu', this.listener);
Dispatcher = EDApi.findModule("dispatch");
Dispatcher.subscribe("CONTEXT_MENU_OPEN", this.listener);
},
listener(e) {
if (document.getElementsByClassName(this._cmClass).length == 0) setTimeout(() => module.exports.onContextMenu(e), 0);
else this.onContextMenu(e);
},
onContextMenu(e) {
e = e.contextMenu;
const messageGroup = e.target.closest('.'+this._contClass);
const parentElem = e.target.parentElement;
const guildWrapper = EDApi.findModule('childWrapper').wrapper;
const memberAvatar = EDApi.findModule('nameAndDecorators').avatar;

if (e.target.localName != 'a' && e.target.localName != 'img' && e.target.localName != 'video' && !messageGroup && !e.target.className.includes(guildWrapper) && !parentElem.className.includes(memberAvatar) && !e.target.className.includes('avatar-')) return;

let saveLabel = 'Download',
url = e.target.poster || e.target.style.backgroundImage.substring(e.target.style.backgroundImage.indexOf(`'`) + 1, e.target.style.backgroundImage.lastIndexOf(`'`)) || e.target.href || e.target.src;

Expand Down Expand Up @@ -127,6 +129,6 @@ module.exports = new Plugin({
setTimeout(() => addMenuItem(url, saveLabel, fileName, fileExtension), 5);
},
unload: function() {
document.removeEventListener('contextmenu', this.listener);
Dispatcher.unsubscribe("CONTEXT_MENU_OPEN", this.listener);
}
});
4 changes: 2 additions & 2 deletions plugins/ed_settings.js
Original file line number Diff line number Diff line change
Expand Up @@ -354,7 +354,7 @@ module.exports = new Plugin({

return e(Button, {size: Button.Sizes.SMALL, color: Button.Colors.GREEN, style: {margin: '0 5px', display: 'inline-block'}, onClick: e => {
setString("Opening...");
const sucess = require("electron").shell.openItem(
const sucess = require("electron").shell.openPath(
e.shiftKey ?
process.env.injDir :
require("path").join(process.env.injDir, "plugins")
Expand Down Expand Up @@ -420,7 +420,7 @@ module.exports = new Plugin({
const DiscordUIGenerator = {
reactMarkdownRules: (() => {
const simpleMarkdown = EDApi.findModule("markdownToReact");
const rules = window._.clone(simpleMarkdown.defaultRules);
const rules = require("electron").webFrame.top.context.window._.clone(simpleMarkdown.defaultRules);

rules.paragraph.react = (node, output, state) => {
return e(Fragment, null, output(node.content, state))
Expand Down
4 changes: 2 additions & 2 deletions plugins/hidden_channels.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ module.exports = new Plugin({
ai = EDApi.findModule('actionIcon');

const getUser = EDApi.findModule('getCurrentUser').getCurrentUser;
const getAllChannels = EDApi.findModule('getChannels').getChannels;
const getAllChannels = EDApi.findModule('getMutableGuildChannels').getMutableGuildChannels;
const can = EDApi.findModule('computePermissions').can;

g_dc = EDApi.findModule('getDefaultChannel');
Expand Down Expand Up @@ -137,7 +137,7 @@ module.exports = new Plugin({
return egg;
});*/

const cancan = EDApi.findModuleByProps('can', 'canUser').can;
const cancan = EDApi.findModuleByProps('can').can;
gsr = EDApi.findModuleByDisplayName("FluxContainer(GuildSettingsRoles)").prototype;
EDApi.monkeyPatch(gsr, 'render', b => {
const egg = b.callOriginalMethod(b.methodArguments);
Expand Down

0 comments on commit 8acb2a0

Please sign in to comment.