···
7
-
import Module from "module";
7
+
import Module from "node:module";
import { constants } from "@moonlight-mod/types";
import { readConfig } from "@moonlight-mod/core/config";
import { getExtensions } from "@moonlight-mod/core/extension";
···
} from "@moonlight-mod/core/extension/loader";
16
-
import EventEmitter from "events";
16
+
import EventEmitter from "node:events";
17
+
import { join, resolve } from "node:path";
const logger = new Logger("injector");
let oldPreloadPath: string | undefined;
let corsAllow: string[] = [];
let isMoonlightDesktop = false;
24
+
let hasOpenAsar = false;
25
+
let openAsarConfigPreload: string | undefined;
ipcMain.on(constants.ipcGetOldPreloadPath, (e) => {
e.returnValue = oldPreloadPath;
···
headers[csp] = [stringified];
80
+
function removeOpenAsarEventIfPresent(eventHandler: (...args: any[]) => void) {
81
+
const code = eventHandler.toString();
82
+
if (code.indexOf("bw.webContents.on('dom-ready'") > -1) {
83
+
electron.app.off("browser-window-created", eventHandler);
class BrowserWindow extends ElectronBrowserWindow {
constructor(opts: BrowserWindowConstructorOptions) {
oldPreloadPath = opts.webPreferences!.preload;
80
-
opts.webPreferences!.preload = require.resolve("./node-preload.js");
91
+
// Only overwrite preload if its the actual main client window
92
+
if (opts.webPreferences!.preload!.indexOf("discord_desktop_core") > -1) {
93
+
opts.webPreferences!.preload = require.resolve("./node-preload.js");
96
+
// Event for modifying window options
moonlightHost.events.emit("window-options", opts);
101
+
// Event for when a window is created
moonlightHost.events.emit("window-created", this);
this.webContents.session.webRequest.onHeadersReceived((details, cb) => {
if (details.responseHeaders != null) {
106
+
// Patch CSP so things can use externally hosted assets
if (details.resourceType === "mainFrame") {
patchCsp(details.responseHeaders);
111
+
// Allow plugins to bypass CORS for specific URLs
if (corsAllow.some((x) => details.url.startsWith(x))) {
details.responseHeaders["access-control-allow-origin"] = ["*"];
···
cb({ cancel: false, responseHeaders: details.responseHeaders });
121
+
// Remove DOM injections
122
+
// Settings can still be opened via:
123
+
// `DiscordNative.ipc.send("DISCORD_UPDATED_QUOTES","o")`
124
+
// @ts-expect-error Electron internals
125
+
const events = electron.app._events["browser-window-created"];
126
+
if (Array.isArray(events)) {
127
+
for (const event of events) {
128
+
removeOpenAsarEventIfPresent(event);
130
+
} else if (events != null) {
131
+
removeOpenAsarEventIfPresent(events);
134
+
// Config screen fails to context bridge properly
135
+
// Less than ideal, but better than disabling it everywhere
136
+
if (opts.webPreferences!.preload === openAsarConfigPreload) {
137
+
opts.webPreferences!.sandbox = false;
···
118
-
// "aight i'm writing exclusively C# from now on and never touching JavaScript again"
export async function inject(asarPath: string) {
isMoonlightDesktop = asarPath === "moonlightDesktop";
···
197
+
// Check if we're running with OpenAsar
199
+
require.resolve(join(asarPath, "updater", "updater.js"));
200
+
hasOpenAsar = true;
201
+
openAsarConfigPreload = resolve(asarPath, "config", "preload.js");
202
+
// eslint-disable-next-line no-empty
206
+
// Disable command line switch injection
207
+
// I personally think that the command line switches should be vetted by
208
+
// the user and not just "trust that these are sane defaults that work
209
+
// always". I'm not hating on Ducko or anything, I'm just opinionated.
210
+
// Someone can always make a command line modifier plugin, thats the point
211
+
// of having host modules.
213
+
const cmdSwitchesPath = require.resolve(
214
+
join(asarPath, "cmdSwitches.js")
216
+
require.cache[cmdSwitchesPath] = new Module(
218
+
require.cache[require.resolve(asarPath)]
220
+
require.cache[cmdSwitchesPath]!.exports = () => {};
222
+
logger.error("Failed to disable OpenAsar's command line flags:", error);
global.moonlightHost.processedExtensions = await loadExtensions(extensions);
await loadProcessedExtensions(global.moonlightHost.processedExtensions);
162
-
logger.error("Failed to inject", e);
231
+
logger.error("Failed to inject:", error);
if (isMoonlightDesktop) return;
// Need to do this instead of require() or it breaks require.main
167
-
// @ts-expect-error why are you not documented
237
+
// @ts-expect-error Module internals
Module._load(asarPath, Module, true);
···
190
-
// exports is a getter only on Windows, let's do some cursed shit instead
260
+
// exports is a getter only on Windows, recreate export cache instead
const electronPath = require.resolve("electron");
const cachedElectron = require.cache[electronPath]!;
require.cache[electronPath] = new Module(cachedElectron.id, require.main);