diff --git a/index.js b/index.js new file mode 100644 index 0000000..d16319c --- /dev/null +++ b/index.js @@ -0,0 +1,101 @@ +import { createConnection } from 'net' + +const port = 23; +const hostname = "localhost"; +const delayMs = 100; // Command delay in milliseconds + +export const IAC = Buffer.from([0xff]); // Interpret As Command +export const DONT = Buffer.from([0xfe]); // Don't +export const DO = Buffer.from([0xfd]); // Do +export const WONT = Buffer.from([0xfc]); // Won't +export const WILL = Buffer.from([0xfb]); // Will +export const SB = Buffer.from([0xfa]); // Subnegotiation Begin +export const GA = Buffer.from([0xf9]); // Go Ahead +export const EL = Buffer.from([0xf8]); // Erase Line +export const EC = Buffer.from([0xf7]); // Erase Character +export const AYT = Buffer.from([0xf6]); // Are You There +export const AO = Buffer.from([0xf5]); // Abort Output +export const IP = Buffer.from([0xf4]); // Interrupt Process +export const BRK = Buffer.from([0xf3]); // Break +export const DM = Buffer.from([0xf2]); // Data Mark +export const NOP = Buffer.from([0xf1]); // No Operation +export const SE = Buffer.from([0xf0]); // Subnegotiation End + +// Common Telnet options or features +export const ECHO = Buffer.from([0x01]); // Echo +export const SUPPRESS_GO_AHEAD = Buffer.from([0x03]); // Suppress Go Ahead +export const STATUS = Buffer.from([0x05]); // Status +export const TIMING_MARK = Buffer.from([0x06]); // Timing Mark +export const TERMINAL_TYPE = Buffer.from([0x18]); // Terminal Type +export const NAWS = Buffer.from([0x1f]); // Negotiate About Window Size +export const TERMINAL_SPEED = Buffer.from([0x20]); // Terminal Speed +export const REMOTE_FLOW_CONTROL = Buffer.from([0x21]); // Remote Flow Control +export const LINEMODE = Buffer.from([0x22]); // Line Mode +export const ENVIRONMENT_VARIABLES = Buffer.from([0x24]); // Environment Variables + +// custom codes for own client +export const CUSTOM_CLIENT_INIT = Buffer.from([0x80]); // Custom Client Initialization +export const KEY_EXCHANGE = Buffer.from([0x81]); // Key Exchange +export const ENCRYPTION = Buffer.from([0x82]); // Encryption +export const AUTHENTICATION = Buffer.from([0x83]); // Authentication +// 0x84 reserved for future use +export const FILE_TRANSFER = Buffer.from([0x85]); // File Transfer +export const PAUSE = Buffer.from([0x86]); // Pause +export const RESUME = Buffer.from([0x87]); // Resume + +const socket = createConnection(port, hostname); + +process.stdin.setEncoding("ascii"); +process.stdin.setRawMode(true); +process.stdin.resume(); + +// format keys before sending to server +process.stdin.on('data', (key) => { + if (key === '\u0003') { // Ctrl+C + process.exit(); + } + + // Log hex values of input for debugging + // console.log("Key pressed:", Array.from(key).map(b => '0x' + b.toString(16))); + + if (key == "\r") { + // Enter key + socket.write("\r\n"); + } else { + socket.write(key); + } +}); + +socket.on("data", (data) => { + if (data.equals(PAUSE)) { + process.stdin.pause(); + } else if (data.equals(RESUME)) { + process.stdin.resume(); + } else { + process.stdout.write(data); + } +}); + +socket.on("connect", async () => { + console.log("Connected to server"); + socket.write(Buffer.concat([IAC, WILL, NAWS, SB, NAWS, Buffer.from([/* 24x80 */ 0x00, 0x18, 0x00, 0x50]), SE])); // Negotiate About Window Size + await delay(delayMs); // Wait for server to process + socket.write(Buffer.concat([IAC, WILL, TERMINAL_TYPE, IAC, SB, TERMINAL_TYPE, Buffer.from("xterm-256color"), IAC, SE])); // Terminal Type + await delay(delayMs); + socket.write(Buffer.concat([IAC, WILL, ECHO])); // Echo + await delay(delayMs); + socket.write(Buffer.from([0x0d, 0x0a])); // Line Feed + await delay(delayMs); + // initialization complete + + await send("help"); +}); + +export const delay = (ms) => new Promise(resolve => setTimeout(resolve, ms)); + +export const send = async (command) => { + await delay(delayMs); + socket.write(command); // Command + await delay(delayMs); + socket.write("\r\n"); // Line Feed +}; \ No newline at end of file diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..a21fff6 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,20 @@ +{ + "name": "telnet-client", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "telnet-client", + "version": "1.0.0", + "license": "MIT", + "dependencies": { + "telnet-client": "file:" + } + }, + "node_modules/telnet-client": { + "resolved": "", + "link": true + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..707f56d --- /dev/null +++ b/package.json @@ -0,0 +1,19 @@ +{ + "name": "telnet-client", + "version": "1.0.0", + "description": "To be used with HTDev BBS Server for encrypted communication and extended functionality.", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "repository": { + "type": "git", + "url": "https://git.ht-dev.de/Hammer1279/node-telnet-client" + }, + "author": "Hammer1279", + "license": "MIT", + "type": "module", + "dependencies": { + "telnet-client": "file:" + } +}