cp dines
This commit is contained in:
parent
4c60362e85
commit
576af8aad0
6 changed files with 34 additions and 204 deletions
File diff suppressed because one or more lines are too long
|
@ -35,6 +35,11 @@ const downloadLogBtn = document.getElementById('downloadLogBtn');
|
|||
const status = document.getElementById('status');
|
||||
const fitAddon = new FitAddon();
|
||||
const terminalContainer = document.getElementById('terminal-container');
|
||||
term.options = {
|
||||
cursorBlink: true,
|
||||
scrollback: 10000,
|
||||
tabStopWidth: 8,
|
||||
};
|
||||
term.loadAddon(fitAddon);
|
||||
term.open(terminalContainer);
|
||||
term.focus();
|
||||
|
@ -45,15 +50,6 @@ const socket = io({
|
|||
transports: ['websocket'],
|
||||
});
|
||||
|
||||
// reauthenticate
|
||||
function reauthSession() {
|
||||
// eslint-disable-line
|
||||
debug('re-authenticating');
|
||||
socket.emit('control', 'reauth');
|
||||
window.location.href = '/ssh/reauth';
|
||||
return false;
|
||||
}
|
||||
|
||||
// cross browser method to "download" an element to the local system
|
||||
// used for our client-side logging feature
|
||||
function downloadLog() {
|
||||
|
@ -115,15 +111,6 @@ function toggleLog() {
|
|||
return false;
|
||||
}
|
||||
|
||||
// replay password to server, requires
|
||||
function replayCredentials() {
|
||||
// eslint-disable-line
|
||||
socket.emit('control', 'replayCredentials');
|
||||
debug(`control: replayCredentials`);
|
||||
term.focus();
|
||||
return false;
|
||||
}
|
||||
|
||||
function resizeScreen() {
|
||||
fitAddon.fit();
|
||||
socket.emit('resize', { cols: term.cols, rows: term.rows });
|
||||
|
@ -148,22 +135,6 @@ socket.on('connect', () => {
|
|||
debug(`geometry: ${term.cols}, ${term.rows}`);
|
||||
});
|
||||
|
||||
socket.on(
|
||||
'setTerminalOpts',
|
||||
(data: {
|
||||
cursorBlink: boolean;
|
||||
scrollback: number;
|
||||
tabStopWidth: number;
|
||||
bellStyle: 'none' | 'sound';
|
||||
fontSize: number;
|
||||
fontFamily: string;
|
||||
letterSpacing: number;
|
||||
lineHeight: number;
|
||||
}) => {
|
||||
term.options = data;
|
||||
},
|
||||
);
|
||||
|
||||
// socket.on('ssherror', (data: string) => {
|
||||
// status.innerHTML = data;
|
||||
// status.style.backgroundColor = 'red';
|
||||
|
@ -174,47 +145,6 @@ socket.on(
|
|||
// header.style.backgroundColor = data;
|
||||
// });
|
||||
|
||||
// socket.on('header', (data: string) => {
|
||||
// if (data) {
|
||||
// header.innerHTML = data;
|
||||
// header.style.display = 'block';
|
||||
// // header is 19px and footer is 19px, recaculate new terminal-container and resize
|
||||
// terminalContainer.style.height = 'calc(100% - 38px)';
|
||||
// resizeScreen();
|
||||
// }
|
||||
// });
|
||||
|
||||
// socket.on('footer', (data: string) => {
|
||||
// sessionFooter = data;
|
||||
// footer.innerHTML = data;
|
||||
// });
|
||||
|
||||
// socket.on('statusBackground', (data: string) => {
|
||||
// status.style.backgroundColor = data;
|
||||
// });
|
||||
|
||||
// socket.on('allowreplay', (data: boolean) => {
|
||||
// if (data === true) {
|
||||
// debug(`allowreplay: ${data}`);
|
||||
// allowreplay = true;
|
||||
// drawMenu();
|
||||
// } else {
|
||||
// allowreplay = false;
|
||||
// debug(`allowreplay: ${data}`);
|
||||
// }
|
||||
// });
|
||||
|
||||
// socket.on('allowreauth', (data: boolean) => {
|
||||
// if (data === true) {
|
||||
// debug(`allowreauth: ${data}`);
|
||||
// allowreauth = true;
|
||||
// drawMenu();
|
||||
// } else {
|
||||
// allowreauth = false;
|
||||
// debug(`allowreauth: ${data}`);
|
||||
// }
|
||||
// });
|
||||
|
||||
socket.on('disconnect', (err: any) => {
|
||||
if (!errorExists) {
|
||||
status.style.backgroundColor = 'red';
|
||||
|
|
|
@ -39,37 +39,26 @@ const io = require('socket.io')(server, { transports: ['websocket'], ...config.s
|
|||
const appSocket = require('./socket');
|
||||
const { connect } = require('./routes');
|
||||
|
||||
// eslint-disable-next-line consistent-return
|
||||
function safeShutdownGuard(req, res, next) {
|
||||
if (!shutdownMode) return next();
|
||||
res.status(503).end('Service unavailable: Server shutting down');
|
||||
}
|
||||
// express
|
||||
app.use(safeShutdownGuard);
|
||||
|
||||
app.disable('x-powered-by');
|
||||
app.use(express.urlencoded({ extended: true }));
|
||||
app.post('/ssh/host/:host?', connect);
|
||||
// To remove
|
||||
// Static files..
|
||||
app.post('/ssh', express.static(publicPath, expressConfig.ssh));
|
||||
app.use('/ssh', express.static(publicPath, expressConfig.ssh));
|
||||
//app.use(basicAuth);
|
||||
//app.get('/ssh/reauth', reauth);
|
||||
///
|
||||
app.get('/ssh/host/:host?', connect);
|
||||
// app.use(notfound);
|
||||
// app.use(handleErrors);
|
||||
|
||||
// clean stop
|
||||
function stopApp(reason) {
|
||||
shutdownMode = false;
|
||||
if (reason) console.info(`Stopping: ${reason}`);
|
||||
clearInterval(shutdownInterval);
|
||||
io.close();
|
||||
server.close();
|
||||
}
|
||||
|
||||
// bring up socket
|
||||
io.on('connection', appSocket);
|
||||
|
||||
// // clean stop
|
||||
// function stopApp(reason) {
|
||||
// shutdownMode = false;
|
||||
// if (reason) console.info(`Stopping: ${reason}`);
|
||||
// clearInterval(shutdownInterval);
|
||||
// io.close();
|
||||
// server.close();
|
||||
// }
|
||||
module.exports = { server, config };
|
||||
|
||||
// const onConnection = (socket) => {
|
||||
|
|
|
@ -1,28 +1,10 @@
|
|||
/* eslint-disable no-console */
|
||||
// ssh.js
|
||||
const validator = require('validator');
|
||||
const path = require('path');
|
||||
|
||||
const nodeRoot = path.dirname(require.main.filename);
|
||||
|
||||
const publicPath = path.join(nodeRoot, 'client', 'public');
|
||||
const { parseBool } = require('./util');
|
||||
const config = require('./config');
|
||||
|
||||
// exports.reauth = function reauth(req, res) {
|
||||
// let { referer } = req.headers;
|
||||
// if (!validator.isURL(referer, { host_whitelist: ['localhost'] })) {
|
||||
// console.error(
|
||||
// `WebSSH2 (${req.sessionID}) ERROR: Referrer '${referer}' for '/reauth' invalid. Setting to '/' which will probably fail.`,
|
||||
// );
|
||||
// referer = '/';
|
||||
// }
|
||||
// res
|
||||
// .status(401)
|
||||
// .send(
|
||||
// `<!DOCTYPE html><html><head><meta http-equiv="refresh" content="0; url=${referer}"></head><body bgcolor="#000"></body></html>`,
|
||||
// );
|
||||
// };
|
||||
|
||||
exports.connect = function connect(req, res) {
|
||||
res.sendFile(path.join(path.join(publicPath, 'client.htm')));
|
||||
|
|
|
@ -1,27 +1,13 @@
|
|||
// private
|
||||
const debugWebSSH2 = require('debug')('WebSSH2');
|
||||
const SSH = require('ssh2').Client;
|
||||
const CIDRMatcher = require('cidr-matcher');
|
||||
const validator = require('validator');
|
||||
const dnsPromises = require('dns').promises;
|
||||
const debug = require('debug');
|
||||
const { Client } = require('ssh2');
|
||||
const tls = require('tls');
|
||||
const forge = require('node-forge');
|
||||
|
||||
const { Runloop } = require('@runloop/api-client');
|
||||
|
||||
function convertPKCS8toPKCS1(pkcs8Key) {
|
||||
const privateKeyInfo = forge.pki.privateKeyFromPem(pkcs8Key);
|
||||
|
||||
// Convert the private key to PKCS#1 format
|
||||
const pkcs1Pem = forge.pki.privateKeyToPem(privateKeyInfo);
|
||||
return pkcs1Pem;
|
||||
}
|
||||
|
||||
const conn = new Client();
|
||||
|
||||
// Function to create a TLS connection (simulating ProxyCommand with openssl s_client)
|
||||
const proxyConnect = (hostname, callback) => {
|
||||
function tlsProxyConnect(hostname, callback) {
|
||||
const tlsSocket = tls.connect(
|
||||
{
|
||||
host: 'ssh.runloop.pro', // Proxy server address
|
||||
|
@ -39,10 +25,10 @@ const proxyConnect = (hostname, callback) => {
|
|||
console.error('TLS connection error:', err);
|
||||
callback(err);
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
// Main function to establish the SSH connection over the TLS proxy
|
||||
async function establishConnection(targetDevbox, bearerToken) {
|
||||
async function establishConnection(conn, targetDevbox, bearerToken) {
|
||||
const runloop = new Runloop({
|
||||
baseURL: 'https://api.runloop.pro',
|
||||
// This is gotten by just inspecting the browser cookies on platform.runloop.pro
|
||||
|
@ -56,7 +42,7 @@ async function establishConnection(targetDevbox, bearerToken) {
|
|||
// SS KEY
|
||||
// Environment
|
||||
// Get ssh config information
|
||||
proxyConnect(hostname, (err, tlsSocket) => {
|
||||
tlsProxyConnect(hostname, (err, tlsSocket) => {
|
||||
if (err) {
|
||||
console.error('Error during proxy connection:', err);
|
||||
return;
|
||||
|
@ -66,22 +52,6 @@ async function establishConnection(targetDevbox, bearerToken) {
|
|||
conn
|
||||
.on('ready', () => {
|
||||
console.log('SSH Client ready');
|
||||
// conn.exec("uptime", (err, stream) => {
|
||||
// if (err) throw err;
|
||||
// stream
|
||||
// .on("close", (code, signal) => {
|
||||
// console.log(
|
||||
// "Stream :: close :: code: " + code + ", signal: " + signal
|
||||
// );
|
||||
// conn.end();
|
||||
// })
|
||||
// .on("data", (data) => {
|
||||
// console.log("STDOUT: " + data);
|
||||
// })
|
||||
// .stderr.on("data", (data) => {
|
||||
// console.log("STDERR: " + data);
|
||||
// });
|
||||
// });
|
||||
})
|
||||
.on('error', (error) => {
|
||||
console.error('SSH Connection error:', error);
|
||||
|
@ -101,11 +71,14 @@ async function establishConnection(targetDevbox, bearerToken) {
|
|||
});
|
||||
});
|
||||
}
|
||||
|
||||
//TODO deal with
|
||||
let termCols;
|
||||
let termRows;
|
||||
|
||||
// public
|
||||
module.exports = function appSocket(socket) {
|
||||
const conn = new Client();
|
||||
async function setupConnection() {
|
||||
// TODO AUTH?
|
||||
// if websocket connection arrives without an express session, kill it
|
||||
|
@ -116,7 +89,6 @@ module.exports = function appSocket(socket) {
|
|||
// return;
|
||||
// }
|
||||
|
||||
// const conn = new SSH();
|
||||
socket.on('geometry', (cols, rows) => {
|
||||
termCols = cols;
|
||||
termRows = rows;
|
||||
|
@ -130,12 +102,6 @@ module.exports = function appSocket(socket) {
|
|||
// debugWebSSH2(
|
||||
// `WebSSH2 Login: user=${socket.request.session.username} from=${socket.handshake.address} host=${socket.request.session.ssh.host} port=${socket.request.session.ssh.port} sessionID=${socket.request.sessionID}/${socket.id} mrhsession=${socket.request.session.ssh.mrhsession} allowreplay=${socket.request.session.ssh.allowreplay} term=${socket.request.session.ssh.term}`,
|
||||
// );
|
||||
socket.emit('setTerminalOpts', {
|
||||
cursorBlink: true,
|
||||
scrollback: 10000,
|
||||
tabStopWidth: 8,
|
||||
bellStyle: 'sound',
|
||||
});
|
||||
conn.shell(
|
||||
{
|
||||
term: 'xterm-color',
|
||||
|
@ -233,9 +199,18 @@ module.exports = function appSocket(socket) {
|
|||
// debug: debug('ssh2'),
|
||||
// });
|
||||
await establishConnection(
|
||||
conn,
|
||||
'dbx_2xb6oS1G1e6TAihVMtjn6',
|
||||
'ss_eyJhbGciOiJIUzI1NiIsImtpZCI6IkEyZExNNUlheFE4L29acW4iLCJ0eXAiOiJKV1QifQ.eyJpc3MiOiJodHRwczovL2t5aGpvaG1xbXFrdmZxc2t4dnNkLnN1cGFiYXNlLmNvL2F1dGgvdjEiLCJzdWIiOiI5NmRlMTVjZC1lZWJmLTRjNzctODQwNy1jZTkwNzNlZTZkMjIiLCJhdWQiOiJhdXRoZW50aWNhdGVkIiwiZXhwIjoxNzI1NDg1NTQwLCJpYXQiOjE3MjU0ODE5NDAsImVtYWlsIjoiYWxleEBydW5sb29wLmFpIiwicGhvbmUiOiIiLCJhcHBfbWV0YWRhdGEiOnsicHJvdmlkZXIiOiJlbWFpbCIsInByb3ZpZGVycyI6WyJlbWFpbCIsImdpdGh1YiJdfSwidXNlcl9tZXRhZGF0YSI6eyJhdmF0YXJfdXJsIjoiaHR0cHM6Ly9hdmF0YXJzLmdpdGh1YnVzZXJjb250ZW50LmNvbS91LzE2MDA3NzkyND92PTQiLCJlbWFpbCI6ImFsZXhAcnVubG9vcC5haSIsImVtYWlsX3ZlcmlmaWVkIjp0cnVlLCJmdWxsX25hbWUiOiJBbGV4YW5kZXIgRGluZXMiLCJpc3MiOiJodHRwczovL2FwaS5naXRodWIuY29tIiwibmFtZSI6IkFsZXhhbmRlciBEaW5lcyIsInBob25lX3ZlcmlmaWVkIjpmYWxzZSwicHJlZmVycmVkX3VzZXJuYW1lIjoiZGluZXMtcmwiLCJwcm92aWRlcl9pZCI6IjE2MDA3NzkyNCIsInN1YiI6IjE2MDA3NzkyNCIsInVzZXJfbmFtZSI6ImRpbmVzLXJsIn0sInJvbGUiOiJhdXRoZW50aWNhdGVkIiwiYWFsIjoiYWFsMSIsImFtciI6W3sibWV0aG9kIjoib2F1dGgiLCJ0aW1lc3RhbXAiOjE3MjM1OTAxODB9XSwic2Vzc2lvbl9pZCI6IjU5MjhkZTIxLTI3M2ItNDkzNC1iMGFmLThlYWE3MDUxOGE3MiIsImlzX2Fub255bW91cyI6ZmFsc2V9.Qby46q2eDZUWjpPPSvmyzQ5bGKGEkpg2r9zBAUTpc3Q',
|
||||
);
|
||||
}
|
||||
setupConnection();
|
||||
};
|
||||
|
||||
function convertPKCS8toPKCS1(pkcs8Key) {
|
||||
const privateKeyInfo = forge.pki.privateKeyFromPem(pkcs8Key);
|
||||
|
||||
// Convert the private key to PKCS#1 format
|
||||
const pkcs1Pem = forge.pki.privateKeyToPem(privateKeyInfo);
|
||||
return pkcs1Pem;
|
||||
}
|
||||
|
|
|
@ -1,46 +0,0 @@
|
|||
/* jshint esversion: 6, asi: true, node: true */
|
||||
// util.js
|
||||
|
||||
// private
|
||||
// const debug = require('debug')('WebSSH2');
|
||||
// const Auth = require('basic-auth');
|
||||
|
||||
|
||||
// exports.setDefaultCredentials = function setDefaultCredentials({
|
||||
// name: username,
|
||||
// password,
|
||||
// privatekey,
|
||||
// overridebasic,
|
||||
// }) {
|
||||
// defaultCredentials = { username, password, privatekey, overridebasic };
|
||||
// };
|
||||
|
||||
// exports.basicAuth = function basicAuth(req, res, next) {
|
||||
// const myAuth = Auth(req);
|
||||
// // If Authorize: Basic header exists and the password isn't blank
|
||||
// // AND config.user.overridebasic is false, extract basic credentials
|
||||
// // from client]
|
||||
// const { username, password, privatekey, overridebasic } = defaultCredentials;
|
||||
// if (myAuth && myAuth.pass !== '' && !overridebasic) {
|
||||
// req.session.username = myAuth.name;
|
||||
// req.session.userpassword = myAuth.pass;
|
||||
// debug(`myAuth.name: ${myAuth.name} and password ${myAuth.pass ? 'exists' : 'is blank'}`);
|
||||
// } else {
|
||||
// req.session.username = username;
|
||||
// req.session.userpassword = password;
|
||||
// req.session.privatekey = privatekey;
|
||||
// }
|
||||
// if (!req.session.userpassword && !req.session.privatekey) {
|
||||
// res.statusCode = 401;
|
||||
// debug('basicAuth credential request (401)');
|
||||
// res.setHeader('WWW-Authenticate', 'Basic realm="WebSSH"');
|
||||
// res.end('Username and password required for web SSH service.');
|
||||
// return;
|
||||
// }
|
||||
// next();
|
||||
// };
|
||||
|
||||
// takes a string, makes it boolean (true if the string is true, false otherwise)
|
||||
exports.parseBool = function parseBool(str) {
|
||||
return str.toLowerCase() === 'true';
|
||||
};
|
Loading…
Reference in a new issue