mirror of
https://github.com/ION606/web-to-fish.git
synced 2026-05-14 18:36:53 +00:00
I gave up
This commit is contained in:
-150
@@ -1,150 +0,0 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>TTY Login</title>
|
||||
<style>
|
||||
body {
|
||||
margin: 0;
|
||||
height: 100vh;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background: #000;
|
||||
/* Black background for terminal feel */
|
||||
color: #00ff00;
|
||||
/* Green text for TTY style */
|
||||
font-family: monospace;
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
.tty-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: 100%;
|
||||
max-width: 600px;
|
||||
padding: 1rem;
|
||||
}
|
||||
|
||||
form {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
|
||||
input {
|
||||
background: transparent;
|
||||
color: #00ff00;
|
||||
border: none;
|
||||
border-bottom: 1px solid #00ff00;
|
||||
font-family: monospace;
|
||||
font-size: 1rem;
|
||||
padding: 0.25rem;
|
||||
outline: none;
|
||||
caret-color: #00ff00;
|
||||
}
|
||||
|
||||
input::placeholder {
|
||||
color: #008000;
|
||||
/* Dim green for placeholder text */
|
||||
}
|
||||
|
||||
input:focus {
|
||||
border-bottom-color: #00ff00;
|
||||
}
|
||||
|
||||
button {
|
||||
display: none;
|
||||
/* TTY doesn't have a visible button */
|
||||
}
|
||||
|
||||
.tty-header {
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.tty-header h1 {
|
||||
margin: 0;
|
||||
font-size: 1.5rem;
|
||||
color: #00ff00;
|
||||
}
|
||||
|
||||
.tty-message {
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.tty-footer {
|
||||
margin-top: 1rem;
|
||||
font-size: 0.85rem;
|
||||
color: #008000;
|
||||
/* Dim green for footer */
|
||||
}
|
||||
|
||||
.error-message {
|
||||
color: red;
|
||||
font-size: 0.9rem;
|
||||
margin-top: 0.5rem;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class="tty-container">
|
||||
<div class="tty-header">
|
||||
<h1>TTY Login</h1>
|
||||
</div>
|
||||
<form id="loginForm">
|
||||
<div class="tty-message">login:</div>
|
||||
<input name="username" type="text" placeholder="Enter username" required autocomplete="off" />
|
||||
<div class="tty-message">password:</div>
|
||||
<input name="password" type="password" placeholder="Enter password" required />
|
||||
<button type="submit">Login</button>
|
||||
<div class="error-message" id="errorMessage"></div>
|
||||
</form>
|
||||
<div class="tty-footer">
|
||||
Type your credentials and press <kbd>Enter</kbd>.
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
const form = document.querySelector('#loginForm');
|
||||
const errorMessage = document.querySelector('#errorMessage');
|
||||
|
||||
form.addEventListener('submit', async (event) => {
|
||||
event.preventDefault(); // Prevent form from submitting the traditional way
|
||||
errorMessage.textContent = ''; // Clear previous error message
|
||||
|
||||
const formData = new FormData(form);
|
||||
const payload = {
|
||||
username: formData.get('username'),
|
||||
password: formData.get('password')
|
||||
};
|
||||
|
||||
try {
|
||||
const response = await fetch('login', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify(payload)
|
||||
});
|
||||
|
||||
if (response.status === 404) {
|
||||
errorMessage.textContent = 'User not found.';
|
||||
} else if (response.status === 401) {
|
||||
errorMessage.textContent = 'Incorrect password.';
|
||||
} else if (response.status === 500) {
|
||||
errorMessage.textContent = 'Error logging in. Please try again later.';
|
||||
} else if (response.ok) {
|
||||
window.location.href = '/shell';
|
||||
} else {
|
||||
errorMessage.textContent = 'Unexpected error occurred.';
|
||||
}
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
errorMessage.textContent = 'Unable to connect to the server. Please try again later.';
|
||||
}
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@@ -1,7 +1,6 @@
|
||||
import express from 'express';
|
||||
import path from 'path';
|
||||
import { fileURLToPath } from 'url';
|
||||
import session from 'express-session';
|
||||
import expressWs from 'express-ws';
|
||||
import { spawn } from 'node-pty';
|
||||
import json from './secrets/config.json' with { type: 'json' };
|
||||
@@ -13,76 +12,18 @@ const __dirname = path.dirname(fileURLToPath(import.meta.url)),
|
||||
expressWs(app); // enable websockets for the app
|
||||
|
||||
|
||||
// configure session
|
||||
app.use(session({
|
||||
secret: json.secretkey,
|
||||
resave: false,
|
||||
saveUninitialized: false
|
||||
}));
|
||||
|
||||
|
||||
// parse form data
|
||||
app.use(express.urlencoded({ extended: true }));
|
||||
app.use(express.json({ extended: true }));
|
||||
app.use('/node_modules', express.static('node_modules'));
|
||||
|
||||
|
||||
// authentication middleware
|
||||
function requireAuth(req, res, next) {
|
||||
if (req.session && req.session.authenticated) {
|
||||
return next();
|
||||
} else {
|
||||
res.redirect('/login');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// serve login page
|
||||
app.get('/login', (req, res) => {
|
||||
res.sendFile('login.html', { root: path.join(__dirname, 'HTML') });
|
||||
});
|
||||
|
||||
|
||||
app.post('/login', async (req, res) => {
|
||||
try {
|
||||
const username = req.body.username;
|
||||
const password = req.body.password;
|
||||
|
||||
// validate input
|
||||
if (!username) return res.status(400).send('Username is required');
|
||||
if (!password) return res.status(400).send('Password is required');
|
||||
|
||||
const { uname, upass } = json;
|
||||
|
||||
if (username !== uname) return res.sendStatus(404);
|
||||
else if (password !== upass) return res.sendStatus(401);
|
||||
|
||||
req.session.authenticated = true;
|
||||
req.session.username = username;
|
||||
|
||||
return res.redirect('/shell');
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
res.status(500).send('Internal server error');
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
|
||||
// shell interface
|
||||
app.get('/shell', requireAuth, (req, res) => {
|
||||
app.get('/shell', (req, res) => {
|
||||
res.sendFile('shell.html', { root: path.join(__dirname, 'HTML') });
|
||||
});
|
||||
|
||||
|
||||
// logout route
|
||||
app.get('/logout', (req, res) => {
|
||||
req.session.destroy(() => {
|
||||
res.redirect('/login');
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
// when a websocket is opened at /shell-ws, spawn a fish shell in a pty
|
||||
app.ws('/shell-ws', (ws, req) => {
|
||||
// spawn a fish shell using node-pty with a pseudo-terminal
|
||||
|
||||
Generated
+1
-120
@@ -11,13 +11,9 @@
|
||||
"dependencies": {
|
||||
"@xterm/addon-fit": "^0.10.0",
|
||||
"@xterm/xterm": "^5.5.0",
|
||||
"authenticate-pam": "^1.0.5",
|
||||
"express": "^4.21.2",
|
||||
"express-session": "^1.18.1",
|
||||
"express-ws": "^5.0.2",
|
||||
"node-pty": "^1.0.0",
|
||||
"passport": "^0.7.0",
|
||||
"passport-local": "^1.0.0"
|
||||
"node-pty": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@xterm/addon-fit": {
|
||||
@@ -54,15 +50,6 @@
|
||||
"integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/authenticate-pam": {
|
||||
"version": "1.0.5",
|
||||
"resolved": "https://registry.npmjs.org/authenticate-pam/-/authenticate-pam-1.0.5.tgz",
|
||||
"integrity": "sha512-zaPml3/19Sa3XLewuOoUNsxwnNz13mTNoO4Q09vr93cjTrH0dwXOU49Bcetk/XWl22bw9zO9WovSKkddGvBEsQ==",
|
||||
"hasInstallScript": true,
|
||||
"dependencies": {
|
||||
"nan": "^2.3.3"
|
||||
}
|
||||
},
|
||||
"node_modules/body-parser": {
|
||||
"version": "1.20.3",
|
||||
"resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.3.tgz",
|
||||
@@ -344,40 +331,6 @@
|
||||
"url": "https://opencollective.com/express"
|
||||
}
|
||||
},
|
||||
"node_modules/express-session": {
|
||||
"version": "1.18.1",
|
||||
"resolved": "https://registry.npmjs.org/express-session/-/express-session-1.18.1.tgz",
|
||||
"integrity": "sha512-a5mtTqEaZvBCL9A9aqkrtfz+3SMDhOVUnjafjo+s7A9Txkq+SVX2DLvSp1Zrv4uCXa3lMSK3viWnh9Gg07PBUA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"cookie": "0.7.2",
|
||||
"cookie-signature": "1.0.7",
|
||||
"debug": "2.6.9",
|
||||
"depd": "~2.0.0",
|
||||
"on-headers": "~1.0.2",
|
||||
"parseurl": "~1.3.3",
|
||||
"safe-buffer": "5.2.1",
|
||||
"uid-safe": "~2.1.5"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.8.0"
|
||||
}
|
||||
},
|
||||
"node_modules/express-session/node_modules/cookie": {
|
||||
"version": "0.7.2",
|
||||
"resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz",
|
||||
"integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/express-session/node_modules/cookie-signature": {
|
||||
"version": "1.0.7",
|
||||
"resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.7.tgz",
|
||||
"integrity": "sha512-NXdYc3dLr47pBkpUCHtKSwIOQXLVn8dZEuywboCOJY/osA0wFSLlSawr3KN8qXJEyX66FcONTH8EIlVuK0yyFA==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/express-ws": {
|
||||
"version": "5.0.2",
|
||||
"resolved": "https://registry.npmjs.org/express-ws/-/express-ws-5.0.2.tgz",
|
||||
@@ -677,15 +630,6 @@
|
||||
"node": ">= 0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/on-headers": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz",
|
||||
"integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/parseurl": {
|
||||
"version": "1.3.3",
|
||||
"resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz",
|
||||
@@ -695,54 +639,12 @@
|
||||
"node": ">= 0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/passport": {
|
||||
"version": "0.7.0",
|
||||
"resolved": "https://registry.npmjs.org/passport/-/passport-0.7.0.tgz",
|
||||
"integrity": "sha512-cPLl+qZpSc+ireUvt+IzqbED1cHHkDoVYMo30jbJIdOOjQ1MQYZBPiNvmi8UM6lJuOpTPXJGZQk0DtC4y61MYQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"passport-strategy": "1.x.x",
|
||||
"pause": "0.0.1",
|
||||
"utils-merge": "^1.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/jaredhanson"
|
||||
}
|
||||
},
|
||||
"node_modules/passport-local": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/passport-local/-/passport-local-1.0.0.tgz",
|
||||
"integrity": "sha512-9wCE6qKznvf9mQYYbgJ3sVOHmCWoUNMVFoZzNoznmISbhnNNPhN9xfY3sLmScHMetEJeoY7CXwfhCe7argfQow==",
|
||||
"dependencies": {
|
||||
"passport-strategy": "1.x.x"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/passport-strategy": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/passport-strategy/-/passport-strategy-1.0.0.tgz",
|
||||
"integrity": "sha512-CB97UUvDKJde2V0KDWWB3lyf6PC3FaZP7YxZ2G8OAtn9p4HI9j9JLP9qjOGZFvyl8uwNT8qM+hGnz/n16NI7oA==",
|
||||
"engines": {
|
||||
"node": ">= 0.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/path-to-regexp": {
|
||||
"version": "0.1.12",
|
||||
"resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.12.tgz",
|
||||
"integrity": "sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/pause": {
|
||||
"version": "0.0.1",
|
||||
"resolved": "https://registry.npmjs.org/pause/-/pause-0.0.1.tgz",
|
||||
"integrity": "sha512-KG8UEiEVkR3wGEb4m5yZkVCzigAD+cVEJck2CzYZO37ZGJfctvVptVO192MwrtPhzONn6go8ylnOdMhKqi4nfg=="
|
||||
},
|
||||
"node_modules/proxy-addr": {
|
||||
"version": "2.0.7",
|
||||
"resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz",
|
||||
@@ -771,15 +673,6 @@
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/random-bytes": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/random-bytes/-/random-bytes-1.0.0.tgz",
|
||||
"integrity": "sha512-iv7LhNVO047HzYR3InF6pUcUsPQiHTM1Qal51DcGSuZFBil1aBBWG5eHPNek7bvILMaYJ/8RU1e8w1AMdHmLQQ==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/range-parser": {
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz",
|
||||
@@ -1010,18 +903,6 @@
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/uid-safe": {
|
||||
"version": "2.1.5",
|
||||
"resolved": "https://registry.npmjs.org/uid-safe/-/uid-safe-2.1.5.tgz",
|
||||
"integrity": "sha512-KPHm4VL5dDXKz01UuEd88Df+KzynaohSL9fBh096KWAxSKZQDI2uBrVqtvRM4rwrIrRRKsdLNML/lnaaVSRioA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"random-bytes": "~1.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/unpipe": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
|
||||
|
||||
+1
-5
@@ -11,13 +11,9 @@
|
||||
"dependencies": {
|
||||
"@xterm/addon-fit": "^0.10.0",
|
||||
"@xterm/xterm": "^5.5.0",
|
||||
"authenticate-pam": "^1.0.5",
|
||||
"express": "^4.21.2",
|
||||
"express-session": "^1.18.1",
|
||||
"express-ws": "^5.0.2",
|
||||
"node-pty": "^1.0.0",
|
||||
"passport": "^0.7.0",
|
||||
"passport-local": "^1.0.0"
|
||||
"node-pty": "^1.0.0"
|
||||
},
|
||||
"type": "module"
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user