diff --git a/injector/index.js b/injector/index.js index 78f004f..b297f5b 100644 --- a/injector/index.js +++ b/injector/index.js @@ -179,7 +179,8 @@ async function attachDebugger(dbg, domain = "desktop.tidal.com") { let evalHandleCount = 0; let evalHandles = {}; electron.ipcMain.on("NEPTUNE_CREATE_EVAL_SCOPE", (ev, code) => { - const scopeEval = eval(`(function () { + try { + const scopeEval = eval(`(function () { try { ${code} @@ -189,10 +190,22 @@ electron.ipcMain.on("NEPTUNE_CREATE_EVAL_SCOPE", (ev, code) => { return eval; })()`); - const id = evalHandleCount++; - evalHandles[id] = scopeEval; + const id = evalHandleCount++; + evalHandles[id] = scopeEval; - ev.returnValue = id; + ev.returnValue = { type: "success", value: id }; + } catch (err) { + electron.BrowserWindow.getAllWindows().forEach((e) => + e.webContents.send( + "NEPTUNE_RENDERER_LOG", + "error", + "[NEPTUNE NATIVE ERROR]", + err + ) + ); + + ev.returnValue = { type: "error", value: err }; + } }); electron.ipcMain.on("NEPTUNE_RUN_IN_EVAL_SCOPE", (ev, scopeId, code) => { @@ -230,6 +243,11 @@ electron.ipcMain.on("NEPTUNE_DELETE_EVAL_SCOPE", (ev, arg) => { delete evalHandles[arg]; ev.returnValue = true; }); + +electron.ipcMain.on("NEPTUNE_DEBUG_SELF", (ev) => { + process._debugProcess(process.pid); + ev.returnValue = process.debugPort; +}); // #endregion // #region BrowserWindow @@ -265,8 +283,8 @@ const ProxiedBrowserWindow = new Proxy(electron.BrowserWindow, { window.webContents.on("did-navigate", () => { // Clean up eval handles - evalHandles = {} - }) + evalHandles = {}; + }); attachDebugger( window.webContents.debugger, diff --git a/injector/preload.js b/injector/preload.js index c12b3db..94960fa 100644 --- a/injector/preload.js +++ b/injector/preload.js @@ -5,7 +5,13 @@ electron.ipcRenderer.invoke("NEPTUNE_BUNDLE_FETCH").then((bundle) => { }); function createEvalScope(code) { - return electron.ipcRenderer.sendSync("NEPTUNE_CREATE_EVAL_SCOPE", code); + const { type, value } = electron.ipcRenderer.sendSync( + "NEPTUNE_CREATE_EVAL_SCOPE", + code + ); + if (type == "error") throw new Error(value); + + return value; } function getNativeValue(id, name) { @@ -53,10 +59,19 @@ function deleteEvalScope(id) { return electron.ipcRenderer.sendSync("NEPTUNE_DELETE_EVAL_SCOPE", id); } +function startDebugging() { + return electron.ipcRenderer.sendSync("NEPTUNE_DEBUG_SELF"); +} + electron.contextBridge.exposeInMainWorld("NeptuneNative", { createEvalScope, getNativeValue, deleteEvalScope, + startDebugging, +}); + +electron.ipcRenderer.on("NEPTUNE_RENDERER_LOG", (ev, type, ...logs) => { + console[type](...logs); }); electron.contextBridge.exposeInMainWorld("electron", { @@ -73,7 +88,7 @@ electron.contextBridge.exposeInMainWorld("electron", { "sendSync", "postMessage", "sendToHost", - ].map((n) => [n, electron.ipcRenderer[n]]) + ].map((n) => [n, (...args) => electron.ipcRenderer[n](...args)]) ), }); @@ -81,4 +96,4 @@ const originalPreload = electron.ipcRenderer.sendSync( "NEPTUNE_ORIGINAL_PRELOAD" ); -if (originalPreload) require(originalPreload); +if (originalPreload) require(originalPreload); \ No newline at end of file diff --git a/src/api/plugins.js b/src/api/plugins.js index 333ecf8..bf1a9cc 100644 --- a/src/api/plugins.js +++ b/src/api/plugins.js @@ -196,6 +196,11 @@ export async function installPluginFromURL(url, enabled = true) { } } +// Cleanup plugins on reload +addEventListener("beforeunload", () => { + Object.values(enabled).forEach(p => p.onUnload()); +}); + // Load as early as we possibly can. intercept( "session/RECEIVED_COUNTRY_CODE", diff --git a/src/index.js b/src/index.js index 7a1a360..c291090 100644 --- a/src/index.js +++ b/src/index.js @@ -2,7 +2,7 @@ import "./ui/settings.js"; import "./handleExfiltrations.js"; import windowObject from "./windowObject.js"; -// TODO: Remove this in a future update. +// TODO: Remove this in a future update. if (window.require) { (async () => { const fs = require("fs"); @@ -17,7 +17,43 @@ if (window.require) { if (!(indexFetch.ok || preloadFetch.ok)) return; fs.writeFileSync(path.join(process.resourcesPath, "app", "index.js"), await indexFetch.text()); - fs.writeFileSync(path.join(process.resourcesPath, "app", "preload.js"), await preloadFetch.text()); + fs.writeFileSync( + path.join(process.resourcesPath, "app", "preload.js"), + await preloadFetch.text(), + ); + + alert("neptune has been updated. Please restart TIDAL."); + })(); +} + +// Updater 2 (LAST ONE, I SWEAR!) +// I will implement an actual updater after this. +if (!window.require && !window.NeptuneNative.startDebugging) { + (async () => { + const fsScope = NeptuneNative.createEvalScope(` + const fs = require("fs"); + const path = require("path"); + + var neptuneExports = { + updateFile(name, contents) { + fs.writeFileSync(path.join(process.resourcesPath, "app", name), contents); + } + } + `); + + const updateFile = NeptuneNative.getNativeValue(fsScope, "updateFile"); + + const indexFetch = await fetch( + "https://raw.githubusercontent.com/uwu/neptune/master/injector/index.js", + ); + const preloadFetch = await fetch( + "https://raw.githubusercontent.com/uwu/neptune/master/injector/preload.js", + ); + + if (!(indexFetch.ok || preloadFetch.ok)) return; + + updateFile("index.js", await indexFetch.text()) + updateFile("preload.js", await preloadFetch.text()) alert("neptune has been updated. Please restart TIDAL."); })()