Working setup + broken loading the actual app

This commit is contained in:
smartfridge 2021-12-26 22:41:09 +01:00
parent 28aac451bf
commit c2c0e50fd3
8 changed files with 277 additions and 82 deletions

View file

@ -2,24 +2,22 @@
@import url("https://kckarnige.github.io/femboi_owo/discord-font.css"); @import url("https://kckarnige.github.io/femboi_owo/discord-font.css");
:root { :root {
background-color: #2c2f33; background-color: #2c2f33 !important;
--header-secondary: #b9bbbe; --header-secondary: #b9bbbe !important;
--header-primary: #fff; --header-primary: #fff !important;
--background-tertiary: #202225; --background-tertiary: #202225 !important;
} }
body { body {
background-color: #2c2f33;
color: white; color: white;
} }
p { p {
color: #8e9297; color: white;
text-align: center; text-align: center;
font-weight: 100; font-weight: 100;
transform: translateY(-185%);
font-family: Whitney, Helvetica Neue, Helvetica, Arial, sans-serif; font-family: Whitney, Helvetica Neue, Helvetica, Arial, sans-serif;
text-rendering: optimizeLegibility; text-rendering: optimizeLegibility;
font-style: italic;
} }
.logo { .logo {
@ -64,22 +62,50 @@ span {
color: #fff; color: #fff;
transform: translate(-50%, -50%); transform: translate(-50%, -50%);
} }
button#express {
margin-right: 84px;
}
button { button {
background-color: #7289da; background-color: #7289da;
font-family: Whitney, "Helvetica Neue", Helvetica, Arial, sans-serif; font-family: Whitney, "Helvetica Neue", Helvetica, Arial, sans-serif;
color: #ffffff; color: #ffffff;
padding: 4px; padding: 4px;
border-radius: 5px; border-radius: 5px;
left: 0; margin-top: 5px;
text-align: center; text-align: center;
border-style: none; border-style: none;
outline: none; outline: none;
} }
.setup-ask {
font-size: 20px;
}
button:hover { button:hover {
background-color: #687dc6; background-color: #687dc6;
border-style: none; border-style: none;
outline: none; outline: none;
cursor: pointer; cursor: pointer;
} }
select {
-webkit-appearance: button;
-moz-appearance: button;
-webkit-padding-end: 20px;
-moz-padding-end: 20px;
-webkit-padding-start: 2px;
-moz-padding-start: 2px;
background-color: #2c2f33;
background-position: center right;
background-repeat: no-repeat;
border: 1px solid #aaa;
border-radius: 2px;
box-shadow: 0px 1px 3px rgba(0, 0, 0, 0.1);
color: #fff;
font-size: inherit;
margin: 0;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.center {
text-align: center;
}

View file

@ -1,24 +1,124 @@
<!DOCTYPE html> <!DOCTYPE html>
<html lang="en"> <html lang="en">
<head>
<link
rel="stylesheet"
href="https://cdn.metroui.org.ua/v4/css/metro-all.min.css"
/>
<meta charset="UTF-8" />
<title>ArmCord Setup</title>
<style>
@import url("css/setup.css");
</style>
</head>
<head> <body>
<meta charset="UTF-8"/> <div class="container">
<title>ArmCord Setup</title> <h1 class="logo"></h1>
<style> <div id="setup">
@import url("css/setup.css"); <p>Select what kind of setup you want to perform:</p>
</style> <button id="express" class="center">Express setup</button>
</head> <button id="full" class="center">Full setup</button>
</div>
</div>
<script>
function discord(){
switch (window.armcord.channel) {
case "stable":
window.location.href = "https://discord.com/app";
break;
case "canary":
window.location.href = "https://canary.discord.com/app";
break;
case "ptb":
window.location.href = "https://ptb.discord.com/app";
break;
case "foss":
window.location.href = "https://dev.fosscord.com/app";
break;
default:
window.location.href = "https://discord.com/app";
}
}
function fade(element) {
var op = 1; // initial opacity
var timer = setInterval(function () {
if (op <= 0.1) {
clearInterval(timer);
element.style.display = "none";
}
element.style.opacity = op;
element.style.filter = "alpha(opacity=" + op * 100 + ")";
op -= op * 0.1;
}, 50);
}
<body> if (window.navigator.onLine === false) {
<div class="container"> document.getElementById("setup").innerHTML =
<h1 class="logo"></h1> "You appear to be offline. Please connect to the internet and restart ArmCord Setup.";
<h2>Welcome to ArmCord!</h2> } else {
<p>Select what kind of setup you want to perform:</p> console.log("Starting ArmCord Setup...");
<button id="express">Express setup</button> document.getElementById("full").addEventListener("click", function () {
<button id="full">Full setup</button> document.getElementById("setup").innerHTML = `
</div> <p class="text-center setup-ask">Choose your Discord channel/instance:</p>
<div class="center">
</body> <select name="channel" id="channel" class="dropdown-button">
<option value="stable">Stable</option>
</html> <option value="canary">Canary</option>
<option value="ptb">PTB</option>
<option value="foss">Fosscord</option>
</select>
</div>
<p class="text-center setup-ask">Should ArmCord handle client mods installation?</p>
<div class="center">
<select name="csp" id="csp" class="dropdown-button">
<option value="true">Yes</option>
<option value="false">No</option>
</select>
</div>
<button id="next" class="center">Next</button>
`;
document
.getElementById("next")
.addEventListener("click", function () {
var branch = document.getElementById("channel").value;
var csp = document.getElementById("csp").value;
if (csp === "true") {
document.getElementById("setup").innerHTML = `
<p class="text-center setup-ask">Select a client mod you want to install:</p>
<div class="center">
<select name="mod" id="mod" class="dropdown-button">
<option value="cumcord">Cumcord</option>
<option value="goosemod">GooseMod</option>
<option value="flicker">Flicker (WIP)</option>
</select>
</div>
<p>Why not all of them? Having many client mods at the same time can cause issues. If you really want to do it though, check our documentation ;)</p>
<button id="next" class="center">Next</button>
`;
document
.getElementById("next")
.addEventListener("click", function () {
var mod = document.getElementById("mod").value;
window.armcord.saveSettings(true, branch, true, mod);
fade(document.getElementById("setup"));
setTimeout(function () {
window.armcord.splashEnd();
discord();
}, 5000);
});
} else {
//saveSettings(customTitlebarSetting: boolean, channelSetting: string, armcordCSPSetting: boolean, modsSetting: string)
window.armcord.saveSettings(true, branch, true, "none");
fade(document.getElementById("setup"));
setTimeout(function () {
window.armcord.splashEnd();
discord();
}, 5000);
}
});
});
}
</script>
</body>
</html>

View file

@ -8,36 +8,35 @@ The above copyright notice and this permission notice shall be included in all c
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/ */
import electron from 'electron'; import electron from "electron";
import * as storage from 'electron-json-storage'; import * as storage from "electron-json-storage";
const otherMods = { const otherMods = {
generic: { generic: {
electronProxy: require('util').types.isProxy(electron) // Many modern mods overwrite electron with a proxy with a custom BrowserWindow (copied from PowerCord) electronProxy: require("util").types.isProxy(electron), // Many modern mods overwrite electron with a proxy with a custom BrowserWindow (copied from PowerCord)
} },
}; };
const unstrictCSP = () => { const unstrictCSP = () => {
console.log('Setting up CSP unstricter...'); console.log("Setting up CSP unstricter...");
const cspAllowAll = [ const cspAllowAll = ["connect-src", "style-src", "img-src", "font-src"];
'connect-src',
'style-src',
'img-src',
'font-src'
];
const corsAllowUrls = [ const corsAllowUrls = [
'https://github.com/GooseMod/GooseMod/releases/download/dev/index.js', "https://github.com/GooseMod/GooseMod/releases/download/dev/index.js",
'https://github-releases.githubusercontent.com/', "https://github-releases.githubusercontent.com/",
'https://raw.githubusercontent.com/Cumcord/Cumcord/stable/dist/build.js', "https://api.goosemod.com/inject.js",
'https://raw.githubusercontent.com/Cumcord/Cumcord/master/dist/build.js', "https://raw.githubusercontent.com/Cumcord/Cumcord/stable/dist/build.js",
'https://raw.githubusercontent.com/FlickerMod/dist/main/build.js' "https://raw.githubusercontent.com/Cumcord/Cumcord/master/dist/build.js",
]; "https://raw.githubusercontent.com/FlickerMod/dist/main/build.js",
];
electron.session.defaultSession.webRequest.onHeadersReceived(({ responseHeaders, url }, done) => { electron.session.defaultSession.webRequest.onHeadersReceived(
let csp = responseHeaders!['content-security-policy']; ({ responseHeaders, url }, done) => {
let csp = responseHeaders!["content-security-policy"];
if (otherMods.generic.electronProxy) { // Since patch v16, override other mod's onHeadersRecieved (Electron only allows 1 listener); because they rely on 0 CSP at all (GM just unrestricts some areas), remove it fully if we detect other mods if (otherMods.generic.electronProxy) {
delete responseHeaders!['content-security-policy']; // Since patch v16, override other mod's onHeadersRecieved (Electron only allows 1 listener); because they rely on 0 CSP at all (GM just unrestricts some areas), remove it fully if we detect other mods
delete responseHeaders!["content-security-policy"];
csp = []; csp = [];
} }
@ -47,21 +46,24 @@ const unstrictCSP = () => {
} }
// Fix Discord's broken CSP which disallows unsafe-inline due to having a nonce (which they don't even use?) // Fix Discord's broken CSP which disallows unsafe-inline due to having a nonce (which they don't even use?)
csp[0] = csp[0].replace(/'nonce-.*?' /, ''); csp[0] = csp[0].replace(/'nonce-.*?' /, "");
} }
if (corsAllowUrls.some((x) => url.startsWith(x))) { if (corsAllowUrls.some((x) => url.startsWith(x))) {
responseHeaders!['access-control-allow-origin'] = ['*']; responseHeaders!["access-control-allow-origin"] = ["*"];
} }
done({ responseHeaders }); done({ responseHeaders });
});
};
storage.get('settings', function(error, data:any) {
if (error) throw error;
if (data.armcordCSP) {
unstrictCSP();
} else {
console.log('ArmCord CSP is disabled. The CSP should be managed by third-party plugin.');
} }
}); );
};
storage.get("settings", function (error, data: any) {
if (error) throw error;
if (data.armcordCSP) {
unstrictCSP();
} else {
console.log(
"ArmCord CSP is disabled. The CSP should be managed by third-party plugin."
);
}
});

