security rewrite

This commit is contained in:
khlam 2019-10-19 20:38:47 -07:00
parent bc0ee8d016
commit 9a96da6ba2
5 changed files with 151 additions and 157 deletions

View File

@ -4,82 +4,18 @@ html, body{
margin:0px;
padding: 0;
overflow: hidden;
font-family: 'Roboto', sans-serif;
}
}
div {
width:100%;
height:97%;
height:100%;
}
webview {
height:100%;
height:97%;
height:100%;
}
::-webkit-scrollbar {
display: none;
}
.title-bar {
-webkit-app-region: drag;
margin: 0;
display: flex;
background-color: #212226;
width: 100%;
height: 3%;
}
.menu-button-container {
background-color: #212226;
display: flex;
align-items: center;
flex-grow: 1;
}
.status {
background-color: #212226;
color: #FFFFFF;
display: flex;
justify-content: center;
align-items: center;
flex-grow: 1;
}
.window-controls-container {
background-color: #212226;
display: flex;
justify-content: flex-end;
align-items: center;
flex-grow: 1;
}
.minimize-button {
border:none;
color: #FFFFFF;
-webkit-app-region: no-drag;
background-color: transparent;
margin: 1px;
width: 20px;
height: 20px;
}
.minimize-button:hover {
background-color: #99AAB5;
}
.close-button {
border:none;
color: #FFFFFF;
-webkit-app-region: no-drag;
background-color: transparent;
margin: 1px;
margin-right: 3px;
width: 20px;
height: 20px;
}
.close-button:hover {
background-color: #B22222;
}

View File

@ -2,21 +2,14 @@
<html>
<head>
<meta charset="UTF-8">
<!--style-src 'self' 'unsafe-inline' needs evaluation, some conflict with node_modules\electron\dist\resources\electron.asar\renderer\web-view\web-view-impl.js-->
<meta http-equiv="Content-Security-Policy" content="default-src none; script-src 'self'; style-src 'self' 'unsafe-inline'">
<link type="text/css" rel="stylesheet" href="./css/style.css">
</head>
<body>
<div id="title-bar" class="title-bar">
<div id='title-bar-status' class="status">
</div>
<div id='title-bar-controls' class="window-controls-container">
<button id="minimize-button" class="minimize-button"> - </button>
<button id="close-button" class="close-button"> x </button>
</div>
</div>
<!--Note that running in electron is already a chromium sandbox. Discord can no longer peek at a user's clipboard.-->
<webview id="discord" webpreferences="plugins=false, webgl=false, enableRemoteModule=false, sandbox=true, useragent='Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; AS; rv:11.0) like Gecko'" src="https://discordapp.com/login"></webview>
<!-- https://electronjs.org/docs/tutorial/security#15-disable-the-remote-module -->
<webview id="discord" enableremotemodule="false" webpreferences="useragent='Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; AS; rv:11.0) like Gecko'" src="https://discordapp.com/login"></webview>
<script src="./renderer.js"></script>
</body>

67
main.js
View File

