http first! implements warning for insecure connections
This commit is contained in:
commit
bb48b93729
|
@ -52,12 +52,22 @@
|
||||||
</ul>
|
</ul>
|
||||||
</footer>
|
</footer>
|
||||||
<div id="dialog-backdrop"></div>
|
<div id="dialog-backdrop"></div>
|
||||||
<div id="connect-dialog">
|
<div id="connect-dialog" class="dialog">
|
||||||
<button id="connect-close">X</button>
|
<button class="dialog-close">X</button>
|
||||||
<p>Enter the address of the server you would like to connect to:</p>
|
<p>Enter the address of the server you would like to connect to:</p>
|
||||||
<input id="connect-url" name="server" type="text" spellcheck="false">
|
<input id="connect-url" name="server" type="text" spellcheck="false">
|
||||||
<button id="connect-submit">Connect</button>
|
<button id="connect-submit">Connect</button>
|
||||||
</div>
|
</div>
|
||||||
|
<div id="warn-dialog" class="dialog">
|
||||||
|
<button class="dialog-close">X</button>
|
||||||
|
<p>
|
||||||
|
WARNING: The server you're about to connect to is insecure.
|
||||||
|
Your activity here may be available to anyone monitoring your network traffic!
|
||||||
|
Are you sure you want to continue?
|
||||||
|
</p>
|
||||||
|
<button id="warn-proceed">Okay!</button>
|
||||||
|
<button id="warn-cancel">Nevermind!</button>
|
||||||
|
</div>
|
||||||
<div id="overlay"></div>
|
<div id="overlay"></div>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
|
@ -6,11 +6,12 @@ document.addEventListener("DOMContentLoaded", () => {
|
||||||
Terminal.start();
|
Terminal.start();
|
||||||
|
|
||||||
const dialog_backdrop = document.getElementById("dialog-backdrop");
|
const dialog_backdrop = document.getElementById("dialog-backdrop");
|
||||||
|
|
||||||
const connect_button = document.getElementById("connect");
|
const connect_button = document.getElementById("connect");
|
||||||
const connect_dialog = document.getElementById("connect-dialog");
|
const connect_dialog = document.getElementById("connect-dialog");
|
||||||
const connect_url = document.getElementById("connect-url");
|
const connect_url = document.getElementById("connect-url");
|
||||||
const connect_submit = document.getElementById("connect-submit");
|
const connect_submit = document.getElementById("connect-submit");
|
||||||
const connect_close = document.getElementById("connect-close");
|
const connect_close = connect_dialog.getElementsByClassName("dialog-close").item(0);
|
||||||
|
|
||||||
connect_url.placeholder = window.location.host;
|
connect_url.placeholder = window.location.host;
|
||||||
|
|
||||||
|
@ -24,8 +25,7 @@ document.addEventListener("DOMContentLoaded", () => {
|
||||||
|
|
||||||
connect_submit.addEventListener("click", () => {
|
connect_submit.addEventListener("click", () => {
|
||||||
connect_close.click();
|
connect_close.click();
|
||||||
const new_server = connect_url.value;
|
const new_server = connect_url.value || window.location.host;
|
||||||
if (!new_server) return;
|
|
||||||
Terminal.connect(new_server);
|
Terminal.connect(new_server);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -41,10 +41,14 @@ document.addEventListener("DOMContentLoaded", () => {
|
||||||
return;
|
return;
|
||||||
});
|
});
|
||||||
|
|
||||||
connect_close.addEventListener("click", () => {
|
[...document.getElementsByClassName("dialog-close")].forEach(dialog_close => {
|
||||||
connect_dialog.classList.remove("show");
|
dialog_close.addEventListener("click", () => {
|
||||||
dialog_backdrop.classList.remove("show");
|
[...document.getElementsByClassName("dialog")].forEach(element => {
|
||||||
Terminal.set_enable_input(true);
|
element.classList.remove("show");
|
||||||
|
});
|
||||||
|
dialog_backdrop.classList.remove("show");
|
||||||
|
Terminal.set_enable_input(true);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
dialog_backdrop.addEventListener("click", () => {
|
dialog_backdrop.addEventListener("click", () => {
|
||||||
|
|
|
@ -111,11 +111,64 @@ export async function connect(server_url) {
|
||||||
|
|
||||||
add_system_message("Connecting to the server...\n");
|
add_system_message("Connecting to the server...\n");
|
||||||
|
|
||||||
if (!server_url.startsWith("wss://")) server_url = "wss://" + server_url;
|
let protocol = false;
|
||||||
client = new WebSocket(server_url);
|
|
||||||
|
// check if user explicitly stated secure/insecure protocol
|
||||||
|
if (server_url.startsWith("wss://")) {
|
||||||
|
protocol = "wss://";
|
||||||
|
server_url = server_url.split(6);
|
||||||
|
} else if (server_url.startsWith("ws://")) {
|
||||||
|
server_url = server_url.split(5);
|
||||||
|
protocol = "ws://";
|
||||||
|
}
|
||||||
|
// otherwise, probe the url!
|
||||||
|
else protocol = await get_available_socket_protocol(server_url);
|
||||||
|
|
||||||
|
// no server was found!
|
||||||
|
if (!protocol) {
|
||||||
|
return add_system_message(`\n[NO SERVER FOUND AT ${server_url}!]\n`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// server was found, but it's insecure!
|
||||||
|
if (protocol === "ws://") {
|
||||||
|
const warn_dialog = document.getElementById("warn-dialog");
|
||||||
|
const warn_close = warn_dialog.getElementsByClassName("dialog-close").item(0);
|
||||||
|
const user_wants_insecure = await new Promise((Resolve, Reject) => {
|
||||||
|
const dialog_backdrop = document.getElementById("dialog-backdrop");
|
||||||
|
const warn_proceed = document.getElementById("warn-proceed");
|
||||||
|
const warn_cancel = document.getElementById("warn-cancel");
|
||||||
|
|
||||||
|
warn_dialog.classList.add("show");
|
||||||
|
dialog_backdrop.classList.add("show");
|
||||||
|
|
||||||
|
set_enable_input(false);
|
||||||
|
|
||||||
|
warn_close.addEventListener('click', () => {
|
||||||
|
Resolve(false);
|
||||||
|
});
|
||||||
|
warn_cancel.addEventListener('click', () => {
|
||||||
|
Resolve(false);
|
||||||
|
});
|
||||||
|
warn_proceed.addEventListener('click', () => {
|
||||||
|
Resolve(true);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
warn_close.click();
|
||||||
|
|
||||||
|
set_enable_input(true);
|
||||||
|
|
||||||
|
if (!user_wants_insecure) {
|
||||||
|
server_indicator.innerText = "not connected";
|
||||||
|
add_system_message(`\n[CONNECTION CLOSED]\n`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
client = new WebSocket(protocol + server_url);
|
||||||
|
|
||||||
client.addEventListener('open', () => {
|
client.addEventListener('open', () => {
|
||||||
server_indicator.innerText = server_url.slice(6);
|
server_indicator.innerText = server_url;
|
||||||
add_system_message(`Connection successful.\n\n`);
|
add_system_message(`Connection successful.\n\n`);
|
||||||
add_system_message(`=== BEGIN SESSION ===\n\n`);
|
add_system_message(`=== BEGIN SESSION ===\n\n`);
|
||||||
new_caret();
|
new_caret();
|
||||||
|
@ -134,6 +187,34 @@ export async function connect(server_url) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* probes the `server_url` for a secure websocket connection first, an insecure websocket second, or resolves to `false` on failure.
|
||||||
|
* @param {string} server_url
|
||||||
|
* @returns a promise either resolving to the discovered protocol, or false on failure.
|
||||||
|
*/
|
||||||
|
function get_available_socket_protocol(server_url) {
|
||||||
|
return new Promise((Resolve, Reject) => {
|
||||||
|
const secure_client = new WebSocket("wss://" + server_url);
|
||||||
|
|
||||||
|
secure_client.addEventListener('open', () => {
|
||||||
|
Resolve("wss://");
|
||||||
|
});
|
||||||
|
|
||||||
|
secure_client.addEventListener('error', () => {
|
||||||
|
const insecure_client = new WebSocket("ws://" + server_url);
|
||||||
|
|
||||||
|
insecure_client.addEventListener('open', () => {
|
||||||
|
Resolve("ws://");
|
||||||
|
});
|
||||||
|
|
||||||
|
insecure_client.addEventListener('error', () => {
|
||||||
|
Reject(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* appends a client-side message to the text buffer.
|
* appends a client-side message to the text buffer.
|
||||||
* @param {string} text - text to send to the buffer.
|
* @param {string} text - text to send to the buffer.
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
:root {
|
:root {
|
||||||
--colour: #a6e3a1;
|
--colour: #a6e3a1;
|
||||||
--bgcolour: #1e1e2e;
|
--bgcolour: #1e1e2e;
|
||||||
|
--warn-colour: #e83737;
|
||||||
}
|
}
|
||||||
|
|
||||||
body {
|
body {
|
||||||
|
@ -186,12 +187,10 @@ body.lcd pre#content {
|
||||||
z-index: 99;
|
z-index: 99;
|
||||||
}
|
}
|
||||||
|
|
||||||
#connect-dialog {
|
div.dialog {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
top: 50%;
|
top: 50%;
|
||||||
left: 50%;
|
left: 50%;
|
||||||
max-width: calc(100vw - 4rem);
|
|
||||||
width: 16rem;
|
|
||||||
margin: auto auto;
|
margin: auto auto;
|
||||||
padding: 1rem;
|
padding: 1rem;
|
||||||
display: none;
|
display: none;
|
||||||
|
@ -203,37 +202,37 @@ body.lcd pre#content {
|
||||||
z-index: 99;
|
z-index: 99;
|
||||||
}
|
}
|
||||||
|
|
||||||
#dialog-backdrop.show,
|
div.dialog p {
|
||||||
#connect-dialog.show {
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
|
|
||||||
#connect-dialog p {
|
|
||||||
margin: 0 0 1em 0;
|
margin: 0 0 1em 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#connect-dialog input {
|
div.dialog input {
|
||||||
font-family: inherit;
|
font-family: inherit;
|
||||||
color: var(--colour);
|
color: inherit;
|
||||||
border: 1px solid var(--colour);
|
border: inherit;
|
||||||
background: transparent;
|
background: transparent;
|
||||||
}
|
}
|
||||||
|
|
||||||
#connect-dialog input::placeholder {
|
div.dialog input::placeholder {
|
||||||
font-family: inherit;
|
font-family: inherit;
|
||||||
color: var(--colour);
|
color: inherit;
|
||||||
opacity: .25;
|
opacity: .25;
|
||||||
}
|
}
|
||||||
|
|
||||||
#connect-dialog button {
|
div.dialog button {
|
||||||
font-family: inherit;
|
font-family: inherit;
|
||||||
border: 1px solid var(--colour);
|
border: inherit;
|
||||||
color: var(--colour);
|
color: inherit;
|
||||||
background: transparent;
|
background: transparent;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
#connect-dialog #connect-close {
|
#dialog-backdrop.show,
|
||||||
|
div.dialog.show {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.dialog .dialog-close {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: -0.7em;
|
top: -0.7em;
|
||||||
right: 1rem;
|
right: 1rem;
|
||||||
|
@ -241,6 +240,17 @@ body.lcd pre#content {
|
||||||
background: var(--bgcolour);
|
background: var(--bgcolour);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#connect-dialog {
|
||||||
|
max-width: calc(100vw - 4rem);
|
||||||
|
width: 16rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
#warn-dialog {
|
||||||
|
max-width: 18rem;
|
||||||
|
color: var(--warn-colour);
|
||||||
|
border-color: var(--warn-colour);
|
||||||
|
}
|
||||||
|
|
||||||
*:focus {
|
*:focus {
|
||||||
outline: none;
|
outline: none;
|
||||||
box-shadow: 0 0 4px;
|
box-shadow: 0 0 4px;
|
||||||
|
|
|
@ -1,13 +1,8 @@
|
||||||
const fs = require('fs');
|
const fs = require('fs');
|
||||||
const https = require('https');
|
const http = require('http');
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
const Websocket = require('ws');
|
const Websocket = require('ws');
|
||||||
|
|
||||||
const config = {
|
|
||||||
cert: fs.readFileSync(process.env.SSL_CERT || './certs/cert.crt'),
|
|
||||||
key: fs.readFileSync(process.env.SSL_KEY || './certs/cert.key'),
|
|
||||||
}
|
|
||||||
|
|
||||||
const MIME_TYPES = {
|
const MIME_TYPES = {
|
||||||
default: "application/octet-stream",
|
default: "application/octet-stream",
|
||||||
html: "text/html; charset=UTF-8",
|
html: "text/html; charset=UTF-8",
|
||||||
|
@ -65,7 +60,7 @@ This connection will now terminate.
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
|
||||||
const PORT = process.env.PORT || 8443;
|
const PORT = process.env.PORT || 8080;
|
||||||
const PING_INTERVAL = 10000;
|
const PING_INTERVAL = 10000;
|
||||||
let sockets = [];
|
let sockets = [];
|
||||||
|
|
||||||
|
@ -74,7 +69,7 @@ const MAX_BUFFER_SIZE = 1024 * 1000;
|
||||||
const MAX_MESSAGE_LENGTH = 1024;
|
const MAX_MESSAGE_LENGTH = 1024;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* simple file fetching for the HTTPS server
|
* simple file fetching for the HTTP server
|
||||||
*/
|
*/
|
||||||
async function get_file(url) {
|
async function get_file(url) {
|
||||||
// ignore query params...not very helpful when getting files!
|
// ignore query params...not very helpful when getting files!
|
||||||
|
@ -94,7 +89,7 @@ async function get_file(url) {
|
||||||
return { stream, ext };
|
return { stream, ext };
|
||||||
}
|
}
|
||||||
|
|
||||||
const server = https.createServer(config, async (req, res) => {
|
const server = http.createServer(async (req, res) => {
|
||||||
const file = await get_file(req.url);
|
const file = await get_file(req.url);
|
||||||
if (!file) {
|
if (!file) {
|
||||||
res.writeHead(404);
|
res.writeHead(404);
|
||||||
|
@ -226,7 +221,7 @@ function generate_colour() {
|
||||||
}
|
}
|
||||||
|
|
||||||
server.listen(PORT, () => {
|
server.listen(PORT, () => {
|
||||||
console.log(`OpenTerminal is now LIVE on https://127.0.0.1:${PORT}!`);
|
console.log(`OpenTerminal is now LIVE on http://127.0.0.1:${PORT}`);
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
Loading…
Reference in a new issue