From aceead90649048a78cca38817fd5c75b81858823 Mon Sep 17 00:00:00 2001 From: raven Date: Wed, 11 Jan 2023 15:48:57 -0500 Subject: [PATCH] Refreactor to add a command handler --- .gitignore | 1 + README.md | 18 +-- commands/AI.js | 15 +++ commands/cd.js | 14 +++ commands/exec.js | 20 ++++ commands/login.js | 33 ++++++ commands/restart.js | 20 ++++ commands/start.js | 19 +++ commands/stats.js | 19 +++ commands/stop.js | 19 +++ sshChat.js | 174 +++++++++++++++++++++++++++ sshChat.mjs | 283 -------------------------------------------- 12 files changed, 343 insertions(+), 292 deletions(-) create mode 100644 commands/AI.js create mode 100644 commands/cd.js create mode 100644 commands/exec.js create mode 100644 commands/login.js create mode 100644 commands/restart.js create mode 100644 commands/start.js create mode 100644 commands/stats.js create mode 100644 commands/stop.js create mode 100644 sshChat.js delete mode 100644 sshChat.mjs diff --git a/.gitignore b/.gitignore index 3c3629e..29085f1 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ node_modules +old_code \ No newline at end of file diff --git a/README.md b/README.md index 9306e8a..9fe1b12 100644 --- a/README.md +++ b/README.md @@ -32,12 +32,12 @@ To install: To run a new topic (room): -`node sshchat.mjs` +`node sshchat.js` This will give you a connection topic to share: ``` -/sshChat ❯ ✦ node sshChat.mjs +/sshChat ❯ ✦ node sshChat.js joined topic: 6076c0903ad293e24c10fceb501fe7b02425f6d26c7a5b2d015abd07e3e6b17b (Share this key to others so they may join.) You are now in a chatroom for your topic, feel free to chat. @@ -51,19 +51,19 @@ To connect to an altready made topic (room) pass the hash on start up: # Commands -/login [API KEY] - Login to the API +\>login [API KEY] - Login to the API -\>command here - Send a command to your container +\> command here - Send a command to your container -\> cd /to/path - Change your working directory. +\>cd /to/path - Change your working directory. -/start - Start your container +>start - Start your container -/stop - Stop your container +>stop - Stop your container -/restart - restart your container +>restart - restart your container -/stats - Get the containers stats +>stats - Get the containers stats ! [prompt] - Send a prompt to GPT3 diff --git a/commands/AI.js b/commands/AI.js new file mode 100644 index 0000000..a331608 --- /dev/null +++ b/commands/AI.js @@ -0,0 +1,15 @@ +// AI.js + +var unirest = require('unirest'); + +async function AIRequest(prompt) { + console.log("Please wait while the AI thinks about this....\n") + let AIRequest = await unirest + .post('https://codex-ai-v9q6.onrender.com/') + .headers({ 'Accept': 'application/json', 'Content-Type': 'application/json' }) + .send({ "prompt": prompt }) + return AIRequest.body.bot +} + + + module.exports = { AIRequest } \ No newline at end of file diff --git a/commands/cd.js b/commands/cd.js new file mode 100644 index 0000000..91ecd23 --- /dev/null +++ b/commands/cd.js @@ -0,0 +1,14 @@ +async function changeDir(commandArgs, USERPWD) { + let newDir; + if (commandArgs.startsWith("/")) { + newDir = commandArgs; + console.log("Directory Changed to: " + newDir) + } else { + newDir = USERPWD + "/" + commandArgs; + console.log("Directory Changed to: " + newDir) + } + return newDir; +} + module.exports = { changeDir } + + \ No newline at end of file diff --git a/commands/exec.js b/commands/exec.js new file mode 100644 index 0000000..8b6c7fc --- /dev/null +++ b/commands/exec.js @@ -0,0 +1,20 @@ +// exec.js +const unirest = require("unirest"); + +async function runCMD(key, cmd, pwd) { + let requestData = await unirest + .post('https://api.discord-linux.com/exec') + .headers({ + 'Accept': 'application/json', 'Content-Type': 'application/json', + 'x-discord-linux-auth': key + }) + .send({ "cmd": cmd, "pwd": pwd }) + return requestData.body.stdout +} + +async function execute(key, cmd, pwd) { + const stdout = await runCMD(key, cmd, pwd) + console.log(stdout) +} + +module.exports = { execute, runCMD } \ No newline at end of file diff --git a/commands/login.js b/commands/login.js new file mode 100644 index 0000000..0e4280b --- /dev/null +++ b/commands/login.js @@ -0,0 +1,33 @@ +var unirest = require('unirest'); + +async function login(key, conns, MYKEY) { + getUSERNAME(key) + .then((data) => { + process.stdout.write("\033[2J") + process.stdout.write("\033[0f") + console.log("Hello, " + data + "\nYou are now logged in.\n\n\n") + USERNAME = data + MYKEY.push(key) + LOGGEDIN = true + for (const conn of conns) { + conn.write(`${USERNAME} is now logged in.`) + } + }) + .catch(err => { + console.log("Invalid Key") + for (const conn of conns) { + conn.write("Invalid Key, please try again.") + } + }) +} + + +// API Functions +async function getUSERNAME(key) { + let requestUSERNAME = await unirest + .get('https://api.discord-linux.com/hello') + .headers({ 'Accept': 'application/json', 'Content-Type': 'application/json', 'x-discord-linux-auth': key }) + return requestUSERNAME.body.message.replace("Hello, ", "").replace("!", "") + } + +module.exports = { login } \ No newline at end of file diff --git a/commands/restart.js b/commands/restart.js new file mode 100644 index 0000000..02d26fa --- /dev/null +++ b/commands/restart.js @@ -0,0 +1,20 @@ +// restart.js +const unirest = require("unirest"); + +async function restart(key) { + + async function restartContainer(key) { + let restartContainer = await unirest + .get('https://api.discord-linux.com/restart') + .headers({ + 'Accept': 'application/json', 'Content-Type': 'application/json', + 'x-discord-linux-auth': key + }) + return restartContainer.body + } + + const response = await restartContainer(key) + console.log(response) +} + +module.exports = { restart } diff --git a/commands/start.js b/commands/start.js new file mode 100644 index 0000000..9ac1a31 --- /dev/null +++ b/commands/start.js @@ -0,0 +1,19 @@ +// start.js +const unirest = require("unirest"); + +async function startContainer(key) { + let startContainer = await unirest + .get('https://api.discord-linux.com/start') + .headers({ + 'Accept': 'application/json', 'Content-Type': 'application/json', + 'x-discord-linux-auth': key + }) + return startContainer.body +} + +async function start(key) { + const response = await startContainer(key) + console.log(response) +} + +module.exports = { start, startContainer } diff --git a/commands/stats.js b/commands/stats.js new file mode 100644 index 0000000..309deec --- /dev/null +++ b/commands/stats.js @@ -0,0 +1,19 @@ +// stats.js +const unirest = require("unirest"); + +async function getStats(key) { + let requestData = await unirest + .get('https://api.discord-linux.com/stats') + .headers({ + 'Accept': 'application/json', 'Content-Type': 'application/json', + 'x-discord-linux-auth': key + }) + return requestData.body +} + +async function stats(key) { + const response = await getStats(key) + console.log(response) +} + +module.exports = { stats, getStats } \ No newline at end of file diff --git a/commands/stop.js b/commands/stop.js new file mode 100644 index 0000000..00e97c3 --- /dev/null +++ b/commands/stop.js @@ -0,0 +1,19 @@ +// start.js +const unirest = require("unirest"); + +async function stopContainer(key) { + let stopContainer = await unirest + .get('https://api.discord-linux.com/stop') + .headers({ + 'Accept': 'application/json', 'Content-Type': 'application/json', + 'x-discord-linux-auth': key + }) + return stopContainer.body +} + +async function stop(key) { + const response = await stopContainer(key) + console.log(response) +} + +module.exports = { stop, stopContainer } diff --git a/sshChat.js b/sshChat.js new file mode 100644 index 0000000..96e5c73 --- /dev/null +++ b/sshChat.js @@ -0,0 +1,174 @@ +const Hyperswarm = require('hyperswarm') +const crypto = require('hypercore-crypto') +const b4a = require('b4a') +const readline = require('readline') +const fs = require("fs"); +const { login } = require('./commands/login'); +const { execute } = require('./commands/exec'); +const { stop } = require('./commands/stop'); +const { start } = require('./commands/start'); +const { restart } = require('./commands/restart'); +const { stats } = require('./commands/stats'); +const { changeDir } = require('./commands/cd'); +const { AIRequest } = require('./commands/AI'); + +let rand = Math.floor(Math.random() * 99999).toString(); + +let USERPWD = "/" +let DAPI_KEY +let USERNAME = "anon" + rand +let LOGGEDIN = false +let MYKEY = [] +let conns = [] + + + +function sleep(ms) { + return new Promise((resolve) => { + setTimeout(resolve, ms); + }); +} + +async function clearCursor() { + readline.moveCursor(process.stdout, 0, -2) // up one line + readline.clearLine(process.stdout, 0) // from cursor to end + readline.moveCursor(process.stdout, 0, 2) // up one line +} + +// Generate a random public key +const publicKey = crypto.randomBytes(32) + +// Create the swarm and pass in the public key +const swarm = new Hyperswarm() + +const commandDir = './commands/'; +const commandFiles = fs.readdirSync(commandDir); + +const commands = {} + +for (const file of commandFiles) { + const commandName = file.split(".")[0] + require(`${commandDir}/${file}`) + const command = require(`${commandDir}/${file}`); + commands[commandName] = command; + +} + + + +async function handleCommand(input) { + if (input.startsWith("!") || input.startsWith(">")) { + const command = input.split(" ") + switch (command[0]) { + case "!": + AIRequest(command.slice(1).join(" ")) + break; + case ">cd": + USERPWD = await changeDir(command[1], USERPWD); + console.log(USERPWD) + break; + case ">stats": + stats(MYKEY[0]) + break; + case ">": + execute(MYKEY[0], command.slice(1), USERPWD); + break; + case ">restart": + restart(MYKEY[0]) + break; + case ">stop": + stop(MYKEY[0]) + break; + case ">start": + start(MYKEY[0]) + break; + case ">login": + login(command[1], conns, MYKEY) + break; + default: + console.log("Command not found.") + } + } else { + for (const conn of conns) + if (input.startsWith("!") || input.startsWith(">")){ + + }else { + conn.write(`${USERNAME}: ${input}`) + } + } + console.log(`${USERNAME}: ${input}`) + clearCursor() + +} + +swarm.on('connection', conn => { + + process.on('SIGINT', async () => { + console.log("Sending close message...") + for (let conn of conns) { + conn.write(`CLOSED: ${publicKey.toString('hex')}`) + } + + await sleep(2000) + process.exit() + + }) + + const name = b4a.toString(conn.remotePublicKey, 'hex') + console.log(`* got a connection from ${name} (${USERNAME}) *`) + conns.push(conn) + conn.once('close', () => conns.splice(conns.indexOf(conn), 1)) + conn.on('data', data => { + if (data.toString().startsWith('CLOSED:')) { + // Extract the key from the message string + const key = data.toString().split(':')[1].trim(); + console.log(`Removing peer ${key}`); + (async () => { + + await sleep(5000) + conns = conns.filter(c => c !== conn); + conn.destroy(); + })(); + + } else { + console.log(`${data}`) + } + // Use the USERNAME if it has been set, otherwise use the public key + }) +}) + +swarm.on('error', (err) => { + console.log('Error connecting to peer:', err); +}); + +// Use readline to accept input from the user +const rl = readline.createInterface({ + input: process.stdin, + output: process.stdout +}) + +// When the user inputs a line of text, broadcast it to all connections +rl.on('line', input => { + handleCommand(input) +}) + +// Join a common topic +const topic = process.argv[2] ? b4a.from(process.argv[2], 'hex') : crypto.randomBytes(32) + +setTimeout(() => { + const discovery = swarm.join(topic, { + lookup: true, + announce: true, + timeout: 300000 + + }); + + // The flushed promise will resolve when the topic has been fully announced to the DHT + discovery.flushed().then(() => { + console.log(`joined topic: ${b4a.toString(topic, 'hex')}\n(Share this key to others so they may join.)`) + console.log('You are now in a chatroom for your topic, feel free to chat.\n') + console.log('Want to login to the SSH.SURF API? Type ">login [APIKEY]" to login.\n\n') + }) +}, 1000); + + diff --git a/sshChat.mjs b/sshChat.mjs deleted file mode 100644 index e36dc78..0000000 --- a/sshChat.mjs +++ /dev/null @@ -1,283 +0,0 @@ - -import Hyperswarm from 'hyperswarm' -import goodbye from 'graceful-goodbye' -import crypto from 'hypercore-crypto' -import b4a from 'b4a' -import readline from 'readline' -import unirest from "unirest"; -let rand = Math.floor(Math.random() * 99999).toString(); - -function sleep(ms) { - return new Promise((resolve) => { - setTimeout(resolve, ms); - }); -} -// Generate a random public key -const publicKey = crypto.randomBytes(32) - -// Create the swarm and pass in the public key -const swarm = new Hyperswarm() -// goodbye(() => { -// const message = `CLOSED: ${publicKey.toString('hex')}`; -// for (let conn of conns) { -// conn.write(message); -// } -// }); -// Keep track of all connections and USERNAMEs -let conns = [] -let USERPWD = "/" -let DAPI_KEY = {} -let USERNAME = "anon" + rand -let LOGGEDIN = false - -async function clearCursor() { - readline.moveCursor(process.stdout, 0, -2) // up one line - readline.clearLine(process.stdout, 0) // from cursor to end - readline.moveCursor(process.stdout, 0, 2) // up one line -} - -// API Functions -async function getUSERNAME(key) { - let requestUSERNAME = await unirest - .get('https://api.discord-linux.com/hello') - .headers({ 'Accept': 'application/json', 'Content-Type': 'application/json', 'x-discord-linux-auth': key }) - return requestUSERNAME.body.message.replace("Hello, ", "").replace("!", "") -} - -async function runCMD(key, cmd, pwd) { - let requestData = await unirest - .post('https://api.discord-linux.com/exec') - .headers({ - 'Accept': 'application/json', 'Content-Type': 'application/json', - 'x-discord-linux-auth': key - }) - .send({ "cmd": cmd, "pwd": pwd }) - return requestData.body.stdout -} - -async function startContainer(key) { - let startContainer = await unirest - .get('https://api.discord-linux.com/start') - .headers({ - 'Accept': 'application/json', 'Content-Type': 'application/json', - 'x-discord-linux-auth': key - }) - return startContainer.body -} - -async function stopContainer(key) { - let stopContainer = await unirest - .get('https://api.discord-linux.com/stop') - .headers({ - 'Accept': 'application/json', 'Content-Type': 'application/json', - 'x-discord-linux-auth': key - }) - return stopContainer.body -} - -async function restartContainer(key) { - let restartContainer = await unirest - .get('https://api.discord-linux.com/restart') - .headers({ - 'Accept': 'application/json', 'Content-Type': 'application/json', - 'x-discord-linux-auth': key - }) - return restartContainer.body -} - -async function getStats(key) { - let getStats = await unirest - .get('https://api.discord-linux.com/stats') - .headers({ - 'Accept': 'application/json', 'Content-Type': 'application/json', - 'x-discord-linux-auth': key - }) - return getStats.body -} - -async function AIRequest(prompt) { - let AIRequest = await unirest - .post('https://codex-ai-v9q6.onrender.com/') - .headers({ 'Accept': 'application/json', 'Content-Type': 'application/json' }) - .send({ "prompt": prompt }) - return AIRequest.body.bot -} - -swarm.on('connection', conn => { - - process.on('SIGINT', async () => { - console.log("Sending close message...") - for (let conn of conns) { - conn.write(`CLOSED: ${publicKey.toString('hex')}`) - } - - await sleep(2000) - process.exit() - - }) - - const name = b4a.toString(conn.remotePublicKey, 'hex') - console.log(`* got a connection from ${name} (${USERNAME}) *`) - conns.push(conn) - conn.once('close', () => conns.splice(conns.indexOf(conn), 1)) - conn.on('data', data => { - if (data.toString().startsWith('CLOSED:')) { - // Extract the key from the message string - const key = data.toString().split(':')[1].trim(); - console.log(`Removing peer ${key}`); - (async () => { - - await sleep(5000) - conns = conns.filter(c => c !== conn); - conn.destroy(); - })(); - - } else { - console.log(`${data}`) - } - // Use the USERNAME if it has been set, otherwise use the public key - }) -}) - -swarm.on('error', (err) => { - console.log('Error connecting to peer:', err); -}); - -// Use readline to accept input from the user -const rl = readline.createInterface({ - input: process.stdin, - output: process.stdout -}) - -// When the user inputs a line of text, broadcast it to all connections -rl.on('line', input => { - - const signIn = input.match(/^\/login (\S+)$/) - if (signIn) { - const APIKEY = signIn[1] - DAPI_KEY = { "key": APIKEY } - getUSERNAME(APIKEY).then((data) => { - USERNAME = data - // const name = b4a.toString(publicKey, 'hex') - // names[name] = USERNAME - for (const conn of conns) { - conn.write(`${USERNAME} has logged in!`) - } - clearCursor() - console.log(`Welcome ${USERNAME} you are now logged in!`) - return LOGGEDIN = true - }); - } - - const changeDir = input.startsWith(">cd") || input.startsWith("> cd") - if (changeDir) { - const commandArgs = input.replace("> cd ", "").replace(">cd", "").replace(" ", "") - if (commandArgs.startsWith("/")) { - USERPWD = commandArgs; - console.log("Directory Changed to: " + USERPWD) - } else { - USERPWD = USERPWD + "/" + commandArgs; - console.log("Directory Changed to: " + USERPWD) - } - - } - - const execute = input.startsWith(">") - if (input.startsWith("/") || input.startsWith("!")) return - - if (execute) { - let inputdata = input.split(2) - const cmdToRun = inputdata.join(" ").replace("> ", "").replace(">", "") - if (cmdToRun.includes("cd")) return - runCMD(DAPI_KEY.key, cmdToRun, USERPWD).then((data) => { - console.log(data) - for (const conn of conns) { - conn.write(`${USERNAME} ran ${cmdToRun}: \n` + data) - } - }) - } - - const AI = input.startsWith("!") - if (AI) { - let inputdata = input.split(2) - const prompt = inputdata.join(" ").replace("! ", "").replace("!", "") - AIRequest(prompt).then((data) => { - console.log(data) - for (const conn of conns) { - conn.write(`${USERNAME} ran ${cmdToRun}: \n` + data) - } - }) - } - - const start = input.startsWith("/start") - if (start) { - startContainer(DAPI_KEY.key).then((data) => { - console.log(data) - for (const conn of conns) { - conn.write(`${USERNAME} ran start.`) - } - }) - } - - const stop = input.startsWith("/stop") - if (stop) { - stopContainer(DAPI_KEY.key).then((data) => { - console.log(data) - for (const conn of conns) { - conn.write(`${USERNAME} ran stop.`) - } - }) - } - - const restart = input.startsWith("/restart") - if (restart) { - restartContainer(DAPI_KEY.key).then((data) => { - console.log(data) - for (const conn of conns) { - conn.write(`${USERNAME} ran restart.`) - } - }) - } - - const stats = input.startsWith("/stats") - if (stats) { - getStats(DAPI_KEY.key).then((data) => { - console.log(data) - for (const conn of conns) { - conn.write(`${USERNAME} ran stats.`) - } - }) - } - else { - // if (!LOGGEDIN) return console.log("Please login using /login [API KEY]") - if (input.startsWith("/") || input.startsWith("!")) return - - for (const conn of conns) { - conn.write(`${USERNAME}: ${input}`) - } - console.log(`${USERNAME}: ${input}`) - // Clear the input line\ - clearCursor() - } -}) - -// Join a common topic -const topic = process.argv[2] ? b4a.from(process.argv[2], 'hex') : crypto.randomBytes(32) - -setTimeout(() => { - const discovery = swarm.join(topic, { - lookup: true, - announce: true, - timeout: 300000 - - }); - - // The flushed promise will resolve when the topic has been fully announced to the DHT - discovery.flushed().then(() => { - console.log(`joined topic: ${b4a.toString(topic, 'hex')}\n(Share this key to others so they may join.)`) - console.log('You are now in a chatroom for your topic, feel free to chat.\n') - console.log('Want to login to the SSH.SURF API? Type "/login [APIKEY]" to login.\n\n') - }) -}, 1000); - -