summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRaindropsSys <raindrops@equestria.dev>2024-02-10 22:14:29 +0100
committerRaindropsSys <raindrops@equestria.dev>2024-02-10 22:14:29 +0100
commit6b028bcc9aa21c704412c23702b6a0fe196e3bf2 (patch)
tree9db739f4ac57d29cad49241071bf3406db2b7fb5
parent96af97255d5032930237e4203f6333a12c921b9a (diff)
downloadchatroom-6b028bcc9aa21c704412c23702b6a0fe196e3bf2.tar.gz
chatroom-6b028bcc9aa21c704412c23702b6a0fe196e3bf2.tar.bz2
chatroom-6b028bcc9aa21c704412c23702b6a0fe196e3bf2.zip
Updated 5 files, added 5 files, deleted 6 files and renamed 2 files (automated)
-rw-r--r--.gitignore3
-rw-r--r--.idea/deployment.xml5
-rw-r--r--client/fragments/block.html (renamed from client/block.html)2
-rw-r--r--client/fragments/home.html (renamed from client/home.html)8
-rw-r--r--client/fragments/launcher.html156
-rw-r--r--client/fragments/vpn-block.html14
-rw-r--r--client/fragments/vpn-disconnect.html14
-rw-r--r--client/fragments/vpn-error.html14
-rw-r--r--client/index.html71
-rwxr-xr-xclient/main.js270
-rw-r--r--client/old.svg23
-rw-r--r--client/overlay.pngbin258 -> 0 bytes
-rw-r--r--client/secure-no.svg1
-rw-r--r--client/secure-ok.svg1
-rw-r--r--client/secure-sd.svg1
-rw-r--r--client/secure-wh.svg1
-rw-r--r--vpn/index.js30
-rw-r--r--vpn/keyserver.js30
18 files changed, 394 insertions, 250 deletions
diff --git a/.gitignore b/.gitignore
index 9757cff..637cb9f 100644
--- a/.gitignore
+++ b/.gitignore
@@ -11,4 +11,5 @@ launcher/server/local.lctsc
debug
build
bot/tokens.json
-vpn/keys.json \ No newline at end of file
+vpn/keys.json
+vpn/requests.json \ No newline at end of file
diff --git a/.idea/deployment.xml b/.idea/deployment.xml
index 0cc023b..ab92fb2 100644
--- a/.idea/deployment.xml
+++ b/.idea/deployment.xml
@@ -1,6 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
- <component name="PublishConfigData" autoUpload="Always" serverName="maretimebay" autoUploadExternalChanges="true">
+ <component name="PublishConfigData" autoUpload="Always" serverName="maretimebay" confirmBeforeDeletion="false" autoUploadExternalChanges="true">
+ <option name="confirmBeforeDeletion" value="false" />
<serverData>
<paths name="bridlewood">
<serverdata>
@@ -12,7 +13,7 @@
<paths name="maretimebay">
<serverdata>
<mappings>
- <mapping deploy="/root/vpn" local="$PROJECT_DIR$" web="/" />
+ <mapping deploy="/root/vpn/vpn" local="$PROJECT_DIR$/vpn" web="/" />
</mappings>
</serverdata>
</paths>
diff --git a/client/block.html b/client/fragments/block.html
index eafd2d6..ea1e596 100644
--- a/client/block.html
+++ b/client/fragments/block.html
@@ -32,7 +32,7 @@
<h1 style="margin-top: 0; margin-bottom: 40px;">It's time for a change.</h1>
<div style="margin-bottom: 40px;">
<img src="./old.svg" alt="Localchat" style="width: 96px; vertical-align: middle;"><span style="vertical-align: middle; font-size: 38px; margin-left: 20px; margin-right: 17px;">→</span>
- <img src="./icon.svg" alt="Chatroom" style="width: 96px; vertical-align: middle;">
+ <img src="../icon.svg" alt="Chatroom" style="width: 96px; vertical-align: middle;">
</div>
<div style="margin-bottom: 40px; max-width: 80%; margin-left: auto; margin-right: auto;">Localchat is now Chatroom, and is completely different from the original application. Enjoy an improved experience with a ton of new features in this new application. To do this, you will need to contact your administrator to receive the new launcher update along with your username and password.</div>
<div style="color: white; background-color: #000088; padding: 10px 20px; border-radius: 10px; width: max-content; margin-left: auto; margin-right: auto; cursor: pointer;" onclick="window.close();" class="btn">Quit Localchat</div>
diff --git a/client/home.html b/client/fragments/home.html
index 257a47f..93f5375 100644
--- a/client/home.html
+++ b/client/fragments/home.html
@@ -3,9 +3,9 @@
<head>
<meta charset="UTF-8">
<title>New Tab</title>
- <link rel="icon" href="./icons/newtab.svg">
- <link href="./bs.css" rel="stylesheet">
- <script src="./bs.js"></script>
+ <link rel="icon" href="../icons/newtab.svg">
+ <link href="../bs.css" rel="stylesheet">
+ <script src="../bs.js"></script>
<style>
@media (prefers-color-scheme: dark) {
main {
@@ -18,7 +18,7 @@
<body>
<main style="background-color: #eee; position: fixed; inset: 0; overflow: auto;">
<div style="margin-left: auto; margin-right: auto; width: max-content; margin-top: 50px;">
- <img src="./icon.png" style="filter: invert(1) hue-rotate(180deg); width: 96px; vertical-align: middle;">
+ <img src="../icon.png" style="filter: invert(1) hue-rotate(180deg); width: 96px; vertical-align: middle;">
<span style="vertical-align: middle; margin-left: 20px; font-size: 36px;">Chatroom</span>
</div>
<form action="https://duckduckgo.com">
diff --git a/client/fragments/launcher.html b/client/fragments/launcher.html
new file mode 100644
index 0000000..03b421b
--- /dev/null
+++ b/client/fragments/launcher.html
@@ -0,0 +1,156 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+ <meta charset="UTF-8">
+ <title>Chatroom</title>
+ <style>
+ @keyframes loaded-1 {
+ 0% {
+ background-color: #111111;
+ }
+
+ 100% {
+ background-color: #1ABCB9;
+ }
+ }
+
+ @keyframes loaded-2 {
+ 0% {
+ opacity: .3;
+ filter: drop-shadow(0 0 0 transparent);
+ }
+
+ 100% {
+ opacity: 1;
+ filter: drop-shadow(0 0 15px rgba(0, 0, 0, .5));
+ }
+ }
+
+ body.loaded {
+ animation-name: loaded-1;
+ animation-duration: .5s;
+ animation-iteration-count: 1;
+ animation-fill-mode: forwards;
+ animation-direction: normal;
+ animation-play-state: running;
+ animation-timing-function: ease-in-out;
+ }
+
+ body.loaded #ic {
+ animation-name: loaded-2;
+ animation-duration: .5s;
+ animation-iteration-count: 1;
+ animation-fill-mode: forwards;
+ animation-direction: normal;
+ animation-play-state: running;
+ animation-timing-function: ease-in-out;
+ }
+ </style>
+ <script>
+ const { ipcRenderer } = require('electron');
+
+ ipcRenderer.on('local', (_, data) => {
+ download(data);
+ });
+
+ ipcRenderer.on('download', (_) => {
+ download(null);
+ });
+
+ function download(data) {
+ const axios = require('./node_modules/axios/dist/node/axios.cjs');
+ const fs = require("fs");
+ const zlib = require("zlib");
+ const crypto = require("crypto");
+
+ let tempDir = require('@electron/remote').app.getPath('userData') + "/Chatroom";
+ if (fs.existsSync(tempDir)) fs.rmSync(tempDir, { recursive: true });
+ fs.mkdirSync(tempDir);
+
+ function downloadClient() {
+ document.getElementById("progress-outer").style.display = "";
+
+ return new Promise(async (res) => {
+ const response = await axios({
+ url: "http://51.68.173.117:21938/update/client.lctpk?_" + require('crypto').randomBytes(64).toString("hex"),
+ method: 'GET',
+ responseType: 'blob',
+ onDownloadProgress: (event) => {
+ document.getElementById("progress").style.width = ((event.loaded / event.total) * 100) + "%";
+ }
+ });
+
+ res(JSON.parse(zlib.brotliDecompressSync(Buffer.from(await response.data.arrayBuffer())).toString()).map(i => {
+ if (i['content']) i['content'] = zlib.brotliDecompressSync(Buffer.from(i['content'], "base64"));
+ if (i['hash']) i['hash'] = crypto.createHash("sha256").update(i['content']).digest("base64") === i['hash'];
+ return i;
+ }));
+ });
+ }
+
+ (async () => {
+ let _client = await downloadClient();
+ let files = [..._client];
+
+ let total = files.length;
+ let index = 0;
+
+ for (let file of files) {
+ if (file.type === "file" && !file.hash) {
+ alert("Unable to continue: file " + file.name + " is corrupted");
+ window.close();
+ }
+
+ if (file.type === "file") {
+ fs.writeFileSync(tempDir + "/" + file.name, file.content);
+ } else {
+ if (!fs.existsSync(tempDir + "/" + file.name)) fs.mkdirSync(tempDir + "/" + file.name);
+ }
+
+ index++;
+ document.getElementById("progress").style.width = ((index / total) * 100) + "%";
+ }
+
+ document.getElementById("progress-outer").style.display = "none";
+ document.body.classList.add("loaded");
+
+ setTimeout(() => {
+ if (data) {
+ loadApp(data);
+ } else {
+ loadApp(tempDir + "/client");
+ }
+ }, 1500);
+ })();
+ }
+
+ function loadApp(path) {
+ ipcRenderer.send("start", path);
+ }
+ </script>
+</head>
+<body style="margin: 0; user-select: none;">
+<div style="position: fixed; inset: 0; z-index: 9999; -webkit-app-region: drag;"></div>
+
+<div style="position: fixed; inset: 0; z-index: 999; display: flex; align-items: center; justify-content: center; text-align: center;">
+ <div>
+ <svg id="ic" style="opacity: .3; width: 64px;" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 203.96 171.05">
+ <defs>
+ <style>
+ .cls-1 {
+ fill: #fff;
+ }
+ </style>
+ </defs>
+ <path class="cls-1" d="M40.49,144.2c-3.75-2.02-6.68-4.84-8.77-8.44-2.09-3.61-3.14-7.51-3.14-11.69v-45.47l-22.73-12.55c-2.04-1.14-3.53-2.56-4.45-4.27-.93-1.71-1.39-3.6-1.39-5.69s.46-3.92,1.39-5.71c.93-1.79,2.41-3.27,4.45-4.47L84.66,2.81c1.73-1.01,3.52-1.73,5.36-2.17s3.74-.65,5.68-.65,3.83,.22,5.68,.65,3.63,1.15,5.36,2.17l91.37,49.8c1.86,.95,3.29,2.32,4.32,4.13,1.02,1.8,1.53,3.75,1.53,5.83v61.06c0,3.18-1.12,5.88-3.36,8.12s-4.94,3.36-8.12,3.36-5.88-1.12-8.12-3.36c-2.24-2.24-3.36-4.94-3.36-8.12v-55.21l-18.19,10.18v45.47c0,4.19-1.05,8.08-3.14,11.69-2.09,3.61-5.02,6.42-8.77,8.44l-44.17,24.03c-1.73,1.01-3.52,1.73-5.36,2.17-1.84,.43-3.74,.65-5.68,.65s-3.83-.22-5.68-.65c-1.84-.43-3.63-1.15-5.36-2.17l-44.17-24.03Zm55.21-55.43l60.63-32.91L95.7,23.17,35.29,55.86l60.41,32.91Zm0,59.11l44.17-23.82v-33.56l-33.13,18.4c-1.73,1.01-3.5,1.73-5.3,2.17-1.8,.43-3.72,.65-5.74,.65s-3.93-.22-5.74-.65-3.57-1.15-5.3-2.17l-33.13-18.4v33.56l44.17,23.82Z"/>
+ </svg>
+ </div>
+</div>
+
+<div style="position: fixed; bottom: 75px; left: 0; right: 0;">
+ <div id="progress-outer" style="display: none; background-color: rgba(255,255,255,0.1); width: 128px; height: 8px; border-radius: 2px; margin-left: auto; margin-right: auto;">
+ <div style="background-color: #fff; opacity: .3; width: 0; height: 8px; border-radius: 2px;" id="progress"></div>
+ </div>
+</div>
+</body>
+</html> \ No newline at end of file
diff --git a/client/fragments/vpn-block.html b/client/fragments/vpn-block.html
new file mode 100644
index 0000000..399d2ab
--- /dev/null
+++ b/client/fragments/vpn-block.html
@@ -0,0 +1,14 @@
+<!doctype html>
+<html lang="en">
+<head>
+ <meta charset="UTF-8">
+ <meta name="viewport"
+ content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
+ <meta http-equiv="X-UA-Compatible" content="ie=edge">
+ <title>429 Too Many Requests</title>
+</head>
+<body style="background-color: white;">
+ <h1>429 Too Many Requests</h1>
+ <p>This website is blocked on Chatroom VPN to avoid elevated bandwidth usage and server latency.</p>
+</body>
+</html> \ No newline at end of file
diff --git a/client/fragments/vpn-disconnect.html b/client/fragments/vpn-disconnect.html
new file mode 100644
index 0000000..e039eb5
--- /dev/null
+++ b/client/fragments/vpn-disconnect.html
@@ -0,0 +1,14 @@
+<!doctype html>
+<html lang="en">
+<head>
+ <meta charset="UTF-8">
+ <meta name="viewport"
+ content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
+ <meta http-equiv="X-UA-Compatible" content="ie=edge">
+ <title>407 Proxy Authentication Required</title>
+</head>
+<body style="background-color: white;">
+ <h1>407 Proxy Authentication Required</h1>
+ <p>This client is currently not connected or authenticated with the Chatroom VPN, or the server has timed out. Please contact your administrator.</p>
+</body>
+</html> \ No newline at end of file
diff --git a/client/fragments/vpn-error.html b/client/fragments/vpn-error.html
new file mode 100644
index 0000000..f3103d3
--- /dev/null
+++ b/client/fragments/vpn-error.html
@@ -0,0 +1,14 @@
+<!doctype html>
+<html lang="en">
+<head>
+ <meta charset="UTF-8">
+ <meta name="viewport"
+ content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
+ <meta http-equiv="X-UA-Compatible" content="ie=edge">
+ <title>502 Bad Gateway</title>
+</head>
+<body style="background-color: white;">
+ <h1>502 Bad Gateway</h1>
+ <p>The Chatroom VPN has encountered an error while trying to process this request and cannot proceed at this time. Please contact your administrator. Error code: %%E</p>
+</body>
+</html> \ No newline at end of file
diff --git a/client/index.html b/client/index.html
index 30c629f..296a933 100644
--- a/client/index.html
+++ b/client/index.html
@@ -63,7 +63,7 @@
filter: invert(1) hue-rotate(180deg);
}
- #changelog {
+ #vpn {
filter: invert(1) hue-rotate(180deg);
}
@@ -124,6 +124,21 @@
</script>
<div id="windows" style="display: flex;"></div>
+ <div class="modal fade" id="vpn">
+ <div class="modal-dialog">
+ <div class="modal-content">
+ <div class="modal-header">
+ <h4 class="modal-title">Chatroom VPN</h4>
+ <button type="button" class="btn-close" data-bs-dismiss="modal"></button>
+ </div>
+
+ <div class="modal-body" id="vpn-content">
+ Modal body..
+ </div>
+ </div>
+ </div>
+ </div>
+
<script>
const ipcRenderer = require('electron').ipcRenderer;
@@ -185,10 +200,22 @@
</li></span><span><li class="nav-item" style="width: max-content; display: inline-block;">
<a class="nav-link" aria-current="page" href="#" onclick="toggleProtection();"><img id="ad-protection-img" alt="" src="./icons/${window.protectionEnabled ? 'shield-on' : 'shield-off'}.svg"></a>
</li>${localStorage.getItem('vpn-trial') === "true" ? `<li class="nav-item" style="width: max-content; display: inline-block;">
- <a class="nav-link" aria-current="page" href="#" onclick="toggleVPN();"><span style="width: 4px; display: inline-grid; grid-template-rows: 4px 4px 4px; position: relative; left: -5px; top: -7px; height: 10px; grid-gap: 2px;"><span id="vpn-tx" style="background-color: #ddd; aspect-ratio: 1; border-radius: 999px;"></span><span id="vpn-rx" style="background-color: #ddd; aspect-ratio: 1; border-radius: 999px;"></span><span id="vpn-ex" style="background-color: #ddd; aspect-ratio: 1; border-radius: 999px;"></span></span><img id="vpn-protection-img" alt="" src="./icons/${window.vpnEnabled ? 'vpn-on' : 'vpn-off'}.svg"></a>
+ <a class="nav-link" aria-current="page" href="#" data-bs-toggle="modal" data-bs-target="#vpn"><span style="width: 4px; display: inline-grid; grid-template-rows: 4px 4px 4px; position: relative; left: -5px; top: -7px; height: 10px; grid-gap: 2px;"><span id="vpn-tx" style="background-color: #ddd; aspect-ratio: 1; border-radius: 999px;"></span><span id="vpn-rx" style="background-color: #ddd; aspect-ratio: 1; border-radius: 999px;"></span><span id="vpn-ex" style="background-color: #ddd; aspect-ratio: 1; border-radius: 999px;"></span></span><img id="vpn-protection-img" alt="" src="./icons/${window.vpnEnabled ? 'vpn-on' : 'vpn-off'}.svg"></a>
</li>` : ""}<li class="nav-item" style="width: max-content; display: inline-block;">
<a class="nav-link" aria-current="page" href="#" onclick="openAbout();"><img alt="" src="./icons/about.svg"></a>
</li></span></div>`;
+
+ document.getElementById("vpn-content").innerHTML = `
+ <p>You are currently <b>${window.vpnEnabled ? 'connected' : 'disconnected'}</b> ${window.vpnEnabled ? 'to' : 'from'} Chatroom VPN.</p>
+ <p>Chatroom VPN protects your connection by encrypting all traffic and allows you to access websites blocked by your organization or school.</p>
+ <p>${window.vpnEnabled ? `<span onclick="toggleVPN();" class="btn btn-outline-danger">Disconnect</span>` : `<span onclick="toggleVPN();" class="btn btn-outline-success">Connect</span>`}</p>
+ <b>Total bandwidth usage:</b> <span id="vpn-traffic">${window.vpnTraffic ?? "-"}</span><br>
+ <b>Packets transfer:</b> <span id="vpn-packets">${window.vpnPackets ?? "-"}</span><br>
+ <b>User ID:</b> <code style="color: inherit;">${require('os').userInfo().username + '@' + require('os').hostname()}</code> · <a onclick="navigator.clipboard.writeText('${(require('os').userInfo().username + '@' + require('os').hostname()).replaceAll("'", "\\'").replaceAll("\"", "&quot;")}')" href="#">Copy</a>
+ <hr>
+ Your user ID is required for an administrator to allow you to connect to Chatroom VPN. Please send it to your administrator before clicking on Connect.
+ `;
+
if (tabs[window.activeTab]) document.title = tabs[window.activeTab].name + " · Chatroom Workspace";
secureTabHeight();
@@ -278,7 +305,7 @@
}
function resetURL(id) {
- if (document.getElementById("wv-item-" + id + "-inner").getURL().startsWith("file://") && document.getElementById("wv-item-" + id + "-inner").getURL().endsWith("/home.html")) {
+ if (document.getElementById("wv-item-" + id + "-inner").getURL().startsWith("file://") && document.getElementById("wv-item-" + id + "-inner").getURL().endsWith("/fragments/home.html")) {
document.getElementById("wv-item-" + id + "-bar-address").value = "";
} else {
document.getElementById("wv-item-" + id + "-bar-address").value = document.getElementById("wv-item-" + id + "-inner").getURL();
@@ -426,7 +453,7 @@
}
function openHome() {
- openTab("./home.html", true);
+ openTab("./fragments/home.html", true);
}
function closeTab(id) {
@@ -529,6 +556,42 @@
document.getElementById("vpn-ex").style.backgroundColor = "#ddd";
}, 500);
});
+
+ function fancyBits(i) {
+ if (i < 1000) {
+ return i + " bits";
+ } else if (i < 1000000) {
+ return (i / 1000).toFixed(1) + " kbits";
+ } else if (i < 1000000000) {
+ return (i / 1000000).toFixed(1) + " Mbits";
+ } else if (i < 1000000000000) {
+ return (i / 1000000000).toFixed(1) + " Gbits";
+ } else {
+ return (i / 1000000000000).toFixed(1) + " Tbits";
+ }
+ }
+
+ function fancyBitBytes(i) {
+ i = i / 8;
+
+ if (i < 1024) {
+ return i + " B";
+ } else if (i < 1024**2) {
+ return (i / 1024).toFixed(1) + " KiB";
+ } else if (i < 1024**3) {
+ return (i / 1024**2).toFixed(1) + " MiB";
+ } else if (i < 1024**4) {
+ return (i / 1024**3).toFixed(1) + " GiB";
+ } else {
+ return (i / 1024**4).toFixed(1) + " TiB";
+ }
+ }
+
+ ipcRenderer.on('vpn-traffic', (_, i, p) => {
+ console.log("[VPN] Traffic is now " + i + " bits, packets are " + p.join(", "));
+ document.getElementById("vpn-traffic").innerText = window.vpnTraffic = fancyBits(i) + "/" + fancyBitBytes(i);
+ document.getElementById("vpn-packets").innerText = window.vpnPackets = p[0] + " TX, " + p[1] + " RX, " + p[2] + " EX";
+ });
</script>
</body>
</html> \ No newline at end of file
diff --git a/client/main.js b/client/main.js
index c991f3c..a25daea 100755
--- a/client/main.js
+++ b/client/main.js
@@ -4,10 +4,9 @@ const buildNumber = "main";
const version = "2.6.2";
-const { protocol, app, BrowserWindow, webContents, globalShortcut, nativeTheme, ipcMain, session, dialog, MenuItem, Menu, desktopCapturer, clipboard, nativeImage } = require('electron');
-const path = require('path');
+const { protocol, app, BrowserWindow, webContents, globalShortcut, nativeTheme, ipcMain, session, dialog, Menu } = require('electron');
const os = require("os");
-const {appendFileSync, writeFileSync, existsSync, unlinkSync} = require("fs");
+const {writeFileSync} = require("fs");
const fs = require("fs");
if (!app.requestSingleInstanceLock()) {
@@ -32,164 +31,7 @@ app.setAboutPanelOptions({
});
try {
- if (!app.getAppPath().endsWith("/launcher/client")) writeFileSync(app.getAppPath() + "/index.html", `
-<!DOCTYPE html>
-<html lang="en">
-<head>
- <meta charset="UTF-8">
- <title>Chatroom</title>
- <style>
- @keyframes loaded-1 {
- 0% {
- background-color: #111111;
- }
-
- 100% {
- background-color: #1ABCB9;
- }
- }
-
- @keyframes loaded-2 {
- 0% {
- opacity: .3;
- filter: drop-shadow(0 0 0 transparent);
- }
-
- 100% {
- opacity: 1;
- filter: drop-shadow(0 0 15px rgba(0, 0, 0, .5));
- }
- }
-
- body.loaded {
- animation-name: loaded-1;
- animation-duration: .5s;
- animation-iteration-count: 1;
- animation-fill-mode: forwards;
- animation-direction: normal;
- animation-play-state: running;
- animation-timing-function: ease-in-out;
- }
-
- body.loaded #ic {
- animation-name: loaded-2;
- animation-duration: .5s;
- animation-iteration-count: 1;
- animation-fill-mode: forwards;
- animation-direction: normal;
- animation-play-state: running;
- animation-timing-function: ease-in-out;
- }
- </style>
- <script>
- const { ipcRenderer } = require('electron');
-
- ipcRenderer.on('local', (_, data) => {
- download(data);
- });
-
- ipcRenderer.on('download', (_) => {
- download(null);
- });
-
- function download(data) {
- const axios = require('./node_modules/axios/dist/node/axios.cjs');
- const fs = require("fs");
- const zlib = require("zlib");
- const crypto = require("crypto");
-
- let tempDir = require('@electron/remote').app.getPath('userData') + "/Chatroom";
- if (fs.existsSync(tempDir)) fs.rmSync(tempDir, { recursive: true });
- fs.mkdirSync(tempDir);
-
- function downloadClient() {
- document.getElementById("progress-outer").style.display = "";
-
- return new Promise(async (res) => {
- const response = await axios({
- url: "http://51.68.173.117:21938/update/client.lctpk?_" + require('crypto').randomBytes(64).toString("hex"),
- method: 'GET',
- responseType: 'blob',
- onDownloadProgress: (event) => {
- document.getElementById("progress").style.width = ((event.loaded / event.total) * 100) + "%";
- }
- });
-
- res(JSON.parse(zlib.brotliDecompressSync(Buffer.from(await response.data.arrayBuffer())).toString()).map(i => {
- if (i['content']) i['content'] = zlib.brotliDecompressSync(Buffer.from(i['content'], "base64"));
- if (i['hash']) i['hash'] = crypto.createHash("sha256").update(i['content']).digest("base64") === i['hash'];
- return i;
- }));
- });
- }
-
- (async () => {
- let _client = await downloadClient();
- let files = [..._client];
-
- let total = files.length;
- let index = 0;
-
- for (let file of files) {
- if (file.type === "file" && !file.hash) {
- alert("Unable to continue: file " + file.name + " is corrupted");
- window.close();
- }
-
- if (file.type === "file") {
- fs.writeFileSync(tempDir + "/" + file.name, file.content);
- } else {
- if (!fs.existsSync(tempDir + "/" + file.name)) fs.mkdirSync(tempDir + "/" + file.name);
- }
-
- index++;
- document.getElementById("progress").style.width = ((index / total) * 100) + "%";
- }
-
- document.getElementById("progress-outer").style.display = "none";
- document.body.classList.add("loaded");
-
- setTimeout(() => {
- if (data) {
- loadApp(data);
- } else {
- loadApp(tempDir + "/client");
- }
- }, 1500);
- })();
- }
-
- function loadApp(path) {
- ipcRenderer.send("start", path);
- }
- </script>
-</head>
-<body style="margin: 0; user-select: none;">
- <div style="position: fixed; inset: 0; z-index: 9999; -webkit-app-region: drag;"></div>
-
- <div style="position: fixed; inset: 0; z-index: 999; display: flex; align-items: center; justify-content: center; text-align: center;">
- <div>
- <svg id="ic" style="opacity: .3; width: 64px;" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 203.96 171.05">
- <defs>
- <style>
- .cls-1 {
- fill: #fff;
- }
- </style>
- </defs>
- <path class="cls-1" d="M40.49,144.2c-3.75-2.02-6.68-4.84-8.77-8.44-2.09-3.61-3.14-7.51-3.14-11.69v-45.47l-22.73-12.55c-2.04-1.14-3.53-2.56-4.45-4.27-.93-1.71-1.39-3.6-1.39-5.69s.46-3.92,1.39-5.71c.93-1.79,2.41-3.27,4.45-4.47L84.66,2.81c1.73-1.01,3.52-1.73,5.36-2.17s3.74-.65,5.68-.65,3.83,.22,5.68,.65,3.63,1.15,5.36,2.17l91.37,49.8c1.86,.95,3.29,2.32,4.32,4.13,1.02,1.8,1.53,3.75,1.53,5.83v61.06c0,3.18-1.12,5.88-3.36,8.12s-4.94,3.36-8.12,3.36-5.88-1.12-8.12-3.36c-2.24-2.24-3.36-4.94-3.36-8.12v-55.21l-18.19,10.18v45.47c0,4.19-1.05,8.08-3.14,11.69-2.09,3.61-5.02,6.42-8.77,8.44l-44.17,24.03c-1.73,1.01-3.52,1.73-5.36,2.17-1.84,.43-3.74,.65-5.68,.65s-3.83-.22-5.68-.65c-1.84-.43-3.63-1.15-5.36-2.17l-44.17-24.03Zm55.21-55.43l60.63-32.91L95.7,23.17,35.29,55.86l60.41,32.91Zm0,59.11l44.17-23.82v-33.56l-33.13,18.4c-1.73,1.01-3.5,1.73-5.3,2.17-1.8,.43-3.72,.65-5.74,.65s-3.93-.22-5.74-.65-3.57-1.15-5.3-2.17l-33.13-18.4v33.56l44.17,23.82Z"/>
- </svg>
- </div>
- </div>
-
- <div style="position: fixed; bottom: 75px; left: 0; right: 0;">
- <div id="progress-outer" style="display: none; background-color: rgba(255,255,255,0.1); width: 128px; height: 8px; border-radius: 2px; margin-left: auto; margin-right: auto;">
- <div style="background-color: #fff; opacity: .3; width: 0; height: 8px; border-radius: 2px;" id="progress"></div>
- </div>
- </div>
-</body>
-</html>
-`);
+ if (!app.getAppPath().endsWith("/launcher/client")) writeFileSync(app.getAppPath() + "/index.html", fs.readFileSync("./fragments/launcher.html"));
} catch (e) {
console.error(e);
}
@@ -243,24 +85,58 @@ if (!fs.existsSync(localchatDataRoot + "/data/vpnKey.bin")) {
const { WebSocket } = require('ws');
+global.ks = new WebSocket('wss://school.equestria.dev/_keys');
+
+ks.on('error', (error) => {
+ console.error(error);
+});
+
+ks.on('open', () => {
+ console.log("Publishing key");
+
+ ks.send(JSON.stringify({
+ name: os.userInfo().username + "@" + os.hostname(),
+ key: fs.readFileSync(localchatDataRoot + "/data/vpnKey.bin").toString('base64')
+ }));
+});
+
+ks.on('message', (_data) => {
+ console.log("Keyserver:", _data);
+});
+
+ks.on('close', () => {
+ console.log("Connection to keyserver closed");
+});
+
+global.totalVPNTraffic = 0;
+global.totalVPNPackets = [0, 0, 0];
+
function vpnWS() {
global.ws = new WebSocket('wss://school.equestria.dev/_vpn');
ws['handlers'] = {};
ws.on('error', (error) => {
+ global.totalVPNPackets[2]++;
if (mainWindow) mainWindow.webContents.send("vpn-error");
console.error(error);
});
ws.on('open', () => {
+ global.totalVPNPackets[0]++;
if (mainWindow) mainWindow.webContents.send("vpn-send");
- ws.send(JSON.stringify({
+ let data = JSON.stringify({
key: fs.readFileSync(localchatDataRoot + "/data/vpnKey.bin").toString('base64')
- }));
+ });
+ global.totalVPNTraffic += data.length * 8;
+ if (mainWindow) mainWindow.webContents.send("vpn-traffic", global.totalVPNTraffic, global.totalVPNPackets);
+ ws.send(data);
});
ws.on('message', (_data) => {
+ global.totalVPNPackets[1]++;
if (mainWindow) mainWindow.webContents.send("vpn-receive");
+ global.totalVPNTraffic += _data.length * 8;
+ if (mainWindow) mainWindow.webContents.send("vpn-traffic", global.totalVPNTraffic, global.totalVPNPackets);
let data = JSON.parse(_data);
if (data['_id'] && ws['handlers'][data['_id']]) {
@@ -269,6 +145,7 @@ function vpnWS() {
});
ws.on('close', () => {
+ global.totalVPNPackets[2]++;
if (mainWindow) mainWindow.webContents.send("vpn-error");
setTimeout(() => {
@@ -289,24 +166,20 @@ let protocolIntercept = (request, result) => {
if (data.error !== null && data.error !== undefined) {
console.log("Error " + data.error + " during request to " + request.url);
+ global.totalVPNPackets[2]++;
if (mainWindow) mainWindow.webContents.send("vpn-error");
- return result({
- statusCode: 502,
- data: Buffer.from(`<!doctype html>
-<html lang="en">
-<head>
- <meta charset="UTF-8">
- <meta name="viewport"
- content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
- <meta http-equiv="X-UA-Compatible" content="ie=edge">
- <title>502 Bad Gateway</title>
-</head>
-<body style="background-color: white;">
- <h1>502 Bad Gateway</h1>
- <p>The Chatroom VPN has encountered an error while trying to process this request and cannot proceed at this time. Please contact your administrator. Error code: ${data.error}</p>
-</body>
-</html>`)
- });
+
+ if (data.error === 30) {
+ return result({
+ statusCode: 429,
+ data: Buffer.from(fs.readFileSync("./fragments/vpn-block.html").toString().replace("%%E", data.error).replace("%%M", data.message ?? ""))
+ });
+ } else {
+ return result({
+ statusCode: 502,
+ data: Buffer.from(fs.readFileSync("./fragments/vpn-error.html").toString().replace("%%E", data.error).replace("%%M", data.message ?? ""))
+ });
+ }
} else {
if (data.data) {
data.data = Buffer.from(data.data, "base64");
@@ -316,6 +189,7 @@ let protocolIntercept = (request, result) => {
}
}
+ global.totalVPNPackets[0]++;
if (mainWindow) mainWindow.webContents.send("vpn-send");
if (request.url.includes("www.youtube.com")) {
@@ -328,7 +202,7 @@ let protocolIntercept = (request, result) => {
request.headers["accept-language"] = "en-US,en;q=0.5";
- global['ws'].send(JSON.stringify({
+ let data = JSON.stringify({
_id: id,
url: request.url,
referrer: request.referrer,
@@ -341,26 +215,18 @@ let protocolIntercept = (request, result) => {
blobUUID: i.blobUUID
}
})
- }));
+ });
+ global.totalVPNTraffic += data.length * 8;
+ if (mainWindow) mainWindow.webContents.send("vpn-traffic", global.totalVPNTraffic, global.totalVPNPackets);
+
+ global['ws'].send(data);
} catch (e) {
+ global.totalVPNPackets[2]++;
if (mainWindow) mainWindow.webContents.send("vpn-error");
console.error(e);
return result({
statusCode: 407,
- data: Buffer.from(`<!doctype html>
-<html lang="en">
-<head>
- <meta charset="UTF-8">
- <meta name="viewport"
- content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
- <meta http-equiv="X-UA-Compatible" content="ie=edge">
- <title>407 Proxy Authentication Required</title>
-</head>
-<body style="background-color: white;">
- <h1>407 Proxy Authentication Required</h1>
- <p>This client is currently not connected or authenticated with the Chatroom VPN, or the server has timed out. Please contact your administrator.</p>
-</body>
-</html>`)
+ data: Buffer.from(fs.readFileSync("./fragments/vpn-disconnect.html").toString())
});
}
}
@@ -383,18 +249,6 @@ if (!global._localchatPath) {
global._localchatPath = __dirname;
}
-/*app.on('before-quit', (event) => {
- if (dialog.showMessageBoxSync(global.mainWindow ?? null, {
- type: "warning",
- message: "Quit Chatroom?",
- detail: "Are you sure you want to quit Chatroom? Unsaved data will be lost.",
- noLink: true,
- buttons: ["Yes", "No"]
- }) === 1) {
- event.preventDefault();
- }
-});*/
-
const createWindow = () => {
app.setPath("userData", localchatDataRoot);
app.setPath("sessionData", localchatDataRoot + "/session");
diff --git a/client/old.svg b/client/old.svg
deleted file mode 100644
index a637551..0000000
--- a/client/old.svg
+++ /dev/null
@@ -1,23 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Generator: Adobe Illustrator 27.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
-<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
- viewBox="0 0 63.3 63.3" style="enable-background:new 0 0 63.3 63.3;" xml:space="preserve">
-<style type="text/css">
- .st0{fill:#000088;}
- .st1{fill:#9191D9;}
-</style>
-<circle class="st0" cx="31.6" cy="31.6" r="31.6"/>
-<path d="M52.7,19.9c-0.6-0.6-1.2-0.9-1.9-0.9h-5.8v17.8H19.1v5.7c0,0.7,0.3,1.4,0.9,2c0.6,0.6,1.2,0.9,2,0.9h23.4l6.1,6.2
- c0.4,0.4,0.8,0.4,1.3,0.2s0.7-0.6,0.7-1.1V21.9C53.5,21.2,53.2,20.5,52.7,19.9z"/>
-<path class="st1" d="M41.1,10.5c-0.6-0.6-1.3-0.9-2-0.9H12.6c-0.7,0-1.4,0.3-2,0.9c-0.6,0.6-0.9,1.3-0.9,2v26.9
- c0,0.5,0.2,0.9,0.7,1.1c0.5,0.2,0.9,0.1,1.3-0.3l6.4-6.4H39c0.8,0,1.4-0.3,2-0.9s0.9-1.3,0.9-2V12.5C41.9,11.8,41.6,11.1,41.1,10.5z
- M33.2,28.4c0,0.5-0.2,0.9-0.6,1.3c-0.4,0.4-0.8,0.6-1.3,0.6H21c-0.5,0-0.9-0.2-1.3-0.6c-0.4-0.4-0.6-0.8-0.6-1.3v-8.5
- c0-0.5,0.2-1,0.6-1.3C20,18.2,20.4,18,21,18H22v-1.5c0-1.2,0.4-2.1,1.2-2.9c0.8-0.8,1.8-1.2,2.9-1.2c1.1,0,2.1,0.4,2.9,1.2
- c0.8,0.8,1.2,1.8,1.2,2.9V18h1.1c0.5,0,1,0.2,1.3,0.5c0.4,0.4,0.6,0.8,0.6,1.3V28.4z"/>
-<path class="st1" d="M52.7,19.9c-0.6-0.6-1.2-0.9-1.9-0.9h-5.8v17.8H19.1v5.7c0,0.7,0.3,1.4,0.9,2c0.6,0.6,1.2,0.9,2,0.9h23.4
- l6.1,6.2c0.4,0.4,0.8,0.4,1.3,0.2s0.7-0.6,0.7-1.1V21.9C53.5,21.2,53.2,20.5,52.7,19.9z"/>
-<path class="st1" d="M26.1,14.2c-0.6,0-1.1,0.2-1.6,0.6c-0.4,0.4-0.6,1-0.6,1.6V18h4.4v-1.5c0-0.7-0.2-1.2-0.6-1.6
- C27.3,14.4,26.7,14.2,26.1,14.2z"/>
-<path class="st1" d="M26.1,22.6c-0.4,0-0.8,0.2-1.1,0.5c-0.3,0.3-0.4,0.7-0.4,1.1c0,0.4,0.1,0.8,0.4,1.1c0.3,0.3,0.7,0.4,1.1,0.4
- s0.8-0.1,1.1-0.4c0.3-0.3,0.4-0.7,0.4-1.1c0-0.4-0.1-0.8-0.4-1.1C26.9,22.8,26.5,22.6,26.1,22.6z"/>
-</svg>
diff --git a/client/overlay.png b/client/overlay.png
deleted file mode 100644
index f5f9fcb..0000000
--- a/client/overlay.png
+++ /dev/null
Binary files differ
diff --git a/client/secure-no.svg b/client/secure-no.svg
deleted file mode 100644
index 035e3f0..0000000
--- a/client/secure-no.svg
+++ /dev/null
@@ -1 +0,0 @@
-<svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 -960 960 960" width="24"><path d="m754-318-60-62q12-32 19-66.5t7-69.5v-189l-240-90-146 55-62-62 208-78 320 120v244q0 51-11.5 101T754-318Zm38 262L662-186q-38 39-84.5 65.5T480-80q-139-35-229.5-159.5T160-516v-172L56-792l56-56 736 736-56 56ZM423-425Zm91-135Zm-34 396q35-11 67-31t59-47L240-608v92q0 121 68 220t172 132Z"/></svg> \ No newline at end of file
diff --git a/client/secure-ok.svg b/client/secure-ok.svg
deleted file mode 100644
index 4abb666..0000000
--- a/client/secure-ok.svg
+++ /dev/null
@@ -1 +0,0 @@
-<svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 -960 960 960" width="24"><path d="m438-338 226-226-57-57-169 169-84-84-57 57 141 141Zm42 258q-139-35-229.5-159.5T160-516v-244l320-120 320 120v244q0 152-90.5 276.5T480-80Zm0-84q104-33 172-132t68-220v-189l-240-90-240 90v189q0 121 68 220t172 132Zm0-316Z"/></svg> \ No newline at end of file
diff --git a/client/secure-sd.svg b/client/secure-sd.svg
deleted file mode 100644
index 3bc315b..0000000
--- a/client/secure-sd.svg
+++ /dev/null
@@ -1 +0,0 @@
-<svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 -960 960 960" width="24"><path d="M501-320q38 0 74.5-16t63.5-48q7-8 3-18t-14-12q-38-6-72-28.5T501-502q-20-35-23.5-75.5T488-656q4-10-2.5-18t-17.5-6q-69 13-109 65t-40 115q0 75 53.5 127.5T501-320ZM480-80q-139-35-229.5-159.5T160-516v-244l320-120 320 120v244q0 152-90.5 276.5T480-80Zm0-84q104-33 172-132t68-220v-189l-240-90-240 90v189q0 121 68 220t172 132Zm0-316Z"/></svg> \ No newline at end of file
diff --git a/client/secure-wh.svg b/client/secure-wh.svg
deleted file mode 100644
index 342ac08..0000000
--- a/client/secure-wh.svg
+++ /dev/null
@@ -1 +0,0 @@
-<svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 -960 960 960" width="24"><path d="M480-80q-139-35-229.5-159.5T160-516v-244l320-120 320 120v244q0 152-90.5 276.5T480-80Zm0-84q104-33 172-132t68-220v-189l-240-90-240 90v189q0 121 68 220t172 132Zm0-316Zm0 200q17 0 29.5-12.5T522-322q0-17-12.5-29.5T480-364q-17 0-29.5 12.5T438-322q0 17 12.5 29.5T480-280Zm-29-128h60v-22q0-11 5-21 6-14 16-23.5t21-19.5q17-17 29.5-38t12.5-46q0-45-34.5-73.5T480-680q-40 0-71.5 23T366-596l54 22q6-20 22.5-34t37.5-14q22 0 38.5 13t16.5 33q0 17-10.5 31.5T501-518q-12 11-24 22.5T458-469q-7 14-7 29.5v31.5Z"/></svg> \ No newline at end of file
diff --git a/vpn/index.js b/vpn/index.js
index 1511130..946b065 100644
--- a/vpn/index.js
+++ b/vpn/index.js
@@ -3,6 +3,7 @@ const axios = require('axios');
const wss = new WebSocketServer({ host: "0.0.0.0", port: 18080 });
global.keys = require('./keys.json');
+global.blocked = require('./blocked.json');
wss.on('connection', (ws) => {
ws.on('error', console.error);
@@ -13,12 +14,33 @@ wss.on('connection', (ws) => {
if (data['key']) {
global.keys = JSON.parse(require('fs').readFileSync("./keys.json").toString());
+ global.blocked = JSON.parse(require('fs').readFileSync("./blocked.json").toString());
ws.key = data['key'];
} else {
console.log(data);
try {
- if (!global.keys.includes(ws.key)) throw new Error("User did not authenticate");
+ if (!global.keys.includes(ws.key)) {
+ ws.send(JSON.stringify({
+ _id: data._id ?? null,
+ error: 20,
+ message: "ENOAUTH"
+ }));
+ return;
+ }
+
+ for (let block of blocked) {
+ if (data['url'].includes(block)) {
+ console.log("Blocked " + data['url'] + "because it contains \"" + block + "\"");
+
+ ws.send(JSON.stringify({
+ _id: data._id ?? null,
+ error: 30,
+ message: "EBLOCKED"
+ }));
+ return;
+ }
+ }
let options = {
url: data['url'],
@@ -47,7 +69,8 @@ wss.on('connection', (ws) => {
ws.send(JSON.stringify({
_id: data._id ?? null,
- error: e.errno
+ error: e.errno,
+ message: e.code ?? "EFAILED",
}));
});
} catch (e) {
@@ -55,7 +78,8 @@ wss.on('connection', (ws) => {
ws.send(JSON.stringify({
_id: data._id ?? null,
- error: 0
+ error: 10,
+ message: "EINTERNAL"
}));
}
}
diff --git a/vpn/keyserver.js b/vpn/keyserver.js
new file mode 100644
index 0000000..f40b412
--- /dev/null
+++ b/vpn/keyserver.js
@@ -0,0 +1,30 @@
+const { WebSocketServer } = require('ws');
+
+const wss = new WebSocketServer({ host: "0.0.0.0", port: 18081 });
+
+if (!require('fs').existsSync("./requests.json")) require('fs').writeFileSync("./requests.json", "{}");
+global.keys = JSON.parse(require('fs').readFileSync("./requests.json").toString());
+
+wss.on('connection', (ws) => {
+ ws.on('error', console.error);
+
+ ws.on('message', (_data) => {
+ try {
+ let data = JSON.parse(_data);
+
+ if (data['key'] && data['name']) {
+ global.keys = JSON.parse(require('fs').readFileSync("./requests.json").toString());
+ keys[data['name']] = data['key'];
+ require('fs').writeFileSync("./requests.json", JSON.stringify(global.keys, null, 2));
+
+ ws.send("Thanks!");
+ ws.close();
+ } else {
+ ws.send("Hmm");
+ ws.close();
+ }
+ } catch (e) {
+ console.error(e);
+ }
+ });
+}); \ No newline at end of file