http first! implements warning for insecure connections

This commit is contained in:
ari melody 2024-01-16 01:07:47 +00:00 committed by GitHub
commit bb48b93729
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 140 additions and 40 deletions

View file

@ -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>

View file

@ -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,11 +41,15 @@ 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", () => {
[...document.getElementsByClassName("dialog")].forEach(element => {
element.classList.remove("show");
});
dialog_backdrop.classList.remove("show"); dialog_backdrop.classList.remove("show");
Terminal.set_enable_input(true); Terminal.set_enable_input(true);
}); });
});
dialog_backdrop.addEventListener("click", () => { dialog_backdrop.addEventListener("click", () => {
connect_close.click(); connect_close.click();

View file

@ -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.

View file

@ -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;

View file

@ -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}`);
}); });
/** /**