compass-bot/repl/index.mjs
2023-11-05 21:49:15 +08:00

86 lines
2.2 KiB
JavaScript

import repl from 'node:repl';
import net from 'node:net';
import { Buffer } from 'node:buffer';
import { timingSafeEqual } from 'node:crypto';
import { waitEvent } from 'compass-utils';
import { RemoteTTY } from './remote-tty.mjs';
import debug from 'debug';
const logger = debug('compass-repl');
export function createRepl(istream, ostream, prompt, contextLoader) {
let r = repl.start({
prompt: `${prompt} > `,
input: istream,
output: ostream,
color: true,
terminal: true,
ignoreUndefined: true,
});
r.on('SIGCONT', () => { });
r.on('SIGTSTP', () => {});
contextLoader(r.context);
return r;
}
export function createLocalRepl(contextLoader) {
return createRepl(process.stdin, process.stdout, 'local', contextLoader);
}
export function createTcpReplServer(port, passcode, contextLoader) {
const connect_repl_sockets = new Set();
let server = net.createServer(socket => {
logger('New TCP connection');
function verifyPasscode(data) {
let pdata = Buffer.from(data);
logger(`Got passcode: ${pdata.toString('hex')}`);
let flag = true;
if (pdata.length != passcode.length) {
flag = false;
pdata = passcode;
}
if (timingSafeEqual(passcode, pdata) && flag) {
logger('Passcode correct, 0x21!');
socket.write(Buffer.from([0x21]));
let tty = new RemoteTTY({}, socket, socket);
tty.ttyReady().then(() => {
logger('Remote TTY is ready, starting REPL');
let r = createRepl(tty, tty, 'tcp', contextLoader);
r.on('exit', () => {
connect_repl_sockets.delete(socket);
socket.destroy();
});
connect_repl_sockets.add(socket);
}).catch(err => {
logger(`TTY Ready Error: ${err}`);
socket.destroy();
});
} else {
logger('Passcode incorrect, 0x20!');
socket.write(Buffer.from([0x20]));
socket.destroy();
}
}
try {
socket.once('data', (data) => verifyPasscode(data));
socket.on('close', () => {
logger('Disconnected');
connect_repl_sockets.delete(socket);
});
} catch(err) {
logger(`Remote Connect Error: ${err}`);
connect_repl_sockets.delete(socket);
socket.destroy();
}
});
server.listen(port);
process.on('exit', () => {
for (const socket of connect_repl_sockets) {
socket.destroy();
}
});
return server;
}