From 5d80d44fc8c033d0c0d67f471770e41a3d42eab6 Mon Sep 17 00:00:00 2001 From: smartfridge <37928912+smartfrigde@users.noreply.github.com> Date: Sat, 19 Nov 2022 18:23:28 +0100 Subject: [PATCH] Re-add client mods (vencord, shelter) --- package.json | 5 ++- pnpm-lock.yaml | 59 +++++++++++++++++++++++++++- src/.npmrc | 3 ++ src/content/setup.html | 4 +- src/content/splash.html | 21 +++++++++- src/extensions/mods.ts | 6 ++- src/extensions/plugin.ts | 2 +- src/ipc.ts | 8 +++- src/main.ts | 6 +-- src/preload/bridge.ts | 2 + src/preload/preload.ts | 22 ++--------- src/settings/settings.html | 8 ++-- src/utils.ts | 78 +++++++++++++++++++++++++++++++++++--- src/window.ts | 2 +- 14 files changed, 188 insertions(+), 38 deletions(-) create mode 100644 src/.npmrc diff --git a/package.json b/package.json index 8ddec2f..a45b83e 100644 --- a/package.json +++ b/package.json @@ -28,11 +28,12 @@ "homepage": "https://github.com/armcord/armcord#readme", "devDependencies": { "@types/node": "^17.0.42", + "@types/node-fetch": "^2.6.2", "@types/ws": "^8.5.3", "chalk-cli": "^5.0.0", "copyfiles": "^2.4.1", "electron": "^20.1.0", - "electron-builder": "^23.0.3", + "electron-builder": "^23.6.0", "husky": "^8.0.1", "prettier": "^2.7.0", "typescript": "^4.7.3" @@ -40,6 +41,8 @@ "dependencies": { "@pyke/vibe": "^0.3.1", "electron-context-menu": "github:ArmCord/electron-context-menu", + "extract-zip": "^2.0.1", + "node-fetch": "v2", "os-locale": "^6.0.2", "v8-compile-cache": "^2.3.0", "ws": "^8.8.0" diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 1c83e3e..dac7aec 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -3,13 +3,16 @@ lockfileVersion: 5.4 specifiers: '@pyke/vibe': ^0.3.1 '@types/node': ^17.0.42 + '@types/node-fetch': ^2.6.2 '@types/ws': ^8.5.3 chalk-cli: ^5.0.0 copyfiles: ^2.4.1 electron: ^20.1.0 - electron-builder: ^23.0.3 + electron-builder: ^23.6.0 electron-context-menu: github:ArmCord/electron-context-menu + extract-zip: ^2.0.1 husky: ^8.0.1 + node-fetch: v2 os-locale: ^6.0.2 prettier: ^2.7.0 typescript: ^4.7.3 @@ -19,12 +22,15 @@ specifiers: dependencies: '@pyke/vibe': 0.3.1_electron@20.3.1 electron-context-menu: github.com/ArmCord/electron-context-menu/280c81398c02a063f46e3285a9708d8db1a7ce32 + extract-zip: 2.0.1 + node-fetch: 2.6.7 os-locale: 6.0.2 v8-compile-cache: 2.3.0 ws: 8.9.0 devDependencies: '@types/node': 17.0.45 + '@types/node-fetch': 2.6.2 '@types/ws': 8.5.3 chalk-cli: 5.0.0 copyfiles: 2.4.1 @@ -184,6 +190,13 @@ packages: resolution: {integrity: sha512-iiUgKzV9AuaEkZqkOLDIvlQiL6ltuZd9tGcW3gwpnX8JbuiuhFlEGmmFXEXkN50Cvq7Os88IY2v0dkDqXYWVgA==} dev: true + /@types/node-fetch/2.6.2: + resolution: {integrity: sha512-DHqhlq5jeESLy19TYhLakJ07kNumXWjcDdxXsLUMJZ6ue8VZJj4kLPQVE/2mdHh3xZziNF1xppu5lwmS53HR+A==} + dependencies: + '@types/node': 17.0.45 + form-data: 3.0.1 + dev: true + /@types/node/16.11.64: resolution: {integrity: sha512-z5hPTlVFzNwtJ2LNozTpJcD1Cu44c4LNuzaq1mwxmiHWQh2ULdR6Vjwo1UGldzRpzL0yUEdZddnfqGW2G70z6Q==} @@ -335,6 +348,7 @@ packages: /asar/3.2.0: resolution: {integrity: sha512-COdw2ZQvKdFGFxXwX3oYh2/sOsJWJegrdJCGxnN4MZ7IULgRBp9P6665aqj9z1v9VwP4oP1hRBojRDQ//IGgAg==} engines: {node: '>=10.12.0'} + deprecated: Please use @electron/asar moving forward. There is no API change, just a package name change hasBin: true dependencies: chromium-pickle-js: 0.2.0 @@ -380,6 +394,7 @@ packages: /base64-js/1.5.1: resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} + requiresBuild: true dev: true /bluebird-lst/1.0.9: @@ -976,10 +991,12 @@ packages: /fast-deep-equal/3.1.3: resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} + requiresBuild: true dev: true /fast-json-stable-stringify/2.1.0: resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} + requiresBuild: true dev: true /fd-slicer/1.1.0: @@ -1001,6 +1018,15 @@ packages: path-exists: 4.0.0 dev: true + /form-data/3.0.1: + resolution: {integrity: sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg==} + engines: {node: '>= 6'} + dependencies: + asynckit: 0.4.0 + combined-stream: 1.0.8 + mime-types: 2.1.35 + dev: true + /form-data/4.0.0: resolution: {integrity: sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==} engines: {node: '>= 6'} @@ -1351,6 +1377,7 @@ packages: /json-schema-traverse/0.4.1: resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} + requiresBuild: true dev: true /json-stringify-safe/5.0.1: @@ -1557,6 +1584,18 @@ packages: dev: true optional: true + /node-fetch/2.6.7: + resolution: {integrity: sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==} + engines: {node: 4.x || >=6.0.0} + peerDependencies: + encoding: ^0.1.0 + peerDependenciesMeta: + encoding: + optional: true + dependencies: + whatwg-url: 5.0.0 + dev: false + /noms/0.0.0: resolution: {integrity: sha512-lNDU9VJaOPxUmXcLb+HQFeUgQQPtMI24Gt6hgfuMHRJgMRHMF/qZ4HJD3GDru4sSw9IQl2jPjAYnQrdIeLbwow==} dependencies: @@ -1692,6 +1731,7 @@ packages: /punycode/2.1.1: resolution: {integrity: sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==} engines: {node: '>=6'} + requiresBuild: true dev: true /pupa/2.1.1: @@ -2026,6 +2066,10 @@ packages: resolution: {integrity: sha512-Iq25XBt6zD5npPhlLVXGFN3/gyR2/qODcKNNyTMd4vbm39HUaOiAM4PMq0eMVC/Tkxz+Zjdsc55g9yyz+Yq00Q==} engines: {node: '>=6'} + /tr46/0.0.3: + resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==} + dev: false + /trim-newlines/4.0.2: resolution: {integrity: sha512-GJtWyq9InR/2HRiLZgpIKv+ufIKrVrvjQWEj7PxAXNc5dwbNJkqhAUoAGgzRmULAnoOM5EIpveYd3J2VeSAIew==} engines: {node: '>=12'} @@ -2082,6 +2126,7 @@ packages: /uri-js/4.4.1: resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} + requiresBuild: true dependencies: punycode: 2.1.1 dev: true @@ -2122,6 +2167,17 @@ packages: dev: true optional: true + /webidl-conversions/3.0.1: + resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==} + dev: false + + /whatwg-url/5.0.0: + resolution: {integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==} + dependencies: + tr46: 0.0.3 + webidl-conversions: 3.0.1 + dev: false + /which/2.0.2: resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} engines: {node: '>= 8'} @@ -2158,6 +2214,7 @@ packages: /xmlbuilder/15.1.1: resolution: {integrity: sha512-yMqGBqtXyeN1e3TGYvgNgDVZ3j84W4cwkOXQswghol6APgZWaff9lnbvN7MHYJOiXsvGPXtjTYJEiC9J2wv9Eg==} engines: {node: '>=8.0'} + requiresBuild: true dev: true /xtend/4.0.2: diff --git a/src/.npmrc b/src/.npmrc new file mode 100644 index 0000000..048b75f --- /dev/null +++ b/src/.npmrc @@ -0,0 +1,3 @@ +node-linker=hoisted +public-hoist-pattern=* +shamefully-hoist=true \ No newline at end of file diff --git a/src/content/setup.html b/src/content/setup.html index 47ecd70..75048c5 100644 --- a/src/content/setup.html +++ b/src/content/setup.html @@ -53,7 +53,9 @@

Select a client mod you want to install:

diff --git a/src/content/splash.html b/src/content/splash.html index f4771d6..383b934 100644 --- a/src/content/splash.html +++ b/src/content/splash.html @@ -47,6 +47,25 @@ console.log("ArmCord is up to date."); } } + + function check() { + if (armcordinternal.installState === "installing") { + text.innerHTML = "Installing mods"; + } else if (armcordinternal.installState === "done") { + return true; + } else if (armcordinternal.installState === "modDownload") { + text.innerHTML = "Updating " + armcord.mods; + } else if (armcordinternal.installState === "none") { + text.innerHTML = "Nothing to install. Starting ArmCord"; + return true; + } else { + return true; + } + } + + while (check() == false) { + console.log("Installing"); + } setTimeout(() => { window.armcord.splashEnd(); switch (window.armcord.channel) { @@ -68,7 +87,7 @@ default: window.location.replace("https://discord.com/app"); } - }, 5000); + }, 3000); } } diff --git a/src/extensions/mods.ts b/src/extensions/mods.ts index 690396e..ad3cae2 100644 --- a/src/extensions/mods.ts +++ b/src/extensions/mods.ts @@ -21,7 +21,11 @@ const unstrictCSP = () => { const cspAllowAll = ["connect-src", "style-src", "img-src", "font-src"]; - const corsAllowUrls = ["https://raw.githubusercontent.com/Cordwood/builds/master/index.js"]; + const corsAllowUrls = [ + "https://raw.githubusercontent.com/Cordwood/builds/master/index.js", + "https://github.com/Vendicated/Vencord/releases/download/devbuild/browser.js", + "https://cors.armcord.xyz/raw.githubusercontent.com/uwu/shelter-builds/main/shelter.js" + ]; electron.session.defaultSession.webRequest.onHeadersReceived(({responseHeaders, url}, done) => { let csp = responseHeaders!["content-security-policy"]; diff --git a/src/extensions/plugin.ts b/src/extensions/plugin.ts index cb1a064..b68be0b 100644 --- a/src/extensions/plugin.ts +++ b/src/extensions/plugin.ts @@ -12,7 +12,7 @@ app.whenReady().then(() => { const manifest = fs.readFileSync(`${userDataPath}/plugins/${file}/manifest.json`, "utf8"); var pluginFile = JSON.parse(manifest); session.defaultSession.loadExtension(`${userDataPath}/plugins/${file}`); - console.log(`%cLoaded ${pluginFile.name} made by ${pluginFile.author}`, "color:red"); + console.log(`[Mod loader] Loaded ${pluginFile.name} made by ${pluginFile.author}`); } catch (err) { console.error(err); } diff --git a/src/ipc.ts b/src/ipc.ts index 0fbaf1f..1dd9080 100644 --- a/src/ipc.ts +++ b/src/ipc.ts @@ -9,11 +9,14 @@ import { getLang, getWindowState, packageVersion, - getDisplayVersion + getDisplayVersion, + modInstallState, + installModLoader } from "./utils"; import {customTitlebar} from "./main"; import {createSettingsWindow} from "./settings/main"; import os from "os"; +import fs from "fs" import path from "path"; export function registerIpc() { ipcMain.on("get-app-path", (event, arg) => { @@ -73,6 +76,9 @@ export function registerIpc() { ipcMain.on("displayVersion", (event) => { event.returnValue = getDisplayVersion(); }); + ipcMain.on("modInstallState", (event) => { + event.returnValue = modInstallState; + }); ipcMain.on("get-package-version", (event) => { event.returnValue = packageVersion; }); diff --git a/src/main.ts b/src/main.ts index d3e8b00..6bcd596 100644 --- a/src/main.ts +++ b/src/main.ts @@ -1,11 +1,10 @@ // Modules to control application life and create native browser window import {app, BrowserWindow, session} from "electron"; import "v8-compile-cache"; -import {getConfig, checkIfConfigExists, injectElectronFlags} from "./utils"; +import {getConfig, checkIfConfigExists, injectElectronFlags, installModLoader} from "./utils"; import "./extensions/mods"; -import "./extensions/plugin"; import "./tray"; -import {createCustomWindow, createNativeWindow, createTransparentWindow} from "./window"; +import {createCustomWindow, createNativeWindow, createTransparentWindow, mainWindow} from "./window"; import path from "path"; export var iconPath: string; export var settings: any; @@ -53,6 +52,7 @@ app.whenReady().then(async () => { } } await init(); + await installModLoader() session.fromPartition("some-partition").setPermissionRequestHandler((webContents, permission, callback) => { if (permission === "notifications") { // Approves the permissions request diff --git a/src/preload/bridge.ts b/src/preload/bridge.ts index 1697584..1b9f32c 100644 --- a/src/preload/bridge.ts +++ b/src/preload/bridge.ts @@ -22,6 +22,7 @@ contextBridge.exposeInMainWorld("armcord", { return result; }), version: ipcRenderer.sendSync("get-app-version", "app-version"), + mods: ipcRenderer.sendSync("clientmod"), packageVersion: ipcRenderer.sendSync("get-package-version", "app-version"), getDisplayMediaSelector: getDisplayMediaSelector, splashEnd: () => ipcRenderer.send("splashEnd"), @@ -31,6 +32,7 @@ contextBridge.exposeInMainWorld("armcord", { if (window.location.href.indexOf("splash.html") > -1 || window.location.href.indexOf("setup.html") > -1) { contextBridge.exposeInMainWorld("armcordinternal", { restart: () => ipcRenderer.send("restart"), + installState: ipcRenderer.sendSync("modInstallState"), saveSettings: (...args: any) => ipcRenderer.send("saveSettings", ...args) }); } diff --git a/src/preload/preload.ts b/src/preload/preload.ts index d93dca0..8ab16e2 100644 --- a/src/preload/preload.ts +++ b/src/preload/preload.ts @@ -1,11 +1,11 @@ +import {ipcRenderer} from "electron"; import "./bridge"; import "./capturer"; import "./patch"; import * as fs from "fs"; import * as path from "path"; import {injectHummusTitlebar, injectTitlebar} from "./titlebar"; -import {sleep, addStyle, injectJS} from "../utils"; -import {ipcRenderer} from "electron"; +import {sleep, addStyle} from "../utils"; import {injectMobileStuff} from "./mobile"; var version = ipcRenderer.sendSync("displayVersion"); var channel = ipcRenderer.sendSync("channel"); @@ -23,10 +23,6 @@ declare global { armcord: any; } } -const clientMods = { - goosemod: "https://api.goosemod.com/inject.js", - cordwood: "https://raw.githubusercontent.com/Cordwood/builds/master/index.js" -}; console.log("ArmCord " + version); ipcRenderer.on("themeLoader", (event, message) => { @@ -48,19 +44,7 @@ if (window.location.href.indexOf("splash.html") > -1) { sleep(5000).then(async () => { const cssPath = path.join(__dirname, "../", "/content/css/discord.css"); addStyle(fs.readFileSync(cssPath, "utf8")); - - switch (ipcRenderer.sendSync("clientmod")) { - case "goosemod": - injectJS(clientMods.goosemod); - console.log("Loading GooseMod..."); - await updateLang(); - break; - case "cordwood": - injectJS(clientMods.cordwood); - console.log("Loading Cordwood..."); - await updateLang(); - break; - } + await updateLang(); }); } /* diff --git a/src/settings/settings.html b/src/settings/settings.html index e3aecbf..603d2cd 100644 --- a/src/settings/settings.html +++ b/src/settings/settings.html @@ -123,7 +123,8 @@

Client mod

@@ -131,8 +132,9 @@ Client mods are programs that allow you customize your Discord experience. They can change appearance of the client, modify behaviours or add new features!
- GooseMod - light, secure, and easy to use, with out of the box experience. Features a built-in - store for plugins. + Vencord - lightweight, and easy to use client mod. Features a built-in store for plugins. +
+ Shelter - is a new generation client mod built to be essentially bulletproof.


diff --git a/src/utils.ts b/src/utils.ts index 4714af5..07b2bd6 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -1,6 +1,10 @@ import * as fs from "fs"; -import {app, dialog} from "electron"; +import {app, dialog, session} from "electron"; import path from "path"; +import fetch from "node-fetch" +import extract from "extract-zip" +import util from "util" +const streamPipeline = util.promisify(require('stream').pipeline) export var firstRun: boolean; export var contentPath: string; export var transparency: boolean; @@ -73,6 +77,7 @@ export function getDisplayVersion() { } } export async function injectJS(inject: string) { + const js = await (await fetch(`${inject}`)).text(); const el = document.createElement("script"); @@ -252,11 +257,8 @@ export async function setConfig(object: string, toSet: any) { fs.writeFileSync(getConfigLocation(), toSave, "utf-8"); } export async function setConfigBulk(object: Settings) { - const userDataPath = app.getPath("userData"); - const storagePath = path.join(userDataPath, "/storage/"); - const settingsFile = storagePath + "settings.json"; let toSave = JSON.stringify(object); - fs.writeFileSync(settingsFile, toSave, "utf-8"); + fs.writeFileSync(getConfigLocation(), toSave, "utf-8"); } export async function checkIfConfigExists() { const userDataPath = app.getPath("userData"); @@ -281,3 +283,69 @@ export async function checkIfConfigExists() { } } } + +// Mods +async function updateModBundle() { + try { + console.log("Downloading mod bundle") + const distFolder = app.getPath("userData") + "/plugins/loader/dist/"; + while (!fs.existsSync(distFolder)){ + //waiting + } + var name: string = await getConfig("mods") + const clientMods = { + vencord: "https://github.com/Vendicated/Vencord/releases/download/devbuild/browser.js", + cordwood: "https://raw.githubusercontent.com/Cordwood/builds/master/index.js", + shelter: "https://raw.githubusercontent.com/uwu/shelter-builds/main/shelter.js" + }; + var bundle: string = await (await fetch(clientMods[name as keyof typeof clientMods])).text() + fs.writeFileSync(distFolder + "bundle.js", bundle, "utf-8"); +} catch (e) { + console.log("[Mod loader] Failed to install mods") + console.error(e) + dialog.showErrorBox( + "Oops, something went wrong.", + "ArmCord couldn't install mods, please check if you have stable internet connection and restart the app. If this issue persists, report it on the support server/Github issues." + ); +} +} +export var modInstallState: string; +export async function installModLoader() { + if (await getConfig("mods") == "none") { + modInstallState = "none" + import("./extensions/plugin"); + console.log("[Mod loader] Skipping") + } else { + const pluginFolder = app.getPath("userData") + "/plugins/"; + if (!fs.existsSync(pluginFolder + "loader")) { + try { + modInstallState = "installing" + var zipPath = app.getPath("temp") + "/" + "loader.zip"; + if (!fs.existsSync(pluginFolder)) { + fs.mkdirSync(pluginFolder); + console.log("[Mod loader] Created missing plugin folder"); + } + var loaderZip = await fetch("https://armcord.xyz/loader.zip") + if (!loaderZip.ok) throw new Error(`unexpected response ${loaderZip.statusText}`) + await streamPipeline(loaderZip.body, fs.createWriteStream(zipPath)) + await extract(zipPath, { dir: path.join(app.getPath("userData"), "plugins") }) + modInstallState = "modDownload" + updateModBundle() + import("./extensions/plugin"); + modInstallState = "done" + } catch(e) { + console.log("[Mod loader] Failed to install modloader") + console.error(e) + dialog.showErrorBox( + "Oops, something went wrong.", + "ArmCord couldn't install internal mod loader, please check if you have stable internet connection and restart the app. If this issue persists, report it on the support server/Github issues." + ); + } + } else { + modInstallState = "modDownload" + updateModBundle() + import("./extensions/plugin"); + modInstallState = "done" + } + } +} diff --git a/src/window.ts b/src/window.ts index c645afa..5694bf3 100644 --- a/src/window.ts +++ b/src/window.ts @@ -12,7 +12,7 @@ import { setConfig, setLang, setWindowState, - transparency + transparency, } from "./utils"; import {registerIpc} from "./ipc"; import {setMenu} from "./menu";