View file

@ -3,13 +3,15 @@ import { app, BrowserWindow, ipcMain, shell, desktopCapturer } from "electron";
import * as path from "path"; import * as path from "path";
import "v8-compile-cache"; import "v8-compile-cache";
import * as storage from "electron-json-storage"; import * as storage from "electron-json-storage";
import { setup } from "./utils"; import { saveSettings } from "./utils";
import "./extensions/mods";
import "./extensions/plugin"; import "./extensions/plugin";
import "./tray"; import "./tray";
var isSetup = null; var isSetup = null;
var contentPath: string = "null"; var contentPath: string = "null";
var frame: boolean; var frame: boolean;
export var mainWindow: BrowserWindow; export var mainWindow: BrowserWindow;
storage.keys(function (error, keys) { storage.keys(function (error, keys) {
if (error) throw error; if (error) throw error;
@ -17,18 +19,18 @@ storage.keys(function (error, keys) {
console.log("There is a key called: " + key); console.log("There is a key called: " + key);
} }
}); });
storage.has("firstRun", function (error, hasKey) { storage.has("settings", function (error, hasKey) {
if (error) throw error; if (error) throw error;
if (!hasKey) { if (!hasKey) {
console.log("First run of the ArmCord. Starting setup."); console.log("First run of the ArmCord. Starting setup.");
isSetup = true; isSetup = true;
setup(); // setup(); will be done at setup
contentPath = __dirname + "/content/setup.html"; contentPath = __dirname + "/content/setup.html";
} else { } else {
console.log("ArmCord has been run before. Skipping setup."); console.log("ArmCord has been run before. Skipping setup.");
isSetup = false; isSetup = false;
contentPath = __dirname + "/content/index.html"; contentPath = __dirname + "/content/splash.html";
} }
}); });
storage.get("settings", function (error, data: any) { storage.get("settings", function (error, data: any) {
@ -78,7 +80,30 @@ function createWindow() {
mainWindow.setSize(800, 600); mainWindow.setSize(800, 600);
}); });
ipcMain.on("channel", (event) => { ipcMain.on("channel", (event) => {
event.returnValue = storage.getSync("channel"); storage.get("settings", function (error, data: any) {
if (error) throw error;
event.returnValue = data.channel;
});
});
ipcMain.on("saveSettings", (event, ...args) => {
//@ts-ignore
saveSettings(...args);
});
ipcMain.on('clientmod' , (event, arg) => {
storage.get("settings", function (error, data: any) {
if (error) throw error;
event.returnValue = data.mods;
});
})
ipcMain.on("setting-armcordCSP", (event) => {
storage.get("settings", function (error, data: any) {
if (error) throw error;
if (data.armcordCSP) {
event.returnValue = true;
} else {
event.returnValue = false;
}
});
}); });
ipcMain.handle("DESKTOP_CAPTURER_GET_SOURCES", (event, opts) => ipcMain.handle("DESKTOP_CAPTURER_GET_SOURCES", (event, opts) =>
desktopCapturer.getSources(opts) desktopCapturer.getSources(opts)

View file

@ -1,7 +1,8 @@
import { contextBridge, ipcRenderer } from 'electron'; import { contextBridge, ipcRenderer } from 'electron';
import {getDisplayMediaSelector} from './capturer'; import {getDisplayMediaSelector} from './capturer';
console.log(ipcRenderer.send('channel'))
contextBridge.exposeInMainWorld("armcord", { contextBridge.exposeInMainWorld("armcord", {
window: { window: {
show: () => ipcRenderer.send('win-show'), show: () => ipcRenderer.send('win-show'),
@ -12,6 +13,8 @@ contextBridge.exposeInMainWorld("armcord", {
electron: process.versions.electron, electron: process.versions.electron,
version: ipcRenderer.send('get-app-version', 'app-version'), version: ipcRenderer.send('get-app-version', 'app-version'),
getDisplayMediaSelector: getDisplayMediaSelector, getDisplayMediaSelector: getDisplayMediaSelector,
saveSettings: (...args: any) => ipcRenderer.send('saveSettings', ...args),
splashEnd: () => ipcRenderer.send('splashEnd'), splashEnd: () => ipcRenderer.send('splashEnd'),
channel: ipcRenderer.send('channel') channel: ipcRenderer.send('channel')
}); });
contextBridge.exposeInMainWorld("electron", {}) //deprecated, used for legacy purposes, will be removed in future versions

View file

@ -1,6 +1,46 @@
import "./capturer"; import "./capturer";
import "./bridge"; import "./bridge";
import { injectTitlebar } from "./titlebar"; import { injectTitlebar } from "./titlebar";
import { ipcRenderer } from "electron";
declare global {
interface Window {
splash: any;
}
}
const clientMods = {
goosemod: "https://api.goosemod.com/inject.js",
cumcord:
"https://raw.githubusercontent.com/Cumcord/Cumcord/stable/dist/build.js",
flicker: "https://raw.githubusercontent.com/FlickerMod/dist/main/build.js",
};
async function injectJS(inject: string) {
const js = await (await fetch(`${inject}`)).text();
const el = document.createElement("script");
el.appendChild(document.createTextNode(js));
document.body.appendChild(el);
}
injectTitlebar();
console.log("ArmCord"); console.log("ArmCord");
if (window.location.href.indexOf("splash.html") > -1) {
console.log("Skipping titlebar injection and client mod injection.");
} else {
injectTitlebar();
switch (ipcRenderer.sendSync("clientmod")) {
case "goosemod":
injectJS(clientMods.goosemod);
console.log("Loading GooseMod...");
break;
case "cumcord":
injectJS(clientMods.cumcord);
console.log("Loading Cumcord...");
break;
case "flicker":
injectJS(clientMods.flicker);
console.log("Loading FlickerMod...");
break;
}
}

View file

@ -1,7 +1,4 @@
/*--------------------------------------------------------------------------------------------------------
* This file has parts of one or more project files (VS Code) from Microsoft
* You can check your respective license and the original file in https://github.com/Microsoft/vscode/
*-------------------------------------------------------------------------------------------------------*/
import * as storage from 'electron-json-storage'; import * as storage from 'electron-json-storage';
//utillity functions that are used all over the codebase or just too obscure to be put in the file used in //utillity functions that are used all over the codebase or just too obscure to be put in the file used in
export function addStyle(styleString: string) { export function addStyle(styleString: string) {
@ -21,10 +18,12 @@ export function setup(){
if (error) throw error; if (error) throw error;
}); });
} }
export function append<T extends Node>(parent: HTMLElement, ...children: T[]): T {
children.forEach(child => parent.appendChild(child));
return children[children.length - 1];
}
export async function sleep(ms:number) { export async function sleep(ms:number) {
return new Promise(resolve => setTimeout(resolve, ms)); return new Promise(resolve => setTimeout(resolve, ms));
}
export function saveSettings(customTitlebarSetting: boolean, channelSetting: string, armcordCSPSetting: boolean, modsSetting: string) {
console.log("Setting up ArmCord settings.");
storage.set('settings', { customTitlebar: customTitlebarSetting, channel: channelSetting, firstRun: 'done', armcordCSP: armcordCSPSetting, mods: modsSetting }, function(error) {
if (error) throw error;
});
} }