//start ws server with socket.io const SerAny = require('serialize-anything'); var http = require('http'); var express = require('express'); import { Request, Response } from 'express'; var app = express(); var server = http.createServer(app); var port = process.env.PORT || 8480; var fs = require('fs'); const { Server } = require("socket.io"); const { abort } = require('process'); import { Socket } from 'socket.io'; const io = new Server(server); app.get('/', (req:Request, res:Response) => { res.sendFile(__dirname + '/index.html'); }); //initialize buffer //var buffer = []; //add type for typescript var buffer: { [id: string]: string } = {}; //var filesystem = []; var filesystem: any = {}; //var curdir = []; var curdir: any = {}; //var sessions = []; var sessions: any = {}; //var curdirx = []; var curdirx: any = {}; //on connection function sendbuffer(socket:Socket, bufferx: { [id: string]: string }) { var bufx = bufferx[socket.id]; //add placeholder character(reserved unicode) for blinking cursor in client; bufx += "\u2588"; socket.emit('buffer', bufx); } io.on('connection', (socket:Socket) => { console.log('a user connected'); buffer[socket.id] = ""; filesystem[socket.id] = {}; curdir[socket.id] = filesystem[socket.id]; curdirx[socket.id] = []; //welcome message buffer[socket.id] = "Welcome to the console!\n"; buffer[socket.id] += "Type 'help' to see the available commands.\n"; buffer[socket.id] += "#"; //send buffer sendbuffer(socket, buffer); socket.on('keypress', (data) => { console.log('a key was pressed'); //get key //convert data to string var key = String.fromCharCode(data); //convert key to lowercase key = key.toLowerCase(); console.log(data); //check if key is printable character or digit or . or space etc //check if key is enter if (data == 8){ //backspace //if line is not empty remove last character if it is not the first character var lines = buffer[socket.id].split("\n"); if (lines[lines.length - 1] != "#") { lines[lines.length - 1] = lines[lines.length - 1].slice(0, -1); buffer[socket.id] = lines.join("\n"); } } else if(data == 13) { //execute command let lines = buffer[socket.id].split('\n'); let command = lines[lines.length-1]; //remove # from command command = command.substring(1); //remove \n and everything after command = command.substring(command.indexOf('\n'), command.length); let args = command.split(' '); let commandName = args[0]; let commandArgs = args.slice(1); //remove trailing spaces commandArgs = commandArgs.map(function(arg) { return arg.trim(); }); //add \n to buffer buffer[socket.id] += "\n"; //remove # in beginning of commandname console.log("Executing command: \"" + commandName + "\" with arguments: \"" + commandArgs + "\""); resolveCommand(commandName, socket, commandArgs); } else{ //add key to buffer buffer[socket.id] += key; } //send buffer to client sendbuffer(socket, buffer); }); }); io.on('disconnect', (socket:Socket) => { console.log('user disconnected'); buffer[socket.id] = ""; }); function resolveCommand(commandname:string, socket:Socket, args:string[]) { switch (commandname) { case "help": buffer[socket.id] += "Available commands:\n"; buffer[socket.id] += "help - shows this help\n"; buffer[socket.id] += "clear - clears the console\n"; buffer[socket.id] += "exit - exits the console\n"; buffer[socket.id] += "ls - lists the files in the current directory\n"; buffer[socket.id] += "cd - changes the current directory\n"; buffer[socket.id] += "echo - prints the arguments\n"; buffer[socket.id] += "mkdir - creates a new directory\n"; buffer[socket.id] += "cat - prints the contents of a file\n"; buffer[socket.id] += "touch - creates a new file\n"; buffer[socket.id] += "rm - removes a file\n"; buffer[socket.id] += "mv - moves a file\n"; buffer[socket.id] += "cp - copies a file\n"; buffer[socket.id] += "rmdir - removes a directory\n"; //spam buffer[socket.id] += "spam - spams the console\n"; //command to write rest of args to file buffer[socket.id] += "write - writes the arguments to a file\n"; //command to take a screenshot which is saved in the current directory with filename from args buffer[socket.id] += "screenshot - takes a screenshot\n"; break; case "savesess": if (args.length == 2) { if (args[0] == "kryptic") { sessions[args[1]] = []; sessions[args[1]]["buffer"] = buffer[socket.id].slice(); sessions[args[1]]["filesystem"] = JSON.parse(JSON.stringify(filesystem[socket.id])); sessions[args[1]]["curdir"] = JSON.parse(JSON.stringify(curdir[socket.id])); var data = SerAny.serialize(sessions); //write all sessions to a single file called sessions.json fs.writeFileSync("./sessions.json", data); buffer[socket.id] += "Session saved.\n"; } else { buffer[socket.id] += "Invalid command."; } } else { buffer[socket.id] += "Invalid command."; } break; case "loadsess": if (args.length == 1) { sessions = SerAny.deserialize(fs.readFileSync("./sessions.json")); if(sessions[args[0]] != undefined) { filesystem[socket.id] = sessions[args[0]]["filesystem"]; curdir[socket.id] = sessions[args[0]]["curdir"]; buffer[socket.id] = sessions[args[0]]["buffer"]; buffer[socket.id] += "Session loaded.\n"; } } else { } break; case "wee": buffer[socket.id] += "woo\n"; break; case "woo": buffer[socket.id] += "wee\n"; break; //implement more commands case "screenshot": curdir[socket.id][args[0]] = buffer[socket.id]; buffer[socket.id] += "Screenshot saved to " + args[0] + "\n"; break; case "rm": if (curdir[socket.id][args[0]] != undefined) { if (typeof curdir[socket.id][args[0]] == "string") { delete curdir[socket.id][args[0]]; buffer[socket.id] += "File " + args[0] + " removed\n"; } else { buffer[socket.id] += "Error: " + args[0] + " is not a file\n"; } } else { buffer[socket.id] += "Error: " + args[0] + " does not exist\n"; } break; case "mv": if (curdir[socket.id][args[0]] != undefined) { if (typeof curdir[socket.id][args[0]] == "string") { curdir[socket.id][args[1]] = curdir[socket.id][args[0]]; delete curdir[socket.id][args[0]]; buffer[socket.id] += "File " + args[0] + " moved to " + args[1] + "\n"; } else { buffer[socket.id] += "Error: " + args[0] + " is not a file\n"; } } else { buffer[socket.id] += "Error: " + args[0] + " does not exist\n"; } break; case "cp": if (curdir[socket.id][args[0]] != undefined) { if (typeof curdir[socket.id][args[0]] == "string") { curdir[socket.id][args[1]] = curdir[socket.id][args[0]].slice(0); buffer[socket.id] += "File " + args[0] + " copied to " + args[1] + "\n"; } else { buffer[socket.id] += "Error: " + args[0] + " is not a file\n"; } } else { buffer[socket.id] += "Error: " + args[0] + " does not exist\n"; } break; case "rmdir": if (curdir[socket.id][args[0]] != undefined) { if (typeof curdir[socket.id][args[0]] == "object") { delete curdir[socket.id][args[0]]; buffer[socket.id] += "Directory " + args[0] + " removed\n"; } else { buffer[socket.id] += "Error: " + args[0] + " is not a directory\n"; } } else { buffer[socket.id] += "Error: " + args[0] + " does not exist\n"; } break; case "spam": //spam arguments times from first argument for (let i = 0; i < parseInt(args[0]); i++) { buffer[socket.id] += args.slice(1).join(" ") + "\n"; } break; case "touch": if (args.length == 0) { buffer[socket.id] += "touch: missing operand\n"; } else { curdir[socket.id][args[0]] = ""; } break; case "write": if (args.length == 0) { buffer[socket.id] += "write: missing operand\n"; } else { curdir[socket.id][args[0]] = ""; for (let i = 1; i < args.length; i++) { curdir[socket.id][args[0]] += args[i] + " "; } } break; case "cat": if (args.length == 0) { buffer[socket.id] += "cat: missing operand\n"; } else { let file = args[0]; if (curdir[socket.id][file] == undefined) { buffer[socket.id] += "cat: " + file + ": No such file or directory\n"; } //check if type string else if(typeof curdir[socket.id][file] == "string") { buffer[socket.id] += curdir[socket.id][file] + "\n"; } else{ buffer[socket.id] += "cat: " + file + ": Is not a file\n"; } } break; case "echo": buffer[socket.id] += args.join(' '); buffer[socket.id] += "\n"; break; case "clear": buffer[socket.id] = ""; break; case "exit": buffer[socket.id] = ""; buffer[socket.id] += "Bye!\n"; socket.disconnect(); break; case "ls": buffer[socket.id] += "Files in the current directory:\n"; //list only first level files for (var key in curdir[socket.id]) { //buffer[socket.id] += key + "\n"; //also print if it is a directory or file if (typeof curdir[socket.id][key] == "string") { buffer[socket.id] += key + " (file)\n"; } else if (typeof curdir[socket.id][key] == "object") { buffer[socket.id] += key + " (directory)\n"; } else { buffer[socket.id] += key + " (unknown)\n"; } } break; case "cd": if (args.length == 0) { buffer[socket.id] += "Please specify a directory.\n"; } else { if(args[0] == "..") { //go up one directory //recursively scan filesystem until we find curdir and then set curdir to its parent //check curdirx is not empty if (curdirx[socket.id].length > 0) { //pop off last element var sync = "filesystem[socket.id]"; for(let i = 0; i < curdirx[socket.id].length; i++) { sync += "['" + curdirx[socket.id][i] + "']"; } sync += " = curdir[socket.id];"; console.log(sync); eval(sync); curdirx[socket.id].pop(); //curdir = filesystem[socket.id][(curdirx[socket.id][0])][(curdirx[socket.id][1])].......; //i know i shouldnt use eval but I don't know any other way to do this var cmdexec = "curdir[socket.id] = filesystem[socket.id]"; //syncing = write curdir to a path in the filesystem for (let i = 0; i < curdirx[socket.id].length; i++) { cmdexec += "[(curdirx[socket.id][" + i + "])]"; } eval(cmdexec); } } else { if (curdir[socket.id][args[0]] != undefined) { //check if type dict if (typeof curdir[socket.id][args[0]] == "object") { curdir[socket.id] = curdir[socket.id][args[0]]; buffer[socket.id] += "Changed directory to " + args[0] + "\n"; curdirx[socket.id].push(args[0]); } else{ buffer[socket.id] += "cd: " + args[0] + ": Is not a directory\n"; } } else { buffer[socket.id] += "Directory " + args[0] + " does not exist.\n"; } } } break; case "pwd": var curdirasstring = curdirx[socket.id].join("/"); buffer[socket.id] += "Current directory: " + curdirasstring + "\n"; break; case "mkdir": if (args.length == 0) { buffer[socket.id] += "Please specify a directory.\n"; } else { if (curdir[socket.id][args[0]]) { buffer[socket.id] += "Directory " + args[0] + " already exists.\n"; } else { curdir[socket.id][args[0]] = {}; buffer[socket.id] += "Created directory " + args[0] + "\n"; } } break; //invalid command default: buffer[socket.id] += "Invalid command.\n"; } buffer[socket.id] += "#"; } server.listen(port, function() { console.log('Server listening at port %d', port); });