Let's get this thing working
This commit is contained in:
42
.gitignore
vendored
Normal file
42
.gitignore
vendored
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
# See https://docs.github.com/get-started/getting-started-with-git/ignoring-files for more about ignoring files.
|
||||||
|
|
||||||
|
# Compiled output
|
||||||
|
/dist
|
||||||
|
/tmp
|
||||||
|
/out-tsc
|
||||||
|
/bazel-out
|
||||||
|
|
||||||
|
# Node
|
||||||
|
/node_modules
|
||||||
|
npm-debug.log
|
||||||
|
yarn-error.log
|
||||||
|
|
||||||
|
# IDEs and editors
|
||||||
|
.idea/
|
||||||
|
.project
|
||||||
|
.classpath
|
||||||
|
.c9/
|
||||||
|
*.launch
|
||||||
|
.settings/
|
||||||
|
*.sublime-workspace
|
||||||
|
|
||||||
|
# Visual Studio Code
|
||||||
|
.vscode/*
|
||||||
|
!.vscode/settings.json
|
||||||
|
!.vscode/tasks.json
|
||||||
|
!.vscode/launch.json
|
||||||
|
!.vscode/extensions.json
|
||||||
|
.history/*
|
||||||
|
|
||||||
|
# Miscellaneous
|
||||||
|
/.angular/cache
|
||||||
|
.sass-cache/
|
||||||
|
/connect.lock
|
||||||
|
/coverage
|
||||||
|
/libpeerconnection.log
|
||||||
|
testem.log
|
||||||
|
/typings
|
||||||
|
|
||||||
|
# System files
|
||||||
|
.DS_Store
|
||||||
|
Thumbs.db
|
||||||
8
Dockerfile
Normal file
8
Dockerfile
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
FROM node:slim
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
COPY package*.json .
|
||||||
|
RUN npm ci
|
||||||
|
COPY . .
|
||||||
|
|
||||||
|
CMD ["node", "server.js"]
|
||||||
11
config.json
Normal file
11
config.json
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
{
|
||||||
|
"web": {
|
||||||
|
"ip": "0.0.0.0",
|
||||||
|
"port": 80
|
||||||
|
},
|
||||||
|
"ssh": {
|
||||||
|
"host": "host.docker.internal",
|
||||||
|
"port": 22,
|
||||||
|
"username": "gibby"
|
||||||
|
}
|
||||||
|
}
|
||||||
69
index.html
Normal file
69
index.html
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>SSH Terminal</title>
|
||||||
|
<link rel="stylesheet" href="/xterm.css" />
|
||||||
|
<script src="/xterm.js"></script>
|
||||||
|
<script src="/xterm-addon-fit.js"></script>
|
||||||
|
<script src="/socket.io/socket.io.js"></script>
|
||||||
|
<script>
|
||||||
|
window.addEventListener(
|
||||||
|
"load",
|
||||||
|
function () {
|
||||||
|
var terminalContainer = document.getElementById("terminal-container");
|
||||||
|
const term = new Terminal({ cursorBlink: true });
|
||||||
|
const fitAddon = new FitAddon.FitAddon();
|
||||||
|
term.loadAddon(fitAddon);
|
||||||
|
term.open(terminalContainer);
|
||||||
|
fitAddon.fit();
|
||||||
|
|
||||||
|
var socket = io(); //.connect();
|
||||||
|
socket.on("connect", function () {
|
||||||
|
term.write("\r\n*** Connected to backend ***\r\n");
|
||||||
|
});
|
||||||
|
|
||||||
|
// Browser -> Backend
|
||||||
|
term.onKey(function (ev) {
|
||||||
|
socket.emit("data", ev.key);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Backend -> Browser
|
||||||
|
socket.on("data", function (data) {
|
||||||
|
term.write(data);
|
||||||
|
});
|
||||||
|
|
||||||
|
socket.on("disconnect", function () {
|
||||||
|
term.write("\r\n*** Disconnected from backend ***\r\n");
|
||||||
|
});
|
||||||
|
},
|
||||||
|
false
|
||||||
|
);
|
||||||
|
</script>
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
font-family: helvetica, sans-serif, arial;
|
||||||
|
font-size: 1em;
|
||||||
|
color: #111;
|
||||||
|
}
|
||||||
|
h1 {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
#terminal-container {
|
||||||
|
width: 960px;
|
||||||
|
height: 600px;
|
||||||
|
margin: 0 auto;
|
||||||
|
padding: 2px;
|
||||||
|
}
|
||||||
|
#terminal-container .terminal {
|
||||||
|
background-color: #111;
|
||||||
|
color: #fafafa;
|
||||||
|
padding: 2px;
|
||||||
|
}
|
||||||
|
#terminal-container .terminal:focus .terminal-cursor {
|
||||||
|
background-color: #fafafa;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="terminal-container"></div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
1170
package-lock.json
generated
Normal file
1170
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
18
package.json
Normal file
18
package.json
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
{
|
||||||
|
"name": "webterm",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "",
|
||||||
|
"main": "server.js",
|
||||||
|
"scripts": {
|
||||||
|
"test": "echo \"Error: no test specified\" && exit 1"
|
||||||
|
},
|
||||||
|
"author": "",
|
||||||
|
"license": "ISC",
|
||||||
|
"dependencies": {
|
||||||
|
"@xterm/addon-fit": "^0.10.0",
|
||||||
|
"@xterm/xterm": "^5.5.0",
|
||||||
|
"express": "^4.21.2",
|
||||||
|
"socket.io": "^4.8.1",
|
||||||
|
"ssh2": "^1.16.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
100
server.js
Normal file
100
server.js
Normal file
@@ -0,0 +1,100 @@
|
|||||||
|
var fs = require("fs");
|
||||||
|
var path = require("path");
|
||||||
|
var server = require("http").createServer(onRequest);
|
||||||
|
|
||||||
|
var io = require("socket.io")(server);
|
||||||
|
var SSHClient = require("ssh2").Client;
|
||||||
|
|
||||||
|
var config = {};
|
||||||
|
try {
|
||||||
|
// try and load the config file
|
||||||
|
const data = fs.readFileSync("/data/config.json", "utf-8");
|
||||||
|
config = JSON.parse(data);
|
||||||
|
console.log("Loaded config.json");
|
||||||
|
} catch (ex) {
|
||||||
|
console.log("Unable to load config.json, using defaults");
|
||||||
|
console.error(ex);
|
||||||
|
}
|
||||||
|
|
||||||
|
var sshConfig = {
|
||||||
|
host: config.ssh?.host ?? "host.docker.internal",
|
||||||
|
port: config.ssh?.port ?? 22,
|
||||||
|
username: config.ssh?.username,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (config.ssh?.password) {
|
||||||
|
sshConfig.password = config.ssh.password;
|
||||||
|
} else if (config.ssh?.privateKey) {
|
||||||
|
sshConfig.privateKey = fs.readFileSync(
|
||||||
|
path.join("/data", config.ssh.privateKey)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load static files into memory
|
||||||
|
var staticFiles = {};
|
||||||
|
var basePath = path.join(require.resolve("@xterm/xterm"), "..");
|
||||||
|
staticFiles["/xterm.css"] = fs.readFileSync(
|
||||||
|
path.join(basePath, "../css/xterm.css")
|
||||||
|
);
|
||||||
|
staticFiles["/xterm.js"] = fs.readFileSync(path.join(basePath, "xterm.js"));
|
||||||
|
basePath = path.join(require.resolve("@xterm/addon-fit"), "..");
|
||||||
|
staticFiles["/xterm-addon-fit.js"] = fs.readFileSync(
|
||||||
|
path.join(basePath, "addon-fit.js")
|
||||||
|
);
|
||||||
|
staticFiles["/"] = fs.readFileSync("index.html");
|
||||||
|
|
||||||
|
// Handle static file serving
|
||||||
|
function onRequest(req, res) {
|
||||||
|
var file;
|
||||||
|
if (req.method === "GET" && (file = staticFiles[req.url])) {
|
||||||
|
res.writeHead(200, {
|
||||||
|
"Content-Type":
|
||||||
|
"text/" +
|
||||||
|
(/css$/.test(req.url)
|
||||||
|
? "css"
|
||||||
|
: /js$/.test(req.url)
|
||||||
|
? "javascript"
|
||||||
|
: "html"),
|
||||||
|
});
|
||||||
|
return res.end(file);
|
||||||
|
}
|
||||||
|
res.writeHead(404);
|
||||||
|
res.end();
|
||||||
|
}
|
||||||
|
|
||||||
|
io.on("connection", function (socket) {
|
||||||
|
var conn = new SSHClient();
|
||||||
|
conn
|
||||||
|
.on("ready", function () {
|
||||||
|
socket.emit("data", "\r\nConnecting...\r\n");
|
||||||
|
conn.shell(function (err, stream) {
|
||||||
|
if (err)
|
||||||
|
return socket.emit(
|
||||||
|
"data",
|
||||||
|
`\r\nConnection Error: ${err.message}\r\n`
|
||||||
|
);
|
||||||
|
socket.on("data", function (data) {
|
||||||
|
stream.write(data);
|
||||||
|
});
|
||||||
|
stream
|
||||||
|
.on("data", function (d) {
|
||||||
|
socket.emit("data", d.toString("binary"));
|
||||||
|
})
|
||||||
|
.on("close", function () {
|
||||||
|
conn.end();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.on("close", function () {
|
||||||
|
socket.emit("data", "\r\nConnection Closed\r\n");
|
||||||
|
})
|
||||||
|
.on("error", function (err) {
|
||||||
|
socket.emit("data", `\r\nConnection Error: ${err.message}\r\n`);
|
||||||
|
})
|
||||||
|
.connect(sshConfig);
|
||||||
|
});
|
||||||
|
|
||||||
|
let port = config.web?.port ?? 80;
|
||||||
|
let ip = config.web?.ip ?? "0.0.0.0";
|
||||||
|
console.log(`Listening on ${ip}:${port}`);
|
||||||
|
server.listen(port, ip);
|
||||||
Reference in New Issue
Block a user