Add initial implementation of Telnet client with basic command handling
Signed-off-by: Hammer1279 <hammer@ht-dev.de>
This commit is contained in:
parent
c2de2bef76
commit
4b3c6e861d
101
index.js
Normal file
101
index.js
Normal file
@ -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
|
||||
};
|
20
package-lock.json
generated
Normal file
20
package-lock.json
generated
Normal file
@ -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
|
||||
}
|
||||
}
|
||||
}
|
19
package.json
Normal file
19
package.json
Normal file
@ -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:"
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user