diff --git a/preload/src/api/https.js b/preload/src/api/https.js index f86904f4..2cc2a0cf 100644 --- a/preload/src/api/https.js +++ b/preload/src/api/https.js @@ -1,21 +1,25 @@ import * as https from "https"; const methods = ["get", "put", "post", "delete"]; +const redirectCodes = new Set([301, 302, 307, 308]); const headersToClone = ["statusCode", "statusMessage", "url", "headers", "method", "aborted", "complete", "rawHeaders", "end"]; -const request = function (url, options, callback) { - let responseObject = undefined; - let pipe = undefined; - +const makeRequest = (url, options, callback, setReq) => { const req = https.request(url, Object.assign({method: "GET"}, options), res => { + if (redirectCodes.has(res.statusCode) && res.headers.location) { + const final = new URL(res.headers.location); + + for (const [key, value] of new URL(url).searchParams.entries()) { + final.searchParams.set(key, value); + } + + return makeRequest(final.toString(), options, callback, setReq); + } + const chunks = []; let error = null; - responseObject = res; - - if (pipe) { - res.pipe(pipe); - } + setReq(res, req); res.addListener("error", err => {error = err;}); @@ -30,11 +34,25 @@ const request = function (url, options, callback) { req.end(); }); }); - req.end(); +} + +const request = function (url, options, callback) { + let responseObject = undefined; + let reqObject = null; + let pipe = null; + + makeRequest(url, options, callback, (req, res) => { + reqObject = req; + responseObject = res; + + if (pipe) { + res.pipe(pipe); + } + }); return { - end() {req.end();}, + end() {reqObject?.end();}, pipe(fsStream) { if (!responseObject) { pipe = fsStream; diff --git a/preload/src/index.js b/preload/src/index.js index 16647497..b64aa9f3 100644 --- a/preload/src/index.js +++ b/preload/src/index.js @@ -1,10 +1,12 @@ import {contextBridge} from "electron"; +import patchDefine from "./patcher"; import newProcess from "./process"; import * as BdApi from "./api"; import init from "./init"; +patchDefine(); + let hasInitialized = false; -contextBridge.exposeInMainWorld("BetterDiscord", BdApi); contextBridge.exposeInMainWorld("process", newProcess); contextBridge.exposeInMainWorld("BetterDiscordPreload", () => { if (hasInitialized) return null; @@ -12,4 +14,4 @@ contextBridge.exposeInMainWorld("BetterDiscordPreload", () => { return BdApi; }); -init(); \ No newline at end of file +init(); diff --git a/preload/src/patcher.js b/preload/src/patcher.js new file mode 100644 index 00000000..1117adfa --- /dev/null +++ b/preload/src/patcher.js @@ -0,0 +1,54 @@ +import {webFrame} from "electron"; + +export default function () { + const patcher = function () { + const chunkName = "webpackChunkdiscord_app"; + const predefine = function (target, prop, effect) { + const value = target[prop]; + Object.defineProperty(target, prop, { + get() {return value;}, + set(value) { + Object.defineProperty(target, prop, { + value, + configurable: true, + enumerable: true, + writable: true + }); + + try { + effect(value); + } catch (error) { + console.error(error); + } + + return value; + }, + configurable: true + }); + }; + + if (!Reflect.has(window, chunkName)) { + predefine(window, chunkName, instance => { + predefine(instance, "push", () => { + instance.push([[Symbol()], {}, require => { + require.d = (target, exports) => { + for (const key in exports) { + if (!Reflect.has(exports, key) || target[key]) continue; + + Object.defineProperty(target, key, { + get: exports[key], + enumerable: true, + configurable: true + }); + } + } + }]); + + instance.pop(); + }); + }); + } + }; + + webFrame.top.executeJavaScript("(" + patcher + ")()"); +}