import { Client } from "twitter-api-sdk"; import Twit from "twit"; import dotenv from "dotenv"; dotenv.config(); import fs from "fs"; import dateFormat from "dateformat" import cmd from "cmd-promise"; import generator from "generate-password" import jsonfile from "jsonfile" import date from "date-and-time"; import Dockerode from 'simple-dockerode'; var docker = new Dockerode({ socketPath: '/var/run/docker.sock' }); let finished let commandToRun let ram let vram let cpus let ifApt let end = "<=================================END===========================>" /*################################## TWITTER API #########################################*/ const config = { consumer_key: process.env.TWITTER_API_KEY, consumer_secret: process.env.TWITTER_API_SECRET_KEY, access_token: process.env.TWITTER_ACCESS_TOKEN, access_token_secret: process.env.TWITTER_ACCESS_TOKEN_SECRET, timeout_ms: 60 * 1000000, strictSSL: true, }; const T = new Twit(config); const client = new Client(process.env.TWITTER_BEARER_TOKEN); //twitter api client const botName = process.env.BOT_USERNAME; //Use the same Twitter username whose API key and token are being used. /*############################# REPLY TO TWITTER API #################################*/ async function replyToTweet(joke, author_id, id) { const data = { status: `${joke}`, //the joke in_reply_to_user_id: author_id, //the id of the user who tweeted in_reply_to_status_id: id, //the id of the tweet auto_populate_reply_metadata: true, //auto populate the reply metadata }; try { const resp = await T.post("statuses/update", data); if (resp) { console.log("replied"); } } catch (error) { console.log(error); } } /*############################# GET THE TWEETS FROM TWITTER API ##########################*/ async function getExitingRule() { //get the existing rules try { const rules = await client.tweets.getRules(); return rules; } catch (error) { console.log(error); } } async function deleteAndSetNewRules() { //delete the existing rules and set new rules try { const rules = await getExitingRule(); // if rules includes id in data then delete the rules if (rules.data) { console.log("rule exists, now deleting"); const ids = rules.data.map((rule) => rule.id); await client.tweets.addOrDeleteRules({ delete: { ids: ids, } }); } console.log("setting new rules"); await client.tweets.addOrDeleteRules({ add: [ { value: `@${botName} has:mentions` } ] }); } catch (error) { console.log(error); } } async function getMentionedTweet() { try { console.log("running"); await deleteAndSetNewRules(); const stream = await client.tweets.searchStream({ "tweet.fields": [ "author_id", // The ID of the user who posted the tweet "id", // The ID of the tweet "in_reply_to_user_id" // The ID of the user the tweet is replying to ], "expansions": [ "referenced_tweets.id.author_id" // The ID of the user who posted the referenced tweet ] }); for await (const response of stream) { if (response.data.text.includes(`@${botName}`)) { //check if the tweet contains the bot's username /* IF BOT IS MENTIONED **IN** THE TWEET */ if (response.includes.tweets === undefined) { //check if the tweet is a reply to another tweet const tweet = JSON.stringify(response.data.text, null, 2).replace(/(https?:\/\/[^\s]+)/g, '').replace(/"/g, '').trim(); r console.log(response.data) const reply = "works" await replyToTweet(reply, response.data.author_id, response.data.id); } else { /* IF BOT IS MENTIONED **UNDER** THE TWEET THEN IT WILL REPLY TO WHOEVER MENTIONED THE BOT BUT WILL TAKE QUESTIONS FROM THE ORIGINAL AUTHORS TWEET */ let userID = response.data.author_id console.log("User ID: " + userID) if (userID == "1600528742396399616") return /////////////////////////////GENERATE if (response.data.text.includes(`generate`)) { cmd(`node /home/opc/genmulti_twit.js` + " " + userID + " " + userID + " " + userID + " ubuntu " + userID).then(out => { console.log('out =', out) const tweet = JSON.stringify(response.includes.tweets[0].text, null, 2).replace(/(https?:\/\/[^\s]+)/g, '').replace(/"/g, '').trim(); //remove the urls and double quotes from the tweet and trim the spaces const now = new Date(); var password = generator.generate({ length: 10, numbers: true }); let rootPass = password cmd("node /exec/dockerexec.js " + userID + " " + "/home" + " " + "\"" + "echo \'root:" + rootPass + "\' | chpasswd" + "\"").then(out => { (async () => { console.log('out =', out.stdout) const reply = "Generated!\n The container will be removed in 7 days!" //get the joke from the openai api return await replyToTweet(reply, response.data.author_id, response.data.id); // reply to the })(); }).catch(err => { console.log('err=', err) if (err.toString().includes("Conflict")) { return } }).catch(err => { console.log('err =', err) }) }).catch(err => { (async () => { (async () => { const reply = "You have a container!" //get the joke from the openai api return await replyToTweet(reply, response.data.author_id, response.data.id); // reply to the })(); console.log(end) })(); console.log(err) return }) } ////////////////////////////////////// if (response.data.text.includes(`destroy`)) { cmd('docker stop ' + userID + " && docker rm " + userID).then(out => { console.log('out =', out) const netConfig = '/home/opc/netcache/' + userID + ".network" try { fs.unlinkSync(netConfig) console.log("Network Config Removed!") } catch(err) { console.log("No Config to remove") } const now = new Date(); (async () => { const reply = "The container was destroyed.\n Come back again!" //get the joke from the openai api await replyToTweet(reply, response.data.author_id, response.data.id); // reply to the return console.log(end) })(); }).catch(err => { if (err.toString().includes("such")) { (async () => { const reply = "No Container can be destroyed." //get the joke from the openai api await replyToTweet(reply, response.data.author_id, response.data.id); // reply to the return console.log(end) })(); } console.log('err =', err) }) } // if (response.data.text.includes(`exec`)) { const tweet = JSON.stringify(response.includes.tweets[0].text, null, 2).replace("exec ", "").replace("@twit-linux ", ""); //remove the urls and double quotes from the tweet and trim the spaces console.log("RUN") if (tweet.includes("destroy")) return if (tweet.includes("generate")) return await cmd('bash /home/opc/check_exist.sh ' + userID).then(out => { console.log('out =', out) if (out.stdout != 1) { (async () => { finished = 1 console.log(end) const reply = "You do not have a container! Use the generate command to make one." //get the joke from the openai api await replyToTweet(reply, response.data.author_id, response.data.id); // reply to the })(); } }).catch(err => { console.log('err =', err) }) console.log("Begin Done") if (finished == 1) { finished = 0 return } else { const path = 'cache/' + userID let test = tweet.replace("@twit_liux ", "").replace("exec ", "").replace(/['"]+/g, '').split(" ") const result = test.filter(word => !word.startsWith("@")); let final = result.join(" ") let code = final console.log("F: " + final) if (code.startsWith("apt install") || code.startsWith("yum install")) { if (!code.includes("-y")) { code = code + " -y" console.log(code) } } if (code.startsWith("pacman install")) { if (!code.includes("--noconfirm")) { code = code + " --noconfirm" console.log(code) } } if (code.startsWith("neofetch")) { code = "neofetch --stdout" } if (fs.existsSync(path)) { console.log("") } else { console.log("No Channel PWD Found! Generating!") fs.writeFile('./cache/' + userID, "{\"pwd\":\"/\"}", function (err) { }); } commandToRun = code.replace("@twit_linux ", "").replace("exec ", "").replace(/['"]+/g, '') console.log("Running: " + commandToRun) if (commandToRun == "yes") return console.log("yes Blocked") /** * * Start of Print Working Directory * */ if (commandToRun == "pwd") { goNoFurther = true // check for channel pwd support file if (fs.existsSync(path)) { console.log("Channel PWD is active") jsonfile = require('jsonfile') jsonfile.readFile(path, function (err, pwdata) { // console.log(pwdata) (async () => { const reply = pwdata.pwd //get the joke from the openai api await replyToTweet(reply, response.data.author_id, response.data.id); // reply to the })(); goNoFurther = false; if (err) console.error(err) }) } function escapeDoubleQuotes(str) { return str.replace(/\\([\s\S])|(")/g, "\\$1$2"); // thanks @slevithan! } } /** * * Main * */ if (commandToRun == "pwd") return /** * * Start of CD * */ if (commandToRun.startsWith("cd")) { console.log("test") argscmd = tweet // check for channel pwd support file if (fs.existsSync(path)) { console.log("Channel PWD is active") jsonfile = require('jsonfile') jsonfile.readFile(path, function (err, pwdata) { let argscmd = commandToRun.replace("cd ", "") let dir = argscmd; // yes, start at 0, not 1. I hate that too. if (startsWith(argscmd, "/") == false) { const cmd = require('cmd-promise') if (!argscmd) { (async () => { const reply = "Give my Syntax Please" //get the joke from the openai api await replyToTweet(reply, response.data.author_id, response.data.id); })(); return } let dir = commandToRun; // yes, start at 0, not 1. I hate that too. let data jsonfile.readFile(path, function (err, pwdata) { if (err) console.error(err) console.log(dir) data = pwdata.pwd + "/" + argscmd if (pwdata.pwd == "/") { data = "/" + argscmd } if (argscmd == "~") { data = "/root" } if (argscmd.includes("~") && argscmd.includes("/")) { data = "/root" + "/" + argscmd.replace("~", "") } if (argscmd.includes("..") || argscmd.includes("../")) { // check if the user is trying to go back a directory console.log(argscmd.split("../")) console.log("user wants to go back " + argscmd.split("../").length + " directories") function RemoveLastDirectoryPartOf(the_url, num) { var the_arr = the_url.split('/'); the_arr.splice(-num, num) return (the_arr.join('/')); } data = RemoveLastDirectoryPartOf(pwdata.pwd, argscmd.split("../").length - 1) } let final = data.replace(/([^:]\/)\/+/g, "$1") console.log(final) const obj = { pwd: final } jsonfile.writeFile(path, obj, function (err) { (async () => { const reply = "Directory Changed to: " + final await replyToTweet(reply, response.data.author_id, response.data.id); // reply to the })(); if (err) console.error(err) }) }); } else { jsonfile.readFile(path, function (err, pwdata) { if (err) console.error(err) console.log('dir:' + dir) //onsole.log(dir) const obj = { pwd: dir.replace(/([^:]\/)\/+/g, "$1") } jsonfile.writeFile(path, obj, function (err) { if (err) console.error(err) }) goNoFurther = false; }); (async () => { const reply = "Directory Changed to: " + dir.replace(/([^:]\/)\/+/g, "$1") await replyToTweet(reply, response.data.author_id, response.data.id); // reply to the })(); } function RemoveLastDirectoryPartOf(the_url) { var the_arr = the_url.split('/'); the_arr.pop(); return (the_arr.join('/')); } function startsWith(str, word) { return str.lastIndexOf(word, 0) === 0; } }) } } /** * * End of CD * */ if (commandToRun.startsWith("destroy")) return if (commandToRun.startsWith("generate")) return if (commandToRun.startsWith("cd")) return console.log("Skipped At Main") if (commandToRun.startsWith("write")) return if (commandToRun == "gobk") return if (fs.existsSync(path)) { function RemoveLastDirectoryPartOf(the_url) { var the_arr = the_url.split('/'); the_arr.pop(); return (the_arr.join('/')); } console.log("Channel PWD is active") jsonfile.readFile(path, function (err, pwdata) { console.log(pwdata) if (code == "neofetch") { code = "neofetch --stdout --color_blocks off" } if (code.startsWith("apt")) { ifApt = "-y" } else if (code.startsWith("yum")) { ifApt = "-y" } else if (code.startsWith("pacman")) { ifApt = "--noconfirm" } else if (code.startsWith("apt-get")) { ifApt = "-y" } else { ifApt = "" } if (code.includes("~")) { code = code.replace("~", "/root") } if (code.includes("..")) { pwdata.pwd = RemoveLastDirectoryPartOf(pwdata.pwd) } // if (code.includes("../")) { // check if the user is trying to go back a directory // function RemoveLastDirectoryPartOf(the_url, num) { // var the_arr = the_url.split('/'); // the_arr.splice(-num, num) // return (the_arr.join('/')); // } // console.log(argscmd.split("../")) // console.log("user wants to go back " + argscmd.split("../").length -1 + " directories in their command") // pwddata.pwd = RemoveLastDirectoryPartOf(pwdata.pwd, argscmd.split("../").length - 1) // } const customerContainer = docker.getContainer(userID); // Simple to grab the stdout and stderr. customerContainer.exec(['/bin/bash', '-c', 'cd ' + pwdata.pwd + ' && ' + commandToRun], { stdout: true, stderr: true }, (err, out) => { if (typeof (out) !== 'undefined') { console.log(out.stdout) if (out.inspect.ExitCode !== 0) { if (out.stderr.includes("syntax error")) { (async () => { const reply = "There is an error in your syntax, please try again." await replyToTweet(reply, response.data.author_id, response.data.id); // reply to the console.log(end) })(); } else { (async () => { const reply = out.stderr await replyToTweet(reply, response.data.author_id, response.data.id); // reply to the console.log(end) })(); } } if (out.inspect.ExitCode == 0) { if (!out.stdout) { (async () => { const reply = 'Command Executed Successfully!' await replyToTweet(reply, response.data.author_id, response.data.id); // reply to the })(); } else { if (out.stdout.length > 230) { fs.writeFile('/tmp/paste', "Command: " + code.replace("--stdout --color_blocks off", "") + " | Container Owner: " + userID + "\n" + out.stdout, err => { if (err) { console.error(err) return } }) cmd("sleep 2; cat /tmp/paste | dpaste").then(pasteout => { (async () => { console.log(end) const reply = "Too Large, Check: " + pasteout.stdout.replace("paste.discord-linux.com", "twit-log.ssh.surf").replace("Pro tip: you can password protect your paste just by typing a username and password after your paste command.", "").replace("Paste Saved: ", "").replace("-------------------------------------------------------", "") //get the joke from the openai api await replyToTweet(reply, response.data.author_id, response.data.id); // reply to the })(); }) } else { //<@UserID NUMBER> (async () => { const reply = out.stdout //get the joke from the openai api await replyToTweet(reply, response.data.author_id, response.data.id); // reply to the console.log("<=================================END===========================>") })(); } } } } else { (async () => { const reply = "Your container either needs to be generated or is not running." //get the joke from the openai api await replyToTweet(reply, response.data.author_id, response.data.id); // reply to the return console.log(end) })(); } }) }) } } /////////////////////////////////////// END OF X } } } } catch (error) { console.log(error); } } getMentionedTweet();