diff --git a/commands/ssh.js b/commands/ssh.js new file mode 100644 index 0000000..3fefa00 --- /dev/null +++ b/commands/ssh.js @@ -0,0 +1,135 @@ +const { Client: SSHClient } = require('ssh2'); + +let sshConnection = null; + +module.exports = { + name: 'ssh', + description: 'Manage an SSH connection. Subcommands: connect, exec, disconnect', + async execute(message, args, deleteTimeout) { + if (!args.length) { + return message.channel + .send("Usage: `.ssh ...`") + .then((msg) => setTimeout(() => msg.delete().catch(() => { }), deleteTimeout)); + } + + const subcommand = args.shift().toLowerCase(); + + if (subcommand === 'connect') { + if (args.length < 3) { + return message.channel + .send("Usage: `.ssh connect [port]`") + .then((msg) => setTimeout(() => msg.delete().catch(() => { }), deleteTimeout)); + } + + if (sshConnection) { + return message.channel + .send("Already connected. Disconnect first using `.ssh disconnect`.") + .then((msg) => setTimeout(() => msg.delete().catch(() => { }), deleteTimeout)); + } + + const host = args[0]; + const username = args[1]; + const password = args[2]; + const port = args[3] ? parseInt(args[3]) : 22; + + sshConnection = new SSHClient(); + + sshConnection + .on('ready', () => { + message.channel + .send(`Connected to ${host}`) + .then((msg) => setTimeout(() => msg.delete().catch(() => { }), deleteTimeout)); + }) + .on('error', (err) => { + message.channel + .send(`SSH Connection error: ${err.message}`) + .then((msg) => setTimeout(() => msg.delete().catch(() => { }), deleteTimeout)); + sshConnection = null; + }) + .on('close', () => { + message.channel + .send(`SSH Connection closed.`) + .then((msg) => setTimeout(() => msg.delete().catch(() => { }), deleteTimeout)); + sshConnection = null; + }); + + sshConnection.connect({ host, port, username, password }); + return; + } + + else if (subcommand === 'exec') { + if (!sshConnection) { + return message.channel + .send("No active SSH connection. Connect first using `.ssh connect ...`") + .then((msg) => setTimeout(() => msg.delete().catch(() => { }), deleteTimeout)); + } + if (!args.length) { + return message.channel + .send("Usage: `.ssh exec `") + .then((msg) => setTimeout(() => msg.delete().catch(() => { }), deleteTimeout)); + } + + const cmd = args.join(' '); + + sshConnection.exec(cmd, (err, stream) => { + if (err) { + return message.channel + .send(`Error executing command: ${err.message}`) + .then((msg) => setTimeout(() => msg.delete().catch(() => { }), deleteTimeout)); + } + + let outputBuffer = ''; + + message.channel.send(`Executing command: \`${cmd}\`\n\`\`\`\n...\n\`\`\``) + .then((sentMsg) => { + const updateInterval = setInterval(() => { + let display = outputBuffer; + if (display.length > 1900) { + display = display.slice(-1900); + } + sentMsg.edit(`Executing command: \`${cmd}\`\n\`\`\`\n${display}\n\`\`\``) + .catch(() => { }); + }, 2000); + + stream.on('data', (data) => { + outputBuffer += data.toString(); + }); + stream.stderr.on('data', (data) => { + outputBuffer += data.toString(); + }); + stream.on('close', (code, signal) => { + clearInterval(updateInterval); + outputBuffer += `\nProcess exited with code ${code}${signal ? ' and signal ' + signal : ''}`; + let display = outputBuffer; + if (display.length > 1900) { + display = display.slice(-1900); + } + sentMsg.edit(`Executing command: \`${cmd}\`\n\`\`\`\n${display}\n\`\`\``) + .catch(() => { }); + }); + }) + .catch(console.error); + }); + return; + } + + else if (subcommand === 'disconnect') { + if (!sshConnection) { + return message.channel + .send("No active SSH connection.") + .then((msg) => setTimeout(() => msg.delete().catch(() => { }), deleteTimeout)); + } + sshConnection.end(); + sshConnection = null; + return message.channel + .send("Disconnecting SSH...") + .then((msg) => setTimeout(() => msg.delete().catch(() => { }), deleteTimeout)); + } + + else { + return message.channel + .send("Unknown subcommand. Use `connect`, `exec`, or `disconnect`.") + .then((msg) => setTimeout(() => msg.delete().catch(() => { }), deleteTimeout)); + } + }, +}; \ No newline at end of file