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");
:root {
background-color: #2c2f33;
--header-secondary: #b9bbbe;
--header-primary: #fff;
--background-tertiary: #202225;
background-color: #2c2f33 !important;
--header-secondary: #b9bbbe !important;
--header-primary: #fff !important;
--background-tertiary: #202225 !important;
}
body {
background-color: #2c2f33;
color: white;
}
p {
color: #8e9297;
color: white;
text-align: center;
font-weight: 100;
transform: translateY(-185%);
font-family: Whitney, Helvetica Neue, Helvetica, Arial, sans-serif;
text-rendering: optimizeLegibility;
font-style: italic;
}
.logo {
@ -64,22 +62,50 @@ span {
color: #fff;
transform: translate(-50%, -50%);
}
button#express {
margin-right: 84px;
}
button {
background-color: #7289da;
font-family: Whitney, "Helvetica Neue", Helvetica, Arial, sans-serif;
color: #ffffff;
padding: 4px;
border-radius: 5px;
left: 0;
margin-top: 5px;
text-align: center;
border-style: none;
outline: none;
}
.setup-ask {
font-size: 20px;
}
button:hover {
background-color: #687dc6;
border-style: none;
outline: none;
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>
<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>
<meta charset="UTF-8"/>
<title>ArmCord Setup</title>
<style>
@import url("css/setup.css");
</style>
</head>
<body>
<div class="container">
<h1 class="logo"></h1>
<div id="setup">
<p>Select what kind of setup you want to perform:</p>
<button id="express" class="center">Express setup</button>
<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>
<div class="container">
<h1 class="logo"></h1>
<h2>Welcome to ArmCord!</h2>
<p>Select what kind of setup you want to perform:</p>
<button id="express">Express setup</button>
<button id="full">Full setup</button>
</div>
</body>
</html>
if (window.navigator.onLine === false) {
document.getElementById("setup").innerHTML =
"You appear to be offline. Please connect to the internet and restart ArmCord Setup.";
} else {
console.log("Starting ArmCord Setup...");
document.getElementById("full").addEventListener("click", function () {
document.getElementById("setup").innerHTML = `
<p class="text-center setup-ask">Choose your Discord channel/instance:</p>
<div class="center">
<select name="channel" id="channel" class="dropdown-button">
<option value="stable">Stable</option>
<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.
*/
import electron from 'electron';
import * as storage from 'electron-json-storage';
import electron from "electron";
import * as storage from "electron-json-storage";
const otherMods = {
generic: {
electronProxy: require('util').types.isProxy(electron) // Many modern mods overwrite electron with a proxy with a custom BrowserWindow (copied from PowerCord)
}
};
generic: {
electronProxy: require("util").types.isProxy(electron), // Many modern mods overwrite electron with a proxy with a custom BrowserWindow (copied from PowerCord)
},
};
const unstrictCSP = () => {
console.log('Setting up CSP unstricter...');
console.log("Setting up CSP unstricter...");
const cspAllowAll = [
'connect-src',
'style-src',
'img-src',
'font-src'
];
const cspAllowAll = ["connect-src", "style-src", "img-src", "font-src"];
const corsAllowUrls = [
'https://github.com/GooseMod/GooseMod/releases/download/dev/index.js',
'https://github-releases.githubusercontent.com/',
'https://raw.githubusercontent.com/Cumcord/Cumcord/stable/dist/build.js',
'https://raw.githubusercontent.com/Cumcord/Cumcord/master/dist/build.js',
'https://raw.githubusercontent.com/FlickerMod/dist/main/build.js'
];
const corsAllowUrls = [
"https://github.com/GooseMod/GooseMod/releases/download/dev/index.js",
"https://github-releases.githubusercontent.com/",
"https://api.goosemod.com/inject.js",
"https://raw.githubusercontent.com/Cumcord/Cumcord/stable/dist/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) => {
let csp = responseHeaders!['content-security-policy'];
electron.session.defaultSession.webRequest.onHeadersReceived(
({ 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
delete 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
delete responseHeaders!["content-security-policy"];
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?)
csp[0] = csp[0].replace(/'nonce-.*?' /, '');
csp[0] = csp[0].replace(/'nonce-.*?' /, "");
}
if (corsAllowUrls.some((x) => url.startsWith(x))) {
responseHeaders!['access-control-allow-origin'] = ['*'];
responseHeaders!["access-control-allow-origin"] = ["*"];
}
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 "v8-compile-cache";
import * as storage from "electron-json-storage";
import { setup } from "./utils";
import { saveSettings } from "./utils";
import "./extensions/mods";
import "./extensions/plugin";
import "./tray";
var isSetup = null;
var contentPath: string = "null";
var frame: boolean;
export var mainWindow: BrowserWindow;
storage.keys(function (error, keys) {
if (error) throw error;
@ -17,18 +19,18 @@ storage.keys(function (error, keys) {
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 (!hasKey) {
console.log("First run of the ArmCord. Starting setup.");
isSetup = true;
setup();
// setup(); will be done at setup
contentPath = __dirname + "/content/setup.html";
} else {
console.log("ArmCord has been run before. Skipping setup.");
isSetup = false;
contentPath = __dirname + "/content/index.html";
contentPath = __dirname + "/content/splash.html";
}
});
storage.get("settings", function (error, data: any) {
@ -78,7 +80,30 @@ function createWindow() {
mainWindow.setSize(800, 600);
});
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) =>
desktopCapturer.getSources(opts)

View file

@ -1,7 +1,8 @@
import { contextBridge, ipcRenderer } from 'electron';
import {getDisplayMediaSelector} from './capturer';
console.log(ipcRenderer.send('channel'))
contextBridge.exposeInMainWorld("armcord", {
window: {
show: () => ipcRenderer.send('win-show'),
@ -12,6 +13,8 @@ contextBridge.exposeInMainWorld("armcord", {
electron: process.versions.electron,
version: ipcRenderer.send('get-app-version', 'app-version'),
getDisplayMediaSelector: getDisplayMediaSelector,
saveSettings: (...args: any) => ipcRenderer.send('saveSettings', ...args),
splashEnd: () => ipcRenderer.send('splashEnd'),
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 "./bridge";
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");
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';
//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) {
@ -21,10 +18,12 @@ export function setup(){
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) {
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;
});
}