Re-add client mods (vencord, shelter)

This commit is contained in:
smartfridge 2022-11-19 18:23:28 +01:00
parent 842b6e8c5d
commit 5d80d44fc8
14 changed files with 188 additions and 38 deletions

View File

@ -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"

View File

@ -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:

3
src/.npmrc Normal file
View File

@ -0,0 +1,3 @@
node-linker=hoisted
public-hoist-pattern=*
shamefully-hoist=true

View File

@ -53,7 +53,9 @@
<p class="text-center setup-ask" id="setup_question4">Select a client mod you want to install:</p>
<div class="center">
<select name="mod" id="mod" class="dropdown-button">
<option value="none">None (check Discord)</option>
<option value="vencord">Vencord</option>
<option value="shelter">Shelter</option>
<option value="none">None</option>
</select>
</div>
<p class="text-center" id="setup_question4_clientmodnotice">

View File

@ -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);
}
}

View File

@ -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"];

View File

@ -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);
}

View File

@ -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;
});

View File

@ -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

View File

@ -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)
});
}

View File

@ -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();
});
}
/*

View File

@ -123,7 +123,8 @@
<br />
<div class="switch acClientMod">
<select name="mod" id="mod" class="left dropdown">
<option value="goosemod">GooseMod</option>
<option value="vencord">Vencord</option>
<option value="shelter">Shelter</option>
<option value="none">None</option>
</select>
<p class="header" id="settings-mod">Client mod</p>
@ -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!
<br />
<b>GooseMod</b> - light, secure, and easy to use, with out of the box experience. Features a built-in
store for plugins.
<b>Vencord</b> - lightweight, and easy to use client mod. Features a built-in store for plugins.
<br />
<b>Shelter</b> - is a new generation client mod built to be essentially bulletproof.
</p>
</div>
<br />

View File

@ -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"
}
}
}

View File

@ -12,7 +12,7 @@ import {
setConfig,
setLang,
setWindowState,
transparency
transparency,
} from "./utils";
import {registerIpc} from "./ipc";
import {setMenu} from "./menu";