@ -1,7 +1,8 @@
// Modules to control application life and create native browser window
const {app, BrowserWindow, ipcMain} = require('electron')
const { app, BrowserWindow, ipcMain} = require('electron')
const path = require('path')
const ioHook = require('iohook')
const URL = require('url').URL
// Keep a global reference of the window object, if you don't, the window will
// be closed automatically when the JavaScript object is garbage collected.
@ -13,15 +14,17 @@ function createWindow () {
// Create the browser window.
mainWindow = new BrowserWindow({
width: 1230,
height: 730,
height: 800,
icon: './assets/icon.ico',
frame: false,
webPreferences: {
preload: path.join(__dirname, 'preload.js'),
nodeIntegration: true,
nodeIntegration: false, // https://electronjs.org/docs/tutorial/security#2-do-not-enable-nodejs-integration-for-remote-content
enableRemoteModule: false, // https://electronjs.org/docs/tutorial/security#15-disable-the-remote-module
webviewTag: true
}
})
// Set Dev mode
if (process.argv.length === 3) {
if (process.argv[2] === 'dev'){
devMode = true
@ -65,19 +68,47 @@ app.on('activate', function () {
if (mainWindow === null) createWindow()
})
// In this file you can include the rest of your app's specific main process
// code. You can also put them in separate files and require them here.
/* Security Stuff */
// https://electronjs.org/docs/tutorial/security#11-verify-webview-options-before-creation
app.on('web-contents-created', (event, contents) => {
contents.on('will-attach-webview', (event, webPreferences, params) => {
// Strip away preload scripts if unused or verify their location is legitimate
delete webPreferences.preload
delete webPreferences.preloadURL
// Disable Node.js integration
webPreferences.nodeIntegration = false
// Verify discordapp.com is being loaded
if (!params.src.startsWith('https://discordapp.com/')) {
event.preventDefault()
}
})
})
// https://electronjs.org/docs/tutorial/security#12-disable-or-limit-navigation
app.on('web-contents-created', (event, contents) => {
contents.on('will-navigate', (event, navigationUrl) => {
const parsedUrl = new URL(navigationUrl)
if (parsedUrl.origin !== 'https://discordapp.com/') { // Limit navigation to discordapp.com; not really relevant
event.preventDefault()
}
})
})
// https://electronjs.org/docs/tutorial/security#13-disable-or-limit-creation-of-new-windows
app.on('web-contents-created', (event, contents) => {
contents.on('new-window', async (event, navigationUrl) => {
event.preventDefault() // External links just don't open
})
})
/* ---- */
'use strict';
let selfMute = false
let isConnected = false
function muteMic() {
console.log("Muted")
mainWindow.webContents.send('micClose', 'mic-closed')
mainWindow.setTitle("MUTED")
}
function unmuteMic() {
if (isConnected === true && selfMute === false) {
console.log("Talking")
@ -86,6 +117,12 @@ function unmuteMic() {
}
}
function muteMic() {
console.log("Muted")
mainWindow.webContents.send('micClose', 'mic-closed')
mainWindow.setTitle("MUTED")
}
app.on('ready', event => {
ioHook.start();
console.log(`Dev Mode: ${devMode}`)
@ -105,21 +142,23 @@ ioHook.on('mouseup', event => {
ipcMain.on('asynchronous-message', (event, msg) => {
if (msg === 'connected') {
console.log("User connected to Discord VOIP server")
isConnected = true
muteMic()
}
if (msg === 'disconnected') {
console.log("User disconnected to Discord VOIP server")
isConnected = false
}
if (msg === 'self-muted') {
console.log("self-muted")
console.log("User self-muted")
selfMute = true
}
if (msg === 'self-unmuted') {
console.log("self-unmuted")
console.log("User self-unmuted")
selfMute = false
}

View File

@ -1,12 +1,46 @@
// All of the Node.js APIs are available in the preload process.
// It has the same sandbox as a Chrome extension.
window.addEventListener('DOMContentLoaded', () => {
const replaceText = (selector, text) => {
const element = document.getElementById(selector)
if (element) element.innerText = text
}
for (const type of ['chrome', 'node', 'electron']) {
replaceText(`${type}-version`, process.versions[type])
}
const { ipcRenderer } = require('electron')
window.addEventListener("DOMContentLoaded", () => {
ipcRenderer.send('asynchronous-message', 'DOMready')
})
// Send commands from main to renderer
ipcRenderer.on('devMode', (event, msg) => {
console.log(`Dev Mode: ${msg}`)
window.postMessage({ type: "devMode", text: `${msg}` }, "*")
})
ipcRenderer.on('micOpen', (event, msg) => {
window.postMessage({ type: "micOpen"}, "*")
})
ipcRenderer.on('micClose', (event, msg) => {
window.postMessage({ type: "micClose"}, "*")
})
// Handle events sent from renderer, sends it to main
window.addEventListener(
"message",
event => {
if (event.origin === "file://" && event.source === window) {
if (event.data.type === 'connected'){
ipcRenderer.send('asynchronous-message', 'connected')
}
if (event.data.type === 'disconnected'){
ipcRenderer.send('asynchronous-message', 'disconnected')
}
if (event.data.type === 'self-muted'){
ipcRenderer.send('asynchronous-message', 'self-muted')
}
if (event.data.type === 'self-unmuted'){
ipcRenderer.send('asynchronous-message', 'self-unmuted')
}
}
},
false
)

View File

@ -1,5 +1,3 @@
const { remote, ipcRenderer } = require('electron')
function removeBloat(webview) {
webview.executeJavaScript(`document.getElementsByClassName("anchor-3Z-8Bb anchorUnderlineOnHover-2ESHQB")[0].remove();`) // Remove top-right help button
webview.executeJavaScript(`document.getElementsByClassName("contents-18-Yxp button-3AYNKb button-2vd_v_")[0].remove();`) // Remove gift from chat
@ -18,43 +16,41 @@ onload = () => {
const webview = document.querySelector('webview')
let muteTimeout = null
ipcRenderer.send('asynchronous-message', 'DOMready')
// Execute JS into the webview to detect when logging in is complete
// Insert JS to detect when discord finishes loading
webview.addEventListener('did-finish-load', function() {
webview.executeJavaScript(`
let dlButton = document.getElementsByClassName("listItem-2P_4kh");
t = setInterval(function(){
if(dlButton.length != 0) {
console.log("discord-load-complete")
clearInterval(t)
}else {
console.log("waiting for load")
}
}, 500);
`)
});
webview.executeJavaScript(`
let dlButton = document.getElementsByClassName("listItem-2P_4kh");
t = setInterval(function(){
if(dlButton.length != 0) {
console.log("discord-load-complete")
clearInterval(t)
}else {
console.log("waiting for load")
}
}, 500);
`)
});
webview.addEventListener('console-message', (e) => {
// Send commands to preload.js
webview.addEventListener('console-message', (e) => {
if (e.message === "Constructed RTCPeerConnection") {
console.log("Connected to server")
ipcRenderer.send('asynchronous-message', 'connected')
window.postMessage({ type: "connected"}, "*")
}
if (e.message === "Close RTCPeerConnection") {
console.log("Disconnected from server")
ipcRenderer.send('asynchronous-message', 'disconnected')
window.postMessage({ type: "disconnected"}, "*")
}
if (e.message === "muted") {
console.log("Self Muted in Discord")
ipcRenderer.send('asynchronous-message', 'self-muted')
window.postMessage({ type: "self-muted"}, "*")
}
if (e.message === "unmuted") {
console.log("Self Muted in Discord")
ipcRenderer.send('asynchronous-message', 'self-unmuted')
console.log("Self Un-Muted in Discord")
window.postMessage({ type: "self-unmuted"}, "*")
}
if (e.message === "signalingState => stable, negotiation needed: false") {
@ -81,36 +77,32 @@ onload = () => {
}
})
ipcRenderer.on('micOpen', (event, msg) => {
if (msg === 'mic-open'){
clearTimeout(muteTimeout) // Cancel mic-off incase of accidental double-tap
console.log("talking")
webview.sendInputEvent({keyCode: 'Backspace', type: 'keyDown'});
webview.sendInputEvent({keyCode: 'Backspace', type: 'char'});
document.getElementById("title-bar-status").style.backgroundColor = "green"
document.getElementById("title-bar-controls").style.backgroundColor = "green"
document.getElementById("title-bar").style.backgroundColor = "green"
}
})
// Accept commands from preload.js
window.addEventListener(
"message",
event => {
if (event.origin === "file://" && event.source === window) {
ipcRenderer.on('micClose', (event, msg) => {
if (msg === 'mic-closed'){
muteTimeout = setTimeout(() => muteMic(webview), 1000); // 1 second threshold incase of accidental double-click or release so the user doesn't cut-out
}
})
if (event.data.type === "devMode" && event.data.text === "true") {
webview.openDevTools()
}
ipcRenderer.on('devMode', (event, msg) => {
console.log(`Dev Mode: ${msg}`)
if (msg === true) {
webview.openDevTools()
}
})
}
if (event.data.type === 'micOpen'){
clearTimeout(muteTimeout) // Cancel mic-off incase of accidental double-tap
console.log("talking")
webview.sendInputEvent({keyCode: 'Backspace', type: 'keyDown'});
webview.sendInputEvent({keyCode: 'Backspace', type: 'char'});
document.getElementById("title-bar-status").style.backgroundColor = "green"
document.getElementById("title-bar-controls").style.backgroundColor = "green"
document.getElementById("title-bar").style.backgroundColor = "green"
}
document.getElementById('minimize-button').addEventListener('click', () => {
remote.getCurrentWindow().minimize()
})
document.getElementById('close-button').addEventListener('click', () => {
remote.app.quit()
})
if (event.data.type === 'micClose'){
muteTimeout = setTimeout(() => muteMic(webview), 1000); // 1 second threshold incase of accidental double-click or release so the user doesn't cut-out
}
}
},
false
)
}