security rewrite
This commit is contained in:
parent
bc0ee8d016
commit
9a96da6ba2
@ -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;
|
||||
}
|
15
index.html
15
index.html
@ -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
67
main.js
@ -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
|
||||
}
|
||||
|
||||
|
56
preload.js
56
preload.js
@ -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
|
||||
)
|
100
renderer.js
100
renderer.js
@ -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
|
||||
)
|
||||
}
|
Loading…
Reference in New Issue
Block a user