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);