From efc1eed472426643e8494aacf1be3779409b47af Mon Sep 17 00:00:00 2001 From: danielpmc Date: Thu, 19 Mar 2020 08:08:15 +0000 Subject: [PATCH 001/255] Updated a few things. --- Panel/index.js | 170 +++++--------------------------- Panel/package.json | 3 +- Panel/views/index.hbs | 163 +++++++++++++++++++++--------- Panel/views/partials/header.hbs | 21 ++++ 4 files changed, 161 insertions(+), 196 deletions(-) create mode 100644 Panel/views/partials/header.hbs diff --git a/Panel/index.js b/Panel/index.js index a6c8208e1..33d270f5e 100644 --- a/Panel/index.js +++ b/Panel/index.js @@ -7,15 +7,15 @@ Free Monitoring software made by danielpmc */ -var config = require("./config.json"); -var PORT = config.ListeningPort; +//var config = require("./config.json"); +var PORT = "1144"; var express = require('express'); var app = express(); var server = require('http').createServer(app); var bodyParser = require('body-parser'); var fs = require("fs"); -var hbs = require('express-handlebars'); var chalk = require('chalk'); +const hbs = require('hbs'); app.use(bodyParser.json()); app.use(bodyParser.urlencoded({extended: true})); @@ -26,7 +26,7 @@ server.listen(PORT, function () { app.get('/data', function (req, res) { - console.log(req.query); + //console.log(req.query); //Write data to JSON file after checking servername. var data = JSON.stringify(req.query); @@ -35,155 +35,33 @@ app.get('/data', function (req, res) { }); //View engine setup +hbs.registerPartials(__dirname + '/views/partials') app.set('view engine', 'hbs'); -app.engine('hbs', hbs({ - extname: 'hbs', - defaultView: 'default', - layoutsDir: '/views/pages', - partialsDir: '/views/partials' -})); -//Config Loading and setting up -if (config.Servers.NumberOfServers == 0) { - - //Errors if config is not setup. - console.log(chalk.red("You have not set up the config file")) - process.exit() - -} else if (config.Servers.NumberOfServers == 1) { - if (config.Servers.One == " ") { - - //Checks if server one field in config has valid data. - console.log(chalk.red("You have not set up Server names. Please fill in `One` in the config with your hostname. Don't know it? Run the daemon and that will tell you the hostname!")); - process.exit(); - - } else { - - //Config has valid data for server one. Set up the website! - //Loads the data - var ServerOneData = fs.readFileSync("./data/" + config.Servers.One + ".json", 'utf8'); - var ServerOne = JSON.parse(ServerOneData); - - //Gets the website page and is ready to display it. - app.get("/" + config.Servers.One, (req, res) => { - res.render('ServerOne', { layout: false, - Data: ServerOne - }); - }); - - } -} else if (config.Servers.NumberOfServers == 2) { - if (config.Servers.One == " ") { - - //Checks if server one field in config has valid data. - console.log(chalk.red("You have not set up Server names. Please fill in `One` in the config with your hostname. Don't know it? Run the daemon and that will tell you the hostname!")); - process.exit(); - - } else if (config.Servers.Two == " ") { - - //Checks if server two field in config has valid data. - console.log(chalk.red("You have not set up Server names. Please fill in `Two` in the config with your hostname. Don't know it? Run the daemon and that will tell you the hostname!")); - process.exit(); - - } else { - - //Config has valid data for server one. Set up the website! - - //Loads the data (SERVER ONE) - var ServerOneData = fs.readFileSync("./data/" + config.Servers.One + ".json", 'utf8'); - var ServerOne = JSON.parse(ServerOneData); - - //Gets the website page and is ready to display it. (Server ONE) - app.get("/" + config.Servers.One, (req, res) => { - - //Loads the data (SERVER ONE) - var ServerOneData = fs.readFileSync("./data/" + config.Servers.One + ".json", 'utf8'); - var ServerOne = JSON.parse(ServerOneData); - - res.render('ServerOne', { layout: false, - Data: ServerOne - }); - }); - - //Loads the data (SERVER TWO) - var ServerTwoData = fs.readFileSync("./data/" + config.Servers.Two + ".json", 'utf8'); - var ServerTwo = JSON.parse(ServerTwoData); - - //Gets the website page and is ready to display it. (Server ONE) - app.get("/" + config.Servers.Two, (req, res) => { - res.render('ServerTwo', { layout: false, - Data: ServerTwo - }); - }); - - } -} else if (config.Servers.NumberOfServers == 3) { - if (config.Servers.One == " ") { - - //Checks if server one field in config has valid data. - console.log(chalk.red("You have not set up Server names. Please fill in `One` in the config with your hostname. Don't know it? Run the daemon and that will tell you the hostname!")); - process.exit(); - - } else if (config.Servers.Two == " ") { - - //Checks if server two field in config has valid data. - console.log(chalk.red("You have not set up Server names. Please fill in `Two` in the config with your hostname. Don't know it? Run the daemon and that will tell you the hostname!")); - process.exit(); - - } else if (config.Servers.Three == " ") { - - //Checks if server two field in config has valid data. - console.log(chalk.red("You have not set up Server names. Please fill in `Three` in the config with your hostname. Don't know it? Run the daemon and that will tell you the hostname!")); - process.exit(); - - } else { - - //Config has valid data for server one. Set up the website! - - //Loads the data (SERVER ONE) - var ServerOneData = fs.readFileSync("./data/" + config.Servers.One + ".json", 'utf8'); - var ServerOne = JSON.parse(ServerOneData); - - //Gets the website page and is ready to display it. (Server ONE) - app.get("/" + config.Servers.One, (req, res) => { - res.render('ServerOne', { layout: false, - Data: ServerOne - }); - }); - - //Loads the data (SERVER TWO) - var ServerTwoData = fs.readFileSync("./data/" + config.Servers.Two + ".json", 'utf8'); - var ServerTwo = JSON.parse(ServerTwoData); - - //Gets the website page and is ready to display it. (Server TWO) - app.get("/" + config.Servers.Two, (req, res) => { - res.render('ServerTwo', { layout: false, - Data: ServerTwo - }); - }); - - //Loads the data (SERVER THREE) - var ServerThreeData = fs.readFileSync("./data/" + config.Servers.Three + ".json", 'utf8'); - var ServerThree = JSON.parse(ServerThreeData); +//Routes +app.get("/", (req, res) => { - //Gets the website page and is ready to display it. (Server THREE) - app.get("/" + config.Servers.Three, (req, res) => { - res.render('ServerThree', { layout: false, - Data: ServerThree - }); - }); + //Data for node 1 + var N1 = fs.readFileSync('./data/vmi347338.contaboserver.net.json', 'utf8'); + var Node1 = JSON.parse(N1); - } -} + //Data for node 2 + var N2 = fs.readFileSync('./data/vmi347340.contaboserver.net.json', 'utf8'); + var Node2 = JSON.parse(N2); + + //Data for node 3 + var N3 = fs.readFileSync('./data/vmi347402.contaboserver.net.json', 'utf8'); + var Node3 = JSON.parse(N3); -//Import data -var data = fs.readFileSync('./data/DESKTOP-4GLHDVM.json', 'utf8'); -var data1 = JSON.parse(data); + //Data for node 4 + var N4 = fs.readFileSync('./data/vmi344960.contaboserver.net.json', 'utf8'); + var Node4 = JSON.parse(N4); -//Routes -app.get("/", (req, res) => { res.render('index', { layout: false, - info: data1 + Node1Data: Node1, + Node2Data: Node2, + Node3Data: Node3, + Node4Data: Node4 }); }); diff --git a/Panel/package.json b/Panel/package.json index 4a8e9b849..00ff043a4 100644 --- a/Panel/package.json +++ b/Panel/package.json @@ -1,5 +1,5 @@ { - "name": "servermonitor", + "name": "servermontior", "version": "1.0.0", "description": "A software that runs a local web server to show system info, E.G: CPU Graph, Memory Graph along with more helpful info. Good for anyone who has multiple servers/computers like me and needs some way to monitor them from a single or multiple computers. ", "main": "index.js", @@ -22,6 +22,7 @@ "ejs": "^3.0.1", "express": "latest", "express-handlebars": "^3.1.0", + "hbs": "^4.1.0", "helmet": "^3.21.2", "http": "latest", "socket.io": "latest" diff --git a/Panel/views/index.hbs b/Panel/views/index.hbs index 7f81ada3f..a15541e0d 100644 --- a/Panel/views/index.hbs +++ b/Panel/views/index.hbs @@ -1,50 +1,115 @@ - -ServerMonitor - - - - {{ info.hostname }} - - - - -
-
-

{{info.servername}} Statistics.

-
-
-
CPU: {{info.cpu}} (Cores: {{info.cpucores}}, Threads: {{info.cputhreads}})
-
-
-
CPU Load: {{info.cpuload}}%
-
-
-
RAM (Used/Total) {{info.memused}} / {{info.memtotal}}
-
-
-
OS Boot Drive (Used/Total): {{info.diskused}} / {{info.disktotal}}
-
-
-
Network: Rx: {{info.netrx}} Tx: {{info.nettx}}
-
-
-
Uptime: {{info.osuptime}}
-
-
+ +DanBot Hosting Stats + + + + + +{{> header}} + +
+
+

Node 1 Stats

+
+
+
CPU: {{Node1Data.cpu}} (Cores: {{Node1Data.cpucores}}, Threads: {{Node1Data.cputhreads}})
+
+
+
CPU Load: {{Node1Data.cpuload}}%
+
+
+
RAM (Used/Total) {{Node1Data.memused}} / {{Node1Data.memtotal}}
+
+
+
Host storage drive (Used/Total): {{Node1Data.diskused}} / {{Node1Data.disktotal}}
+
+
+
Network: Rx: {{Node1Data.netrx}} Tx: {{Node1Data.nettx}}
+
+
+
Uptime: {{Node1Data.osuptime}}
+
+ +
+

Node 2 Stats

+
+
+
CPU: {{Node2Data.cpu}} (Cores: {{Node2Data.cpucores}}, Threads: {{Node2Data.cputhreads}})
+
+
+
CPU Load: {{Node2Data.cpuload}}%
+
+
+
RAM (Used/Total) {{Node2Data.memused}} / {{Node2Data.memtotal}}
+
+
+
Host storage drive (Used/Total): {{Node2Data.diskused}} / {{Node2Data.disktotal}}
+
+
+
Network: Rx: {{Node2Data.netrx}} Tx: {{Node2Data.nettx}}
+
+
+
Uptime: {{Node2Data.osuptime}}
+
+ +
+

Node 3 Stats

+
+
+
CPU: {{Node3Data.cpu}} (Cores: {{Node3Data.cpucores}}, Threads: {{Node3Data.cputhreads}})
+
+
+
CPU Load: {{Node3Data.cpuload}}%
+
+
+
RAM (Used/Total) {{Node3Data.memused}} / {{Node3Data.memtotal}}
+
+
+
Host storage drive (Used/Total): {{Node3Data.diskused}} / {{Node3Data.disktotal}}
+
+
+
Network: Rx: {{Node3Data.netrx}} Tx: {{Node3Data.nettx}}
+
+
+
Uptime: {{Node3Data.osuptime}}
+
+ +
+

Node 4 Stats

+
+
+
CPU: {{Node4Data.cpu}} (Cores: {{Node4Data.cpucores}}, Threads: {{Node4Data.cputhreads}})
+
+
+
CPU Load: {{Node4Data.cpuload}}%
+
+
+
RAM (Used/Total) {{Node4Data.memused}} / {{Node4Data.memtotal}}
+
+
+
Host storage drive (Used/Total): {{Node4Data.diskused}} / {{Node4Data.disktotal}}
+
+
+
Network: Rx: {{Node4Data.netrx}} Tx: {{Node4Data.nettx}}
+
+
+
Uptime: {{Node4Data.osuptime}}
+
+
\ No newline at end of file diff --git a/Panel/views/partials/header.hbs b/Panel/views/partials/header.hbs new file mode 100644 index 000000000..81e58b198 --- /dev/null +++ b/Panel/views/partials/header.hbs @@ -0,0 +1,21 @@ + \ No newline at end of file From c7e850a0020352aceb88d72f0ec258a70504ca33 Mon Sep 17 00:00:00 2001 From: danielpmc Date: Thu, 19 Mar 2020 08:12:11 +0000 Subject: [PATCH 002/255] Delete config.json because its not needed for now. --- Panel/config.json | 17 ----------------- 1 file changed, 17 deletions(-) delete mode 100644 Panel/config.json diff --git a/Panel/config.json b/Panel/config.json deleted file mode 100644 index 946595731..000000000 --- a/Panel/config.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "ListeningPort": 80, - - "Servers": { - "NumberOfServers": 2, - "One": "Server-01", - "Two": "DESKTOP-4GLHDVM", - "Three": " ", - "Four": " ", - "Five": " ", - "Six": " ", - "Seven": " ", - "Eight": " ", - "Nine": " ", - "Ten": " " - } -} \ No newline at end of file From 64c5c7a36fec335f34d7671c047d4bdea0a1b17d Mon Sep 17 00:00:00 2001 From: danielpmc Date: Mon, 30 Mar 2020 12:43:56 +0100 Subject: [PATCH 003/255] Update a ton of files. Much better --- .gitignore | 1 + BetaDaemon/config.json | 6 +- BetaDaemon/index.js | 14 +- Daemon/config.json | 4 - Daemon/index.js | 82 -- Daemon/package-lock.json | 1051 ---------------------- Daemon/package.json | 21 - Panel/bot/discord/commands/monitor.js | 47 + Panel/bot/discord/commands/reload.js | 14 + Panel/bot/discord/commands/stats.js | 37 + Panel/bot/discord/events/ready.js | 5 + Panel/index.js | 119 ++- Panel/package.json | 2 + Panel/views/index.hbs | 46 +- Panel/views/{ServerOne.hbs => node1.hbs} | 20 +- Panel/views/node2.hbs | 50 + Panel/views/node3.hbs | 50 + Panel/views/node4.hbs | 50 + Panel/views/node5.hbs | 50 + Panel/views/partials/header.hbs | 2 - 20 files changed, 480 insertions(+), 1191 deletions(-) delete mode 100644 Daemon/config.json delete mode 100644 Daemon/index.js delete mode 100644 Daemon/package-lock.json delete mode 100644 Daemon/package.json create mode 100644 Panel/bot/discord/commands/monitor.js create mode 100644 Panel/bot/discord/commands/reload.js create mode 100644 Panel/bot/discord/commands/stats.js create mode 100644 Panel/bot/discord/events/ready.js rename Panel/views/{ServerOne.hbs => node1.hbs} (66%) create mode 100644 Panel/views/node2.hbs create mode 100644 Panel/views/node3.hbs create mode 100644 Panel/views/node4.hbs create mode 100644 Panel/views/node5.hbs diff --git a/.gitignore b/.gitignore index 800c73f16..0188802b5 100644 --- a/.gitignore +++ b/.gitignore @@ -3,6 +3,7 @@ Panel/node_modules Panel/package-lock.json Panel/data +Panel/config.json Daemon/node_modules Daemon/package-lock.json diff --git a/BetaDaemon/config.json b/BetaDaemon/config.json index 558849ed3..5c5965d52 100644 --- a/BetaDaemon/config.json +++ b/BetaDaemon/config.json @@ -1,12 +1,12 @@ { - "panelip": "192.168.0.3", - "panelport": "80", + "panelip": "207.180.236.5", + "panelport": "1144", "debug": true, "panelping": true, "panelms": 5000, "Discord": false, - "DiscordWebhook": "HOE", + "DiscordWebhook": "No webhook token", "SystemIPs": [ "192.168.1.175", diff --git a/BetaDaemon/index.js b/BetaDaemon/index.js index 22fdf7a66..67d5b1b6a 100644 --- a/BetaDaemon/index.js +++ b/BetaDaemon/index.js @@ -130,6 +130,7 @@ app.get('/', async function (req, res) { console.log(chalk.red("You enabled docker in the config but your system does not have docker installed. Please disable this!")); process.exit(); } else { + var timestamp = `${moment().format("YYYY-MM-DD HH:mm:ss")}`; request({ uri: "http://" + config.panelip + ":" + config.panelport + "/data?servername=" + os.hostname + //OS hostname for saving data panel sided. "&cpu=" + cpumain + //CPU make and brand. @@ -156,7 +157,8 @@ app.get('/', async function (req, res) { "&dockercontainers=" + docker.containers + //Number of docker containers "&dockercontainersrunning=" + docker.containersRunning + //Number of running docker containers "&dockercontainerspaused=" + docker.containersPaused + //Number of paused docker containers - "&dockercontainersstopped=" + docker.containersStopped, //Number of stopped docker containers + "&dockercontainersstopped=" + docker.containersStopped + //Number of stopped docker containers + "&updatetime= " + timestamp, //Last time the node sent data to the panel method: "GET", timeout: 5000, followRedirect: true, @@ -188,6 +190,7 @@ app.get('/', async function (req, res) { }); } } else { + var timestamp = `${moment().format("YYYY-MM-DD HH:mm:ss")}`; request({ uri: "http://" + config.panelip + ":" + config.panelport + "/data?servername=" + os.hostname + //OS hostname for saving data panel sided. "&cpu=" + cpumain + //CPU make and brand. @@ -210,7 +213,7 @@ app.get('/', async function (req, res) { "&biosversion=" + bios.version + //Bios version (Example: A22.00) "&biosdate=" + bios.releaseDate + //Bios release date (Example: 2018-11-29) "&servermonitorversion=" + Version + //ServerMonitor version (Example: 1.0.1) - "&datatime=" + datatime, //Date and time (Example: 1578594094569) + "&updatetime= " + timestamp, //Last time the node sent data to the panel //Date and time (Example: 1578594094569) method: "GET", timeout: 5000, followRedirect: true, @@ -249,6 +252,7 @@ app.get('/', async function (req, res) { console.log(chalk.red("You enabled docker in the config but your system does not have docker installed. Please disable this!")); process.exit(); } else { + var timestamp = `${moment().format("YYYY-MM-DD HH:mm:ss")}`; request({ uri: "http://" + config.panelip + ":" + config.panelport + "/data?servername=" + os.hostname + //OS hostname for saving data panel sided. "&cpu=" + cpudata.manufacturer + " " + cpudata.brand + //CPU make and brand. @@ -275,7 +279,8 @@ app.get('/', async function (req, res) { "&dockercontainers=" + docker.containers + //Number of docker containers "&dockercontainersrunning=" + docker.containersRunning + //Number of running docker containers "&dockercontainerspaused=" + docker.containersPaused + //Number of paused docker containers - "&dockercontainersstopped=" + docker.containersStopped, //Number of stopped docker containers + "&dockercontainersstopped=" + docker.containersStopped + //Number of stopped docker containers + "&updatetime= " + timestamp, //Last time the node sent data to the panel method: "GET", timeout: 5000, followRedirect: true, @@ -307,6 +312,7 @@ app.get('/', async function (req, res) { }); } } else { + var timestamp = `${moment().format("YYYY-MM-DD HH:mm:ss")}`; request({ uri: "http://" + config.panelip + ":" + config.panelport + "/data?servername=" + os.hostname + //OS hostname for saving data panel sided. "&cpu=" + cpudata.manufacturer + " " + cpudata.brand + //CPU make and brand. @@ -329,7 +335,7 @@ app.get('/', async function (req, res) { "&biosversion=" + bios.version + //Bios version (Example: A22.00) "&biosdate=" + bios.releaseDate + //Bios release date (Example: 2018-11-29) "&servermonitorversion=" + Version + //ServerMonitor version (Example: 1.0.1) - "&datatime=" + datatime, //Date and time (Example: 1578594094569) + "&updatetime= " + timestamp, //Last time the node sent data to the panel method: "GET", timeout: 5000, followRedirect: true, diff --git a/Daemon/config.json b/Daemon/config.json deleted file mode 100644 index 24dfb7d15..000000000 --- a/Daemon/config.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "panelip": "173.249.33.82", - "panelport": "70" -} \ No newline at end of file diff --git a/Daemon/index.js b/Daemon/index.js deleted file mode 100644 index 978fd7c60..000000000 --- a/Daemon/index.js +++ /dev/null @@ -1,82 +0,0 @@ -/* _____ __ __ _ _ - / ____| | \/ | (_)| | - | (___ ___ _ __ __ __ ___ _ __ | \ / | ___ _ __ _ | |_ ___ _ __ - \___ \ / _ \| '__|\ \ / // _ \| '__|| |\/| | / _ \ | '_ \ | || __|/ _ \ | '__| - ____) || __/| | \ V /| __/| | | | | || (_) || | | || || |_| (_) || | - |_____/ \___||_| \_/ \___||_| |_| |_| \___/ |_| |_||_| \__|\___/ |_| - Free Monitoring software made by danielpmc -*/ - -var PORT = 2001; -var app = require('express')(); -var server = require('http').createServer(app); -var request = require("request"); -var si = require('systeminformation'); -var os = require("os"); -var pretty = require('prettysize'); -var ping = require('node-http-ping'); -var package = require("./package.json"); -var config = require("./config.json"); - -server.listen(PORT, function () { - console.log(PORT + " listening..."); - ping('0.0.0.0', 2001) - -}); - -app.get('/', async function (req, res) { - - setInterval(async () => { - //Data using the systeminformation package. - var cpudata = await si.cpu(); - var cpu = os.loadavg(); - var memdata = await si.mem(); - var ramused = pretty(memdata.used); - var ramtotal = pretty(memdata.total); - var diskdata = await si.fsSize(); - var diskused = pretty(diskdata[0].used); - var disktotal = pretty(diskdata[0].size); - var netdata = await si.networkStats(); - var netrx = pretty(netdata[0].rx_bytes); - var nettx = pretty(netdata[0].tx_bytes); - var osdata = await si.osInfo(); - var bios = await si.bios(); - var ipadd = await si.networkInterfaces(); - var ip = ipadd.ip4 - - //OS UPTIME - var uptime = os.uptime(); - var d = Math.floor(uptime / (3600*24)); - var h = Math.floor(uptime % (3600*24) / 3600); - var m = Math.floor(uptime % 3600 / 60); - var s = Math.floor(uptime % 60); - var dDisplay = d > 0 ? d + (d == 1 ? " day, " : " days, ") : ""; - var hDisplay = h > 0 ? h + (h == 1 ? " hour, " : " hours, ") : ""; - var mDisplay = m > 0 ? m + (m == 1 ? " minute, " : " minutes, ") : ""; - var sDisplay = s > 0 ? s + (s == 1 ? " second" : " seconds") : ""; - - //Version - var Version = package.version; - - //Fetch time that data was sent. (Used panel sided to check if server has gone offline) - var datatime = Date.now(); - -console.log(cpudata) - - console.log(cpudata.brand) - //console.log("http://" + config.panelip + ":" + config.panelport + "/data?servername=" + os.hostname + "&cpuman= " + cpudata.manufacturer + "&cpubrand= " + cpudata.brand + "&cpuload= " + Math.ceil(cpu[1] * 100) / 10 + "&cpuspeed=" + cpudata.speed + "GHz" + "&memused=" + ramused + "&memtotal=" + ramtotal + "&diskused=" + diskused + "&disktotal=" + disktotal + "&netrx=" + netrx + "&nettx=" + nettx + "&osplatform=" + osdata.platform + "&oslogofile=" + osdata.logofile + "&osrelease=" + osdata.release + "&osuptime=" + dDisplay + hDisplay + mDisplay + sDisplay + "&biosvendor=" + bios.vendor + "&biosversion=" + bios.version + "&biosdate=" + bios.releaseDate + "&servermonitorversion=" + Version + "&datatime=" + datatime) - request({ - uri: "http://" + config.panelip + ":" + config.panelport + "/data?servername=" + os.hostname + "&cpuman=" + cpudata.manufacturer + "&cpuload=" + Math.ceil(cpu[1] * 100) / 10 + "&cpuspeed=" + cpudata.speed + "GHz" + "&memused=" + ramused + "&memtotal=" + ramtotal + "&diskused=" + diskused + "&disktotal=" + disktotal + "&netrx=" + netrx + "&nettx=" + nettx + "&osplatform=" + osdata.platform + "&oslogofile=" + osdata.logofile + "&osrelease=" + osdata.release + "&osuptime=" + dDisplay + hDisplay + mDisplay + sDisplay + "&biosvendor=" + bios.vendor + "&biosversion=" + bios.version + "&biosdate=" + bios.releaseDate + "&servermonitorversion=" + Version + "&datatime=" + datatime, - method: "GET", - timeout: 10000, - followRedirect: true, - maxRedirects: 10 - }, function (error, response, body) { - res.send(body); - console.log(body) - console.log(response) - console.log(error) - }); -}, 2500); - -}); diff --git a/Daemon/package-lock.json b/Daemon/package-lock.json deleted file mode 100644 index 6d0f67283..000000000 --- a/Daemon/package-lock.json +++ /dev/null @@ -1,1051 +0,0 @@ -{ - "name": "servermonitor-fetch", - "version": "1.0.0", - "lockfileVersion": 1, - "requires": true, - "dependencies": { - "accepts": { - "version": "1.3.7", - "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz", - "integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==", - "requires": { - "mime-types": "~2.1.24", - "negotiator": "0.6.2" - } - }, - "after": { - "version": "0.8.2", - "resolved": "https://registry.npmjs.org/after/-/after-0.8.2.tgz", - "integrity": "sha1-/ts5T58OAqqXaOcCvaI7UF+ufh8=" - }, - "ajv": { - "version": "6.10.2", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.10.2.tgz", - "integrity": "sha512-TXtUUEYHuaTEbLZWIKUr5pmBuhDLy+8KYtPYdcV8qC+pOZL+NKqYwvWSRrVXHn+ZmRRAu8vJTAznH7Oag6RVRw==", - "requires": { - "fast-deep-equal": "^2.0.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - } - }, - "array-flatten": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", - "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" - }, - "arraybuffer.slice": { - "version": "0.0.7", - "resolved": "https://registry.npmjs.org/arraybuffer.slice/-/arraybuffer.slice-0.0.7.tgz", - "integrity": "sha512-wGUIVQXuehL5TCqQun8OW81jGzAWycqzFF8lFp+GOM5BXLYj3bKNsYC4daB7n6XjCqxQA/qgTJ+8ANR3acjrog==" - }, - "asn1": { - "version": "0.2.4", - "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz", - "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==", - "requires": { - "safer-buffer": "~2.1.0" - } - }, - "assert-plus": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", - "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" - }, - "async-limiter": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.1.tgz", - "integrity": "sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==" - }, - "asynckit": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" - }, - "aws-sign2": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", - "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=" - }, - "aws4": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.9.0.tgz", - "integrity": "sha512-Uvq6hVe90D0B2WEnUqtdgY1bATGz3mw33nH9Y+dmA+w5DHvUmBgkr5rM/KCHpCsiFNRUfokW/szpPPgMK2hm4A==" - }, - "backo2": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/backo2/-/backo2-1.0.2.tgz", - "integrity": "sha1-MasayLEpNjRj41s+u2n038+6eUc=" - }, - "base64-arraybuffer": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-0.1.5.tgz", - "integrity": "sha1-c5JncZI7Whl0etZmqlzUv5xunOg=" - }, - "base64id": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/base64id/-/base64id-2.0.0.tgz", - "integrity": "sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog==" - }, - "bcrypt-pbkdf": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", - "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", - "requires": { - "tweetnacl": "^0.14.3" - } - }, - "better-assert": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/better-assert/-/better-assert-1.0.2.tgz", - "integrity": "sha1-QIZrnhueC1W0gYlDEeaPr/rrxSI=", - "requires": { - "callsite": "1.0.0" - } - }, - "blob": { - "version": "0.0.5", - "resolved": "https://registry.npmjs.org/blob/-/blob-0.0.5.tgz", - "integrity": "sha512-gaqbzQPqOoamawKg0LGVd7SzLgXS+JH61oWprSLH+P+abTczqJbhTR8CmJ2u9/bUYNmHTGJx/UEmn6doAvvuig==" - }, - "bluebird": { - "version": "2.11.0", - "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-2.11.0.tgz", - "integrity": "sha1-U0uQM8AiyVecVro7Plpcqvu2UOE=" - }, - "body-parser": { - "version": "1.19.0", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.0.tgz", - "integrity": "sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw==", - "requires": { - "bytes": "3.1.0", - "content-type": "~1.0.4", - "debug": "2.6.9", - "depd": "~1.1.2", - "http-errors": "1.7.2", - "iconv-lite": "0.4.24", - "on-finished": "~2.3.0", - "qs": "6.7.0", - "raw-body": "2.4.0", - "type-is": "~1.6.17" - } - }, - "bytes": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz", - "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==" - }, - "callsite": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/callsite/-/callsite-1.0.0.tgz", - "integrity": "sha1-KAOY5dZkvXQDi28JBRU+borxvCA=" - }, - "caseless": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", - "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=" - }, - "combined-stream": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", - "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", - "requires": { - "delayed-stream": "~1.0.0" - } - }, - "component-bind": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/component-bind/-/component-bind-1.0.0.tgz", - "integrity": "sha1-AMYIq33Nk4l8AAllGx06jh5zu9E=" - }, - "component-emitter": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz", - "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=" - }, - "component-inherit": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/component-inherit/-/component-inherit-0.0.3.tgz", - "integrity": "sha1-ZF/ErfWLcrZJ1crmUTVhnbJv8UM=" - }, - "content-disposition": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.3.tgz", - "integrity": "sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g==", - "requires": { - "safe-buffer": "5.1.2" - } - }, - "content-type": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", - "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==" - }, - "cookie": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.0.tgz", - "integrity": "sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg==" - }, - "cookie-signature": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", - "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=" - }, - "core-util-is": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" - }, - "dashdash": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", - "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", - "requires": { - "assert-plus": "^1.0.0" - } - }, - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "requires": { - "ms": "2.0.0" - } - }, - "delayed-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=" - }, - "depd": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", - "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=" - }, - "destroy": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", - "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=" - }, - "ecc-jsbn": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", - "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=", - "requires": { - "jsbn": "~0.1.0", - "safer-buffer": "^2.1.0" - } - }, - "ee-first": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", - "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" - }, - "encodeurl": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", - "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=" - }, - "engine.io": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-3.4.0.tgz", - "integrity": "sha512-XCyYVWzcHnK5cMz7G4VTu2W7zJS7SM1QkcelghyIk/FmobWBtXE7fwhBusEKvCSqc3bMh8fNFMlUkCKTFRxH2w==", - "requires": { - "accepts": "~1.3.4", - "base64id": "2.0.0", - "cookie": "0.3.1", - "debug": "~4.1.0", - "engine.io-parser": "~2.2.0", - "ws": "^7.1.2" - }, - "dependencies": { - "cookie": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.3.1.tgz", - "integrity": "sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s=" - }, - "debug": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", - "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", - "requires": { - "ms": "^2.1.1" - } - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" - } - } - }, - "engine.io-client": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-3.4.0.tgz", - "integrity": "sha512-a4J5QO2k99CM2a0b12IznnyQndoEvtA4UAldhGzKqnHf42I3Qs2W5SPnDvatZRcMaNZs4IevVicBPayxYt6FwA==", - "requires": { - "component-emitter": "1.2.1", - "component-inherit": "0.0.3", - "debug": "~4.1.0", - "engine.io-parser": "~2.2.0", - "has-cors": "1.1.0", - "indexof": "0.0.1", - "parseqs": "0.0.5", - "parseuri": "0.0.5", - "ws": "~6.1.0", - "xmlhttprequest-ssl": "~1.5.4", - "yeast": "0.1.2" - }, - "dependencies": { - "debug": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", - "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", - "requires": { - "ms": "^2.1.1" - } - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" - }, - "ws": { - "version": "6.1.4", - "resolved": "https://registry.npmjs.org/ws/-/ws-6.1.4.tgz", - "integrity": "sha512-eqZfL+NE/YQc1/ZynhojeV8q+H050oR8AZ2uIev7RU10svA9ZnJUddHcOUZTJLinZ9yEfdA2kSATS2qZK5fhJA==", - "requires": { - "async-limiter": "~1.0.0" - } - } - } - }, - "engine.io-parser": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-2.2.0.tgz", - "integrity": "sha512-6I3qD9iUxotsC5HEMuuGsKA0cXerGz+4uGcXQEkfBidgKf0amsjrrtwcbwK/nzpZBxclXlV7gGl9dgWvu4LF6w==", - "requires": { - "after": "0.8.2", - "arraybuffer.slice": "~0.0.7", - "base64-arraybuffer": "0.1.5", - "blob": "0.0.5", - "has-binary2": "~1.0.2" - } - }, - "escape-html": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", - "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" - }, - "etag": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", - "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=" - }, - "express": { - "version": "4.17.1", - "resolved": "https://registry.npmjs.org/express/-/express-4.17.1.tgz", - "integrity": "sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g==", - "requires": { - "accepts": "~1.3.7", - "array-flatten": "1.1.1", - "body-parser": "1.19.0", - "content-disposition": "0.5.3", - "content-type": "~1.0.4", - "cookie": "0.4.0", - "cookie-signature": "1.0.6", - "debug": "2.6.9", - "depd": "~1.1.2", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "finalhandler": "~1.1.2", - "fresh": "0.5.2", - "merge-descriptors": "1.0.1", - "methods": "~1.1.2", - "on-finished": "~2.3.0", - "parseurl": "~1.3.3", - "path-to-regexp": "0.1.7", - "proxy-addr": "~2.0.5", - "qs": "6.7.0", - "range-parser": "~1.2.1", - "safe-buffer": "5.1.2", - "send": "0.17.1", - "serve-static": "1.14.1", - "setprototypeof": "1.1.1", - "statuses": "~1.5.0", - "type-is": "~1.6.18", - "utils-merge": "1.0.1", - "vary": "~1.1.2" - } - }, - "extend": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", - "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" - }, - "extsprintf": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", - "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=" - }, - "fast-deep-equal": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz", - "integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=" - }, - "fast-json-stable-stringify": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==" - }, - "finalhandler": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", - "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==", - "requires": { - "debug": "2.6.9", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "on-finished": "~2.3.0", - "parseurl": "~1.3.3", - "statuses": "~1.5.0", - "unpipe": "~1.0.0" - } - }, - "forever-agent": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", - "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=" - }, - "form-data": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", - "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", - "requires": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.6", - "mime-types": "^2.1.12" - } - }, - "forwarded": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz", - "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=" - }, - "fresh": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", - "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=" - }, - "getpass": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", - "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", - "requires": { - "assert-plus": "^1.0.0" - } - }, - "har-schema": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", - "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=" - }, - "har-validator": { - "version": "5.1.3", - "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.3.tgz", - "integrity": "sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g==", - "requires": { - "ajv": "^6.5.5", - "har-schema": "^2.0.0" - } - }, - "has-binary2": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has-binary2/-/has-binary2-1.0.3.tgz", - "integrity": "sha512-G1LWKhDSvhGeAQ8mPVQlqNcOB2sJdwATtZKl2pDKKHfpf/rYj24lkinxf69blJbnsvtqqNU+L3SL50vzZhXOnw==", - "requires": { - "isarray": "2.0.1" - } - }, - "has-cors": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/has-cors/-/has-cors-1.1.0.tgz", - "integrity": "sha1-XkdHk/fqmEPRu5nCPu9J/xJv/zk=" - }, - "http": { - "version": "0.0.0", - "resolved": "https://registry.npmjs.org/http/-/http-0.0.0.tgz", - "integrity": "sha1-huYybSnF0Dnen6xYSkVon5KfT3I=" - }, - "http-errors": { - "version": "1.7.2", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz", - "integrity": "sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==", - "requires": { - "depd": "~1.1.2", - "inherits": "2.0.3", - "setprototypeof": "1.1.1", - "statuses": ">= 1.5.0 < 2", - "toidentifier": "1.0.0" - } - }, - "http-signature": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", - "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", - "requires": { - "assert-plus": "^1.0.0", - "jsprim": "^1.2.2", - "sshpk": "^1.7.0" - } - }, - "iconv-lite": { - "version": "0.4.24", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", - "requires": { - "safer-buffer": ">= 2.1.2 < 3" - } - }, - "indexof": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/indexof/-/indexof-0.0.1.tgz", - "integrity": "sha1-gtwzbSMrkGIXnQWrMpOmYFn9Q10=" - }, - "inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" - }, - "ipaddr.js": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.0.tgz", - "integrity": "sha512-M4Sjn6N/+O6/IXSJseKqHoFc+5FdGJ22sXqnjTpdZweHK64MzEPAyQZyEU3R/KRv2GLoa7nNtg/C2Ev6m7z+eA==" - }, - "is-typedarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", - "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=" - }, - "isarray": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.1.tgz", - "integrity": "sha1-o32U7ZzaLVmGXJ92/llu4fM4dB4=" - }, - "isstream": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", - "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=" - }, - "jsbn": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", - "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=" - }, - "json-schema": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", - "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=" - }, - "json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" - }, - "json-stringify-safe": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", - "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=" - }, - "jsprim": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", - "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=", - "requires": { - "assert-plus": "1.0.0", - "extsprintf": "1.3.0", - "json-schema": "0.2.3", - "verror": "1.10.0" - } - }, - "media-typer": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", - "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=" - }, - "merge-descriptors": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", - "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=" - }, - "methods": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", - "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=" - }, - "mime": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", - "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==" - }, - "mime-db": { - "version": "1.42.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.42.0.tgz", - "integrity": "sha512-UbfJCR4UAVRNgMpfImz05smAXK7+c+ZntjaA26ANtkXLlOe947Aag5zdIcKQULAiF9Cq4WxBi9jUs5zkA84bYQ==" - }, - "mime-types": { - "version": "2.1.25", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.25.tgz", - "integrity": "sha512-5KhStqB5xpTAeGqKBAMgwaYMnQik7teQN4IAzC7npDv6kzeU6prfkR67bc87J1kWMPGkoaZSq1npmexMgkmEVg==", - "requires": { - "mime-db": "1.42.0" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" - }, - "negotiator": { - "version": "0.6.2", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz", - "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==" - }, - "node-http-ping": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/node-http-ping/-/node-http-ping-0.3.1.tgz", - "integrity": "sha512-4q295gTtUXhFYp3CRMsmUWAXwHoB0oKEz3czmO9ZueWDcTcS3sX4I8L5zvdiXRrZpCMhb/TBaY9I27Gi7/Pa1Q==", - "requires": { - "bluebird": "^2.9.14" - } - }, - "oauth-sign": { - "version": "0.9.0", - "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", - "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==" - }, - "object-component": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/object-component/-/object-component-0.0.3.tgz", - "integrity": "sha1-8MaapQ78lbhmwYb0AKM3acsvEpE=" - }, - "on-finished": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", - "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", - "requires": { - "ee-first": "1.1.1" - } - }, - "parseqs": { - "version": "0.0.5", - "resolved": "https://registry.npmjs.org/parseqs/-/parseqs-0.0.5.tgz", - "integrity": "sha1-1SCKNzjkZ2bikbouoXNoSSGouJ0=", - "requires": { - "better-assert": "~1.0.0" - } - }, - "parseuri": { - "version": "0.0.5", - "resolved": "https://registry.npmjs.org/parseuri/-/parseuri-0.0.5.tgz", - "integrity": "sha1-gCBKUNTbt3m/3G6+J3jZDkvOMgo=", - "requires": { - "better-assert": "~1.0.0" - } - }, - "parseurl": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", - "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==" - }, - "path-to-regexp": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", - "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" - }, - "performance-now": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", - "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=" - }, - "prettysize": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/prettysize/-/prettysize-2.0.0.tgz", - "integrity": "sha512-VVtxR7sOh0VsG8o06Ttq5TrI1aiZKmC+ClSn4eBPaNf4SHr5lzbYW+kYGX3HocBL/MfpVrRfFZ9V3vCbLaiplg==" - }, - "proxy-addr": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.5.tgz", - "integrity": "sha512-t/7RxHXPH6cJtP0pRG6smSr9QJidhB+3kXu0KgXnbGYMgzEnUxRQ4/LDdfOwZEMyIh3/xHb8PX3t+lfL9z+YVQ==", - "requires": { - "forwarded": "~0.1.2", - "ipaddr.js": "1.9.0" - } - }, - "psl": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/psl/-/psl-1.6.0.tgz", - "integrity": "sha512-SYKKmVel98NCOYXpkwUqZqh0ahZeeKfmisiLIcEZdsb+WbLv02g/dI5BUmZnIyOe7RzZtLax81nnb2HbvC2tzA==" - }, - "punycode": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", - "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==" - }, - "qs": { - "version": "6.7.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz", - "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==" - }, - "range-parser": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", - "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==" - }, - "raw-body": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.0.tgz", - "integrity": "sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q==", - "requires": { - "bytes": "3.1.0", - "http-errors": "1.7.2", - "iconv-lite": "0.4.24", - "unpipe": "1.0.0" - } - }, - "request": { - "version": "2.88.0", - "resolved": "https://registry.npmjs.org/request/-/request-2.88.0.tgz", - "integrity": "sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg==", - "requires": { - "aws-sign2": "~0.7.0", - "aws4": "^1.8.0", - "caseless": "~0.12.0", - "combined-stream": "~1.0.6", - "extend": "~3.0.2", - "forever-agent": "~0.6.1", - "form-data": "~2.3.2", - "har-validator": "~5.1.0", - "http-signature": "~1.2.0", - "is-typedarray": "~1.0.0", - "isstream": "~0.1.2", - "json-stringify-safe": "~5.0.1", - "mime-types": "~2.1.19", - "oauth-sign": "~0.9.0", - "performance-now": "^2.1.0", - "qs": "~6.5.2", - "safe-buffer": "^5.1.2", - "tough-cookie": "~2.4.3", - "tunnel-agent": "^0.6.0", - "uuid": "^3.3.2" - }, - "dependencies": { - "qs": { - "version": "6.5.2", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", - "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==" - } - } - }, - "safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" - }, - "safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" - }, - "send": { - "version": "0.17.1", - "resolved": "https://registry.npmjs.org/send/-/send-0.17.1.tgz", - "integrity": "sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg==", - "requires": { - "debug": "2.6.9", - "depd": "~1.1.2", - "destroy": "~1.0.4", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "fresh": "0.5.2", - "http-errors": "~1.7.2", - "mime": "1.6.0", - "ms": "2.1.1", - "on-finished": "~2.3.0", - "range-parser": "~1.2.1", - "statuses": "~1.5.0" - }, - "dependencies": { - "ms": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", - "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==" - } - } - }, - "serve-static": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.1.tgz", - "integrity": "sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg==", - "requires": { - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "parseurl": "~1.3.3", - "send": "0.17.1" - } - }, - "setprototypeof": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz", - "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==" - }, - "socket.io": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-2.3.0.tgz", - "integrity": "sha512-2A892lrj0GcgR/9Qk81EaY2gYhCBxurV0PfmmESO6p27QPrUK1J3zdns+5QPqvUYK2q657nSj0guoIil9+7eFg==", - "requires": { - "debug": "~4.1.0", - "engine.io": "~3.4.0", - "has-binary2": "~1.0.2", - "socket.io-adapter": "~1.1.0", - "socket.io-client": "2.3.0", - "socket.io-parser": "~3.4.0" - }, - "dependencies": { - "debug": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", - "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", - "requires": { - "ms": "^2.1.1" - } - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" - } - } - }, - "socket.io-adapter": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-1.1.2.tgz", - "integrity": "sha512-WzZRUj1kUjrTIrUKpZLEzFZ1OLj5FwLlAFQs9kuZJzJi5DKdU7FsWc36SNmA8iDOtwBQyT8FkrriRM8vXLYz8g==" - }, - "socket.io-client": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-2.3.0.tgz", - "integrity": "sha512-cEQQf24gET3rfhxZ2jJ5xzAOo/xhZwK+mOqtGRg5IowZsMgwvHwnf/mCRapAAkadhM26y+iydgwsXGObBB5ZdA==", - "requires": { - "backo2": "1.0.2", - "base64-arraybuffer": "0.1.5", - "component-bind": "1.0.0", - "component-emitter": "1.2.1", - "debug": "~4.1.0", - "engine.io-client": "~3.4.0", - "has-binary2": "~1.0.2", - "has-cors": "1.1.0", - "indexof": "0.0.1", - "object-component": "0.0.3", - "parseqs": "0.0.5", - "parseuri": "0.0.5", - "socket.io-parser": "~3.3.0", - "to-array": "0.1.4" - }, - "dependencies": { - "debug": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", - "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", - "requires": { - "ms": "^2.1.1" - } - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" - }, - "socket.io-parser": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-3.3.0.tgz", - "integrity": "sha512-hczmV6bDgdaEbVqhAeVMM/jfUfzuEZHsQg6eOmLgJht6G3mPKMxYm75w2+qhAQZ+4X+1+ATZ+QFKeOZD5riHng==", - "requires": { - "component-emitter": "1.2.1", - "debug": "~3.1.0", - "isarray": "2.0.1" - }, - "dependencies": { - "debug": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", - "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", - "requires": { - "ms": "2.0.0" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" - } - } - } - } - }, - "socket.io-parser": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-3.4.0.tgz", - "integrity": "sha512-/G/VOI+3DBp0+DJKW4KesGnQkQPFmUCbA/oO2QGT6CWxU7hLGWqU3tyuzeSK/dqcyeHsQg1vTe9jiZI8GU9SCQ==", - "requires": { - "component-emitter": "1.2.1", - "debug": "~4.1.0", - "isarray": "2.0.1" - }, - "dependencies": { - "debug": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", - "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", - "requires": { - "ms": "^2.1.1" - } - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" - } - } - }, - "sshpk": { - "version": "1.16.1", - "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz", - "integrity": "sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==", - "requires": { - "asn1": "~0.2.3", - "assert-plus": "^1.0.0", - "bcrypt-pbkdf": "^1.0.0", - "dashdash": "^1.12.0", - "ecc-jsbn": "~0.1.1", - "getpass": "^0.1.1", - "jsbn": "~0.1.0", - "safer-buffer": "^2.0.2", - "tweetnacl": "~0.14.0" - } - }, - "statuses": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", - "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=" - }, - "systeminformation": { - "version": "4.16.0", - "resolved": "https://registry.npmjs.org/systeminformation/-/systeminformation-4.16.0.tgz", - "integrity": "sha512-1FjxPJSw7ad0zug+1YIQATj6Cn+wM5OBASEpjohEeOD2EGPIf0Cnhthd1L2O1YX+wKgOMuPldGfxYdo8yNHEIg==" - }, - "to-array": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/to-array/-/to-array-0.1.4.tgz", - "integrity": "sha1-F+bBH3PdTz10zaek/zI46a2b+JA=" - }, - "toidentifier": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz", - "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==" - }, - "tough-cookie": { - "version": "2.4.3", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.4.3.tgz", - "integrity": "sha512-Q5srk/4vDM54WJsJio3XNn6K2sCG+CQ8G5Wz6bZhRZoAe/+TxjWB/GlFAnYEbkYVlON9FMk/fE3h2RLpPXo4lQ==", - "requires": { - "psl": "^1.1.24", - "punycode": "^1.4.1" - }, - "dependencies": { - "punycode": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", - "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=" - } - } - }, - "tunnel-agent": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", - "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", - "requires": { - "safe-buffer": "^5.0.1" - } - }, - "tweetnacl": { - "version": "0.14.5", - "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", - "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=" - }, - "type-is": { - "version": "1.6.18", - "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", - "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", - "requires": { - "media-typer": "0.3.0", - "mime-types": "~2.1.24" - } - }, - "unpipe": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", - "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=" - }, - "uri-js": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz", - "integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==", - "requires": { - "punycode": "^2.1.0" - } - }, - "utils-merge": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", - "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=" - }, - "uuid": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.3.tgz", - "integrity": "sha512-pW0No1RGHgzlpHJO1nsVrHKpOEIxkGg1xB+v0ZmdNH5OAeAwzAVrCnI2/6Mtx+Uys6iaylxa+D3g4j63IKKjSQ==" - }, - "vary": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", - "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=" - }, - "verror": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", - "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", - "requires": { - "assert-plus": "^1.0.0", - "core-util-is": "1.0.2", - "extsprintf": "^1.2.0" - } - }, - "ws": { - "version": "7.2.1", - "resolved": "https://registry.npmjs.org/ws/-/ws-7.2.1.tgz", - "integrity": "sha512-sucePNSafamSKoOqoNfBd8V0StlkzJKL2ZAhGQinCfNQ+oacw+Pk7lcdAElecBF2VkLNZRiIb5Oi1Q5lVUVt2A==" - }, - "xmlhttprequest-ssl": { - "version": "1.5.5", - "resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.5.5.tgz", - "integrity": "sha1-wodrBhaKrcQOV9l+gRkayPQ5iz4=" - }, - "yeast": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/yeast/-/yeast-0.1.2.tgz", - "integrity": "sha1-AI4G2AlDIMNy28L47XagymyKxBk=" - } - } -} diff --git a/Daemon/package.json b/Daemon/package.json deleted file mode 100644 index 6d491a591..000000000 --- a/Daemon/package.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "name": "servermonitor-fetch", - "version": "1.0.0", - "description": "A program that runs in system background to fetch data for the main ServerMonitor program.", - "main": "index.js", - "scripts": { - "test": "echo \"Error: no test specified\" && exit 1" - }, - "author": "danielpmc", - "license": "MIT", - "dependencies": { - "body-parser": "latest", - "express": "latest", - "http": "latest", - "node-http-ping": "^0.3.1", - "prettysize": "^2.0.0", - "request": "^2.88.0", - "socket.io": "latest", - "systeminformation": "^4.16.0" - } -} diff --git a/Panel/bot/discord/commands/monitor.js b/Panel/bot/discord/commands/monitor.js new file mode 100644 index 000000000..82b8e55ec --- /dev/null +++ b/Panel/bot/discord/commands/monitor.js @@ -0,0 +1,47 @@ +exports.run = (client, message, args) => { + if (message.author.id !== config.DiscordBot.ownerID) return message.channel.send("Sorry, No permission :O"); + try { + + //Alerts me that the Node Monitor is now running. (Please Please Please. If you run this bot only run this once or you might get spam and banned from discord) + message.channel.send('Monitor is now running and watching all nodes for `DanBot Hosting`. Any issues will be updated and sent in <#640158471001735169>') + + //Node Monitor + setInterval(() => { + //Data for node 1 + var N1 = fs.readFileSync('./data/0286b2ad-dc80-4b5c-a0de-b81945b010e8.json', 'utf8'); + var Node1 = JSON.parse(N1); + + //Data for node 2 + var N2 = fs.readFileSync('./data/2e3f071a-af2b-4dc9-be5a-7ce72590a181.json', 'utf8'); + var Node2 = JSON.parse(N2); + + //Data for node 3 + var N3 = fs.readFileSync('./data/6fc3e9bf-24a8-47cd-99d3-fa159e05a9f4.json', 'utf8'); + var Node3 = JSON.parse(N3); + + //Data for node 4 + var N4 = fs.readFileSync('./data/15ffcdd0-a021-4ded-977d-284d777330a0.json', 'utf8'); + var Node4 = JSON.parse(N4); + + //Runs if statements for each node. this checks each node's ram + if (Node1.memused >= "7.5 GB") { + return client.channels.get("640158471001735169").send("⚠️ `Node 1` is currently running with " + Node1.memused + " out of " + Node1.memtotal + ". Will continue to monitor this node!"), client.channels.get("640158471001735169").setTopic('⚠️Monitoring: Node 1 running with ' + Node1.memused + " out of " + Node1.memtotal) + }; + + client.guilds.get("639477525927690240").channels.get("640158471001735169").fetchMessage("693937194863427655") + .then(msgb => { + console.log(msgb.content) + msgb.edit("testing") + }) + // Node1msg.edit('testing') + + //if (Node1.memused >= "7.5 GB") return client.channels.get("640158471001735169").send("⚠️ `Node 1` is currently running with " + Node1.memused + " out of " + Node1.memtotal + ". Will continue to monitor this node!"), client.channels.get("640158471001735169").setTopic('⚠️Monitoring: Node 1 running with ' + Node1.memused + " out of " + Node1.memtotal) + //if (Node2.memused >= "7.5 GB") return client.channels.get("640158471001735169").send("⚠️ `Node 2` is currently running with " + Node2.memused + " out of " + Node2.memtotal + ". Will continue to monitor this node!"), client.channels.get("640158471001735169").setTopic('⚠️Monitoring: Node 2 running with ' + Node2.memused + " out of " + Node2.memtotal) + //if (Node3.memused >= "7.5 GB") return client.channels.get("640158471001735169").send("⚠️ `Node 3` is currently running with " + Node3.memused + " out of " + Node3.memtotal + ". Will continue to monitor this node!"), client.channels.get("640158471001735169").setTopic('⚠️Monitoring: Node 3 running with ' + Node3.memused + " out of " + Node3.memtotal) + //if (Node4.memused >= "7.5 GB") return client.channels.get("640158471001735169").send("⚠️ `Node 4` is currently running with " + Node4.memused + " out of " + Node4.memtotal + ". Will continue to monitor this node!"), client.channels.get("640158471001735169").setTopic('⚠️Monitoring: Node 4 running with ' + Node4.memused + " out of " + Node4.memtotal) + }, 5000); + +} catch (err) { + return console.log(err) + } +}; \ No newline at end of file diff --git a/Panel/bot/discord/commands/reload.js b/Panel/bot/discord/commands/reload.js new file mode 100644 index 000000000..fc2ad7e7e --- /dev/null +++ b/Panel/bot/discord/commands/reload.js @@ -0,0 +1,14 @@ +exports.run = (client, message, args) => { + if (message.author.id !== config.DiscordBot.ownerID) return message.channel.send("Sorry, No permission :O"); + try { + fs.readdir("./bot/discord/commands/", (err, files) => { + if (err) return console.error(err); + message.channel.send(`Refreshed \`${files.length}\` commands successfully!`) + files.forEach(file => { + delete require.cache[require.resolve(`./${file}`)]; + }); + }); +} catch (err) { + return; + } +}; \ No newline at end of file diff --git a/Panel/bot/discord/commands/stats.js b/Panel/bot/discord/commands/stats.js new file mode 100644 index 000000000..419c2c6c7 --- /dev/null +++ b/Panel/bot/discord/commands/stats.js @@ -0,0 +1,37 @@ +exports.run = async(client, message) => { + + //Sends message while the json's are being cached + let embed = new Discord.RichEmbed() + .setColor(`RANDOM`) + .addField(`__**Please wait...**__`, `Loading all node's stats!`, true); + let msg = await message.channel.send(embed) + + //Reads the saved jsons for each node + //Data for node 1 + var N1 = fs.readFileSync('./data/0286b2ad-dc80-4b5c-a0de-b81945b010e8.json', 'utf8'); + var Node1Data = JSON.parse(N1); + + //Data for node 2 + var N2 = fs.readFileSync('./data/2e3f071a-af2b-4dc9-be5a-7ce72590a181.json', 'utf8'); + var Node2Data = JSON.parse(N2); + + //Data for node 3 + var N3 = fs.readFileSync('./data/6fc3e9bf-24a8-47cd-99d3-fa159e05a9f4.json', 'utf8'); + var Node3Data = JSON.parse(N3); + + //Data for node 4 + var N4 = fs.readFileSync('./data/15ffcdd0-a021-4ded-977d-284d777330a0.json', 'utf8'); + var Node4Data = JSON.parse(N4); + + //Edits the message to display the data + embed.fields.pop() + embed.addField("\u200b", "__**[Node 1](https://stats.danbot.xyz/Node1)**__ \n**CPU LOAD**: " + Node1Data.cpuload + "% \n**RAM (USED/TOTAL)**: " + Node1Data.memused + " / " + Node1Data.memtotal + " \n**STORAGE (USED/TOTAL)**: " + Node1Data.diskused + " / " + Node1Data.disktotal + " \n**UPTIME**: " + Node1Data.osuptime) + embed.addField('\u200b', '\u200b') + embed.addField("\u200b", "__**[Node 2](https://stats.danbot.xyz/Node2)**__ \n**CPU LOAD**: " + Node2Data.cpuload + "% \n**RAM (USED/TOTAL)**: " + Node2Data.memused + " / " + Node2Data.memtotal + " \n**STORAGE (USED/TOTAL)**: " + Node2Data.diskused + " / " + Node2Data.disktotal + " \n**UPTIME**: " + Node2Data.osuptime) + embed.addField('\u200b', '\u200b') + embed.addField("\u200b", "__**[Node 3](https://stats.danbot.xyz/Node3)**__ \n**CPU LOAD**: " + Node3Data.cpuload + "% \n**RAM (USED/TOTAL)**: " + Node3Data.memused + " / " + Node3Data.memtotal + " \n**STORAGE (USED/TOTAL)**: " + Node3Data.diskused + " / " + Node3Data.disktotal + " \n**UPTIME**: " + Node3Data.osuptime) + embed.addField('\u200b', '\u200b') + embed.addField("\u200b", "__**[Node 4](https://stats.danbot.xyz/Node4)**__ \n**CPU LOAD**: " + Node4Data.cpuload + "% \n**RAM (USED/TOTAL)**: " + Node4Data.memused + " / " + Node4Data.memtotal + " \n**STORAGE (USED/TOTAL)**: " + Node4Data.diskused + " / " + Node4Data.disktotal + " \n**UPTIME**: " + Node4Data.osuptime) + embed.setDescription('Want to view more stats live? [Click Here!](https://stats.danbot.xyz/)') + msg.edit(embed); +}; \ No newline at end of file diff --git a/Panel/bot/discord/events/ready.js b/Panel/bot/discord/events/ready.js new file mode 100644 index 000000000..c0d8bb92b --- /dev/null +++ b/Panel/bot/discord/events/ready.js @@ -0,0 +1,5 @@ +module.exports = (client, guild, files) => { + const timestamp = `${moment().format("YYYY-MM-DD HH:mm:ss")}`; + console.log(chalk.yellow("[" + timestamp + "] Discord bot logged in!")); + client.user.setActivity("over DanBot Hosting", { type: "WATCHING" }); +}; \ No newline at end of file diff --git a/Panel/index.js b/Panel/index.js index 33d270f5e..4ca37463b 100644 --- a/Panel/index.js +++ b/Panel/index.js @@ -7,15 +7,15 @@ Free Monitoring software made by danielpmc */ -//var config = require("./config.json"); -var PORT = "1144"; +global.config = require("./config.json"); +var PORT = config.Port; var express = require('express'); var app = express(); var server = require('http').createServer(app); var bodyParser = require('body-parser'); -var fs = require("fs"); -var chalk = require('chalk'); +global.fs = require("fs"); const hbs = require('hbs'); +global.chalk = require('chalk'); app.use(bodyParser.json()); app.use(bodyParser.urlencoded({extended: true})); @@ -25,10 +25,51 @@ server.listen(PORT, function () { }); + +//Discord bot +global.Discord = require("discord.js"); +const client = new Discord.Client() +global.fs = require("fs"); +global.moment = require("moment"); + +//Event handler +fs.readdir('./bot/discord/events/', (err, files) => { + files = files.filter(f => f.endsWith('.js')); + files.forEach(f => { + const event = require(`./bot/discord/events/${f}`); + client.on(f.split('.')[0], event.bind(null, client)); + delete require.cache[require.resolve(`./bot/discord/events/${f}`)]; + }); + }); + +//Command handler +client.on('message', message => { + + const prefix = config.DiscordBot.Prefix; + if (message.content.indexOf(prefix) !== 0) return; + const args = message.content.slice(prefix.length).trim().split(/ +/g); + const commandargs = message.content.split(' ').slice(1).join(' '); + const command = args.shift().toLowerCase(); + console.log(`[${message.author.username}] [${message.author.id}] >> ${prefix}${command} ${commandargs}`); + try { + let commandFile = require(`./bot/discord/commands/${command}.js`); + commandFile.run(client, message, args); + } catch (err) { + if (err instanceof Error && err.code === "MODULE_NOT_FOUND") { + return console.log(err) + } + } +}) + +//Bot login +client.login(config.DiscordBot.Token); + + + app.get('/data', function (req, res) { //console.log(req.query); - //Write data to JSON file after checking servername. + //Write data to JSON file after checking the servers Hostname. var data = JSON.stringify(req.query); fs.writeFileSync('data/' + req.query.servername + '.json', data); @@ -42,29 +83,89 @@ app.set('view engine', 'hbs'); app.get("/", (req, res) => { //Data for node 1 - var N1 = fs.readFileSync('./data/vmi347338.contaboserver.net.json', 'utf8'); + var N1 = fs.readFileSync('./data/0286b2ad-dc80-4b5c-a0de-b81945b010e8.json', 'utf8'); var Node1 = JSON.parse(N1); //Data for node 2 - var N2 = fs.readFileSync('./data/vmi347340.contaboserver.net.json', 'utf8'); + var N2 = fs.readFileSync('./data/2e3f071a-af2b-4dc9-be5a-7ce72590a181.json', 'utf8'); var Node2 = JSON.parse(N2); //Data for node 3 - var N3 = fs.readFileSync('./data/vmi347402.contaboserver.net.json', 'utf8'); + var N3 = fs.readFileSync('./data/6fc3e9bf-24a8-47cd-99d3-fa159e05a9f4.json', 'utf8'); var Node3 = JSON.parse(N3); //Data for node 4 - var N4 = fs.readFileSync('./data/vmi344960.contaboserver.net.json', 'utf8'); + var N4 = fs.readFileSync('./data/15ffcdd0-a021-4ded-977d-284d777330a0.json', 'utf8'); var Node4 = JSON.parse(N4); + //Data for node 5 (Private) + var N5 = fs.readFileSync('./data/Server-01.json', 'utf8'); + var Node5 = JSON.parse(N5); + res.render('index', { layout: false, Node1Data: Node1, Node2Data: Node2, Node3Data: Node3, + Node4Data: Node4, + Node5Data: Node5 +}); +}); + +app.get("/Node1", (req, res) => { + + //Data for node 1 + var N1 = fs.readFileSync('./data/0286b2ad-dc80-4b5c-a0de-b81945b010e8.json', 'utf8'); + var Node1 = JSON.parse(N1); + + res.render('node1', { layout: false, + Node1Data: Node1 +}); +}); + +app.get("/Node2", (req, res) => { + + //Data for node 2 + var N2 = fs.readFileSync('./data/2e3f071a-af2b-4dc9-be5a-7ce72590a181.json', 'utf8'); + var Node2 = JSON.parse(N2); + + res.render('node2', { layout: false, + Node2Data: Node2 +}); +}); + +app.get("/Node3", (req, res) => { + + //Data for node 3 + var N3 = fs.readFileSync('./data/6fc3e9bf-24a8-47cd-99d3-fa159e05a9f4.json', 'utf8'); + var Node3 = JSON.parse(N3); + + res.render('node3', { layout: false, + Node3Data: Node3 +}); +}); + +app.get("/Node4", (req, res) => { + + //Data for node 4 + var N4 = fs.readFileSync('./data/15ffcdd0-a021-4ded-977d-284d777330a0.json', 'utf8'); + var Node4 = JSON.parse(N4); + + res.render('node4', { layout: false, Node4Data: Node4 }); }); +app.get("/Node5", (req, res) => { + + //Data for node 5 + var N5 = fs.readFileSync('./data/Server-01.json', 'utf8'); + var Node5 = JSON.parse(N5); + + res.render('node5', { layout: false, + Node5Data: Node5 +}); +}); + //Catch 404 and forward to error handler app.use(function(req, res, next) { var err = new Error('Not Found'); diff --git a/Panel/package.json b/Panel/package.json index 00ff043a4..38e39f987 100644 --- a/Panel/package.json +++ b/Panel/package.json @@ -19,12 +19,14 @@ "dependencies": { "body-parser": "latest", "chalk": "^3.0.0", + "discord.js": "^11.6.3", "ejs": "^3.0.1", "express": "latest", "express-handlebars": "^3.1.0", "hbs": "^4.1.0", "helmet": "^3.21.2", "http": "latest", + "moment": "^2.24.0", "socket.io": "latest" } } diff --git a/Panel/views/index.hbs b/Panel/views/index.hbs index a15541e0d..82a090bc8 100644 --- a/Panel/views/index.hbs +++ b/Panel/views/index.hbs @@ -21,11 +21,10 @@ } -{{> header}}
-

Node 1 Stats

+

Node 1 Stats

CPU: {{Node1Data.cpu}} (Cores: {{Node1Data.cpucores}}, Threads: {{Node1Data.cputhreads}})
@@ -45,9 +44,12 @@
Uptime: {{Node1Data.osuptime}}
+
+
Last Updated: {{Node1Data.updatetime}}
+
-

Node 2 Stats

+

Node 2 Stats

CPU: {{Node2Data.cpu}} (Cores: {{Node2Data.cpucores}}, Threads: {{Node2Data.cputhreads}})
@@ -67,9 +69,12 @@
Uptime: {{Node2Data.osuptime}}
+
+
Last Updated: {{Node2Data.updatetime}}
+
-

Node 3 Stats

+

Node 3 Stats

CPU: {{Node3Data.cpu}} (Cores: {{Node3Data.cpucores}}, Threads: {{Node3Data.cputhreads}})
@@ -89,9 +94,12 @@
Uptime: {{Node3Data.osuptime}}
+
+
Last Updated: {{Node3Data.updatetime}}
+
-

Node 4 Stats

+

Node 4 Stats

CPU: {{Node4Data.cpu}} (Cores: {{Node4Data.cpucores}}, Threads: {{Node4Data.cputhreads}})
@@ -111,5 +119,33 @@
Uptime: {{Node4Data.osuptime}}
+
+
Last Updated: {{Node4Data.updatetime}}
+
+ + +
+
CPU: {{Node5Data.cpu}} (Cores: {{Node5Data.cpucores}}, Threads: {{Node5Data.cputhreads}})
+
+
+
CPU Load: {{Node5Data.cpuload}}%
+
+
+
RAM (Used/Total) {{Node5Data.memused}} / {{Node5Data.memtotal}}
+
+
+
Host storage drive (Used/Total): {{Node5Data.diskused}} / {{Node5Data.disktotal}}
+
+
+
Network: Rx: {{Node5Data.netrx}} Tx: {{Node5Data.nettx}}
+
+
+
Uptime: {{Node5Data.osuptime}}
+
+
+
Last Updated: {{Node5Data.updatetime}}
+
\ No newline at end of file diff --git a/Panel/views/ServerOne.hbs b/Panel/views/node1.hbs similarity index 66% rename from Panel/views/ServerOne.hbs rename to Panel/views/node1.hbs index b4656ae82..f28118eb6 100644 --- a/Panel/views/ServerOne.hbs +++ b/Panel/views/node1.hbs @@ -1,9 +1,8 @@ -ServerMonitor - {{Data.hostname}} +Node 1 - DanBot Hosting Stats - {{ Data.hostname }} -
+ All host stats
-

{{Data.servername}} Statistics.

+

Node 1 Stats

-
CPU: {{Data.cpu}} (Cores: {{Data.cpucores}}, Threads: {{Data.cputhreads}})
+
CPU: {{Node1Data.cpu}} (Cores: {{Node1Data.cpucores}}, Threads: {{Node1Data.cputhreads}})
-
CPU Load: {{Data.cpuload}}%
+
CPU Load: {{Node1Data.cpuload}}%
-
RAM (Used/Total) {{Data.memused}} / {{Data.memtotal}}
+
RAM (Used/Total) {{Node1Data.memused}} / {{Node1Data.memtotal}}
-
OS Boot Drive (Used/Total): {{Data.diskused}} / {{Data.disktotal}}
+
Host storage drive (Used/Total): {{Node1Data.diskused}} / {{Node1Data.disktotal}}
-
Network: Rx: {{Data.netrx}} Tx: {{Data.nettx}}
+
Network: Rx: {{Node1Data.netrx}} Tx: {{Node1Data.nettx}}
-
Uptime: {{Data.osuptime}}
+
Uptime: {{Node1Data.osuptime}}
+
\ No newline at end of file diff --git a/Panel/views/node2.hbs b/Panel/views/node2.hbs new file mode 100644 index 000000000..a2b85bee7 --- /dev/null +++ b/Panel/views/node2.hbs @@ -0,0 +1,50 @@ + +Node 2 - DanBot Hosting Stats + + + + + + +
+ All host stats +
+

Node 2 Stats

+
+
+
CPU: {{Node2Data.cpu}} (Cores: {{Node2Data.cpucores}}, Threads: {{Node2Data.cputhreads}})
+
+
+
CPU Load: {{Node2Data.cpuload}}%
+
+
+
RAM (Used/Total) {{Node2Data.memused}} / {{Node2Data.memtotal}}
+
+
+
Host storage drive (Used/Total): {{Node2Data.diskused}} / {{Node2Data.disktotal}}
+
+
+
Network: Rx: {{Node2Data.netrx}} Tx: {{Node2Data.nettx}}
+
+
+
Uptime: {{Node2Data.osuptime}}
+
+ +
+ \ No newline at end of file diff --git a/Panel/views/node3.hbs b/Panel/views/node3.hbs new file mode 100644 index 000000000..d974d2c1b --- /dev/null +++ b/Panel/views/node3.hbs @@ -0,0 +1,50 @@ + +Node 3 - DanBot Hosting Stats + + + + + + +
+ All host stats +
+

Node 3 Stats

+
+
+
CPU: {{Node3Data.cpu}} (Cores: {{Node3Data.cpucores}}, Threads: {{Node3Data.cputhreads}})
+
+
+
CPU Load: {{Node3Data.cpuload}}%
+
+
+
RAM (Used/Total) {{Node3Data.memused}} / {{Node3Data.memtotal}}
+
+
+
Host storage drive (Used/Total): {{Node3Data.diskused}} / {{Node3Data.disktotal}}
+
+
+
Network: Rx: {{Node3Data.netrx}} Tx: {{Node3Data.nettx}}
+
+
+
Uptime: {{Node3Data.osuptime}}
+
+ +
+ \ No newline at end of file diff --git a/Panel/views/node4.hbs b/Panel/views/node4.hbs new file mode 100644 index 000000000..bea8c90b4 --- /dev/null +++ b/Panel/views/node4.hbs @@ -0,0 +1,50 @@ + +Node 4 - DanBot Hosting Stats + + + + + + +
+ All host stats +
+

Node 4 Stats

+
+
+
CPU: {{Node4Data.cpu}} (Cores: {{Node4Data.cpucores}}, Threads: {{Node4Data.cputhreads}})
+
+
+
CPU Load: {{Node4Data.cpuload}}%
+
+
+
RAM (Used/Total) {{Node4Data.memused}} / {{Node4Data.memtotal}}
+
+
+
Host storage drive (Used/Total): {{Node4Data.diskused}} / {{Node4Data.disktotal}}
+
+
+
Network: Rx: {{Node4Data.netrx}} Tx: {{Node4Data.nettx}}
+
+
+
Uptime: {{Node4Data.osuptime}}
+
+ +
+ \ No newline at end of file diff --git a/Panel/views/node5.hbs b/Panel/views/node5.hbs new file mode 100644 index 000000000..191d8138b --- /dev/null +++ b/Panel/views/node5.hbs @@ -0,0 +1,50 @@ + +Node 5 (Private) - DanBot Hosting Stats + + + + + + +
+ All host stats +
+

Node 5 Stats (Private)

+
+
+
CPU: {{Node5Data.cpu}} (Cores: {{Node5Data.cpucores}}, Threads: {{Node5Data.cputhreads}})
+
+
+
CPU Load: {{Node5Data.cpuload}}%
+
+
+
RAM (Used/Total) {{Node5Data.memused}} / {{Node5Data.memtotal}}
+
+
+
Host storage drive (Used/Total): {{Node5Data.diskused}} / {{Node5Data.disktotal}}
+
+
+
Network: Rx: {{Node5Data.netrx}} Tx: {{Node5Data.nettx}}
+
+
+
Uptime: {{Node5Data.osuptime}}
+
+ +
+ \ No newline at end of file diff --git a/Panel/views/partials/header.hbs b/Panel/views/partials/header.hbs index 81e58b198..55d612d73 100644 --- a/Panel/views/partials/header.hbs +++ b/Panel/views/partials/header.hbs @@ -7,8 +7,6 @@
{{#unless user }} - Login - Signup {{else}} From b5928ce6116579c8d88d5881c87a727735a5876d Mon Sep 17 00:00:00 2001 From: danielpmc Date: Wed, 22 Apr 2020 15:27:33 +0100 Subject: [PATCH 004/255] Few updates to the code. --- Panel/bot/discord/commands/getstarted.js | 209 +++++++++++++++++++++++ Panel/bot/discord/commands/tickets.js | 13 ++ Panel/bot/discord/commands/uptime.js | 52 ++++++ Panel/bot/discord/index.js | 37 ++++ Panel/index.js | 28 +-- Panel/package.json | 4 +- 6 files changed, 331 insertions(+), 12 deletions(-) create mode 100644 Panel/bot/discord/commands/getstarted.js create mode 100644 Panel/bot/discord/commands/tickets.js create mode 100644 Panel/bot/discord/commands/uptime.js create mode 100644 Panel/bot/discord/index.js diff --git a/Panel/bot/discord/commands/getstarted.js b/Panel/bot/discord/commands/getstarted.js new file mode 100644 index 000000000..1ce46dcdd --- /dev/null +++ b/Panel/bot/discord/commands/getstarted.js @@ -0,0 +1,209 @@ +exports.run = async (client, message) => { + //Args + const args = message.content.split(' ').slice(1).join(' '); + var validator = require('validator'); + + //Random password gen + var CAPSNUM = "ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890"; + let getPassword = () => { + + var password = ""; + while (password.length < 10) { + password += CAPSNUM[Math.floor(Math.random() * CAPSNUM.length)]; + } + return password; + }; + + if (args == "") { + let embed = new Discord.RichEmbed() + .setColor(`BLUE`) + .addField(`__**How to get started!**__`, 'Create an account by typing: `' + config.DiscordBot.Prefix + 'getstarted account` \nOnce done run `' + config.DiscordBot.Prefix + 'getstarted server` to create a server! \n \nAny problems? Please send a message in <#640158951899398144>', true); + message.channel.send(embed) + + } else if (args == "account") { + const server = message.guild + + let channel = await server.createChannel(message.author.tag, "text", [{ + type: 'role', + id: message.guild.id, + deny: 0x400 + }, + { + type: 'user', + id: message.author.id, + deny: 1024 + } + ]).catch(console.error); + + let category = server.channels.find(c => c.id == "697585283214082078" && c.type == "category"); + if (!category) throw new Error("Category channel does not exist"); + + await channel.setParent(category.id); + + channel.overwritePermissions(message.author, { + VIEW_CHANNEL: true, + SEND_MESSAGES: true, + READ_MESSAGE_HISTORY: true + }) + + + const filter2 = m => m.author.id === message.author.id; + + let msg = await channel.send("<@" + message.author.id + ">", { + embed: new Discord.RichEmbed() + .setColor(0x36393e) + .setDescription("Please enter a username") + .setFooter("You can type 'cancel' to cancel the request") + }) + + //First Collection "UserName" + + let collected1 = await channel.awaitMessages(filter2, { + max: 1, + time: 30000, + errors: ['time'], + }).catch(x => { + msg.delete() + channel.send(`ERROR: User failed to provide an answer.`); + setTimeout(() => { + channel.delete(); + }, 3000); + return false; + }) + + if (collected1.first().content === 'cancel') { + return msg.edit("Request to create a new user has been canceled!", null).then(channel.delete()) + } + + await msg.edit("", { + embed: new Discord.RichEmbed() + .setColor(0x36393e) + .setDescription(`Username: **${collected1.first().content}** \nPlease enter a Email.`) + .setFooter("You can type 'cancel' to cancel the request") + }) + collected1.first().delete(); + + //scnd Collection "Email" + + let collected2 = await channel.awaitMessages(filter2, { + max: 1, + time: 30000, + errors: ['time'], + }).catch(x => { + msg.delete() + channel.send(`ERROR: User failed to provide an answer.`); + setTimeout(() => { + channel.delete(); + }, 3000); + return false; + }) + + + if (collected2.first().content === 'cancel') { + msg.edit("Request to create a new user has been canceled!", null).then(channel.delete()) + return false; + } + + if (!validator.isEmail(collected2.first().content.trim())) { + msg.delete() + channel.send(`\`${collected2.first().content.trim()}`+"` is not a Valid Email!"); + setTimeout(() => { + channel.delete(); + }, 3000); + return false; + } + collected2.first().delete(); + + let password = await getPassword(); + + DanBotHosting.createUser(collected1.first().content, password, collected2.first().content, collected1.first().content, ".", false, "en").then(user => { + + console.log(user) + + if (user == "Error: User already exists! (Or Email/Username is existing already)") { + msg.edit("ERROR: A user with that email/username already exists.", null).then(channel.delete()) + return false; + } + msg.edit("Hello! You created an new account, Heres the login information", { + embed: new Discord.RichEmbed() + .setColor(0x36393e) + .setDescription("URL: " + config.Pterodactyl.hosturl + " \nUsername: " + collected1.first().content + " \nEmail: " + collected2.first().content + " \nPassword: " + password) + .setFooter("Please note: It is recommended that you change the password") + }) + channel.send('**You have 1Hour to keep note of this info before the channel is deleted.**') + message.guild.members.get(message.author.id).addRole("639489891016638496"); + setTimeout(function () { + channel.delete(); + }, 3600000); + + }).catch(err => { + console.log(err); + }) + + } else if (args == "server") { + message.channel.send('This is being worked on. Please ping one of our Admins or the Owner and they will create a server for you!') + + /* const filter2 = m => m.author.id === message.author.id; + message.channel.send("", { + embed: new Discord.RichEmbed() + .setColor(0x36393e) + .setDescription("NodeJS Or Minecraft?") + .setFooter("You can type 'cancel' to cancel the request") + }).then((message2) => { + message2.channel.awaitMessages(filter2, { + max: 1, + time: 20000, + errors: ['time'], + }).then((collected1) => { + if (collected1.first().content === 'cancel') { + message.channel.bulkDelete(3) + return message.reply("Request to create a server has been canceled!").then(q => q.delete(5000)) + } + if (collected1.first().content.toLowercase == "Minecraft") { + message2.channel.send("", { + embed: new Discord.RichEmbed() + .setColor(0x36393e) + .setDescription(`Minecraft Server Version? (Example: 1.15.2)`) + .setFooter("You can type 'cancel' to cancel the request") + }).then((message3) => { + message3.channel.awaitMessages(filter2, { + max: 1, + time: 20000, + errors: ['time'], + }).then((collected2) => { + if (collected2.first().content === 'cancel') { + message.channel.bulkDelete(5) + return message.reply("Request to create a new user has been canceled!").then(q => q.delete(5000)) + } + + DanBotHosting.createUser(collected1.first().content, password, collected2.first().content, collected1.first().content, ".", false, "en").then(user => { + console.log(user) + if (user == "Error: User already exists! (Or Email/Username is existing already)") { + message.channel.send("ERROR: A user with that email/username already exists."); + message.channel.bulkDelete(5); + } else { + message.author.send("Hello! You created an new account, Heres the login information", { + embed: new Discord.RichEmbed() + .setColor(0x36393e) + .setDescription("URL: " + config.Pterodactyl.hosturl + " \nUsername: " + collected1.first().content + " \nEmail: " + collected2.first().content + " \nPassword: " + password) + .setFooter("Please note: It is recommended that you change the password") + }) + message.channel.bulkDelete(5); + + } + }).catch(err => { + console.log(err); + + + }) + }) + }) + } else if (collected1.first().content.toLowercase == "NodeJS") { + message.channel.send("**Created!**") + } + }) + }) + */ + } //End of ifs + +}; \ No newline at end of file diff --git a/Panel/bot/discord/commands/tickets.js b/Panel/bot/discord/commands/tickets.js new file mode 100644 index 000000000..331843d54 --- /dev/null +++ b/Panel/bot/discord/commands/tickets.js @@ -0,0 +1,13 @@ +exports.run = (client, message) => { + const args = message.content.split(' ').slice(1).join(' '); + + if (args == "") { + let embed = new Discord.RichEmbed() + .setColor(`GREEN`) + .addField(`__**Tickets**__`, 'You can create a new ticket by typing: `' + config.DiscordBot.Prefix + 'tickets new` \nYou can download your old tickets by running: `' + config.DiscordBot.Prefix + 'tickets logs` \nYou can download your old tickets by running: `' + config.DiscordBot.Prefix + 'tickets logs` \n\nAny problems? Please send a message in <#640158951899398144>', true); + message.channel.send(embed) + + } else if (args == "new") { + + } +}; \ No newline at end of file diff --git a/Panel/bot/discord/commands/uptime.js b/Panel/bot/discord/commands/uptime.js new file mode 100644 index 000000000..684b2905c --- /dev/null +++ b/Panel/bot/discord/commands/uptime.js @@ -0,0 +1,52 @@ +exports.run = async(client, message, args) => { + + var getUptime = function(millis) { + var dur = {}; + var units = [{ + label: "milliseconds", + mod: 1000 + }, + { + label: "seconds", + mod: 60 + }, + { + label: "minutes", + mod: 60 + }, + { + label: "hours", + mod: 24 + }, + { + label: "days", + mod: 31 + } + ]; + + units.forEach(function(u) { + millis = (millis - (dur[u.label] = (millis % u.mod))) / u.mod; + }); + + var nonZero = function(u) { + return dur[u.label]; + }; + dur.toString = function() { + return units + .reverse() + .filter(nonZero) + .map(function(u) { + return dur[u.label] + " " + (dur[u.label] == 1 ? u.label.slice(0, -1) : u.label); + }) + .join(', '); + }; + return dur; + }; + +let myDate = new Date(client.readyTimestamp); + var embed = new Discord.RichEmbed() + .addField(":white_check_mark: Uptime:", `**${getUptime(client.uptime)}**`) + .setFooter(`Ready Timestamp: ${myDate.toString()}`) + .setColor("GREEN") + message.channel.send(embed); + } \ No newline at end of file diff --git a/Panel/bot/discord/index.js b/Panel/bot/discord/index.js new file mode 100644 index 000000000..ba278ec8a --- /dev/null +++ b/Panel/bot/discord/index.js @@ -0,0 +1,37 @@ +//Discord bot +global.Discord = require("discord.js"); +const client = new Discord.Client() +global.fs = require("fs"); +global.moment = require("moment"); + +//Event handler +fs.readdir('./events/', (err, files) => { + files = files.filter(f => f.endsWith('.js')); + files.forEach(f => { + const event = require(`./events/${f}`); + client.on(f.split('.')[0], event.bind(null, client)); + delete require.cache[require.resolve(`./events/${f}`)]; + }); + }); + +//Command handler +client.on('message', message => { + + const prefix = config.DiscordBot.Prefix; + if (message.content.indexOf(prefix) !== 0) return; + const args = message.content.slice(prefix.length).trim().split(/ +/g); + const commandargs = message.content.split(' ').slice(1).join(' '); + const command = args.shift().toLowerCase(); + console.log(`[${message.author.username}] [${message.author.id}] >> ${prefix}${command} ${commandargs}`); + try { + let commandFile = require(`./commands/${command}.js`); + commandFile.run(client, message, args); + } catch (err) { + if (err instanceof Error && err.code === "MODULE_NOT_FOUND") { + return console.log(err) + } + } +}) + +//Bot login +client.login(config.DiscordBot.Token); \ No newline at end of file diff --git a/Panel/index.js b/Panel/index.js index 4ca37463b..b479ce317 100644 --- a/Panel/index.js +++ b/Panel/index.js @@ -17,6 +17,9 @@ global.fs = require("fs"); const hbs = require('hbs'); global.chalk = require('chalk'); +//Discord Bot +//require('./bot/discord/index.js') + app.use(bodyParser.json()); app.use(bodyParser.urlencoded({extended: true})); @@ -24,9 +27,18 @@ server.listen(PORT, function () { console.log(chalk.green("Listening on port " + PORT)); }); +app.get('/data', function (req, res) { + //console.log(req.query); + //Write data to JSON file after checking the servers Hostname. + var data = JSON.stringify(req.query); + fs.writeFileSync('data/' + req.query.servername + '.json', data); + +}); //Discord bot +var node = require('nodeactyl-beta'); +global.DanBotHosting = node.Application; global.Discord = require("discord.js"); const client = new Discord.Client() global.fs = require("fs"); @@ -61,20 +73,14 @@ client.on('message', message => { } }) +//Logging into pterodactyl using Nodeactyl +DanBotHosting.login(config.Pterodactyl.hosturl, config.Pterodactyl.apikey, (logged_in) => { + console.log("Nodeactyl logged in? " + logged_in); +}); + //Bot login client.login(config.DiscordBot.Token); - - -app.get('/data', function (req, res) { - //console.log(req.query); - - //Write data to JSON file after checking the servers Hostname. - var data = JSON.stringify(req.query); - fs.writeFileSync('data/' + req.query.servername + '.json', data); - -}); - //View engine setup hbs.registerPartials(__dirname + '/views/partials') app.set('view engine', 'hbs'); diff --git a/Panel/package.json b/Panel/package.json index 38e39f987..eb1c9e346 100644 --- a/Panel/package.json +++ b/Panel/package.json @@ -27,6 +27,8 @@ "helmet": "^3.21.2", "http": "latest", "moment": "^2.24.0", - "socket.io": "latest" + "nodeactyl-beta": "0.0.10", + "socket.io": "latest", + "validator": "^13.0.0" } } From 2156dd2c2c21f417f06b9d6b890506a8c3091098 Mon Sep 17 00:00:00 2001 From: danielpmc Date: Wed, 22 Apr 2020 16:54:09 +0100 Subject: [PATCH 005/255] Update timing for channel delete for used email/username and working on tickets.js --- Panel/bot/discord/commands/getstarted.js | 7 +++++-- Panel/bot/discord/commands/tickets.js | 2 +- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/Panel/bot/discord/commands/getstarted.js b/Panel/bot/discord/commands/getstarted.js index 1ce46dcdd..43c4bde80 100644 --- a/Panel/bot/discord/commands/getstarted.js +++ b/Panel/bot/discord/commands/getstarted.js @@ -109,7 +109,7 @@ exports.run = async (client, message) => { channel.send(`\`${collected2.first().content.trim()}`+"` is not a Valid Email!"); setTimeout(() => { channel.delete(); - }, 3000); + }, 10000); return false; } collected2.first().delete(); @@ -121,7 +121,10 @@ exports.run = async (client, message) => { console.log(user) if (user == "Error: User already exists! (Or Email/Username is existing already)") { - msg.edit("ERROR: A user with that email/username already exists.", null).then(channel.delete()) + msg.edit("ERROR: A user with that email/username already exists.", null) + setTimeout(function () { + channel.delete(); + }, 10000); return false; } msg.edit("Hello! You created an new account, Heres the login information", { diff --git a/Panel/bot/discord/commands/tickets.js b/Panel/bot/discord/commands/tickets.js index 331843d54..49a73930c 100644 --- a/Panel/bot/discord/commands/tickets.js +++ b/Panel/bot/discord/commands/tickets.js @@ -4,7 +4,7 @@ exports.run = (client, message) => { if (args == "") { let embed = new Discord.RichEmbed() .setColor(`GREEN`) - .addField(`__**Tickets**__`, 'You can create a new ticket by typing: `' + config.DiscordBot.Prefix + 'tickets new` \nYou can download your old tickets by running: `' + config.DiscordBot.Prefix + 'tickets logs` \nYou can download your old tickets by running: `' + config.DiscordBot.Prefix + 'tickets logs` \n\nAny problems? Please send a message in <#640158951899398144>', true); + .addField(`__**Tickets**__`, 'You can create a new ticket by typing: `' + config.DiscordBot.Prefix + 'tickets new` \nYou can download your old tickets by running: `' + config.DiscordBot.Prefix + 'tickets logs` \n\nAny problems? Please send a message in <#640158951899398144>', true); message.channel.send(embed) } else if (args == "new") { From 9f9e33ab20aa7b6bbecfc85ce1c49817eeecaeac Mon Sep 17 00:00:00 2001 From: danielpmc Date: Fri, 22 May 2020 12:59:58 +0100 Subject: [PATCH 006/255] Giant Update. v1.0.1 --- .gitignore | 1 + BetaDaemon/index.js | 49 +++- BetaDaemon/package.json | 1 + Panel/bot/discord/commands/access.js | 15 ++ Panel/bot/discord/commands/getstarted-new.js | 248 +++++++++++++++++++ Panel/bot/discord/commands/help.js | 27 ++ Panel/bot/discord/commands/link.js | 102 ++++++++ Panel/bot/discord/commands/linked.js | 13 + Panel/bot/discord/commands/purge.js | 36 +++ Panel/bot/discord/commands/staff.js | 23 ++ Panel/bot/discord/commands/stats.js | 60 ++--- Panel/bot/discord/commands/status.js | 50 ++++ Panel/bot/discord/commands/tickets.js | 96 ++++++- Panel/bot/discord/events/guildMemberAdd.js | 32 +++ Panel/bot/discord/events/message.js | 17 ++ Panel/bot/discord/events/messageDelete.js | 17 ++ Panel/bot/discord/events/messageUpdate.js | 17 ++ Panel/bot/discord/events/ready.js | 27 +- Panel/bot/discord/index.js | 37 --- Panel/index.js | 145 ++++++----- Panel/package.json | 16 +- Panel/views/index.hbs | 35 +-- Panel/views/node1.hbs | 3 + Panel/views/node2.hbs | 3 + Panel/views/node3.hbs | 3 + Panel/views/node4.hbs | 5 +- Panel/views/node5.hbs | 50 ---- 27 files changed, 911 insertions(+), 217 deletions(-) create mode 100644 Panel/bot/discord/commands/access.js create mode 100644 Panel/bot/discord/commands/getstarted-new.js create mode 100644 Panel/bot/discord/commands/help.js create mode 100644 Panel/bot/discord/commands/link.js create mode 100644 Panel/bot/discord/commands/linked.js create mode 100644 Panel/bot/discord/commands/purge.js create mode 100644 Panel/bot/discord/commands/staff.js create mode 100644 Panel/bot/discord/commands/status.js create mode 100644 Panel/bot/discord/events/guildMemberAdd.js create mode 100644 Panel/bot/discord/events/message.js create mode 100644 Panel/bot/discord/events/messageDelete.js create mode 100644 Panel/bot/discord/events/messageUpdate.js delete mode 100644 Panel/bot/discord/index.js delete mode 100644 Panel/views/node5.hbs diff --git a/.gitignore b/.gitignore index 0188802b5..ab9280538 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,7 @@ Panel/node_modules Panel/package-lock.json Panel/data Panel/config.json +Panel/json.sqlite Daemon/node_modules Daemon/package-lock.json diff --git a/BetaDaemon/index.js b/BetaDaemon/index.js index 67d5b1b6a..37b7eec24 100644 --- a/BetaDaemon/index.js +++ b/BetaDaemon/index.js @@ -20,6 +20,7 @@ var config = require("./config.json"); var { get } = require('superagent') var chalk = require('chalk'); var moment = require("moment"); +const speedTest = require('speedtest-net'); server.listen(PORT, function () { console.log(chalk.blueBright("The servers hostname is: " + chalk.green(os.hostname) + ", Please put this in the config file")) @@ -352,16 +353,19 @@ app.get('/', async function (req, res) { //Because Panel doesn't give response to Daemon it thinks it timed out. //But really it didn't data was still sent. //So ignore this error. + return; } else if (error == "Error: read ECONNRESET") { //Do nothing because panel went down. Program will still continue to try and send data. //So ignore this error. + return; } else if (error == "Error: ETIMEDOUT") { //Do nothing because panel went down. Program will still continue to try and send data. //So ignore this error. + return; }else { //Log the error in red and exit process console.log(chalk.red("ERROR! " + error)) - process.exit(); + return; } }); @@ -372,6 +376,47 @@ app.get('/', async function (req, res) { process.exit(); } -}, 2500); +}, 2500); + +setInterval(async () => { +var timestamp = `${moment().format("YYYY-MM-DD HH:mm:ss")}`; +const speed = await speedTest({maxTime: 5000}) +speed.on('data', async (data) => { +request({ + uri: "http://" + config.panelip + ":" + config.panelport + "/data?speedname=" + os.hostname + //OS hostname for saving data panel sided. + "&ping=" + data.server.ping + //Speedtest Ping. (MS) + "&download=" + data.speeds.download + //Download Speed (Mbps) + "&upload=" + data.speeds.upload + //Upload Speed (Mbps) + "&updatetime= " + timestamp, //Last time the node sent data to the panel //Date and time (Example: 1578594094569) + method: "GET", + timeout: 5000, + followRedirect: true, + maxRedirects: 10 +}, function (error, response, body) { + + //Send data to panel + res.send(body); + //Error checking. + if (error == "undefined") { + //No errors = Do nothing :D + } else if (error == "Error: ESOCKETTIMEDOUT") { + //Because Panel doesn't give response to Daemon it thinks it timed out. + //But really it didn't data was still sent. + //So ignore this error. + } else if (error == "Error: read ECONNRESET") { + //Do nothing because panel went down. Program will still continue to try and send data. + //So ignore this error. + } else if (error == "Error: connect ECONNREFUSED " + config.panelip + ":" + config.panelport) { + //Do nothing because panel went down. Program will still continue to try and send data. + //So ignore this error. + }else { + //Log the error in red and exit process + console.log(chalk.red("ERROR! " + error)) + process.exit(); + } +}); +}); +}, 21600000); +//}, 20000); }); diff --git a/BetaDaemon/package.json b/BetaDaemon/package.json index 1cc5417c8..58a58f615 100644 --- a/BetaDaemon/package.json +++ b/BetaDaemon/package.json @@ -18,6 +18,7 @@ "prettysize": "^2.0.0", "request": "^2.88.0", "socket.io": "latest", + "speedtest-net": "^1.5.1", "superagent": "^5.2.1", "systeminformation": "^4.16.0" } diff --git a/Panel/bot/discord/commands/access.js b/Panel/bot/discord/commands/access.js new file mode 100644 index 000000000..c6902ee78 --- /dev/null +++ b/Panel/bot/discord/commands/access.js @@ -0,0 +1,15 @@ +exports.run = (client, message) => { + const args = message.content.split(' ').slice(1).join(' '); + + if(message.member.roles.find(r => r.name === "Moderators")){ + if (args == "") { + let embed = new Discord.RichEmbed() + .setColor(`GREEN`) + .addField(`__**Access a user's server**__`, '', true); + message.channel.send(embed) + + } else { + + } + } +}; \ No newline at end of file diff --git a/Panel/bot/discord/commands/getstarted-new.js b/Panel/bot/discord/commands/getstarted-new.js new file mode 100644 index 000000000..ae5e26ac6 --- /dev/null +++ b/Panel/bot/discord/commands/getstarted-new.js @@ -0,0 +1,248 @@ +exports.run = async (client, message) => { + //Args + const args = message.content.split(' ').slice(1).join(' '); + var validator = require('validator'); + + //Random password gen + var CAPSNUM = "ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890"; + let getPassword = () => { + + var password = ""; + while (password.length < 10) { + password += CAPSNUM[Math.floor(Math.random() * CAPSNUM.length)]; + } + return password; + }; + + if (args == "") { + let embed = new Discord.RichEmbed() + .setColor(`BLUE`) + .addField(`__**How to get started!**__`, 'Create an account by typing: `' + config.DiscordBot.Prefix + 'getstarted account` \nOnce done run `' + config.DiscordBot.Prefix + 'getstarted server` to create a server! \n \nAny problems? Please send a message in <#640158951899398144>', true); + message.channel.send(embed) + + } else if (args == "account") { + const server = message.guild + + let channel = await server.createChannel(message.author.tag, "text", [{ + type: 'role', + id: message.guild.id, + deny: 0x400 + }, + { + type: 'user', + id: message.author.id, + deny: 1024 + } + ]).catch(console.error); + console.log(channel.id) + message.channel.send('<@' + message.author.id + '>, Please check <#' + channel.id + '>') + + let category = server.channels.find(c => c.id == "697585283214082078" && c.type == "category"); + if (!category) throw new Error("Category channel does not exist"); + + await channel.setParent(category.id); + + channel.overwritePermissions(message.author, { + VIEW_CHANNEL: true, + SEND_MESSAGES: true, + READ_MESSAGE_HISTORY: true + }) + + + const filter2 = m => m.author.id === message.author.id; + + let msg = await channel.send("<@" + message.author.id + ">", { + embed: new Discord.RichEmbed() + .setColor(0x36393e) + .setDescription("Please enter a username") + .setFooter("You can type 'cancel' to cancel the request") + }) + + //First Collection "UserName" + + let collected1 = await channel.awaitMessages(filter2, { + max: 1, + time: 30000, + errors: ['time'], + }).catch(x => { + msg.delete() + channel.send(`ERROR: User failed to provide an answer.`); + setTimeout(() => { + channel.delete(); + }, 3000); + return false; + }) + + if (collected1.first().content === 'cancel') { + return msg.edit("Request to create a new user has been canceled!", null).then(channel.delete()) + } + + await msg.edit("", { + embed: new Discord.RichEmbed() + .setColor(0x36393e) + .setDescription(`Username: **${collected1.first().content}** \nPlease enter a Email.`) + .setFooter("You can type 'cancel' to cancel the request") + }) + collected1.first().delete(); + + //scnd Collection "Email" + + let collected2 = await channel.awaitMessages(filter2, { + max: 1, + time: 30000, + errors: ['time'], + }).catch(x => { + msg.delete() + channel.send(`ERROR: User failed to provide an answer.`); + setTimeout(() => { + channel.delete(); + }, 3000); + return false; + }) + + + if (collected2.first().content === 'cancel') { + msg.edit("Request to create a new user has been canceled!", null).then(channel.delete()) + return false; + } + + if (!validator.isEmail(collected2.first().content.trim())) { + msg.delete() + channel.send(`\`${collected2.first().content.trim()}`+"` is not a Valid Email!"); + setTimeout(() => { + channel.delete(); + }, 10000); + return false; + } + collected2.first().delete(); + + let password = await getPassword(); + + DanBotHosting.createUser(collected1.first().content, password, collected2.first().content, collected1.first().content, ".", false, "en").then(user => { + + console.log(user) + + if (user == "Error: User already exists! (Or Email/Username is existing already)") { + msg.edit("ERROR: A user with that email/username already exists.", null) + setTimeout(function () { + channel.delete(); + }, 10000); + return false; + } + msg.edit("Hello! You created an new account, Heres the login information", { + embed: new Discord.RichEmbed() + .setColor(0x36393e) + .setDescription("URL: " + config.Pterodactyl.hosturl + " \nUsername: " + collected1.first().content + " \nEmail: " + collected2.first().content + " \nPassword: " + password) + .setFooter("Please note: It is recommended that you change the password") + }) + channel.send('**You have 1Hour to keep note of this info before the channel is deleted.**') + message.guild.members.get(message.author.id).addRole("639489891016638496"); + setTimeout(function () { + channel.delete(); + }, 3600000); + + }).catch(err => { + console.log(err); + }) + + } else if (args == "server") { + message.channel.send('This is being worked on. Please ping one of our Admins or the Owner and they will create a server for you!') + + const server = message.guild + + let channel = await server.createChannel(message.author.tag, "text", [{ + type: 'role', + id: message.guild.id, + deny: 0x400 + }, + { + type: 'user', + id: message.author.id, + deny: 1024 + } + ]).catch(console.error); + console.log(channel.id) + message.channel.send('<@' + message.author.id + '>, Please check <#' + channel.id + '>') + + let category = server.channels.find(c => c.id == "697585283214082078" && c.type == "category"); + if (!category) throw new Error("Category channel does not exist"); + + await channel.setParent(category.id); + + channel.overwritePermissions(message.author, { + VIEW_CHANNEL: true, + SEND_MESSAGES: true, + READ_MESSAGE_HISTORY: true + }) + + + const filter2 = m => m.author.id === message.author.id; + + let msg = await channel.send("<@" + message.author.id + ">", { + embed: new Discord.RichEmbed() + .setColor(0x36393e) + .setDescription("What would you like the server to be called?") + .setFooter("You can type 'cancel' to cancel the request") + }) + + //First Collection "Server name" + + let collected1 = await channel.awaitMessages(filter2, { + max: 1, + time: 30000, + errors: ['time'], + }).catch(x => { + msg.delete() + channel.send(`ERROR: User failed to provide an answer.`); + setTimeout(() => { + channel.delete(); + }, 3000); + return false; + }) + + if (collected1.first().content === 'cancel') { + return msg.edit("Request to create a new server has been canceled!", null).then(channel.delete()) + } + + await msg.edit("", { + embed: new Discord.RichEmbed() + .setColor(0x36393e) + .setDescription(`Servername: **${collected1.first().content}** \nMinecraft or NodeJS`) + .setFooter("You can type 'cancel' to cancel the request") + }) + collected1.first().delete(); + + //send Collection "Server type" + + let collected2 = await channel.awaitMessages(filter2, { + max: 1, + time: 30000, + errors: ['time'], + }).catch(x => { + msg.delete() + channel.send(`ERROR: User failed to provide an answer.`); + setTimeout(() => { + channel.delete(); + }, 3000); + return false; + }) + + + if (collected2.first().content === 'cancel') { + msg.edit("Request to create a new server has been canceled!", null).then(channel.delete()) + return false; + } else if (collected2.first().content.toLowerCase() === 'minecraft') { + collected2.first().delete(); + DanBotHosting.createServer("latest", collected1.first().content, userData.fetch(message.author.id + ".consoleID"), null, "3", "quay.io/pterodactyl/core:java", null, "2048", "0", "5000", "500", "200", "0", "0").then(res => { + console.log(res) + }).catch(error =>{ + console.log(error); + }) + + } else if (collected2.first().content === 'nodejs') { + collected2.first().delete(); + + } + } + +}; \ No newline at end of file diff --git a/Panel/bot/discord/commands/help.js b/Panel/bot/discord/commands/help.js new file mode 100644 index 000000000..23710fbbf --- /dev/null +++ b/Panel/bot/discord/commands/help.js @@ -0,0 +1,27 @@ +const Help = { + "Users": `${config.DiscordBot.Prefix}getstarted | Create a server or account \n${config.DiscordBot.Prefix}link | Link your console account with your discord account \n${config.DiscordBot.Prefix}linked | Check if your account is linked \n${config.DiscordBot.Prefix}stats | Shows the stats of each hosting node. \n${config.DiscordBot.Prefix}tickets | Create a ticket for help from the staff team! \n${config.DiscordBot.Prefix}status | Check the status of your server! \n${config.DiscordBot.Prefix}uptime | Shows the bots uptime`, + "Staff": `${config.DiscordBot.Prefix}staff | Gets the ID of a user on console using their discord ID \n${config.DiscordBot.Prefix}purge | Delete messages in a channel \n${config.DiscordBot.Prefix}access | Gain subuser access to a server`, + "Owner": `${config.DiscordBot.Prefix}reload | Reloads all commands on the bot \n${config.DiscordBot.Prefix}restart | Restarts **EVERYTHING**, Bot and Stats website` +} + +exports.run = async (client, message, args) => { + if (message.member.roles.find(r => r.name === "Staff")) { + let embed = new Discord.RichEmbed() + .setColor(`BLUE`) + .addField(`__**Commands List for users:**__`, Help.Users) + .addField(`__**Staff Commands:**__`, Help.Staff) + message.channel.send(embed) + } else if (message.member.roles.find(r => r.name === "Owner")) { + let embed = new Discord.RichEmbed() + .setColor(`BLUE`) + .addField(`__**Commands List for users:**__`, Help.Users) + .addField(`__**Staff Commands:**__`, Help.Staff) + .addField(`__**Owner Commands:**__`, Help.Owner) + message.channel.send(embed) + } else if (message.member.roles.find(r => r.name === "Members")) { + let embed = new Discord.RichEmbed() + .setColor(`BLUE`) + .addField(`__**Commands List for users:**__`, Help.Users) + message.channel.send(embed) + }; +}; \ No newline at end of file diff --git a/Panel/bot/discord/commands/link.js b/Panel/bot/discord/commands/link.js new file mode 100644 index 000000000..19cb941e0 --- /dev/null +++ b/Panel/bot/discord/commands/link.js @@ -0,0 +1,102 @@ +var path = require("path") +var fs = require("fs") +const moment = require("moment"); +exports.run = async (client, message) => { + + const args = message.content.split(' ').slice(1).join(' '); + + let result = userData.get(message.author.id) + if (userData.get(message.author.id) == null) { + if (message.member.roles.find(r => r.name === "Customers")) { + + const server = message.guild + + let channel = await server.createChannel(message.author.tag, "text", [{ + type: 'role', + id: message.guild.id, + deny: 0x400 + }, + { + type: 'user', + id: message.author.id, + deny: 1024 + } + ]).catch(console.error); + message.channel.send(`<@${message.author.id}>, Please check <#${channel.id}> to link your account.`) + + let category = server.channels.find(c => c.id == "697585283214082078" && c.type == "category"); + if (!category) throw new Error("Category channel does not exist"); + + await channel.setParent(category.id); + + channel.overwritePermissions(message.author, { + VIEW_CHANNEL: true, + SEND_MESSAGES: true, + READ_MESSAGE_HISTORY: true + }) + + + const filter2 = m => m.author.id === message.author.id; + + let msg = await channel.send(message.author, { + embed: new Discord.RichEmbed() + .setColor(0x36393e) + .setDescription("Please enter your console email address") + .setFooter("You can type 'cancel' to cancel the request") + }) + + let collected1 = await channel.awaitMessages(filter2, { + max: 1, + time: 60000, + errors: ['time'], + }).catch(x => { + msg.delete() + channel.send(`ERROR: User failed to provide an answer.`); + setTimeout(() => { + channel.delete(); + }, 3000); + return false; + }) + + if (collected1.first().content === 'cancel') { + return msg.edit("Request to link your account canceled.", null).then(channel.delete()) + } + + let consoleUser = await DanBotHosting.getAllUsers(); + consoleUser = consoleUser.filter(x => x.attributes.email == collected1.first().content.trim()) + console.log(consoleUser) + + if (consoleUser.length == 0) return channel.send("No account with that email exists...").then( + setTimeout(() => { + channel.delete(); + }, 5000) + ) + + consoleUser = consoleUser[0]; + const timestamp = `${moment().format("HH:mm:ss")}`; + const datestamp = `${moment().format("YYYY-MM-DD")}`; + userData.set(`${message.author.id}`, { + discordID: message.author.id, + consoleID: consoleUser.attributes.id, + email: consoleUser.attributes.email, + username: consoleUser.attributes.username, + linkTime: timestamp, + linkDate: datestamp + }) + channel.send("Account linked! You can now create server's and use other features on this bot!").then( + setTimeout(() => { + channel.delete(); + }, 5000) + ) + + + } +} else { + let embed = new Discord.RichEmbed() + .setColor(`GREEN`) + .addField(`__**Username**__`, userData.fetch(message.author.id + ".username")) + .addField(`__**Date (DD/MM/YY)**__`, userData.fetch(message.author.id + ".linkDate")) + .addField(`__**Time**__`, userData.fetch(message.author.id + ".linkTime")) + message.channel.send("You'r account is already linked. ", embed) +} +} \ No newline at end of file diff --git a/Panel/bot/discord/commands/linked.js b/Panel/bot/discord/commands/linked.js new file mode 100644 index 000000000..50bf914f3 --- /dev/null +++ b/Panel/bot/discord/commands/linked.js @@ -0,0 +1,13 @@ +exports.run = async (client, message) => { + let result = userData.get(message.author.id) + if (userData.get(message.author.id) == null) { + message.channel.send("You'r account is not linked. Please link you'r account using " + config.DiscordBot.Prefix + "link") + } else { + let embed = new Discord.RichEmbed() + .setColor(`GREEN`) + .addField(`__**Username**__`, userData.fetch(message.author.id + ".username")) + .addField(`__**Date (YYYY/MM/DD)**__`, userData.fetch(message.author.id + ".linkDate")) + .addField(`__**Time**__`, userData.fetch(message.author.id + ".linkTime")) + message.channel.send('Your account is linked. Heres some data: ', embed) + } +}; \ No newline at end of file diff --git a/Panel/bot/discord/commands/purge.js b/Panel/bot/discord/commands/purge.js new file mode 100644 index 000000000..f8242805a --- /dev/null +++ b/Panel/bot/discord/commands/purge.js @@ -0,0 +1,36 @@ +const Discord = require("discord.js"); +exports.run = (client, message, args) => { +const prefixtouse = config.prefix +const usage = new Discord.RichEmbed() + .setColor(0x00A2E8) + .setTitle("Command: " + prefixtouse + "purge") + .addField("Usage", prefixtouse + "purge @Someone") + .addField("Example", prefixtouse + "purge 20 spam") + .setDescription("Description: " + "Purges the channels messages (min 2 max 100)"); + +const user = message.mentions.users.first() +const amount = !!parseInt(message.content.split(' ')[2]) ? parseInt(message.content.split(' ')[2]) : parseInt(message.content.split(' ')[1]) +let reason = args[3] || `Moderator didn't give a reason.`; +if (!amount) return message.channel.send(usage); +if (!amount && !user) return message.channel.send(usage); +message.channel.fetchMessages({ + limit: amount, +}).then((messages) => { + if (user) { + const filterBy = user ? user.id : client.user.id; + messages = messages.filter(m => m.author.id === filterBy).array().slice(0, amount + 1); + } + if (amount <= 1) return message.channel.send("Can only delete a min of 2 messages") + if (amount >= 101) return message.channel.send("Can only delete a max of 100 messages") + message.channel.bulkDelete(messages, true).catch(error => console.log(error.stack)); + message.channel.send("***The server messages/users messages has been successfully purged! :white_check_mark:***") + const embed = new Discord.RichEmbed() + .setColor(0x00A2E8) + .addField("Moderator", message.author.tag, true) + .addField("Purge Amount", amount) + .addField("In channel", message.channel.name, true) + .addField("Reason", reason, true) + .setFooter("Time used: " + message.createdAt.toDateString()) + return client.channels.get(config.DiscordBot.mLogs).send({embed}); + }) +} \ No newline at end of file diff --git a/Panel/bot/discord/commands/staff.js b/Panel/bot/discord/commands/staff.js new file mode 100644 index 000000000..0864625de --- /dev/null +++ b/Panel/bot/discord/commands/staff.js @@ -0,0 +1,23 @@ +exports.run = async (client, message, args) => { + //const args = message.content.split(' ').slice(1).join(' '); + //const args2 = message.content.split(' ').slice(3).join(' '); + + if (message.content.toLowerCase().includes("linked")) { + if (args.slice(0).join(" ") == "") { + message.channel.send('Please send a users discord ID to see if they are linked with an account on the host.') + } else { + if (userData.get(args.slice(1).join(" ")) == null) { + message.channel.send("That account is not linked with a console account :sad:") + } else { + let embed = new Discord.RichEmbed() + .setColor(`GREEN`) + .addField(`__**Username**__`, userData.fetch(args.slice(1).join(" ") + ".username")) + .addField(`__**Date (YYYY/MM/DD)**__`, userData.fetch(args.slice(1).join(" ") + ".linkDate")) + .addField(`__**Time**__`, userData.fetch(args.slice(1).join(" ") + ".linkTime")) + message.channel.send('That account is linked. Heres some data: ', embed) + } + } + } else if (message.content.toLowerCase().includes("createserver")) { + message.channels.send('Who would you like to create') + } +} \ No newline at end of file diff --git a/Panel/bot/discord/commands/stats.js b/Panel/bot/discord/commands/stats.js index 419c2c6c7..17169d34d 100644 --- a/Panel/bot/discord/commands/stats.js +++ b/Panel/bot/discord/commands/stats.js @@ -1,37 +1,37 @@ exports.run = async(client, message) => { - //Sends message while the json's are being cached - let embed = new Discord.RichEmbed() - .setColor(`RANDOM`) - .addField(`__**Please wait...**__`, `Loading all node's stats!`, true); - let msg = await message.channel.send(embed) + //Sends message while the json's are being cached + let embed = new Discord.RichEmbed() + .setColor(`RANDOM`) + .addField(`__**Please wait...**__`, `Loading all node's stats!`, true); + let msg = await message.channel.send(embed) - //Reads the saved jsons for each node - //Data for node 1 - var N1 = fs.readFileSync('./data/0286b2ad-dc80-4b5c-a0de-b81945b010e8.json', 'utf8'); - var Node1Data = JSON.parse(N1); + //Reads the saved jsons for each node +//Data for node 1 +var N1 = fs.readFileSync('./data/0286b2ad-dc80-4b5c-a0de-b81945b010e8.json', 'utf8'); +var Node1Data = JSON.parse(N1); - //Data for node 2 - var N2 = fs.readFileSync('./data/2e3f071a-af2b-4dc9-be5a-7ce72590a181.json', 'utf8'); - var Node2Data = JSON.parse(N2); - - //Data for node 3 - var N3 = fs.readFileSync('./data/6fc3e9bf-24a8-47cd-99d3-fa159e05a9f4.json', 'utf8'); - var Node3Data = JSON.parse(N3); +//Data for node 2 +var N2 = fs.readFileSync('./data/2e3f071a-af2b-4dc9-be5a-7ce72590a181.json', 'utf8'); +var Node2Data = JSON.parse(N2); - //Data for node 4 - var N4 = fs.readFileSync('./data/15ffcdd0-a021-4ded-977d-284d777330a0.json', 'utf8'); - var Node4Data = JSON.parse(N4); +//Data for node 3 +var N3 = fs.readFileSync('./data/bed240f5-7c87-4013-90ee-a5bbc21f60da.json', 'utf8'); +var Node3Data = JSON.parse(N3); - //Edits the message to display the data - embed.fields.pop() - embed.addField("\u200b", "__**[Node 1](https://stats.danbot.xyz/Node1)**__ \n**CPU LOAD**: " + Node1Data.cpuload + "% \n**RAM (USED/TOTAL)**: " + Node1Data.memused + " / " + Node1Data.memtotal + " \n**STORAGE (USED/TOTAL)**: " + Node1Data.diskused + " / " + Node1Data.disktotal + " \n**UPTIME**: " + Node1Data.osuptime) - embed.addField('\u200b', '\u200b') - embed.addField("\u200b", "__**[Node 2](https://stats.danbot.xyz/Node2)**__ \n**CPU LOAD**: " + Node2Data.cpuload + "% \n**RAM (USED/TOTAL)**: " + Node2Data.memused + " / " + Node2Data.memtotal + " \n**STORAGE (USED/TOTAL)**: " + Node2Data.diskused + " / " + Node2Data.disktotal + " \n**UPTIME**: " + Node2Data.osuptime) - embed.addField('\u200b', '\u200b') - embed.addField("\u200b", "__**[Node 3](https://stats.danbot.xyz/Node3)**__ \n**CPU LOAD**: " + Node3Data.cpuload + "% \n**RAM (USED/TOTAL)**: " + Node3Data.memused + " / " + Node3Data.memtotal + " \n**STORAGE (USED/TOTAL)**: " + Node3Data.diskused + " / " + Node3Data.disktotal + " \n**UPTIME**: " + Node3Data.osuptime) - embed.addField('\u200b', '\u200b') - embed.addField("\u200b", "__**[Node 4](https://stats.danbot.xyz/Node4)**__ \n**CPU LOAD**: " + Node4Data.cpuload + "% \n**RAM (USED/TOTAL)**: " + Node4Data.memused + " / " + Node4Data.memtotal + " \n**STORAGE (USED/TOTAL)**: " + Node4Data.diskused + " / " + Node4Data.disktotal + " \n**UPTIME**: " + Node4Data.osuptime) - embed.setDescription('Want to view more stats live? [Click Here!](https://stats.danbot.xyz/)') - msg.edit(embed); +//Data for node 4 +var N4 = fs.readFileSync('./data/Server-01.json', 'utf8'); +var Node4Data = JSON.parse(N4); + + //Edits the message to display the data + embed.fields.pop() + embed.addField("\u200b", "__**[Node 1](https://stats.danbot.xyz/Node1)**__ \n**CPU LOAD**: " + Node1Data.cpuload + "% \n**RAM (USED/TOTAL)**: " + Node1Data.memused + " / " + Node1Data.memtotal + " \n**STORAGE (USED/TOTAL)**: " + Node1Data.diskused + " / " + Node1Data.disktotal + " \n**UPTIME**: " + Node1Data.osuptime) + embed.addField('\u200b', '\u200b') + embed.addField("\u200b", "__**[Node 2](https://stats.danbot.xyz/Node2)**__ \n**CPU LOAD**: " + Node2Data.cpuload + "% \n**RAM (USED/TOTAL)**: " + Node2Data.memused + " / " + Node2Data.memtotal + " \n**STORAGE (USED/TOTAL)**: " + Node2Data.diskused + " / " + Node2Data.disktotal + " \n**UPTIME**: " + Node2Data.osuptime) + embed.addField('\u200b', '\u200b') + embed.addField("\u200b", "__**[Node 3](https://stats.danbot.xyz/Node3)**__ \n**CPU LOAD**: " + Node3Data.cpuload + "% \n**RAM (USED/TOTAL)**: " + Node3Data.memused + " / " + Node3Data.memtotal + " \n**STORAGE (USED/TOTAL)**: " + Node3Data.diskused + " / " + Node3Data.disktotal + " \n**UPTIME**: " + Node3Data.osuptime) + embed.addField('\u200b', '\u200b') + embed.addField("\u200b", "__**[Node 4](https://stats.danbot.xyz/Node4)**__ \n**CPU LOAD**: " + Node4Data.cpuload + "% \n**RAM (USED/TOTAL)**: " + Node4Data.memused + " / " + Node4Data.memtotal + " \n**STORAGE (USED/TOTAL)**: " + Node4Data.diskused + " / " + Node4Data.disktotal + " \n**UPTIME**: " + Node4Data.osuptime) + embed.setDescription('Want to view more stats live? [Click Here!](https://stats.danbot.xyz/)') + msg.edit(embed); }; \ No newline at end of file diff --git a/Panel/bot/discord/commands/status.js b/Panel/bot/discord/commands/status.js new file mode 100644 index 000000000..0b498b281 --- /dev/null +++ b/Panel/bot/discord/commands/status.js @@ -0,0 +1,50 @@ +exports.run = (client, message) => { + const args = message.content.split(' ').slice(1).join(' '); + + if (args == "") { + let embed = new Discord.RichEmbed() + .setColor(`GREEN`) + .addField(`__**Server Status**__`, 'What server would you like to view? Please type: ' + config.DiscordBot.Prefix + 'status serveridhere', true) + message.channel.send(embed) + + } else { + message.delete(); + DanBotHostingClient.getServerStatus(args).then((status) => { + DanBotHostingClient.getCPUUsage(args).then(CPUUsageResponse => { + DanBotHostingClient.getRAMUsage(args).then(RAMUsageResponse => { + DanBotHostingClient.getDiskUsage(args).then(DISKUsageResponse => { + DanBotHostingClient.getServerInfo(args).then(InfoResponse => { + if (status == "on") { + if (RAMUsageResponse.limit == "0") { + let embedstatus = new Discord.RichEmbed() + .setColor('GREEN') + .addField('**Server name**', InfoResponse.attributes.name) + .addField('**Status**', `Online :)`, true) + .addField('**CPU Usage**', CPUUsageResponse.current + ' %') + .addField('**RAM Usage**', RAMUsageResponse.current + ' MB out of UNLIMITED MB') + .addField('**DISK Usage**', DISKUsageResponse.current + ' MB out of ' + DISKUsageResponse.limit + ' MB') + .addField('**LIMITS (0 = unlimited)**', 'Memory: ' + InfoResponse.attributes.limits.memory + ' MB, Disk: ' + InfoResponse.attributes.limits.disk + ' MB, CPU Cores: ' + InfoResponse.attributes.limits.cpu) + message.reply(embedstatus) + } else { + let embedstatus = new Discord.RichEmbed() + .setColor('GREEN') + .addField('**Server name**', InfoResponse.attributes.name) + .addField('**Status**', `Online :)`, true) + .addField('**CPU Usage**', CPUUsageResponse.current + ' %') + .addField('**RAM Usage**', RAMUsageResponse.current + ' MB out of ' + RAMUsageResponse.limit + ' MB') + .addField('**DISK Usage**', DISKUsageResponse.current + ' MB out of ' + DISKUsageResponse.limit + ' MB') + .addField('**LIMITS (0 = unlimited)**', 'Memory: ' + InfoResponse.attributes.limits.memory + ' MB, Disk: ' + InfoResponse.attributes.limits.disk + ' MB, CPU Cores: ' + InfoResponse.attributes.limits.cpu) + message.reply(embedstatus) + } + } else if (status == "off") { + let embedstatus = new Discord.RichEmbed() + .setColor('RED') + .addField('**Server name**', InfoResponse.attributes.name) + .addField('**Status**', `Offline :(`) + message.reply(embedstatus) + } + }).catch((error) => { + console.log(error); + })})})})}); + }; +}; \ No newline at end of file diff --git a/Panel/bot/discord/commands/tickets.js b/Panel/bot/discord/commands/tickets.js index 49a73930c..f56256d58 100644 --- a/Panel/bot/discord/commands/tickets.js +++ b/Panel/bot/discord/commands/tickets.js @@ -1,13 +1,105 @@ -exports.run = (client, message) => { +exports.run = async (client, message) => { const args = message.content.split(' ').slice(1).join(' '); + const user = message.content.split(' ').slice(2).join(' '); if (args == "") { let embed = new Discord.RichEmbed() .setColor(`GREEN`) - .addField(`__**Tickets**__`, 'You can create a new ticket by typing: `' + config.DiscordBot.Prefix + 'tickets new` \nYou can download your old tickets by running: `' + config.DiscordBot.Prefix + 'tickets logs` \n\nAny problems? Please send a message in <#640158951899398144>', true); + .addField(`__**Tickets**__`, 'You can create a new ticket by typing: `' + config.DiscordBot.Prefix + 'tickets new` \nYou can download your old tickets by running: `' + config.DiscordBot.Prefix + 'tickets logs` \nYou can close your ticket by running: `' + config.DiscordBot.Prefix + 'tickets close` \n\nAny problems? Please send a message in <#640158951899398144>', true); message.channel.send(embed) } else if (args == "new") { + const server = message.guild + let channel = await server.createChannel(message.author.username + "-Ticket", "text", [{ + type: 'role', + id: message.guild.id, + deny: 0x400 + }, + { + type: 'user', + id: message.author.id, + deny: 1024 + }, + { + type: "role", + id: "697599153538334841", + allow: 84992 + } + ]).catch(console.error); + + let category = server.channels.find(c => c.id == "654313162086285323" && c.type == "category"); + if (!category) throw new Error("Category channel does not exist"); + + await channel.setParent(category.id); + + channel.overwritePermissions(message.author, { + VIEW_CHANNEL: true, + SEND_MESSAGES: true, + READ_MESSAGE_HISTORY: true + }) + + if (userData.get(message.author.id) == null) { + channel.send('@ everyone \n\n <@' + message.author.id + '> here is your ticket! Please give as much info as possible about your problem. \n\n *This account is not linked with a console account*') + } else { + let embed = new Discord.RichEmbed() + .setColor(`GREEN`) + .addField(`__**Username**__`, userData.fetch(message.author.id + ".username")) + .addField(`__**Date (YYYY/MM/DD)**__`, userData.fetch(message.author.id + ".linkDate")) + .addField(`__**Time**__`, userData.fetch(message.author.id + ".linkTime")) + channel.send('@ everyone \n\n <@' + message.author.id + '> here is your ticket! Please give as much info as possible about your problem. \n\n *This account is linked with:* ', embed) + } + } else if (args == "close") { + if (message.channel.name.includes('-ticket')) { + const filter2 = m => m.author.id === message.author.id; + const warning = await message.channel.send('<@' + message.author.id + '> are you sure you want to close this ticket? please type `confirm` to close the ticket or `cancel` to keep the ticket open.') + + let collected1 = await message.channel.awaitMessages(filter2, { + max: 1, + time: 30000, + errors: ['time'], + }).catch(x => { + warning.delete() + message.channel.send(`ERROR: User failed to provide an answer. Ticket staying open.`); + setTimeout(() => { + message.channel.delete(); + }, 3000); + return false; + }) + + if (collected1.first().content === 'confirm') { + return message.channel.send("**Closing ticket.**", null).then(setTimeout(() => { message.channel.delete()}, 5000)) + } else if (collected1.first().content === 'cancel') { + return message.channel.send('Closing ticket. __**Canceled**__ Ticket staying open.'); + } + } else if (!message.channel.name.includes('-ticket')) { + message.channel.send('ERROR: You can only use this command in ticket channels.') + + } + } else if (args == "add") { + if (message.channel.name.includes('-ticket')) { + if (!args[1] == "") { + message.channel.send('Please run this command again with the users ID') + } else { + console.log(args[1]) + message.channel.overwritePermissions(args[1], { + VIEW_CHANNEL: true, + SEND_MESSAGES: true, + READ_MESSAGE_HISTORY: true + }) + } + } else { + message.channel.send('This command is only to be used inside of ticket channels.') + } + } else if (args == "remove") { + if (!args[1] == "") { + message.channel.send('Please run this command again with the users ID') + } else { + message.channel.overwritePermissions(args[1], { + VIEW_CHANNEL: false, + SEND_MESSAGES: false, + READ_MESSAGE_HISTORY: false + }) + } } }; \ No newline at end of file diff --git a/Panel/bot/discord/events/guildMemberAdd.js b/Panel/bot/discord/events/guildMemberAdd.js new file mode 100644 index 000000000..86afae702 --- /dev/null +++ b/Panel/bot/discord/events/guildMemberAdd.js @@ -0,0 +1,32 @@ +const config = { + "welcome": "704648079361573024", + "inviterewmsg": "704648079361573024", + "invite5": "704650026076602449", + "invite10": "704650153797091418", + "invite25": "704650197732556891", + "invite50": "704650269182394398", + "invitechannel": "704650867642597468", + "member": "639490038434103306" +} + +module.exports = async(client, member, guild) => { + const memberrole = member.guild.roles.find(role => role.id === config.member); + member.guild.members.get(member.user.id).addRole(memberrole) + client.channels.get(config.welcome).send("Welcome <@" + member.user.id + "> to DanBot Hosting. To get started please read <#640158484985413632>"); + + member.guild.fetchInvites().then(guildInvites => { + const ei = invites[member.guild.id]; + invites[member.guild.id] = guildInvites; + const invite = guildInvites.find(i => ei.get(i.code).uses < i.uses); + const inviter = client.users.get(invite.inviter.id); + client.channels.get(config.invitechannel).send(`${member.user.tag} (ID: ${member.user.id}) joined using invite code ` + "`" + invite.code + "`" + ` from ${inviter.tag} (ID: ${inviter.id}). Invite code has been used ${invite.uses} times.`); + const invite5 = member.guild.roles.find(role => role.id === config.invite5); + const invite10 = member.guild.roles.find(role => role.id === config.invite10); + const invite25 = member.guild.roles.find(role => role.id === config.invite25); + const invite50 = member.guild.roles.find(role => role.id === config.invite50); + if (invite.uses == 5) return member.guild.members.get(inviter.id).addRole(invite5), client.channels.get(config.inviterewmsg).send(`<@${inviter.id}> just hit 5 invites! Here's a role for you :)`); + if (invite.uses == 10) return member.guild.members.get(inviter.id).removeRole(invite5), member.guild.members.get(inviter.id).addRole(invite10), client.channels.get(config.inviterewmsg).send(`<@${inviter.id}> just hit 10 invites! Here's a role for you :)`);; + if (invite.uses >= 25) return member.guild.members.get(inviter.id).removeRole(invite10), member.guild.members.get(inviter.id).addRole(invite25), client.channels.get(config.inviterewmsg).send(`<@${inviter.id}> just hit 25 invites! Here's a role for you :)`);; + if (invite.uses >= 50) return member.guild.members.get(inviter.id).removeRole(invite25), member.guild.members.get(inviter.id).addRole(invite50), client.channels.get(config.inviterewmsg).send(`<@${inviter.id}> just hit 50 invites! Here's a role for you :)`);; + }); +}; \ No newline at end of file diff --git a/Panel/bot/discord/events/message.js b/Panel/bot/discord/events/message.js new file mode 100644 index 000000000..1e1221907 --- /dev/null +++ b/Panel/bot/discord/events/message.js @@ -0,0 +1,17 @@ +module.exports = (client, message) => { + if(message.content.toLowerCase().includes("tiktok")) { message.delete() } + const prefix = config.DiscordBot.Prefix; + if (message.content.indexOf(prefix) !== 0) return; + const args = message.content.slice(prefix.length).trim().split(/ +/g); + const commandargs = message.content.split(' ').slice(1).join(' '); + const command = args.shift().toLowerCase(); + console.log(chalk.magenta("[DISCORD] ") + chalk.yellow(`[${message.author.username}] [${message.author.id}] >> ${prefix}${command} ${commandargs}`)); + try { + let commandFile = require(`../commands/${command}.js`); + commandFile.run(client, message, args); + } catch (err) { + if (err instanceof Error && err.code === "MODULE_NOT_FOUND") { + return; + } + } +}; \ No newline at end of file diff --git a/Panel/bot/discord/events/messageDelete.js b/Panel/bot/discord/events/messageDelete.js new file mode 100644 index 000000000..7510260b5 --- /dev/null +++ b/Panel/bot/discord/events/messageDelete.js @@ -0,0 +1,17 @@ +module.exports = (client, message) => { + if (message.author.bot) return; + if (message.channel.type === 'dm') return; + if (message.channel.type !== 'text') return; + + + const description = message.cleanContent + const descriptionfix = description.substr(0, 600); + const embed = new Discord.RichEmbed() + .setColor(0x00A2E8) + .setThumbnail(message.author.avatarURL) + .addField("Author ", `${message.author.tag} (ID: ${message.author.id})`) + .addField("Message Content:", `${descriptionfix}`) + .setTimestamp() + .setFooter("Message delete in " + message.channel.name); + client.channels.get(config.DiscordBot.mLogs).send({embed}); +} \ No newline at end of file diff --git a/Panel/bot/discord/events/messageUpdate.js b/Panel/bot/discord/events/messageUpdate.js new file mode 100644 index 000000000..863aab49c --- /dev/null +++ b/Panel/bot/discord/events/messageUpdate.js @@ -0,0 +1,17 @@ +module.exports = (client, message, editedMessage) => { + if(message.content.toLowerCase().includes("tiktok")) { message.delete() } + if (message.author.bot) return; + if (message.channel.type === 'dm') return; + if (message === editedMessage) return; + if (message.channel.type !== 'text') return; + + const embed = new Discord.RichEmbed() + .setColor(0x00A2E8) + .setThumbnail(message.author.avatarURL) + .addField("Author ", `${message.author.tag} (ID: ${message.author.id})`) + .addField("Before Edit ", `${message}`) + .addField("After Edit", `${editedMessage}`) + .setTimestamp() + .setFooter("Message edit in " + message.channel.name); + client.channels.get(config.DiscordBot.mLogs).send({embed}); + } \ No newline at end of file diff --git a/Panel/bot/discord/events/ready.js b/Panel/bot/discord/events/ready.js index c0d8bb92b..c23f98748 100644 --- a/Panel/bot/discord/events/ready.js +++ b/Panel/bot/discord/events/ready.js @@ -1,5 +1,26 @@ module.exports = (client, guild, files) => { - const timestamp = `${moment().format("YYYY-MM-DD HH:mm:ss")}`; - console.log(chalk.yellow("[" + timestamp + "] Discord bot logged in!")); - client.user.setActivity("over DanBot Hosting", { type: "WATCHING" }); + console.log(chalk.magenta('[DISCORD] ') + chalk.green("Bot logged in!")); + +//Auto Activities List +const activities = [ + { + "text": "over DanBot Hosting", + "type": "WATCHING" + }, + { + "text": "DanBot FM", + "type": "LISTENING" + } +]; +setInterval(() => { + const activity = activities[Math.floor(Math.random() * activities.length)]; + client.user.setActivity(activity.text, { type: activity.type }); +}, 30000); + +global.invites = {}; +client.guilds.forEach(g => { + g.fetchInvites().then(guildInvites => { + invites[g.id] = guildInvites; + }); + }); }; \ No newline at end of file diff --git a/Panel/bot/discord/index.js b/Panel/bot/discord/index.js deleted file mode 100644 index ba278ec8a..000000000 --- a/Panel/bot/discord/index.js +++ /dev/null @@ -1,37 +0,0 @@ -//Discord bot -global.Discord = require("discord.js"); -const client = new Discord.Client() -global.fs = require("fs"); -global.moment = require("moment"); - -//Event handler -fs.readdir('./events/', (err, files) => { - files = files.filter(f => f.endsWith('.js')); - files.forEach(f => { - const event = require(`./events/${f}`); - client.on(f.split('.')[0], event.bind(null, client)); - delete require.cache[require.resolve(`./events/${f}`)]; - }); - }); - -//Command handler -client.on('message', message => { - - const prefix = config.DiscordBot.Prefix; - if (message.content.indexOf(prefix) !== 0) return; - const args = message.content.slice(prefix.length).trim().split(/ +/g); - const commandargs = message.content.split(' ').slice(1).join(' '); - const command = args.shift().toLowerCase(); - console.log(`[${message.author.username}] [${message.author.id}] >> ${prefix}${command} ${commandargs}`); - try { - let commandFile = require(`./commands/${command}.js`); - commandFile.run(client, message, args); - } catch (err) { - if (err instanceof Error && err.code === "MODULE_NOT_FOUND") { - return console.log(err) - } - } -}) - -//Bot login -client.login(config.DiscordBot.Token); \ No newline at end of file diff --git a/Panel/index.js b/Panel/index.js index b479ce317..f786bbe37 100644 --- a/Panel/index.js +++ b/Panel/index.js @@ -16,33 +16,27 @@ var bodyParser = require('body-parser'); global.fs = require("fs"); const hbs = require('hbs'); global.chalk = require('chalk'); - -//Discord Bot -//require('./bot/discord/index.js') - -app.use(bodyParser.json()); -app.use(bodyParser.urlencoded({extended: true})); - -server.listen(PORT, function () { - console.log(chalk.green("Listening on port " + PORT)); +const nodemailer = require('nodemailer'); +let transport = nodemailer.createTransport({ + host: config.Email.Host, + port: config.Email.Port, + auth: { + user: config.Email.User, + pass: config.Email.Password + } }); -app.get('/data', function (req, res) { - //console.log(req.query); - - //Write data to JSON file after checking the servers Hostname. - var data = JSON.stringify(req.query); - fs.writeFileSync('data/' + req.query.servername + '.json', data); - -}); -//Discord bot +//Discord Bot var node = require('nodeactyl-beta'); global.DanBotHosting = node.Application; +global.DanBotHostingClient = node.Client; global.Discord = require("discord.js"); const client = new Discord.Client() global.fs = require("fs"); global.moment = require("moment"); +let db = require("quick.db"); +global.userData = new db.table("userData") //Event handler fs.readdir('./bot/discord/events/', (err, files) => { @@ -54,33 +48,53 @@ fs.readdir('./bot/discord/events/', (err, files) => { }); }); -//Command handler -client.on('message', message => { - - const prefix = config.DiscordBot.Prefix; - if (message.content.indexOf(prefix) !== 0) return; - const args = message.content.slice(prefix.length).trim().split(/ +/g); - const commandargs = message.content.split(' ').slice(1).join(' '); - const command = args.shift().toLowerCase(); - console.log(`[${message.author.username}] [${message.author.id}] >> ${prefix}${command} ${commandargs}`); - try { - let commandFile = require(`./bot/discord/commands/${command}.js`); - commandFile.run(client, message, args); - } catch (err) { - if (err instanceof Error && err.code === "MODULE_NOT_FOUND") { - return console.log(err) - } - } -}) +//Disconnected from discord. Probs time to restart while disconnected. +//client.on('reconnecting', () => console.log('Disconnected from discord. Restarting...'), process.exit()); //Logging into pterodactyl using Nodeactyl DanBotHosting.login(config.Pterodactyl.hosturl, config.Pterodactyl.apikey, (logged_in) => { - console.log("Nodeactyl logged in? " + logged_in); + console.log(chalk.magenta('[APP] ') + chalk.green("Nodeactyl logged in? " + logged_in)); +}); +DanBotHostingClient.login(config.Pterodactyl.hosturl, config.Pterodactyl.apikeyclient, (logged_in) => { + console.log(chalk.magenta('[CLIENT] ') + chalk.green("Nodeactyl logged in? " + logged_in)); }); //Bot login client.login(config.DiscordBot.Token); +//Test Email +//const message = { +// from: config.Email.From, +// to: 'danielpd93@gmail.com', +// subject: 'DanBot Hosting Webpage and Discord Bot now online!', +// html: "DanBot Hosting Stats page is now online!" +//}; +//transport.sendMail(message, function(err, info) { +// if (err) { +// console.log(err) +// } else { +// console.log(info); +// } +//}); + + +app.use(bodyParser.json()); +app.use(bodyParser.urlencoded({extended: true})); + +server.listen(PORT, function () { + console.log(chalk.magenta('[WEB] ') + chalk.green("Listening on port " + PORT)); +}); + +app.get('/data', function (req, res) { + if (req.query.servername == undefined) { + var data = JSON.stringify(req.query); + fs.writeFileSync('data/' + req.query.speedname + '-speedtest.json', data); + } else { + var data = JSON.stringify(req.query); + fs.writeFileSync('data/' + req.query.servername + '.json', data); + } +}); + //View engine setup hbs.registerPartials(__dirname + '/views/partials') app.set('view engine', 'hbs'); @@ -91,29 +105,36 @@ app.get("/", (req, res) => { //Data for node 1 var N1 = fs.readFileSync('./data/0286b2ad-dc80-4b5c-a0de-b81945b010e8.json', 'utf8'); var Node1 = JSON.parse(N1); + var N1speed = fs.readFileSync('./data/0286b2ad-dc80-4b5c-a0de-b81945b010e8-speedtest.json', 'utf8'); + var Node1speed = JSON.parse(N1speed); //Data for node 2 var N2 = fs.readFileSync('./data/2e3f071a-af2b-4dc9-be5a-7ce72590a181.json', 'utf8'); var Node2 = JSON.parse(N2); + var N2speed = fs.readFileSync('./data/2e3f071a-af2b-4dc9-be5a-7ce72590a181-speedtest.json', 'utf8'); + var Node2speed = JSON.parse(N2speed); //Data for node 3 - var N3 = fs.readFileSync('./data/6fc3e9bf-24a8-47cd-99d3-fa159e05a9f4.json', 'utf8'); + var N3 = fs.readFileSync('./data/bed240f5-7c87-4013-90ee-a5bbc21f60da.json', 'utf8'); var Node3 = JSON.parse(N3); + var N3speed = fs.readFileSync('./data/bed240f5-7c87-4013-90ee-a5bbc21f60da-speedtest.json', 'utf8'); + var Node3speed = JSON.parse(N3speed); - //Data for node 4 - var N4 = fs.readFileSync('./data/15ffcdd0-a021-4ded-977d-284d777330a0.json', 'utf8'); + //Data for node 4 (Private) + var N4 = fs.readFileSync('./data/Server-01.json', 'utf8'); var Node4 = JSON.parse(N4); - - //Data for node 5 (Private) - var N5 = fs.readFileSync('./data/Server-01.json', 'utf8'); - var Node5 = JSON.parse(N5); + var N4speed = fs.readFileSync('./data/Server-01-speedtest.json', 'utf8'); + var Node4speed = JSON.parse(N4speed); res.render('index', { layout: false, Node1Data: Node1, Node2Data: Node2, Node3Data: Node3, Node4Data: Node4, - Node5Data: Node5 + Node1DataSpeed: Node1speed, + Node2DataSpeed: Node2speed, + Node3DataSpeed: Node3speed, + Node4DataSpeed: Node4speed }); }); @@ -122,9 +143,12 @@ app.get("/Node1", (req, res) => { //Data for node 1 var N1 = fs.readFileSync('./data/0286b2ad-dc80-4b5c-a0de-b81945b010e8.json', 'utf8'); var Node1 = JSON.parse(N1); + var N1speed = fs.readFileSync('./data/0286b2ad-dc80-4b5c-a0de-b81945b010e8-speedtest.json', 'utf8'); + var Node1speed = JSON.parse(N1speed); res.render('node1', { layout: false, - Node1Data: Node1 + Node1Data: Node1, + Node1DataSpeed: Node1speed }); }); @@ -133,44 +157,43 @@ app.get("/Node2", (req, res) => { //Data for node 2 var N2 = fs.readFileSync('./data/2e3f071a-af2b-4dc9-be5a-7ce72590a181.json', 'utf8'); var Node2 = JSON.parse(N2); + var N2speed = fs.readFileSync('./data/2e3f071a-af2b-4dc9-be5a-7ce72590a181-speedtest.json', 'utf8'); + var Node2speed = JSON.parse(N2speed); res.render('node2', { layout: false, - Node2Data: Node2 + Node2Data: Node2, + Node2DataSpeed: Node2speed }); }); app.get("/Node3", (req, res) => { //Data for node 3 - var N3 = fs.readFileSync('./data/6fc3e9bf-24a8-47cd-99d3-fa159e05a9f4.json', 'utf8'); + var N3 = fs.readFileSync('./data/bed240f5-7c87-4013-90ee-a5bbc21f60da.json', 'utf8'); var Node3 = JSON.parse(N3); + var N3speed = fs.readFileSync('./data/bed240f5-7c87-4013-90ee-a5bbc21f60da-speedtest.json', 'utf8'); + var Node3speed = JSON.parse(N3speed); res.render('node3', { layout: false, - Node3Data: Node3 + Node3Data: Node3, + Node3DataSpeed: Node3speed }); }); app.get("/Node4", (req, res) => { //Data for node 4 - var N4 = fs.readFileSync('./data/15ffcdd0-a021-4ded-977d-284d777330a0.json', 'utf8'); + var N4 = fs.readFileSync('./data/Server-01.json', 'utf8'); var Node4 = JSON.parse(N4); + var N4speed = fs.readFileSync('./data/Server-01-speedtest.json', 'utf8'); + var Node4speed = JSON.parse(N4speed); res.render('node4', { layout: false, - Node4Data: Node4 + Node4Data: Node4, + Node4DataSpeed: Node4speed }); }); -app.get("/Node5", (req, res) => { - - //Data for node 5 - var N5 = fs.readFileSync('./data/Server-01.json', 'utf8'); - var Node5 = JSON.parse(N5); - - res.render('node5', { layout: false, - Node5Data: Node5 -}); -}); //Catch 404 and forward to error handler app.use(function(req, res, next) { diff --git a/Panel/package.json b/Panel/package.json index eb1c9e346..2b91b2d38 100644 --- a/Panel/package.json +++ b/Panel/package.json @@ -1,21 +1,21 @@ { - "name": "servermontior", - "version": "1.0.0", - "description": "A software that runs a local web server to show system info, E.G: CPU Graph, Memory Graph along with more helpful info. Good for anyone who has multiple servers/computers like me and needs some way to monitor them from a single or multiple computers. ", + "name": "danbothostingstats", + "version": "1.0.1", + "description": "A modified version of ServerMonitor by danielpmc. ", "main": "index.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1" }, "repository": { "type": "git", - "url": "git+https://github.com/danielpmc/ServerMonitor.git" + "url": "git+https://github.com/danbot-devs/DanBotHostingStats.git" }, - "author": "danielpmc", + "author": "danbot-devs", "license": "MIT", "bugs": { - "url": "https://github.com/danielpmc/ServerMonitor/issues" + "url": "https://github.com/danbot-devs/DanBotHostingStats/issues" }, - "homepage": "https://github.com/danielpmc/ServerMonitor#readme", + "homepage": "https://github.com/danbot-devs/DanBotHostingStats#readme", "dependencies": { "body-parser": "latest", "chalk": "^3.0.0", @@ -28,6 +28,8 @@ "http": "latest", "moment": "^2.24.0", "nodeactyl-beta": "0.0.10", + "nodemailer": "^6.4.6", + "quick.db": "^7.1.1", "socket.io": "latest", "validator": "^13.0.0" } diff --git a/Panel/views/index.hbs b/Panel/views/index.hbs index 82a090bc8..056b2149e 100644 --- a/Panel/views/index.hbs +++ b/Panel/views/index.hbs @@ -47,6 +47,9 @@
Last Updated: {{Node1Data.updatetime}}
+
+
Speedtest (Updates every 6hours) | Ping: {{Node1DataSpeed.ping}}, Download: {{Node1DataSpeed.download}}, Upload: {{Node1DataSpeed.upload}}
+

Node 2 Stats

@@ -72,6 +75,9 @@
Last Updated: {{Node2Data.updatetime}}
+
+
Speedtest (Updates every 6hours) | Ping: {{Node2DataSpeed.ping}}, Download: {{Node2DataSpeed.download}}, Upload: {{Node2DataSpeed.upload}}
+

Node 3 Stats

@@ -97,9 +103,12 @@
Last Updated: {{Node3Data.updatetime}}
+
+
Speedtest (Updates every 6hours) | Ping: {{Node3DataSpeed.ping}}, Download: {{Node3DataSpeed.download}}, Upload: {{Node3DataSpeed.upload}}
+
CPU: {{Node4Data.cpu}} (Cores: {{Node4Data.cpucores}}, Threads: {{Node4Data.cputhreads}})
@@ -122,30 +131,8 @@
Last Updated: {{Node4Data.updatetime}}
- - -
-
CPU: {{Node5Data.cpu}} (Cores: {{Node5Data.cpucores}}, Threads: {{Node5Data.cputhreads}})
-
-
-
CPU Load: {{Node5Data.cpuload}}%
-
-
-
RAM (Used/Total) {{Node5Data.memused}} / {{Node5Data.memtotal}}
-
-
-
Host storage drive (Used/Total): {{Node5Data.diskused}} / {{Node5Data.disktotal}}
-
-
-
Network: Rx: {{Node5Data.netrx}} Tx: {{Node5Data.nettx}}
-
-
-
Uptime: {{Node5Data.osuptime}}
-
-
Last Updated: {{Node5Data.updatetime}}
+
Speedtest (Updates every 6hours) | Ping: {{Node4DataSpeed.ping}}, Download: {{Node4DataSpeed.download}}, Upload: {{Node4DataSpeed.upload}}
\ No newline at end of file diff --git a/Panel/views/node1.hbs b/Panel/views/node1.hbs index f28118eb6..6da36ed4b 100644 --- a/Panel/views/node1.hbs +++ b/Panel/views/node1.hbs @@ -45,6 +45,9 @@
Uptime: {{Node1Data.osuptime}}
+
+
Speedtest (Updates every 6hours) | Ping: {{Node1DataSpeed.ping}}, Download: {{Node1DataSpeed.download}}, Upload: {{Node1DataSpeed.upload}}
+
\ No newline at end of file diff --git a/Panel/views/node2.hbs b/Panel/views/node2.hbs index a2b85bee7..e39df4f2e 100644 --- a/Panel/views/node2.hbs +++ b/Panel/views/node2.hbs @@ -45,6 +45,9 @@
Uptime: {{Node2Data.osuptime}}
+
+
Speedtest (Updates every 6hours) | Ping: {{Node2DataSpeed.ping}}, Download: {{Node2DataSpeed.download}}, Upload: {{Node2DataSpeed.upload}}
+
\ No newline at end of file diff --git a/Panel/views/node3.hbs b/Panel/views/node3.hbs index d974d2c1b..225dd5ba1 100644 --- a/Panel/views/node3.hbs +++ b/Panel/views/node3.hbs @@ -45,6 +45,9 @@
Uptime: {{Node3Data.osuptime}}
+
+
Speedtest (Updates every 6hours) | Ping: {{Node3DataSpeed.ping}}, Download: {{Node3DataSpeed.download}}, Upload: {{Node3DataSpeed.upload}}
+
\ No newline at end of file diff --git a/Panel/views/node4.hbs b/Panel/views/node4.hbs index bea8c90b4..3c82842a3 100644 --- a/Panel/views/node4.hbs +++ b/Panel/views/node4.hbs @@ -25,7 +25,7 @@
All host stats
-

Node 4 Stats

+

Node 4 Stats (Private, Home dedi)

CPU: {{Node4Data.cpu}} (Cores: {{Node4Data.cpucores}}, Threads: {{Node4Data.cputhreads}})
@@ -45,6 +45,9 @@
Uptime: {{Node4Data.osuptime}}
+
+
Speedtest (Updates every 6hours) | Ping: {{Node4DataSpeed.ping}}, Download: {{Node4DataSpeed.download}}, Upload: {{Node4DataSpeed.upload}}
+
\ No newline at end of file diff --git a/Panel/views/node5.hbs b/Panel/views/node5.hbs deleted file mode 100644 index 191d8138b..000000000 --- a/Panel/views/node5.hbs +++ /dev/null @@ -1,50 +0,0 @@ - -Node 5 (Private) - DanBot Hosting Stats - - - - - - -
- All host stats -
-

Node 5 Stats (Private)

-
-
-
CPU: {{Node5Data.cpu}} (Cores: {{Node5Data.cpucores}}, Threads: {{Node5Data.cputhreads}})
-
-
-
CPU Load: {{Node5Data.cpuload}}%
-
-
-
RAM (Used/Total) {{Node5Data.memused}} / {{Node5Data.memtotal}}
-
-
-
Host storage drive (Used/Total): {{Node5Data.diskused}} / {{Node5Data.disktotal}}
-
-
-
Network: Rx: {{Node5Data.netrx}} Tx: {{Node5Data.nettx}}
-
-
-
Uptime: {{Node5Data.osuptime}}
-
- -
- \ No newline at end of file From 4be57645a68280b322d8199282ce1e09e99b2f54 Mon Sep 17 00:00:00 2001 From: danielpmc Date: Fri, 22 May 2020 16:37:41 +0100 Subject: [PATCH 007/255] Added last update time to speedtest data --- Panel/views/index.hbs | 10 +++++----- Panel/views/node1.hbs | 2 +- Panel/views/node2.hbs | 2 +- Panel/views/node3.hbs | 2 +- Panel/views/node4.hbs | 2 +- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/Panel/views/index.hbs b/Panel/views/index.hbs index 056b2149e..19a5cb921 100644 --- a/Panel/views/index.hbs +++ b/Panel/views/index.hbs @@ -48,12 +48,12 @@
Last Updated: {{Node1Data.updatetime}}
-
Speedtest (Updates every 6hours) | Ping: {{Node1DataSpeed.ping}}, Download: {{Node1DataSpeed.download}}, Upload: {{Node1DataSpeed.upload}}
+
Speedtest (Updates every 6hours) | Ping: {{Node1DataSpeed.ping}}, Download: {{Node1DataSpeed.download}}, Upload: {{Node1DataSpeed.upload}}, Last Updated: {{Node1DataSpeed.updatetime}}
+
CPU: {{Node2Data.cpu}} (Cores: {{Node2Data.cpucores}}, Threads: {{Node2Data.cputhreads}})
@@ -76,7 +76,7 @@
Last Updated: {{Node2Data.updatetime}}
-
Speedtest (Updates every 6hours) | Ping: {{Node2DataSpeed.ping}}, Download: {{Node2DataSpeed.download}}, Upload: {{Node2DataSpeed.upload}}
+
Speedtest (Updates every 6hours) | Ping: {{Node2DataSpeed.ping}}, Download: {{Node2DataSpeed.download}}, Upload: {{Node2DataSpeed.upload}}, Last Updated: {{Node2DataSpeed.updatetime}}
@@ -104,7 +104,7 @@
Last Updated: {{Node3Data.updatetime}}
-
Speedtest (Updates every 6hours) | Ping: {{Node3DataSpeed.ping}}, Download: {{Node3DataSpeed.download}}, Upload: {{Node3DataSpeed.upload}}
+
Speedtest (Updates every 6hours) | Ping: {{Node3DataSpeed.ping}}, Download: {{Node3DataSpeed.download}}, Upload: {{Node3DataSpeed.upload}}, Last Updated: {{Node3DataSpeed.updatetime}}
@@ -132,7 +132,7 @@
Last Updated: {{Node4Data.updatetime}}
-
Speedtest (Updates every 6hours) | Ping: {{Node4DataSpeed.ping}}, Download: {{Node4DataSpeed.download}}, Upload: {{Node4DataSpeed.upload}}
+
Speedtest (Updates every 6hours) | Ping: {{Node4DataSpeed.ping}}, Download: {{Node4DataSpeed.download}}, Upload: {{Node4DataSpeed.upload}}, Last Updated: {{Node4DataSpeed.updatetime}}
\ No newline at end of file diff --git a/Panel/views/node1.hbs b/Panel/views/node1.hbs index 6da36ed4b..29696a0e1 100644 --- a/Panel/views/node1.hbs +++ b/Panel/views/node1.hbs @@ -46,7 +46,7 @@
Uptime: {{Node1Data.osuptime}}
-
Speedtest (Updates every 6hours) | Ping: {{Node1DataSpeed.ping}}, Download: {{Node1DataSpeed.download}}, Upload: {{Node1DataSpeed.upload}}
+
Speedtest (Updates every 6hours) | Ping: {{Node1DataSpeed.ping}}, Download: {{Node1DataSpeed.download}}, Upload: {{Node1DataSpeed.upload}}, Last Updated: {{Node1DataSpeed.updatetime}}
diff --git a/Panel/views/node2.hbs b/Panel/views/node2.hbs index e39df4f2e..6dae1de53 100644 --- a/Panel/views/node2.hbs +++ b/Panel/views/node2.hbs @@ -46,7 +46,7 @@
Uptime: {{Node2Data.osuptime}}
-
Speedtest (Updates every 6hours) | Ping: {{Node2DataSpeed.ping}}, Download: {{Node2DataSpeed.download}}, Upload: {{Node2DataSpeed.upload}}
+
Speedtest (Updates every 6hours) | Ping: {{Node2DataSpeed.ping}}, Download: {{Node2DataSpeed.download}}, Upload: {{Node2DataSpeed.upload}}, Last Updated: {{Node2DataSpeed.updatetime}}
diff --git a/Panel/views/node3.hbs b/Panel/views/node3.hbs index 225dd5ba1..8d354681e 100644 --- a/Panel/views/node3.hbs +++ b/Panel/views/node3.hbs @@ -46,7 +46,7 @@
Uptime: {{Node3Data.osuptime}}
-
Speedtest (Updates every 6hours) | Ping: {{Node3DataSpeed.ping}}, Download: {{Node3DataSpeed.download}}, Upload: {{Node3DataSpeed.upload}}
+
Speedtest (Updates every 6hours) | Ping: {{Node3DataSpeed.ping}}, Download: {{Node3DataSpeed.download}}, Upload: {{Node3DataSpeed.upload}}, Last Updated: {{Node3DataSpeed.updatetime}}
diff --git a/Panel/views/node4.hbs b/Panel/views/node4.hbs index 3c82842a3..ca56c0758 100644 --- a/Panel/views/node4.hbs +++ b/Panel/views/node4.hbs @@ -46,7 +46,7 @@
Uptime: {{Node4Data.osuptime}}
-
Speedtest (Updates every 6hours) | Ping: {{Node4DataSpeed.ping}}, Download: {{Node4DataSpeed.download}}, Upload: {{Node4DataSpeed.upload}}
+
Speedtest (Updates every 6hours) | Ping: {{Node4DataSpeed.ping}}, Download: {{Node4DataSpeed.download}}, Upload: {{Node4DataSpeed.upload}}, Last Updated: {{Node4DataSpeed.updatetime}}
From 1eca6762422afc9e2ed008d4e726ede04154f6a4 Mon Sep 17 00:00:00 2001 From: danielpmc Date: Sun, 24 May 2020 09:02:17 +0100 Subject: [PATCH 008/255] Bot now pings the user and tells then a channel has been created for them... Also links accounts when accounts are created. --- Panel/bot/discord/commands/getstarted.js | 22 ++++++++++++++++++++-- Panel/bot/discord/commands/link.js | 2 +- Panel/bot/discord/commands/own.js | 14 ++++++++++++++ Panel/bot/discord/commands/tickets.js | 1 + Panel/bot/discord/events/message.js | 1 + Panel/views/index.hbs | 1 + 6 files changed, 38 insertions(+), 3 deletions(-) create mode 100644 Panel/bot/discord/commands/own.js diff --git a/Panel/bot/discord/commands/getstarted.js b/Panel/bot/discord/commands/getstarted.js index 43c4bde80..6e51017ac 100644 --- a/Panel/bot/discord/commands/getstarted.js +++ b/Panel/bot/discord/commands/getstarted.js @@ -34,6 +34,7 @@ exports.run = async (client, message) => { deny: 1024 } ]).catch(console.error); + message.reply(`Please check ${channel.id} to create an account.`) let category = server.channels.find(c => c.id == "697585283214082078" && c.type == "category"); if (!category) throw new Error("Category channel does not exist"); @@ -118,8 +119,6 @@ exports.run = async (client, message) => { DanBotHosting.createUser(collected1.first().content, password, collected2.first().content, collected1.first().content, ".", false, "en").then(user => { - console.log(user) - if (user == "Error: User already exists! (Or Email/Username is existing already)") { msg.edit("ERROR: A user with that email/username already exists.", null) setTimeout(function () { @@ -139,6 +138,25 @@ exports.run = async (client, message) => { channel.delete(); }, 3600000); + //Account Linking. + consoleUser = consoleUser.filter(x => x.attributes.email == collected2.first().content) + console.log(consoleUser) + + if (consoleUser.length == 0) return console.log(chalk.magenta('[DISCORD] ') + chalk.green("No account with that email exists...")).then( + ) + + consoleUser = consoleUser[0]; + const timestamp = `${moment().format("HH:mm:ss")}`; + const datestamp = `${moment().format("YYYY-MM-DD")}`; + userData.set(`${message.author.id}`, { + discordID: message.author.id, + consoleID: consoleUser.attributes.id, + email: consoleUser.attributes.email, + username: consoleUser.attributes.username, + linkTime: timestamp, + linkDate: datestamp + }) + }).catch(err => { console.log(err); }) diff --git a/Panel/bot/discord/commands/link.js b/Panel/bot/discord/commands/link.js index 19cb941e0..856187b70 100644 --- a/Panel/bot/discord/commands/link.js +++ b/Panel/bot/discord/commands/link.js @@ -22,7 +22,7 @@ exports.run = async (client, message) => { deny: 1024 } ]).catch(console.error); - message.channel.send(`<@${message.author.id}>, Please check <#${channel.id}> to link your account.`) + message.reply(`Please check ${channel.id} to link your account.`) let category = server.channels.find(c => c.id == "697585283214082078" && c.type == "category"); if (!category) throw new Error("Category channel does not exist"); diff --git a/Panel/bot/discord/commands/own.js b/Panel/bot/discord/commands/own.js new file mode 100644 index 000000000..593b14118 --- /dev/null +++ b/Panel/bot/discord/commands/own.js @@ -0,0 +1,14 @@ +exports.run = async (client, message) => { + if (userData.get(message.author.id) == null) { + message.channel.send("You can't use this command as your account is not linked. You can link it with: `" + config.DiscordBot.Prefix + "link`") + } else { + let consoleUser = await DanBotHosting.getAllServers(); + consoleUser = consoleUser.filter(x => x.attributes.user == userData.fetch(message.author.id + ".consoleID")) + + let embed = new Discord.RichEmbed() + .setColor(`GREEN`) + .addField(`__**Server's you own:**__`, userData.fetch(message.author.id + ".username")) + //message.channel.send('Your account is linked. Heres some data: ', embed) + console.log(consoleUser) + } +}; \ No newline at end of file diff --git a/Panel/bot/discord/commands/tickets.js b/Panel/bot/discord/commands/tickets.js index f56256d58..e9f239b02 100644 --- a/Panel/bot/discord/commands/tickets.js +++ b/Panel/bot/discord/commands/tickets.js @@ -27,6 +27,7 @@ exports.run = async (client, message) => { allow: 84992 } ]).catch(console.error); + message.reply(`Please check ${channel.id} for your ticket.`) let category = server.channels.find(c => c.id == "654313162086285323" && c.type == "category"); if (!category) throw new Error("Category channel does not exist"); diff --git a/Panel/bot/discord/events/message.js b/Panel/bot/discord/events/message.js index 1e1221907..b45f2cd9f 100644 --- a/Panel/bot/discord/events/message.js +++ b/Panel/bot/discord/events/message.js @@ -1,5 +1,6 @@ module.exports = (client, message) => { if(message.content.toLowerCase().includes("tiktok")) { message.delete() } + if(message.content.toLowerCase().includes("discord.gg")) { message.delete() } const prefix = config.DiscordBot.Prefix; if (message.content.indexOf(prefix) !== 0) return; const args = message.content.slice(prefix.length).trim().split(/ +/g); diff --git a/Panel/views/index.hbs b/Panel/views/index.hbs index 19a5cb921..c68cc1cfe 100644 --- a/Panel/views/index.hbs +++ b/Panel/views/index.hbs @@ -1,6 +1,7 @@ DanBot Hosting Stats +Fork me on GitHub + + + +
+ + + + + + + DanBot Hosting Stats + + + + + + +
+

+ You need JavaScript enabled to view this page :( +

+
+
+
+ + + +
\ No newline at end of file From fa555d87207879b420f2880853953cafc78150f5 Mon Sep 17 00:00:00 2001 From: danielpmc Date: Sun, 28 Jun 2020 15:52:35 +0100 Subject: [PATCH 017/255] A big update --- .gitignore | 3 +- DBH-Daemon/config.json | 17 - DBH-Daemon/index.js | 422 ------ DBH-Daemon/package-lock.json | 1364 -------------------- DBH-Daemon/package.json | 25 - {BetaDaemon => Daemon}/config.json | 0 {BetaDaemon => Daemon}/index.js | 4 +- {BetaDaemon => Daemon}/package.json | 0 Panel/bot/discord/commands/eval.js | 2 +- Panel/bot/discord/commands/exec.js | 2 +- Panel/bot/discord/commands/help.js | 6 +- Panel/bot/discord/commands/link.js | 5 +- Panel/bot/discord/commands/say.js | 2 +- Panel/bot/discord/commands/ticket.js | 2 +- Panel/bot/discord/events/guildMemberAdd.js | 49 +- Panel/bot/discord/events/message.js | 6 +- Panel/bot/discord/events/messageDelete.js | 4 +- Panel/bot/discord/events/messageUpdate.js | 36 +- Panel/bot/discord/events/ready.js | 47 +- Panel/bot/discord/tickets/ticketModule.js | 3 + Panel/index.js | 26 +- Panel/package.json | 3 +- Panel/package.zip | Bin 63093 -> 0 bytes Panel/test.js | 12 +- Panel/views/index.hbs | 36 +- Panel/views/node1.hbs | 3 + Panel/views/node2.hbs | 3 + Panel/views/node3.hbs | 3 + Panel/views/node4.hbs | 3 + 29 files changed, 153 insertions(+), 1935 deletions(-) delete mode 100644 DBH-Daemon/config.json delete mode 100644 DBH-Daemon/index.js delete mode 100644 DBH-Daemon/package-lock.json delete mode 100644 DBH-Daemon/package.json rename {BetaDaemon => Daemon}/config.json (100%) rename {BetaDaemon => Daemon}/index.js (99%) rename {BetaDaemon => Daemon}/package.json (100%) create mode 100644 Panel/bot/discord/tickets/ticketModule.js delete mode 100644 Panel/package.zip diff --git a/.gitignore b/.gitignore index ab9280538..abcb4e4c7 100644 --- a/.gitignore +++ b/.gitignore @@ -9,5 +9,4 @@ Panel/json.sqlite Daemon/node_modules Daemon/package-lock.json -BetaDaemon/node_modules -BetaDaemon/package-lock.json +test/ \ No newline at end of file diff --git a/DBH-Daemon/config.json b/DBH-Daemon/config.json deleted file mode 100644 index db8382705..000000000 --- a/DBH-Daemon/config.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "panelip": "154.27.68.232", - "panelport": "1144", - "debug": true, - "panelping": true, - "panelms": 5000, - - "Discord": false, - "DiscordWebhook": "No webhook token", - - "SystemIPs": [ - "192.168.1.175", - "173.249.33.82" - ], - - "Docker": false -} \ No newline at end of file diff --git a/DBH-Daemon/index.js b/DBH-Daemon/index.js deleted file mode 100644 index 27d3ff905..000000000 --- a/DBH-Daemon/index.js +++ /dev/null @@ -1,422 +0,0 @@ -/* _____ __ __ _ _ - / ____| | \/ | (_)| | - | (___ ___ _ __ __ __ ___ _ __ | \ / | ___ _ __ _ | |_ ___ _ __ - \___ \ / _ \| '__|\ \ / // _ \| '__|| |\/| | / _ \ | '_ \ | || __|/ _ \ | '__| - ____) || __/| | \ V /| __/| | | | | || (_) || | | || || |_| (_) || | - |_____/ \___||_| \_/ \___||_| |_| |_| \___/ |_| |_||_| \__|\___/ |_| - Free Monitoring software made by danielpmc -*/ - -var PORT = 2001; -var app = require('express')(); -var server = require('http').createServer(app); -var request = require("request"); -var si = require('systeminformation'); -var os = require("os"); -var pretty = require('prettysize'); -var ping = require('node-http-ping'); -var package = require("./package.json"); -var config = require("./config.json"); -var { get } = require('superagent') -var chalk = require('chalk'); -var moment = require("moment"); -const speedTest = require('speedtest-net'); - -server.listen(PORT, function () { - console.log(chalk.blueBright("The servers hostname is: " + chalk.green(os.hostname) + ", Please put this in the config file")) - console.log(PORT + " listening..."); - ping('0.0.0.0', 2001) - - //Config file checking - if (config.panelip == "Your panel ip here") { - //Log that the ip has not been set and process will exit. - console.log(chalk.red("Your panel ip has not been set in config.json. Please set the panel ip.")) - process.exit(); - } else { - //Panel ip has been set. Ping the panel and see if its alive. - ping(config.panelip, config.panelport) - .then(time => console.log(chalk.green(`Panel is online! Response time: ${time}ms`))) - .catch(() => console.log(chalk.red(`Failed to ping the panel. Please check if the panel is running!`)) + process.exit()) - } -}); - -if (config.panelping == true) { - //User requested to ping the panel every x ms - setInterval(async () => { - var timestamp = `${moment().format("YYYY-MM-DD HH:mm:ss")}`; - ping(config.panelip, config.panelport) - .then(time => console.log(chalk.white(`[${timestamp}] Panel Pinger: ` + chalk.green(`Response time: ${time}ms`)))) - .catch(() => console.log(chalk.white(`[${timestamp}] Panel Pinger: ` + chalk.red(`Failed to ping the panel. Please check if the panel is running! `) + chalk.white("Will continue to ping panel.")))) - }, config.panelms) -} - - -app.get('/', async function (req, res) { - - setInterval(async () => { - //Data using the systeminformation package. - var memdata = await si.mem(); - var ramused = pretty(memdata.used); - var ramtotal = pretty(memdata.total); - var swapused = pretty(memdata.swapused); - var swaptotal = pretty(memdata.swaptotal); - var diskdata = await si.fsSize(); - var diskused = pretty(diskdata[0].used); - var disktotal = pretty(diskdata[0].size); - var netdata = await si.networkStats(); - var netrx = pretty(netdata[0].rx_bytes); - var nettx = pretty(netdata[0].tx_bytes); - var osdata = await si.osInfo(); - var bios = await si.bios(); - var docker = await si.dockerInfo(); - - //CPU data. - var cl = await si.currentLoad(); - var cpudata = await si.cpu(); - var cputhreads = cpudata.cores; - var cpucores = cpudata.physicalCores; - var cpumain = os.cpus().length > 0 ? os.cpus()[0].model : 'Uh oh. You dont have a cpu?'; - - //OS UPTIME - var uptime = os.uptime(); - var d = Math.floor(uptime / (3600*24)); - var h = Math.floor(uptime % (3600*24) / 3600); - var m = Math.floor(uptime % 3600 / 60); - var s = Math.floor(uptime % 60); - var dDisplay = d > 0 ? d + (d == 1 ? " day, " : " days, ") : ""; - var hDisplay = h > 0 ? h + (h == 1 ? " hour, " : " hours, ") : ""; - var mDisplay = m > 0 ? m + (m == 1 ? " minute, " : " minutes, ") : ""; - var sDisplay = s > 0 ? s + (s == 1 ? " second" : " seconds") : ""; - - //Version - var Version = package.version; - - //Fetch time that data was sent. (Used panel sided to check if server has gone offline) - var datatime = Date.now(); - - //Different errors - function discordchecker() { - if (config.Discord == true) { - if (config.DiscordWebhook == " ") { - console.log(chalk.red("Error: Discord webhooks are enabled but no url is valid. Please enter a valid url or go into the config file and change `Discord: true` to `Discord: false`")); - } else { - //Discord is enabled and webhook has a input. Check for discord webhook link. - var WebhookURL = ["https://discordapp.com/api/webhooks/", "https://canary.discordapp.com/api/webhooks/"] - if (WebhookURL.some(link => config.DiscordWebhook.includes(link))) { - //Webhook config has discord link. Check if link is valid. - get(config.DiscordWebhook).end((response) => { - console.log("Valid link") - - if (response.body.type == "1") { - console.log(chalk.green("Url valid")) - } else { - console.log(chalk.red("URL invalid.")) - } - }) - - } else { - //Post in console that there is no valid discord link. - console.log(chalk.red("Error: Discord webhooks are enabled but the text entered in the config is not a valid discord link.")); - } - } - } - } - - //Find system OS if windows and else linux (No MacOS support yet, Sorry Apple fans) - if (osdata.platform == "win32") { - discordchecker(); - if (config.Docker == true) { - if (docker.containers == "undefined") { - //Docker enabled but no docker found. - console.log(chalk.red("You enabled docker in the config but your system does not have docker installed. Please disable this!")); - process.exit(); - } else { - var timestamp = `${moment().format("YYYY-MM-DD HH:mm:ss")}`; - request({ - uri: "http://" + config.panelip + ":" + config.panelport + "/data?servername=" + os.hostname + //OS hostname for saving data panel sided. - "&cpu=" + cpumain + //CPU make and brand. - "&cpuload=" + cl.currentload.toFixed(2) + //CPU load but doesn't work on windows :( - "&cputhreads=" + cputhreads + //CPU threads. - "&cpucores=" + cpucores + //CPU cores - "&memused=" + ramused + //Ram used (Auto to MB, GB, TB) - "&memtotal=" + ramtotal + //Ram total (Auto to MB, GB, TB) - "&swapused=" + swapused + //Swap used (Auto to MB, GB, TB) - "&swaptotal=" + swaptotal + //Swap total (Auto to MB, GB, TB) - "&diskused=" + diskused + //Disk used (Auto to MB, GB, TB) - "&disktotal=" + disktotal + //Disk total (Auto to MB, GB, TB) - "&netrx=" + netrx + //Network received (Auto to MB, GB, TB) - "&nettx=" + nettx + //Network transmited (Auto to MB, GB, TB) - "&osplatform=" + osdata.platform + //OS platform (win32 or linux) - "&oslogofile=" + osdata.logofile + //OS logofile (Linux example: Debian/Ubuntu | Windows example: Windows) - "&osrelease=" + osdata.release + //OS release (Linux example: 9 | Windows example: 10.0.18362) - "&osuptime=" + dDisplay + hDisplay + mDisplay + sDisplay + //OS uptime (Day/Days, Hours/Hour, Minutes/Minute, Seconds/Second) - "&biosvendor=" + bios.vendor + //Bios vendor (Example: Dell Inc) - "&biosversion=" + bios.version + //Bios version (Example: A22.00) - "&biosdate=" + bios.releaseDate + //Bios release date (Example: 2018-11-29) - "&servermonitorversion=" + Version + //ServerMonitor version (Example: 1.0.1) - "&datatime=" + datatime + //Date and time (Example: 1578594094569) - "&dockercontainers=" + docker.containers + //Number of docker containers - "&dockercontainersrunning=" + docker.containersRunning + //Number of running docker containers - "&dockercontainerspaused=" + docker.containersPaused + //Number of paused docker containers - "&dockercontainersstopped=" + docker.containersStopped + //Number of stopped docker containers - "&updatetime= " + timestamp, //Last time the node sent data to the panel - method: "GET", - timeout: 5000, - followRedirect: true, - maxRedirects: 10 - }, function (error, response, body) { - - //Send data to panel - res.send(body); - - //Error checking. - if (error == "undefined") { - //No errors = Do nothing :D - } else if (error == "Error: ESOCKETTIMEDOUT") { - //Because Panel doesn't give response to Daemon it thinks it timed out. - //But really it didn't data was still sent. - //So ignore this error. - } else if (error == "Error: read ECONNRESET") { - //Do nothing because panel went down. Program will still continue to try and send data. - //So ignore this error. - } else if (error == "Error: connect ECONNREFUSED " + config.panelip + ":" + config.panelport) { - //Do nothing because panel went down. Program will still continue to try and send data. - //So ignore this error. - }else { - //Log the error in red and exit process - //console.log(chalk.red("ERROR! " + error)) - return; - } - - }); - } - } else { - var timestamp = `${moment().format("YYYY-MM-DD HH:mm:ss")}`; - request({ - uri: "http://" + config.panelip + ":" + config.panelport + "/data?servername=" + os.hostname + //OS hostname for saving data panel sided. - "&cpu=" + cpumain + //CPU make and brand. - "&cpuload=" + cl.currentload.toFixed(2) + //CPU load but doesn't work on windows :( - "&cputhreads=" + cputhreads + //CPU threads. - "&cpucores=" + cpucores + //CPU cores - "&memused=" + ramused + //Ram used (Auto to MB, GB, TB) - "&memtotal=" + ramtotal + //Ram total (Auto to MB, GB, TB) - "&swapused=" + swapused + //Swap used (Auto to MB, GB, TB) - "&swaptotal=" + swaptotal + //Swap total (Auto to MB, GB, TB) - "&diskused=" + diskused + //Disk used (Auto to MB, GB, TB) - "&disktotal=" + disktotal + //Disk total (Auto to MB, GB, TB) - "&netrx=" + netrx + //Network received (Auto to MB, GB, TB) - "&nettx=" + nettx + //Network transmited (Auto to MB, GB, TB) - "&osplatform=" + osdata.platform + //OS platform (win32 or linux) - "&oslogofile=" + osdata.logofile + //OS logofile (Linux example: Debian/Ubuntu | Windows example: Windows) - "&osrelease=" + osdata.release + //OS release (Linux example: 9 | Windows example: 10.0.18362) - "&osuptime=" + dDisplay + hDisplay + mDisplay + sDisplay + //OS uptime (Day/Days, Hours/Hour, Minutes/Minute, Seconds/Second) - "&biosvendor=" + bios.vendor + //Bios vendor (Example: Dell Inc) - "&biosversion=" + bios.version + //Bios version (Example: A22.00) - "&biosdate=" + bios.releaseDate + //Bios release date (Example: 2018-11-29) - "&servermonitorversion=" + Version + //ServerMonitor version (Example: 1.0.1) - "&updatetime= " + timestamp, //Last time the node sent data to the panel //Date and time (Example: 1578594094569) - method: "GET", - timeout: 5000, - followRedirect: true, - maxRedirects: 10 - }, function (error, response, body) { - - //Send data to panel - res.send(body); - - //Error checking. - if (error == "undefined") { - //No errors = Do nothing :D - } else if (error == "Error: ESOCKETTIMEDOUT") { - //Because Panel doesn't give response to Daemon it thinks it timed out. - //But really it didn't data was still sent. - //So ignore this error. - } else if (error == "Error: read ECONNRESET") { - //Do nothing because panel went down. Program will still continue to try and send data. - //So ignore this error. - } else if (error == "Error: connect ECONNREFUSED " + config.panelip + ":" + config.panelport) { - //Do nothing because panel went down. Program will still continue to try and send data. - //So ignore this error. - }else { - //Log the error in red and exit process - //console.log(chalk.red("ERROR! " + error)) - return; - } - - }); - } - } else if (osdata.platform == "linux") { - discordchecker(); - if (config.Docker == true) { - if (docker.containers == "undefined") { - //Docker enabled but no docker found. - console.log(chalk.red("You enabled docker in the config but your system does not have docker installed. Please disable this!")); - process.exit(); - } else { - var timestamp = `${moment().format("YYYY-MM-DD HH:mm:ss")}`; - request({ - uri: "http://" + config.panelip + ":" + config.panelport + "/data?servername=" + os.hostname + //OS hostname for saving data panel sided. - "&cpu=" + cpudata.manufacturer + " " + cpudata.brand + //CPU make and brand. - "&cpuload=" + cl.currentload.toFixed(2) + //CPU load but doesn't work on windows :( - "&cputhreads=" + cputhreads + //CPU threads. - "&cpucores=" + cpucores + //CPU cores - "&memused=" + ramused + //Ram used (Auto to MB, GB, TB) - "&memtotal=" + ramtotal + //Ram total (Auto to MB, GB, TB) - "&swapused=" + swapused + //Swap used (Auto to MB, GB, TB) - "&swaptotal=" + swaptotal + //Swap total (Auto to MB, GB, TB) - "&diskused=" + diskused + //Disk used (Auto to MB, GB, TB) - "&disktotal=" + disktotal + //Disk total (Auto to MB, GB, TB) - "&netrx=" + netrx + //Network received (Auto to MB, GB, TB) - "&nettx=" + nettx + //Network transmited (Auto to MB, GB, TB) - "&osplatform=" + osdata.platform + //OS platform (win32 or linux) - "&oslogofile=" + osdata.logofile + //OS logofile (Linux example: Debian/Ubuntu | Windows example: Windows) - "&osrelease=" + osdata.release + //OS release (Linux example: 9 | Windows example: 10.0.18362) - "&osuptime=" + dDisplay + hDisplay + mDisplay + sDisplay + //OS uptime (Day/Days, Hours/Hour, Minutes/Minute, Seconds/Second) - "&biosvendor=" + bios.vendor + //Bios vendor (Example: Dell Inc) - "&biosversion=" + bios.version + //Bios version (Example: A22.00) - "&biosdate=" + bios.releaseDate + //Bios release date (Example: 2018-11-29) - "&servermonitorversion=" + Version + //ServerMonitor version (Example: 1.0.1) - "&datatime=" + datatime + //Date and time (Example: 1578594094569) - "&dockercontainers=" + docker.containers + //Number of docker containers - "&dockercontainersrunning=" + docker.containersRunning + //Number of running docker containers - "&dockercontainerspaused=" + docker.containersPaused + //Number of paused docker containers - "&dockercontainersstopped=" + docker.containersStopped + //Number of stopped docker containers - "&updatetime= " + timestamp, //Last time the node sent data to the panel - method: "GET", - timeout: 5000, - followRedirect: true, - maxRedirects: 10 - }, function (error, response, body) { - - //Send data to panel - res.send(body); - - //Error checking. - if (error == "undefined") { - //No errors = Do nothing :D - } else if (error == "Error: ESOCKETTIMEDOUT") { - //Because Panel doesn't give response to Daemon it thinks it timed out. - //But really it didn't data was still sent. - //So ignore this error. - } else if (error == "Error: read ECONNRESET") { - //Do nothing because panel went down. Program will still continue to try and send data. - //So ignore this error. - } else if (error == "Error: ETIMEDOUT") { - //Do nothing because panel went down. Program will still continue to try and send data. - //So ignore this error. - }else { - //Log the error in red and exit process - //console.log(chalk.red("ERROR! " + error)) - return; - } - - }); - } - } else { - var timestamp = `${moment().format("YYYY-MM-DD HH:mm:ss")}`; - request({ - uri: "http://" + config.panelip + ":" + config.panelport + "/data?servername=" + os.hostname + //OS hostname for saving data panel sided. - "&cpu=" + cpudata.manufacturer + " " + cpudata.brand + //CPU make and brand. - "&cpuload=" + cl.currentload.toFixed(2) + //CPU load but doesn't work on windows :( - "&cputhreads=" + cputhreads + //CPU threads. - "&cpucores=" + cpucores + //CPU cores - "&memused=" + ramused + //Ram used (Auto to MB, GB, TB) - "&memtotal=" + ramtotal + //Ram total (Auto to MB, GB, TB) - "&swapused=" + swapused + //Swap used (Auto to MB, GB, TB) - "&swaptotal=" + swaptotal + //Swap total (Auto to MB, GB, TB) - "&diskused=" + diskused + //Disk used (Auto to MB, GB, TB) - "&disktotal=" + disktotal + //Disk total (Auto to MB, GB, TB) - "&netrx=" + netrx + //Network received (Auto to MB, GB, TB) - "&nettx=" + nettx + //Network transmited (Auto to MB, GB, TB) - "&osplatform=" + osdata.platform + //OS platform (win32 or linux) - "&oslogofile=" + osdata.logofile + //OS logofile (Linux example: Debian/Ubuntu | Windows example: Windows) - "&osrelease=" + osdata.release + //OS release (Linux example: 9 | Windows example: 10.0.18362) - "&osuptime=" + dDisplay + hDisplay + mDisplay + sDisplay + //OS uptime (Day/Days, Hours/Hour, Minutes/Minute, Seconds/Second) - "&biosvendor=" + bios.vendor + //Bios vendor (Example: Dell Inc) - "&biosversion=" + bios.version + //Bios version (Example: A22.00) - "&biosdate=" + bios.releaseDate + //Bios release date (Example: 2018-11-29) - "&servermonitorversion=" + Version + //ServerMonitor version (Example: 1.0.1) - "&updatetime= " + timestamp, //Last time the node sent data to the panel - method: "GET", - timeout: 5000, - followRedirect: true, - maxRedirects: 10 - }, function (error, response, body) { - - //Send data to panel - res.send(body); - - //Error checking. - if (error == "undefined") { - //No errors = Do nothing :D - } else if (error == "Error: ESOCKETTIMEDOUT") { - //Because Panel doesn't give response to Daemon it thinks it timed out. - //But really it didn't data was still sent. - //So ignore this error. - return; - } else if (error == "Error: read ECONNRESET") { - //Do nothing because panel went down. Program will still continue to try and send data. - //So ignore this error. - return; - } else if (error == "Error: ETIMEDOUT") { - //Do nothing because panel went down. Program will still continue to try and send data. - //So ignore this error. - return; - }else { - //Log the error in red and exit process - //console.log(chalk.red("ERROR! " + error)) - return; - } - - }); - } - - } else { - console.log("Your running a unsupported OS. :(") - process.exit(); - } - -}, 2500); - -setInterval(async () => { -var timestamp = `${moment().format("YYYY-MM-DD HH:mm:ss")}`; -const speed = await speedTest({maxTime: 5000}) -speed.on('data', async (data) => { -request({ - uri: "http://" + config.panelip + ":" + config.panelport + "/data?speedname=" + os.hostname + //OS hostname for saving data panel sided. - "&ping=" + data.server.ping + //Speedtest Ping. (MS) - "&download=" + data.speeds.download + //Download Speed (Mbps) - "&upload=" + data.speeds.upload + //Upload Speed (Mbps) - "&updatetime= " + timestamp, //Last time the node sent data to the panel //Date and time (Example: 1578594094569) - method: "GET", - timeout: 5000, - followRedirect: true, - maxRedirects: 10 -}, function (error, response, body) { - - //Send data to panel - res.send(body); - - //Error checking. - if (error == "undefined") { - //No errors = Do nothing :D - } else if (error == "Error: ESOCKETTIMEDOUT") { - //Because Panel doesn't give response to Daemon it thinks it timed out. - //But really it didn't data was still sent. - //So ignore this error. - } else if (error == "Error: read ECONNRESET") { - //Do nothing because panel went down. Program will still continue to try and send data. - //So ignore this error. - } else if (error == "Error: connect ECONNREFUSED " + config.panelip + ":" + config.panelport) { - //Do nothing because panel went down. Program will still continue to try and send data. - //So ignore this error. - }else { - //Log the error in red and exit process - //console.log(chalk.red("ERROR! " + error)) - return; - } -}); -}); -}, 21600000); -//}, 20000); -}); diff --git a/DBH-Daemon/package-lock.json b/DBH-Daemon/package-lock.json deleted file mode 100644 index c7770b109..000000000 --- a/DBH-Daemon/package-lock.json +++ /dev/null @@ -1,1364 +0,0 @@ -{ - "name": "servermonitor-fetch", - "version": "1.0.1", - "lockfileVersion": 1, - "requires": true, - "dependencies": { - "@types/color-name": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@types/color-name/-/color-name-1.1.1.tgz", - "integrity": "sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ==" - }, - "accepts": { - "version": "1.3.7", - "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz", - "integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==", - "requires": { - "mime-types": "~2.1.24", - "negotiator": "0.6.2" - } - }, - "after": { - "version": "0.8.2", - "resolved": "https://registry.npmjs.org/after/-/after-0.8.2.tgz", - "integrity": "sha1-/ts5T58OAqqXaOcCvaI7UF+ufh8=" - }, - "agent-base": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-4.3.0.tgz", - "integrity": "sha512-salcGninV0nPrwpGNn4VTXBb1SOuXQBiqbrNXoeizJsHrsL6ERFM2Ne3JUSBWRE6aeNJI2ROP/WEEIDUiDe3cg==", - "requires": { - "es6-promisify": "^5.0.0" - } - }, - "ajv": { - "version": "6.10.2", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.10.2.tgz", - "integrity": "sha512-TXtUUEYHuaTEbLZWIKUr5pmBuhDLy+8KYtPYdcV8qC+pOZL+NKqYwvWSRrVXHn+ZmRRAu8vJTAznH7Oag6RVRw==", - "requires": { - "fast-deep-equal": "^2.0.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - } - }, - "ansi-styles": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", - "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==", - "requires": { - "@types/color-name": "^1.1.1", - "color-convert": "^2.0.1" - } - }, - "array-flatten": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", - "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" - }, - "arraybuffer.slice": { - "version": "0.0.7", - "resolved": "https://registry.npmjs.org/arraybuffer.slice/-/arraybuffer.slice-0.0.7.tgz", - "integrity": "sha512-wGUIVQXuehL5TCqQun8OW81jGzAWycqzFF8lFp+GOM5BXLYj3bKNsYC4daB7n6XjCqxQA/qgTJ+8ANR3acjrog==" - }, - "asn1": { - "version": "0.2.4", - "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz", - "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==", - "requires": { - "safer-buffer": "~2.1.0" - } - }, - "assert-plus": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", - "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" - }, - "async-limiter": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.1.tgz", - "integrity": "sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==" - }, - "asynckit": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" - }, - "aws-sign2": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", - "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=" - }, - "aws4": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.9.0.tgz", - "integrity": "sha512-Uvq6hVe90D0B2WEnUqtdgY1bATGz3mw33nH9Y+dmA+w5DHvUmBgkr5rM/KCHpCsiFNRUfokW/szpPPgMK2hm4A==" - }, - "backo2": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/backo2/-/backo2-1.0.2.tgz", - "integrity": "sha1-MasayLEpNjRj41s+u2n038+6eUc=" - }, - "base64-arraybuffer": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-0.1.5.tgz", - "integrity": "sha1-c5JncZI7Whl0etZmqlzUv5xunOg=" - }, - "base64id": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/base64id/-/base64id-2.0.0.tgz", - "integrity": "sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog==" - }, - "bcrypt-pbkdf": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", - "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", - "requires": { - "tweetnacl": "^0.14.3" - } - }, - "better-assert": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/better-assert/-/better-assert-1.0.2.tgz", - "integrity": "sha1-QIZrnhueC1W0gYlDEeaPr/rrxSI=", - "requires": { - "callsite": "1.0.0" - } - }, - "blob": { - "version": "0.0.5", - "resolved": "https://registry.npmjs.org/blob/-/blob-0.0.5.tgz", - "integrity": "sha512-gaqbzQPqOoamawKg0LGVd7SzLgXS+JH61oWprSLH+P+abTczqJbhTR8CmJ2u9/bUYNmHTGJx/UEmn6doAvvuig==" - }, - "bluebird": { - "version": "2.11.0", - "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-2.11.0.tgz", - "integrity": "sha1-U0uQM8AiyVecVro7Plpcqvu2UOE=" - }, - "body-parser": { - "version": "1.19.0", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.0.tgz", - "integrity": "sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw==", - "requires": { - "bytes": "3.1.0", - "content-type": "~1.0.4", - "debug": "2.6.9", - "depd": "~1.1.2", - "http-errors": "1.7.2", - "iconv-lite": "0.4.24", - "on-finished": "~2.3.0", - "qs": "6.7.0", - "raw-body": "2.4.0", - "type-is": "~1.6.17" - } - }, - "bytes": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz", - "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==" - }, - "callsite": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/callsite/-/callsite-1.0.0.tgz", - "integrity": "sha1-KAOY5dZkvXQDi28JBRU+borxvCA=" - }, - "caseless": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", - "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=" - }, - "chalk": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", - "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" - }, - "combined-stream": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", - "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", - "requires": { - "delayed-stream": "~1.0.0" - } - }, - "component-bind": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/component-bind/-/component-bind-1.0.0.tgz", - "integrity": "sha1-AMYIq33Nk4l8AAllGx06jh5zu9E=" - }, - "component-emitter": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz", - "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=" - }, - "component-inherit": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/component-inherit/-/component-inherit-0.0.3.tgz", - "integrity": "sha1-ZF/ErfWLcrZJ1crmUTVhnbJv8UM=" - }, - "content-disposition": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.3.tgz", - "integrity": "sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g==", - "requires": { - "safe-buffer": "5.1.2" - } - }, - "content-type": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", - "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==" - }, - "cookie": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.0.tgz", - "integrity": "sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg==" - }, - "cookie-signature": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", - "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=" - }, - "cookiejar": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/cookiejar/-/cookiejar-2.1.2.tgz", - "integrity": "sha512-Mw+adcfzPxcPeI+0WlvRrr/3lGVO0bD75SxX6811cxSh1Wbxx7xZBGK1eVtDf6si8rg2lhnUjsVLMFMfbRIuwA==" - }, - "core-util-is": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" - }, - "dashdash": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", - "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", - "requires": { - "assert-plus": "^1.0.0" - } - }, - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "requires": { - "ms": "2.0.0" - } - }, - "delayed-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=" - }, - "depd": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", - "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=" - }, - "destroy": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", - "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=" - }, - "draftlog": { - "version": "1.0.12", - "resolved": "https://registry.npmjs.org/draftlog/-/draftlog-1.0.12.tgz", - "integrity": "sha1-fbajxbYhBrsy3Uo11nvMy2x9naA=" - }, - "ecc-jsbn": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", - "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=", - "requires": { - "jsbn": "~0.1.0", - "safer-buffer": "^2.1.0" - } - }, - "ee-first": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", - "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" - }, - "encodeurl": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", - "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=" - }, - "engine.io": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-3.4.0.tgz", - "integrity": "sha512-XCyYVWzcHnK5cMz7G4VTu2W7zJS7SM1QkcelghyIk/FmobWBtXE7fwhBusEKvCSqc3bMh8fNFMlUkCKTFRxH2w==", - "requires": { - "accepts": "~1.3.4", - "base64id": "2.0.0", - "cookie": "0.3.1", - "debug": "~4.1.0", - "engine.io-parser": "~2.2.0", - "ws": "^7.1.2" - }, - "dependencies": { - "cookie": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.3.1.tgz", - "integrity": "sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s=" - }, - "debug": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", - "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", - "requires": { - "ms": "^2.1.1" - } - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" - } - } - }, - "engine.io-client": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-3.4.0.tgz", - "integrity": "sha512-a4J5QO2k99CM2a0b12IznnyQndoEvtA4UAldhGzKqnHf42I3Qs2W5SPnDvatZRcMaNZs4IevVicBPayxYt6FwA==", - "requires": { - "component-emitter": "1.2.1", - "component-inherit": "0.0.3", - "debug": "~4.1.0", - "engine.io-parser": "~2.2.0", - "has-cors": "1.1.0", - "indexof": "0.0.1", - "parseqs": "0.0.5", - "parseuri": "0.0.5", - "ws": "~6.1.0", - "xmlhttprequest-ssl": "~1.5.4", - "yeast": "0.1.2" - }, - "dependencies": { - "debug": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", - "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", - "requires": { - "ms": "^2.1.1" - } - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" - }, - "ws": { - "version": "6.1.4", - "resolved": "https://registry.npmjs.org/ws/-/ws-6.1.4.tgz", - "integrity": "sha512-eqZfL+NE/YQc1/ZynhojeV8q+H050oR8AZ2uIev7RU10svA9ZnJUddHcOUZTJLinZ9yEfdA2kSATS2qZK5fhJA==", - "requires": { - "async-limiter": "~1.0.0" - } - } - } - }, - "engine.io-parser": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-2.2.0.tgz", - "integrity": "sha512-6I3qD9iUxotsC5HEMuuGsKA0cXerGz+4uGcXQEkfBidgKf0amsjrrtwcbwK/nzpZBxclXlV7gGl9dgWvu4LF6w==", - "requires": { - "after": "0.8.2", - "arraybuffer.slice": "~0.0.7", - "base64-arraybuffer": "0.1.5", - "blob": "0.0.5", - "has-binary2": "~1.0.2" - } - }, - "es6-promise": { - "version": "4.2.8", - "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz", - "integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==" - }, - "es6-promisify": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/es6-promisify/-/es6-promisify-5.0.0.tgz", - "integrity": "sha1-UQnWLz5W6pZ8S2NQWu8IKRyKUgM=", - "requires": { - "es6-promise": "^4.0.3" - } - }, - "escape-html": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", - "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" - }, - "escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" - }, - "etag": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", - "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=" - }, - "express": { - "version": "4.17.1", - "resolved": "https://registry.npmjs.org/express/-/express-4.17.1.tgz", - "integrity": "sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g==", - "requires": { - "accepts": "~1.3.7", - "array-flatten": "1.1.1", - "body-parser": "1.19.0", - "content-disposition": "0.5.3", - "content-type": "~1.0.4", - "cookie": "0.4.0", - "cookie-signature": "1.0.6", - "debug": "2.6.9", - "depd": "~1.1.2", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "finalhandler": "~1.1.2", - "fresh": "0.5.2", - "merge-descriptors": "1.0.1", - "methods": "~1.1.2", - "on-finished": "~2.3.0", - "parseurl": "~1.3.3", - "path-to-regexp": "0.1.7", - "proxy-addr": "~2.0.5", - "qs": "6.7.0", - "range-parser": "~1.2.1", - "safe-buffer": "5.1.2", - "send": "0.17.1", - "serve-static": "1.14.1", - "setprototypeof": "1.1.1", - "statuses": "~1.5.0", - "type-is": "~1.6.18", - "utils-merge": "1.0.1", - "vary": "~1.1.2" - } - }, - "extend": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", - "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" - }, - "extsprintf": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", - "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=" - }, - "fast-deep-equal": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz", - "integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=" - }, - "fast-json-stable-stringify": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==" - }, - "fast-safe-stringify": { - "version": "2.0.7", - "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.0.7.tgz", - "integrity": "sha512-Utm6CdzT+6xsDk2m8S6uL8VHxNwI6Jub+e9NYTcAms28T84pTa25GJQV9j0CY0N1rM8hK4x6grpF2BQf+2qwVA==" - }, - "finalhandler": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", - "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==", - "requires": { - "debug": "2.6.9", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "on-finished": "~2.3.0", - "parseurl": "~1.3.3", - "statuses": "~1.5.0", - "unpipe": "~1.0.0" - } - }, - "forever-agent": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", - "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=" - }, - "form-data": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", - "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", - "requires": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.6", - "mime-types": "^2.1.12" - } - }, - "formidable": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/formidable/-/formidable-1.2.1.tgz", - "integrity": "sha512-Fs9VRguL0gqGHkXS5GQiMCr1VhZBxz0JnJs4JmMp/2jL18Fmbzvv7vOFRU+U8TBkHEE/CX1qDXzJplVULgsLeg==" - }, - "forwarded": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz", - "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=" - }, - "fresh": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", - "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=" - }, - "getpass": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", - "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", - "requires": { - "assert-plus": "^1.0.0" - } - }, - "har-schema": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", - "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=" - }, - "har-validator": { - "version": "5.1.3", - "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.3.tgz", - "integrity": "sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g==", - "requires": { - "ajv": "^6.5.5", - "har-schema": "^2.0.0" - } - }, - "has-binary2": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has-binary2/-/has-binary2-1.0.3.tgz", - "integrity": "sha512-G1LWKhDSvhGeAQ8mPVQlqNcOB2sJdwATtZKl2pDKKHfpf/rYj24lkinxf69blJbnsvtqqNU+L3SL50vzZhXOnw==", - "requires": { - "isarray": "2.0.1" - } - }, - "has-cors": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/has-cors/-/has-cors-1.1.0.tgz", - "integrity": "sha1-XkdHk/fqmEPRu5nCPu9J/xJv/zk=" - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" - }, - "http": { - "version": "0.0.0", - "resolved": "https://registry.npmjs.org/http/-/http-0.0.0.tgz", - "integrity": "sha1-huYybSnF0Dnen6xYSkVon5KfT3I=" - }, - "http-errors": { - "version": "1.7.2", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz", - "integrity": "sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==", - "requires": { - "depd": "~1.1.2", - "inherits": "2.0.3", - "setprototypeof": "1.1.1", - "statuses": ">= 1.5.0 < 2", - "toidentifier": "1.0.0" - } - }, - "http-proxy-agent": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-2.1.0.tgz", - "integrity": "sha512-qwHbBLV7WviBl0rQsOzH6o5lwyOIvwp/BdFnvVxXORldu5TmjFfjzBcWUWS5kWAZhmv+JtiDhSuQCp4sBfbIgg==", - "requires": { - "agent-base": "4", - "debug": "3.1.0" - }, - "dependencies": { - "debug": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", - "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", - "requires": { - "ms": "2.0.0" - } - } - } - }, - "http-signature": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", - "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", - "requires": { - "assert-plus": "^1.0.0", - "jsprim": "^1.2.2", - "sshpk": "^1.7.0" - } - }, - "https-proxy-agent": { - "version": "2.2.4", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-2.2.4.tgz", - "integrity": "sha512-OmvfoQ53WLjtA9HeYP9RNrWMJzzAz1JGaSFr1nijg0PVR1JaD/xbJq1mdEIIlxGpXp9eSe/O2LgU9DJmTPd0Eg==", - "requires": { - "agent-base": "^4.3.0", - "debug": "^3.1.0" - }, - "dependencies": { - "debug": { - "version": "3.2.6", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", - "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", - "requires": { - "ms": "^2.1.1" - } - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" - } - } - }, - "iconv-lite": { - "version": "0.4.24", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", - "requires": { - "safer-buffer": ">= 2.1.2 < 3" - } - }, - "indexof": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/indexof/-/indexof-0.0.1.tgz", - "integrity": "sha1-gtwzbSMrkGIXnQWrMpOmYFn9Q10=" - }, - "inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" - }, - "ipaddr.js": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.0.tgz", - "integrity": "sha512-M4Sjn6N/+O6/IXSJseKqHoFc+5FdGJ22sXqnjTpdZweHK64MzEPAyQZyEU3R/KRv2GLoa7nNtg/C2Ev6m7z+eA==" - }, - "is-typedarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", - "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=" - }, - "isarray": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.1.tgz", - "integrity": "sha1-o32U7ZzaLVmGXJ92/llu4fM4dB4=" - }, - "isstream": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", - "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=" - }, - "jsbn": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", - "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=" - }, - "json-schema": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", - "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=" - }, - "json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" - }, - "json-stringify-safe": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", - "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=" - }, - "jsprim": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", - "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=", - "requires": { - "assert-plus": "1.0.0", - "extsprintf": "1.3.0", - "json-schema": "0.2.3", - "verror": "1.10.0" - } - }, - "media-typer": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", - "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=" - }, - "merge-descriptors": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", - "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=" - }, - "methods": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", - "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=" - }, - "mime": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", - "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==" - }, - "mime-db": { - "version": "1.43.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.43.0.tgz", - "integrity": "sha512-+5dsGEEovYbT8UY9yD7eE4XTc4UwJ1jBYlgaQQF38ENsKR3wj/8q8RFZrF9WIZpB2V1ArTVFUva8sAul1NzRzQ==" - }, - "mime-types": { - "version": "2.1.26", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.26.tgz", - "integrity": "sha512-01paPWYgLrkqAyrlDorC1uDwl2p3qZT7yl806vW7DvDoxwXi46jsjFbg+WdwotBIk6/MbEhO/dh5aZ5sNj/dWQ==", - "requires": { - "mime-db": "1.43.0" - } - }, - "moment": { - "version": "2.24.0", - "resolved": "https://registry.npmjs.org/moment/-/moment-2.24.0.tgz", - "integrity": "sha512-bV7f+6l2QigeBBZSM/6yTNq4P2fNpSWj/0e7jQcy87A8e7o2nAfP/34/2ky5Vw4B9S446EtIhodAzkFCcR4dQg==" - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" - }, - "negotiator": { - "version": "0.6.2", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz", - "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==" - }, - "node-http-ping": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/node-http-ping/-/node-http-ping-0.3.1.tgz", - "integrity": "sha512-4q295gTtUXhFYp3CRMsmUWAXwHoB0oKEz3czmO9ZueWDcTcS3sX4I8L5zvdiXRrZpCMhb/TBaY9I27Gi7/Pa1Q==", - "requires": { - "bluebird": "^2.9.14" - } - }, - "oauth-sign": { - "version": "0.9.0", - "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", - "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==" - }, - "object-component": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/object-component/-/object-component-0.0.3.tgz", - "integrity": "sha1-8MaapQ78lbhmwYb0AKM3acsvEpE=" - }, - "on-finished": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", - "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", - "requires": { - "ee-first": "1.1.1" - } - }, - "parseqs": { - "version": "0.0.5", - "resolved": "https://registry.npmjs.org/parseqs/-/parseqs-0.0.5.tgz", - "integrity": "sha1-1SCKNzjkZ2bikbouoXNoSSGouJ0=", - "requires": { - "better-assert": "~1.0.0" - } - }, - "parseuri": { - "version": "0.0.5", - "resolved": "https://registry.npmjs.org/parseuri/-/parseuri-0.0.5.tgz", - "integrity": "sha1-gCBKUNTbt3m/3G6+J3jZDkvOMgo=", - "requires": { - "better-assert": "~1.0.0" - } - }, - "parseurl": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", - "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==" - }, - "path-to-regexp": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", - "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" - }, - "performance-now": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", - "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=" - }, - "prettysize": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/prettysize/-/prettysize-2.0.0.tgz", - "integrity": "sha512-VVtxR7sOh0VsG8o06Ttq5TrI1aiZKmC+ClSn4eBPaNf4SHr5lzbYW+kYGX3HocBL/MfpVrRfFZ9V3vCbLaiplg==" - }, - "proxy-addr": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.5.tgz", - "integrity": "sha512-t/7RxHXPH6cJtP0pRG6smSr9QJidhB+3kXu0KgXnbGYMgzEnUxRQ4/LDdfOwZEMyIh3/xHb8PX3t+lfL9z+YVQ==", - "requires": { - "forwarded": "~0.1.2", - "ipaddr.js": "1.9.0" - } - }, - "psl": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/psl/-/psl-1.7.0.tgz", - "integrity": "sha512-5NsSEDv8zY70ScRnOTn7bK7eanl2MvFrOrS/R6x+dBt5g1ghnj9Zv90kO8GwT8gxcu2ANyFprnFYB85IogIJOQ==" - }, - "punycode": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", - "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==" - }, - "qs": { - "version": "6.7.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz", - "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==" - }, - "range-parser": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", - "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==" - }, - "raw-body": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.0.tgz", - "integrity": "sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q==", - "requires": { - "bytes": "3.1.0", - "http-errors": "1.7.2", - "iconv-lite": "0.4.24", - "unpipe": "1.0.0" - } - }, - "readable-stream": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.4.0.tgz", - "integrity": "sha512-jItXPLmrSR8jmTRmRWJXCnGJsfy85mB3Wd/uINMXA65yrnFo0cPClFIUWzo2najVNSl+mx7/4W8ttlLWJe99pQ==", - "requires": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - } - }, - "request": { - "version": "2.88.0", - "resolved": "https://registry.npmjs.org/request/-/request-2.88.0.tgz", - "integrity": "sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg==", - "requires": { - "aws-sign2": "~0.7.0", - "aws4": "^1.8.0", - "caseless": "~0.12.0", - "combined-stream": "~1.0.6", - "extend": "~3.0.2", - "forever-agent": "~0.6.1", - "form-data": "~2.3.2", - "har-validator": "~5.1.0", - "http-signature": "~1.2.0", - "is-typedarray": "~1.0.0", - "isstream": "~0.1.2", - "json-stringify-safe": "~5.0.1", - "mime-types": "~2.1.19", - "oauth-sign": "~0.9.0", - "performance-now": "^2.1.0", - "qs": "~6.5.2", - "safe-buffer": "^5.1.2", - "tough-cookie": "~2.4.3", - "tunnel-agent": "^0.6.0", - "uuid": "^3.3.2" - }, - "dependencies": { - "qs": { - "version": "6.5.2", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", - "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==" - } - } - }, - "safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" - }, - "safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" - }, - "sax": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", - "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==" - }, - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" - }, - "send": { - "version": "0.17.1", - "resolved": "https://registry.npmjs.org/send/-/send-0.17.1.tgz", - "integrity": "sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg==", - "requires": { - "debug": "2.6.9", - "depd": "~1.1.2", - "destroy": "~1.0.4", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "fresh": "0.5.2", - "http-errors": "~1.7.2", - "mime": "1.6.0", - "ms": "2.1.1", - "on-finished": "~2.3.0", - "range-parser": "~1.2.1", - "statuses": "~1.5.0" - }, - "dependencies": { - "ms": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", - "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==" - } - } - }, - "serve-static": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.1.tgz", - "integrity": "sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg==", - "requires": { - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "parseurl": "~1.3.3", - "send": "0.17.1" - } - }, - "setprototypeof": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz", - "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==" - }, - "socket.io": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-2.3.0.tgz", - "integrity": "sha512-2A892lrj0GcgR/9Qk81EaY2gYhCBxurV0PfmmESO6p27QPrUK1J3zdns+5QPqvUYK2q657nSj0guoIil9+7eFg==", - "requires": { - "debug": "~4.1.0", - "engine.io": "~3.4.0", - "has-binary2": "~1.0.2", - "socket.io-adapter": "~1.1.0", - "socket.io-client": "2.3.0", - "socket.io-parser": "~3.4.0" - }, - "dependencies": { - "debug": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", - "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", - "requires": { - "ms": "^2.1.1" - } - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" - } - } - }, - "socket.io-adapter": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-1.1.2.tgz", - "integrity": "sha512-WzZRUj1kUjrTIrUKpZLEzFZ1OLj5FwLlAFQs9kuZJzJi5DKdU7FsWc36SNmA8iDOtwBQyT8FkrriRM8vXLYz8g==" - }, - "socket.io-client": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-2.3.0.tgz", - "integrity": "sha512-cEQQf24gET3rfhxZ2jJ5xzAOo/xhZwK+mOqtGRg5IowZsMgwvHwnf/mCRapAAkadhM26y+iydgwsXGObBB5ZdA==", - "requires": { - "backo2": "1.0.2", - "base64-arraybuffer": "0.1.5", - "component-bind": "1.0.0", - "component-emitter": "1.2.1", - "debug": "~4.1.0", - "engine.io-client": "~3.4.0", - "has-binary2": "~1.0.2", - "has-cors": "1.1.0", - "indexof": "0.0.1", - "object-component": "0.0.3", - "parseqs": "0.0.5", - "parseuri": "0.0.5", - "socket.io-parser": "~3.3.0", - "to-array": "0.1.4" - }, - "dependencies": { - "debug": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", - "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", - "requires": { - "ms": "^2.1.1" - } - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" - }, - "socket.io-parser": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-3.3.0.tgz", - "integrity": "sha512-hczmV6bDgdaEbVqhAeVMM/jfUfzuEZHsQg6eOmLgJht6G3mPKMxYm75w2+qhAQZ+4X+1+ATZ+QFKeOZD5riHng==", - "requires": { - "component-emitter": "1.2.1", - "debug": "~3.1.0", - "isarray": "2.0.1" - }, - "dependencies": { - "debug": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", - "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", - "requires": { - "ms": "2.0.0" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" - } - } - } - } - }, - "socket.io-parser": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-3.4.0.tgz", - "integrity": "sha512-/G/VOI+3DBp0+DJKW4KesGnQkQPFmUCbA/oO2QGT6CWxU7hLGWqU3tyuzeSK/dqcyeHsQg1vTe9jiZI8GU9SCQ==", - "requires": { - "component-emitter": "1.2.1", - "debug": "~4.1.0", - "isarray": "2.0.1" - }, - "dependencies": { - "debug": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", - "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", - "requires": { - "ms": "^2.1.1" - } - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" - } - } - }, - "speedtest-net": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/speedtest-net/-/speedtest-net-1.5.1.tgz", - "integrity": "sha512-az10ue3vkUUt49p5ommRO5eKXB5GfzyLehWCNRUnO686GjtdXJcSJFPnluc93UdoWTtWbr4fCVeH9Kka1OpHIA==", - "requires": { - "chalk": "^2.4.1", - "draftlog": "^1.0.12", - "http-proxy-agent": "^2.0.0", - "https-proxy-agent": "^2.1.1", - "xml2js": "^0.4.4" - }, - "dependencies": { - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "requires": { - "color-convert": "^1.9.0" - } - }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "requires": { - "color-name": "1.1.3" - } - }, - "color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" - }, - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "sshpk": { - "version": "1.16.1", - "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz", - "integrity": "sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==", - "requires": { - "asn1": "~0.2.3", - "assert-plus": "^1.0.0", - "bcrypt-pbkdf": "^1.0.0", - "dashdash": "^1.12.0", - "ecc-jsbn": "~0.1.1", - "getpass": "^0.1.1", - "jsbn": "~0.1.0", - "safer-buffer": "^2.0.2", - "tweetnacl": "~0.14.0" - } - }, - "statuses": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", - "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=" - }, - "string_decoder": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", - "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", - "requires": { - "safe-buffer": "~5.2.0" - }, - "dependencies": { - "safe-buffer": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.0.tgz", - "integrity": "sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg==" - } - } - }, - "superagent": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/superagent/-/superagent-5.2.1.tgz", - "integrity": "sha512-46b4Lkwnlz7Ebdv2FBbfuqb3kVkG1jV/SK3EW6NnwL9a3T4h5hHtegNEQfbXvTFbDoUZXId4W3dMgap2f6ic1g==", - "requires": { - "component-emitter": "^1.3.0", - "cookiejar": "^2.1.2", - "debug": "^4.1.1", - "fast-safe-stringify": "^2.0.7", - "form-data": "^3.0.0", - "formidable": "^1.2.1", - "methods": "^1.1.2", - "mime": "^2.4.4", - "qs": "^6.9.1", - "readable-stream": "^3.4.0", - "semver": "^6.3.0" - }, - "dependencies": { - "component-emitter": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz", - "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==" - }, - "debug": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", - "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", - "requires": { - "ms": "^2.1.1" - } - }, - "form-data": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.0.tgz", - "integrity": "sha512-CKMFDglpbMi6PyN+brwB9Q/GOw0eAnsrEZDgcsH5Krhz5Od/haKHAX0NmQfha2zPPz0JpWzA7GJHGSnvCRLWsg==", - "requires": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.8", - "mime-types": "^2.1.12" - } - }, - "mime": { - "version": "2.4.4", - "resolved": "https://registry.npmjs.org/mime/-/mime-2.4.4.tgz", - "integrity": "sha512-LRxmNwziLPT828z+4YkNzloCFC2YM4wrB99k+AV5ZbEyfGNWfG8SO1FUXLmLDBSo89NrJZ4DIWeLjy1CHGhMGA==" - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" - }, - "qs": { - "version": "6.9.1", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.9.1.tgz", - "integrity": "sha512-Cxm7/SS/y/Z3MHWSxXb8lIFqgqBowP5JMlTUFyJN88y0SGQhVmZnqFK/PeuMX9LzUyWsqqhNxIyg0jlzq946yA==" - } - } - }, - "supports-color": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz", - "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==", - "requires": { - "has-flag": "^4.0.0" - } - }, - "systeminformation": { - "version": "4.18.1", - "resolved": "https://registry.npmjs.org/systeminformation/-/systeminformation-4.18.1.tgz", - "integrity": "sha512-VvJ0SKvo8tXAYwFjQkJVzQyy9x/4ubPn2CMdFHER3r1K7AIXSFUZHNlNghi6uBRp5MYTalo9BrIYMx6nSuqU1A==" - }, - "to-array": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/to-array/-/to-array-0.1.4.tgz", - "integrity": "sha1-F+bBH3PdTz10zaek/zI46a2b+JA=" - }, - "toidentifier": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz", - "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==" - }, - "tough-cookie": { - "version": "2.4.3", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.4.3.tgz", - "integrity": "sha512-Q5srk/4vDM54WJsJio3XNn6K2sCG+CQ8G5Wz6bZhRZoAe/+TxjWB/GlFAnYEbkYVlON9FMk/fE3h2RLpPXo4lQ==", - "requires": { - "psl": "^1.1.24", - "punycode": "^1.4.1" - }, - "dependencies": { - "punycode": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", - "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=" - } - } - }, - "tunnel-agent": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", - "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", - "requires": { - "safe-buffer": "^5.0.1" - } - }, - "tweetnacl": { - "version": "0.14.5", - "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", - "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=" - }, - "type-is": { - "version": "1.6.18", - "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", - "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", - "requires": { - "media-typer": "0.3.0", - "mime-types": "~2.1.24" - } - }, - "unpipe": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", - "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=" - }, - "uri-js": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz", - "integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==", - "requires": { - "punycode": "^2.1.0" - } - }, - "util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" - }, - "utils-merge": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", - "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=" - }, - "uuid": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.3.tgz", - "integrity": "sha512-pW0No1RGHgzlpHJO1nsVrHKpOEIxkGg1xB+v0ZmdNH5OAeAwzAVrCnI2/6Mtx+Uys6iaylxa+D3g4j63IKKjSQ==" - }, - "vary": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", - "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=" - }, - "verror": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", - "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", - "requires": { - "assert-plus": "^1.0.0", - "core-util-is": "1.0.2", - "extsprintf": "^1.2.0" - } - }, - "ws": { - "version": "7.2.1", - "resolved": "https://registry.npmjs.org/ws/-/ws-7.2.1.tgz", - "integrity": "sha512-sucePNSafamSKoOqoNfBd8V0StlkzJKL2ZAhGQinCfNQ+oacw+Pk7lcdAElecBF2VkLNZRiIb5Oi1Q5lVUVt2A==" - }, - "xml2js": { - "version": "0.4.23", - "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.23.tgz", - "integrity": "sha512-ySPiMjM0+pLDftHgXY4By0uswI3SPKLDw/i3UXbnO8M/p28zqexCUoPmQFrYD+/1BzhGJSs2i1ERWKJAtiLrug==", - "requires": { - "sax": ">=0.6.0", - "xmlbuilder": "~11.0.0" - } - }, - "xmlbuilder": { - "version": "11.0.1", - "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz", - "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==" - }, - "xmlhttprequest-ssl": { - "version": "1.5.5", - "resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.5.5.tgz", - "integrity": "sha1-wodrBhaKrcQOV9l+gRkayPQ5iz4=" - }, - "yeast": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/yeast/-/yeast-0.1.2.tgz", - "integrity": "sha1-AI4G2AlDIMNy28L47XagymyKxBk=" - } - } -} diff --git a/DBH-Daemon/package.json b/DBH-Daemon/package.json deleted file mode 100644 index 58a58f615..000000000 --- a/DBH-Daemon/package.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "name": "servermonitor-fetch", - "version": "1.0.1", - "description": "A program that runs in system background to fetch data for the main ServerMonitor program.", - "main": "index.js", - "scripts": { - "test": "echo \"Error: no test specified\" && exit 1" - }, - "author": "danielpmc", - "license": "MIT", - "dependencies": { - "body-parser": "latest", - "chalk": "^3.0.0", - "express": "latest", - "http": "latest", - "moment": "^2.24.0", - "node-http-ping": "^0.3.1", - "prettysize": "^2.0.0", - "request": "^2.88.0", - "socket.io": "latest", - "speedtest-net": "^1.5.1", - "superagent": "^5.2.1", - "systeminformation": "^4.16.0" - } -} diff --git a/BetaDaemon/config.json b/Daemon/config.json similarity index 100% rename from BetaDaemon/config.json rename to Daemon/config.json diff --git a/BetaDaemon/index.js b/Daemon/index.js similarity index 99% rename from BetaDaemon/index.js rename to Daemon/index.js index e4b1f36dc..72bad406a 100644 --- a/BetaDaemon/index.js +++ b/Daemon/index.js @@ -68,7 +68,7 @@ app.get('/', async function (req, res) { var nettx = pretty(netdata[0].tx_bytes); var osdata = await si.osInfo(); var bios = await si.bios(); - var docker = await si.dockerInfo(); + var docker = await si.dockerInfo(); //CPU data. var cl = await si.currentLoad(); @@ -376,7 +376,7 @@ app.get('/', async function (req, res) { process.exit(); } -}, 2500); +}, 2500); setInterval(async () => { var timestamp = `${moment().format("YYYY-MM-DD HH:mm:ss")}`; diff --git a/BetaDaemon/package.json b/Daemon/package.json similarity index 100% rename from BetaDaemon/package.json rename to Daemon/package.json diff --git a/Panel/bot/discord/commands/eval.js b/Panel/bot/discord/commands/eval.js index 93f10f431..c8df108d9 100644 --- a/Panel/bot/discord/commands/eval.js +++ b/Panel/bot/discord/commands/eval.js @@ -1,7 +1,7 @@ const execSync = require('child_process').execSync; exports.run = async(client, message) => { - if(!message.member.roles.find(r => r.name === "Owner")){ + if (message.author.id !== config.DiscordBot.ownerID) { return message.channel.send(`Only my master can use this command`); } diff --git a/Panel/bot/discord/commands/exec.js b/Panel/bot/discord/commands/exec.js index 40527fdee..08cdbde1e 100644 --- a/Panel/bot/discord/commands/exec.js +++ b/Panel/bot/discord/commands/exec.js @@ -1,6 +1,6 @@ const exec = require('child_process').exec; exports.run = (client, message, args) => { - if(message.member.roles.find(r => r.name === "Owner")){ + if (message.author.id !== config.DiscordBot.ownerID) { const start = process.hrtime(); exec(`${args.join(" ")}`, (error, stdout) => { let response = (error || stdout); diff --git a/Panel/bot/discord/commands/help.js b/Panel/bot/discord/commands/help.js index 26c8ca961..cb1d02220 100644 --- a/Panel/bot/discord/commands/help.js +++ b/Panel/bot/discord/commands/help.js @@ -5,20 +5,20 @@ const Help = { } exports.run = async (client, message, args) => { - if (message.member.roles.find(r => r.name === "Staff")) { + if (message.member.roles.find(r => r.id === "713154800178561134")) { let embed = new Discord.RichEmbed() .setColor(`BLUE`) .addField(`__**Commands List for users:**__`, Help.Users) .addField(`__**Staff Commands:**__`, Help.Staff) message.channel.send(embed) - } else if (message.member.roles.find(r => r.name === "Owner")) { + } else if (message.member.roles.find(r => r.id === "639481606112804875")) { let embed = new Discord.RichEmbed() .setColor(`BLUE`) .addField(`__**Commands List for users:**__`, Help.Users) .addField(`__**Staff Commands:**__`, Help.Staff) .addField(`__**Owner Commands:**__`, Help.Owner) message.channel.send(embed) - } else if (message.member.roles.find(r => r.name === "Members")) { + } else if (message.member.roles.find(r => r.id === "639490038434103306")) { let embed = new Discord.RichEmbed() .setColor(`BLUE`) .addField(`__**Commands List for users:**__`, Help.Users) diff --git a/Panel/bot/discord/commands/link.js b/Panel/bot/discord/commands/link.js index 1ac4c277c..adc7417ba 100644 --- a/Panel/bot/discord/commands/link.js +++ b/Panel/bot/discord/commands/link.js @@ -7,7 +7,7 @@ exports.run = async (client, message) => { let result = userData.get(message.author.id) if (userData.get(message.author.id) == null) { - if (message.member.roles.find(r => r.name === "Customers")) { + if (message.member.roles.find(r => r.id === "639489891016638496")) { const server = message.guild @@ -63,6 +63,7 @@ exports.run = async (client, message) => { } let consoleUser3 = await DanBotHosting.getAllUsers(); + console.log(consoleUser3) consoleUser2 = consoleUser3.filter(x => x.attributes.email == collected1.first().content.trim()) console.log(consoleUser2) @@ -88,7 +89,7 @@ exports.run = async (client, message) => { .setColor('GREEN') .addField('__**Linked Discord account:**__', message.author.id) .addField('__**Linked Console account email:**__', consoleUser.attributes.email) - .addField('__**Linked At: (TIME / DATE)**__', linkTime + " / " + linkDate) + .addField('__**Linked At: (TIME / DATE)**__', timestamp + " / " + datestamp) .addField('__**Linked Console username:**__', consoleUser.attributes.username) .addField('__**Linked Console ID:**__', consoleUser.attributes.id) diff --git a/Panel/bot/discord/commands/say.js b/Panel/bot/discord/commands/say.js index 3ab85b012..163937650 100644 --- a/Panel/bot/discord/commands/say.js +++ b/Panel/bot/discord/commands/say.js @@ -1,7 +1,7 @@ exports.run = async (client, message) => { const args = message.content.split(' ').slice(1).join(' '); - if (message.member.roles.find(r => r.name === "Owner")) { + if (message.author.id !== config.DiscordBot.ownerID) { message.delete() message.channel.send(args) } else { diff --git a/Panel/bot/discord/commands/ticket.js b/Panel/bot/discord/commands/ticket.js index e9f239b02..c20639df2 100644 --- a/Panel/bot/discord/commands/ticket.js +++ b/Panel/bot/discord/commands/ticket.js @@ -5,7 +5,7 @@ exports.run = async (client, message) => { if (args == "") { let embed = new Discord.RichEmbed() .setColor(`GREEN`) - .addField(`__**Tickets**__`, 'You can create a new ticket by typing: `' + config.DiscordBot.Prefix + 'tickets new` \nYou can download your old tickets by running: `' + config.DiscordBot.Prefix + 'tickets logs` \nYou can close your ticket by running: `' + config.DiscordBot.Prefix + 'tickets close` \n\nAny problems? Please send a message in <#640158951899398144>', true); + .addField(`__**Tickets**__`, 'You can create a new ticket by typing: `' + config.DiscordBot.Prefix + 'ticket new` \nYou can download your old tickets by running: `' + config.DiscordBot.Prefix + 'ticket logs` \nYou can close your ticket by running: `' + config.DiscordBot.Prefix + 'ticket close` \n\nAny problems? Please send a message in <#640158951899398144>', true); message.channel.send(embed) } else if (args == "new") { diff --git a/Panel/bot/discord/events/guildMemberAdd.js b/Panel/bot/discord/events/guildMemberAdd.js index d31ab2b4d..9323b060d 100644 --- a/Panel/bot/discord/events/guildMemberAdd.js +++ b/Panel/bot/discord/events/guildMemberAdd.js @@ -6,28 +6,35 @@ const config = { "invite25": "704650197732556891", "invite50": "704650269182394398", "invitechannel": "704650867642597468", - "member": "639490038434103306" + "member": "639490038434103306", + "bot": "704467807122882562" } +//let client = require("../../../../index.js").client; module.exports = async(client, member, guild) => { - if(member.bot) return console.log("huh a bot just joined :) more friends :D") - const memberrole = member.guild.roles.find(role => role.id === config.member); - member.guild.members.get(member.user.id).addRole(memberrole) - client.channels.get(config.welcome).send("Welcome <@" + member.user.id + "> to DanBot Hosting. To get started please read <#640158484985413632>"); - - member.guild.fetchInvites().then(guildInvites => { - const ei = invites[member.guild.id]; - invites[member.guild.id] = guildInvites; - const invite = guildInvites.find(i => ei.get(i.code).uses < i.uses); - const inviter = client.users.get(invite.inviter.id); - client.channels.get(config.invitechannel).send(`${member.user.tag} (ID: ${member.user.id}) joined using invite code ` + "`" + invite.code + "`" + ` from ${inviter.tag} (ID: ${inviter.id}). Invite code has been used ${invite.uses} times.`); - const invite5 = member.guild.roles.find(role => role.id === config.invite5); - const invite10 = member.guild.roles.find(role => role.id === config.invite10); - const invite25 = member.guild.roles.find(role => role.id === config.invite25); - const invite50 = member.guild.roles.find(role => role.id === config.invite50); - if (invite.uses == 5) return member.guild.members.get(inviter.id).addRole(invite5), client.channels.get(config.inviterewmsg).send(`<@${inviter.id}> just hit 5 invites! Here's a role for you :)`); - if (invite.uses == 10) return member.guild.members.get(inviter.id).removeRole(invite5), member.guild.members.get(inviter.id).addRole(invite10), client.channels.get(config.inviterewmsg).send(`<@${inviter.id}> just hit 10 invites! Here's a role for you :)`);; - if (invite.uses >= 25) return member.guild.members.get(inviter.id).removeRole(invite10), member.guild.members.get(inviter.id).addRole(invite25), client.channels.get(config.inviterewmsg).send(`<@${inviter.id}> just hit 25 invites! Here's a role for you :)`);; - if (invite.uses >= 50) return member.guild.members.get(inviter.id).removeRole(invite25), member.guild.members.get(inviter.id).addRole(invite50), client.channels.get(config.inviterewmsg).send(`<@${inviter.id}> just hit 50 invites! Here's a role for you :)`);; - }); + if(member.user.bot) { + const botrole = member.guild.roles.find(role => role.id === config.bot); + member.guild.members.get(member.user.id).addRole(botrole) + client.channels.get(config.welcome).send("Welcome <@" + member.user.id + ">, More bot friends :D") + } else if (!member.user.bot) { + const memberrole = member.guild.roles.find(role => role.id === config.member); + member.guild.members.get(member.user.id).addRole(memberrole) + client.channels.get(config.welcome).send("Welcome <@" + member.user.id + "> to DanBot Hosting. To get started please read <#724021367842013346>"); + + member.guild.fetchInvites().then(guildInvites => { + const ei = invites[member.guild.id]; + invites[member.guild.id] = guildInvites; + const invite = guildInvites.find(i => ei.get(i.code).uses < i.uses); + const inviter = client.users.get(invite.inviter.id); + client.channels.get(config.invitechannel).send(`${member.user.tag} (ID: ${member.user.id}) joined using invite code ` + "`" + invite.code + "`" + ` from ${inviter.tag} (ID: ${inviter.id}). Invite code has been used ${invite.uses} times.`); + const invite5 = member.guild.roles.find(role => role.id === config.invite5); + const invite10 = member.guild.roles.find(role => role.id === config.invite10); + const invite25 = member.guild.roles.find(role => role.id === config.invite25); + const invite50 = member.guild.roles.find(role => role.id === config.invite50); + if (invite.uses == 5) return member.guild.members.get(inviter.id).addRole(invite5), client.channels.get(config.inviterewmsg).send(`<@${inviter.id}> just hit 5 invites! Here's a role for you :)`); + if (invite.uses == 10) return member.guild.members.get(inviter.id).removeRole(invite5), member.guild.members.get(inviter.id).addRole(invite10), client.channels.get(config.inviterewmsg).send(`<@${inviter.id}> just hit 10 invites! Here's a role for you :)`);; + if (invite.uses >= 25) return member.guild.members.get(inviter.id).removeRole(invite10), member.guild.members.get(inviter.id).addRole(invite25), client.channels.get(config.inviterewmsg).send(`<@${inviter.id}> just hit 25 invites! Here's a role for you :)`);; + if (invite.uses >= 50) return member.guild.members.get(inviter.id).removeRole(invite25), member.guild.members.get(inviter.id).addRole(invite50), client.channels.get(config.inviterewmsg).send(`<@${inviter.id}> just hit 50 invites! Here's a role for you :)`);; + }); + } }; \ No newline at end of file diff --git a/Panel/bot/discord/events/message.js b/Panel/bot/discord/events/message.js index ab9124c97..93b775c2f 100644 --- a/Panel/bot/discord/events/message.js +++ b/Panel/bot/discord/events/message.js @@ -1,5 +1,7 @@ +//let client = require("../../../../index.js").client; + module.exports = (client, message) => { - if(message.content.toLowerCase().includes("tiktok")) {message.reply('Ew. Get out here with that crap :bammer:'), message.delete() } + //if(message.content.toLowerCase().includes("tiktok")) {message.reply('Ew. Get out here with that crap :bammer:'), message.delete() } if(message.content.toLowerCase().includes("discord.gg")) { if(message.channel.id === '717146816918847489') { return; @@ -7,7 +9,7 @@ module.exports = (client, message) => { return; } else { message.delete(); - message.reply('No advertising here. Check out <#717146816918847489> or <#719259195471429722> for advertising!') + //message.reply('No advertising here. Check out <#717146816918847489> or <#719259195471429722> for advertising!') } } diff --git a/Panel/bot/discord/events/messageDelete.js b/Panel/bot/discord/events/messageDelete.js index 7510260b5..8f1dc7028 100644 --- a/Panel/bot/discord/events/messageDelete.js +++ b/Panel/bot/discord/events/messageDelete.js @@ -1,3 +1,5 @@ +//let client = require("../../../../index.js").client; + module.exports = (client, message) => { if (message.author.bot) return; if (message.channel.type === 'dm') return; @@ -14,4 +16,4 @@ module.exports = (client, message) => { .setTimestamp() .setFooter("Message delete in " + message.channel.name); client.channels.get(config.DiscordBot.mLogs).send({embed}); -} \ No newline at end of file +}; \ No newline at end of file diff --git a/Panel/bot/discord/events/messageUpdate.js b/Panel/bot/discord/events/messageUpdate.js index 863aab49c..45d7047be 100644 --- a/Panel/bot/discord/events/messageUpdate.js +++ b/Panel/bot/discord/events/messageUpdate.js @@ -1,17 +1,23 @@ +//let client = require("../../../../index.js").client; + module.exports = (client, message, editedMessage) => { - if(message.content.toLowerCase().includes("tiktok")) { message.delete() } - if (message.author.bot) return; - if (message.channel.type === 'dm') return; - if (message === editedMessage) return; - if (message.channel.type !== 'text') return; + if (message.content.toLowerCase().includes("tiktok")) { + message.delete() + } + if (message.author.bot) return; + if (message.channel.type === 'dm') return; + if (message === editedMessage) return; + if (message.channel.type !== 'text') return; - const embed = new Discord.RichEmbed() - .setColor(0x00A2E8) - .setThumbnail(message.author.avatarURL) - .addField("Author ", `${message.author.tag} (ID: ${message.author.id})`) - .addField("Before Edit ", `${message}`) - .addField("After Edit", `${editedMessage}`) - .setTimestamp() - .setFooter("Message edit in " + message.channel.name); - client.channels.get(config.DiscordBot.mLogs).send({embed}); - } \ No newline at end of file + const embed = new Discord.RichEmbed() + .setColor(0x00A2E8) + .setThumbnail(message.author.avatarURL) + .addField("Author ", `${message.author.tag} (ID: ${message.author.id})`) + .addField("Before Edit ", `${message}`) + .addField("After Edit", `${editedMessage}`) + .setTimestamp() + .setFooter("Message edit in " + message.channel.name); + client.channels.get(config.DiscordBot.mLogs).send({ + embed + }); +}; \ No newline at end of file diff --git a/Panel/bot/discord/events/ready.js b/Panel/bot/discord/events/ready.js index 10ff1f892..30b3cfe5a 100644 --- a/Panel/bot/discord/events/ready.js +++ b/Panel/bot/discord/events/ready.js @@ -1,26 +1,33 @@ +//let client = require("../../../../index.js").client; + module.exports = async (client, guild, files) => { console.log(chalk.magenta('[DISCORD] ') + chalk.green("Bot logged in!")); -//Auto Activities List -const activities = [ - { - "text": "over DanBot Hosting", - "type": "WATCHING" - }, - { - "text": "DanBot FM", - "type": "LISTENING" - } -]; -setInterval(() => { - const activity = activities[Math.floor(Math.random() * activities.length)]; - client.user.setActivity(activity.text, { type: activity.type }); -}, 30000); + //Auto Activities List + const activities = [{ + "text": "over DanBot Hosting", + "type": "WATCHING" + }, + { + "text": "DanBot FM", + "type": "LISTENING" + }, + { + "text": "Stalking Dan coding me :)", + "type": "WATCHING" + } + ]; + setInterval(() => { + const activity = activities[Math.floor(Math.random() * activities.length)]; + client.user.setActivity(activity.text, { + type: activity.type + }); + }, 30000); -global.invites = {}; -client.guilds.forEach(g => { - g.fetchInvites().then(guildInvites => { - invites[g.id] = guildInvites; + global.invites = {}; + client.guilds.forEach(g => { + g.fetchInvites().then(guildInvites => { + invites[g.id] = guildInvites; + }); }); - }); }; \ No newline at end of file diff --git a/Panel/bot/discord/tickets/ticketModule.js b/Panel/bot/discord/tickets/ticketModule.js new file mode 100644 index 000000000..11451b0d9 --- /dev/null +++ b/Panel/bot/discord/tickets/ticketModule.js @@ -0,0 +1,3 @@ +const Discord = require('discord.js'); +const fs = require('fs'); + diff --git a/Panel/index.js b/Panel/index.js index 89aeed7a8..d27b1499c 100644 --- a/Panel/index.js +++ b/Panel/index.js @@ -28,16 +28,21 @@ let transport = nodemailer.createTransport({ //Discord Bot +//const events = require("events"); var node = require('nodeactyl'); +let db = require("quick.db"); global.DanBotHosting = node.Application; global.DanBotHostingClient = node.Client; global.Discord = require("discord.js"); -const client = new Discord.Client() global.fs = require("fs"); global.moment = require("moment"); -let db = require("quick.db"); global.userData = new db.table("userData") +global.client = new Discord.Client(); +//const DBH = new events(); +const bot = client; +//exports.bot = client; +//exports.DBH = DBH; //Event handler fs.readdir('./bot/discord/events/', (err, files) => { @@ -49,6 +54,23 @@ fs.readdir('./bot/discord/events/', (err, files) => { }); }); + + //Event Handler + +/*fs.readdir("./bot/discord/events/", (err, files) => { + if (err) return console.log(err); + files.forEach(file => { + fs.readdir("./bot/discord/events/" + file, (err, ff) => { + if (!ff || ff.length == 0) return console.log(`No Events Found in ${file}`); + ff.filter(x => x.toLowerCase().endsWith(".js")).forEach(x => { + + require(`./bot/discord/events/${file}/${x}`); + }); + console.log(`${file} - ${ff.filter(x => toLowerCase().endsWith(".js")).join(", ")}`); + }); + }); +});*/ + //Disconnected from discord. Probs time to restart while disconnected. //client.on('reconnecting', () => console.log('Disconnected from discord. Restarting...'), process.exit()); diff --git a/Panel/package.json b/Panel/package.json index 4642d733b..76b428d00 100644 --- a/Panel/package.json +++ b/Panel/package.json @@ -21,6 +21,7 @@ "chalk": "^3.0.0", "discord.js": "^11.6.3", "ejs": "^3.0.1", + "events": "^3.1.0", "express": "latest", "express-handlebars": "^3.1.0", "git-repo-info": "^2.1.1", @@ -28,7 +29,7 @@ "helmet": "^3.21.2", "http": "latest", "moment": "^2.24.0", - "nodeactyl": "^2.0.2", + "nodeactyl": "github:zLupa/Nodeactyl", "nodeactyl-beta": "0.0.10", "nodemailer": "^6.4.6", "puppeteer": "^1.19.0", diff --git a/Panel/package.zip b/Panel/package.zip deleted file mode 100644 index 1276925011b19a0321d767ab02c45065f5430c3d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 63093 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 G@4o=B=&LFK diff --git a/Panel/test.js b/Panel/test.js index a6b89f0a8..c8a4448b8 100644 --- a/Panel/test.js +++ b/Panel/test.js @@ -6,9 +6,11 @@ const chalk = require('chalk'); Application.login(config.Pterodactyl.hosturl, config.Pterodactyl.apikey, (logged_in) => { console.log(chalk.magenta('[APP] ') + chalk.green("Nodeactyl logged in? " + logged_in)); }); +setTimeout(async () => { -Application.createServer("latest", "TEST", "90", null, "5", "danielpmc/discordnode8", "bash", "0", "-1", "1024", "500", "1", "0", "1").then(res => { - console.log(res) -}).catch(error =>{ - console.log(error); -}) \ No newline at end of file + Application.createServer("latest", `test`, `1`, null, "3", "quay.io/pterodactyl/core:java", "java -Xms128M -Xmx{{SERVER_MEMORY}}M -Dterminal.jline=false -Dterminal.ansi=true -jar {{SERVER_JARFILE}}", "2048", "0", "25000", "500", "0", "0", "1").then(res => { + console.log(res) + }).catch(error =>{ + console.log(error); + }) +}, 2000) \ No newline at end of file diff --git a/Panel/views/index.hbs b/Panel/views/index.hbs index f6ea8911a..cd5161ae7 100644 --- a/Panel/views/index.hbs +++ b/Panel/views/index.hbs @@ -35,6 +35,9 @@
RAM (Used/Total) {{Node1Data.memused}} / {{Node1Data.memtotal}}
+
+
SWAP (Used/Total) {{Node1Data.swapused}} / {{Node1Data.swaptotal}}
+
Host storage drive (Used/Total): {{Node1Data.diskused}} / {{Node1Data.disktotal}}
@@ -63,6 +66,9 @@
RAM (Used/Total) {{Node2Data.memused}} / {{Node2Data.memtotal}}
+
+
SWAP (Used/Total) {{Node2Data.swapused}} / {{Node2Data.swaptotal}}
+
Host storage drive (Used/Total): {{Node2Data.diskused}} / {{Node2Data.disktotal}}
@@ -91,6 +97,9 @@
RAM (Used/Total) {{Node3Data.memused}} / {{Node3Data.memtotal}}
+
+
SWAP (Used/Total) {{Node3Data.swapused}} / {{Node3Data.swaptotal}}
+
Host storage drive (Used/Total): {{Node3Data.diskused}} / {{Node3Data.disktotal}}
@@ -107,32 +116,5 @@
Speedtest (Updates every 6hours) | Ping: {{Node3DataSpeed.ping}}ms, Download: {{Node3DataSpeed.download}}Mbps, Upload: {{Node3DataSpeed.upload}}Mbps, Last Updated: {{Node3DataSpeed.updatetime}}
- -
-
CPU: {{Node4Data.cpu}} (Cores: {{Node4Data.cpucores}}, Threads: {{Node4Data.cputhreads}})
-
-
-
CPU Load: {{Node4Data.cpuload}}%
-
-
-
RAM (Used/Total) {{Node4Data.memused}} / {{Node4Data.memtotal}}
-
-
-
Host storage drive (Used/Total): {{Node4Data.diskused}} / {{Node4Data.disktotal}}
-
-
-
Network: Rx: {{Node4Data.netrx}} Tx: {{Node4Data.nettx}}
-
-
-
Uptime: {{Node4Data.osuptime}}
-
-
-
Last Updated: {{Node4Data.updatetime}}
-
-
-
Speedtest (Updates every 6hours) | Ping: {{Node4DataSpeed.ping}}ms, Download: {{Node4DataSpeed.download}}Mbps, Upload: {{Node4DataSpeed.upload}}Mbps, Last Updated: {{Node4DataSpeed.updatetime}}
-
\ No newline at end of file diff --git a/Panel/views/node1.hbs b/Panel/views/node1.hbs index 612cb1444..815697c07 100644 --- a/Panel/views/node1.hbs +++ b/Panel/views/node1.hbs @@ -36,6 +36,9 @@
RAM (Used/Total) {{Node1Data.memused}} / {{Node1Data.memtotal}}
+
+
SWAP (Used/Total) {{Node1Data.swapused}} / {{Node1Data.swaptotal}}
+
Host storage drive (Used/Total): {{Node1Data.diskused}} / {{Node1Data.disktotal}}
diff --git a/Panel/views/node2.hbs b/Panel/views/node2.hbs index e3b54e7d7..42ff31944 100644 --- a/Panel/views/node2.hbs +++ b/Panel/views/node2.hbs @@ -36,6 +36,9 @@
RAM (Used/Total) {{Node2Data.memused}} / {{Node2Data.memtotal}}
+
+
SWAP (Used/Total) {{Node2Data.swapused}} / {{Node2Data.swaptotal}}
+
Host storage drive (Used/Total): {{Node2Data.diskused}} / {{Node2Data.disktotal}}
diff --git a/Panel/views/node3.hbs b/Panel/views/node3.hbs index c96a57852..2a60a049a 100644 --- a/Panel/views/node3.hbs +++ b/Panel/views/node3.hbs @@ -36,6 +36,9 @@
RAM (Used/Total) {{Node3Data.memused}} / {{Node3Data.memtotal}}
+
+
SWAP (Used/Total) {{Node3Data.swapused}} / {{Node3Data.swaptotal}}
+
Host storage drive (Used/Total): {{Node3Data.diskused}} / {{Node3Data.disktotal}}
diff --git a/Panel/views/node4.hbs b/Panel/views/node4.hbs index a8228f399..97b63d32d 100644 --- a/Panel/views/node4.hbs +++ b/Panel/views/node4.hbs @@ -36,6 +36,9 @@
RAM (Used/Total) {{Node4Data.memused}} / {{Node4Data.memtotal}}
+
+
SWAP (Used/Total) {{Node4Data.swapused}} / {{Node4Data.swaptotal}}
+
Host storage drive (Used/Total): {{Node4Data.diskused}} / {{Node4Data.disktotal}}
From a5e87cca7165641096787ac74fcc9f6dbd30216c Mon Sep 17 00:00:00 2001 From: danielpmc Date: Sun, 28 Jun 2020 15:54:21 +0100 Subject: [PATCH 018/255] Uh remove a file? --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index abcb4e4c7..8df4e69a4 100644 --- a/.gitignore +++ b/.gitignore @@ -5,6 +5,7 @@ Panel/package-lock.json Panel/data Panel/config.json Panel/json.sqlite +Panel/test.js Daemon/node_modules Daemon/package-lock.json From 4950e26549182fe431efe0ebcdf2fe59a06d7dad Mon Sep 17 00:00:00 2001 From: danielpmc Date: Sun, 28 Jun 2020 15:56:48 +0100 Subject: [PATCH 019/255] be gone file --- Panel/test.js | 16 ---------------- 1 file changed, 16 deletions(-) delete mode 100644 Panel/test.js diff --git a/Panel/test.js b/Panel/test.js deleted file mode 100644 index c8a4448b8..000000000 --- a/Panel/test.js +++ /dev/null @@ -1,16 +0,0 @@ -var node = require('nodeactyl-beta'); -const Application = node.Application; -const config = require("./config.json"); -const chalk = require('chalk'); - -Application.login(config.Pterodactyl.hosturl, config.Pterodactyl.apikey, (logged_in) => { - console.log(chalk.magenta('[APP] ') + chalk.green("Nodeactyl logged in? " + logged_in)); -}); -setTimeout(async () => { - - Application.createServer("latest", `test`, `1`, null, "3", "quay.io/pterodactyl/core:java", "java -Xms128M -Xmx{{SERVER_MEMORY}}M -Dterminal.jline=false -Dterminal.ansi=true -jar {{SERVER_JARFILE}}", "2048", "0", "25000", "500", "0", "0", "1").then(res => { - console.log(res) - }).catch(error =>{ - console.log(error); - }) -}, 2000) \ No newline at end of file From cf09532a77fd0f55995983b3eeff16e587775cc2 Mon Sep 17 00:00:00 2001 From: danielpmc Date: Sun, 28 Jun 2020 16:28:24 +0100 Subject: [PATCH 020/255] fix a fucking dumb thing i put in the code --- Panel/bot/discord/events/guildMemberAdd.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Panel/bot/discord/events/guildMemberAdd.js b/Panel/bot/discord/events/guildMemberAdd.js index 9323b060d..25e1c0db1 100644 --- a/Panel/bot/discord/events/guildMemberAdd.js +++ b/Panel/bot/discord/events/guildMemberAdd.js @@ -33,8 +33,8 @@ module.exports = async(client, member, guild) => { const invite50 = member.guild.roles.find(role => role.id === config.invite50); if (invite.uses == 5) return member.guild.members.get(inviter.id).addRole(invite5), client.channels.get(config.inviterewmsg).send(`<@${inviter.id}> just hit 5 invites! Here's a role for you :)`); if (invite.uses == 10) return member.guild.members.get(inviter.id).removeRole(invite5), member.guild.members.get(inviter.id).addRole(invite10), client.channels.get(config.inviterewmsg).send(`<@${inviter.id}> just hit 10 invites! Here's a role for you :)`);; - if (invite.uses >= 25) return member.guild.members.get(inviter.id).removeRole(invite10), member.guild.members.get(inviter.id).addRole(invite25), client.channels.get(config.inviterewmsg).send(`<@${inviter.id}> just hit 25 invites! Here's a role for you :)`);; - if (invite.uses >= 50) return member.guild.members.get(inviter.id).removeRole(invite25), member.guild.members.get(inviter.id).addRole(invite50), client.channels.get(config.inviterewmsg).send(`<@${inviter.id}> just hit 50 invites! Here's a role for you :)`);; + if (invite.uses == 25) return member.guild.members.get(inviter.id).removeRole(invite10), member.guild.members.get(inviter.id).addRole(invite25), client.channels.get(config.inviterewmsg).send(`<@${inviter.id}> just hit 25 invites! Here's a role for you :)`);; + if (invite.uses == 50) return member.guild.members.get(inviter.id).removeRole(invite25), member.guild.members.get(inviter.id).addRole(invite50), client.channels.get(config.inviterewmsg).send(`<@${inviter.id}> just hit 50 invites! Here's a role for you :)`);; }); } }; \ No newline at end of file From f2f658c806ff72e19f7ebdc265aab26505774d7f Mon Sep 17 00:00:00 2001 From: danielpmc Date: Sun, 28 Jun 2020 16:31:23 +0100 Subject: [PATCH 021/255] more status's because why tf not --- Panel/bot/discord/events/ready.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Panel/bot/discord/events/ready.js b/Panel/bot/discord/events/ready.js index 30b3cfe5a..512ce9344 100644 --- a/Panel/bot/discord/events/ready.js +++ b/Panel/bot/discord/events/ready.js @@ -13,8 +13,12 @@ module.exports = async (client, guild, files) => { "type": "LISTENING" }, { - "text": "Stalking Dan coding me :)", + "text": "over Dan coding me :)", "type": "WATCHING" + }, + { + "text": "with bots on DanBot Hosting.", + "type": "PLAYING" } ]; setInterval(() => { From 7796060d25460601baf83ce0c04fc828bcbc1dff Mon Sep 17 00:00:00 2001 From: Robin Schapendonk <46354497+RobinSchapendonk@users.noreply.github.com> Date: Sun, 5 Jul 2020 09:53:23 +0000 Subject: [PATCH 022/255] ticket confirm lowercase + no awaitmessage limit --- Panel/bot/discord/commands/ticket.js | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/Panel/bot/discord/commands/ticket.js b/Panel/bot/discord/commands/ticket.js index c20639df2..89f341b06 100644 --- a/Panel/bot/discord/commands/ticket.js +++ b/Panel/bot/discord/commands/ticket.js @@ -56,7 +56,6 @@ exports.run = async (client, message) => { const warning = await message.channel.send('<@' + message.author.id + '> are you sure you want to close this ticket? please type `confirm` to close the ticket or `cancel` to keep the ticket open.') let collected1 = await message.channel.awaitMessages(filter2, { - max: 1, time: 30000, errors: ['time'], }).catch(x => { @@ -68,7 +67,7 @@ exports.run = async (client, message) => { return false; }) - if (collected1.first().content === 'confirm') { + if (collected1.first().content.toLowerCase() === 'confirm') { return message.channel.send("**Closing ticket.**", null).then(setTimeout(() => { message.channel.delete()}, 5000)) } else if (collected1.first().content === 'cancel') { return message.channel.send('Closing ticket. __**Canceled**__ Ticket staying open.'); @@ -103,4 +102,4 @@ exports.run = async (client, message) => { }) } } -}; \ No newline at end of file +}; From 971567b31d91ac9d976ae19eaf8cb86b9a835478 Mon Sep 17 00:00:00 2001 From: danielpmc Date: Sun, 5 Jul 2020 22:09:30 +0100 Subject: [PATCH 023/255] Ah, push it, push it good --- Panel/bot/discord/commands/getstarted.js | 2 +- Panel/bot/discord/commands/kick.js | 0 Panel/bot/discord/commands/mute.js | 59 ++++++++++++++++++++++++ Panel/index.js | 2 +- Panel/package.json | 2 +- 5 files changed, 62 insertions(+), 3 deletions(-) create mode 100644 Panel/bot/discord/commands/kick.js create mode 100644 Panel/bot/discord/commands/mute.js diff --git a/Panel/bot/discord/commands/getstarted.js b/Panel/bot/discord/commands/getstarted.js index 408eb4592..ee4858840 100644 --- a/Panel/bot/discord/commands/getstarted.js +++ b/Panel/bot/discord/commands/getstarted.js @@ -53,7 +53,7 @@ exports.run = async (client, message) => { let msg = await channel.send("<@" + message.author.id + ">", { embed: new Discord.RichEmbed() .setColor(0x36393e) - .setDescription("Please enter a username") + .setDescription("Please enter a username (**Please dont use spaces**)") .setFooter("You can type 'cancel' to cancel the request") }) diff --git a/Panel/bot/discord/commands/kick.js b/Panel/bot/discord/commands/kick.js new file mode 100644 index 000000000..e69de29bb diff --git a/Panel/bot/discord/commands/mute.js b/Panel/bot/discord/commands/mute.js new file mode 100644 index 000000000..25a419559 --- /dev/null +++ b/Panel/bot/discord/commands/mute.js @@ -0,0 +1,59 @@ +exports.run = async (client, message, args) => { + + //Usage embed + const usage = new Discord.RichEmbed() + .setColor(0x00A2E8) + .setThumbnail(client.user.avatarURL) + .setTitle("Command: " + config.DiscordBot.Prefix + "mute") + .addField("Usage", config.DiscordBot.Prefix + "mute @Someone ") + .addField("Example", config.DiscordBot.Prefix + "mute @Someone 5 spamming in general.") + .setDescription("Description: " + "Gives a user the muted role for x minutes"); + + if(message.member.roles.find(r => r.id === "713154800178561134")) { + if (!message.guild.member(client.user).hasPermission('MANAGE_ROLES')) return message.reply('Sorry, i dont have the perms to do this cmd i need MANAGE_ROLES. :x:') + + //If no user pinged + if (message.mentions.users.size < 1) return message.channel.send(usage) + + let user = message.guild.member(message.mentions.users.first()); + let messagez = parseInt(args[1]) + if (isNaN(messagez)) return message.channel.send("That is not a valid time") + if (messagez > 1440) return message.channel.send('Maximum time is 1 day (1440 minutes)'); + if (messagez < 1) return message.channel.send('Time must be at least 1 minute.'); + let reason = args.slice(2).join(' ') || `No reason.`; + let modlog = message.guild.channels.find(channel => channel.id == config.DiscordBot.mLogs); + if (reason.length < 1) return; + let muteRole = client.guilds.get(message.guild.id).roles.find(r => r.id == "726829710935457872"); + + //Muted embed + const embed = new Discord.RichEmbed() + .setColor(0x00A2E8) + .setTitle("Action: Mute") + .addField("Moderator", message.author.tag + " (ID: " + message.author.id + ")") + .addField("User", user.user.tag + " (ID: " + user.user.id + ")") + .addField("Time", messagez, true) + .addField("Reason", reason, true) + .setFooter("Time used: " + message.createdAt.toDateString()) + + message.guild.member(user).addRole(muteRole).then(() => { + message.channel.send("***The user has been successfully muted for " + messagez + " minute(s) :white_check_mark:***") + + if (!modlog) { + setTimeout(() => { + message.guild.member(user).removeRole(muteRole) + console.log(chalk.magenta('[DISCORD] ') + chalk.cyan(user.user.username + ' has now been unmuted after ' + messagez +' minute(s)')) + }, messagez * 60000); + } else { + client.channels.get(modlog.id).send({embed}) + setTimeout(() => { + message.guild.member(user).removeRole(muteRole) + console.log(chalk.magenta('[DISCORD] ') + chalk.cyan(user.user.username + ' has now been unmuted after ' + messagez +' minute(s)')) + }, messagez * 60000); + } + }) + + + } else { + message.channel.send('Missing perms to do that :(') + }; +}; \ No newline at end of file diff --git a/Panel/index.js b/Panel/index.js index d27b1499c..37f93ed5f 100644 --- a/Panel/index.js +++ b/Panel/index.js @@ -194,7 +194,7 @@ app.get("/Node3", (req, res) => { //Data for node 3 var N3 = fs.readFileSync('./data/e5406f6d-a9a6-44fa-9dde-429ffc1bf1d7.json', 'utf8'); var Node3 = JSON.parse(N3); - var N3speed = fs.readFileSync('./data/bed240f5-7c87-4013-90ee-a5bbc21f60da-speedtest.json', 'utf8'); + var N3speed = fs.readFileSync('./data/e5406f6d-a9a6-44fa-9dde-429ffc1bf1d7-speedtest.json', 'utf8'); var Node3speed = JSON.parse(N3speed); res.render('node3', { layout: false, diff --git a/Panel/package.json b/Panel/package.json index 76b428d00..a0655a98e 100644 --- a/Panel/package.json +++ b/Panel/package.json @@ -29,7 +29,7 @@ "helmet": "^3.21.2", "http": "latest", "moment": "^2.24.0", - "nodeactyl": "github:zLupa/Nodeactyl", + "nodeactyl": "github:Burchard36/Nodeactyl", "nodeactyl-beta": "0.0.10", "nodemailer": "^6.4.6", "puppeteer": "^1.19.0", From 8d9c93cfb9acae51b69ee5ce8c8dbb35377b1196 Mon Sep 17 00:00:00 2001 From: Robin Schapendonk <46354497+RobinSchapendonk@users.noreply.github.com> Date: Mon, 6 Jul 2020 15:24:14 +0000 Subject: [PATCH 024/255] Update ticket.js --- Panel/bot/discord/commands/ticket.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Panel/bot/discord/commands/ticket.js b/Panel/bot/discord/commands/ticket.js index 89f341b06..9f80eea7c 100644 --- a/Panel/bot/discord/commands/ticket.js +++ b/Panel/bot/discord/commands/ticket.js @@ -27,7 +27,7 @@ exports.run = async (client, message) => { allow: 84992 } ]).catch(console.error); - message.reply(`Please check ${channel.id} for your ticket.`) + message.reply(`Please check ${channel} for your ticket.`) let category = server.channels.find(c => c.id == "654313162086285323" && c.type == "category"); if (!category) throw new Error("Category channel does not exist"); From 67453469a08a29296353672e817cf29ca88e0ef2 Mon Sep 17 00:00:00 2001 From: danielpmc Date: Tue, 22 Sep 2020 19:32:01 +0100 Subject: [PATCH 025/255] Add files via upload --- Panel/bot/discord/commands/access.js | 28 +- Panel/bot/discord/commands/apikey.js | 89 +++ Panel/bot/discord/commands/changelog.js | 20 +- Panel/bot/discord/commands/createserver.js | 6 + Panel/bot/discord/commands/eval.js | 5 +- Panel/bot/discord/commands/exec.js | 2 +- Panel/bot/discord/commands/getstarted-new.js | 498 +++++++-------- Panel/bot/discord/commands/getstarted.js | 52 +- Panel/bot/discord/commands/giveaway.js | 216 +++---- Panel/bot/discord/commands/help.js | 8 +- Panel/bot/discord/commands/info.js | 32 + Panel/bot/discord/commands/link.js | 254 ++++++-- Panel/bot/discord/commands/monitor.js | 92 +-- Panel/bot/discord/commands/mute.js | 116 ++-- Panel/bot/discord/commands/own.js | 26 +- Panel/bot/discord/commands/play.js | 88 +-- Panel/bot/discord/commands/proxmox.js | 2 + Panel/bot/discord/commands/purge.js | 71 ++- Panel/bot/discord/commands/radio.js | 14 +- Panel/bot/discord/commands/reload.js | 26 +- Panel/bot/discord/commands/say.js | 2 +- Panel/bot/discord/commands/server.js | 415 ++++++++++++ Panel/bot/discord/commands/staff.js | 50 +- Panel/bot/discord/commands/stats.js | 71 +-- Panel/bot/discord/commands/status.js | 115 ++-- Panel/bot/discord/commands/suggest.js | 12 + Panel/bot/discord/commands/ticket.js | 18 +- Panel/bot/discord/commands/tickets.js | 10 + Panel/bot/discord/commands/uptime.js | 102 +-- Panel/bot/discord/events/guildMemberAdd.js | 74 ++- Panel/bot/discord/events/guildMemberUpdate.js | 84 +++ Panel/bot/discord/events/message.js | 105 +-- Panel/bot/discord/events/messageDelete.js | 36 +- Panel/bot/discord/events/messageUpdate.js | 47 +- Panel/bot/discord/events/ready.js | 62 +- Panel/bot/discord/events/voiceStateUpdate.js | 6 + Panel/bot/discord/music/functions.js | 140 ++-- Panel/bot/discord/music/utils.js | 80 +-- Panel/bot/discord/tickets/ticketModule.js | 6 +- Panel/index.js | 603 +++++++++++------- Panel/package.json | 33 +- Panel/routes/admin.js | 3 + Panel/routes/api.js | 183 ++++++ Panel/routes/bot.js | 68 ++ Panel/routes/index.js | 153 +++++ Panel/routes/me.js | 61 ++ Panel/routes/stats.js | 81 +++ Panel/util/MBL.js | 43 ++ Panel/util/discordAPI.js | 47 ++ Panel/util/isSnowflake.js | 4 + Panel/util/pterodactyl.js | 51 ++ Panel/views/bot/index.ejs | 136 ++++ Panel/views/bots.ejs | 151 +++++ Panel/views/error.ejs | 9 + Panel/views/feedback.ejs | 74 +++ Panel/views/forms/apply-staff.ejs | 119 ++++ Panel/views/forms/newserver.ejs | 130 ++++ Panel/views/index.ejs | 140 ++++ Panel/views/main.ejs | 41 ++ Panel/views/me/index.ejs | 57 ++ Panel/views/me/user.ejs | 139 ++++ Panel/views/node1.ejs | 57 ++ Panel/views/node2.ejs | 57 ++ Panel/views/node3.ejs | 57 ++ Panel/views/node4.ejs | 57 ++ Panel/views/partials/header.ejs | 278 ++++++++ Panel/views/partials/header.hbs | 2 +- Panel/views/partners.ejs | 28 + 68 files changed, 4644 insertions(+), 1298 deletions(-) create mode 100644 Panel/bot/discord/commands/apikey.js create mode 100644 Panel/bot/discord/commands/createserver.js create mode 100644 Panel/bot/discord/commands/info.js create mode 100644 Panel/bot/discord/commands/proxmox.js create mode 100644 Panel/bot/discord/commands/server.js create mode 100644 Panel/bot/discord/commands/suggest.js create mode 100644 Panel/bot/discord/commands/tickets.js create mode 100644 Panel/bot/discord/events/guildMemberUpdate.js create mode 100644 Panel/bot/discord/events/voiceStateUpdate.js create mode 100644 Panel/routes/admin.js create mode 100644 Panel/routes/api.js create mode 100644 Panel/routes/bot.js create mode 100644 Panel/routes/index.js create mode 100644 Panel/routes/me.js create mode 100644 Panel/routes/stats.js create mode 100644 Panel/util/MBL.js create mode 100644 Panel/util/discordAPI.js create mode 100644 Panel/util/isSnowflake.js create mode 100644 Panel/util/pterodactyl.js create mode 100644 Panel/views/bot/index.ejs create mode 100644 Panel/views/bots.ejs create mode 100644 Panel/views/error.ejs create mode 100644 Panel/views/feedback.ejs create mode 100644 Panel/views/forms/apply-staff.ejs create mode 100644 Panel/views/forms/newserver.ejs create mode 100644 Panel/views/index.ejs create mode 100644 Panel/views/main.ejs create mode 100644 Panel/views/me/index.ejs create mode 100644 Panel/views/me/user.ejs create mode 100644 Panel/views/node1.ejs create mode 100644 Panel/views/node2.ejs create mode 100644 Panel/views/node3.ejs create mode 100644 Panel/views/node4.ejs create mode 100644 Panel/views/partials/header.ejs create mode 100644 Panel/views/partners.ejs diff --git a/Panel/bot/discord/commands/access.js b/Panel/bot/discord/commands/access.js index c6902ee78..4574db3c1 100644 --- a/Panel/bot/discord/commands/access.js +++ b/Panel/bot/discord/commands/access.js @@ -1,15 +1,15 @@ -exports.run = (client, message) => { - const args = message.content.split(' ').slice(1).join(' '); - - if(message.member.roles.find(r => r.name === "Moderators")){ - if (args == "") { - let embed = new Discord.RichEmbed() - .setColor(`GREEN`) - .addField(`__**Access a user's server**__`, '', true); - message.channel.send(embed) - - } else { - - } - } +exports.run = (client, message) => { + const args = message.content.split(' ').slice(1).join(' '); + + if(message.member.roles.find(r => r.name === "Moderators")){ + if (args == "") { + let embed = new Discord.RichEmbed() + .setColor(`GREEN`) + .addField(`__**Access a user's server**__`, '', true); + message.channel.send(embed) + + } else { + + } + } }; \ No newline at end of file diff --git a/Panel/bot/discord/commands/apikey.js b/Panel/bot/discord/commands/apikey.js new file mode 100644 index 000000000..8558f9bda --- /dev/null +++ b/Panel/bot/discord/commands/apikey.js @@ -0,0 +1,89 @@ +let db = require("quick.db"); +const Discord = require("discord.js"); + +exports.run = async (client, message, args) => { + /* to do: + + - create api key, example: danbot-key + - send it to the user + - reset a key + - store the key under an array + + */ + + let startkey = Math.random() + .toString(36) + .substring(7); + let key = `danbot-${startkey}`; + + let keyPool = db.get("apiKeys"); + if (!keyPool) keyPool = []; + + if (!args[0]) { + if (db.has(`${message.author.id}_apikey`)) { + return message.channel.send( + "You already have a `Key`, please check your direct messages, \n or do `DBH!APIKey Reset`" + ); + } + + let Awaiter = await message.channel.send( + "Getting you an `API` Key please wait..." + ); + + setTimeout(() => { + command(); + Awaiter.delete(); + }, 2500); + + async function command() { + try { + let apiKeyEmbed = new Discord.RichEmbed() + .setColor("BLUE") + .setTitle("DanBot Hosting Bot Stats") + .setDescription( + `API Key:\n\`${key}\`\n\nHow to Post? [Visit This](https://www.npmjs.com/package/danbot-hosting) \n Package Github: [Click Here](https://github.com/danbot-devs/danbot-hosting)` + ); + + message.author.send(apiKeyEmbed); + message.channel.send("Check your direct messages for your `API` key."); + } catch (e) { + return message.channel.send( + `I ran into an error while trying to setup your api key. \n Error: ${e}` + ); + } + + db.push("apiKeys", key); + db.set(`${message.author.id}_apikey`, key); + db.set(`${key}`, message.author.id) + return; + } + } + + if (args[0].toLowerCase() === "reset") { + // reset token + let token = db.get(`${message.author.id}_apikey`); + if (!token) + return message.channel.send( + "You dont have an api key to reset, please use `DBH!APIKey` to generate one!" + ); + + let Reset = await message.channel.send(`Resetting your API Key...`); + + setTimeout(() => { + rest(); + Reset.delete(); + }, 2500); + + async function rest() { + let keys = db.get("apiKeys"); + var filtered = keys.filter(function(el) { + return el != `${token}`; + }); + + db.set("apiKeys", filtered); + db.delete(`${message.author.id}_apikey`); + db.delete(`${token}`) + return message.channel.send("Your API Key has been reset!"); + } + } +}; \ No newline at end of file diff --git a/Panel/bot/discord/commands/changelog.js b/Panel/bot/discord/commands/changelog.js index 45c5ad4ac..e9fd954b4 100644 --- a/Panel/bot/discord/commands/changelog.js +++ b/Panel/bot/discord/commands/changelog.js @@ -1,11 +1,11 @@ -var getRepoInfo = require('git-repo-info'); -exports.run = async (client, message) => { - var info = getRepoInfo(); - - let embed = new Discord.RichEmbed() - .setColor(`BLUE`) - .addField(`__**Latest GitHub push:**__`, info.committerDate) - .addField(`__**Latest GitHub commit message:**__`, info.commitMessage) - .addField(`__**Latest GitHub committer:**__`, info.committer) - message.channel.send(embed) +var getRepoInfo = require('git-repo-info'); +exports.run = async (client, message) => { + var info = getRepoInfo(); + + let embed = new Discord.RichEmbed() + .setColor(`BLUE`) + .addField(`__**Latest GitHub push:**__`, info.committerDate) + .addField(`__**Latest GitHub commit message:**__`, info.commitMessage) + .addField(`__**Latest GitHub committer:**__`, info.committer) + message.channel.send(embed) }; \ No newline at end of file diff --git a/Panel/bot/discord/commands/createserver.js b/Panel/bot/discord/commands/createserver.js new file mode 100644 index 000000000..4b7b9f997 --- /dev/null +++ b/Panel/bot/discord/commands/createserver.js @@ -0,0 +1,6 @@ +const axios = require('axios'); +const { response } = require('express'); +exports.run = async (client, message, args) => { + message.channel.send('Command has been renamed to `' + config.DiscordBot.Prefix + "server create`") + +}; \ No newline at end of file diff --git a/Panel/bot/discord/commands/eval.js b/Panel/bot/discord/commands/eval.js index c8df108d9..4505fc1d8 100644 --- a/Panel/bot/discord/commands/eval.js +++ b/Panel/bot/discord/commands/eval.js @@ -1,7 +1,8 @@ const execSync = require('child_process').execSync; - +const ms = require('ms'); exports.run = async(client, message) => { - if (message.author.id !== config.DiscordBot.ownerID) { + let ids = [ "338192747754160138", "137624084572798976", "293841631583535106"]; + if (!ids.includes(message.author.id)) { return message.channel.send(`Only my master can use this command`); } diff --git a/Panel/bot/discord/commands/exec.js b/Panel/bot/discord/commands/exec.js index 08cdbde1e..7313788b1 100644 --- a/Panel/bot/discord/commands/exec.js +++ b/Panel/bot/discord/commands/exec.js @@ -1,6 +1,6 @@ const exec = require('child_process').exec; exports.run = (client, message, args) => { - if (message.author.id !== config.DiscordBot.ownerID) { + if (message.author.id == config.DiscordBot.ownerID) { const start = process.hrtime(); exec(`${args.join(" ")}`, (error, stdout) => { let response = (error || stdout); diff --git a/Panel/bot/discord/commands/getstarted-new.js b/Panel/bot/discord/commands/getstarted-new.js index 99d1659c6..cd60fa44b 100644 --- a/Panel/bot/discord/commands/getstarted-new.js +++ b/Panel/bot/discord/commands/getstarted-new.js @@ -1,250 +1,250 @@ -exports.run = async (client, message) => { - //Args - const args = message.content.split(' ').slice(1).join(' '); - var validator = require('validator'); - - //Random password gen - var CAPSNUM = "ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890"; - let getPassword = () => { - - var password = ""; - while (password.length < 10) { - password += CAPSNUM[Math.floor(Math.random() * CAPSNUM.length)]; - } - return password; - }; - - if (args == "") { - let embed = new Discord.RichEmbed() - .setColor(`BLUE`) - .addField(`__**How to get started!**__`, 'Create an account by typing: `' + config.DiscordBot.Prefix + 'getstarted account` \nOnce done run `' + config.DiscordBot.Prefix + 'getstarted server` to create a server! \n \nAny problems? Please send a message in <#640158951899398144>', true); - message.channel.send(embed) - - } else if (args == "account") { - const server = message.guild - - let channel = await server.createChannel(message.author.tag, "text", [{ - type: 'role', - id: message.guild.id, - deny: 0x400 - }, - { - type: 'user', - id: message.author.id, - deny: 1024 - } - ]).catch(console.error); - console.log(channel.id) - message.channel.send('<@' + message.author.id + '>, Please check <#' + channel.id + '>') - - let category = server.channels.find(c => c.id == "697585283214082078" && c.type == "category"); - if (!category) throw new Error("Category channel does not exist"); - - await channel.setParent(category.id); - - channel.overwritePermissions(message.author, { - VIEW_CHANNEL: true, - SEND_MESSAGES: true, - READ_MESSAGE_HISTORY: true - }) - - - const filter2 = m => m.author.id === message.author.id; - - let msg = await channel.send("<@" + message.author.id + ">", { - embed: new Discord.RichEmbed() - .setColor(0x36393e) - .setDescription("Please enter a username") - .setFooter("You can type 'cancel' to cancel the request") - }) - - //First Collection "UserName" - - let collected1 = await channel.awaitMessages(filter2, { - max: 1, - time: 30000, - errors: ['time'], - }).catch(x => { - msg.delete() - channel.send(`ERROR: User failed to provide an answer.`); - setTimeout(() => { - channel.delete(); - }, 3000); - return false; - }) - - if (collected1.first().content === 'cancel') { - return msg.edit("Request to create a new user has been canceled!", null).then(channel.delete()) - } - - await msg.edit("", { - embed: new Discord.RichEmbed() - .setColor(0x36393e) - .setDescription(`Username: **${collected1.first().content}** \nPlease enter a Email.`) - .setFooter("You can type 'cancel' to cancel the request") - }) - collected1.first().delete(); - - //scnd Collection "Email" - - let collected2 = await channel.awaitMessages(filter2, { - max: 1, - time: 30000, - errors: ['time'], - }).catch(x => { - msg.delete() - channel.send(`ERROR: User failed to provide an answer.`); - setTimeout(() => { - channel.delete(); - }, 3000); - return false; - }) - - - if (collected2.first().content === 'cancel') { - msg.edit("Request to create a new user has been canceled!", null).then(channel.delete()) - return false; - } - - if (!validator.isEmail(collected2.first().content.trim())) { - msg.delete() - channel.send(`\`${collected2.first().content.trim()}`+"` is not a Valid Email!"); - setTimeout(() => { - channel.delete(); - }, 10000); - return false; - } - collected2.first().delete(); - - let password = await getPassword(); - - DanBotHosting.createUser(collected1.first().content, password, collected2.first().content, collected1.first().content, ".", false, "en").then(user => { - - console.log(user) - - if (user == "Error: User already exists! (Or Email/Username is existing already)") { - msg.edit("ERROR: A user with that email/username already exists.", null) - setTimeout(function () { - channel.delete(); - }, 10000); - return false; - } - msg.edit("Hello! You created an new account, Heres the login information", { - embed: new Discord.RichEmbed() - .setColor(0x36393e) - .setDescription("URL: " + config.Pterodactyl.hosturl + " \nUsername: " + collected1.first().content + " \nEmail: " + collected2.first().content + " \nPassword: " + password) - .setFooter("Please note: It is recommended that you change the password") - }) - channel.send('**You have 1Hour to keep note of this info before the channel is deleted.**') - message.guild.members.get(message.author.id).addRole("639489891016638496"); - setTimeout(function () { - channel.delete(); - }, 3600000); - - }).catch(err => { - console.log(err); - }) - - } else if (args == "server") { - message.channel.send('This is being worked on. Please ping one of our Admins or the Owner and they will create a server for you!') - - const server = message.guild - - let channel = await server.createChannel(message.author.tag, "text", [{ - type: 'role', - id: message.guild.id, - deny: 0x400 - }, - { - type: 'user', - id: message.author.id, - deny: 1024 - } - ]).catch(console.error); - console.log(channel.id) - message.channel.send('<@' + message.author.id + '>, Please check <#' + channel.id + '>') - - let category = server.channels.find(c => c.id == "697585283214082078" && c.type == "category"); - if (!category) throw new Error("Category channel does not exist"); - - await channel.setParent(category.id); - - channel.overwritePermissions(message.author, { - VIEW_CHANNEL: true, - SEND_MESSAGES: true, - READ_MESSAGE_HISTORY: true - }) - - - const filter2 = m => m.author.id === message.author.id; - - let msg = await channel.send("<@" + message.author.id + ">", { - embed: new Discord.RichEmbed() - .setColor(0x36393e) - .setDescription("What would you like the server to be called?") - .setFooter("You can type 'cancel' to cancel the request") - }) - - //First Collection "Server name" - - let collected1 = await channel.awaitMessages(filter2, { - max: 1, - time: 30000, - errors: ['time'], - }).catch(x => { - msg.delete() - channel.send(`ERROR: User failed to provide an answer.`); - setTimeout(() => { - channel.delete(); - }, 3000); - return false; - }) - - if (collected1.first().content === 'cancel') { - return msg.edit("Request to create a new server has been canceled!", null).then(channel.delete()) - } - - await msg.edit("", { - embed: new Discord.RichEmbed() - .setColor(0x36393e) - .setDescription(`Servername: **${collected1.first().content}** \nMinecraft or NodeJS`) - .setFooter("You can type 'cancel' to cancel the request") - }) - collected1.first().delete(); - - //send Collection "Server type" - - let collected2 = await channel.awaitMessages(filter2, { - max: 1, - time: 30000, - errors: ['time'], - }).catch(x => { - msg.delete() - channel.send(`ERROR: User failed to provide an answer.`); - setTimeout(() => { - channel.delete(); - }, 3000); - return false; - }) - - - if (collected2.first().content === 'cancel') { - msg.edit("Request to create a new server has been canceled!", null).then(channel.delete()) - return false; - } else if (collected2.first().content.toLowerCase() === 'minecraft') { - collected2.first().delete(); - console.log(collected1.first().content) - DanBotHosting.createServer("latest", `test`, `1`, null, "3", "quay.io/pterodactyl/core:java", "java -Xms128M -Xmx{{SERVER_MEMORY}}M -Dterminal.jline=false -Dterminal.ansi=true -jar {{SERVER_JARFILE}}", "2048", "0", "25000", "500", "0", "0", "1").then(res => { - //DanBotHosting.createServer("latest", collected1.first().content, userData.fetch(message.author.id + ".consoleID"), null, "3", "quay.io/pterodactyl/core:java", null, "2048", "0", "5000", "500", "200", "0", "0").then(res => { - console.log(res) - }).catch(error =>{ - console.log(error); - }) - - } else if (collected2.first().content === 'nodejs') { - collected2.first().delete(); - - } - } - +exports.run = async (client, message) => { + //Args + const args = message.content.split(' ').slice(1).join(' '); + var validator = require('validator'); + + //Random password gen + var CAPSNUM = "ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890"; + let getPassword = () => { + + var password = ""; + while (password.length < 10) { + password += CAPSNUM[Math.floor(Math.random() * CAPSNUM.length)]; + } + return password; + }; + + if (args == "") { + let embed = new Discord.RichEmbed() + .setColor(`BLUE`) + .addField(`__**How to get started!**__`, 'Create an account by typing: `' + config.DiscordBot.Prefix + 'getstarted account` \nOnce done run `' + config.DiscordBot.Prefix + 'getstarted server` to create a server! \n \nAny problems? Please send a message in <#640158951899398144>', true); + message.channel.send(embed) + + } else if (args == "account") { + const server = message.guild + + let channel = await server.createChannel(message.author.tag, "text", [{ + type: 'role', + id: message.guild.id, + deny: 0x400 + }, + { + type: 'user', + id: message.author.id, + deny: 1024 + } + ]).catch(console.error); + console.log(channel.id) + message.channel.send('<@' + message.author.id + '>, Please check <#' + channel.id + '>') + + let category = server.channels.find(c => c.id == "697585283214082078" && c.type == "category"); + if (!category) throw new Error("Category channel does not exist"); + + await channel.setParent(category.id); + + channel.overwritePermissions(message.author, { + VIEW_CHANNEL: true, + SEND_MESSAGES: true, + READ_MESSAGE_HISTORY: true + }) + + + const filter2 = m => m.author.id === message.author.id; + + let msg = await channel.send("<@" + message.author.id + ">", { + embed: new Discord.RichEmbed() + .setColor(0x36393e) + .setDescription("Please enter a username") + .setFooter("You can type 'cancel' to cancel the request") + }) + + //First Collection "UserName" + + let collected1 = await channel.awaitMessages(filter2, { + max: 1, + time: 30000, + errors: ['time'], + }).catch(x => { + msg.delete() + channel.send(`ERROR: User failed to provide an answer.`); + setTimeout(() => { + channel.delete(); + }, 3000); + return false; + }) + + if (collected1.first().content === 'cancel') { + return msg.edit("Request to create a new user has been canceled!", null).then(channel.delete()) + } + + await msg.edit("", { + embed: new Discord.RichEmbed() + .setColor(0x36393e) + .setDescription(`Username: **${collected1.first().content}** \nPlease enter a Email.`) + .setFooter("You can type 'cancel' to cancel the request") + }) + collected1.first().delete(); + + //scnd Collection "Email" + + let collected2 = await channel.awaitMessages(filter2, { + max: 1, + time: 30000, + errors: ['time'], + }).catch(x => { + msg.delete() + channel.send(`ERROR: User failed to provide an answer.`); + setTimeout(() => { + channel.delete(); + }, 3000); + return false; + }) + + + if (collected2.first().content === 'cancel') { + msg.edit("Request to create a new user has been canceled!", null).then(channel.delete()) + return false; + } + + if (!validator.isEmail(collected2.first().content.trim())) { + msg.delete() + channel.send(`\`${collected2.first().content.trim()}`+"` is not a Valid Email!"); + setTimeout(() => { + channel.delete(); + }, 10000); + return false; + } + collected2.first().delete(); + + let password = await getPassword(); + + DanBotHosting.createUser(collected1.first().content, password, collected2.first().content, collected1.first().content, ".", false, "en").then(user => { + + console.log(user) + + if (user == "Error: User already exists! (Or Email/Username is existing already)") { + msg.edit("ERROR: A user with that email/username already exists.", null) + setTimeout(function () { + channel.delete(); + }, 10000); + return false; + } + msg.edit("Hello! You created an new account, Heres the login information", { + embed: new Discord.RichEmbed() + .setColor(0x36393e) + .setDescription("URL: " + config.Pterodactyl.hosturl + " \nUsername: " + collected1.first().content + " \nEmail: " + collected2.first().content + " \nPassword: " + password) + .setFooter("Please note: It is recommended that you change the password") + }) + channel.send('**You have 1Hour to keep note of this info before the channel is deleted.**') + message.guild.members.get(message.author.id).addRole("639489891016638496"); + setTimeout(function () { + channel.delete(); + }, 3600000); + + }).catch(err => { + console.log(err); + }) + + } else if (args == "server") { + message.channel.send('This is being worked on. Please ping one of our Admins or the Owner and they will create a server for you!') + + const server = message.guild + + let channel = await server.createChannel(message.author.tag, "text", [{ + type: 'role', + id: message.guild.id, + deny: 0x400 + }, + { + type: 'user', + id: message.author.id, + deny: 1024 + } + ]).catch(console.error); + console.log(channel.id) + message.channel.send('<@' + message.author.id + '>, Please check <#' + channel.id + '>') + + let category = server.channels.find(c => c.id == "697585283214082078" && c.type == "category"); + if (!category) throw new Error("Category channel does not exist"); + + await channel.setParent(category.id); + + channel.overwritePermissions(message.author, { + VIEW_CHANNEL: true, + SEND_MESSAGES: true, + READ_MESSAGE_HISTORY: true + }) + + + const filter2 = m => m.author.id === message.author.id; + + let msg = await channel.send("<@" + message.author.id + ">", { + embed: new Discord.RichEmbed() + .setColor(0x36393e) + .setDescription("What would you like the server to be called?") + .setFooter("You can type 'cancel' to cancel the request") + }) + + //First Collection "Server name" + + let collected1 = await channel.awaitMessages(filter2, { + max: 1, + time: 30000, + errors: ['time'], + }).catch(x => { + msg.delete() + channel.send(`ERROR: User failed to provide an answer.`); + setTimeout(() => { + channel.delete(); + }, 3000); + return false; + }) + + if (collected1.first().content === 'cancel') { + return msg.edit("Request to create a new server has been canceled!", null).then(channel.delete()) + } + + await msg.edit("", { + embed: new Discord.RichEmbed() + .setColor(0x36393e) + .setDescription(`Servername: **${collected1.first().content}** \nMinecraft or NodeJS`) + .setFooter("You can type 'cancel' to cancel the request") + }) + collected1.first().delete(); + + //send Collection "Server type" + + let collected2 = await channel.awaitMessages(filter2, { + max: 1, + time: 30000, + errors: ['time'], + }).catch(x => { + msg.delete() + channel.send(`ERROR: User failed to provide an answer.`); + setTimeout(() => { + channel.delete(); + }, 3000); + return false; + }) + + + if (collected2.first().content === 'cancel') { + msg.edit("Request to create a new server has been canceled!", null).then(channel.delete()) + return false; + } else if (collected2.first().content.toLowerCase() === 'minecraft') { + collected2.first().delete(); + console.log(collected1.first().content) + DanBotHosting.createServer("latest", `test`, `1`, null, "3", "quay.io/pterodactyl/core:java", "java -Xms128M -Xmx{{SERVER_MEMORY}}M -Dterminal.jline=false -Dterminal.ansi=true -jar {{SERVER_JARFILE}}", "2048", "0", "25000", "500", "0", "0", "1").then(res => { + //DanBotHosting.createServer("latest", collected1.first().content, userData.fetch(message.author.id + ".consoleID"), null, "3", "quay.io/pterodactyl/core:java", null, "2048", "0", "5000", "500", "200", "0", "0").then(res => { + console.log(res) + }).catch(error =>{ + console.log(error); + }) + + } else if (collected2.first().content === 'nodejs') { + collected2.first().delete(); + + } + } + }; \ No newline at end of file diff --git a/Panel/bot/discord/commands/getstarted.js b/Panel/bot/discord/commands/getstarted.js index ee4858840..3c6d25903 100644 --- a/Panel/bot/discord/commands/getstarted.js +++ b/Panel/bot/discord/commands/getstarted.js @@ -21,6 +21,7 @@ exports.run = async (client, message) => { message.channel.send(embed) } else if (args == "account") { + if (userData.get(message.author.id) == null) { const server = message.guild let channel = await server.createChannel(message.author.tag, "text", [{ @@ -36,7 +37,7 @@ exports.run = async (client, message) => { ]).catch(console.error); message.reply(`Please check <#${channel.id}> to create an account.`) - let category = server.channels.find(c => c.id == "697585283214082078" && c.type == "category"); + let category = server.channels.find(c => c.id == "738539016688894024" && c.type == "category"); if (!category) throw new Error("Category channel does not exist"); await channel.setParent(category.id); @@ -101,8 +102,7 @@ exports.run = async (client, message) => { if (collected2.first().content === 'cancel') { - msg.edit("Request to create a new user has been canceled!", null).then(channel.delete()) - return false; + channel.delete() } if (!validator.isEmail(collected2.first().content.trim())) { @@ -120,7 +120,18 @@ exports.run = async (client, message) => { DanBotHosting.createUser(collected1.first().content, password, collected2.first().content, collected1.first().content, ".", false, "en").then(user => { console.log(user) - if (user == "Error: User already exists! (Or Email/Username is existing already)") { + const timestamp = `${moment().format("HH:mm:ss")}`; + const datestamp = `${moment().format("YYYY-MM-DD")}`; + userData.set(`${message.author.id}`, { + discordID: message.author.id, + consoleID: user.id, + email: user.email, + username: user.username, + linkTime: timestamp, + linkDate: datestamp + }) + + if (user == "Error: User already exists! (Or Email/Username is in use already)") { msg.edit("ERROR: A user with that email/username already exists.", null) setTimeout(function () { channel.delete(); @@ -139,32 +150,21 @@ exports.run = async (client, message) => { channel.delete(); }, 3600000); - //Account Linking. - consoleUser = consoleUser.filter(x => x.attributes.email == collected2.first().content) - console.log(consoleUser) - - if (consoleUser.length == 0) return console.log(chalk.magenta('[DISCORD] ') + chalk.green("No account with that email exists...")).then( - ) - - consoleUser = consoleUser[0]; - const timestamp = `${moment().format("HH:mm:ss")}`; - const datestamp = `${moment().format("YYYY-MM-DD")}`; - userData.set(`${message.author.id}`, { - discordID: message.author.id, - consoleID: consoleUser.attributes.id, - email: consoleUser.attributes.email, - username: consoleUser.attributes.username, - linkTime: timestamp, - linkDate: datestamp - }) - }).catch(err => { - console.log(err); + if (err = "Error: User already exists! (Or Email/Username is in use already)") { + msg.edit("ERROR: A user with that email/username already exists.", null) + setTimeout(function () { + channel.delete(); + }, 10000); + } }) - + } else { + message.channel.send('You already have an account') + } } else if (args == "server") { - message.channel.send('This is being worked on. Please ping one of our Admins or the Owner and they will create a server for you!') + message.channel.send('Please use `' + config.DiscordBot.Prefix + "server create type servername` \nTo see server types please do: `" + config.DiscordBot.Prefix + "server create list`") + const filter2 = m => m.author.id === message.author.id; /* const filter2 = m => m.author.id === message.author.id; message.channel.send("", { embed: new Discord.RichEmbed() diff --git a/Panel/bot/discord/commands/giveaway.js b/Panel/bot/discord/commands/giveaway.js index 95d4d50dd..5556a313e 100644 --- a/Panel/bot/discord/commands/giveaway.js +++ b/Panel/bot/discord/commands/giveaway.js @@ -1,109 +1,109 @@ -const ms = require('ms') -exports.run = async (bot, message, args) => { - if (message.member.roles.find(r => r.name === "Owner")) { - message.delete() - let channel, giveaway; - let time = args[0]; - const prefix = `${config.DiscordBot.prefix}giveaway ${time}`; - const a = message.content.slice(prefix.length).split(' '); - const prize = a.join(' ') - let actualTime = ms(time) - - try{ - if(!channel) { - let reaction = '🎉'; - let giveawayMessage = await message.channel.send("", { - embed: new Discord.RichEmbed() - .setTitle("GIVEAWAY! 🎉") - .setDescription(`Giveaway event started by <@${message.author.id}>. React to this message with ${reaction} to get a chance to win **${prize}**.`) - .setColor("#0000ff") - .setFooter(`Event stops in ${time}. You will get your reward after the event has concluded.`) - }); - await giveawayMessage.react(reaction); - - let giveawayMessageID = giveawayMessage.id; - channel = message.channel.id; - - let interval = await setInterval (function () { - time = ms(time) - time = time - 5000 - time = ms(time) - if(time === '5s' || time === '4s' || time === '3s' || time === '2s' || time === '1s' || time === '0s') clearInterval(interval) - giveawayMessage.edit("🎉🎉🎉", { - embed: new Discord.RichEmbed() - .setTitle("GIVEAWAY! 🎉") - .setDescription(`Giveaway event started by <@${message.author.id}>. React to this message with ${reaction} to get a chance to win **${prize}**.`) - .setColor("#0000ff") - .setFooter(`Event stops in ${time}. You will get your reward after the event has concluded.`) - }); - }, 5 * 1000); - - giveaway = bot.setTimeout(async () => { - let giveawayMessage = await message.channel.fetchMessage(giveawayMessageID); - - let winners = []; - if (giveawayMessage.reactions.get(reaction)) { - winners = giveawayMessage.reactions.get(reaction).users.filter(user => !user.bot).map(u => u.id); - } - - let winner; - while (!winner && winners.length) { - winner = winners[Math.floor(Math.random() * winners.length)]; - winners.splice(winners.indexOf(winner), 1); - winner = await bot.fetchUser(winner).catch(() => {}); - } - - if (winner) { - - giveawayMessage.edit("", { - embed: new Discord.RichEmbed() - .setTitle("Giveaway Event Ended") - .setDescription(`${winner} won the giveaway! You just won ${prize}!\nThank you everyone for participating. Better luck next time.`) - .setColor("#0000ff") - }).catch(err => { - console.log(err); - }); - - winner.send("", { - embed: new Discord.RichEmbed() - .setTitle("Congratulations") - .setDescription(`You won the giveaway in **${message.guild.name}** Server! And you've been awarded with **${prize}**!`) - .setColor("#0000ff") - }).catch(() => {}); - } - else { - giveawayMessage.edit("", { - embed: new Discord.RichEmbed() - .setTitle("Giveaway Event Ended") - .setDescription(`Unfortunately, no one participated and apparently there\'s no winner. 😕`) - .setColor("#ff0000") - }).catch(e => { - bot.log.error(e); - }); - } - - channel = null; - }, actualTime); - } - else { - if (args[0] === 'end') { - bot.clearTimeout(giveaway); - channel = null; - - message.channel.send("", { - embed: new Discord.RichEmbed() - .setTitle("Giveaway Event Ended") - .setDescription(`The giveaway event was abruptly ended by ${message.author.tag}. Sorry, no giveaways this time!`) - .setColor("#ff0000") - }).catch(e => { - bot.log.error(e); - }); - } - else { - return; - } - } - } catch (err) { - console.log(err) - } +const ms = require('ms') +exports.run = async (bot, message, args) => { + if (message.member.roles.find(r => r.name === "Owner")) { + message.delete() + let channel, giveaway; + let time = args[0]; + const prefix = `${config.DiscordBot.prefix}giveaway ${time}`; + const a = message.content.slice(prefix.length).split(' '); + const prize = a.join(' ') + let actualTime = ms(time) + + try{ + if(!channel) { + let reaction = '🎉'; + let giveawayMessage = await message.channel.send("", { + embed: new Discord.RichEmbed() + .setTitle("GIVEAWAY! 🎉") + .setDescription(`Giveaway event started by <@${message.author.id}>. React to this message with ${reaction} to get a chance to win **${prize}**.`) + .setColor("#0000ff") + .setFooter(`Event stops in ${time}. You will get your reward after the event has concluded.`) + }); + await giveawayMessage.react(reaction); + + let giveawayMessageID = giveawayMessage.id; + channel = message.channel.id; + + let interval = await setInterval (function () { + time = ms(time) + time = time - 5000 + time = ms(time) + if(time === '5s' || time === '4s' || time === '3s' || time === '2s' || time === '1s' || time === '0s') clearInterval(interval) + giveawayMessage.edit("🎉🎉🎉", { + embed: new Discord.RichEmbed() + .setTitle("GIVEAWAY! 🎉") + .setDescription(`Giveaway event started by <@${message.author.id}>. React to this message with ${reaction} to get a chance to win **${prize}**.`) + .setColor("#0000ff") + .setFooter(`Event stops in ${time}. You will get your reward after the event has concluded.`) + }); + }, 5 * 1000); + + giveaway = bot.setTimeout(async () => { + let giveawayMessage = await message.channel.fetchMessage(giveawayMessageID); + + let winners = []; + if (giveawayMessage.reactions.get(reaction)) { + winners = giveawayMessage.reactions.get(reaction).users.filter(user => !user.bot).map(u => u.id); + } + + let winner; + while (!winner && winners.length) { + winner = winners[Math.floor(Math.random() * winners.length)]; + winners.splice(winners.indexOf(winner), 1); + winner = await bot.fetchUser(winner).catch(() => {}); + } + + if (winner) { + + giveawayMessage.edit("", { + embed: new Discord.RichEmbed() + .setTitle("Giveaway Event Ended") + .setDescription(`${winner} won the giveaway! You just won ${prize}!\nThank you everyone for participating. Better luck next time.`) + .setColor("#0000ff") + }).catch(err => { + console.log(err); + }); + + winner.send("", { + embed: new Discord.RichEmbed() + .setTitle("Congratulations") + .setDescription(`You won the giveaway in **${message.guild.name}** Server! And you've been awarded with **${prize}**!`) + .setColor("#0000ff") + }).catch(() => {}); + } + else { + giveawayMessage.edit("", { + embed: new Discord.RichEmbed() + .setTitle("Giveaway Event Ended") + .setDescription(`Unfortunately, no one participated and apparently there\'s no winner. 😕`) + .setColor("#ff0000") + }).catch(e => { + bot.log.error(e); + }); + } + + channel = null; + }, actualTime); + } + else { + if (args[0] === 'end') { + bot.clearTimeout(giveaway); + channel = null; + + message.channel.send("", { + embed: new Discord.RichEmbed() + .setTitle("Giveaway Event Ended") + .setDescription(`The giveaway event was abruptly ended by ${message.author.tag}. Sorry, no giveaways this time!`) + .setColor("#ff0000") + }).catch(e => { + bot.log.error(e); + }); + } + else { + return; + } + } + } catch (err) { + console.log(err) + } }} \ No newline at end of file diff --git a/Panel/bot/discord/commands/help.js b/Panel/bot/discord/commands/help.js index cb1d02220..22ac573f2 100644 --- a/Panel/bot/discord/commands/help.js +++ b/Panel/bot/discord/commands/help.js @@ -1,22 +1,22 @@ const Help = { - "Users": `${config.DiscordBot.Prefix}getstarted | Create a server or account \n${config.DiscordBot.Prefix}link | Link your console account with your discord account \n${config.DiscordBot.Prefix}linked | Check if your account is linked \n${config.DiscordBot.Prefix}stats | Shows the stats of each hosting node. \n${config.DiscordBot.Prefix}ticket | Create a ticket for help from the staff team! \n${config.DiscordBot.Prefix}status | Check the status of your server! \n${config.DiscordBot.Prefix}uptime | Shows the bots uptime \n${config.DiscordBot.Prefix}changelog | Check the changelog for the github commit. \n${config.DiscordBot.Prefix}radio | Joins VC and plays DanBot Radio.`, + "Users": `${config.DiscordBot.Prefix}getstarted | Create a server or account \n${config.DiscordBot.Prefix}link | Link your console account with your discord account \n${config.DiscordBot.Prefix}linked | Check if your account is linked \n${config.DiscordBot.Prefix}stats | Shows the stats of each hosting node. \n${config.DiscordBot.Prefix}ticket | Create a ticket for help from the staff team! \n${config.DiscordBot.Prefix}status | Check the status of your server! \n${config.DiscordBot.Prefix}uptime | Shows the bots uptime \n${config.DiscordBot.Prefix}changelog | Check the changelog for the github commit. \n${config.DiscordBot.Prefix}radio | Joins VC and plays DanBot Radio.\n${config.DiscordBot.Prefix}info | Get a bots info. \n ${config.DiscordBot.Prefix}suggest | Get the link to send in suggestions.`, "Staff": `${config.DiscordBot.Prefix}staff | Gets the ID of a user on console using their discord ID \n${config.DiscordBot.Prefix}purge | Delete messages in a channel \n${config.DiscordBot.Prefix}access | Gain subuser access to a server`, "Owner": `${config.DiscordBot.Prefix}reload | Reloads all commands on the bot \n${config.DiscordBot.Prefix}restart | Restarts **EVERYTHING**, Bot and Stats website \n${config.DiscordBot.Prefix}say | Says what you want it to say \n${config.DiscordBot.Prefix}eval | Eval some code \n${config.DiscordBot.Prefix}exec | Run some system commands \n${config.DiscordBot.Prefix}giveaway | Launch a giveaway` } exports.run = async (client, message, args) => { - if (message.member.roles.find(r => r.id === "713154800178561134")) { + if (message.member.roles.find(r => r.id === "639481606112804875")) { let embed = new Discord.RichEmbed() .setColor(`BLUE`) .addField(`__**Commands List for users:**__`, Help.Users) .addField(`__**Staff Commands:**__`, Help.Staff) + .addField(`__**Owner Commands:**__`, Help.Owner) message.channel.send(embed) - } else if (message.member.roles.find(r => r.id === "639481606112804875")) { + } else if (message.member.roles.find(r => r.id === "748117822370086932")) { let embed = new Discord.RichEmbed() .setColor(`BLUE`) .addField(`__**Commands List for users:**__`, Help.Users) .addField(`__**Staff Commands:**__`, Help.Staff) - .addField(`__**Owner Commands:**__`, Help.Owner) message.channel.send(embed) } else if (message.member.roles.find(r => r.id === "639490038434103306")) { let embed = new Discord.RichEmbed() diff --git a/Panel/bot/discord/commands/info.js b/Panel/bot/discord/commands/info.js new file mode 100644 index 000000000..bf654ab50 --- /dev/null +++ b/Panel/bot/discord/commands/info.js @@ -0,0 +1,32 @@ +let db = require("quick.db"); +const Discord = require("discord.js"); + +exports.run = async (client, message, args) => { + + let botID = args[0]; + if (message.mentions.users.first()) { + let t = message.mentions.users.first(); + botID = t.id; + }; + + if(!botID)return message.channel.send("Error: Please provide a bot id!"); + let bot = db.get(`${botID}`); + + if(!bot)return message.channel.send("Error: The bot you gave is not in my database!"); + if(bot.deleted)return message.channel.send("Error: This bot has been deleted."); + + let infoEmbed = new Discord.RichEmbed() + .setColor("BLUE") + .setTitle(`${bot.client.username} | DanBot Hosting Stats`) + .setURL("https://danbot.host/bot/" + bot.id) + .setThumbnail(`https://cdn.discordapp.com/avatars/${bot.id}/${bot.client.avatar}`) + .setDescription(` + **Status:** ${bot.status} + **Servers:** ${bot.servers.toLocaleString()} + **Users:** ${bot.users.toLocaleString()} + `) + .addField("Owner", `<@${bot.owner}> \`(${bot.owner})\``) + + message.channel.send(infoEmbed) + +}; \ No newline at end of file diff --git a/Panel/bot/discord/commands/link.js b/Panel/bot/discord/commands/link.js index adc7417ba..a1f648f6a 100644 --- a/Panel/bot/discord/commands/link.js +++ b/Panel/bot/discord/commands/link.js @@ -1,13 +1,11 @@ var path = require("path") var fs = require("fs") const moment = require("moment"); +const axios = require('axios'); exports.run = async (client, message) => { - const args = message.content.split(' ').slice(1).join(' '); - let result = userData.get(message.author.id) if (userData.get(message.author.id) == null) { - if (message.member.roles.find(r => r.id === "639489891016638496")) { const server = message.guild @@ -24,7 +22,7 @@ exports.run = async (client, message) => { ]).catch(console.error); message.reply(`Please check <#${channel.id}> to link your account.`) - let category = server.channels.find(c => c.id == "697585283214082078" && c.type == "category"); + let category = server.channels.find(c => c.id == "738539016688894024" && c.type == "category"); if (!category) throw new Error("Category channel does not exist"); await channel.setParent(category.id); @@ -36,78 +34,218 @@ exports.run = async (client, message) => { }) - const filter2 = m => m.author.id === message.author.id; let msg = await channel.send(message.author, { embed: new Discord.RichEmbed() .setColor(0x36393e) .setDescription("Please enter your console email address") - .setFooter("You can type 'cancel' to cancel the request") - }) - - let collected1 = await channel.awaitMessages(filter2, { - max: 1, - time: 60000, - errors: ['time'], - }).catch(x => { - msg.delete() - channel.send(`ERROR: User failed to provide an answer.`); - setTimeout(() => { - channel.delete(); - }, 3000); - return false; + .setFooter("You can type 'cancel' to cancel the request \n**This will take a few seconds to find your account.**") }) - if (collected1.first().content === 'cancel') { + const collector = new Discord.MessageCollector(channel, m => m.author.id === message.author.id, { time: 60000 }); + collector.on('collect', message => { + //console.log(message.content) + + if (message.content === 'cancel') { return msg.edit("Request to link your account canceled.", null).then(channel.delete()) } - let consoleUser3 = await DanBotHosting.getAllUsers(); - console.log(consoleUser3) - consoleUser2 = consoleUser3.filter(x => x.attributes.email == collected1.first().content.trim()) - console.log(consoleUser2) - - if (consoleUser2.length == 0) return channel.send("No account with that email exists...").then( - setTimeout(() => { - channel.delete(); - }, 5000) - ) - - consoleUser = consoleUser2[0]; - const timestamp = `${moment().format("HH:mm:ss")}`; - const datestamp = `${moment().format("YYYY-MM-DD")}`; - userData.set(`${message.author.id}`, { - discordID: message.author.id, - consoleID: consoleUser.attributes.id, - email: consoleUser.attributes.email, - username: consoleUser.attributes.username, - linkTime: timestamp, - linkDate: datestamp - }) - - let embedstaff = new Discord.RichEmbed() - .setColor('GREEN') - .addField('__**Linked Discord account:**__', message.author.id) - .addField('__**Linked Console account email:**__', consoleUser.attributes.email) - .addField('__**Linked At: (TIME / DATE)**__', timestamp + " / " + datestamp) - .addField('__**Linked Console username:**__', consoleUser.attributes.username) - .addField('__**Linked Console ID:**__', consoleUser.attributes.id) + //Page 1 + axios({ + url: config.Pterodactyl.hosturl + "/api/application/users", + method: 'GET', + followRedirect: true, + maxRedirects: 5, + headers: { + 'Authorization': 'Bearer ' + config.Pterodactyl.apikey, + 'Content-Type': 'application/json', + 'Accept': 'Application/vnd.pterodactyl.v1+json', + } + }).then(response1 => { + //console.log(consoleUserPage1) + + //Page 2 + axios({ + url: config.Pterodactyl.hosturl + "/api/application/users?page=2", + method: 'GET', + followRedirect: true, + maxRedirects: 5, + headers: { + 'Authorization': 'Bearer ' + config.Pterodactyl.apikey, + 'Content-Type': 'application/json', + 'Accept': 'Application/vnd.pterodactyl.v1+json', + } + }).then(response2 => { + //console.log(consoleUserPage2) + + //Page 3 + axios({ + url: config.Pterodactyl.hosturl + "/api/application/users?page=3", + method: 'GET', + followRedirect: true, + maxRedirects: 5, + headers: { + 'Authorization': 'Bearer ' + config.Pterodactyl.apikey, + 'Content-Type': 'application/json', + 'Accept': 'Application/vnd.pterodactyl.v1+json', + } + }).then(response3 => { + //console.log(consoleUserPage3) + + //Page 4 + axios({ + url: config.Pterodactyl.hosturl + "/api/application/users?page=4", + method: 'GET', + followRedirect: true, + maxRedirects: 5, + headers: { + 'Authorization': 'Bearer ' + config.Pterodactyl.apikey, + 'Content-Type': 'application/json', + 'Accept': 'Application/vnd.pterodactyl.v1+json', + } + }).then(response4 => { + //console.log(consoleUserPage4) + + //Page 5 + axios({ + url: config.Pterodactyl.hosturl + "/api/application/users?page=5", + method: 'GET', + followRedirect: true, + maxRedirects: 5, + headers: { + 'Authorization': 'Bearer ' + config.Pterodactyl.apikey, + 'Content-Type': 'application/json', + 'Accept': 'Application/vnd.pterodactyl.v1+json', + } + }).then(response5 => { + //console.log(consoleUserPage5) + + //Page 6 + axios({ + url: config.Pterodactyl.hosturl + "/api/application/users?page=6", + method: 'GET', + followRedirect: true, + maxRedirects: 5, + headers: { + 'Authorization': 'Bearer ' + config.Pterodactyl.apikey, + 'Content-Type': 'application/json', + 'Accept': 'Application/vnd.pterodactyl.v1+json', + } + }).then(response6 => { + //console.log(consoleUserPage6) + + //Page 7 + axios({ + url: config.Pterodactyl.hosturl + "/api/application/users?page=7", + method: 'GET', + followRedirect: true, + maxRedirects: 5, + headers: { + 'Authorization': 'Bearer ' + config.Pterodactyl.apikey, + 'Content-Type': 'application/json', + 'Accept': 'Application/vnd.pterodactyl.v1+json', + } + }).then(response7 => { + //console.log(consoleUserPage7) + + //Page 8 + axios({ + url: config.Pterodactyl.hosturl + "/api/application/users?page=8", + method: 'GET', + followRedirect: true, + maxRedirects: 5, + headers: { + 'Authorization': 'Bearer ' + config.Pterodactyl.apikey, + 'Content-Type': 'application/json', + 'Accept': 'Application/vnd.pterodactyl.v1+json', + } + }).then(response8 => { + //console.log(consoleUserPage8) + + //Page 9 + axios({ + url: config.Pterodactyl.hosturl + "/api/application/users?page=9", + method: 'GET', + followRedirect: true, + maxRedirects: 5, + headers: { + 'Authorization': 'Bearer ' + config.Pterodactyl.apikey, + 'Content-Type': 'application/json', + 'Accept': 'Application/vnd.pterodactyl.v1+json', + } + }).then(response9 => { + //console.log(consoleUserPage9) + + //Page 10 + axios({ + url: config.Pterodactyl.hosturl + "/api/application/users?page=10", + method: 'GET', + followRedirect: true, + maxRedirects: 5, + headers: { + 'Authorization': 'Bearer ' + config.Pterodactyl.apikey, + 'Content-Type': 'application/json', + 'Accept': 'Application/vnd.pterodactyl.v1+json', + } + }).then(response10 => { + //console.log(consoleUserPage10) + + //Page 11 + axios({ + url: config.Pterodactyl.hosturl + "/api/application/users?page=11", + method: 'GET', + followRedirect: true, + maxRedirects: 5, + headers: { + 'Authorization': 'Bearer ' + config.Pterodactyl.apikey, + 'Content-Type': 'application/json', + 'Accept': 'Application/vnd.pterodactyl.v1+json', + } + }).then(response11 => { + //console.log(consoleUserPage11) + const bigArr = [...response1.data.data, ...response2.data.data, ...response3.data.data, ...response4.data.data, ...response5.data.data, ...response6.data.data, ...response7.data.data, ...response8.data.data, ...response9.data.data, ...response10.data.data, ...response11.data.data] + const consoleUser = bigArr.find(usr => usr.attributes ? usr.attributes.email == message.content : false); + + if (!consoleUser) { + channel.send('I can\'t find a user with that account!') + } else { + //consoleUser1 = consoleUser[0]; + const timestamp = `${moment().format("HH:mm:ss")}`; + const datestamp = `${moment().format("YYYY-MM-DD")}`; + userData.set(`${message.author.id}`, { + discordID: message.author.id, + consoleID: consoleUser.attributes.id, + email: consoleUser.attributes.email, + username: consoleUser.attributes.username, + linkTime: timestamp, + linkDate: datestamp + }); + + let embedstaff = new Discord.RichEmbed() + .setColor('Green') + .addField('__**Linked Discord account:**__', message.author.id) + .addField('__**Linked Console account email:**__', consoleUser.attributes.email) + .addField('__**Linked At: (TIME / DATE)**__', timestamp + " / " + datestamp) + .addField('__**Linked Console username:**__', consoleUser.attributes.username) + .addField('__**Linked Console ID:**__', consoleUser.attributes.id) channel.send("Account linked! You can now create server's and use other features on this bot!").then( - client.channels.get(config.DiscordBot.mLogs).send(`<@${message.author.id}> linked their account. Heres some info: `, embedstaff), + client.channels.get(config.DiscordBot.oLogs).send(`<@${message.author.id}> linked their account. Heres some info: `, embedstaff), setTimeout(() => { channel.delete(); }, 5000) - ) - - - } + ); + + }; + })})})})})})})})})})}) +}); } else { let embed = new Discord.RichEmbed() .setColor(`GREEN`) .addField(`__**Username**__`, userData.fetch(message.author.id + ".username")) - .addField(`__**Date (DD/MM/YY)**__`, userData.fetch(message.author.id + ".linkDate")) - .addField(`__**Time**__`, userData.fetch(message.author.id + ".linkTime")) - message.channel.send("You'r account is already linked. ", embed) + .addField(`__**Linked Date (DD/MM/YY)**__`, userData.fetch(message.author.id + ".linkDate")) + .addField(`__**Linked Time**__`, userData.fetch(message.author.id + ".linkTime")) + message.channel.send("This account is linked!", embed) } + } \ No newline at end of file diff --git a/Panel/bot/discord/commands/monitor.js b/Panel/bot/discord/commands/monitor.js index 82b8e55ec..2cd7ef3f2 100644 --- a/Panel/bot/discord/commands/monitor.js +++ b/Panel/bot/discord/commands/monitor.js @@ -1,47 +1,47 @@ -exports.run = (client, message, args) => { - if (message.author.id !== config.DiscordBot.ownerID) return message.channel.send("Sorry, No permission :O"); - try { - - //Alerts me that the Node Monitor is now running. (Please Please Please. If you run this bot only run this once or you might get spam and banned from discord) - message.channel.send('Monitor is now running and watching all nodes for `DanBot Hosting`. Any issues will be updated and sent in <#640158471001735169>') - - //Node Monitor - setInterval(() => { - //Data for node 1 - var N1 = fs.readFileSync('./data/0286b2ad-dc80-4b5c-a0de-b81945b010e8.json', 'utf8'); - var Node1 = JSON.parse(N1); - - //Data for node 2 - var N2 = fs.readFileSync('./data/2e3f071a-af2b-4dc9-be5a-7ce72590a181.json', 'utf8'); - var Node2 = JSON.parse(N2); - - //Data for node 3 - var N3 = fs.readFileSync('./data/6fc3e9bf-24a8-47cd-99d3-fa159e05a9f4.json', 'utf8'); - var Node3 = JSON.parse(N3); - - //Data for node 4 - var N4 = fs.readFileSync('./data/15ffcdd0-a021-4ded-977d-284d777330a0.json', 'utf8'); - var Node4 = JSON.parse(N4); - - //Runs if statements for each node. this checks each node's ram - if (Node1.memused >= "7.5 GB") { - return client.channels.get("640158471001735169").send("⚠️ `Node 1` is currently running with " + Node1.memused + " out of " + Node1.memtotal + ". Will continue to monitor this node!"), client.channels.get("640158471001735169").setTopic('⚠️Monitoring: Node 1 running with ' + Node1.memused + " out of " + Node1.memtotal) - }; - - client.guilds.get("639477525927690240").channels.get("640158471001735169").fetchMessage("693937194863427655") - .then(msgb => { - console.log(msgb.content) - msgb.edit("testing") - }) - // Node1msg.edit('testing') - - //if (Node1.memused >= "7.5 GB") return client.channels.get("640158471001735169").send("⚠️ `Node 1` is currently running with " + Node1.memused + " out of " + Node1.memtotal + ". Will continue to monitor this node!"), client.channels.get("640158471001735169").setTopic('⚠️Monitoring: Node 1 running with ' + Node1.memused + " out of " + Node1.memtotal) - //if (Node2.memused >= "7.5 GB") return client.channels.get("640158471001735169").send("⚠️ `Node 2` is currently running with " + Node2.memused + " out of " + Node2.memtotal + ". Will continue to monitor this node!"), client.channels.get("640158471001735169").setTopic('⚠️Monitoring: Node 2 running with ' + Node2.memused + " out of " + Node2.memtotal) - //if (Node3.memused >= "7.5 GB") return client.channels.get("640158471001735169").send("⚠️ `Node 3` is currently running with " + Node3.memused + " out of " + Node3.memtotal + ". Will continue to monitor this node!"), client.channels.get("640158471001735169").setTopic('⚠️Monitoring: Node 3 running with ' + Node3.memused + " out of " + Node3.memtotal) - //if (Node4.memused >= "7.5 GB") return client.channels.get("640158471001735169").send("⚠️ `Node 4` is currently running with " + Node4.memused + " out of " + Node4.memtotal + ". Will continue to monitor this node!"), client.channels.get("640158471001735169").setTopic('⚠️Monitoring: Node 4 running with ' + Node4.memused + " out of " + Node4.memtotal) - }, 5000); - -} catch (err) { - return console.log(err) - } +exports.run = (client, message, args) => { + if (message.author.id !== config.DiscordBot.ownerID) return message.channel.send("Sorry, No permission :O"); + try { + + //Alerts me that the Node Monitor is now running. (Please Please Please. If you run this bot only run this once or you might get spam and banned from discord) + message.channel.send('Monitor is now running and watching all nodes for `DanBot Hosting`. Any issues will be updated and sent in <#640158471001735169>') + + //Node Monitor + setInterval(() => { + //Data for node 1 + var N1 = fs.readFileSync('./data/0286b2ad-dc80-4b5c-a0de-b81945b010e8.json', 'utf8'); + var Node1 = JSON.parse(N1); + + //Data for node 2 + var N2 = fs.readFileSync('./data/2e3f071a-af2b-4dc9-be5a-7ce72590a181.json', 'utf8'); + var Node2 = JSON.parse(N2); + + //Data for node 3 + var N3 = fs.readFileSync('./data/6fc3e9bf-24a8-47cd-99d3-fa159e05a9f4.json', 'utf8'); + var Node3 = JSON.parse(N3); + + //Data for node 4 + var N4 = fs.readFileSync('./data/15ffcdd0-a021-4ded-977d-284d777330a0.json', 'utf8'); + var Node4 = JSON.parse(N4); + + //Runs if statements for each node. this checks each node's ram + if (Node1.memused >= "7.5 GB") { + return client.channels.get("640158471001735169").send("⚠️ `Node 1` is currently running with " + Node1.memused + " out of " + Node1.memtotal + ". Will continue to monitor this node!"), client.channels.get("640158471001735169").setTopic('⚠️Monitoring: Node 1 running with ' + Node1.memused + " out of " + Node1.memtotal) + }; + + client.guilds.get("639477525927690240").channels.get("640158471001735169").fetchMessage("693937194863427655") + .then(msgb => { + console.log(msgb.content) + msgb.edit("testing") + }) + // Node1msg.edit('testing') + + //if (Node1.memused >= "7.5 GB") return client.channels.get("640158471001735169").send("⚠️ `Node 1` is currently running with " + Node1.memused + " out of " + Node1.memtotal + ". Will continue to monitor this node!"), client.channels.get("640158471001735169").setTopic('⚠️Monitoring: Node 1 running with ' + Node1.memused + " out of " + Node1.memtotal) + //if (Node2.memused >= "7.5 GB") return client.channels.get("640158471001735169").send("⚠️ `Node 2` is currently running with " + Node2.memused + " out of " + Node2.memtotal + ". Will continue to monitor this node!"), client.channels.get("640158471001735169").setTopic('⚠️Monitoring: Node 2 running with ' + Node2.memused + " out of " + Node2.memtotal) + //if (Node3.memused >= "7.5 GB") return client.channels.get("640158471001735169").send("⚠️ `Node 3` is currently running with " + Node3.memused + " out of " + Node3.memtotal + ". Will continue to monitor this node!"), client.channels.get("640158471001735169").setTopic('⚠️Monitoring: Node 3 running with ' + Node3.memused + " out of " + Node3.memtotal) + //if (Node4.memused >= "7.5 GB") return client.channels.get("640158471001735169").send("⚠️ `Node 4` is currently running with " + Node4.memused + " out of " + Node4.memtotal + ". Will continue to monitor this node!"), client.channels.get("640158471001735169").setTopic('⚠️Monitoring: Node 4 running with ' + Node4.memused + " out of " + Node4.memtotal) + }, 5000); + +} catch (err) { + return console.log(err) + } }; \ No newline at end of file diff --git a/Panel/bot/discord/commands/mute.js b/Panel/bot/discord/commands/mute.js index 25a419559..5d492ce65 100644 --- a/Panel/bot/discord/commands/mute.js +++ b/Panel/bot/discord/commands/mute.js @@ -1,59 +1,59 @@ -exports.run = async (client, message, args) => { - - //Usage embed - const usage = new Discord.RichEmbed() - .setColor(0x00A2E8) - .setThumbnail(client.user.avatarURL) - .setTitle("Command: " + config.DiscordBot.Prefix + "mute") - .addField("Usage", config.DiscordBot.Prefix + "mute @Someone ") - .addField("Example", config.DiscordBot.Prefix + "mute @Someone 5 spamming in general.") - .setDescription("Description: " + "Gives a user the muted role for x minutes"); - - if(message.member.roles.find(r => r.id === "713154800178561134")) { - if (!message.guild.member(client.user).hasPermission('MANAGE_ROLES')) return message.reply('Sorry, i dont have the perms to do this cmd i need MANAGE_ROLES. :x:') - - //If no user pinged - if (message.mentions.users.size < 1) return message.channel.send(usage) - - let user = message.guild.member(message.mentions.users.first()); - let messagez = parseInt(args[1]) - if (isNaN(messagez)) return message.channel.send("That is not a valid time") - if (messagez > 1440) return message.channel.send('Maximum time is 1 day (1440 minutes)'); - if (messagez < 1) return message.channel.send('Time must be at least 1 minute.'); - let reason = args.slice(2).join(' ') || `No reason.`; - let modlog = message.guild.channels.find(channel => channel.id == config.DiscordBot.mLogs); - if (reason.length < 1) return; - let muteRole = client.guilds.get(message.guild.id).roles.find(r => r.id == "726829710935457872"); - - //Muted embed - const embed = new Discord.RichEmbed() - .setColor(0x00A2E8) - .setTitle("Action: Mute") - .addField("Moderator", message.author.tag + " (ID: " + message.author.id + ")") - .addField("User", user.user.tag + " (ID: " + user.user.id + ")") - .addField("Time", messagez, true) - .addField("Reason", reason, true) - .setFooter("Time used: " + message.createdAt.toDateString()) - - message.guild.member(user).addRole(muteRole).then(() => { - message.channel.send("***The user has been successfully muted for " + messagez + " minute(s) :white_check_mark:***") - - if (!modlog) { - setTimeout(() => { - message.guild.member(user).removeRole(muteRole) - console.log(chalk.magenta('[DISCORD] ') + chalk.cyan(user.user.username + ' has now been unmuted after ' + messagez +' minute(s)')) - }, messagez * 60000); - } else { - client.channels.get(modlog.id).send({embed}) - setTimeout(() => { - message.guild.member(user).removeRole(muteRole) - console.log(chalk.magenta('[DISCORD] ') + chalk.cyan(user.user.username + ' has now been unmuted after ' + messagez +' minute(s)')) - }, messagez * 60000); - } - }) - - - } else { - message.channel.send('Missing perms to do that :(') - }; +exports.run = async (client, message, args) => { + + //Usage embed + const usage = new Discord.RichEmbed() + .setColor(0x00A2E8) + .setThumbnail(client.user.avatarURL) + .setTitle("Command: " + config.DiscordBot.Prefix + "mute") + .addField("Usage", config.DiscordBot.Prefix + "mute @Someone ") + .addField("Example", config.DiscordBot.Prefix + "mute @Someone 5 spamming in general.") + .setDescription("Description: " + "Gives a user the muted role for x minutes"); + + if(message.member.roles.find(r => r.id === "748117822370086932")) { + if (!message.guild.member(client.user).hasPermission('MANAGE_ROLES')) return message.reply('Sorry, i dont have the perms to do this cmd i need MANAGE_ROLES. :x:') + + //If no user pinged + if (message.mentions.users.size < 1) return message.channel.send(usage) + + let user = message.guild.member(message.mentions.users.first()); + let messagez = parseInt(args[1]) + if (isNaN(messagez)) return message.channel.send("That is not a valid time") + if (messagez > 1440) return message.channel.send('Maximum time is 1 day (1440 minutes)'); + if (messagez < 1) return message.channel.send('Time must be at least 1 minute.'); + let reason = args.slice(2).join(' ') || `No reason.`; + let modlog = message.guild.channels.find(channel => channel.id == config.DiscordBot.mLogs); + if (reason.length < 1) return; + let muteRole = client.guilds.get(message.guild.id).roles.find(r => r.id == "726829710935457872"); + + //Muted embed + const embed = new Discord.RichEmbed() + .setColor(0x00A2E8) + .setTitle("Action: Mute") + .addField("Moderator", message.author.tag + " (ID: " + message.author.id + ")") + .addField("User", user.user.tag + " (ID: " + user.user.id + ")") + .addField("Time", messagez, true) + .addField("Reason", reason, true) + .setFooter("Time used: " + message.createdAt.toDateString()) + + message.guild.member(user).addRole(muteRole).then(() => { + message.channel.send("***The user has been successfully muted for " + messagez + " minute(s) :white_check_mark:***") + + if (!modlog) { + setTimeout(() => { + message.guild.member(user).removeRole(muteRole) + console.log(chalk.magenta('[DISCORD] ') + chalk.cyan(user.user.username + ' has now been unmuted after ' + messagez +' minute(s)')) + }, messagez * 60000); + } else { + client.channels.get(modlog.id).send({embed}) + setTimeout(() => { + message.guild.member(user).removeRole(muteRole) + console.log(chalk.magenta('[DISCORD] ') + chalk.cyan(user.user.username + ' has now been unmuted after ' + messagez +' minute(s)')) + }, messagez * 60000); + } + }) + + + } else { + message.channel.send('Missing perms to do that :(') + }; }; \ No newline at end of file diff --git a/Panel/bot/discord/commands/own.js b/Panel/bot/discord/commands/own.js index 593b14118..3588555d4 100644 --- a/Panel/bot/discord/commands/own.js +++ b/Panel/bot/discord/commands/own.js @@ -1,14 +1,14 @@ -exports.run = async (client, message) => { - if (userData.get(message.author.id) == null) { - message.channel.send("You can't use this command as your account is not linked. You can link it with: `" + config.DiscordBot.Prefix + "link`") - } else { - let consoleUser = await DanBotHosting.getAllServers(); - consoleUser = consoleUser.filter(x => x.attributes.user == userData.fetch(message.author.id + ".consoleID")) - - let embed = new Discord.RichEmbed() - .setColor(`GREEN`) - .addField(`__**Server's you own:**__`, userData.fetch(message.author.id + ".username")) - //message.channel.send('Your account is linked. Heres some data: ', embed) - console.log(consoleUser) - } +exports.run = async (client, message) => { + if (userData.get(message.author.id) == null) { + message.channel.send("You can't use this command as your account is not linked. You can link it with: `" + config.DiscordBot.Prefix + "link`") + } else { + let consoleUser = await DanBotHosting.getAllServers(); + consoleUser = consoleUser.filter(x => x.attributes.user == userData.fetch(message.author.id + ".consoleID")) + + let embed = new Discord.RichEmbed() + .setColor(`GREEN`) + .addField(`__**Server's you own:**__`, userData.fetch(message.author.id + ".username")) + //message.channel.send('Your account is linked. Heres some data: ', embed) + console.log(consoleUser) + } }; \ No newline at end of file diff --git a/Panel/bot/discord/commands/play.js b/Panel/bot/discord/commands/play.js index 9939510db..31a6980f1 100644 --- a/Panel/bot/discord/commands/play.js +++ b/Panel/bot/discord/commands/play.js @@ -1,45 +1,45 @@ -const utils = require('../music/utils'); - - -exports.run = async (client, message, args) => { - - let VC = message.member.voiceChannel; - if (!VC) return [message.delete(), utils.timed_msg(utils.cmd_fail(`${message.author}, please join a voice channel!`, `${config.DiscordBot.prefix}play `), 5000)]; - - let url = args[0] ? args[0].replace(/<(.+)>/g, '$1') : ''; - let pl = /^https?:\/\/(www.youtube.com|youtube.com)\/playlist(.*)$/ - - let searchString = args.join(' '); - if (!url || !searchString) return [message.delete(), utils.timed_msg(utils.cmd_fail(`${message.author}, please enter a music name or url!`, `${config.DiscordBot.prefix}play `), 5000)]; - - let perms = VC.permissionsFor(message.client.user); - if (!perms.has('CONNECT')) return [message.delete(), utils.timed_msg(utils.cmd_fail(`${message.author}, I do not have permissions to connect to voice channels!`, `${config.DiscordBot.prefix}play `), 5000)]; - if (!perms.has('SPEAK')) return [message.delete(), utils.timed_msg(utils.cmd_fail(`${message.author}, I do not have permissions to speak in a voice channel`, `${config.DiscordBot.prefix}play `), 5000)]; - - if (url.match(pl)) { - let playlist = await client.youtube.getPlaylist(url); - let videos = await playlist.getVideos(); - - for (const vid of Object.values(videos)) { - let video = await client.youtube.getVideoByID(vid.id) - await client.handleVideo(video, message, VC, true) - } - - return message.channel.send(`**${playlist.title}** has been added to queue.`); - } else { - - try { - var video = await client.youtube.getVideo(url); - } catch (err) { - if (err) undefined; - try { - var vid = await client.youtube.searchVideos(searchString, 1); - var video = await client.youtube.getVideoByID(vid[0].id); - } catch (err) { - console.error(err); - return [message.delete(), utils.timed_msg(utils.cmd_fail(`${message.author}, no videos can be found with the argument \`${searchString}\``, `${config.DiscordBot.prefix}play `), 5000)]; - } - } - return client.handleVideo(video, message, VC); - } +const utils = require('../music/utils'); + + +exports.run = async (client, message, args) => { + + let VC = message.member.voiceChannel; + if (!VC) return [message.delete(), utils.timed_msg(utils.cmd_fail(`${message.author}, please join a voice channel!`, `${config.DiscordBot.prefix}play `), 5000)]; + + let url = args[0] ? args[0].replace(/<(.+)>/g, '$1') : ''; + let pl = /^https?:\/\/(www.youtube.com|youtube.com)\/playlist(.*)$/ + + let searchString = args.join(' '); + if (!url || !searchString) return [message.delete(), utils.timed_msg(utils.cmd_fail(`${message.author}, please enter a music name or url!`, `${config.DiscordBot.prefix}play `), 5000)]; + + let perms = VC.permissionsFor(message.client.user); + if (!perms.has('CONNECT')) return [message.delete(), utils.timed_msg(utils.cmd_fail(`${message.author}, I do not have permissions to connect to voice channels!`, `${config.DiscordBot.prefix}play `), 5000)]; + if (!perms.has('SPEAK')) return [message.delete(), utils.timed_msg(utils.cmd_fail(`${message.author}, I do not have permissions to speak in a voice channel`, `${config.DiscordBot.prefix}play `), 5000)]; + + if (url.match(pl)) { + let playlist = await client.youtube.getPlaylist(url); + let videos = await playlist.getVideos(); + + for (const vid of Object.values(videos)) { + let video = await client.youtube.getVideoByID(vid.id) + await client.handleVideo(video, message, VC, true) + } + + return message.channel.send(`**${playlist.title}** has been added to queue.`); + } else { + + try { + var video = await client.youtube.getVideo(url); + } catch (err) { + if (err) undefined; + try { + var vid = await client.youtube.searchVideos(searchString, 1); + var video = await client.youtube.getVideoByID(vid[0].id); + } catch (err) { + console.error(err); + return [message.delete(), utils.timed_msg(utils.cmd_fail(`${message.author}, no videos can be found with the argument \`${searchString}\``, `${config.DiscordBot.prefix}play `), 5000)]; + } + } + return client.handleVideo(video, message, VC); + } }; \ No newline at end of file diff --git a/Panel/bot/discord/commands/proxmox.js b/Panel/bot/discord/commands/proxmox.js new file mode 100644 index 000000000..ec1eee05b --- /dev/null +++ b/Panel/bot/discord/commands/proxmox.js @@ -0,0 +1,2 @@ +exports.run = async (client, message) => { +}; \ No newline at end of file diff --git a/Panel/bot/discord/commands/purge.js b/Panel/bot/discord/commands/purge.js index f8242805a..9bb471315 100644 --- a/Panel/bot/discord/commands/purge.js +++ b/Panel/bot/discord/commands/purge.js @@ -1,36 +1,37 @@ -const Discord = require("discord.js"); -exports.run = (client, message, args) => { -const prefixtouse = config.prefix -const usage = new Discord.RichEmbed() - .setColor(0x00A2E8) - .setTitle("Command: " + prefixtouse + "purge") - .addField("Usage", prefixtouse + "purge @Someone") - .addField("Example", prefixtouse + "purge 20 spam") - .setDescription("Description: " + "Purges the channels messages (min 2 max 100)"); - -const user = message.mentions.users.first() -const amount = !!parseInt(message.content.split(' ')[2]) ? parseInt(message.content.split(' ')[2]) : parseInt(message.content.split(' ')[1]) -let reason = args[3] || `Moderator didn't give a reason.`; -if (!amount) return message.channel.send(usage); -if (!amount && !user) return message.channel.send(usage); -message.channel.fetchMessages({ - limit: amount, -}).then((messages) => { - if (user) { - const filterBy = user ? user.id : client.user.id; - messages = messages.filter(m => m.author.id === filterBy).array().slice(0, amount + 1); - } - if (amount <= 1) return message.channel.send("Can only delete a min of 2 messages") - if (amount >= 101) return message.channel.send("Can only delete a max of 100 messages") - message.channel.bulkDelete(messages, true).catch(error => console.log(error.stack)); - message.channel.send("***The server messages/users messages has been successfully purged! :white_check_mark:***") - const embed = new Discord.RichEmbed() - .setColor(0x00A2E8) - .addField("Moderator", message.author.tag, true) - .addField("Purge Amount", amount) - .addField("In channel", message.channel.name, true) - .addField("Reason", reason, true) - .setFooter("Time used: " + message.createdAt.toDateString()) - return client.channels.get(config.DiscordBot.mLogs).send({embed}); - }) +const Discord = require("discord.js"); +exports.run = (client, message, args) => { +const prefixtouse = config.prefix +const usage = new Discord.RichEmbed() + .setColor(0x00A2E8) + .setTitle("Command: " + prefixtouse + "purge") + .addField("Usage", prefixtouse + "purge @Someone") + .addField("Example", prefixtouse + "purge 20 spam") + .setDescription("Description: " + "Purges the channels messages (min 2 max 100)"); +if(message.member.roles.find(r => r.id === "748117822370086932")) { +const user = message.mentions.users.first() +const amount = !!parseInt(message.content.split(' ')[2]) ? parseInt(message.content.split(' ')[2]) : parseInt(message.content.split(' ')[1]) +let reason = args[3] || `Moderator didn't give a reason.`; +if (!amount) return message.channel.send(usage); +if (!amount && !user) return message.channel.send(usage); +message.channel.fetchMessages({ + limit: amount, +}).then((messages) => { + if (user) { + const filterBy = user ? user.id : client.user.id; + messages = messages.filter(m => m.author.id === filterBy).array().slice(0, amount + 1); + } + if (amount <= 1) return message.channel.send("Can only delete a min of 2 messages") + if (amount >= 100) return message.channel.send("Can only delete a max of 100 messages") + message.channel.bulkDelete(messages, true).catch(error => console.log(error.stack)); + message.channel.send("***The server messages/users messages has been successfully purged! :white_check_mark:***") + const embed = new Discord.RichEmbed() + .setColor(0x00A2E8) + .addField("Moderator", message.author.tag, true) + .addField("Purge Amount", amount) + .addField("In channel", message.channel.name, true) + .addField("Reason", reason, true) + .setFooter("Time used: " + message.createdAt.toDateString()) + return client.channels.get(config.DiscordBot.mLogs).send({embed}); + }) +} } \ No newline at end of file diff --git a/Panel/bot/discord/commands/radio.js b/Panel/bot/discord/commands/radio.js index ac18450c7..39add931c 100644 --- a/Panel/bot/discord/commands/radio.js +++ b/Panel/bot/discord/commands/radio.js @@ -1,8 +1,8 @@ -exports.run = (client, message) => { - message.channel.send('Playing...') - client.channels.get("691609366155100201").join() - .then(connection => { - connection.playStream('http://207.180.236.5:8000/DanBotFM') - }); - +exports.run = (client, message) => { + message.channel.send('Playing...') + client.channels.get("691609366155100201").join() + .then(connection => { + connection.playStream('http://207.180.236.5:8000/DanBotFM') + }); + }; \ No newline at end of file diff --git a/Panel/bot/discord/commands/reload.js b/Panel/bot/discord/commands/reload.js index fc2ad7e7e..04eda73e9 100644 --- a/Panel/bot/discord/commands/reload.js +++ b/Panel/bot/discord/commands/reload.js @@ -1,14 +1,14 @@ -exports.run = (client, message, args) => { - if (message.author.id !== config.DiscordBot.ownerID) return message.channel.send("Sorry, No permission :O"); - try { - fs.readdir("./bot/discord/commands/", (err, files) => { - if (err) return console.error(err); - message.channel.send(`Refreshed \`${files.length}\` commands successfully!`) - files.forEach(file => { - delete require.cache[require.resolve(`./${file}`)]; - }); - }); -} catch (err) { - return; - } +exports.run = (client, message, args) => { + if (message.author.id !== config.DiscordBot.ownerID) return message.channel.send("Sorry, No permission :O"); + try { + fs.readdir("./bot/discord/commands/", (err, files) => { + if (err) return console.error(err); + message.channel.send(`Refreshed \`${files.length}\` commands successfully!`) + files.forEach(file => { + delete require.cache[require.resolve(`./${file}`)]; + }); + }); +} catch (err) { + return; + } }; \ No newline at end of file diff --git a/Panel/bot/discord/commands/say.js b/Panel/bot/discord/commands/say.js index 163937650..5d4a82c22 100644 --- a/Panel/bot/discord/commands/say.js +++ b/Panel/bot/discord/commands/say.js @@ -1,7 +1,7 @@ exports.run = async (client, message) => { const args = message.content.split(' ').slice(1).join(' '); - if (message.author.id !== config.DiscordBot.ownerID) { + if (message.author.id == config.DiscordBot.ownerID) { message.delete() message.channel.send(args) } else { diff --git a/Panel/bot/discord/commands/server.js b/Panel/bot/discord/commands/server.js new file mode 100644 index 000000000..16109ab40 --- /dev/null +++ b/Panel/bot/discord/commands/server.js @@ -0,0 +1,415 @@ +const axios = require('axios'); +exports.run = async (client, message, args) => { + const otherargs = message.content.split(' ').slice(3).join(' '); + if (userData.get(message.author.id) == null) { + message.channel.send("This account is not linked. Please link it using `" + config.DiscordBot.Prefix + "link`, then retry this command") + } else { + if (!args[0]) { + //No args + let embed = new Discord.RichEmbed() + .setTitle('__**Commands**__ \n' + config.DiscordBot.Prefix + 'server create type servername \n' + config.DiscordBot.Prefix + 'server list') + + } else if (args[0].toLowerCase() == "create") { + //Do server creation things + if (args[1].toLowerCase() === "nodejs") { + //Code for nodejs server + if (!otherargs) { + message.channel.send('You must provide a server name!') + } else { + //Data to send + const data = { + "name": otherargs, + "user": userData.get(message.author.id + ".consoleID"), + "nest": 5, + "egg": 16, + "docker_image": "quay.io/parkervcp/pterodactyl-images:debian_nodejs-12", + "startup": `if [[ -d .git ]] && [[ {{AUTO_UPDATE}} == "1" ]]; then git pull; fi && /usr/local/bin/npm install --production && /usr/local/bin/node /home/container/{{BOT_JS_FILE}}`, + "limits": { + "memory": 0, + "swap": 0, + "disk": 0, + "io": 500, + "cpu": 0 + }, + "environment": { + "INSTALL_REPO": null, + "INSTALL_BRANCH": null, + "USER_UPLOAD": "0", + "AUTO_UPDATE": "0", + "BOT_JS_FILE": "index.js" + }, + "feature_limits": { + "databases": 0, + "allocations": 1 + }, + "deploy": { + "locations": [3], + "dedicated_ip": false, + "port_range": [] + }, + "start_on_completion": false + }; + + //Sending the data: + axios({ + url: config.Pterodactyl.hosturl + "/api/application/servers", + method: 'POST', + followRedirect: true, + maxRedirects: 5, + headers: { + 'Authorization': 'Bearer ' + config.Pterodactyl.apikey, + 'Content-Type': 'application/json', + 'Accept': 'Application/vnd.pterodactyl.v1+json', + }, + data: data, + }).then(response => { + let embed = new Discord.RichEmbed() + .setColor(`GREEN`) + .addField(`__**Status:**__`, response.statusText) + .addField(`__**Created for user ID:**__`, data.user) + .addField(`__**Server name:**__`, data.name) + .addField(`__**Type:**__`, args[1].toLowerCase()) + message.channel.send(embed) + console.log(response) + }).catch(error => { + let embed1 = new Discord.RichEmbed() + .setColor(`RED`) + .addField(`__**FAILED:**__`, "Please contact a host admin. \n\nError: `" + error + "`") + message.channel.send(embed1) + message.channel.send("<@137624084572798976> Issue when creating server. \nResponse: `" + error + "`") + }) + } + } else if (args[1].toLowerCase() === "python") { + if (!otherargs) { + message.channel.send('You must provide a server name!') + } else { + //Data to send + const data = { + "name": otherargs, + "user": userData.get(message.author.id + ".consoleID"), + "nest": 5, + "egg": 22, + "docker_image": "quay.io/parkervcp/pterodactyl-images:debian_python-3.8", + "startup": "${STARTUP_CMD}", + "limits": { + "memory": 0, + "swap": 0, + "disk": 0, + "io": 500, + "cpu": 0 + }, + "environment": { + "STARTUP_CMD": "bash" + }, + "feature_limits": { + "databases": 0, + "allocations": 1 + }, + "deploy": { + "locations": [3], + "dedicated_ip": false, + "port_range": [] + }, + "start_on_completion": false + }; + + //Sending the data: + axios({ + url: config.Pterodactyl.hosturl + "/api/application/servers", + method: 'POST', + followRedirect: true, + maxRedirects: 5, + headers: { + 'Authorization': 'Bearer ' + config.Pterodactyl.apikey, + 'Content-Type': 'application/json', + 'Accept': 'Application/vnd.pterodactyl.v1+json', + }, + data: data, + }).then(response => { + let embed = new Discord.RichEmbed() + .setColor(`GREEN`) + .addField(`__**Status:**__`, response.statusText) + .addField(`__**Created for user ID:**__`, data.user) + .addField(`__**Server name:**__`, data.name) + .addField(`__**Type:**__`, args[1].toLowerCase()) + message.channel.send(embed) + }).catch(error => { + let embed1 = new Discord.RichEmbed() + .setColor(`RED`) + .addField(`__**FAILED:**__`, "Please contact a host admin. \n\nError: `" + error + "`") + message.channel.send(embed1) + message.channel.send("<@137624084572798976> Issue when creating server. \nResponse: `" + error + "`") + }) + } + } else if (args[1].toLowerCase() === "java") { + if (!otherargs) { + message.channel.send('You must provide a server name!') + } else { + //Data to send + const data = { + "name": otherargs, + "user": userData.get(message.author.id + ".consoleID"), + "nest": 5, + "egg": 25, + "docker_image": "quay.io/parkervcp/pterodactyl-images:debian_openjdk-8-jre", + "startup": "${STARTUP_CMD}", + "limits": { + "memory": 0, + "swap": 0, + "disk": 0, + "io": 500, + "cpu": 0 + }, + "environment": { + "STARTUP_CMD": "bash" + }, + "feature_limits": { + "databases": 0, + "allocations": 1 + }, + "deploy": { + "locations": [3], + "dedicated_ip": false, + "port_range": [] + }, + "start_on_completion": false + }; + + //Sending the data: + axios({ + url: config.Pterodactyl.hosturl + "/api/application/servers", + method: 'POST', + followRedirect: true, + maxRedirects: 5, + headers: { + 'Authorization': 'Bearer ' + config.Pterodactyl.apikey, + 'Content-Type': 'application/json', + 'Accept': 'Application/vnd.pterodactyl.v1+json', + }, + data: data, + }).then(response => { + let embed = new Discord.RichEmbed() + .setColor(`GREEN`) + .addField(`__**Status:**__`, response.statusText) + .addField(`__**Created for user ID:**__`, data.user) + .addField(`__**Server name:**__`, data.name) + .addField(`__**Type:**__`, args[1].toLowerCase()) + message.channel.send(embed) + }).catch(error => { + let embed1 = new Discord.RichEmbed() + .setColor(`RED`) + .addField(`__**FAILED:**__`, "Please contact a host admin. \n\nError: `" + error + "`") + message.channel.send(embed1) + message.channel.send("<@137624084572798976> Issue when creating server. \nResponse: `" + error + "`") + }) + } + } else if (args[1].toLowerCase() === "minecraft.paper") { + if (!otherargs) { + message.channel.send('You must provide a server name!') + } else { + //Data to send + const data = { + "name": otherargs, + "user": userData.get(message.author.id + ".consoleID"), + "nest": 1, + "egg": 3, + "docker_image": "quay.io/pterodactyl/core:java", + "startup": "java -Xms128M -Xmx{{SERVER_MEMORY}}M -Dterminal.jline=false -Dterminal.ansi=true -jar {{SERVER_JARFILE}}", + "limits": { + "memory": 2048, + "swap": 0, + "disk": 0, + "io": 500, + "cpu": 0 + }, + "environment": { + "MINECRAFT_VERSION": "latest", + "SERVER_JARFILE": "server.jar", + "DL_PATH": "https://papermc.io/api/v1/paper/1.16.1/138/download", + "BUILD_NUMBER": "latest" + }, + "feature_limits": { + "databases": 0, + "allocations": 1 + }, + "deploy": { + "locations": [5], + "dedicated_ip": false, + "port_range": [] + }, + "start_on_completion": false + }; + + //Sending the data: + axios({ + url: config.Pterodactyl.hosturl + "/api/application/servers", + method: 'POST', + followRedirect: true, + maxRedirects: 5, + headers: { + 'Authorization': 'Bearer ' + config.Pterodactyl.apikey, + 'Content-Type': 'application/json', + 'Accept': 'Application/vnd.pterodactyl.v1+json', + }, + data: data, + }).then(response => { + let embed = new Discord.RichEmbed() + .setColor(`GREEN`) + .addField(`__**Status:**__`, response.statusText) + .addField(`__**Created for user ID:**__`, data.user) + .addField(`__**Server name:**__`, data.name) + .addField(`__**Type:**__`, args[1].toLowerCase()) + message.channel.send(embed) + }).catch(error => { + let embed1 = new Discord.RichEmbed() + .setColor(`RED`) + .addField(`__**FAILED:**__`, "Please contact a host admin. \n\nError: `" + error + "`") + message.channel.send(embed1) + message.channel.send("<@137624084572798976> Issue when creating server. \nResponse: `" + error + "`") + }) + } + } else if (args[1].toLowerCase() === "minecraft.forge") { + if (!otherargs) { + message.channel.send('You must provide a server name!') + } else { + //Data to send + const data = { + "name": otherargs, + "user": userData.get(message.author.id + ".consoleID"), + "nest": 1, + "egg": 2, + "docker_image": "quay.io/pterodactyl/core:java", + "startup": "java -Xms128M -Xmx{{SERVER_MEMORY}}M -jar {{SERVER_JARFILE}}", + "limits": { + "memory": 2048, + "swap": 0, + "disk": 0, + "io": 500, + "cpu": 0 + }, + "environment": { + "SERVER_JARFILE": "server.jar", + "MC_VERSION": "latest" + }, + "feature_limits": { + "databases": 0, + "allocations": 1 + }, + "deploy": { + "locations": [5], + "dedicated_ip": false, + "port_range": [] + }, + "start_on_completion": false + }; + + //Sending the data: + axios({ + url: config.Pterodactyl.hosturl + "/api/application/servers", + method: 'POST', + followRedirect: true, + maxRedirects: 5, + headers: { + 'Authorization': 'Bearer ' + config.Pterodactyl.apikey, + 'Content-Type': 'application/json', + 'Accept': 'Application/vnd.pterodactyl.v1+json', + }, + data: data, + }).then(response => { + let embed = new Discord.RichEmbed() + .setColor(`GREEN`) + .addField(`__**Status:**__`, response.statusText) + .addField(`__**Created for user ID:**__`, data.user) + .addField(`__**Server name:**__`, data.name) + .addField(`__**Type:**__`, args[1].toLowerCase()) + message.channel.send(embed) + }).catch(error => { + let embed1 = new Discord.RichEmbed() + .setColor(`RED`) + .addField(`__**FAILED:**__`, "Please contact a host admin. \n\nError: `" + error + "`") + message.channel.send(embed1) + message.channel.send("<@137624084572798976> Issue when creating server. \nResponse: `" + error + "`") + }) + } + } else if (args[1].toLowerCase() === "fivem") { + if (!otherargs) { + message.channel.send('You must provide a server name!') + } else { + //Data to send + const data = { + "name": otherargs, + "user": userData.get(message.author.id + ".consoleID"), + "nest": 9, + "egg": 26, + "docker_image": "quay.io/parkervcp/pterodactyl-images:base_alpine", + "startup": `$(pwd)/alpine/opt/cfx-server/ld-musl-x86_64.so.1 --library-path "$(pwd)/alpine/usr/lib/v8/:$(pwd)/alpine/lib/:$(pwd)/alpine/usr/lib/" -- $(pwd)/alpine/opt/cfx-server/FXServer +set citizen_dir $(pwd)/alpine/opt/cfx-server/citizen/ +set sv_licenseKey {{FIVEM_LICENSE}} +set steam_webApiKey {{STEAM_WEBAPIKEY}} +set sv_maxplayers {{MAX_PLAYERS}} +set serverProfile default +set txAdminPort {{TXADMIN_PORT}} $( [ "$TXADMIN_ENABLE" == "1" ] || printf %s '+exec server.cfg' )`, + "limits": { + "memory": 2048, + "swap": 0, + "disk": 0, + "io": 500, + "cpu": 0 + }, + "environment": { + "FIVEM_LICENSE": "6pc7xbhxoep0ms5m5rsg09k11plzib6w", + "MAX_PLAYERS": "32", + "SERVER_HOSTNAME": "My new FXServer!", + "FIVEM_VERSION": "latest", + "DOWNLOAD_URL": null, + "STEAM_WEBAPIKEY": "none", + "TXADMIN_PORT": "40120", + "TXADMIN_ENABLE": "0" + }, + "feature_limits": { + "databases": 2, + "allocations": 1 + }, + "deploy": { + "locations": [5], + "dedicated_ip": false, + "port_range": [] + }, + "start_on_completion": false + }; + + //Sending the data: + axios({ + url: config.Pterodactyl.hosturl + "/api/application/servers", + method: 'POST', + followRedirect: true, + maxRedirects: 5, + headers: { + 'Authorization': 'Bearer ' + config.Pterodactyl.apikey, + 'Content-Type': 'application/json', + 'Accept': 'Application/vnd.pterodactyl.v1+json', + }, + data: data, + }).then(response => { + let embed = new Discord.RichEmbed() + .setColor(`GREEN`) + .addField(`__**Status:**__`, response.statusText) + .addField(`__**Created for user ID:**__`, data.user) + .addField(`__**Server name:**__`, data.name) + .addField(`__**Type:**__`, args[1].toLowerCase()) + message.channel.send(embed) + }).catch(error => { + let embed1 = new Discord.RichEmbed() + .setColor(`RED`) + .addField(`__**FAILED:**__`, "Please contact a host admin. \n\nError: `" + error + "`") + message.channel.send(embed1) + message.channel.send("<@137624084572798976> Issue when creating server. \nResponse: `" + error + "`") + }) + } + } else { + //Anything else + let embed2 = new Discord.RichEmbed() + .setColor(`RED`) + .addField(`__**Supported By Server Creation:**__`, "NodeJS \nPython \nJava \nMinecraft.Paper \nMinecraft.Forge \nFiveM") + message.channel.send(embed2) + } + } else if (args[0].toLowerCase() == "delete") { + //delete server things + message.channel.send('Uh this isnt done yet...') + } +}; +}; \ No newline at end of file diff --git a/Panel/bot/discord/commands/staff.js b/Panel/bot/discord/commands/staff.js index 0864625de..158ad3025 100644 --- a/Panel/bot/discord/commands/staff.js +++ b/Panel/bot/discord/commands/staff.js @@ -1,23 +1,29 @@ -exports.run = async (client, message, args) => { - //const args = message.content.split(' ').slice(1).join(' '); - //const args2 = message.content.split(' ').slice(3).join(' '); - - if (message.content.toLowerCase().includes("linked")) { - if (args.slice(0).join(" ") == "") { - message.channel.send('Please send a users discord ID to see if they are linked with an account on the host.') - } else { - if (userData.get(args.slice(1).join(" ")) == null) { - message.channel.send("That account is not linked with a console account :sad:") - } else { - let embed = new Discord.RichEmbed() - .setColor(`GREEN`) - .addField(`__**Username**__`, userData.fetch(args.slice(1).join(" ") + ".username")) - .addField(`__**Date (YYYY/MM/DD)**__`, userData.fetch(args.slice(1).join(" ") + ".linkDate")) - .addField(`__**Time**__`, userData.fetch(args.slice(1).join(" ") + ".linkTime")) - message.channel.send('That account is linked. Heres some data: ', embed) - } - } - } else if (message.content.toLowerCase().includes("createserver")) { - message.channels.send('Who would you like to create') - } +exports.run = async (client, message, args) => { + if (!args[0]) { + let embed = new Discord.RichEmbed() + .setColor('RANDOM') + .addField('**Staff Commands:**', config.DiscordBot.Prefix + "staff linked useridhere | Shows if the users account is linked.") + message.channel.send(embed) + } else if (message.content.toLowerCase().includes("linked")) { + if (args[1] === "") { + message.channel.send('Please send a users discord ID to see if they are linked with an account on the host.') + } else { + if (userData.get(args[1]) == null) { + message.channel.send("That account is not linked with a console account :sad:") + } else { + console.log(userData.fetch(args[1])) + let embed = new Discord.RichEmbed() + .setColor(`GREEN`) + .addField(`__**Username**__`, userData.fetch(args[1] + ".username")) + .addField(`__**Email**__`, userData.fetch(args[1] + ".email")) + .addField(`__**Discord ID**__`, userData.fetch(args[1] + ".discordID")) + .addField(`__**Console ID**__`, userData.fetch(args[1] + ".consoleID")) + .addField(`__**Date (YYYY/MM/DD)**__`, userData.fetch(args[1] + ".linkDate")) + .addField(`__**Time**__`, userData.fetch(args[1] + ".linkTime")) + message.channel.send('That account is linked. Heres some data: ', embed) + } + } + } else if (message.content.toLowerCase().includes("createserver")) { + message.channels.send('Who would you like to create') + } } \ No newline at end of file diff --git a/Panel/bot/discord/commands/stats.js b/Panel/bot/discord/commands/stats.js index 46330237e..679e82dcc 100644 --- a/Panel/bot/discord/commands/stats.js +++ b/Panel/bot/discord/commands/stats.js @@ -1,43 +1,30 @@ -exports.run = async(client, message) => { - - //Sends message while the json's are being cached - let embed = new Discord.RichEmbed() - .setColor(`RANDOM`) - .addField(`__**Please wait...**__`, `Loading all node's stats!`, true); - let msg = await message.channel.send(embed) - - //Reads the saved jsons for each node -//Data for node 1 -var N1 = fs.readFileSync('./data/0286b2ad-dc80-4b5c-a0de-b81945b010e8.json', 'utf8'); -var Node1Data = JSON.parse(N1); - -//Data for node 2 -var N2 = fs.readFileSync('./data/2e3f071a-af2b-4dc9-be5a-7ce72590a181.json', 'utf8'); -var Node2Data = JSON.parse(N2); - -//Data for node 3 -var N3 = fs.readFileSync('./data/e5406f6d-a9a6-44fa-9dde-429ffc1bf1d7.json', 'utf8'); -var Node3Data = JSON.parse(N3); - -//Data for Main Dedi -var MainD = fs.readFileSync('./data/pve.json', 'utf8'); -var Node4Data = JSON.parse(MainD); - -//Data for node 5 -var N5 = fs.readFileSync('./data/Server-01.json', 'utf8'); -var Node5Data = JSON.parse(N5); - - //Edits the message to display the data - embed.fields.pop() - embed.addField("\u200b", "__**[Node 1 - Discord Bots](https://stats.danbot.xyz/Node1)**__ \n**CPU LOAD**: " + Node1Data.cpuload + "% \n**RAM (USED/TOTAL)**: " + Node1Data.memused + " / " + Node1Data.memtotal + " \n**STORAGE (USED/TOTAL)**: " + Node1Data.diskused + " / " + Node1Data.disktotal + " \n**UPTIME**: " + Node1Data.osuptime) - embed.addField('\u200b', '\u200b') - embed.addField("\u200b", "__**[Node 2 - Discord Bots](https://stats.danbot.xyz/Node2)**__ \n**CPU LOAD**: " + Node2Data.cpuload + "% \n**RAM (USED/TOTAL)**: " + Node2Data.memused + " / " + Node2Data.memtotal + " \n**STORAGE (USED/TOTAL)**: " + Node2Data.diskused + " / " + Node2Data.disktotal + " \n**UPTIME**: " + Node2Data.osuptime) - embed.addField('\u200b', '\u200b') - embed.addField("\u200b", "__**[Node 3 - Gaming](https://stats.danbot.xyz/Node3)**__ \n**CPU LOAD**: " + Node3Data.cpuload + "% \n**RAM (USED/TOTAL)**: " + Node3Data.memused + " / " + Node3Data.memtotal + " \n**STORAGE (USED/TOTAL)**: " + Node3Data.diskused + " / " + Node3Data.disktotal + " \n**UPTIME**: " + Node3Data.osuptime) - embed.addField('\u200b', '\u200b') - embed.addField("\u200b", "__**[Main Dedi](https://stats.danbot.xyz/Main)**__ \n**CPU LOAD**: " + Node4Data.cpuload + "% \n**RAM (USED/TOTAL)**: " + Node4Data.memused + " / " + Node4Data.memtotal + " \n**STORAGE (USED/TOTAL)**: " + Node4Data.diskused + " / " + Node4Data.disktotal + " \n**UPTIME**: " + Node4Data.osuptime) - embed.addField('\u200b', '\u200b') - embed.addField("\u200b", "__**[Node 4 - Private](https://stats.danbot.xyz/Node4)**__ \n**CPU LOAD**: " + Node5Data.cpuload + "% \n**RAM (USED/TOTAL)**: " + Node5Data.memused + " / " + Node5Data.memtotal + " \n**STORAGE (USED/TOTAL)**: " + Node5Data.diskused + " / " + Node5Data.disktotal + " \n**UPTIME**: " + Node5Data.osuptime) - embed.setDescription('Want to view more stats live? [Click Here!](https://stats.danbot.xyz/)') - msg.edit(embed); +exports.run = async(client, message) => { + + //Sends message while the json's are being cached + let embed = new Discord.RichEmbed() + .setColor(`RANDOM`) + .addField(`__**Please wait...**__`, `Loading all node's stats! (If this takes longer than 5seconds. This command is broken)`, true); + let msg = await message.channel.send(embed) + +//Data for node 1 +var N1 = fs.readFileSync('./data/Node1.json', 'utf8'); +var Node1Data = JSON.parse(N1); + +//Data for node 2 +var N2 = fs.readFileSync('./data/Node2.json', 'utf8'); +var Node2Data = JSON.parse(N2); + +//Data for node 3 +var N3 = fs.readFileSync('./data/vmi450443.contaboserver.net.json', 'utf8'); +var Node3Data = JSON.parse(N3); + + //Edits the message to display the data + embed.fields.pop() + embed.addField("\u200b", "__**[Node 1 - Discord Bots](https://danbot.host/Node1)**__ \n**CPU LOAD**: " + Node1Data.cpuload + "% \n**RAM (USED/TOTAL)**: " + Node1Data.memused + " / " + Node1Data.memtotal + " \n**STORAGE (USED/TOTAL)**: " + Node1Data.diskused + " / " + Node1Data.disktotal + " \n**UPTIME**: " + Node1Data.osuptime) + embed.addField('\u200b', '\u200b') + embed.addField("\u200b", "__**[Node 2 - Discord Bots](https://danbot.host/Node2)**__ \n**CPU LOAD**: " + Node2Data.cpuload + "% \n**RAM (USED/TOTAL)**: " + Node2Data.memused + " / " + Node2Data.memtotal + " \n**STORAGE (USED/TOTAL)**: " + Node2Data.diskused + " / " + Node2Data.disktotal + " \n**UPTIME**: " + Node2Data.osuptime) + embed.addField('\u200b', '\u200b') + embed.addField("\u200b", "__**[Node 3 - Gaming](https://danbot.host/Node3)**__ \n**CPU LOAD**: " + Node3Data.cpuload + "% \n**RAM (USED/TOTAL)**: " + Node3Data.memused + " / " + Node3Data.memtotal + " \n**STORAGE (USED/TOTAL)**: " + Node3Data.diskused + " / " + Node3Data.disktotal + " \n**UPTIME**: " + Node3Data.osuptime) + embed.setDescription('Want to view more stats live? [Click Here!](https://danbot.host/stats)') + msg.edit(embed); }; \ No newline at end of file diff --git a/Panel/bot/discord/commands/status.js b/Panel/bot/discord/commands/status.js index 0b498b281..d627d251d 100644 --- a/Panel/bot/discord/commands/status.js +++ b/Panel/bot/discord/commands/status.js @@ -1,50 +1,67 @@ -exports.run = (client, message) => { - const args = message.content.split(' ').slice(1).join(' '); - - if (args == "") { - let embed = new Discord.RichEmbed() - .setColor(`GREEN`) - .addField(`__**Server Status**__`, 'What server would you like to view? Please type: ' + config.DiscordBot.Prefix + 'status serveridhere', true) - message.channel.send(embed) - - } else { - message.delete(); - DanBotHostingClient.getServerStatus(args).then((status) => { - DanBotHostingClient.getCPUUsage(args).then(CPUUsageResponse => { - DanBotHostingClient.getRAMUsage(args).then(RAMUsageResponse => { - DanBotHostingClient.getDiskUsage(args).then(DISKUsageResponse => { - DanBotHostingClient.getServerInfo(args).then(InfoResponse => { - if (status == "on") { - if (RAMUsageResponse.limit == "0") { - let embedstatus = new Discord.RichEmbed() - .setColor('GREEN') - .addField('**Server name**', InfoResponse.attributes.name) - .addField('**Status**', `Online :)`, true) - .addField('**CPU Usage**', CPUUsageResponse.current + ' %') - .addField('**RAM Usage**', RAMUsageResponse.current + ' MB out of UNLIMITED MB') - .addField('**DISK Usage**', DISKUsageResponse.current + ' MB out of ' + DISKUsageResponse.limit + ' MB') - .addField('**LIMITS (0 = unlimited)**', 'Memory: ' + InfoResponse.attributes.limits.memory + ' MB, Disk: ' + InfoResponse.attributes.limits.disk + ' MB, CPU Cores: ' + InfoResponse.attributes.limits.cpu) - message.reply(embedstatus) - } else { - let embedstatus = new Discord.RichEmbed() - .setColor('GREEN') - .addField('**Server name**', InfoResponse.attributes.name) - .addField('**Status**', `Online :)`, true) - .addField('**CPU Usage**', CPUUsageResponse.current + ' %') - .addField('**RAM Usage**', RAMUsageResponse.current + ' MB out of ' + RAMUsageResponse.limit + ' MB') - .addField('**DISK Usage**', DISKUsageResponse.current + ' MB out of ' + DISKUsageResponse.limit + ' MB') - .addField('**LIMITS (0 = unlimited)**', 'Memory: ' + InfoResponse.attributes.limits.memory + ' MB, Disk: ' + InfoResponse.attributes.limits.disk + ' MB, CPU Cores: ' + InfoResponse.attributes.limits.cpu) - message.reply(embedstatus) - } - } else if (status == "off") { - let embedstatus = new Discord.RichEmbed() - .setColor('RED') - .addField('**Server name**', InfoResponse.attributes.name) - .addField('**Status**', `Offline :(`) - message.reply(embedstatus) - } - }).catch((error) => { - console.log(error); - })})})})}); - }; +const axios = require('axios'); +exports.run = (client, message) => { + const args = message.content.split(' ').slice(1).join(' '); + + if (args == "") { + let embed = new Discord.RichEmbed() + .setColor(`GREEN`) + .addField(`__**Server Status**__`, 'What server would you like to view? Please type: ' + config.DiscordBot.Prefix + 'status serveridhere', true) + message.channel.send(embed) + + } else { + message.delete(); + + //Send Request + axios({ + url: config.Pterodactyl.hosturl + "/api/application/users", + method: 'GET', + followRedirect: true, + maxRedirects: 5, + headers: { + 'Authorization': 'Bearer ' + config.Pterodactyl.apikey, + 'Content-Type': 'application/json', + 'Accept': 'Application/vnd.pterodactyl.v1+json', + } + }).then(response => { + const data = response.attributes; + + DanBotHostingClient.getServerStatus(args).then((status) => { + DanBotHostingClient.getCPUUsage(args).then(CPUUsageResponse => { + DanBotHostingClient.getRAMUsage(args).then(RAMUsageResponse => { + DanBotHostingClient.getDiskUsage(args).then(DISKUsageResponse => { + DanBotHostingClient.getServerInfo(args).then(InfoResponse => { + if (status == "on") { + if (RAMUsageResponse.limit == "0") { + let embedstatus = new Discord.RichEmbed() + .setColor('GREEN') + .addField('**Server name**', data.name) + .addField('**Status**', `Online :)`, true) + .addField('**CPU Usage**', CPUUsageResponse.current + ' %') + .addField('**RAM Usage**', RAMUsageResponse.current + ' MB out of UNLIMITED MB') + .addField('**DISK Usage**', DISKUsageResponse.current + ' MB out of ' + DISKUsageResponse.limit + ' MB') + .addField('**LIMITS (0 = unlimited)**', 'Memory: ' + InfoResponse.attributes.limits.memory + ' MB, Disk: ' + InfoResponse.attributes.limits.disk + ' MB, CPU Cores: ' + InfoResponse.attributes.limits.cpu) + message.reply(embedstatus) + } else { + let embedstatus = new Discord.RichEmbed() + .setColor('GREEN') + .addField('**Server name**', InfoResponse.attributes.name) + .addField('**Status**', `Online :)`, true) + .addField('**CPU Usage**', CPUUsageResponse.current + ' %') + .addField('**RAM Usage**', RAMUsageResponse.current + ' MB out of ' + RAMUsageResponse.limit + ' MB') + .addField('**DISK Usage**', DISKUsageResponse.current + ' MB out of ' + DISKUsageResponse.limit + ' MB') + .addField('**LIMITS (0 = unlimited)**', 'Memory: ' + InfoResponse.attributes.limits.memory + ' MB, Disk: ' + InfoResponse.attributes.limits.disk + ' MB, CPU Cores: ' + InfoResponse.attributes.limits.cpu) + message.reply(embedstatus) + } + } else if (status == "off") { + let embedstatus = new Discord.RichEmbed() + .setColor('RED') + .addField('**Server name**', InfoResponse.attributes.name) + .addField('**Status**', `Offline :(`) + message.reply(embedstatus) + } + }).catch((error) => { + console.log(error); + })})})})}); + }); + }; }; \ No newline at end of file diff --git a/Panel/bot/discord/commands/suggest.js b/Panel/bot/discord/commands/suggest.js new file mode 100644 index 000000000..a2f9997d5 --- /dev/null +++ b/Panel/bot/discord/commands/suggest.js @@ -0,0 +1,12 @@ +let db = require("quick.db"); +const Discord = require("discord.js"); + +exports.run = async (client, message, args) => { + +let embed = new Discord.RichEmbed() +.setColor("BLUE") +.setTitle("DanBot Hosting Suggestion") +.setDescription("To send in Suggestions and or Feedback please visit our Feedback form [Here](https://stats.danbot.xyz/feedback)") +message.channel.send(embed) + +}; \ No newline at end of file diff --git a/Panel/bot/discord/commands/ticket.js b/Panel/bot/discord/commands/ticket.js index 9f80eea7c..d0c4ffa42 100644 --- a/Panel/bot/discord/commands/ticket.js +++ b/Panel/bot/discord/commands/ticket.js @@ -23,16 +23,16 @@ exports.run = async (client, message) => { }, { type: "role", - id: "697599153538334841", + id: "748117822370086932", allow: 84992 } ]).catch(console.error); - message.reply(`Please check ${channel} for your ticket.`) + message.reply(`Please check <#${channel.id}> for your ticket.`) - let category = server.channels.find(c => c.id == "654313162086285323" && c.type == "category"); + let category = server.channels.find(c => c.id == "738538742603841650" && c.type == "category"); if (!category) throw new Error("Category channel does not exist"); - await channel.setParent(category.id); + await channel.setParent(category.id).catch(console.error); channel.overwritePermissions(message.author, { VIEW_CHANNEL: true, @@ -41,14 +41,15 @@ exports.run = async (client, message) => { }) if (userData.get(message.author.id) == null) { - channel.send('@ everyone \n\n <@' + message.author.id + '> here is your ticket! Please give as much info as possible about your problem. \n\n *This account is not linked with a console account*') + channel.send('@<@' + message.author.id + '> here is your ticket! Please give as much info as possible about your problem. \n\n *This account is not linked with a console account*') } else { let embed = new Discord.RichEmbed() .setColor(`GREEN`) .addField(`__**Username**__`, userData.fetch(message.author.id + ".username")) + .addField(`__**Email**__`, userData.fetch(message.author.id + ".email")) .addField(`__**Date (YYYY/MM/DD)**__`, userData.fetch(message.author.id + ".linkDate")) .addField(`__**Time**__`, userData.fetch(message.author.id + ".linkTime")) - channel.send('@ everyone \n\n <@' + message.author.id + '> here is your ticket! Please give as much info as possible about your problem. \n\n *This account is linked with:* ', embed) + channel.send('<@' + message.author.id + '> here is your ticket! Please give as much info as possible about your problem. \n\n *This account is linked with:* ', embed) } } else if (args == "close") { if (message.channel.name.includes('-ticket')) { @@ -56,6 +57,7 @@ exports.run = async (client, message) => { const warning = await message.channel.send('<@' + message.author.id + '> are you sure you want to close this ticket? please type `confirm` to close the ticket or `cancel` to keep the ticket open.') let collected1 = await message.channel.awaitMessages(filter2, { + max: 1, time: 30000, errors: ['time'], }).catch(x => { @@ -67,7 +69,7 @@ exports.run = async (client, message) => { return false; }) - if (collected1.first().content.toLowerCase() === 'confirm') { + if (collected1.first().content === 'confirm') { return message.channel.send("**Closing ticket.**", null).then(setTimeout(() => { message.channel.delete()}, 5000)) } else if (collected1.first().content === 'cancel') { return message.channel.send('Closing ticket. __**Canceled**__ Ticket staying open.'); @@ -102,4 +104,4 @@ exports.run = async (client, message) => { }) } } -}; +}; \ No newline at end of file diff --git a/Panel/bot/discord/commands/tickets.js b/Panel/bot/discord/commands/tickets.js new file mode 100644 index 000000000..eba182660 --- /dev/null +++ b/Panel/bot/discord/commands/tickets.js @@ -0,0 +1,10 @@ +exports.run = async (client, message) => { + const args = message.content.split(' ').slice(1).join(' '); + + if (args == "") { + let embed = new Discord.RichEmbed() + .setColor(`GREEN`) + .addField(`__**Tickets**__`, `Create a new ticket: ${config.DiscordBot.Prefix}ticket new \nNeed to close a ticket? ${config.DiscordBot.Prefix}ticket close`, true); + message.channel.send(embed) + } +}; \ No newline at end of file diff --git a/Panel/bot/discord/commands/uptime.js b/Panel/bot/discord/commands/uptime.js index 684b2905c..40a44e9c5 100644 --- a/Panel/bot/discord/commands/uptime.js +++ b/Panel/bot/discord/commands/uptime.js @@ -1,52 +1,52 @@ -exports.run = async(client, message, args) => { - - var getUptime = function(millis) { - var dur = {}; - var units = [{ - label: "milliseconds", - mod: 1000 - }, - { - label: "seconds", - mod: 60 - }, - { - label: "minutes", - mod: 60 - }, - { - label: "hours", - mod: 24 - }, - { - label: "days", - mod: 31 - } - ]; - - units.forEach(function(u) { - millis = (millis - (dur[u.label] = (millis % u.mod))) / u.mod; - }); - - var nonZero = function(u) { - return dur[u.label]; - }; - dur.toString = function() { - return units - .reverse() - .filter(nonZero) - .map(function(u) { - return dur[u.label] + " " + (dur[u.label] == 1 ? u.label.slice(0, -1) : u.label); - }) - .join(', '); - }; - return dur; - }; - -let myDate = new Date(client.readyTimestamp); - var embed = new Discord.RichEmbed() - .addField(":white_check_mark: Uptime:", `**${getUptime(client.uptime)}**`) - .setFooter(`Ready Timestamp: ${myDate.toString()}`) - .setColor("GREEN") - message.channel.send(embed); +exports.run = async(client, message, args) => { + + var getUptime = function(millis) { + var dur = {}; + var units = [{ + label: "milliseconds", + mod: 1000 + }, + { + label: "seconds", + mod: 60 + }, + { + label: "minutes", + mod: 60 + }, + { + label: "hours", + mod: 24 + }, + { + label: "days", + mod: 31 + } + ]; + + units.forEach(function(u) { + millis = (millis - (dur[u.label] = (millis % u.mod))) / u.mod; + }); + + var nonZero = function(u) { + return dur[u.label]; + }; + dur.toString = function() { + return units + .reverse() + .filter(nonZero) + .map(function(u) { + return dur[u.label] + " " + (dur[u.label] == 1 ? u.label.slice(0, -1) : u.label); + }) + .join(', '); + }; + return dur; + }; + +let myDate = new Date(client.readyTimestamp); + var embed = new Discord.RichEmbed() + .addField(":white_check_mark: Uptime:", `**${getUptime(client.uptime)}**`) + .setFooter(`Ready Timestamp: ${myDate.toString()}`) + .setColor("GREEN") + message.channel.send(embed); } \ No newline at end of file diff --git a/Panel/bot/discord/events/guildMemberAdd.js b/Panel/bot/discord/events/guildMemberAdd.js index 25e1c0db1..016784557 100644 --- a/Panel/bot/discord/events/guildMemberAdd.js +++ b/Panel/bot/discord/events/guildMemberAdd.js @@ -1,17 +1,67 @@ const config = { - "welcome": "704648079361573024", - "inviterewmsg": "704648079361573024", + "welcome": "738527858594414663", + "inviterewmsg": "738527858594414663", "invite5": "704650026076602449", "invite10": "704650153797091418", "invite25": "704650197732556891", "invite50": "704650269182394398", - "invitechannel": "704650867642597468", + "invitechannel": "738536628376698981", "member": "639490038434103306", "bot": "704467807122882562" } //let client = require("../../../../index.js").client; module.exports = async(client, member, guild) => { + + var getAge = function(millis) { + var dur = {}; + var units = [{ + label: "milliseconds", + mod: 1000 + }, + { + label: "seconds", + mod: 60 + }, + { + label: "minutes", + mod: 60 + }, + { + label: "hours", + mod: 24 + }, + { + label: "days", + mod: 31 + } + ]; + + units.forEach(function(u) { + millis = (millis - (dur[u.label] = (millis % u.mod))) / u.mod; + }); + + var nonZero = function(u) { + return dur[u.label]; + }; + dur.toString = function() { + return units + .reverse() + .filter(nonZero) + .map(function(u) { + return dur[u.label] + " " + (dur[u.label] == 1 ? u.label.slice(0, -1) : u.label); + }) + .join(', '); + }; + return dur; + }; + + if (Date.now() - member.user.createdAt < 863136000) { + member.kick().then(memberkicked => { + client.channels.get('738527858594414663').send(member.user.tag + ` has been auto-kicked as account is under 10days old \nThat account was created ${getAge(member.user.createdAt)}, ago`) + }); + } + if(member.user.bot) { const botrole = member.guild.roles.find(role => role.id === config.bot); member.guild.members.get(member.user.id).addRole(botrole) @@ -19,14 +69,26 @@ module.exports = async(client, member, guild) => { } else if (!member.user.bot) { const memberrole = member.guild.roles.find(role => role.id === config.member); member.guild.members.get(member.user.id).addRole(memberrole) - client.channels.get(config.welcome).send("Welcome <@" + member.user.id + "> to DanBot Hosting. To get started please read <#724021367842013346>"); + client.channels.get(config.welcome).send("Welcome <@" + member.user.id + "> to DanBot Hosting. To get started please read <#738527470164377630>"); member.guild.fetchInvites().then(guildInvites => { const ei = invites[member.guild.id]; invites[member.guild.id] = guildInvites; const invite = guildInvites.find(i => ei.get(i.code).uses < i.uses); const inviter = client.users.get(invite.inviter.id); - client.channels.get(config.invitechannel).send(`${member.user.tag} (ID: ${member.user.id}) joined using invite code ` + "`" + invite.code + "`" + ` from ${inviter.tag} (ID: ${inviter.id}). Invite code has been used ${invite.uses} times.`); + let embed = new Discord.RichEmbed() + .setColor(`GREEN`) + .addField(`New Members Username:`, member.user.tag, true) + .addField(`New Members ID:`, '`' + member.user.id + '`', true) + .addField('Account created:', member.user.createdAt.toDateString(), true) + .addField("Members Status", member.user.presence !== null && member.user.presence.status !== null ? member.user.presence.status : "Offline") + .addField('\u200b', '\u200b') + .addField(`Invited by:`, inviter.tag, true) + .addField(`Inviter's ID:`, '`' + inviter.id + '`', true) + .addField(`Invite code used:`, '`' + invite.code + '`', true) + .addField(`Invite used`, invite.uses + ' times', true); + client.channels.get(config.invitechannel).send(embed) + //client.channels.get(config.invitechannel).send(`${member.user.tag} (ID: ${member.user.id}) joined using invite code ` + "`" + invite.code + "`" + ` from ${inviter.tag} (ID: ${inviter.id}). Invite code has been used ${invite.uses} times.`); const invite5 = member.guild.roles.find(role => role.id === config.invite5); const invite10 = member.guild.roles.find(role => role.id === config.invite10); const invite25 = member.guild.roles.find(role => role.id === config.invite25); @@ -36,5 +98,7 @@ module.exports = async(client, member, guild) => { if (invite.uses == 25) return member.guild.members.get(inviter.id).removeRole(invite10), member.guild.members.get(inviter.id).addRole(invite25), client.channels.get(config.inviterewmsg).send(`<@${inviter.id}> just hit 25 invites! Here's a role for you :)`);; if (invite.uses == 50) return member.guild.members.get(inviter.id).removeRole(invite25), member.guild.members.get(inviter.id).addRole(invite50), client.channels.get(config.inviterewmsg).send(`<@${inviter.id}> just hit 50 invites! Here's a role for you :)`);; }); + + } }; \ No newline at end of file diff --git a/Panel/bot/discord/events/guildMemberUpdate.js b/Panel/bot/discord/events/guildMemberUpdate.js new file mode 100644 index 000000000..cac2bdaf9 --- /dev/null +++ b/Panel/bot/discord/events/guildMemberUpdate.js @@ -0,0 +1,84 @@ +module.exports = async(client, oldMember, newMember) => { + // If user nickname changes. + if (oldMember.nickname !== newMember.nickname) { + + // Make local vars + var oldName = oldMember.nickname; + var newName = newMember.nickname; + + // If no set nickname, use the user's username. + if (oldMember.nickname === null) { + oldName = oldMember.user.username; + } + if (newMember.nickname === null) { + newName = newMember.user.username; + } + const a = "\u200B"; + if (newName.includes(" ឵឵")) { + oldMember.setNickname('') + } else if(newName.includes("͔")) { + oldMember.setNickname("") + } else if(newName.includes(" ឵឵")) { + oldMember.setNickname("") + } else if(newName.includes(a)) { + oldMember.setNickname("") + } + + // Make a new RichEmbed + const embed = new Discord.RichEmbed() + .setTitle("User Nickname changed.") + .setThumbnail(`${oldMember.user.displayAvatarURL}`) + .setDescription(`User: ${oldMember.user} Nickname has changed.`) + .addField("Old Nickname", oldName, true) + .addField("New Nickname", newName, true) + .setColor(0xFF7700) + .setTimestamp(new Date()); + + //oldMember.setNickname('') + client.channels.get(config.DiscordBot.oLogs).send(embed) + + return; + } else if (oldMember.roles !== newMember.roles) { + + // Make local vars. + var oldRoles = []; + var newRoles = []; + + // Get the roles from the user and push to our local vars. + oldMember.roles.forEach(function (k) { + oldRoles.push(k.name); + }); + newMember.roles.forEach(function (k) { + newRoles.push(k.name); + }); + + // If a role was Added. + if (oldRoles.length < newRoles.length) { + var addedChange = filterArray(newRoles, oldRoles)[0]; + + // Make a new RichEmbed + const embed = new Discord.RichEmbed() + .setTitle("User Role changed.") + .setThumbnail(`${oldMember.user.displayAvatarURL}`) + .setDescription("User: " + oldMember + " has gained the role: " + addedChange) + .setColor(0xFF7700) + .setTimestamp(new Date()); + + + client.channels.get(config.DiscordBot.oLogs).send(embed) + + } } else { + var removedChange = filterArray(oldRoles, newRoles)[0]; + + // Make a new RichEmbed + const embed = new Discord.RichEmbed() + .setTitle("User Role changed.") + .setThumbnail(`${oldMember.user.displayAvatarURL}`) + .setDescription("User: " + oldMember + " has lost the role: " + removedChange) + .setColor(0xFF7700) + .setTimestamp(new Date()); + + client.channels.get(config.DiscordBot.oLogs).send(embed) + + } +}; \ No newline at end of file diff --git a/Panel/bot/discord/events/message.js b/Panel/bot/discord/events/message.js index 93b775c2f..f9ce4c6b2 100644 --- a/Panel/bot/discord/events/message.js +++ b/Panel/bot/discord/events/message.js @@ -1,37 +1,70 @@ -//let client = require("../../../../index.js").client; - -module.exports = (client, message) => { - //if(message.content.toLowerCase().includes("tiktok")) {message.reply('Ew. Get out here with that crap :bammer:'), message.delete() } - if(message.content.toLowerCase().includes("discord.gg")) { - if(message.channel.id === '717146816918847489') { - return; - } else if(message.channel.id === '719259195471429722') { - return; - } else { - message.delete(); - //message.reply('No advertising here. Check out <#717146816918847489> or <#719259195471429722> for advertising!') - } - } - - if (message.channel.type == "dm") { - if(message.author.id == "137624084572798976") { - const args = message.content.trim().split(/ +/g); - client.channels.get(args[0]).send(message.content.split(' ').slice(1).join(' ')) - }}; - - - const prefix = config.DiscordBot.Prefix; - if (message.content.indexOf(prefix) !== 0) return; - const args = message.content.slice(prefix.length).trim().split(/ +/g); - const commandargs = message.content.split(' ').slice(1).join(' '); - const command = args.shift().toLowerCase(); - console.log(chalk.magenta("[DISCORD] ") + chalk.yellow(`[${message.author.username}] [${message.author.id}] >> ${prefix}${command} ${commandargs}`)); - try { - let commandFile = require(`../commands/${command}.js`); - commandFile.run(client, message, args); - } catch (err) { - if (err instanceof Error && err.code === "MODULE_NOT_FOUND") { - return; - } - } +//let client = require("../../../../index.js").client; + +module.exports = (client, message) => { + //if(message.content.toLowerCase().includes("tiktok")) {message.reply('Ew. Get out here with that crap :bammer:'), message.delete() } + if(message.content.toLowerCase().includes("discord.gg")) { + message.delete(); + } else if (message.content.toLowerCase().includes("discord.com")) { + message.delete() + } else if (message.content.toLowerCase().includes(" ឵឵")) { + message.delete() + } else if (message.content.toLowerCase().includes("")) + +/* + const Tesseract = require("tesseract.js") + if (message.attachments.size > 0) { + message.attachments.forEach(attachment => { + //console.log(attachment.url) + Tesseract.recognize( + attachment.url, + 'eng', + ).then(({ data: { text } }) => { + if (text.includes("There was an error attempting to establish")) { + message.reply('It looks like you are getting a error with the websocket. Try refreshing if that doesnt work please check <#738530520945786921>') + } else if (text.includes("HTTP/E_CONN_REFUSED")) { + message.reply('It looks like you might be getting a `HTTP/E_CONN_REFUSED` error. \nThis error is normally found in the file management. Please refresh. \nIf that doesnt fix check <#738530520945786921> for any possible outages. No outages but still got the error? make a ticket!') + } else if (text.includes("We were unable to locate the requested resource on the server.")) { + message.reply('Uh oh. Server you are trying to access doesnt exist. Did you get the wrong url or was the server deleted?') + } else if (text.includes("You do not have permission to access this resource on this server.")) { + message.reply('The server you are trying to access you do not have perms to view. If you did before the user might of removed you as subuser.') + } else if (text.includes('Gateway Timeout')) { + message.reply('It looks like you are getting a `Gateway Timeout` error. This normally happens when a outage is happening. \nIf nothing is posted in <#738530520945786921> then you might just be having the issue. \nIt should fix its self soon') + } else if (text.includes('instal process')) { + message.reply('It looks like your server might be stuck on installing. Please open a ticket so we can fix this for you.') + } else { + message.react('👀'); + } + message.channel.send(text) + }) + }); + }; + */ + + if (message.channel.type == "dm") { + if(message.author.id == "137624084572798976") { + const args = message.content.trim().split(/ +/g); + client.channels.get(args[0]).send(message.content.split(' ').slice(1).join(' ')) + }}; + + + const prefix = config.DiscordBot.Prefix; + if (message.content.indexOf(prefix) !== 0) return; + const args = message.content.slice(prefix.length).trim().split(/ +/g); + const commandargs = message.content.split(' ').slice(1).join(' '); + const command = args.shift().toLowerCase(); + console.log(chalk.magenta("[DISCORD] ") + chalk.yellow(`[${message.author.username}] [${message.author.id}] >> ${prefix}${command} ${commandargs}`)); + try { + let commandFile = require(`../commands/${command}.js`); + commandFile.run(client, message, args); + } catch (err) { + if (err instanceof Error && err.code === "MODULE_NOT_FOUND") { + return; + } + } + + //Requests channel auto react + if (message.channel.id == config.DiscordBot.requestsChannel) { + message.react('✅'); + } + }; \ No newline at end of file diff --git a/Panel/bot/discord/events/messageDelete.js b/Panel/bot/discord/events/messageDelete.js index 8f1dc7028..87ca17544 100644 --- a/Panel/bot/discord/events/messageDelete.js +++ b/Panel/bot/discord/events/messageDelete.js @@ -1,19 +1,19 @@ -//let client = require("../../../../index.js").client; - -module.exports = (client, message) => { - if (message.author.bot) return; - if (message.channel.type === 'dm') return; - if (message.channel.type !== 'text') return; - - - const description = message.cleanContent - const descriptionfix = description.substr(0, 600); - const embed = new Discord.RichEmbed() - .setColor(0x00A2E8) - .setThumbnail(message.author.avatarURL) - .addField("Author ", `${message.author.tag} (ID: ${message.author.id})`) - .addField("Message Content:", `${descriptionfix}`) - .setTimestamp() - .setFooter("Message delete in " + message.channel.name); - client.channels.get(config.DiscordBot.mLogs).send({embed}); +//let client = require("../../../../index.js").client; + +module.exports = (client, message) => { + if (message.author.bot) return; + if (message.channel.type === 'dm') return; + if (message.channel.type !== 'text') return; + + + const description = message.cleanContent + const descriptionfix = description.substr(0, 600); + const embed = new Discord.RichEmbed() + .setColor(0x00A2E8) + .setThumbnail(message.author.avatarURL) + .addField("Author ", `${message.author.tag} (ID: ${message.author.id})`) + .addField("Message Content:", `${descriptionfix}`) + .setTimestamp() + .setFooter("Message delete in " + message.channel.name); + client.channels.get(config.DiscordBot.mLogs).send({embed}); }; \ No newline at end of file diff --git a/Panel/bot/discord/events/messageUpdate.js b/Panel/bot/discord/events/messageUpdate.js index 45d7047be..276a77919 100644 --- a/Panel/bot/discord/events/messageUpdate.js +++ b/Panel/bot/discord/events/messageUpdate.js @@ -1,23 +1,26 @@ -//let client = require("../../../../index.js").client; - -module.exports = (client, message, editedMessage) => { - if (message.content.toLowerCase().includes("tiktok")) { - message.delete() - } - if (message.author.bot) return; - if (message.channel.type === 'dm') return; - if (message === editedMessage) return; - if (message.channel.type !== 'text') return; - - const embed = new Discord.RichEmbed() - .setColor(0x00A2E8) - .setThumbnail(message.author.avatarURL) - .addField("Author ", `${message.author.tag} (ID: ${message.author.id})`) - .addField("Before Edit ", `${message}`) - .addField("After Edit", `${editedMessage}`) - .setTimestamp() - .setFooter("Message edit in " + message.channel.name); - client.channels.get(config.DiscordBot.mLogs).send({ - embed - }); +//let client = require("../../../../index.js").client; + +module.exports = (client, message, editedMessage) => { + if(editedMessage.content.toLowerCase().includes("discord.gg")) { + editedMessage.delete(); +} else if (editedMessage.content.toLowerCase().includes("discord.com")) { + editedMessage.delete() +} + + if (message.author.bot) return; + if (message.channel.type === 'dm') return; + if (message === editedMessage) return; + if (message.channel.type !== 'text') return; + + const embed = new Discord.RichEmbed() + .setColor(0x00A2E8) + .setThumbnail(message.author.avatarURL) + .addField("Author ", `${message.author.tag} (ID: ${message.author.id})`) + .addField("Before Edit ", `${message}`) + .addField("After Edit", `${editedMessage}`) + .setTimestamp() + .setFooter("Message edit in " + message.channel.name); + client.channels.get(config.DiscordBot.mLogs).send({ + embed + }); }; \ No newline at end of file diff --git a/Panel/bot/discord/events/ready.js b/Panel/bot/discord/events/ready.js index 512ce9344..9f90c6931 100644 --- a/Panel/bot/discord/events/ready.js +++ b/Panel/bot/discord/events/ready.js @@ -1,7 +1,7 @@ //let client = require("../../../../index.js").client; - +const axios = require('axios'); module.exports = async (client, guild, files) => { - console.log(chalk.magenta('[DISCORD] ') + chalk.green("Bot logged in!")); + console.log(chalk.magenta('[DISCORD] ') + chalk.green(client.user.username + " has logged in!")); //Auto Activities List const activities = [{ @@ -13,12 +13,8 @@ module.exports = async (client, guild, files) => { "type": "LISTENING" }, { - "text": "over Dan coding me :)", + "text": "Stalking Dan coding me :)", "type": "WATCHING" - }, - { - "text": "with bots on DanBot Hosting.", - "type": "PLAYING" } ]; setInterval(() => { @@ -34,4 +30,56 @@ module.exports = async (client, guild, files) => { invites[g.id] = guildInvites; }); }); + + //const ticketCategory = await client.guilds.get("639477525927690240").fetch('654313162086285323') + // console.log(ticketCategory.children.size) + + setInterval(async () => { + let guild1 = await client.guilds.get("639477525927690240").fetchMembers(); + let roleID1 = '748117822370086932'; + let staffCount = guild1.roles.get(roleID1).members.size; + client.channels.get("739821419910791348").edit({ name: `Staff: ${staffCount}`, reason: "Staff count update" }); + + let guild2 = await client.guilds.get("639477525927690240").fetchMembers(); + let roleID2 = '639490038434103306'; + let memberCount = guild2.roles.get(roleID2).members.size; + client.channels.get("739821366991257621").edit({ name: `Members: ${memberCount}`, reason: "Member count update" }); + + let guild3 = await client.guilds.get("639477525927690240").fetchMembers(); + let roleID3 = '704467807122882562'; + let botCount = guild3.roles.get(roleID3).members.size; + client.channels.get("739821468296413254").edit({ name: `Bots: ${botCount}`, reason: "Bot count update" }); + + let guild4 = await client.guilds.get("639477525927690240") + const ticketcount = guild4.channels.filter(x=> x.name.endsWith("-ticket")).size + client.channels.get("739821447924416562").edit({ name: `Tickets: ${ticketcount}`, reaon: "Ticket count update"}) + + axios({ + url: config.Pterodactyl.hosturl + "/api/application/servers", + method: 'GET', + followRedirect: true, + maxRedirects: 5, + headers: { + 'Authorization': 'Bearer ' + config.Pterodactyl.apikey, + 'Content-Type': 'application/json', + 'Accept': 'Application/vnd.pterodactyl.v1+json', + } + }).then(response => { + client.channels.get("757199549977722890").edit({ name: `Servers Hosting: ${response.data.meta.pagination.total}`, reaon: "Server count update"}) + }); + + axios({ + url: config.Pterodactyl.hosturl + "/api/application/users", + method: 'GET', + followRedirect: true, + maxRedirects: 5, + headers: { + 'Authorization': 'Bearer ' + config.Pterodactyl.apikey, + 'Content-Type': 'application/json', + 'Accept': 'Application/vnd.pterodactyl.v1+json', + } + }).then(response => { + client.channels.get("757222585015599214").edit({ name: `Clients Hosting: ${response.data.meta.pagination.total}`, reaon: "Client count update"}) + }); + }, 30000); }; \ No newline at end of file diff --git a/Panel/bot/discord/events/voiceStateUpdate.js b/Panel/bot/discord/events/voiceStateUpdate.js new file mode 100644 index 000000000..9e397f68e --- /dev/null +++ b/Panel/bot/discord/events/voiceStateUpdate.js @@ -0,0 +1,6 @@ +module.exports = async (oldMember, newMember) => { + let newUserVC1 = newMember.voiceChannel + let oldUserVC1 = oldMember.voiceChannel + //console.log(newUserVC1) + +}; \ No newline at end of file diff --git a/Panel/bot/discord/music/functions.js b/Panel/bot/discord/music/functions.js index f9b0cace0..0ab4ef8ea 100644 --- a/Panel/bot/discord/music/functions.js +++ b/Panel/bot/discord/music/functions.js @@ -1,71 +1,71 @@ -const fs = require('fs'); -module.exports = (client, utils, ytdl, message) => { - const prefix = config.DiscordBot.Prefix; - - client.handleVideo = async (video, message, vc, playlist = false) => { - let queue = client.queue.get(message.guild.id); - let music = { - id: video.id, - title: video.title, - url: `https://www.youtube.com/watch?v=${video.id}` - }; - - if (!queue) { - let queueConstruct = { - textChannel: message.channel, - voiceChannel: vc, - connection: null, - musics: [], - volume: 100, - playing: true - }; - let voteConstruct = { - votes: 0, - voters: [] - }; - - client.queue.set(message.guild.id, queueConstruct); - client.votes.set(message.guild.id, voteConstruct) - queueConstruct.musics.push(music); - - try { - var connection = await vc.join(); - queueConstruct.connection = connection; - client.play(message.guild, queueConstruct.musics[0]); - } catch (err) { - client.queue.delete(message.guild.id); - console.error(`I could not join your voice channel: ${err}`); - } - } else { - queue.musics.push(music); - if (playlist) return; - else return message.channel.send(`**${music.title}** has been added to queue`); - } - return; - } - - client.play = (guild, music) => { - let queue = client.queue.get(guild.id); - let votes = client.votes.get(guild.id) - if (!music) { - queue.voiceChannel.leave(); - client.queue.delete(guild.id); - client.votes.delete(guild.id); - return queue.textChannel.send(`Music playback has ended`); - } - - let dispatcher = queue.connection.playStream(ytdl(music.url)) - .on('end', () => { - queue.musics.shift(); - votes.votes = 0; - votes.voters = []; - setTimeout(() => { - client.play(guild, queue.musics[0]); - }, 250); - }) - .on('error', err => console.error(err)); - dispatcher.setVolumeLogarithmic(queue.volume / 100); - - queue.textChannel.send(`**${music.title}** is now being played`); - } +const fs = require('fs'); +module.exports = (client, utils, ytdl, message) => { + const prefix = config.DiscordBot.Prefix; + + client.handleVideo = async (video, message, vc, playlist = false) => { + let queue = client.queue.get(message.guild.id); + let music = { + id: video.id, + title: video.title, + url: `https://www.youtube.com/watch?v=${video.id}` + }; + + if (!queue) { + let queueConstruct = { + textChannel: message.channel, + voiceChannel: vc, + connection: null, + musics: [], + volume: 100, + playing: true + }; + let voteConstruct = { + votes: 0, + voters: [] + }; + + client.queue.set(message.guild.id, queueConstruct); + client.votes.set(message.guild.id, voteConstruct) + queueConstruct.musics.push(music); + + try { + var connection = await vc.join(); + queueConstruct.connection = connection; + client.play(message.guild, queueConstruct.musics[0]); + } catch (err) { + client.queue.delete(message.guild.id); + console.error(`I could not join your voice channel: ${err}`); + } + } else { + queue.musics.push(music); + if (playlist) return; + else return message.channel.send(`**${music.title}** has been added to queue`); + } + return; + } + + client.play = (guild, music) => { + let queue = client.queue.get(guild.id); + let votes = client.votes.get(guild.id) + if (!music) { + queue.voiceChannel.leave(); + client.queue.delete(guild.id); + client.votes.delete(guild.id); + return queue.textChannel.send(`Music playback has ended`); + } + + let dispatcher = queue.connection.playStream(ytdl(music.url)) + .on('end', () => { + queue.musics.shift(); + votes.votes = 0; + votes.voters = []; + setTimeout(() => { + client.play(guild, queue.musics[0]); + }, 250); + }) + .on('error', err => console.error(err)); + dispatcher.setVolumeLogarithmic(queue.volume / 100); + + queue.textChannel.send(`**${music.title}** is now being played`); + } } \ No newline at end of file diff --git a/Panel/bot/discord/music/utils.js b/Panel/bot/discord/music/utils.js index 65f708c21..849c35d12 100644 --- a/Panel/bot/discord/music/utils.js +++ b/Panel/bot/discord/music/utils.js @@ -1,41 +1,41 @@ -let disc; -let b; -let conf; -let msg; -let a; -let g; - -module.exports = { - - load: (discord, client, config, message, args, guild) => { - disc = discord; - b = client; - conf = config; - msg = message; - a = args; - g = guild; - }, - - timed_msg: (string, time) => { - return message.channel.send(string).then(msg => msg.delete(time)); - }, - - no_perm: (error) => { - let embed = new Discord.RichEmbed() - .setColor('#B6C2F5') - .setAuthor('ERROR: Insufficient Permissions!') - .setDescription(error) - .setFooter('Insufficient Permissions!'); - - return embed; - }, - - cmd_fail: (error, syntax) => { - let embed = new Discord.RichEmbed() - .setColor("#B6C2F5") - .setAuthor('ERROR: WRONG SYNTAX') - .setDescription(error) - .setFooter(syntax); - return embed; - } +let disc; +let b; +let conf; +let msg; +let a; +let g; + +module.exports = { + + load: (discord, client, config, message, args, guild) => { + disc = discord; + b = client; + conf = config; + msg = message; + a = args; + g = guild; + }, + + timed_msg: (string, time) => { + return message.channel.send(string).then(msg => msg.delete(time)); + }, + + no_perm: (error) => { + let embed = new Discord.RichEmbed() + .setColor('#B6C2F5') + .setAuthor('ERROR: Insufficient Permissions!') + .setDescription(error) + .setFooter('Insufficient Permissions!'); + + return embed; + }, + + cmd_fail: (error, syntax) => { + let embed = new Discord.RichEmbed() + .setColor("#B6C2F5") + .setAuthor('ERROR: WRONG SYNTAX') + .setDescription(error) + .setFooter(syntax); + return embed; + } } \ No newline at end of file diff --git a/Panel/bot/discord/tickets/ticketModule.js b/Panel/bot/discord/tickets/ticketModule.js index 11451b0d9..a1491d353 100644 --- a/Panel/bot/discord/tickets/ticketModule.js +++ b/Panel/bot/discord/tickets/ticketModule.js @@ -1,3 +1,3 @@ -const Discord = require('discord.js'); -const fs = require('fs'); - +const Discord = require('discord.js'); +const fs = require('fs'); + diff --git a/Panel/index.js b/Panel/index.js index 37f93ed5f..18f80d471 100644 --- a/Panel/index.js +++ b/Panel/index.js @@ -1,226 +1,377 @@ -/* _____ __ __ _ _ - / ____| | \/ | (_)| | - | (___ ___ _ __ __ __ ___ _ __ | \ / | ___ _ __ _ | |_ ___ _ __ - \___ \ / _ \| '__|\ \ / // _ \| '__|| |\/| | / _ \ | '_ \ | || __|/ _ \ | '__| - ____) || __/| | \ V /| __/| | | | | || (_) || | | || || |_| (_) || | - |_____/ \___||_| \_/ \___||_| |_| |_| \___/ |_| |_||_| \__|\___/ |_| - Free Monitoring software made by danielpmc -*/ - -global.config = require("./config.json"); -var PORT = config.Port; -var express = require('express'); -var app = express(); -var server = require('http').createServer(app); -var bodyParser = require('body-parser'); -global.fs = require("fs"); -const hbs = require('hbs'); -global.chalk = require('chalk'); -const nodemailer = require('nodemailer'); -let transport = nodemailer.createTransport({ - host: config.Email.Host, - port: config.Email.Port, - auth: { - user: config.Email.User, - pass: config.Email.Password - } -}); - - -//Discord Bot -//const events = require("events"); -var node = require('nodeactyl'); -let db = require("quick.db"); -global.DanBotHosting = node.Application; -global.DanBotHostingClient = node.Client; -global.Discord = require("discord.js"); -global.fs = require("fs"); -global.moment = require("moment"); -global.userData = new db.table("userData") -global.client = new Discord.Client(); -//const DBH = new events(); -const bot = client; - -//exports.bot = client; -//exports.DBH = DBH; - -//Event handler -fs.readdir('./bot/discord/events/', (err, files) => { - files = files.filter(f => f.endsWith('.js')); - files.forEach(f => { - const event = require(`./bot/discord/events/${f}`); - client.on(f.split('.')[0], event.bind(null, client)); - delete require.cache[require.resolve(`./bot/discord/events/${f}`)]; - }); - }); - - - //Event Handler - -/*fs.readdir("./bot/discord/events/", (err, files) => { - if (err) return console.log(err); - files.forEach(file => { - fs.readdir("./bot/discord/events/" + file, (err, ff) => { - if (!ff || ff.length == 0) return console.log(`No Events Found in ${file}`); - ff.filter(x => x.toLowerCase().endsWith(".js")).forEach(x => { - - require(`./bot/discord/events/${file}/${x}`); - }); - console.log(`${file} - ${ff.filter(x => toLowerCase().endsWith(".js")).join(", ")}`); - }); - }); -});*/ - -//Disconnected from discord. Probs time to restart while disconnected. -//client.on('reconnecting', () => console.log('Disconnected from discord. Restarting...'), process.exit()); - -//Logging into pterodactyl using Nodeactyl -DanBotHosting.login(config.Pterodactyl.hosturl, config.Pterodactyl.apikey, (logged_in) => { - console.log(chalk.magenta('[APP] ') + chalk.green("Nodeactyl logged in? " + logged_in)); -}); -DanBotHostingClient.login(config.Pterodactyl.hosturl, config.Pterodactyl.apikeyclient, (logged_in) => { - console.log(chalk.magenta('[CLIENT] ') + chalk.green("Nodeactyl logged in? " + logged_in)); -}); - -//Bot login -client.login(config.DiscordBot.Token); - -//Test Email -//const message = { -// from: config.Email.From, -// to: 'danielpd93@gmail.com', -// subject: 'DanBot Hosting Webpage and Discord Bot now online!', -// html: "DanBot Hosting Stats page is now online!" -//}; -//transport.sendMail(message, function(err, info) { -// if (err) { -// console.log(err) -// } else { -// console.log(info); -// } -//}); - - -app.use(bodyParser.json()); -app.use(bodyParser.urlencoded({extended: true})); - -server.listen(PORT, function () { - console.log(chalk.magenta('[WEB] ') + chalk.green("Listening on port " + PORT)); -}); - -app.get('/data', function (req, res) { - if (req.query.servername == undefined) { - var data = JSON.stringify(req.query); - fs.writeFileSync('data/' + req.query.speedname + '-speedtest.json', data); - } else { - var data = JSON.stringify(req.query); - fs.writeFileSync('data/' + req.query.servername + '.json', data); - } -}); - -//View engine setup -hbs.registerPartials(__dirname + '/views/partials') -app.set('view engine', 'hbs'); - -//Routes -app.get("/", (req, res) => { - - //Data for node 1 - var N1 = fs.readFileSync('./data/0286b2ad-dc80-4b5c-a0de-b81945b010e8.json', 'utf8'); - var Node1 = JSON.parse(N1); - var N1speed = fs.readFileSync('./data/0286b2ad-dc80-4b5c-a0de-b81945b010e8-speedtest.json', 'utf8'); - var Node1speed = JSON.parse(N1speed); - - //Data for node 2 - var N2 = fs.readFileSync('./data/2e3f071a-af2b-4dc9-be5a-7ce72590a181.json', 'utf8'); - var Node2 = JSON.parse(N2); - var N2speed = fs.readFileSync('./data/2e3f071a-af2b-4dc9-be5a-7ce72590a181-speedtest.json', 'utf8'); - var Node2speed = JSON.parse(N2speed); - - //Data for node 3 - var N3 = fs.readFileSync('./data/e5406f6d-a9a6-44fa-9dde-429ffc1bf1d7.json', 'utf8'); - var Node3 = JSON.parse(N3); - var N3speed = fs.readFileSync('./data/e5406f6d-a9a6-44fa-9dde-429ffc1bf1d7-speedtest.json', 'utf8'); - var Node3speed = JSON.parse(N3speed); - - //Data for node 4 (Private) - var N4 = fs.readFileSync('./data/Server-01.json', 'utf8'); - var Node4 = JSON.parse(N4); - var N4speed = fs.readFileSync('./data/Server-01-speedtest.json', 'utf8'); - var Node4speed = JSON.parse(N4speed); - - res.render('index', { layout: false, - Node1Data: Node1, - Node2Data: Node2, - Node3Data: Node3, - Node4Data: Node4, - Node1DataSpeed: Node1speed, - Node2DataSpeed: Node2speed, - Node3DataSpeed: Node3speed, - Node4DataSpeed: Node4speed -}); -}); - -app.get("/Node1", (req, res) => { - - //Data for node 1 - var N1 = fs.readFileSync('./data/0286b2ad-dc80-4b5c-a0de-b81945b010e8.json', 'utf8'); - var Node1 = JSON.parse(N1); - var N1speed = fs.readFileSync('./data/0286b2ad-dc80-4b5c-a0de-b81945b010e8-speedtest.json', 'utf8'); - var Node1speed = JSON.parse(N1speed); - - res.render('node1', { layout: false, - Node1Data: Node1, - Node1DataSpeed: Node1speed -}); -}); - -app.get("/Node2", (req, res) => { - - //Data for node 2 - var N2 = fs.readFileSync('./data/2e3f071a-af2b-4dc9-be5a-7ce72590a181.json', 'utf8'); - var Node2 = JSON.parse(N2); - var N2speed = fs.readFileSync('./data/2e3f071a-af2b-4dc9-be5a-7ce72590a181-speedtest.json', 'utf8'); - var Node2speed = JSON.parse(N2speed); - - res.render('node2', { layout: false, - Node2Data: Node2, - Node2DataSpeed: Node2speed -}); -}); - -app.get("/Node3", (req, res) => { - - //Data for node 3 - var N3 = fs.readFileSync('./data/e5406f6d-a9a6-44fa-9dde-429ffc1bf1d7.json', 'utf8'); - var Node3 = JSON.parse(N3); - var N3speed = fs.readFileSync('./data/e5406f6d-a9a6-44fa-9dde-429ffc1bf1d7-speedtest.json', 'utf8'); - var Node3speed = JSON.parse(N3speed); - - res.render('node3', { layout: false, - Node3Data: Node3, - Node3DataSpeed: Node3speed -}); -}); - -app.get("/Node4", (req, res) => { - - //Data for node 4 - var N4 = fs.readFileSync('./data/Server-01.json', 'utf8'); - var Node4 = JSON.parse(N4); - var N4speed = fs.readFileSync('./data/Server-01-speedtest.json', 'utf8'); - var Node4speed = JSON.parse(N4speed); - - res.render('node4', { layout: false, - Node4Data: Node4, - Node4DataSpeed: Node4speed -}); -}); - - -//Catch 404 and forward to error handler -app.use(function(req, res, next) { - var err = new Error('Not Found'); - err.status = 404; - next(err); -}); \ No newline at end of file +/* _____ __ __ _ _ + / ____| | \/ | (_)| | + | (___ ___ _ __ __ __ ___ _ __ | \ / | ___ _ __ _ | |_ ___ _ __ + \___ \ / _ \| '__|\ \ / // _ \| '__|| |\/| | / _ \ | '_ \ | || __|/ _ \ | '__| + ____) || __/| | \ V /| __/| | | | | || (_) || | | || || |_| (_) || | + |_____/ \___||_| \_/ \___||_| |_| |_| \___/ |_| |_||_| \__|\___/ |_| + Free Monitoring software made by danielpmc +*/ + +global.config = require("./config.json"); +var PORT = config.Port; +var express = require('express'); +var app = express(); +var server = require('http').createServer(app); +var bodyParser = require('body-parser'); +global.fs = require("fs"); +const hbs = require('hbs'); +global.chalk = require('chalk'); +const nodemailer = require('nodemailer'); +let transport = nodemailer.createTransport({ + host: config.Email.Host, + port: config.Email.Port, + auth: { + user: config.Email.User, + pass: config.Email.Password + } +}); + +const isSnowflake = require(process.cwd() + "/util/isSnowflake.js"); +const { getUser, getBot } = require(process.cwd() + "/util/discordAPI"); + + +//Discord Bot +//const events = require("events"); +var node = require('nodeactyl'); +let db = require("quick.db"); +global.DanBotHosting = node.Application; +global.DanBotHostingClient = node.Client; +global.Discord = require("discord.js"); +global.fs = require("fs"); +global.moment = require("moment"); +global.userData = new db.table("userData") +global.client = new Discord.Client({disableEveryone: true}); +//const DBH = new events(); +const bot = client; +global.suggestionLog = new Discord.WebhookClient(config.DiscordSuggestions.channelID, config.DiscordSuggestions.channelID) + +//exports.bot = client; +//exports.DBH = DBH; + +//Event handler +fs.readdir('./bot/discord/events/', (err, files) => { + files = files.filter(f => f.endsWith('.js')); + files.forEach(f => { + const event = require(`./bot/discord/events/${f}`); + client.on(f.split('.')[0], event.bind(null, client)); + delete require.cache[require.resolve(`./bot/discord/events/${f}`)]; + }); + }); + + + + //Event Handler + +/*fs.readdir("./bot/discord/events/", (err, files) => { + if (err) return console.log(err); + files.forEach(file => { + fs.readdir("./bot/discord/events/" + file, (err, ff) => { + if (!ff || ff.length == 0) return console.log(`No Events Found in ${file}`); + ff.filter(x => x.toLowerCase().endsWith(".js")).forEach(x => { + + require(`./bot/discord/events/${file}/${x}`); + }); + console.log(`${file} - ${ff.filter(x => toLowerCase().endsWith(".js")).join(", ")}`); + }); + }); +});*/ + +//Disconnected from discord. Probs time to restart while disconnected. +//client.on('reconnecting', () => console.log('Disconnected from discord. Restarting...'), process.exit()); + +//Logging into pterodactyl using Nodeactyl +DanBotHosting.login(config.Pterodactyl.hosturl, config.Pterodactyl.apikey, (logged_in) => { + console.log(chalk.magenta('[APP] ') + chalk.green("Nodeactyl logged in? " + logged_in)); +}); +DanBotHostingClient.login(config.Pterodactyl.hosturl, config.Pterodactyl.apikeyclient, (logged_in) => { + console.log(chalk.magenta('[CLIENT] ') + chalk.green("Nodeactyl logged in? " + logged_in)); +}); + +//Logging into proxmox (Virtual Machine manager) +//global.proxmox = require("proxmox")(config.Proxmox.username, config.Proxmox.password, config.Proxmox.url); + +//global.proxmox = require('node-proxmox')(config.Proxmox.url, config.Proxmox.username, config.Proxmox.auth, config.Proxmox.password); +//proxmox.get('/nodes/', (data) => { +// console.log(data) +//}) + +//Bot login +client.login(config.DiscordBot.Token); +global.Allowed = [ "338192747754160138", "137624084572798976" ]; + +//Test Email +//const message = { +// from: config.Email.From, +// to: 'danielpd93@gmail.com', +// subject: 'DanBot Hosting Webpage and Discord Bot now online!', +// html: "DanBot Hosting Stats page is now online!" +//}; +//transport.sendMail(message, function(err, info) { +// if (err) { +// console.log(err) +// } else { +// console.log(info); +// } +//}); + +// website things + +const passport = require("passport"); +const session = require("express-session"); +const strategy = require("passport-discord").Strategy; +const MongoStore = require("connect-mongo")(session); +const cookieParser = require("cookie-parser"); +const csrf = require("csurf"); +const helmet = require("helmet"); + +passport.serializeUser((user, done) => { + done(null, user); +}); +passport.deserializeUser((obj, done) => { + done(null, obj); +}); + +passport.use( + new strategy( + { + clientID: config.DiscordBot.clientID, + clientSecret: config.DiscordBot.clientSecret, + callbackURL: config.DiscordBot.callbackURL, + scope: ["identify"] + }, + (accessToken, refreshToken, profile, done) => { + process.nextTick(() => { + return done(null, profile); + }); + } + ) +); + +app.use( + session({ + store: new MongoStore({ + url: + config.DB.MongoDB + }), + secret: "FROPT", + resave: false, + saveUninitialized: false + }) +); + +app.use(passport.initialize()); +app.use(passport.session()); +app.use(helmet({ frameguard: false })); +app.use(cookieParser()); + +app.use(bodyParser.json()); +app.use(bodyParser.urlencoded({extended: true})); + +server.listen(PORT, function () { + console.log(chalk.magenta('[WEB] ') + chalk.green("Listening on port " + PORT)); +}); + +global.nodeData = new db.table("nodeData") +app.get('/data', function (req, res) { + if (req.query.servername == undefined) { + var data = JSON.stringify(req.query); + fs.writeFileSync('data/' + req.query.speedname + '-speedtest.json', data); + } else { + var data = JSON.stringify(req.query); + //fs.writeFileSync('data/' + req.query.servername + '.json', data); + console.log(data) + nodeData.set(req.query.servername, { + servername: req.query.servername, + cpu: data.cpu, + cpuload: data.cpuload, + cputhreads: data.cputhreads, + cpucores: data.cpucores, + memused: data.memused, + memtotal: data.memtotal, + swapused: data.swapused, + swaptotal: data.swaptotal, + diskused: data.diskused, + disktotal: data.disktotal, + netrx: data.netrx, + nettx: data.nettx, + osplatform: data.osplatform, + oslogofile: data.oslogofile, + osrelease: data.osrelease, + osuptime: data.osuptime, + biosvendor: data.biosvendor, + biosversion: data.biosversion, + biosdate: data.biosdate, + servermonitorversion: data.servermonitorversion, + datatime: data.datatime, + dockercontainers: data.dockercontainers, + dockercontainersrunning: data.dockercontainersrunning, + dockercontainerspaused: data.dockercontainerspaused, + dockercontainersstopped: data.dockercontainersstopped, + updatetime: data.updatetime + }); + } +}); +/* +userData.set(`${message.author.id}`, { + discordID: message.author.id, + consoleID: user.id, + email: user.email, + username: user.username, + linkTime: timestamp, + linkDate: datestamp + }) +*/ + + +//View engine setup +hbs.registerPartials(__dirname + '/views/partials') +app.set('view engine', 'hbs'); + +app.use((req, res, next) => { + res.set("Access-Control-Allow-Origin", "*"); + res.set("Access-Control-Allow-Methods", "GET, POST"); + + console.log( + (req.headers["cf-connecting-ip"] || + req.headers["x-forwarded-for"] || + req.ip) + + " [" + + req.method + + "] " + + req.url + ); + + next(); + }); + +//Routes + + +// DanBot Hosting Stats + +const apiRoute = require("./routes/api.js"); +const botRoute = require("./routes/bot.js"); +const indexRoute = require("./routes/index.js"); +const statsRoute = require("./routes/stats.js"); +const meRoute = require("./routes/me.js"); +//const { config } = require("process"); + +app.use("/api", apiRoute); +app.use("/bot", botRoute); +app.use("/", indexRoute); +app.use("/stats", statsRoute); +app.use("/me", meRoute); + +app.get("/user/:ID", async (req, res) => { + let user = req.params.ID; + let memberr = "No" + + if (!isSnowflake(user)) { + return res.render("error.ejs", { + user: req.isAuthenticated() ? req.user : null, + message: "Make sure ID is a valid ID" + }); + } + + let [use] = await getBot(user) + + if (use.user_id && use.user_id[0].endsWith("is not snowflake.")) + return res.render("error.ejs", { + user: req.isAuthenticated() ? req.user : null, + message: "ID is invalid" + }); + + if (use.message == "Unknown User") + return res.render("error.ejs", { + user: req.isAuthenticated() ? req.user : null, + message: "Discord API - Unknown User" + }); + + if (use.bot === true) return res.redirect("/bot/" + user); + + try { + bot.fetchUser(user).then(User => { + if (User.bot) { + return res.redirect("/bot/" + User.id); + } + + var member = bot.guilds + .get("639477525927690240") + .members.get(User.id); + if (!member) { + (pColor = "grey"), (presence = "offline"); + } + let guild = bot.guilds.get("639477525927690240"); + if (guild.member(User.id)) { + memberr = "yes"; + } + if (member) { + presence = member.presence.status; + + if (presence) { + if (presence === "offline") { + presence = "Offline"; + pColor = "grey"; + } else if (presence === "online") { + presence = "Online"; + pColor = "#43B581"; + } else if (presence === "dnd") { + presence = "DND"; + pColor = "#F04747"; + } else if (presence === "streaming") { + presence = "Streaming"; + pColor = "purple"; + } else if (presence === "idle") { + presence = "Idle"; + pColor = "#FAA61A"; + } else { + (pColor = "grey"), (presence = "Not Available"); + } + } + } + + let avatar = `https://mythicalbots.xyz/bot/${user}/avatar`; + + let bots = db.get(`${User.id}.bots`); + if(!bots) bots = null; + + console.log(bots) + + res.render("me/user.ejs", { + user: req.isAuthenticated() ? req.user : null, + User, + avatar, + // Data, + pColor, + presence, + // info, + memberr, + use, + bots, + db, + // Discord, + // pageType: { user: true } + }); + }); + } catch (e) { + return res.render("error.ejs", { + user: req.isAuthenticated() ? req.user : null, + message: e + }); + } + +}); + + +//Catch 404 and forward to error handler +app.use(function(req, res, next) { + res.status(404).render("error.ejs", { + message: "Page Not Found", + user: req.isAuthenticated() ? req.user : null + }); +}); + +setInterval(async() => { + console.log("[Automatic Process] Getting bot stats from MBL") + require("./util/MBL.js") +}, 600000); \ No newline at end of file diff --git a/Panel/package.json b/Panel/package.json index a0655a98e..a71dccadb 100644 --- a/Panel/package.json +++ b/Panel/package.json @@ -19,23 +19,38 @@ "dependencies": { "body-parser": "latest", "chalk": "^3.0.0", - "discord.js": "^11.6.3", - "ejs": "^3.0.1", + "connect-mongo": "^3.2.0", + "cookie-parser": "^1.4.5", + "csurf": "^1.11.0", + "discord.js": "^11.6.4", + "ejs": "^3.1.3", "events": "^3.1.0", "express": "latest", "express-handlebars": "^3.1.0", + "express-rate-limit": "^5.1.3", + "express-session": "^1.17.1", "git-repo-info": "^2.1.1", - "hbs": "^4.1.0", - "helmet": "^3.21.2", + "hbs": "^4.1.1", + "helmet": "^3.23.3", "http": "latest", - "moment": "^2.24.0", - "nodeactyl": "github:Burchard36/Nodeactyl", + "moment": "^2.27.0", + "node-cron": "^2.0.3", + "node-fetch": "^2.6.0", + "node-proxmox": "^0.1.2", + "node-tesseract-ocr": "^2.0.0", + "nodeactyl": "^2.0.0", "nodeactyl-beta": "0.0.10", - "nodemailer": "^6.4.6", - "puppeteer": "^1.19.0", + "nodemailer": "^6.4.11", + "passport": "^0.4.1", + "passport-discord": "^0.1.4", + "proxmox": "^0.1.0", + "pterodactyl.js": "^2.1.1", + "puppeteer": "^1.20.0", "quick.db": "^7.1.1", "resolve": "^1.17.0", "socket.io": "latest", - "validator": "^13.0.0" + "tesseract.js": "^2.1.1", + "unirest": "^0.6.0", + "validator": "^13.1.1" } } diff --git a/Panel/routes/admin.js b/Panel/routes/admin.js new file mode 100644 index 000000000..f78bdd3db --- /dev/null +++ b/Panel/routes/admin.js @@ -0,0 +1,3 @@ +const Router = require("express").Router(); +const db = require("quick.db"); +const isSnowflake = require(process.cwd() + "/util/isSnowflake.js"); \ No newline at end of file diff --git a/Panel/routes/api.js b/Panel/routes/api.js new file mode 100644 index 000000000..4cf0425c7 --- /dev/null +++ b/Panel/routes/api.js @@ -0,0 +1,183 @@ +// api stuff for bots to submit their stats + +const Router = require("express").Router(); +const db = require("quick.db"); +const isSnowflake = require(process.cwd() + "/util/isSnowflake.js"); +const passport = require("passport"); +let Developers = [ "137624084572798976", "338192747754160138" ]; +const rateLimitt = require('express-rate-limit'); + +Router.post("/bot/:ID/stats", /* rateLimit(10000, 2) , */ (req, res) => { // temp remove if ratelimit + let ID = req.params.ID; + if (!ID) + return res + .status(400) + .send({ error: true, message: "Please give a bot ID" }); + + if (!isSnowflake(ID)) { + return res + .status(400) + .send({ error: true, message: "'bot_id' must be a snowflake" }); + } + + let data = req.body; + let keys = db.get("apiKeys"); + + if (keys.includes(data.key)) { + let owner = db.get(`${data.key}`); + // console.log(data); + let info = db.get(data.id); + + console.log(`API: ${data.id} just submitted stats`) + + if (info) { + let botData = { + id: data.id, + keyLastUsed: data.key, + servers: data.servers, + users: data.users, + owner: owner, + client: data.clientInfo, + deleted: info.deleted, + added: info.added, + status: info.status || "N/A", + mbl: info.mbl || [], + lastPost: Date.now() + }; + + db.set(ID, botData); + } else { + let botData = { + id: data.id, + keyLastUsed: data.key, + servers: data.servers, + users: data.users, + owner: owner, + client: data.clientInfo, + deleted: false, + added: Date.now(), + status: "N/A", + mbl: [], + lastPost: Date.now() + }; + + db.set(ID, botData); + } + + + /* db.fetch(`botIDs`) + db.push("botIDs", `${ID}`); + */ + + let ids = db.get("bot.IDs"); + if(!ids.includes(ID)) { + db.push("bot.IDs", `${ID}`); + } + + let bots = db.get(`${owner}.bots`); + + if(bots) { + + if(!bots.includes(ID)) { + db.push(`${owner}.bots`, `${ID}`); + } + + } else { + db.push(`${owner}.bots`, `${ID}`); + } + + return res + .status(200) + .send({ error: false, message: "Bot stats have been recorded" }); + } else { + return res + .status(400) + .send({ error: true, message: "The API Key you gave is invalid" }); + } +}); + +Router.get("/bot/:ID/info", rateLimit(15000, 4), (req, res) => { + let ID = req.params.ID; + if (!ID) + return res + .status(400) + .send({ error: true, message: "Please give a bot ID" }); + + if (!isSnowflake(ID)) { + return res + .status(400) + .send({ error: true, message: "'bot_id' must be a snowflake" }); + } + + let bot = db.get(`${ID}`); + if (!bot) + return res.status(400).send({ error: true, message: "bot not found" }); + + let data = { + id: bot.id, + servers: bot.servers, + users: bot.users, + owner: bot.owner, + client: bot.client, + deleted: bot.deleted, + added: bot.added + }; + + res.json(data); +}); + +Router.get("/bots", rateLimit(15000, 4), (req, res) => { + + let bots = db.get("bot.IDs"); + + res.json(bots); +}); + +Router.get( + "/callback", + passport.authenticate("discord", { failureRedirect: "/404" }), + (req, res) => { + console.log(`Testing: ` + req.query.state); + // addUser(req.user); + if (Developers.includes(req.user.id)) { + req.session.isAdmin = true; + } else { + req.session.isAdmin = false; + } + res.redirect("/me"); + + //maybe future features. + + } +); + +Router.use("*", (req, res) => { + res + .status(404) + .json({ error: true, status: 404, message: "Endpoint not found" }); +}); + +Router.use("*", (err, req, res) => { + res + .status(404) + .json({ error: true, status: 404, message: "Endpoint not found" }); +}); + +module.exports = Router; + +function rateLimit(windowMs, max, req, res, next) { + return rateLimitt({ + windowMs, + max, + // keyGenerator: req.header("x-forwarded-for") || req.connection.remoteAddress, + handler: function(req, res) { + return res + .status(429) + .json({ + error: true, + code: 429, + message: "DanBot Hosting Stats API - You are sending too many requests, please slow down" + }); + } + }); +} \ No newline at end of file diff --git a/Panel/routes/bot.js b/Panel/routes/bot.js new file mode 100644 index 000000000..89e6b11da --- /dev/null +++ b/Panel/routes/bot.js @@ -0,0 +1,68 @@ +// route for users to get bot information + +const Router = require("express").Router(); +const db = require("quick.db"); +const isSnowflake = require(process.cwd() + "/util/isSnowflake.js"); + +Router.get("/:ID/", (req, res) => { + let ID = req.params.ID; + if (!ID) return res.status(400).send({ error: true, message: "Please give a bot ID" }); + + if (!isSnowflake(ID)) { + return res.status(400).send({ error: true, message: "'bot_id' must be a snowflake" }); + } + + let bot = db.get(`${ID}`); + if(!bot)return res.render("error.ejs", { message: "Bot Not Found" }); + + res.render("bot/index.ejs", { bot, user: req.isAuthenticated() ? req.user : null }); + +}); + +Router.get("/:ID/remove", checkAuth, (req, res) => { + + let ID = req.params.ID; + if (!ID) return res.status(400).send({ error: true, message: "Please give a bot ID" }); + + if (!isSnowflake(ID)) { + return res.status(400).send({ error: true, message: "'bot_id' must be a snowflake" }); + } + + let bot = db.get(`${ID}`); + if(!bot)return res.render("error.ejs", { message: "Bot Not Found" }); + + let allowed = ["338192747754160138","137624084572798976"]; + allowed.push(bot.owner); + + if(allowed.includes(req.user.id)) { + + let bots = db.get("bot.IDs"); + var filtered = bots.filter(function(el) { return el != `${ID}`; }); + + let ownerbots = db.get(`${bot.owner}.bots`); + let own = ownerbots.filter(function (be) { return be != `${ID}` }); + + db.delete(`${ID}`); // remove bot from db + db.set("bot.IDs", filtered); // remove bot from the array + db.set(`${bot.owner}.bots`, own); + + res.redirect("/me?s=removed_" + ID + "_from_stats"); + + } else { + return res.render("error.ejs", { message: "You're not authorized to make changes to this bot." }); + } +}); + +module.exports = Router; + + /* Authorization check, if not authorized return them to the login page. + */ +function checkAuth(req, res, next) { + if (req.isAuthenticated()) { + return next(); + } else { + req.session.backURL = req.url; + + res.redirect("/login?redirect=" + req.url); + } +} \ No newline at end of file diff --git a/Panel/routes/index.js b/Panel/routes/index.js new file mode 100644 index 000000000..000212c46 --- /dev/null +++ b/Panel/routes/index.js @@ -0,0 +1,153 @@ +const Router = require("express").Router(); +const db = require("quick.db"); +const isSnowflake = require(process.cwd() + "/util/isSnowflake.js"); + +Router.get("/", (req, res) => { + + let Query = req.query.q; + let from = req.query.utm_source; + let Message = null; + let MessageDefined = null; + + res.render('main.ejs', { + user: req.isAuthenticated() ? req.user : null +}); +}); + +Router.get("/Node1", (req, res) => { + res.redirect("/stats/Node1"); +}); + +Router.get("/Node2", (req, res) => { + res.redirect("/stats/Node2"); +}); + +Router.get("/Node3", (req, res) => { + res.redirect("/stats/Node3"); +}); + + + +Router.get("/bots", (req, res) => { + let q = req.query.q; + + let ar = []; + let lar = []; + + let bots = db.get("bot.IDs"); + for(var i=0; i < bots.length; i++) { + ar.push(db.get(bots[i])); + lar.push(db.get(bots[i])); + } + ar.sort((a, b) => a.client.username.localeCompare(b.client.username)); + // console.log(ar); + + lar.sort(function(a, b) { + return b.servers - a.servers; + }); + + res.render('bots.ejs', { + bots: db.get("bot.IDs"), + db, + user: req.isAuthenticated() ? req.user : null, + q, + ar, + lar + }); +}); + +Router.get("/login", (req, res) => { + let redirect = req.query.redirect; + if (!redirect) redirect = "/me"; + //console.log(redirect) + res.redirect( + "https://discordapp.com/api/oauth2/authorize?client_id=640161047671603205&redirect_uri=https%3A%2F%2Fdanbot.host%2Fapi%2Fcallback&response_type=code&scope=identify&prompt=none&state=" + + redirect + ); +}); + +Router.get("/logout", function(req, res) { + req.session.destroy(() => { + req.logout(); + // req.flash('success_msg', 'You are logged out'); + res.redirect("/"); + }); +}); + +Router.get("/feedback", async (req, res) => { + let Page = "Feedback"; + let ErrorMessage = null; + let Error = req.query.error; + if (Error === "not_msg") ErrorMessage = "no_message"; + res.render("feedback.ejs", { + user: req.isAuthenticated() ? req.user : null, + ErrorMessage, + }); +}); + +Router.post("/feedback/post/suggestion", checkAuth, async (req, res) => { + if (req.body.suggestion) { + + // embed + + let Kiro = req.isAuthenticated() ? req.user : null; + let suggestion = req.body.suggestion; + let SuggestionEmbed = new Discord.RichEmbed() + .setColor("BLUE") + .setTitle("Suggestion Submission") + .setThumbnail(`https://cdn.discordapp.com/avatars/${Kiro.id}/${Kiro.avatar}`) + .addField("User", `<@${Kiro.id}>(${Kiro.id})`) + .addField("Suggestion", `${suggestion}`) + + suggestionLog.send(SuggestionEmbed) + + res.redirect("/?q=SENT_FEEDBACK"); + } else { + res.redirect("/feedback?error=not_msg"); + } +}); + +Router.post("/feedback/post/bug", checkAuth, async (req, res) => { + if (req.body.bug) { + + let Kiro = req.isAuthenticated() ? req.user : null; + let Bug = req.body.bug; + + let BugEmbed = new Discord.RichEmbed() + .setColor("BLUE") + .setTitle("Bug Submission") + .setThumbnail(`https://cdn.discordapp.com/avatars/${Kiro.id}/${Kiro.avatar}`) + .addField("User", `<@${Kiro.id}>(${Kiro.id})`) + .addField("Bug", `${Bug}`); + + suggestionLog.send(BugEmbed) + + res.redirect("/?q=SENT_FEEDBACK"); + } else { + res.redirect("/feedback?error=not_msg"); + } +}); + +Router.get(["/discord","/support"], (req, res) => { + res.redirect("//discord.gg/92HBc2Z") +}); + +Router.get("/partners", async (req, res) => { + res.render("partners.ejs", { + user: req.isAuthenticated() ? req.user : null, + }); +}); + +module.exports = Router; + + /* Authorization check, if not authorized return them to the login page. + */ +function checkAuth(req, res, next) { + if (req.isAuthenticated()) { + return next(); + } else { + req.session.backURL = req.url; + + res.redirect("/login?redirect=" + req.url); + } +} \ No newline at end of file diff --git a/Panel/routes/me.js b/Panel/routes/me.js new file mode 100644 index 000000000..70cd91a17 --- /dev/null +++ b/Panel/routes/me.js @@ -0,0 +1,61 @@ +// route for users to get their own bots + +const Router = require("express").Router(); +const db = require("quick.db"); +const isSnowflake = require(process.cwd() + "/util/isSnowflake.js"); + +Router.get("/", checkAuth, (req, res) => { + let bots = db.get(`${req.user.id}.bots`); + res.render("me/index.ejs", { user: req.isAuthenticated() ? req.user : null, bots, db }); +}); + +Router.get("/form/new-server", checkAuth, (req, res) => { + let bots = db.get(`${req.user.id}.bots`); + res.render("forms/newserver.ejs", { user: req.isAuthenticated() ? req.user : null, bots, db }); +}); + +Router.post("/form/new-server", checkAuth, (req, res) => { + + let data = req.body; + console.log(data); +//{ id: '137624084572798976', name: 'test', type: 'NodeJS', ssubm: '' } + if(data.type == "NodeJS") { + console.log('Lmao nodejs') + } + + res.redirect("/me?e=ERROR"); + +}); + +Router.get("/form/staff-apply", checkAuth, (req, res) => { + let bots = db.get(`${req.user.id}.bots`); + res.render("forms/apply-staff.ejs", { user: req.isAuthenticated() ? req.user : null, bots, db }); +}); + +Router.post("/form/staff-apply", checkAuth, (req, res) => { + + let data = req.body; + console.log(data); +//{ id: '137624084572798976', name: 'test', type: 'NodeJS', ssubm: '' } + if(data.type == "NodeJS") { + console.log('Lmao nodejs') + } + + res.redirect("/me?e=ERROR"); + +}); + +module.exports = Router; + +/* + * Authorization check, if not authorized return them to the login page. + */ +function checkAuth(req, res, next) { + if (req.isAuthenticated()) { + return next(); + } else { + req.session.backURL = req.url; + + res.redirect("/login?redirect=/me"); + } +} \ No newline at end of file diff --git a/Panel/routes/stats.js b/Panel/routes/stats.js new file mode 100644 index 000000000..f70a26b88 --- /dev/null +++ b/Panel/routes/stats.js @@ -0,0 +1,81 @@ +const Router = require("express").Router(); +const db = require("quick.db"); +const isSnowflake = require(process.cwd() + "/util/isSnowflake.js"); + +Router.get("/", (req, res) => { + + //Data for node 1 + var N1 = fs.readFileSync('././data/Node1.json', 'utf8'); + var Node1 = JSON.parse(N1); + var N1speed = fs.readFileSync('././data/Node1-speedtest.json', 'utf8'); + var Node1speed = JSON.parse(N1speed); + + //Data for node 2 + var N2 = fs.readFileSync('././data/Node2.json', 'utf8'); + var Node2 = JSON.parse(N2); + var N2speed = fs.readFileSync('././data/Node2-speedtest.json', 'utf8'); + var Node2speed = JSON.parse(N2speed); + + //Data for node 3 + var N3 = fs.readFileSync('././data/vmi450443.contaboserver.net.json', 'utf8'); + var Node3 = JSON.parse(N3); + var N3speed = fs.readFileSync('././data/vmi450443.contaboserver.net-speedtest.json', 'utf8'); + var Node3speed = JSON.parse(N3speed); + + res.render('index.ejs', { layout: false, + Node1Data: Node1, + Node2Data: Node2, + Node3Data: Node3, + Node1DataSpeed: Node1speed, + Node2DataSpeed: Node2speed, + Node3DataSpeed: Node3speed, + user: req.isAuthenticated() ? req.user : null +}); +}); + +Router.get("/Node1", (req, res) => { + + //Data for node 1 + var N1 = fs.readFileSync('././data/Node1.json', 'utf8'); + var Node1 = JSON.parse(N1); + var N1speed = fs.readFileSync('././data/Node1-speedtest.json', 'utf8'); + var Node1speed = JSON.parse(N1speed); + + res.render('node1.ejs', { layout: false, + Node1Data: Node1, + Node1DataSpeed: Node1speed, + user: req.isAuthenticated() ? req.user : null +}); +}); + +Router.get("/Node2", (req, res) => { + + //Data for node 2 + var N2 = fs.readFileSync('././data/Node2.json', 'utf8'); + var Node2 = JSON.parse(N2); + var N2speed = fs.readFileSync('././data/Node2-speedtest.json', 'utf8'); + var Node2speed = JSON.parse(N2speed); + + res.render('node2.ejs', { layout: false, + Node2Data: Node2, + Node2DataSpeed: Node2speed, + user: req.isAuthenticated() ? req.user : null +}); +}); + +Router.get("/Node3", (req, res) => { + + //Data for node 3 + var N3 = fs.readFileSync('././data/vmi450443.contaboserver.net.json', 'utf8'); + var Node3 = JSON.parse(N3); + var N3speed = fs.readFileSync('././data/vmi450443.contaboserver.net-speedtest.json', 'utf8'); + var Node3speed = JSON.parse(N3speed); + + res.render('node3.ejs', { layout: false, + Node3Data: Node3, + Node3DataSpeed: Node3speed, + user: req.isAuthenticated() ? req.user : null +}); +}); + +module.exports = Router; \ No newline at end of file diff --git a/Panel/util/MBL.js b/Panel/util/MBL.js new file mode 100644 index 000000000..33ac3577a --- /dev/null +++ b/Panel/util/MBL.js @@ -0,0 +1,43 @@ +const db = require("quick.db"); +let ids = db.get("bot.IDs"); +let fetch = require("node-fetch"); + +ids.map(async ID => { + + let res = await fetch(`https://mythicalbots.xyz/api/dan/bot/${ID}/info`); + + let response = await res.json(); + + if(response.error) return; // bot not in mbl + + let info = db.get(ID); + if(!info)return; // bot not found + + let mbl = { + invite: response.invite + } + + console.log(response.invite) + let up = "N/A"; + + if(response.uptime) { + up = response.uptime.status + } + + let botData = { + id: info.id, + keyLastUsed: info.keyLastUsed, + servers: info.servers, + users: info.users, + owner: info.owner, + client: info.client, + deleted: info.deleted, + added: info.added, + status: up, + mbl: mbl, + lastPost: info.lastPost + }; + + db.set(ID, botData); + +}); \ No newline at end of file diff --git a/Panel/util/discordAPI.js b/Panel/util/discordAPI.js new file mode 100644 index 000000000..2bfcee650 --- /dev/null +++ b/Panel/util/discordAPI.js @@ -0,0 +1,47 @@ +const unirest = require("unirest"); +const fetch = require("node-fetch"); +//const btoa = require("btoa"); + +const { CLIENT_ID, CLIENT_SECRET, DOMAIN } = process.env; + +module.exports.getUser = token => { + /* return new Promise(async function(resolve, reject) { + const creds = btoa(`${CLIENT_ID}:${CLIENT_SECRET}`); + const response = await fetch( + `https://discordapp.com/api/oauth2/token?grant_type=refresh_token&refresh_token=${token}&scope=identify&redirect_uri=${encodeURIComponent( + DOMAIN + )}/api/callback`, + { + method: "POST", + headers: { + Authorization: `Basic ${creds}` + } + } + ); + const json = await response.json(); + let data = []; + unirest + .get("https://discordapp.com/api/users/@me") + .headers({ Authorization: `Bearer ${json.access_token}` }) + .end(function(user) { + if (user["raw_body"].error) return resolve(false); + data.push(JSON.parse(user["raw_body"])); + data.push(json.refresh_token); + resolve(data); + }); + }); */ +}; + +module.exports.getBot = id => { + return new Promise(function(resolve, reject) { + let data = []; + unirest + .get(`https://discordapp.com/api/users/${id}`) + .headers({ Authorization: `Bot ${config.DiscordBot.Token}` }) + .end(function(user) { + if (user["raw_body"].error) return resolve(false); + data.push(JSON.parse(user["raw_body"])); + resolve(data); + }); + }); +}; \ No newline at end of file diff --git a/Panel/util/isSnowflake.js b/Panel/util/isSnowflake.js new file mode 100644 index 000000000..4dd4fad7e --- /dev/null +++ b/Panel/util/isSnowflake.js @@ -0,0 +1,4 @@ +module.exports = snowflake => { + return !isNaN(snowflake) && snowflake.length >= 16; +}; +// Added to make life easier \ No newline at end of file diff --git a/Panel/util/pterodactyl.js b/Panel/util/pterodactyl.js new file mode 100644 index 000000000..8964fab4e --- /dev/null +++ b/Panel/util/pterodactyl.js @@ -0,0 +1,51 @@ +const request = ('request'); +module.exports = { + + createServer: function(servername, type, userid, url, apikey) { + + //Post data + request({ + uri: "http://" + config.panelip + ":" + config.panelport + "/data?servername=" + os.hostname + //OS hostname for saving data panel sided. + "&cpu=" + cpumain + //CPU make and brand. + "&cpuload=" + cl.currentload.toFixed(2) + //CPU load but doesn't work on windows :( + "&cputhreads=" + cputhreads + //CPU threads. + "&cpucores=" + cpucores + //CPU cores + "&memused=" + ramused + //Ram used (Auto to MB, GB, TB) + "&memtotal=" + ramtotal + //Ram total (Auto to MB, GB, TB) + "&swapused=" + swapused + //Swap used (Auto to MB, GB, TB) + "&swaptotal=" + swaptotal + //Swap total (Auto to MB, GB, TB) + "&diskused=" + diskused + //Disk used (Auto to MB, GB, TB) + "&disktotal=" + disktotal + //Disk total (Auto to MB, GB, TB) + "&netrx=" + netrx + //Network received (Auto to MB, GB, TB) + "&nettx=" + nettx + //Network transmited (Auto to MB, GB, TB) + "&osplatform=" + osdata.platform + //OS platform (win32 or linux) + "&oslogofile=" + osdata.logofile + //OS logofile (Linux example: Debian/Ubuntu | Windows example: Windows) + "&osrelease=" + osdata.release + //OS release (Linux example: 9 | Windows example: 10.0.18362) + "&osuptime=" + dDisplay + hDisplay + mDisplay + sDisplay + //OS uptime (Day/Days, Hours/Hour, Minutes/Minute, Seconds/Second) + "&biosvendor=" + bios.vendor + //Bios vendor (Example: Dell Inc) + "&biosversion=" + bios.version + //Bios version (Example: A22.00) + "&biosdate=" + bios.releaseDate + //Bios release date (Example: 2018-11-29) + "&servermonitorversion=" + Version + //ServerMonitor version (Example: 1.0.1) + "&datatime=" + datatime + //Date and time (Example: 1578594094569) + "&dockercontainers=" + docker.containers + //Number of docker containers + "&dockercontainersrunning=" + docker.containersRunning + //Number of running docker containers + "&dockercontainerspaused=" + docker.containersPaused + //Number of paused docker containers + "&dockercontainersstopped=" + docker.containersStopped + //Number of stopped docker containers + "&updatetime= " + timestamp, //Last time the node sent data to the panel + method: "GET", + timeout: 5000, + followRedirect: true, + maxRedirects: 10 + }, function (error, response, body) { + + //Send request + res.send(body); + + }); + + return result; + } + +}; + + diff --git a/Panel/views/bot/index.ejs b/Panel/views/bot/index.ejs new file mode 100644 index 000000000..fb65b04e2 --- /dev/null +++ b/Panel/views/bot/index.ejs @@ -0,0 +1,136 @@ +<%- include("../partials/header.ejs", { botInfo: true, Title: `${bot.client.username}`, Avatar: `https://cdn.discordapp.com/avatars/${bot.id}/${bot.client.avatar}`, Redirect: `/bot/${bot.id}`, user }) %> + +



+
+ +
+
Page still being done <3
+
+ +
+

+
+ +
+
+
+
+
+
Bot Name
+
<%= bot.client.username %>
+
+
+ +
+
+
+
+
+ +
+
+
+
+
+
Status
+
<% if(bot.status === "online") { %> Online <% } else if(bot.status === "idle") { %> Idle <% } else { %> <%- bot.status %> <% } %>
+
+
+ +
+
+
+
+
+ +
+
+
+
+
+
Servers
+<% let servers = Number(bot.servers) %> +
<%- servers.toLocaleString() %>
+
+
+ +
+
+
+
+
+ +
+
+
+
+
+
Users
+<% let users = Number(bot.users) %> +
<%- users.toLocaleString() %>
+
+
+ +
+
+
+
+
+
+ + +
+ +
+
+
+
+
+
Bot Invite
+
+ +<% if(bot.mbl.invite) { %> + +<% } else { %> + +<% } %> + +
+
+
+ +
+
+
+
+
+ +<% if(user) { %> +<% console.log(bot) %> +<% +let allowed = ["338192747754160138","137624084572798976"]; +allowed.push(bot.owner); +%> + +<% if(allowed.includes(user.id)) { %> + +
+
+
+
+
+
Settings
+
+ +
+
+
+ +
+
+
+
+
+<% } %> + +<% } %> \ No newline at end of file diff --git a/Panel/views/bots.ejs b/Panel/views/bots.ejs new file mode 100644 index 000000000..97913381c --- /dev/null +++ b/Panel/views/bots.ejs @@ -0,0 +1,151 @@ +<%- include("./partials/header.ejs", { botInfo: false, Title: "Bots", Avatar: "", Redirect: "/bots" }) %> + + + +


+ +<% if(!q) { %> + +
+
+
All of the bot that send stats.
+ + + +
+ +
+
+ +<% for(var i=0; i < bots.length; i++) { %> + + <% let data = db.get(bots[i]) + %> + + + +<% } %> +
+
+ +<% } else { %> +<% if(q === "sort_abc") { %> +
+
+
All of bots sorted alphabetically.
+ + +
+ +
+
+ +<% for(var i=0; i < ar.length; i++) { %> + + <% let data = db.get(ar[i].id) + %> + + + +<% } %> +
+
+ + <% } %> + +<% if(q === "sort_largest") { %> +
+
+
All of bots sorted alphabetically.
+ + + +
+ +
+
+ +<% for(var i=0; i < lar.length; i++) { %> + + <% let data = db.get(lar[i].id) + %> + + + +<% } %> +
+
+ + <% } %> + +<% } %> + + + \ No newline at end of file diff --git a/Panel/views/error.ejs b/Panel/views/error.ejs new file mode 100644 index 000000000..f40a0f5ed --- /dev/null +++ b/Panel/views/error.ejs @@ -0,0 +1,9 @@ +<%- include("./partials/header.ejs", { botInfo: false, Title: "Home", Avatar: "", Redirect: "/me" }) %> + + +



+ +
+
<%- message %>
+ +
\ No newline at end of file diff --git a/Panel/views/feedback.ejs b/Panel/views/feedback.ejs new file mode 100644 index 000000000..dbecfd559 --- /dev/null +++ b/Panel/views/feedback.ejs @@ -0,0 +1,74 @@ +<%- include("./partials/header.ejs", { botInfo: false, Title: "Bots", Avatar: "", Redirect: "/bots" }) %> + + + + + + + + + + + + + + +
+
+
+
+
+
+
+

Feedback Area

+
+Welcome to the Feedback Area of DanBot Hosting. You can report bugs & suggestions via this forms.

Before posting, please verify if your bug/suggestion isn't listed. +

+
+ +
+
+
+
+
+
+
+
+
+

I would like to file a bug report.

+
+
+ + +
+ +
+
+
+
+
+

I have a suggestion!

+
+
+ + +
+ +
+
+
+
+









+
+
+
+
+ + + + + + \ No newline at end of file diff --git a/Panel/views/forms/apply-staff.ejs b/Panel/views/forms/apply-staff.ejs new file mode 100644 index 000000000..615d45ed7 --- /dev/null +++ b/Panel/views/forms/apply-staff.ejs @@ -0,0 +1,119 @@ +<%- include("../partials/header.ejs", { botInfo: false, Title: `Your Bots`, Avatar: ``, Redirect: `/me` }) %> + + + + + + + + + + + + + + + + + + + +
+
+
+
+

Staff application

+

Apply for staff

+
+
+
+ + + +
+
+
+
+
+ + +
Console Email: *
+
+
+ +
+ +
+
+ +
How long have you been in DBH? *
+
+
+ +
+ +
+
+ +
Location? *
+
+
+ +
+ +
+
+ +
+ +
+ +
+ +
+
+
+
+ +
+ + \ No newline at end of file diff --git a/Panel/views/forms/newserver.ejs b/Panel/views/forms/newserver.ejs new file mode 100644 index 000000000..be2187334 --- /dev/null +++ b/Panel/views/forms/newserver.ejs @@ -0,0 +1,130 @@ +<%- include("../partials/header.ejs", { botInfo: false, Title: `Your Bots`, Avatar: ``, Redirect: `/me` }) %> + + + + + + + + + + + + + + + + + + + +
+
+
+
+

New Server

+

Create a new server

+
+
+
+ + + +
+
+
+
+
+ + +
Server Name *
+
+
+ +
+ +
+

- Ex: Baby Witch Help +

+
+ +
What type of Server? *
+
+
+ +
+ +
+

- Use the selector +

+
+ +
Location? *
+
+
+ +
+ +
+

- Use the selector (ONLY WORKS FOR GAMESERVERS) +

+
+ +
+ +
+ +
+ +
+
+
+
+ +
+ + \ No newline at end of file diff --git a/Panel/views/index.ejs b/Panel/views/index.ejs new file mode 100644 index 000000000..46701be03 --- /dev/null +++ b/Panel/views/index.ejs @@ -0,0 +1,140 @@ +<%- include("./partials/header.ejs", { botInfo: false, Title: "Home", Avatar: "", Redirect: "/me" }) %> + + +


+ +


+ + +
+ +
+
CPU: <%- Node1Data.cpu %> (Cores: <%- Node1Data.cpucores %>, Threads: <%- Node1Data.cputhreads %>)
+
+
+
CPU Load: <%-Node1Data.cpuload%>%
+
+
+
RAM (Used/Total) <%-Node1Data.memused%> / <%-Node1Data.memtotal%>
+
+
+
SWAP (Used/Total) <%-Node1Data.swapused%> / <%-Node1Data.swaptotal%>
+
+
+
Host storage drive (Used/Total): <%- Node1Data.diskused %> / <%- Node1Data.disktotal %>
+
+
+
Network: Rx: <%- Node1Data.netrx %> Tx: <%- Node1Data.nettx %>
+
+
+
Uptime: <%- Node1Data.osuptime %>
+
+
+
Last Updated: <%- Node1Data.updatetime %>
+
+
+
Speedtest (Updates every 6hours) | Ping: <%- Node1DataSpeed.ping %>ms
Download: <%- Node1DataSpeed.download %>Mbps, Upload: <%- Node1DataSpeed.upload %>Mbps, Last Updated: <%- Node1DataSpeed.updatetime %>
+
+ + +
+
CPU: <%-Node2Data.cpu %> (Cores: <%-Node2Data.cpucores%>, Threads: <%-Node2Data.cputhreads%>)
+
+
+
CPU Load: <%-Node2Data.cpuload%>%
+
+
+
RAM (Used/Total) <%-Node2Data.memused%> / <%-Node2Data.memtotal%>
+
+
+
SWAP (Used/Total) <%-Node2Data.swapused%> / <%-Node2Data.swaptotal%>
+
+
+
Host storage drive (Used/Total): <%-Node2Data.diskused%> / <%-Node2Data.disktotal%>
+
+
+
Network: Rx: <%-Node2Data.netrx%> Tx: <%-Node2Data.nettx%>
+
+
+
Uptime: <%-Node2Data.osuptime %>
+
+
+
Last Updated: <%-Node2Data.updatetime%>
+
+
+
Speedtest (Updates every 6hours) | Ping: <%-Node2DataSpeed.ping%>ms
Download: <%-Node2DataSpeed.download%>Mbps, Upload: <%-Node2DataSpeed.upload%>Mbps, Last Updated: <%-Node2DataSpeed.updatetime%>
+
+ + +
+
CPU: <%-Node3Data.cpu%> (Cores: <%-Node3Data.cpucores%>, Threads: <%-Node3Data.cputhreads%>)
+
+
+
CPU Load: <%-Node3Data.cpuload%>%
+
+
+
RAM (Used/Total) <%-Node3Data.memused%> / <%-Node3Data.memtotal%>
+
+
+
SWAP (Used/Total) <%-Node3Data.swapused%> / <%-Node3Data.swaptotal%>
+
+
+
Host storage drive (Used/Total): <%-Node3Data.diskused%> / <%-Node3Data.disktotal%>
+
+
+
Network: Rx: <%-Node3Data.netrx%> Tx: <%-Node3Data.nettx%>
+
+
+
Uptime: <%-Node3Data.osuptime%>
+
+
+
Last Updated: <%-Node3Data.updatetime%>
+
+
+
Speedtest (Updates every 6hours) | Ping: <%-Node3DataSpeed.ping%>ms
Download: <%-Node3DataSpeed.download%>Mbps, Upload: <%-Node3DataSpeed.upload%>Mbps, Last Updated: <%-Node3DataSpeed.updatetime%>
+
+
+ + + \ No newline at end of file diff --git a/Panel/views/main.ejs b/Panel/views/main.ejs new file mode 100644 index 000000000..8530a6404 --- /dev/null +++ b/Panel/views/main.ejs @@ -0,0 +1,41 @@ +<%- include("./partials/header.ejs", { botInfo: false, Title: "Home", Avatar: "", Redirect: "/me" }) %> +




+ + +
+

Welcome To DanBot Hosting

+

Free and fast hosting, available for everyone to use.

+ +
+ + we're still working on this page so check back soon! + +
+
+ +

About Us

+ + + \ No newline at end of file diff --git a/Panel/views/me/index.ejs b/Panel/views/me/index.ejs new file mode 100644 index 000000000..fa6f68a1c --- /dev/null +++ b/Panel/views/me/index.ejs @@ -0,0 +1,57 @@ +<%- include("../partials/header.ejs", { botInfo: false, Title: `Your Bots`, Avatar: ``, Redirect: `/me` }) %> + + +


+ +
+
+
+
+
+
+ +

<%- user.username%>#<%- user.discriminator %>

+
You can find your Bots & More here.

+
+
+
+
+ +
+ +<% if(bots) { %> +
+
+ + +<% for(var i=0; i < bots.length; i++) { %> + + <% let data = db.get(bots[i]) %> + + + +<% } %> +
+
+ +<% } else { %> +
+
+
Sorry no bots were found.
This might be a code issue or you have no bots.
+
+<% } %> \ No newline at end of file diff --git a/Panel/views/me/user.ejs b/Panel/views/me/user.ejs new file mode 100644 index 000000000..1cd0ad607 --- /dev/null +++ b/Panel/views/me/user.ejs @@ -0,0 +1,139 @@ +<%- include("../partials/header.ejs", { botInfo: false, Title: `Your Bots`, Avatar: `${avatar}`, Redirect: `/me` }) %> + + + +
+
+
+
+
+
+ + +

<%= User.tag %>

+ + + + +

<%- presence %>

+ + + <% + let flags = use.public_flags; + let userFlags = []; + + if ((flags & 1) === 1) userFlags.push("Discord Employee"); + if ((flags & 2) === 2) userFlags.push("Discord Partner"); + if ((flags & 4) === 4) userFlags.push("HypeSquad Events"); + if ((flags & 8) === 8) userFlags.push("Bug Hunter Level 1"); + if ((flags & 64) === 64) userFlags.push("HypeSquad House of Bravery"); + else if ((flags & 128) === 128) + userFlags.push("HypeSquad House of Brilliance"); + else if ((flags & 256) === 256) + userFlags.push("HypeSquad House of Balance"); + if ((flags & 512) === 512) userFlags.push("Early_Supporter"); + if ((flags & 1024) === 1024) userFlags.push("Team User"); + if ((flags & 4096) === 4096) userFlags.push("System"); + if ((flags & 16384) === 16384) userFlags.push("Bug Hunter Level 2"); + if ((flags & 131072) === 131072) + userFlags.push("Verified_Bot_Developer"); + + + + %> + + + + + + + +

+ + + + <% if(userFlags.includes("Verified_Bot_Developer")) { %> + + <% } %> + + <% if(userFlags.includes("Early_Supporter")) { %> + + <% } %> + +

+ +
+
+
+
+
+
+ +<% if(bots) { %> +
+
+
All of <%= User.tag %> bots.
+
+ +
+
+ +<% for(var i=0; i < bots.length; i++) { %> + + + <% let data = db.get(bots[i]) %> + + + +<% } %> + + +
+
+<% } else { %> +
+
+
Sorry no bots were found.
+
+<% } %> \ No newline at end of file diff --git a/Panel/views/node1.ejs b/Panel/views/node1.ejs new file mode 100644 index 000000000..6f1119cc7 --- /dev/null +++ b/Panel/views/node1.ejs @@ -0,0 +1,57 @@ +<%- include("./partials/header.ejs", { botInfo: false, Title: "Node 1 Stats", Avatar: "", Redirect: "/me" }) %> + + +


+ +


+ + + +
+
+

All Stats

+
+
+
CPU: <%- Node1Data.cpu %> (Cores: <%- Node1Data.cpucores %>, Threads: <%- Node1Data.cputhreads %>)
+
+
+
CPU Load: <%-Node1Data.cpuload%>%
+
+
+
RAM (Used/Total) <%-Node1Data.memused%> / <%-Node1Data.memtotal%>
+
+
+
SWAP (Used/Total) <%-Node1Data.swapused%> / <%-Node1Data.swaptotal%>
+
+
+
Host storage drive (Used/Total): <%- Node1Data.diskused %> / <%- Node1Data.disktotal %>
+
+
+
Network: Rx: <%- Node1Data.netrx %> Tx: <%- Node1Data.nettx %>
+
+
+
Uptime: <%- Node1Data.osuptime %>
+
+
+
Last Updated: <%- Node1Data.updatetime %>
+
+
+
Speedtest (Updates every 6hours) | Ping: <%- Node1DataSpeed.ping %>ms
Download: <%- Node1DataSpeed.download %>Mbps, Upload: <%- Node1DataSpeed.upload %>Mbps, Last Updated: <%- Node1DataSpeed.updatetime %>
+
+ + + +
\ No newline at end of file diff --git a/Panel/views/node2.ejs b/Panel/views/node2.ejs new file mode 100644 index 000000000..10fd68005 --- /dev/null +++ b/Panel/views/node2.ejs @@ -0,0 +1,57 @@ +<%- include("./partials/header.ejs", { botInfo: false, Title: "Node 2 Stats", Avatar: "", Redirect: "/me" }) %> + + +


+ +


+ + + +
+
+

All Stats

+
+
+
CPU: <%- Node2Data.cpu %> (Cores: <%- Node2Data.cpucores %>, Threads: <%- Node2Data.cputhreads %>)
+
+
+
CPU Load: <%-Node2Data.cpuload%>%
+
+
+
RAM (Used/Total) <%-Node2Data.memused%> / <%-Node2Data.memtotal%>
+
+
+
SWAP (Used/Total) <%-Node2Data.swapused%> / <%-Node2Data.swaptotal%>
+
+
+
Host storage drive (Used/Total): <%- Node2Data.diskused %> / <%- Node2Data.disktotal %>
+
+
+
Network: Rx: <%- Node2Data.netrx %> Tx: <%- Node2Data.nettx %>
+
+
+
Uptime: <%- Node2Data.osuptime %>
+
+
+
Last Updated: <%- Node2Data.updatetime %>
+
+
+
Speedtest (Updates every 6hours) | Ping: <%- Node2DataSpeed.ping %>ms
Download: <%- Node2DataSpeed.download %>Mbps, Upload: <%- Node2DataSpeed.upload %>Mbps, Last Updated: <%- Node2DataSpeed.updatetime %>
+
+ + + +
\ No newline at end of file diff --git a/Panel/views/node3.ejs b/Panel/views/node3.ejs new file mode 100644 index 000000000..12c7a431a --- /dev/null +++ b/Panel/views/node3.ejs @@ -0,0 +1,57 @@ +<%- include("./partials/header.ejs", { botInfo: false, Title: "Node 3 Stats", Avatar: "", Redirect: "/me" }) %> + + +


+ +


+ + + +
+
+

All Stats

+
+
+
CPU: <%- Node3Data.cpu %> (Cores: <%- Node3Data.cpucores %>, Threads: <%- Node3Data.cputhreads %>)
+
+
+
CPU Load: <%-Node3Data.cpuload%>%
+
+
+
RAM (Used/Total) <%-Node3Data.memused%> / <%-Node3Data.memtotal%>
+
+
+
SWAP (Used/Total) <%-Node3Data.swapused%> / <%-Node3Data.swaptotal%>
+
+
+
Host storage drive (Used/Total): <%- Node3Data.diskused %> / <%- Node3Data.disktotal %>
+
+
+
Network: Rx: <%- Node3Data.netrx %> Tx: <%- Node3Data.nettx %>
+
+
+
Uptime: <%- Node3Data.osuptime %>
+
+
+
Last Updated: <%- Node3Data.updatetime %>
+
+
+
Speedtest (Updates every 6hours) | Ping: <%- Node3DataSpeed.ping %>ms
Download: <%- Node3DataSpeed.download %>Mbps, Upload: <%- Node3DataSpeed.upload %>Mbps, Last Updated: <%- Node3DataSpeed.updatetime %>
+
+ + + +
\ No newline at end of file diff --git a/Panel/views/node4.ejs b/Panel/views/node4.ejs new file mode 100644 index 000000000..f09721be8 --- /dev/null +++ b/Panel/views/node4.ejs @@ -0,0 +1,57 @@ +<%- include("./partials/header.ejs", { botInfo: false, Title: "Node 4 Stats", Avatar: "", Redirect: "/me" }) %> + + +


+ +


+ + + +
+
+

All Stats

+
+
+
CPU: <%- Node4Data.cpu %> (Cores: <%- Node4Data.cpucores %>, Threads: <%- Node4Data.cputhreads %>)
+
+
+
CPU Load: <%-Node4Data.cpuload%>%
+
+
+
RAM (Used/Total) <%-Node4Data.memused%> / <%-Node4Data.memtotal%>
+
+
+
SWAP (Used/Total) <%-Node4Data.swapused%> / <%-Node4Data.swaptotal%>
+
+
+
Host storage drive (Used/Total): <%- Node4Data.diskused %> / <%- Node4Data.disktotal %>
+
+
+
Network: Rx: <%- Node4Data.netrx %> Tx: <%- Node4Data.nettx %>
+
+
+
Uptime: <%- Node4Data.osuptime %>
+
+
+
Last Updated: <%- Node4Data.updatetime %>
+
+
+
Speedtest (Updates every 6hours) | Ping: <%- Node4DataSpeed.ping %>ms
Download: <%- Node4DataSpeed.download %>Mbps, Upload: <%- Node4DataSpeed.upload %>Mbps, Last Updated: <%- Node4DataSpeed.updatetime %>
+
+ + + +
\ No newline at end of file diff --git a/Panel/views/partials/header.ejs b/Panel/views/partials/header.ejs new file mode 100644 index 000000000..6741e5b23 --- /dev/null +++ b/Panel/views/partials/header.ejs @@ -0,0 +1,278 @@ + + + + + + + + +<%= Title %> | DanBot Hosting +<% if(botInfo) { %> + + +<% } else { %> + + +<% } %> + + + + + + + + + + + + + + + + + + + + + + + + + + + +<% if(botInfo) { %> + + + + + + + + + + + + +<% } %> + + + + + + + + + + + \ No newline at end of file diff --git a/Panel/views/partials/header.hbs b/Panel/views/partials/header.hbs index 9eeed9db5..6050c7f61 100644 --- a/Panel/views/partials/header.hbs +++ b/Panel/views/partials/header.hbs @@ -170,7 +170,7 @@ window.cookieconsent.initialise({
-
CPU: <%-Node2Data.cpu %> (Cores: <%-Node2Data.cpucores%>, Threads: <%-Node2Data.cputhreads%>)
+
CPU: <%- nodeData.fetch("Node2.cpu") %> (Cores: <%- nodeData.fetch("Node2.cpucores") %>, Threads: <%- nodeData.fetch("Node2.cputhreads") %>)
-
CPU Load: <%-Node2Data.cpuload%>%
+
CPU Load: <%- nodeData.fetch("Node2.cpuload") %>%
-
RAM (Used/Total) <%-Node2Data.memused%> / <%-Node2Data.memtotal%>
+
RAM (Used/Total) <%- nodeData.fetch("Node2.memused") %> / <%- nodeData.fetch("Node2.memtotal") %>
-
SWAP (Used/Total) <%-Node2Data.swapused%> / <%-Node2Data.swaptotal%>
+
SWAP (Used/Total) <%- nodeData.fetch("Node2.swapused") %> / <%- nodeData.fetch("Node2.swaptotal") %>
-
Host storage drive (Used/Total): <%-Node2Data.diskused%> / <%-Node2Data.disktotal%>
+
Host storage drive (Used/Total): <%- nodeData.fetch("Node2.diskused") %> / <%- nodeData.fetch("Node2.total") %>
-
Network: Rx: <%-Node2Data.netrx%> Tx: <%-Node2Data.nettx%>
+
Network: Rx: <%- nodeData.fetch("Node2.netrx") %> Tx: <%- nodeData.fetch("Node2.nettx") %>
-
Uptime: <%-Node2Data.osuptime %>
+
Uptime: <%- nodeData.fetch("Node2.osuptime") %>
-
Last Updated: <%-Node2Data.updatetime%>
+
Last Updated: <%- nodeData.fetch("Node2.updatetime") %>
-
Speedtest (Updates every 6hours) | Ping: <%-Node2DataSpeed.ping%>ms
Download: <%-Node2DataSpeed.download%>Mbps, Upload: <%-Node2DataSpeed.upload%>Mbps, Last Updated: <%-Node2DataSpeed.updatetime%>
+
Speedtest (Updates every 6hours) | Ping: <%- nodeData.fetch("Node2-speedtest.ping") %>ms
Download: <%- nodeData.fetch("Node2-speedtest.download") %>Mbps, Upload: <%- nodeData.fetch("Node2-speedtest.upload") %>Mbps, Last Updated: <%- nodeData.fetch("Node2-speedtest.updatetime") %>
-
CPU: <%-Node3Data.cpu%> (Cores: <%-Node3Data.cpucores%>, Threads: <%-Node3Data.cputhreads%>)
+
CPU: <%- nodeData.fetch("Node3.cpu") %> (Cores: <%- nodeData.fetch("Node3.cpucores") %>, Threads: <%- nodeData.fetch("Node3.cputhreads") %>)
-
CPU Load: <%-Node3Data.cpuload%>%
+
CPU Load: <%- nodeData.fetch("Node3.cpuload") %>%
-
RAM (Used/Total) <%-Node3Data.memused%> / <%-Node3Data.memtotal%>
+
RAM (Used/Total) <%- nodeData.fetch("Node3.memused") %> / <%- nodeData.fetch("Node3.memtotal") %>
-
SWAP (Used/Total) <%-Node3Data.swapused%> / <%-Node3Data.swaptotal%>
+
SWAP (Used/Total) <%- nodeData.fetch("Node3.swapused") %> / <%- nodeData.fetch("Node3.swaptotal") %>
-
Host storage drive (Used/Total): <%-Node3Data.diskused%> / <%-Node3Data.disktotal%>
+
Host storage drive (Used/Total): <%- nodeData.fetch("Node3.diskused") %> / <%- nodeData.fetch("Node3.total") %>
-
Network: Rx: <%-Node3Data.netrx%> Tx: <%-Node3Data.nettx%>
+
Network: Rx: <%- nodeData.fetch("Node3.netrx") %> Tx: <%- nodeData.fetch("Node3.nettx") %>
-
Uptime: <%-Node3Data.osuptime%>
+
Uptime: <%- nodeData.fetch("Node3.osuptime") %>
-
Last Updated: <%-Node3Data.updatetime%>
+
Last Updated: <%- nodeData.fetch("Node3.updatetime") %>
-
Speedtest (Updates every 6hours) | Ping: <%-Node3DataSpeed.ping%>ms
Download: <%-Node3DataSpeed.download%>Mbps, Upload: <%-Node3DataSpeed.upload%>Mbps, Last Updated: <%-Node3DataSpeed.updatetime%>
+
Speedtest (Updates every 6hours) | Ping: <%- nodeData.fetch("Node3-speedtest.ping") %>ms
Download: <%- nodeData.fetch("Node3-speedtest.download") %>Mbps, Upload: <%- nodeData.fetch("Node3-speedtest.upload") %>Mbps, Last Updated: <%- nodeData.fetch("Node3-speedtest.updatetime") %>
diff --git a/Panel/views/index.hbs b/Panel/views/index.hbs deleted file mode 100644 index cd5161ae7..000000000 --- a/Panel/views/index.hbs +++ /dev/null @@ -1,120 +0,0 @@ - -DanBot Hosting Stats - - - - - - -
- -
-
CPU: {{Node1Data.cpu}} (Cores: {{Node1Data.cpucores}}, Threads: {{Node1Data.cputhreads}})
-
-
-
CPU Load: {{Node1Data.cpuload}}%
-
-
-
RAM (Used/Total) {{Node1Data.memused}} / {{Node1Data.memtotal}}
-
-
-
SWAP (Used/Total) {{Node1Data.swapused}} / {{Node1Data.swaptotal}}
-
-
-
Host storage drive (Used/Total): {{Node1Data.diskused}} / {{Node1Data.disktotal}}
-
-
-
Network: Rx: {{Node1Data.netrx}} Tx: {{Node1Data.nettx}}
-
-
-
Uptime: {{Node1Data.osuptime}}
-
-
-
Last Updated: {{Node1Data.updatetime}}
-
-
-
Speedtest (Updates every 6hours) | Ping: {{Node1DataSpeed.ping}}ms, Download: {{Node1DataSpeed.download}}Mbps, Upload: {{Node1DataSpeed.upload}}Mbps, Last Updated: {{Node1DataSpeed.updatetime}}
-
- - -
-
CPU: {{Node2Data.cpu}} (Cores: {{Node2Data.cpucores}}, Threads: {{Node2Data.cputhreads}})
-
-
-
CPU Load: {{Node2Data.cpuload}}%
-
-
-
RAM (Used/Total) {{Node2Data.memused}} / {{Node2Data.memtotal}}
-
-
-
SWAP (Used/Total) {{Node2Data.swapused}} / {{Node2Data.swaptotal}}
-
-
-
Host storage drive (Used/Total): {{Node2Data.diskused}} / {{Node2Data.disktotal}}
-
-
-
Network: Rx: {{Node2Data.netrx}} Tx: {{Node2Data.nettx}}
-
-
-
Uptime: {{Node2Data.osuptime}}
-
-
-
Last Updated: {{Node2Data.updatetime}}
-
-
-
Speedtest (Updates every 6hours) | Ping: {{Node2DataSpeed.ping}}ms, Download: {{Node2DataSpeed.download}}Mbps, Upload: {{Node2DataSpeed.upload}}Mbps, Last Updated: {{Node2DataSpeed.updatetime}}
-
- - -
-
CPU: {{Node3Data.cpu}} (Cores: {{Node3Data.cpucores}}, Threads: {{Node3Data.cputhreads}})
-
-
-
CPU Load: {{Node3Data.cpuload}}%
-
-
-
RAM (Used/Total) {{Node3Data.memused}} / {{Node3Data.memtotal}}
-
-
-
SWAP (Used/Total) {{Node3Data.swapused}} / {{Node3Data.swaptotal}}
-
-
-
Host storage drive (Used/Total): {{Node3Data.diskused}} / {{Node3Data.disktotal}}
-
-
-
Network: Rx: {{Node3Data.netrx}} Tx: {{Node3Data.nettx}}
-
-
-
Uptime: {{Node3Data.osuptime}}
-
-
-
Last Updated: {{Node3Data.updatetime}}
-
-
-
Speedtest (Updates every 6hours) | Ping: {{Node3DataSpeed.ping}}ms, Download: {{Node3DataSpeed.download}}Mbps, Upload: {{Node3DataSpeed.upload}}Mbps, Last Updated: {{Node3DataSpeed.updatetime}}
-
- -
- \ No newline at end of file diff --git a/Panel/views/node1.ejs b/Panel/views/node1.ejs index 6f1119cc7..1d6af26a9 100644 --- a/Panel/views/node1.ejs +++ b/Panel/views/node1.ejs @@ -25,31 +25,31 @@

All Stats

-
CPU: <%- Node1Data.cpu %> (Cores: <%- Node1Data.cpucores %>, Threads: <%- Node1Data.cputhreads %>)
+
CPU: <%- nodeData.fetch("Node1.cpu") %> (Cores: <%- nodeData.fetch("Node1.cpucores") %>, Threads: <%- nodeData.fetch("Node1.cputhreads") %>)
-
CPU Load: <%-Node1Data.cpuload%>%
+
CPU Load: <%- nodeData.fetch("Node1.cpuload") %>%
-
RAM (Used/Total) <%-Node1Data.memused%> / <%-Node1Data.memtotal%>
+
RAM (Used/Total) <%- nodeData.fetch("Node1.memused") %> / <%- nodeData.fetch("Node1.memtotal") %>
-
SWAP (Used/Total) <%-Node1Data.swapused%> / <%-Node1Data.swaptotal%>
+
SWAP (Used/Total) <%- nodeData.fetch("Node1.swapused") %> / <%- nodeData.fetch("Node1.swaptotal") %>
-
Host storage drive (Used/Total): <%- Node1Data.diskused %> / <%- Node1Data.disktotal %>
+
Host storage drive (Used/Total): <%- nodeData.fetch("Node1.diskused") %> / <%- nodeData.fetch("Node1.total") %>
-
Network: Rx: <%- Node1Data.netrx %> Tx: <%- Node1Data.nettx %>
+
Network: Rx: <%- nodeData.fetch("Node1.netrx") %> Tx: <%- nodeData.fetch("Node1.nettx") %>
-
Uptime: <%- Node1Data.osuptime %>
+
Uptime: <%- nodeData.fetch("Node1.osuptime") %>
-
Last Updated: <%- Node1Data.updatetime %>
+
Last Updated: <%- nodeData.fetch("Node1.updatetime") %>
-
Speedtest (Updates every 6hours) | Ping: <%- Node1DataSpeed.ping %>ms
Download: <%- Node1DataSpeed.download %>Mbps, Upload: <%- Node1DataSpeed.upload %>Mbps, Last Updated: <%- Node1DataSpeed.updatetime %>
+
Speedtest (Updates every 6hours) | Ping: <%- nodeData.fetch("Node1-speedtest.ping") %>ms
Download: <%- nodeData.fetch("Node1-speedtest.download") %>Mbps, Upload: <%- nodeData.fetch("Node1-speedtest.upload") %>Mbps, Last Updated: <%- nodeData.fetch("Node1-speedtest.updatetime") %>
diff --git a/Panel/views/node1.hbs b/Panel/views/node1.hbs deleted file mode 100644 index 815697c07..000000000 --- a/Panel/views/node1.hbs +++ /dev/null @@ -1,56 +0,0 @@ - -Node 1 - DanBot Hosting Stats - - - - - - -
- All host stats -
-

Node 1 Stats

-
-
-
CPU: {{Node1Data.cpu}} (Cores: {{Node1Data.cpucores}}, Threads: {{Node1Data.cputhreads}})
-
-
-
CPU Load: {{Node1Data.cpuload}}%
-
-
-
RAM (Used/Total) {{Node1Data.memused}} / {{Node1Data.memtotal}}
-
-
-
SWAP (Used/Total) {{Node1Data.swapused}} / {{Node1Data.swaptotal}}
-
-
-
Host storage drive (Used/Total): {{Node1Data.diskused}} / {{Node1Data.disktotal}}
-
-
-
Network: Rx: {{Node1Data.netrx}} Tx: {{Node1Data.nettx}}
-
-
-
Uptime: {{Node1Data.osuptime}}
-
-
-
Speedtest (Updates every 6hours) | Ping: {{Node1DataSpeed.ping}}ms, Download: {{Node1DataSpeed.download}}Mbps, Upload: {{Node1DataSpeed.upload}}Mbps, Last Updated: {{Node1DataSpeed.updatetime}}
-
- -
- \ No newline at end of file diff --git a/Panel/views/node2.ejs b/Panel/views/node2.ejs index 10fd68005..ec40424e3 100644 --- a/Panel/views/node2.ejs +++ b/Panel/views/node2.ejs @@ -25,31 +25,31 @@

All Stats

-
CPU: <%- Node2Data.cpu %> (Cores: <%- Node2Data.cpucores %>, Threads: <%- Node2Data.cputhreads %>)
+
CPU: <%- nodeData.fetch("Node2.cpu") %> (Cores: <%- nodeData.fetch("Node2.cpucores") %>, Threads: <%- nodeData.fetch("Node2.cputhreads") %>)
-
CPU Load: <%-Node2Data.cpuload%>%
+
CPU Load: <%- nodeData.fetch("Node2.cpuload") %>%
-
RAM (Used/Total) <%-Node2Data.memused%> / <%-Node2Data.memtotal%>
+
RAM (Used/Total) <%- nodeData.fetch("Node2.memused") %> / <%- nodeData.fetch("Node2.memtotal") %>
-
SWAP (Used/Total) <%-Node2Data.swapused%> / <%-Node2Data.swaptotal%>
+
SWAP (Used/Total) <%- nodeData.fetch("Node2.swapused") %> / <%- nodeData.fetch("Node2.swaptotal") %>
-
Host storage drive (Used/Total): <%- Node2Data.diskused %> / <%- Node2Data.disktotal %>
+
Host storage drive (Used/Total): <%- nodeData.fetch("Node2.diskused") %> / <%- nodeData.fetch("Node2.total") %>
-
Network: Rx: <%- Node2Data.netrx %> Tx: <%- Node2Data.nettx %>
+
Network: Rx: <%- nodeData.fetch("Node2.netrx") %> Tx: <%- nodeData.fetch("Node2.nettx") %>
-
Uptime: <%- Node2Data.osuptime %>
+
Uptime: <%- nodeData.fetch("Node2.osuptime") %>
-
Last Updated: <%- Node2Data.updatetime %>
+
Last Updated: <%- nodeData.fetch("Node2.updatetime") %>
-
Speedtest (Updates every 6hours) | Ping: <%- Node2DataSpeed.ping %>ms
Download: <%- Node2DataSpeed.download %>Mbps, Upload: <%- Node2DataSpeed.upload %>Mbps, Last Updated: <%- Node2DataSpeed.updatetime %>
+
Speedtest (Updates every 6hours) | Ping: <%- nodeData.fetch("Node2-speedtest.ping") %>ms
Download: <%- nodeData.fetch("Node2-speedtest.download") %>Mbps, Upload: <%- nodeData.fetch("Node2-speedtest.upload") %>Mbps, Last Updated: <%- nodeData.fetch("Node2-speedtest.updatetime") %>
diff --git a/Panel/views/node2.hbs b/Panel/views/node2.hbs deleted file mode 100644 index 42ff31944..000000000 --- a/Panel/views/node2.hbs +++ /dev/null @@ -1,56 +0,0 @@ - -Node 2 - DanBot Hosting Stats - - - - - - -
- All host stats -
-

Node 2 Stats

-
-
-
CPU: {{Node2Data.cpu}} (Cores: {{Node2Data.cpucores}}, Threads: {{Node2Data.cputhreads}})
-
-
-
CPU Load: {{Node2Data.cpuload}}%
-
-
-
RAM (Used/Total) {{Node2Data.memused}} / {{Node2Data.memtotal}}
-
-
-
SWAP (Used/Total) {{Node2Data.swapused}} / {{Node2Data.swaptotal}}
-
-
-
Host storage drive (Used/Total): {{Node2Data.diskused}} / {{Node2Data.disktotal}}
-
-
-
Network: Rx: {{Node2Data.netrx}} Tx: {{Node2Data.nettx}}
-
-
-
Uptime: {{Node2Data.osuptime}}
-
-
-
Speedtest (Updates every 6hours) | Ping: {{Node2DataSpeed.ping}}ms, Download: {{Node2DataSpeed.download}}Mbps, Upload: {{Node2DataSpeed.upload}}Mbps, Last Updated: {{Node2DataSpeed.updatetime}}
-
- -
- \ No newline at end of file diff --git a/Panel/views/node3.ejs b/Panel/views/node3.ejs index 12c7a431a..bff63f35b 100644 --- a/Panel/views/node3.ejs +++ b/Panel/views/node3.ejs @@ -25,31 +25,31 @@

All Stats

-
CPU: <%- Node3Data.cpu %> (Cores: <%- Node3Data.cpucores %>, Threads: <%- Node3Data.cputhreads %>)
+
CPU: <%- nodeData.fetch("Node3.cpu") %> (Cores: <%- nodeData.fetch("Node3.cpucores") %>, Threads: <%- nodeData.fetch("Node3.cputhreads") %>)
-
CPU Load: <%-Node3Data.cpuload%>%
+
CPU Load: <%- nodeData.fetch("Node3.cpuload") %>%
-
RAM (Used/Total) <%-Node3Data.memused%> / <%-Node3Data.memtotal%>
+
RAM (Used/Total) <%- nodeData.fetch("Node3.memused") %> / <%- nodeData.fetch("Node3.memtotal") %>
-
SWAP (Used/Total) <%-Node3Data.swapused%> / <%-Node3Data.swaptotal%>
+
SWAP (Used/Total) <%- nodeData.fetch("Node3.swapused") %> / <%- nodeData.fetch("Node3.swaptotal") %>
-
Host storage drive (Used/Total): <%- Node3Data.diskused %> / <%- Node3Data.disktotal %>
+
Host storage drive (Used/Total): <%- nodeData.fetch("Node3.diskused") %> / <%- nodeData.fetch("Node3.total") %>
-
Network: Rx: <%- Node3Data.netrx %> Tx: <%- Node3Data.nettx %>
+
Network: Rx: <%- nodeData.fetch("Node3.netrx") %> Tx: <%- nodeData.fetch("Node3.nettx") %>
-
Uptime: <%- Node3Data.osuptime %>
+
Uptime: <%- nodeData.fetch("Node3.osuptime") %>
-
Last Updated: <%- Node3Data.updatetime %>
+
Last Updated: <%- nodeData.fetch("Node3.updatetime") %>
-
Speedtest (Updates every 6hours) | Ping: <%- Node3DataSpeed.ping %>ms
Download: <%- Node3DataSpeed.download %>Mbps, Upload: <%- Node3DataSpeed.upload %>Mbps, Last Updated: <%- Node3DataSpeed.updatetime %>
+
Speedtest (Updates every 6hours) | Ping: <%- nodeData.fetch("Node3-speedtest.ping") %>ms
Download: <%- nodeData.fetch("Node3-speedtest.download") %>Mbps, Upload: <%- nodeData.fetch("Node3-speedtest.upload") %>Mbps, Last Updated: <%- nodeData.fetch("Node3-speedtest.updatetime") %>
diff --git a/Panel/views/node3.hbs b/Panel/views/node3.hbs deleted file mode 100644 index 2a60a049a..000000000 --- a/Panel/views/node3.hbs +++ /dev/null @@ -1,56 +0,0 @@ - -Node 3 - DanBot Hosting Stats - - - - - - -
- All host stats -
-

Node 3 Stats

-
-
-
CPU: {{Node3Data.cpu}} (Cores: {{Node3Data.cpucores}}, Threads: {{Node3Data.cputhreads}})
-
-
-
CPU Load: {{Node3Data.cpuload}}%
-
-
-
RAM (Used/Total) {{Node3Data.memused}} / {{Node3Data.memtotal}}
-
-
-
SWAP (Used/Total) {{Node3Data.swapused}} / {{Node3Data.swaptotal}}
-
-
-
Host storage drive (Used/Total): {{Node3Data.diskused}} / {{Node3Data.disktotal}}
-
-
-
Network: Rx: {{Node3Data.netrx}} Tx: {{Node3Data.nettx}}
-
-
-
Uptime: {{Node3Data.osuptime}}
-
-
-
Speedtest (Updates every 6hours) | Ping: {{Node3DataSpeed.ping}}ms, Download: {{Node3DataSpeed.download}}Mbps, Upload: {{Node3DataSpeed.upload}}Mbps, Last Updated: {{Node3DataSpeed.updatetime}}
-
- -
- \ No newline at end of file diff --git a/Panel/views/node4.ejs b/Panel/views/node4.ejs deleted file mode 100644 index f09721be8..000000000 --- a/Panel/views/node4.ejs +++ /dev/null @@ -1,57 +0,0 @@ -<%- include("./partials/header.ejs", { botInfo: false, Title: "Node 4 Stats", Avatar: "", Redirect: "/me" }) %> - - -


- -


- - - -
-
-

All Stats

-
-
-
CPU: <%- Node4Data.cpu %> (Cores: <%- Node4Data.cpucores %>, Threads: <%- Node4Data.cputhreads %>)
-
-
-
CPU Load: <%-Node4Data.cpuload%>%
-
-
-
RAM (Used/Total) <%-Node4Data.memused%> / <%-Node4Data.memtotal%>
-
-
-
SWAP (Used/Total) <%-Node4Data.swapused%> / <%-Node4Data.swaptotal%>
-
-
-
Host storage drive (Used/Total): <%- Node4Data.diskused %> / <%- Node4Data.disktotal %>
-
-
-
Network: Rx: <%- Node4Data.netrx %> Tx: <%- Node4Data.nettx %>
-
-
-
Uptime: <%- Node4Data.osuptime %>
-
-
-
Last Updated: <%- Node4Data.updatetime %>
-
-
-
Speedtest (Updates every 6hours) | Ping: <%- Node4DataSpeed.ping %>ms
Download: <%- Node4DataSpeed.download %>Mbps, Upload: <%- Node4DataSpeed.upload %>Mbps, Last Updated: <%- Node4DataSpeed.updatetime %>
-
- - - -
\ No newline at end of file diff --git a/Panel/views/node4.hbs b/Panel/views/node4.hbs deleted file mode 100644 index 97b63d32d..000000000 --- a/Panel/views/node4.hbs +++ /dev/null @@ -1,56 +0,0 @@ - -Node 4 - DanBot Hosting Stats - - - - - - -
- All host stats -
-

Node 4 Stats (Private, Home dedi)

-
-
-
CPU: {{Node4Data.cpu}} (Cores: {{Node4Data.cpucores}}, Threads: {{Node4Data.cputhreads}})
-
-
-
CPU Load: {{Node4Data.cpuload}}%
-
-
-
RAM (Used/Total) {{Node4Data.memused}} / {{Node4Data.memtotal}}
-
-
-
SWAP (Used/Total) {{Node4Data.swapused}} / {{Node4Data.swaptotal}}
-
-
-
Host storage drive (Used/Total): {{Node4Data.diskused}} / {{Node4Data.disktotal}}
-
-
-
Network: Rx: {{Node4Data.netrx}} Tx: {{Node4Data.nettx}}
-
-
-
Uptime: {{Node4Data.osuptime}}
-
-
-
Speedtest (Updates every 6hours) | Ping: {{Node4DataSpeed.ping}}ms, Download: {{Node4DataSpeed.download}}Mbps, Upload: {{Node4DataSpeed.upload}}Mbps, Last Updated: {{Node4DataSpeed.updatetime}}
-
- -
- \ No newline at end of file diff --git a/Panel/views/partials/header.ejs b/Panel/views/partials/header.ejs index 6741e5b23..1cf869f03 100644 --- a/Panel/views/partials/header.ejs +++ b/Panel/views/partials/header.ejs @@ -209,6 +209,15 @@ h4 {
<% if(user) { %> + + + <% } else { %> @@ -261,6 +266,7 @@ h4 { diff --git a/Panel/views/request.ejs b/Panel/views/request.ejs new file mode 100644 index 000000000..db89f9f45 --- /dev/null +++ b/Panel/views/request.ejs @@ -0,0 +1,108 @@ +<%- include("./partials/header.ejs", { botInfo: false, Title: `Your Bots`, Avatar: ``, Redirect: `/me` }) %> + + + + + + + + + + + + + + + + + + + +
+
+
+
+

Requests

+

View and submit a new request here!

+
+
+
+ +
+
+
+
+
+ + +
*
+
+
+ +
+ +
+

+
+ +
Welcome Channel *
+
+
+ +
+ +
+

- Use the selector +

+
+ +
Location? *
+
+
+ +
+ +
+

- Use the selector (ONLY WORKS FOR GAMESERVERS) +

+
+ +
+ +
+ +
+ +
+
+
+
+ +
+ + \ No newline at end of file diff --git a/Panel/views/requests-admin.ejs b/Panel/views/requests-admin.ejs new file mode 100644 index 000000000..a91f51c4b --- /dev/null +++ b/Panel/views/requests-admin.ejs @@ -0,0 +1,133 @@ +<%- include("./partials/header.ejs", { botInfo: false, Title: `Your Bots`, Avatar: ``, Redirect: `/me` }) %> + + + + + + + + + + + + + + + + + + + +
+
+
+
+

Server settings

+

Change/View server settings

+
+
+
+ + + +
+
+
+
+
+ + +
*
+
+
+ +
+ +
+

+
+ +
Welcome Channel *
+
+
+ +
+ +
+

- Use the selector +

+
+ +
Location? *
+
+
+ +
+ +
+

- Use the selector (ONLY WORKS FOR GAMESERVERS) +

+
+ +
+ +
+ +
+ +
+
+
+
+ +
+ + \ No newline at end of file From 44bd71ae790738986232d9f7b7f3759aac0de573 Mon Sep 17 00:00:00 2001 From: danielpmc Date: Sat, 17 Oct 2020 05:09:33 +0100 Subject: [PATCH 048/255] Remove comment of old invite message --- Panel/bot/discord/events/guildMemberAdd.js | 1 - 1 file changed, 1 deletion(-) diff --git a/Panel/bot/discord/events/guildMemberAdd.js b/Panel/bot/discord/events/guildMemberAdd.js index c5be4615d..d90a406f6 100644 --- a/Panel/bot/discord/events/guildMemberAdd.js +++ b/Panel/bot/discord/events/guildMemberAdd.js @@ -91,7 +91,6 @@ module.exports = async (client, member, guild) => { .addField(`Invite code used:`, '`' + invite.code + '`', true) .addField(`Invite used`, invite.uses + ' times', true); client.channels.get(config.invitechannel).send(embed) - //client.channels.get(config.invitechannel).send(`${member.user.tag} (ID: ${member.user.id}) joined using invite code ` + "`" + invite.code + "`" + ` from ${inviter.tag} (ID: ${inviter.id}). Invite code has been used ${invite.uses} times.`); const invite5 = member.guild.roles.find(role => role.id === config.invite5); const invite10 = member.guild.roles.find(role => role.id === config.invite10); const invite25 = member.guild.roles.find(role => role.id === config.invite25); From 49e72e014d527c432aedaa0505f1e3a9ef05848f Mon Sep 17 00:00:00 2001 From: danielpmc Date: Sat, 17 Oct 2020 05:10:55 +0100 Subject: [PATCH 049/255] Restore message.js from beta as missing updates to repo --- Panel/bot/discord/events/message.js | 115 ++++++++++++++++------------ 1 file changed, 64 insertions(+), 51 deletions(-) diff --git a/Panel/bot/discord/events/message.js b/Panel/bot/discord/events/message.js index 59a18ffe5..d67d6b52f 100644 --- a/Panel/bot/discord/events/message.js +++ b/Panel/bot/discord/events/message.js @@ -2,50 +2,68 @@ module.exports = (client, message) => { //if(message.content.toLowerCase().includes("tiktok")) {message.reply('Ew. Get out here with that crap :bammer:'), message.delete() } - if (message.content.toLowerCase().includes("discord.gg")) { - message.delete(); + if(message.author.id === client.user.id) { + return; + } else if (message.content.toLowerCase().includes("discord.gg")) { + message.delete(); } else if (message.content.toLowerCase().includes("discord.com")) { message.delete() - } else if (message.content.toLowerCase().includes(" ឵឵")) { + } else if (message.content.toLowerCase().includes("discordapp.com឵឵")) { message.delete() - } else if (message.content.toLowerCase().includes("")) + } + if(mutesData.fetch(message.author.id + ".muted") === "true") { + let muteRole = client.guilds.get(message.guild.id).roles.find(r => r.id == "726829710935457872"); + message.guild.members.get(message.author.id).addRole(muteRole) + } else if(mutesData.fetch(message.author.id + ".muted") === "false") { + let muteRole = client.guilds.get(message.guild.id).roles.find(r => r.id == "726829710935457872"); + message.guild.members.get(message.author.id).removeRole(muteRole) + } - /* + + if (message.attachments.size > 0) { + if (message.attachments.every(attachIsImage)){ const Tesseract = require("tesseract.js") - if (message.attachments.size > 0) { - message.attachments.forEach(attachment => { - //console.log(attachment.url) - Tesseract.recognize( - attachment.url, - 'eng', - ).then(({ data: { text } }) => { - if (text.includes("There was an error attempting to establish")) { - message.reply('It looks like you are getting a error with the websocket. Try refreshing if that doesnt work please check <#738530520945786921>') - } else if (text.includes("HTTP/E_CONN_REFUSED")) { - message.reply('It looks like you might be getting a `HTTP/E_CONN_REFUSED` error. \nThis error is normally found in the file management. Please refresh. \nIf that doesnt fix check <#738530520945786921> for any possible outages. No outages but still got the error? make a ticket!') - } else if (text.includes("We were unable to locate the requested resource on the server.")) { - message.reply('Uh oh. Server you are trying to access doesnt exist. Did you get the wrong url or was the server deleted?') - } else if (text.includes("You do not have permission to access this resource on this server.")) { - message.reply('The server you are trying to access you do not have perms to view. If you did before the user might of removed you as subuser.') - } else if (text.includes('Gateway Timeout')) { - message.reply('It looks like you are getting a `Gateway Timeout` error. This normally happens when a outage is happening. \nIf nothing is posted in <#738530520945786921> then you might just be having the issue. \nIt should fix its self soon') - } else if (text.includes('instal process')) { - message.reply('It looks like your server might be stuck on installing. Please open a ticket so we can fix this for you.') - } else { - message.react('👀'); - } - message.channel.send(text) - }) - }); - }; - */ + message.attachments.forEach(attachment => { + Tesseract.recognize( + attachment.url, + 'eng', + ).then(({ data: { text } }) => { + if (text.includes("There was an error attempting to establish")) { + message.reply('It looks like you are getting a error with the websocket. Try refreshing if that doesnt work please check <#738530520945786921>') + } else if (text.includes("HTTP/E_CONN_REFUSED")) { + message.reply('It looks like you might be getting a `HTTP/E_CONN_REFUSED` error. \nThis error is normally found in the file management. Please refresh. \nIf that doesnt fix check <#738530520945786921> for any possible outages. No outages but still got the error? make a ticket!') + } else if (text.includes("We were unable to locate the requested resource on the server.")) { + message.reply('Uh oh. Server you are trying to access doesnt exist. Did you get the wrong url or was the server deleted?') + } else if (text.includes("You do not have permission to access this resource on this server.")) { + message.reply('The server you are trying to access you do not have perms to view. If you did before the user might of removed you as subuser.') + } else if (text.includes('Gateway Timeout')) { + message.reply('It looks like you are getting a `Gateway Timeout` error. This normally happens when a outage is happening. \nIf nothing is posted in <#738530520945786921> then you might just be having the issue. \nIt should fix its self soon') + } else if (text.includes('instal process')) { + message.reply('It looks like your server might be stuck on installing. Please open a ticket so we can fix this for you.') + } else if (text.includes('invalid ELF header')) { + message.reply('Looks like you might be getting a error about a invalid ELF header on a node.js server. If this is happening please delete `node_modules` folder and let it auto reinstall next time you start the server. This should fix the problem!') + } else if (text.includes(`find module '/home/container/index.js'`)) { + message.reply('Looks like the server cant find a `index.js` file. Please check make sure you uploaded your main file and changed startup prams to make sure the server is starting with the correct file. \nIf that doesnt help please wait for a human to come help you.') + } else if (text.includes('Please try re-compiling or re-installing')) { + message.channel.send('Looks like you might of uploaded your `node_modules` folder. Please delete this folder and when you server starts modules will be auto installed.') + } + })})}} + + function attachIsImage(msgAttach) { + var url = msgAttach.url; + //True if this url is a png image. + return url.indexOf("png", url.length - "png".length /*or 3*/) !== -1; + } - if (message.channel.type == "dm") { - if (message.author.id == "137624084572798976") { - const args = message.content.trim().split(/ +/g); - client.channels.get(args[0]).send(message.content.split(' ').slice(1).join(' ')) - } - }; + if (message.channel.type == "dm") { + if(message.author.id == "137624084572798976") { + const args = message.content.trim().split(/ +/g); + client.channels.get(args[0]).startTyping() + setTimeout(async () => { + client.channels.get(args[0]).send(message.content.split(' ').slice(1).join(' ')) + }, 5000) + client.channels.get(args[0]).stopTyping() + }}; const prefix = config.DiscordBot.Prefix; @@ -54,18 +72,13 @@ module.exports = (client, message) => { const commandargs = message.content.split(' ').slice(1).join(' '); const command = args.shift().toLowerCase(); console.log(chalk.magenta("[DISCORD] ") + chalk.yellow(`[${message.author.username}] [${message.author.id}] >> ${prefix}${command} ${commandargs}`)); - try { - let commandFile = require(`../commands/${command}.js`); - commandFile.run(client, message, args); - } catch (err) { - if (err instanceof Error && err.code === "MODULE_NOT_FOUND") { - return; - } - } - - //Requests channel auto react - if (message.channel.id == config.DiscordBot.requestsChannel) { - message.react('✅'); - } + try { + let commandFile = require(`../commands/${command}.js`); + commandFile.run(client, message, args); + } catch (err) { + if (err instanceof Error && err.code === "MODULE_NOT_FOUND") { + return; + } + } }; \ No newline at end of file From a72a64679371159b4da4c87814285157795a51c5 Mon Sep 17 00:00:00 2001 From: danielpmc Date: Sat, 17 Oct 2020 05:15:27 +0100 Subject: [PATCH 050/255] Push more missing updates --- Panel/bot/discord/events/message.js | 3 -- Panel/bot/discord/events/messageDelete.js | 23 +++++++------ Panel/bot/discord/events/messageUpdate.js | 4 ++- Panel/bot/discord/events/ready.js | 41 ++++++----------------- 4 files changed, 26 insertions(+), 45 deletions(-) diff --git a/Panel/bot/discord/events/message.js b/Panel/bot/discord/events/message.js index d67d6b52f..0561c5713 100644 --- a/Panel/bot/discord/events/message.js +++ b/Panel/bot/discord/events/message.js @@ -1,7 +1,4 @@ -//let client = require("../../../../index.js").client; - module.exports = (client, message) => { - //if(message.content.toLowerCase().includes("tiktok")) {message.reply('Ew. Get out here with that crap :bammer:'), message.delete() } if(message.author.id === client.user.id) { return; } else if (message.content.toLowerCase().includes("discord.gg")) { diff --git a/Panel/bot/discord/events/messageDelete.js b/Panel/bot/discord/events/messageDelete.js index 86729b44d..29bd1310d 100644 --- a/Panel/bot/discord/events/messageDelete.js +++ b/Panel/bot/discord/events/messageDelete.js @@ -1,6 +1,6 @@ -//let client = require("../../../../index.js").client; - module.exports = (client, message) => { + if (!message.attachments.size > 0) { + if (message.author.bot) return; if (message.channel.type === 'dm') return; if (message.channel.type !== 'text') return; @@ -9,13 +9,14 @@ module.exports = (client, message) => { const description = message.cleanContent const descriptionfix = description.substr(0, 600); const embed = new Discord.RichEmbed() - .setColor(0x00A2E8) - .setThumbnail(message.author.avatarURL) - .addField("Author ", `${message.author.tag} (ID: ${message.author.id})`) - .addField("Message Content:", `${descriptionfix}`) - .setTimestamp() - .setFooter("Message delete in " + message.channel.name); - client.channels.get(config.DiscordBot.mLogs).send({ - embed - }); + .setColor(0x00A2E8) + .setThumbnail(message.author.avatarURL) + .addField("Author ", `${message.author.tag} (ID: ${message.author.id})`) + .addField("Message Content:", `${descriptionfix}`) + .setTimestamp() + .setFooter("Message delete in " + message.channel.name); + client.channels.get(config.DiscordBot.mLogs).send({embed}); + + } else { + } }; \ No newline at end of file diff --git a/Panel/bot/discord/events/messageUpdate.js b/Panel/bot/discord/events/messageUpdate.js index 6d4a240b5..0ebd427d5 100644 --- a/Panel/bot/discord/events/messageUpdate.js +++ b/Panel/bot/discord/events/messageUpdate.js @@ -5,7 +5,9 @@ module.exports = (client, message, editedMessage) => { editedMessage.delete(); } else if (editedMessage.content.toLowerCase().includes("discord.com")) { editedMessage.delete() - } + } else if (editedMessage.content.toLowerCase().includes("discordapp.com឵឵")) { + message.delete() + } if (message.author.bot) return; if (message.channel.type === 'dm') return; diff --git a/Panel/bot/discord/events/ready.js b/Panel/bot/discord/events/ready.js index 13a5de7a3..4c964512e 100644 --- a/Panel/bot/discord/events/ready.js +++ b/Panel/bot/discord/events/ready.js @@ -43,40 +43,26 @@ module.exports = async (client, guild, files) => { }); }); - //const ticketCategory = await client.guilds.get("639477525927690240").fetch('654313162086285323') - // console.log(ticketCategory.children.size) - + //Voice channel stats updator setInterval(async () => { let guild1 = await client.guilds.get("639477525927690240").fetchMembers(); let roleID1 = '748117822370086932'; let staffCount = guild1.roles.get(roleID1).members.size; - client.channels.get("739821419910791348").edit({ - name: `Staff: ${staffCount}`, - reason: "Staff count update" - }); - + client.channels.get("739821419910791348").edit({ name: `Staff: ${staffCount}`, reason: "Staff count update" }); + let guild2 = await client.guilds.get("639477525927690240").fetchMembers(); let roleID2 = '639490038434103306'; let memberCount = guild2.roles.get(roleID2).members.size; - client.channels.get("739821366991257621").edit({ - name: `Members: ${memberCount}`, - reason: "Member count update" - }); - + client.channels.get("739821366991257621").edit({ name: `Members: ${memberCount}`, reason: "Member count update" }); + let guild3 = await client.guilds.get("639477525927690240").fetchMembers(); let roleID3 = '704467807122882562'; let botCount = guild3.roles.get(roleID3).members.size; - client.channels.get("739821468296413254").edit({ - name: `Bots: ${botCount}`, - reason: "Bot count update" - }); + client.channels.get("739821468296413254").edit({ name: `Bots: ${botCount}`, reason: "Bot count update" }); let guild4 = await client.guilds.get("639477525927690240") - const ticketcount = guild4.channels.filter(x => x.name.endsWith("-ticket")).size - client.channels.get("739821447924416562").edit({ - name: `Tickets: ${ticketcount}`, - reaon: "Ticket count update" - }) + const ticketcount = guild4.channels.filter(x=> x.name.endsWith("-ticket")).size + client.channels.get("739821447924416562").edit({ name: `Tickets: ${ticketcount}`, reason: "Ticket count update"}) axios({ url: config.Pterodactyl.hosturl + "/api/application/servers", @@ -89,10 +75,7 @@ module.exports = async (client, guild, files) => { 'Accept': 'Application/vnd.pterodactyl.v1+json', } }).then(response => { - client.channels.get("757199549977722890").edit({ - name: `Servers Hosting: ${response.data.meta.pagination.total}`, - reaon: "Server count update" - }) + client.channels.get("757199549977722890").edit({ name: `Servers Hosting: ${response.data.meta.pagination.total}`, reason: "Server count update"}) }); axios({ @@ -106,10 +89,8 @@ module.exports = async (client, guild, files) => { 'Accept': 'Application/vnd.pterodactyl.v1+json', } }).then(response => { - client.channels.get("757222585015599214").edit({ - name: `Clients Hosting: ${response.data.meta.pagination.total}`, - reaon: "Client count update" - }) + client.channels.get("757222585015599214").edit({ name: `Clients Hosting: ${response.data.meta.pagination.total}`, reason: "Client count update"}) }); + client.channels.get("758746579636191382").edit({ name: `Boosts: ${client.guilds.get("639477525927690240").premiumSubscriptionCount}`, reason: "Boosts count update" }) }, 30000); }; \ No newline at end of file From 6d8306a03466f15f19bbbe8a8f766386dd9209cf Mon Sep 17 00:00:00 2001 From: danielpmc Date: Sat, 17 Oct 2020 05:22:44 +0100 Subject: [PATCH 051/255] Changed auto activities to be near the list. --- Panel/bot/discord/events/ready.js | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Panel/bot/discord/events/ready.js b/Panel/bot/discord/events/ready.js index 4c964512e..d33aba4e6 100644 --- a/Panel/bot/discord/events/ready.js +++ b/Panel/bot/discord/events/ready.js @@ -17,6 +17,12 @@ module.exports = async (client, guild, files) => { "type": "WATCHING" } ]; + setInterval(() => { + const activity = activities[Math.floor(Math.random() * activities.length)]; + client.user.setActivity(activity.text, { + type: activity.type + }); + }, 30000); //Reaction-Roles: let rChannel = client.channels.get(client.reactionRoles.channel); @@ -29,12 +35,6 @@ module.exports = async (client, guild, files) => { await rMessage.react(reaction); } // end of Reaction-Roles - setInterval(() => { - const activity = activities[Math.floor(Math.random() * activities.length)]; - client.user.setActivity(activity.text, { - type: activity.type - }); - }, 30000); global.invites = {}; client.guilds.forEach(g => { @@ -43,7 +43,7 @@ module.exports = async (client, guild, files) => { }); }); - //Voice channel stats updator + //Voice channel stats setInterval(async () => { let guild1 = await client.guilds.get("639477525927690240").fetchMembers(); let roleID1 = '748117822370086932'; From 26dd146a5500529c130ea820aba7be477edfc179 Mon Sep 17 00:00:00 2001 From: danielpmc Date: Sat, 17 Oct 2020 05:28:15 +0100 Subject: [PATCH 052/255] Updated logo text --- Daemon/index.js | 9 +++++++++ Panel/index.js | 14 +++++++------- 2 files changed, 16 insertions(+), 7 deletions(-) diff --git a/Daemon/index.js b/Daemon/index.js index eef7c766d..dee2942e9 100644 --- a/Daemon/index.js +++ b/Daemon/index.js @@ -1,3 +1,12 @@ +/* + ____ ____ __ __ __ __ _ + / __ \____ _____ / __ )____ / /_ / / / /___ _____/ /_(_)___ ____ _ + / / / / __ `/ __ \/ __ / __ \/ __/ / /_/ / __ \/ ___/ __/ / __ \/ __ `/ + / /_/ / /_/ / / / / /_/ / /_/ / /_ / __ / /_/ (__ ) /_/ / / / / /_/ / +/_____/\__,_/_/ /_/_____/\____/\__/ /_/ /_/\____/____/\__/_/_/ /_/\__, / +Free Hosting for ever! /____/ +*/ + var si = require('systeminformation'); var os = require("os"); var pretty = require('prettysize'); diff --git a/Panel/index.js b/Panel/index.js index c71e43d09..b6fec6cc3 100644 --- a/Panel/index.js +++ b/Panel/index.js @@ -1,10 +1,10 @@ -/* _____ __ __ _ _ - / ____| | \/ | (_)| | - | (___ ___ _ __ __ __ ___ _ __ | \ / | ___ _ __ _ | |_ ___ _ __ - \___ \ / _ \| '__|\ \ / // _ \| '__|| |\/| | / _ \ | '_ \ | || __|/ _ \ | '__| - ____) || __/| | \ V /| __/| | | | | || (_) || | | || || |_| (_) || | - |_____/ \___||_| \_/ \___||_| |_| |_| \___/ |_| |_||_| \__|\___/ |_| - Free Monitoring software made by danielpmc +/* + ____ ____ __ __ __ __ _ + / __ \____ _____ / __ )____ / /_ / / / /___ _____/ /_(_)___ ____ _ + / / / / __ `/ __ \/ __ / __ \/ __/ / /_/ / __ \/ ___/ __/ / __ \/ __ `/ + / /_/ / /_/ / / / / /_/ / /_/ / /_ / __ / /_/ (__ ) /_/ / / / / /_/ / +/_____/\__,_/_/ /_/_____/\____/\__/ /_/ /_/\____/____/\__/_/_/ /_/\__, / +Free Hosting for ever! /____/ */ global.config = require("./config.json"); From 1545c3649a6aab3c2cf6391ac7c9b17a0a428c3b Mon Sep 17 00:00:00 2001 From: danielpmc Date: Sat, 17 Oct 2020 05:31:18 +0100 Subject: [PATCH 053/255] Removed tickets.js --- Panel/bot/discord/commands/tickets.js | 10 ---------- 1 file changed, 10 deletions(-) delete mode 100644 Panel/bot/discord/commands/tickets.js diff --git a/Panel/bot/discord/commands/tickets.js b/Panel/bot/discord/commands/tickets.js deleted file mode 100644 index eba182660..000000000 --- a/Panel/bot/discord/commands/tickets.js +++ /dev/null @@ -1,10 +0,0 @@ -exports.run = async (client, message) => { - const args = message.content.split(' ').slice(1).join(' '); - - if (args == "") { - let embed = new Discord.RichEmbed() - .setColor(`GREEN`) - .addField(`__**Tickets**__`, `Create a new ticket: ${config.DiscordBot.Prefix}ticket new \nNeed to close a ticket? ${config.DiscordBot.Prefix}ticket close`, true); - message.channel.send(embed) - } -}; \ No newline at end of file From 78261c8ea146f0c9c7bb80cd1e9ce8304e3cf7d4 Mon Sep 17 00:00:00 2001 From: danielpmc Date: Sat, 17 Oct 2020 05:40:08 +0100 Subject: [PATCH 054/255] Enabled no args message on server.js --- Panel/bot/discord/commands/server.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Panel/bot/discord/commands/server.js b/Panel/bot/discord/commands/server.js index e3cff6ec4..e2a3073e1 100644 --- a/Panel/bot/discord/commands/server.js +++ b/Panel/bot/discord/commands/server.js @@ -2,12 +2,13 @@ const axios = require('axios'); exports.run = async (client, message, args) => { const otherargs = message.content.split(' ').slice(3).join(' '); if (userData.get(message.author.id) == null) { - message.channel.send("This account is not linked. Please link it using `" + config.DiscordBot.Prefix + "link`, then retry this command") + message.channel.send("Oh no, Seems like you do not have an account linked to your discord ID. \nIf you have not made an account yet please check out `" + config.DiscordBot.prefix + "getstarted` to create an account \nIf you already have an account link it using `" + config.DiscordBot.Prefix + "link`") } else { if (!args[0]) { //No args let embed = new Discord.RichEmbed() - .setTitle('__**Commands**__ \n' + config.DiscordBot.Prefix + 'server create type servername \n' + config.DiscordBot.Prefix + 'server list') + .setTitle('__**Commands**__ \nCreate a server: `' + config.DiscordBot.Prefix + 'server create type servername` \nServer Types: `' + config.DiscordBot.Prefix + 'server create list`') + message.channel.send(embed) } else if (args[0].toLowerCase() == "create") { //Do server creation things From 9fa3605f56ef2792deea9bb8f1858da258d445c0 Mon Sep 17 00:00:00 2001 From: danielpmc Date: Sat, 17 Oct 2020 05:49:28 +0100 Subject: [PATCH 055/255] Fixed a missing ` ` on a command --- Panel/bot/discord/commands/ticket.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Panel/bot/discord/commands/ticket.js b/Panel/bot/discord/commands/ticket.js index cb8672d69..b44e8a70c 100644 --- a/Panel/bot/discord/commands/ticket.js +++ b/Panel/bot/discord/commands/ticket.js @@ -8,8 +8,8 @@ exports.run = async (client, message) => { .addField(`__**Tickets**__`, 'You can create a new ticket by typing: `' + config.DiscordBot.Prefix + 'ticket new` \nYou can download your old tickets by running: `' + config.DiscordBot.Prefix + 'ticket logs` \nYou can close your ticket by running: `' + - config.DiscordBot.Prefix + 'ticket close` \nYou can upgrade your ticket by running:' + - config.DiscordBot.Prefix + 'ticket upgrade \n\nAny problems? Please send a message in <#640158951899398144>' , true); + config.DiscordBot.Prefix + 'ticket close` \nYou can upgrade your ticket by running:`' + + config.DiscordBot.Prefix + 'ticket upgrade` \n\nAny problems? Please send a message in <#640158951899398144>' , true); message.channel.send(embed) } else if (args == "new") { From 1aedf00c8f1ed682b2664afa063a424a30d945db Mon Sep 17 00:00:00 2001 From: danielpmc Date: Sat, 17 Oct 2020 05:50:50 +0100 Subject: [PATCH 056/255] More missing " " lmao --- Panel/bot/discord/commands/ticket.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Panel/bot/discord/commands/ticket.js b/Panel/bot/discord/commands/ticket.js index b44e8a70c..df2360db3 100644 --- a/Panel/bot/discord/commands/ticket.js +++ b/Panel/bot/discord/commands/ticket.js @@ -102,7 +102,7 @@ exports.run = async (client, message) => { } else if (args == "upgrade") { if (message.channel.name.includes('-ticket')) { message.reply("Only admins can see this ticket now.") - message.channel.overwritePermissions(748117822370086932, { + message.channel.overwritePermissions("748117822370086932", { VIEW_CHANNEL: false, SEND_MESSAGES: false, READ_MESSAGE_HISTORY: false From 15645cf8332d69bc8a0429f4b6798a25d29b9ff0 Mon Sep 17 00:00:00 2001 From: danielpmc Date: Sat, 17 Oct 2020 06:03:01 +0100 Subject: [PATCH 057/255] If main ticket category is full. use backup --- Panel/bot/discord/commands/ticket.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Panel/bot/discord/commands/ticket.js b/Panel/bot/discord/commands/ticket.js index df2360db3..137b0d5de 100644 --- a/Panel/bot/discord/commands/ticket.js +++ b/Panel/bot/discord/commands/ticket.js @@ -36,7 +36,10 @@ exports.run = async (client, message) => { let category = server.channels.find(c => c.id == "738538742603841650" && c.type == "category"); if (!category) throw new Error("Category channel does not exist"); - await channel.setParent(category.id).catch(console.error); + let categorybackup = server.channels.find(c => c.id == "741082659610034257" && c.type == "category"); + if (!categorybackup) throw new Error("Category channel does not exist"); + + await channel.setParent(category.id).catch(channel.setParent(categorybackup.id).catch(console.error)); channel.overwritePermissions(message.author, { VIEW_CHANNEL: true, From 76f0c94f24079e60a3927bc3d1b6fa08768a7175 Mon Sep 17 00:00:00 2001 From: danielpmc Date: Sat, 17 Oct 2020 06:05:45 +0100 Subject: [PATCH 058/255] remove the 2nd @ --- Panel/bot/discord/commands/ticket.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Panel/bot/discord/commands/ticket.js b/Panel/bot/discord/commands/ticket.js index 137b0d5de..9c815805d 100644 --- a/Panel/bot/discord/commands/ticket.js +++ b/Panel/bot/discord/commands/ticket.js @@ -48,7 +48,7 @@ exports.run = async (client, message) => { }) if (userData.get(message.author.id) == null) { - channel.send('@<@' + message.author.id + '> here is your ticket! Please give as much info as possible about your problem. \n\n *This account is not linked with a console account*') + channel.send('<@' + message.author.id + '> here is your ticket! Please give as much info as possible about your problem. \n\n *This account is not linked with a console account*') } else { let embed = new Discord.RichEmbed() .setColor(`GREEN`) From 9e77aa9d252e11ec543d64668da1619c1942f430 Mon Sep 17 00:00:00 2001 From: danielpmc Date: Sat, 17 Oct 2020 15:20:01 +0100 Subject: [PATCH 059/255] Update stats command --- .gitignore | 1 + Panel/bot/discord/commands/stats.js | 36 ++++++++++------------------- 2 files changed, 13 insertions(+), 24 deletions(-) diff --git a/.gitignore b/.gitignore index 484f77266..1b66118c5 100644 --- a/.gitignore +++ b/.gitignore @@ -7,6 +7,7 @@ Panel/config.json Panel/json.sqlite Panel/images Panel/start.bat +Panel/eng.traineddata Daemon/node_modules Daemon/package-lock.json diff --git a/Panel/bot/discord/commands/stats.js b/Panel/bot/discord/commands/stats.js index a562440e5..a39d7ad44 100644 --- a/Panel/bot/discord/commands/stats.js +++ b/Panel/bot/discord/commands/stats.js @@ -1,30 +1,18 @@ -exports.run = async (client, message) => { - +exports.run = async(client, message) => { + //Sends message while the json's are being cached let embed = new Discord.RichEmbed() - .setColor(`RANDOM`) - .addField(`__**Please wait...**__`, `Loading all node's stats! (If this takes longer than 5seconds. This command is broken)`, true); + .setColor(`RANDOM`) + .addField(`__**Please wait...**__`, `Loading all node's stats! (If this takes longer than 5seconds. This command is broken)`, true); let msg = await message.channel.send(embed) - //Data for node 1 - var N1 = fs.readFileSync('./data/Node1.json', 'utf8'); - var Node1Data = JSON.parse(N1); - - //Data for node 2 - var N2 = fs.readFileSync('./data/Node2.json', 'utf8'); - var Node2Data = JSON.parse(N2); - - //Data for node 3 - var N3 = fs.readFileSync('./data/vmi450443.contaboserver.net.json', 'utf8'); - var Node3Data = JSON.parse(N3); - //Edits the message to display the data - embed.fields.pop() - embed.addField("\u200b", "__**[Node 1 - Discord Bots](https://danbot.host/Node1)**__ \n**CPU LOAD**: " + Node1Data.cpuload + "% \n**RAM (USED/TOTAL)**: " + Node1Data.memused + " / " + Node1Data.memtotal + " \n**STORAGE (USED/TOTAL)**: " + Node1Data.diskused + " / " + Node1Data.disktotal + " \n**UPTIME**: " + Node1Data.osuptime) - embed.addField('\u200b', '\u200b') - embed.addField("\u200b", "__**[Node 2 - Discord Bots](https://danbot.host/Node2)**__ \n**CPU LOAD**: " + Node2Data.cpuload + "% \n**RAM (USED/TOTAL)**: " + Node2Data.memused + " / " + Node2Data.memtotal + " \n**STORAGE (USED/TOTAL)**: " + Node2Data.diskused + " / " + Node2Data.disktotal + " \n**UPTIME**: " + Node2Data.osuptime) - embed.addField('\u200b', '\u200b') - embed.addField("\u200b", "__**[Node 3 - Gaming](https://danbot.host/Node3)**__ \n**CPU LOAD**: " + Node3Data.cpuload + "% \n**RAM (USED/TOTAL)**: " + Node3Data.memused + " / " + Node3Data.memtotal + " \n**STORAGE (USED/TOTAL)**: " + Node3Data.diskused + " / " + Node3Data.disktotal + " \n**UPTIME**: " + Node3Data.osuptime) - embed.setDescription('Want to view more stats live? [Click Here!](https://danbot.host/stats)') - msg.edit(embed); + embed.fields.pop() + embed.addField("\u200b", "__**[Node 1 - Discord Bots](https://danbot.host/Node1)**__ \n**CPU LOAD**: " + nodeData.fetch("Node1.cpuload") + "% \n**RAM (USED/TOTAL)**: " + nodeData.fetch("Node1.memused") + " / " + nodeData.fetch("Node1.memtotal") + " \n**STORAGE (USED/TOTAL)**: " + nodeData.fetch("Node1.diskused") + " / " + nodeData.fetch("Node1.disktotal") + " \n**UPTIME**: " + nodeData.fetch("Node1.osuptime") + "\n**Servers:** **Total**: " + nodeData.fetch("Node1.dockercontainers") + ", **Running**: " + nodeData.fetch("Node1.dockercontainersrunning") + ", **Stopped**: " + nodeData.fetch("Node1.dockercontainersstopped")) + embed.addField('\u200b', '\u200b') + embed.addField("\u200b", "__**[Node 2 - Discord Bots](https://danbot.host/Node2)**__ \n**CPU LOAD**: " + nodeData.fetch("Node2.cpuload") + "% \n**RAM (USED/TOTAL)**: " + nodeData.fetch("Node2.memused") + " / " + nodeData.fetch("Node2.memtotal") + " \n**STORAGE (USED/TOTAL)**: " + nodeData.fetch("Node2.diskused") + " / " + nodeData.fetch("Node2.disktotal") + " \n**UPTIME**: " + nodeData.fetch("Node2.osuptime") + "\n**Servers**: **Total**: " + nodeData.fetch("Node2.dockercontainers") + ", **Running**: " + nodeData.fetch("Node2.dockercontainersrunning") + ", **Stopped**: " + nodeData.fetch("Node2.dockercontainersstopped")) + embed.addField('\u200b', '\u200b') + embed.addField("\u200b", "__**[Node 3 - Gaming](https://danbot.host/Node3)**__ \n**CPU LOAD**: " + nodeData.fetch("Node3.cpuload") + "% \n**RAM (USED/TOTAL)**: " + nodeData.fetch("Node3.memused") + " / " + nodeData.fetch("Node3.memtotal") + " \n**STORAGE (USED/TOTAL)**: " + nodeData.fetch("Node3.diskused") + " / " + nodeData.fetch("Node3.disktotal") + " \n**UPTIME**: " + nodeData.fetch("Node3.osuptime") + "\n**Servers**: **Total**: " + nodeData.fetch("Node3.dockercontainers") + ", **Running**: " + nodeData.fetch("Node3.dockercontainersrunning") + ", **Stopped**: " + nodeData.fetch("Node3.dockercontainersstopped")) + embed.setDescription('Want to view more stats live? [Click Here!](https://danbot.host/stats)') + msg.edit(embed); }; \ No newline at end of file From 356d096b1542dae127a52e9e72f0b3db61730a52 Mon Sep 17 00:00:00 2001 From: danielpmc Date: Sun, 18 Oct 2020 15:21:07 +0100 Subject: [PATCH 060/255] Update index as i added a UK node, Disabled link again, Added new node to stats and disabled commands in some channels --- .gitignore | 2 + Daemon/config.json | 9 +- Panel/bot/discord/commands/link.js | 413 ++++++++++++++-------------- Panel/bot/discord/commands/stats.js | 2 + Panel/bot/discord/events/message.js | 8 + Panel/index.js | 2 +- 6 files changed, 217 insertions(+), 219 deletions(-) diff --git a/.gitignore b/.gitignore index 1b66118c5..b889b3f85 100644 --- a/.gitignore +++ b/.gitignore @@ -11,3 +11,5 @@ Panel/eng.traineddata Daemon/node_modules Daemon/package-lock.json + +Test/* \ No newline at end of file diff --git a/Daemon/config.json b/Daemon/config.json index e2688b3cc..36602c17f 100644 --- a/Daemon/config.json +++ b/Daemon/config.json @@ -1,6 +1,6 @@ { - "panelip": "154.27.68.232", - "panelport": "1144", + "panelip": "danbot.host", + "panelport": "80", "debug": true, "panelping": true, "panelms": 5000, @@ -10,10 +10,5 @@ "Discord": false, "DiscordWebhook": "No webhook token", - "SystemIPs": [ - "192.168.1.175", - "173.249.33.82" - ], - "Docker": false } \ No newline at end of file diff --git a/Panel/bot/discord/commands/link.js b/Panel/bot/discord/commands/link.js index 0e228cd97..6678858f8 100644 --- a/Panel/bot/discord/commands/link.js +++ b/Panel/bot/discord/commands/link.js @@ -4,6 +4,7 @@ const moment = require("moment"); const axios = require('axios'); exports.run = async (client, message) => { const args = message.content.split(' ').slice(1).join(' '); + if (message.member.roles.find(r => r.id === "639481606112804875")) { if (userData.get(message.author.id) == null) { @@ -42,222 +43,212 @@ exports.run = async (client, message) => { .setFooter("You can type 'cancel' to cancel the request \n**This will take a few seconds to find your account.**") }) - const collector = new Discord.MessageCollector(channel, m => m.author.id === message.author.id, { - time: 60000 - }); + const collector = new Discord.MessageCollector(channel, m => m.author.id === message.author.id, { time: 60000 }); collector.on('collect', message => { //console.log(message.content) - - if (message.content === 'cancel') { - return msg.edit("Request to link your account canceled.", null).then(channel.delete()) + + if (message.content === 'cancel') { + return msg.edit("Request to link your account canceled.", null).then(channel.delete()) + } + + //Page 1 + axios({ + url: config.Pterodactyl.hosturl + "/api/application/users", + method: 'GET', + followRedirect: true, + maxRedirects: 5, + headers: { + 'Authorization': 'Bearer ' + config.Pterodactyl.apikey, + 'Content-Type': 'application/json', + 'Accept': 'Application/vnd.pterodactyl.v1+json', } - - //Page 1 - axios({ - url: config.Pterodactyl.hosturl + "/api/application/users", - method: 'GET', - followRedirect: true, - maxRedirects: 5, - headers: { - 'Authorization': 'Bearer ' + config.Pterodactyl.apikey, - 'Content-Type': 'application/json', - 'Accept': 'Application/vnd.pterodactyl.v1+json', - } - }).then(response1 => { - //console.log(consoleUserPage1) - - //Page 2 - axios({ - url: config.Pterodactyl.hosturl + "/api/application/users?page=2", - method: 'GET', - followRedirect: true, - maxRedirects: 5, - headers: { - 'Authorization': 'Bearer ' + config.Pterodactyl.apikey, - 'Content-Type': 'application/json', - 'Accept': 'Application/vnd.pterodactyl.v1+json', - } - }).then(response2 => { - //console.log(consoleUserPage2) - - //Page 3 - axios({ - url: config.Pterodactyl.hosturl + "/api/application/users?page=3", - method: 'GET', - followRedirect: true, - maxRedirects: 5, - headers: { - 'Authorization': 'Bearer ' + config.Pterodactyl.apikey, - 'Content-Type': 'application/json', - 'Accept': 'Application/vnd.pterodactyl.v1+json', - } - }).then(response3 => { - //console.log(consoleUserPage3) - - //Page 4 - axios({ - url: config.Pterodactyl.hosturl + "/api/application/users?page=4", - method: 'GET', - followRedirect: true, - maxRedirects: 5, - headers: { - 'Authorization': 'Bearer ' + config.Pterodactyl.apikey, - 'Content-Type': 'application/json', - 'Accept': 'Application/vnd.pterodactyl.v1+json', - } - }).then(response4 => { - //console.log(consoleUserPage4) - - //Page 5 - axios({ - url: config.Pterodactyl.hosturl + "/api/application/users?page=5", - method: 'GET', - followRedirect: true, - maxRedirects: 5, - headers: { - 'Authorization': 'Bearer ' + config.Pterodactyl.apikey, - 'Content-Type': 'application/json', - 'Accept': 'Application/vnd.pterodactyl.v1+json', - } - }).then(response5 => { - //console.log(consoleUserPage5) - - //Page 6 - axios({ - url: config.Pterodactyl.hosturl + "/api/application/users?page=6", - method: 'GET', - followRedirect: true, - maxRedirects: 5, - headers: { - 'Authorization': 'Bearer ' + config.Pterodactyl.apikey, - 'Content-Type': 'application/json', - 'Accept': 'Application/vnd.pterodactyl.v1+json', - } - }).then(response6 => { - //console.log(consoleUserPage6) - - //Page 7 - axios({ - url: config.Pterodactyl.hosturl + "/api/application/users?page=7", - method: 'GET', - followRedirect: true, - maxRedirects: 5, - headers: { - 'Authorization': 'Bearer ' + config.Pterodactyl.apikey, - 'Content-Type': 'application/json', - 'Accept': 'Application/vnd.pterodactyl.v1+json', - } - }).then(response7 => { - //console.log(consoleUserPage7) - - //Page 8 - axios({ - url: config.Pterodactyl.hosturl + "/api/application/users?page=8", - method: 'GET', - followRedirect: true, - maxRedirects: 5, - headers: { - 'Authorization': 'Bearer ' + config.Pterodactyl.apikey, - 'Content-Type': 'application/json', - 'Accept': 'Application/vnd.pterodactyl.v1+json', - } - }).then(response8 => { - //console.log(consoleUserPage8) - - //Page 9 - axios({ - url: config.Pterodactyl.hosturl + "/api/application/users?page=9", - method: 'GET', - followRedirect: true, - maxRedirects: 5, - headers: { - 'Authorization': 'Bearer ' + config.Pterodactyl.apikey, - 'Content-Type': 'application/json', - 'Accept': 'Application/vnd.pterodactyl.v1+json', - } - }).then(response9 => { - //console.log(consoleUserPage9) - - //Page 10 - axios({ - url: config.Pterodactyl.hosturl + "/api/application/users?page=10", - method: 'GET', - followRedirect: true, - maxRedirects: 5, - headers: { - 'Authorization': 'Bearer ' + config.Pterodactyl.apikey, - 'Content-Type': 'application/json', - 'Accept': 'Application/vnd.pterodactyl.v1+json', - } - }).then(response10 => { - //console.log(consoleUserPage10) - - //Page 11 - axios({ - url: config.Pterodactyl.hosturl + "/api/application/users?page=11", - method: 'GET', - followRedirect: true, - maxRedirects: 5, - headers: { - 'Authorization': 'Bearer ' + config.Pterodactyl.apikey, - 'Content-Type': 'application/json', - 'Accept': 'Application/vnd.pterodactyl.v1+json', - } - }).then(response11 => { - //console.log(consoleUserPage11) - const bigArr = [...response1.data.data, ...response2.data.data, ...response3.data.data, ...response4.data.data, ...response5.data.data, ...response6.data.data, ...response7.data.data, ...response8.data.data, ...response9.data.data, ...response10.data.data, ...response11.data.data] - const consoleUser = bigArr.find(usr => usr.attributes ? usr.attributes.email == message.content : false); - - if (!consoleUser) { - channel.send('I can\'t find a user with that account!') - } else { - //consoleUser1 = consoleUser[0]; - const timestamp = `${moment().format("HH:mm:ss")}`; - const datestamp = `${moment().format("YYYY-MM-DD")}`; - userData.set(`${message.author.id}`, { - discordID: message.author.id, - consoleID: consoleUser.attributes.id, - email: consoleUser.attributes.email, - username: consoleUser.attributes.username, - linkTime: timestamp, - linkDate: datestamp - }); - - let embedstaff = new Discord.RichEmbed() - .setColor('Green') - .addField('__**Linked Discord account:**__', message.author.id) - .addField('__**Linked Console account email:**__', consoleUser.attributes.email) - .addField('__**Linked At: (TIME / DATE)**__', timestamp + " / " + datestamp) - .addField('__**Linked Console username:**__', consoleUser.attributes.username) - .addField('__**Linked Console ID:**__', consoleUser.attributes.id) - - channel.send("Account linked! You can now create server's and use other features on this bot!").then( - client.channels.get(config.DiscordBot.oLogs).send(`<@${message.author.id}> linked their account. Heres some info: `, embedstaff), - setTimeout(() => { - channel.delete(); - }, 5000) - ); - - }; - }) - }) - }) - }) - }) - }) - }) - }) - }) - }) - }) - }); - } else { - let embed = new Discord.RichEmbed() + }).then(response1 => { + //console.log(consoleUserPage1) + + //Page 2 + axios({ + url: config.Pterodactyl.hosturl + "/api/application/users?page=2", + method: 'GET', + followRedirect: true, + maxRedirects: 5, + headers: { + 'Authorization': 'Bearer ' + config.Pterodactyl.apikey, + 'Content-Type': 'application/json', + 'Accept': 'Application/vnd.pterodactyl.v1+json', + } + }).then(response2 => { + //console.log(consoleUserPage2) + + //Page 3 + axios({ + url: config.Pterodactyl.hosturl + "/api/application/users?page=3", + method: 'GET', + followRedirect: true, + maxRedirects: 5, + headers: { + 'Authorization': 'Bearer ' + config.Pterodactyl.apikey, + 'Content-Type': 'application/json', + 'Accept': 'Application/vnd.pterodactyl.v1+json', + } + }).then(response3 => { + //console.log(consoleUserPage3) + + //Page 4 + axios({ + url: config.Pterodactyl.hosturl + "/api/application/users?page=4", + method: 'GET', + followRedirect: true, + maxRedirects: 5, + headers: { + 'Authorization': 'Bearer ' + config.Pterodactyl.apikey, + 'Content-Type': 'application/json', + 'Accept': 'Application/vnd.pterodactyl.v1+json', + } + }).then(response4 => { + //console.log(consoleUserPage4) + + //Page 5 + axios({ + url: config.Pterodactyl.hosturl + "/api/application/users?page=5", + method: 'GET', + followRedirect: true, + maxRedirects: 5, + headers: { + 'Authorization': 'Bearer ' + config.Pterodactyl.apikey, + 'Content-Type': 'application/json', + 'Accept': 'Application/vnd.pterodactyl.v1+json', + } + }).then(response5 => { + //console.log(consoleUserPage5) + + //Page 6 + axios({ + url: config.Pterodactyl.hosturl + "/api/application/users?page=6", + method: 'GET', + followRedirect: true, + maxRedirects: 5, + headers: { + 'Authorization': 'Bearer ' + config.Pterodactyl.apikey, + 'Content-Type': 'application/json', + 'Accept': 'Application/vnd.pterodactyl.v1+json', + } + }).then(response6 => { + //console.log(consoleUserPage6) + + //Page 7 + axios({ + url: config.Pterodactyl.hosturl + "/api/application/users?page=7", + method: 'GET', + followRedirect: true, + maxRedirects: 5, + headers: { + 'Authorization': 'Bearer ' + config.Pterodactyl.apikey, + 'Content-Type': 'application/json', + 'Accept': 'Application/vnd.pterodactyl.v1+json', + } + }).then(response7 => { + //console.log(consoleUserPage7) + + //Page 8 + axios({ + url: config.Pterodactyl.hosturl + "/api/application/users?page=8", + method: 'GET', + followRedirect: true, + maxRedirects: 5, + headers: { + 'Authorization': 'Bearer ' + config.Pterodactyl.apikey, + 'Content-Type': 'application/json', + 'Accept': 'Application/vnd.pterodactyl.v1+json', + } + }).then(response8 => { + //console.log(consoleUserPage8) + + //Page 9 + axios({ + url: config.Pterodactyl.hosturl + "/api/application/users?page=9", + method: 'GET', + followRedirect: true, + maxRedirects: 5, + headers: { + 'Authorization': 'Bearer ' + config.Pterodactyl.apikey, + 'Content-Type': 'application/json', + 'Accept': 'Application/vnd.pterodactyl.v1+json', + } + }).then(response9 => { + //console.log(consoleUserPage9) + + //Page 10 + axios({ + url: config.Pterodactyl.hosturl + "/api/application/users?page=10", + method: 'GET', + followRedirect: true, + maxRedirects: 5, + headers: { + 'Authorization': 'Bearer ' + config.Pterodactyl.apikey, + 'Content-Type': 'application/json', + 'Accept': 'Application/vnd.pterodactyl.v1+json', + } + }).then(response10 => { + //console.log(consoleUserPage10) + + //Page 11 + axios({ + url: config.Pterodactyl.hosturl + "/api/application/users?page=11", + method: 'GET', + followRedirect: true, + maxRedirects: 5, + headers: { + 'Authorization': 'Bearer ' + config.Pterodactyl.apikey, + 'Content-Type': 'application/json', + 'Accept': 'Application/vnd.pterodactyl.v1+json', + } + }).then(response11 => { + //console.log(consoleUserPage11) + const bigArr = [...response1.data.data, ...response2.data.data, ...response3.data.data, ...response4.data.data, ...response5.data.data, ...response6.data.data, ...response7.data.data, ...response8.data.data, ...response9.data.data, ...response10.data.data, ...response11.data.data] + const consoleUser = bigArr.find(usr => usr.attributes ? usr.attributes.email == message.content : false); + + if (!consoleUser) { + channel.send('I can\'t find a user with that account!') + } else { + //consoleUser1 = consoleUser[0]; + const timestamp = `${moment().format("HH:mm:ss")}`; + const datestamp = `${moment().format("YYYY-MM-DD")}`; + userData.set(`${message.author.id}`, { + discordID: message.author.id, + consoleID: consoleUser.attributes.id, + email: consoleUser.attributes.email, + username: consoleUser.attributes.username, + linkTime: timestamp, + linkDate: datestamp + }); + + let embedstaff = new Discord.RichEmbed() + .setColor('Green') + .addField('__**Linked Discord account:**__', message.author.id) + .addField('__**Linked Console account email:**__', consoleUser.attributes.email) + .addField('__**Linked At: (TIME / DATE)**__', timestamp + " / " + datestamp) + .addField('__**Linked Console username:**__', consoleUser.attributes.username) + .addField('__**Linked Console ID:**__', consoleUser.attributes.id) + + channel.send("Account linked! You can now create server's and use other features on this bot!").then( + client.channels.get(config.DiscordBot.oLogs).send(`<@${message.author.id}> linked their account. Heres some info: `, embedstaff), + setTimeout(() => { + channel.delete(); + }, 5000) + ); + + }; + })})})})})})})})})})}) +}); +} else { + let embed = new Discord.RichEmbed() .setColor(`GREEN`) .addField(`__**Username**__`, userData.fetch(message.author.id + ".username")) .addField(`__**Linked Date (DD/MM/YY)**__`, userData.fetch(message.author.id + ".linkDate")) .addField(`__**Linked Time**__`, userData.fetch(message.author.id + ".linkTime")) - message.channel.send("This account is linked!", embed) - } - + message.channel.send("This account is linked!", embed) +} +} else { + message.channel.send('Command disabled...') +} } \ No newline at end of file diff --git a/Panel/bot/discord/commands/stats.js b/Panel/bot/discord/commands/stats.js index a39d7ad44..767a3c4ce 100644 --- a/Panel/bot/discord/commands/stats.js +++ b/Panel/bot/discord/commands/stats.js @@ -13,6 +13,8 @@ exports.run = async(client, message) => { embed.addField("\u200b", "__**[Node 2 - Discord Bots](https://danbot.host/Node2)**__ \n**CPU LOAD**: " + nodeData.fetch("Node2.cpuload") + "% \n**RAM (USED/TOTAL)**: " + nodeData.fetch("Node2.memused") + " / " + nodeData.fetch("Node2.memtotal") + " \n**STORAGE (USED/TOTAL)**: " + nodeData.fetch("Node2.diskused") + " / " + nodeData.fetch("Node2.disktotal") + " \n**UPTIME**: " + nodeData.fetch("Node2.osuptime") + "\n**Servers**: **Total**: " + nodeData.fetch("Node2.dockercontainers") + ", **Running**: " + nodeData.fetch("Node2.dockercontainersrunning") + ", **Stopped**: " + nodeData.fetch("Node2.dockercontainersstopped")) embed.addField('\u200b', '\u200b') embed.addField("\u200b", "__**[Node 3 - Gaming](https://danbot.host/Node3)**__ \n**CPU LOAD**: " + nodeData.fetch("Node3.cpuload") + "% \n**RAM (USED/TOTAL)**: " + nodeData.fetch("Node3.memused") + " / " + nodeData.fetch("Node3.memtotal") + " \n**STORAGE (USED/TOTAL)**: " + nodeData.fetch("Node3.diskused") + " / " + nodeData.fetch("Node3.disktotal") + " \n**UPTIME**: " + nodeData.fetch("Node3.osuptime") + "\n**Servers**: **Total**: " + nodeData.fetch("Node3.dockercontainers") + ", **Running**: " + nodeData.fetch("Node3.dockercontainersrunning") + ", **Stopped**: " + nodeData.fetch("Node3.dockercontainersstopped")) + embed.addField('\u200b', '\u200b') + embed.addField("\u200b", "__**[Node 4 - Test](https://danbot.host/Node4)**__ \n**CPU LOAD**: " + nodeData.fetch("Node4.cpuload") + "% \n**RAM (USED/TOTAL)**: " + nodeData.fetch("Node4.memused") + " / " + nodeData.fetch("Node4.memtotal") + " \n**STORAGE (USED/TOTAL)**: " + nodeData.fetch("Node4.diskused") + " / " + nodeData.fetch("Node4.disktotal") + " \n**UPTIME**: " + nodeData.fetch("Node4.osuptime") + "\n**Servers**: **Total**: " + nodeData.fetch("Node4.dockercontainers") + ", **Running**: " + nodeData.fetch("Node4.dockercontainersrunning") + ", **Stopped**: " + nodeData.fetch("Node4.dockercontainersstopped")) embed.setDescription('Want to view more stats live? [Click Here!](https://danbot.host/stats)') msg.edit(embed); }; \ No newline at end of file diff --git a/Panel/bot/discord/events/message.js b/Panel/bot/discord/events/message.js index 0561c5713..2df000840 100644 --- a/Panel/bot/discord/events/message.js +++ b/Panel/bot/discord/events/message.js @@ -70,6 +70,14 @@ module.exports = (client, message) => { const command = args.shift().toLowerCase(); console.log(chalk.magenta("[DISCORD] ") + chalk.yellow(`[${message.author.username}] [${message.author.id}] >> ${prefix}${command} ${commandargs}`)); try { + //Channel checker + if (message.channel.id == "754441222424363088") return; //Lounge + if (message.channel.id == "739231758087880845") return; //Host support + if (message.channel.id == "738839334333186068") return; //Python Support + if (message.channel.id == "738840097218101309") return; //Javascript Support + if (message.channel.id == "738844675372482720") return; //HTML support + if (message.channel.id == "738846229919825992") return; //Java support + let commandFile = require(`../commands/${command}.js`); commandFile.run(client, message, args); } catch (err) { diff --git a/Panel/index.js b/Panel/index.js index b6fec6cc3..116904bf5 100644 --- a/Panel/index.js +++ b/Panel/index.js @@ -142,7 +142,7 @@ server.listen(PORT, function () { global.nodeData = new db.table("nodeData") app.get('/data', function (req, res) { - let nodes = [ "154.27.68.232", "154.27.68.233", "154.27.68.234", "167.86.113.158"]; + let nodes = [ "154.27.68.232", "154.27.68.233", "154.27.68.234", "167.86.113.158", "51.38.69.73"]; if (req.query.servername == undefined) { if (!nodes.includes(req.headers["cf-connecting-ip"])) { res.redirect("/") From 1132137b431c460e3e29ddd1779dca9e04f49ad6 Mon Sep 17 00:00:00 2001 From: danielpmc Date: Sun, 18 Oct 2020 16:46:06 +0100 Subject: [PATCH 061/255] Fix tickets. Assigning perms then moving channel breaaking perms for user to view channel --- Panel/bot/discord/commands/server.js | 32 +++++----------------------- Panel/bot/discord/commands/ticket.js | 13 ++++++----- 2 files changed, 13 insertions(+), 32 deletions(-) diff --git a/Panel/bot/discord/commands/server.js b/Panel/bot/discord/commands/server.js index e2a3073e1..066540e24 100644 --- a/Panel/bot/discord/commands/server.js +++ b/Panel/bot/discord/commands/server.js @@ -301,24 +301,13 @@ exports.run = async (client, message, args) => { .addField(`__**Type:**__`, args[1].toLowerCase()) message.channel.send(embed) }).catch(error => { - if (error.includes("400")) { - const embed = new Discord.RichEmbed() - .setColor('RED') - .addField(`__**ERROR:**__`, "Node is out of ports. \nPlease wait for a host admin to open more ports.") - message.channel.send(embed) - message.channel.send('<@137624084572798976> Assign more ports.') - } else if (error.includes('504')) { - const embed = new Discord.RichEmbed() - .setColor('RED') - .addField(`__**ERROR:**__`, "Node did not respond in time. You could re-run the command or a outage might be happening if this happens multiple times") - message.channel.send(embed) - } else { + let embed1 = new Discord.RichEmbed() .setColor(`RED`) .addField(`__**FAILED:**__`, "Please contact a host admin. \n\nError: `" + error + "`") message.channel.send(embed1) message.channel.send("<@137624084572798976> Issue when creating server. \nResponse: `" + error + "`") - } + }) } } else if (args[1].toLowerCase() === "minecraft.forge") { @@ -345,7 +334,7 @@ exports.run = async (client, message, args) => { "MC_VERSION": "latest" }, "feature_limits": { - "databases": 0, + "databases": 2, "allocations": 1 }, "deploy": { @@ -377,24 +366,13 @@ exports.run = async (client, message, args) => { .addField(`__**Type:**__`, args[1].toLowerCase()) message.channel.send(embed) }).catch(error => { - if (error.includes("400")) { - const embed = new Discord.RichEmbed() - .setColor('RED') - .addField(`__**ERROR:**__`, "Node is out of ports. \nPlease wait for a host admin to open more ports.") - message.channel.send(embed) - message.channel.send('<@137624084572798976> Assign more ports.') - } else if (error.includes('504')) { - const embed = new Discord.RichEmbed() - .setColor('RED') - .addField(`__**ERROR:**__`, "Node did not respond in time. You could re-run the command or a outage might be happening if this happens multiple times") - message.channel.send(embed) - } else { + let embed1 = new Discord.RichEmbed() .setColor(`RED`) .addField(`__**FAILED:**__`, "Please contact a host admin. \n\nError: `" + error + "`") message.channel.send(embed1) message.channel.send("<@137624084572798976> Issue when creating server. \nResponse: `" + error + "`") - } + }) } } else if (args[1].toLowerCase() === "fivem") { diff --git a/Panel/bot/discord/commands/ticket.js b/Panel/bot/discord/commands/ticket.js index 9c815805d..8cb3dccc9 100644 --- a/Panel/bot/discord/commands/ticket.js +++ b/Panel/bot/discord/commands/ticket.js @@ -41,11 +41,14 @@ exports.run = async (client, message) => { await channel.setParent(category.id).catch(channel.setParent(categorybackup.id).catch(console.error)); - channel.overwritePermissions(message.author, { - VIEW_CHANNEL: true, - SEND_MESSAGES: true, - READ_MESSAGE_HISTORY: true - }) + setTimeout(() => { + channel.overwritePermissions(message.author, { + VIEW_CHANNEL: true, + SEND_MESSAGES: true, + READ_MESSAGE_HISTORY: true + }) + + }, 1000) if (userData.get(message.author.id) == null) { channel.send('<@' + message.author.id + '> here is your ticket! Please give as much info as possible about your problem. \n\n *This account is not linked with a console account*') From 96416ebdaf952e3f4ba8c5ccefd2f4d718cc80da Mon Sep 17 00:00:00 2001 From: danielpmc Date: Sun, 18 Oct 2020 22:25:18 +0100 Subject: [PATCH 062/255] Added node 4 to display on the website --- Panel/bot/discord/commands/server.js | 5 ++- Panel/bot/discord/events/message.js | 5 ++- Panel/routes/index.js | 4 ++ Panel/routes/stats.js | 6 +++ Panel/views/node4.ejs | 57 ++++++++++++++++++++++++++++ 5 files changed, 74 insertions(+), 3 deletions(-) create mode 100644 Panel/views/node4.ejs diff --git a/Panel/bot/discord/commands/server.js b/Panel/bot/discord/commands/server.js index 066540e24..7156d7b37 100644 --- a/Panel/bot/discord/commands/server.js +++ b/Panel/bot/discord/commands/server.js @@ -2,7 +2,7 @@ const axios = require('axios'); exports.run = async (client, message, args) => { const otherargs = message.content.split(' ').slice(3).join(' '); if (userData.get(message.author.id) == null) { - message.channel.send("Oh no, Seems like you do not have an account linked to your discord ID. \nIf you have not made an account yet please check out `" + config.DiscordBot.prefix + "getstarted` to create an account \nIf you already have an account link it using `" + config.DiscordBot.Prefix + "link`") + message.channel.send("Oh no, Seems like you do not have an account linked to your discord ID. \nIf you have not made an account yet please check out `" + config.DiscordBot.Prefix + "getstarted` to create an account \nIf you already have an account link it using `" + config.DiscordBot.Prefix + "link`") } else { if (!args[0]) { //No args @@ -331,7 +331,8 @@ exports.run = async (client, message, args) => { }, "environment": { "SERVER_JARFILE": "server.jar", - "MC_VERSION": "latest" + "MC_VERSION": "latest", + "FORGE_VERSION": "1.16.3" }, "feature_limits": { "databases": 2, diff --git a/Panel/bot/discord/events/message.js b/Panel/bot/discord/events/message.js index 2df000840..d209f17c8 100644 --- a/Panel/bot/discord/events/message.js +++ b/Panel/bot/discord/events/message.js @@ -77,7 +77,10 @@ module.exports = (client, message) => { if (message.channel.id == "738840097218101309") return; //Javascript Support if (message.channel.id == "738844675372482720") return; //HTML support if (message.channel.id == "738846229919825992") return; //Java support - + if (message.channel.id == "738548111323955270") { + if (!command == "info") return; + } //Add Your Bot + let commandFile = require(`../commands/${command}.js`); commandFile.run(client, message, args); } catch (err) { diff --git a/Panel/routes/index.js b/Panel/routes/index.js index 000212c46..2b621d8f6 100644 --- a/Panel/routes/index.js +++ b/Panel/routes/index.js @@ -26,6 +26,10 @@ Router.get("/Node3", (req, res) => { res.redirect("/stats/Node3"); }); +Router.get("/Node4", (req, res) => { + res.redirect("/stats/Node4"); +}); + Router.get("/bots", (req, res) => { diff --git a/Panel/routes/stats.js b/Panel/routes/stats.js index f67bf7a42..f98aa94be 100644 --- a/Panel/routes/stats.js +++ b/Panel/routes/stats.js @@ -27,4 +27,10 @@ Router.get("/Node3", (req, res) => { }); }); +Router.get("/Node4", (req, res) => { + res.render('node4.ejs', { layout: false, + user: req.isAuthenticated() ? req.user : null +}); +}); + module.exports = Router; \ No newline at end of file diff --git a/Panel/views/node4.ejs b/Panel/views/node4.ejs new file mode 100644 index 000000000..6ab1ac437 --- /dev/null +++ b/Panel/views/node4.ejs @@ -0,0 +1,57 @@ +<%- include("./partials/header.ejs", { botInfo: false, Title: "Node 4 Stats", Avatar: "", Redirect: "/me" }) %> + + +


+ +


+ + + +
+
+

All Stats

+
+
+
CPU: <%- nodeData.fetch("Node4.cpu") %> (Cores: <%- nodeData.fetch("Node4.cpucores") %>, Threads: <%- nodeData.fetch("Node4.cputhreads") %>)
+
+
+
CPU Load: <%- nodeData.fetch("Node4.cpuload") %>%
+
+
+
RAM (Used/Total) <%- nodeData.fetch("Node4.memused") %> / <%- nodeData.fetch("Node4.memtotal") %>
+
+
+
SWAP (Used/Total) <%- nodeData.fetch("Node4.swapused") %> / <%- nodeData.fetch("Node4.swaptotal") %>
+
+
+
Host storage drive (Used/Total): <%- nodeData.fetch("Node4.diskused") %> / <%- nodeData.fetch("Node4.total") %>
+
+
+
Network: Rx: <%- nodeData.fetch("Node4.netrx") %> Tx: <%- nodeData.fetch("Node4.nettx") %>
+
+
+
Uptime: <%- nodeData.fetch("Node4.osuptime") %>
+
+
+
Last Updated: <%- nodeData.fetch("Node4.updatetime") %>
+
+
+
Speedtest (Updates every 6hours) | Ping: <%- nodeData.fetch("Node4-speedtest.ping") %>ms
Download: <%- nodeData.fetch("Node4-speedtest.download") %>Mbps, Upload: <%- nodeData.fetch("Node4-speedtest.upload") %>Mbps, Last Updated: <%- nodeData.fetch("Node4-speedtest.updatetime") %>
+
+ + + +
\ No newline at end of file From 99910906c5d9dec4fc0a9a897cd208794e54842f Mon Sep 17 00:00:00 2001 From: danielpmc Date: Mon, 19 Oct 2020 02:35:12 +0100 Subject: [PATCH 063/255] Added node4 and fixed disk not showing --- Panel/bot/discord/commands/server.js | 7 ++ Panel/bot/discord/commands/staff.js | 95 ++++++++++++++++++++++++++-- Panel/views/index.ejs | 38 ++++++++++- 3 files changed, 131 insertions(+), 9 deletions(-) diff --git a/Panel/bot/discord/commands/server.js b/Panel/bot/discord/commands/server.js index 7156d7b37..21cdee0fc 100644 --- a/Panel/bot/discord/commands/server.js +++ b/Panel/bot/discord/commands/server.js @@ -12,6 +12,11 @@ exports.run = async (client, message, args) => { } else if (args[0].toLowerCase() == "create") { //Do server creation things + if (!args[1]) { + let embed = new Discord.RichEmbed() + .setTitle('__**Commands**__ \nCreate a server: `' + config.DiscordBot.Prefix + 'server create type servername` \nServer Types: `' + config.DiscordBot.Prefix + 'server create list`') + message.channel.send(embed) + } if (args[1].toLowerCase() === "nodejs") { //Code for nodejs server if (!otherargs) { @@ -468,6 +473,8 @@ exports.run = async (client, message, args) => { } else if (args[0].toLowerCase() == "delete") { //delete server things message.channel.send('Uh this isnt done yet...') + } else if (args[0].toLowerCase() == "manage") { + } }; }; \ No newline at end of file diff --git a/Panel/bot/discord/commands/staff.js b/Panel/bot/discord/commands/staff.js index 014a13d4b..622148a0c 100644 --- a/Panel/bot/discord/commands/staff.js +++ b/Panel/bot/discord/commands/staff.js @@ -1,16 +1,26 @@ exports.run = async (client, message, args) => { - if (!args[0]) { - let embed = new Discord.RichEmbed() - .setColor('RANDOM') - .addField('**Staff Commands:**', config.DiscordBot.Prefix + "staff linked useridhere | Shows if the users account is linked.") - message.channel.send(embed) + if (message.member.roles.find(r => r.id === "748117822370086932")) { + if (!args[0]) { + if (message.member.roles.find(r => r.id === "639489438036000769")) { + let embed = new Discord.RichEmbed() + .setColor('RANDOM') + .addField('**Staff Commands:**', config.DiscordBot.Prefix + "staff linked useridhere | Shows if the users account is linked.") + .addField('**Admin Commands:**', config.DiscordBot.Prefix + "staff apply open/closed | Open or close staff applications. \n" + config.DiscordBot.Prefix + "staff settings | Shows current website settings") + .addField('**Owner Commands:**', config.DiscordBot.Prefix + "staff maintenance on/off | Enable or disable website maintenance.") + message.channel.send(embed) + } else { + let embed = new Discord.RichEmbed() + .setColor('RANDOM') + .addField('**Staff Commands:**', config.DiscordBot.Prefix + "staff linked useridhere | Shows if the users account is linked.") + message.channel.send(embed) + } } else if (message.content.toLowerCase().includes("linked")) { if (args[1] === "") { message.channel.send('Please send a users discord ID to see if they are linked with an account on the host.') } else { if (userData.get(args[1]) == null) { message.channel.send("That account is not linked with a console account :sad:") - } else { + } else { console.log(userData.fetch(args[1])) let embed = new Discord.RichEmbed() .setColor(`GREEN`) @@ -25,5 +35,78 @@ exports.run = async (client, message, args) => { } } else if (message.content.toLowerCase().includes("createserver")) { message.channels.send('Who would you like to create') + } else if (message.content.toLowerCase().includes("apply")) { + if (message.member.roles.find(r => r.id === "639489438036000769")) { + if (args[1] === "") { + message.channel.send("Please run the command using the following format: `" + config.DiscordBot.Prefix + "staff apply open/closed` to enable or disable staff applications") + } else { + if (args[1] === "open") { + webSettings.set("staff-applications", { + enabled: "true" + }); + message.channel.send("Staff applications now open") + } else if (args[1] === "closed") { + webSettings.set("staff-applications", { + enabled: "false" + }); + message.channel.send("Staff applications now closed") + } else { + if (webSettings.fetch("staff-applications.enabled") == "true") { + message.channel.send("Please run the command using the following format: `" + config.DiscordBot.Prefix + "staff apply open/closed` to enable or disable staff applications \n**Staff applications are currently:** **OPEN**"); + } else if (webSettings.fetch("staff-applications.enabled") == "false") { + message.channel.send("Please run the command using the following format: `" + config.DiscordBot.Prefix + "staff apply open/closed` to enable or disable staff applications \n**Staff applications are currently:** **CLOSED**"); + } + }; + }; + }; + } else if (message.content.toLowerCase().includes("settings")) { + if (message.member.roles.find(r => r.id === "639489438036000769")) { + let embed = new Discord.RichEmbed() + .addField('__**Staff Applications Enabled?**__', webSettings.fetch("staff-applications.enabled"), true) + .addField('__**Website maintenance enabled?**__', webSettings.fetch("maintenance.enabled"), true) + message.channel.send(embed) + }; + } else if (message.content.toLowerCase().includes("maintenance")) { + if (message.member.roles.find(r => r.id === "639481606112804875")) { + if (args[1] === "") { + message.channel.send("Please run the command using the following format: `" + config.DiscordBot.Prefix + "staff maintenance on/off` to enable or disable maintenance mode") + } else { + if (args[1] === "off") { + webSettings.set("maintenance", { + enabled: "false" + }); + message.channel.send("Website maintenance mode now **Disabled**") + } else if (args[1] === "on") { + webSettings.set("maintenance", { + enabled: "true" + }); + message.channel.send("Website maintenance mode now **Enabled**") + } else { + if (webSettings.fetch("maintenance.enabled") == "true") { + message.channel.send("Please run the command using the following format: `" + config.DiscordBot.Prefix + "staff maintenance on/off` to enable or disable website maintenance mode \n**Website maintenance mode is currently:** **ENABLED**"); + } else if (webSettings.fetch("maintenance.enabled") == "false") { + message.channel.send("Please run the command using the following format: `" + config.DiscordBot.Prefix + "staff maintenance on/off` to enable or disable website maintenance mode \n**Website maintenance mode is currently:** **DISABLED**"); + }; + }; + }; + } + } else if (message.content.toLowerCase().includes("ticket")) { + + } else if (message.content.toLowerCase().includes("request")) { + if (args[1] === "new") { + if (args[2] === "proxy") { + //Type: Proxy + } + //New request + message.channel.send('Please use the following format: `' + config.DiscordBot.Prefix + "staff request type userid serverid` \nYou can view types by running: `" + config.DiscordBot.Prefix + "staff request types`") + } else if (args[1] === "types") { + //Types + let embed = new Discord.RichEmbed() + .addField('__**Request Types (Type | Type Meaning):**__', "`proxy` | Reverse Proxy \n`password` | Password reset \n`server` | Server creation (If not on createserver) \n`delete` | Server Deletion") + message.channel.send(embed) + } else if (args[1] === "delete") { + //Delete request + } } +}; } \ No newline at end of file diff --git a/Panel/views/index.ejs b/Panel/views/index.ejs index 9106ca5a6..17cb24b51 100644 --- a/Panel/views/index.ejs +++ b/Panel/views/index.ejs @@ -36,7 +36,7 @@
SWAP (Used/Total) <%- nodeData.fetch("Node1.swapused") %> / <%- nodeData.fetch("Node1.swaptotal") %>
-
Host storage drive (Used/Total): <%- nodeData.fetch("Node1.diskused") %> / <%- nodeData.fetch("Node1.total") %>
+
Host storage drive (Used/Total): <%- nodeData.fetch("Node1.diskused") %> / <%- nodeData.fetch("Node1.disktotal") %>
Network: Rx: <%- nodeData.fetch("Node1.netrx") %> Tx: <%- nodeData.fetch("Node1.nettx") %>
@@ -67,7 +67,7 @@
SWAP (Used/Total) <%- nodeData.fetch("Node2.swapused") %> / <%- nodeData.fetch("Node2.swaptotal") %>
-
Host storage drive (Used/Total): <%- nodeData.fetch("Node2.diskused") %> / <%- nodeData.fetch("Node2.total") %>
+
Host storage drive (Used/Total): <%- nodeData.fetch("Node2.diskused") %> / <%- nodeData.fetch("Node2.disktotal") %>
Network: Rx: <%- nodeData.fetch("Node2.netrx") %> Tx: <%- nodeData.fetch("Node2.nettx") %>
@@ -98,7 +98,7 @@
SWAP (Used/Total) <%- nodeData.fetch("Node3.swapused") %> / <%- nodeData.fetch("Node3.swaptotal") %>
-
Host storage drive (Used/Total): <%- nodeData.fetch("Node3.diskused") %> / <%- nodeData.fetch("Node3.total") %>
+
Host storage drive (Used/Total): <%- nodeData.fetch("Node3.diskused") %> / <%- nodeData.fetch("Node3.disktotal") %>
Network: Rx: <%- nodeData.fetch("Node3.netrx") %> Tx: <%- nodeData.fetch("Node3.nettx") %>
@@ -112,6 +112,38 @@
Speedtest (Updates every 6hours) | Ping: <%- nodeData.fetch("Node3-speedtest.ping") %>ms
Download: <%- nodeData.fetch("Node3-speedtest.download") %>Mbps, Upload: <%- nodeData.fetch("Node3-speedtest.upload") %>Mbps, Last Updated: <%- nodeData.fetch("Node3-speedtest.updatetime") %>
+ + +
+
CPU: <%- nodeData.fetch("Node4.cpu") %> (Cores: <%- nodeData.fetch("Node4.cpucores") %>, Threads: <%- nodeData.fetch("Node4.cputhreads") %>)
+
+
+
CPU Load: <%- nodeData.fetch("Node4.cpuload") %>%
+
+
+
RAM (Used/Total) <%- nodeData.fetch("Node4.memused") %> / <%- nodeData.fetch("Node4.memtotal") %>
+
+
+
SWAP (Used/Total) <%- nodeData.fetch("Node4.swapused") %> / <%- nodeData.fetch("Node4.swaptotal") %>
+
+
+
Host storage drive (Used/Total): <%- nodeData.fetch("Node4.diskused") %> / <%- nodeData.fetch("Node4.disktotal") %>
+
+
+
Network: Rx: <%- nodeData.fetch("Node4.netrx") %> Tx: <%- nodeData.fetch("Node4.nettx") %>
+
+
+
Uptime: <%- nodeData.fetch("Node4.osuptime") %>
+
+
+
Last Updated: <%- nodeData.fetch("Node4.updatetime") %>
+
+
+
Speedtest (Updates every 6hours) | Ping: <%- nodeData.fetch("Node4-speedtest.ping") %>ms
Download: <%- nodeData.fetch("Node4-speedtest.download") %>Mbps, Upload: <%- nodeData.fetch("Node4-speedtest.upload") %>Mbps, Last Updated: <%- nodeData.fetch("Node4-speedtest.updatetime") %>
+
+
From f34226388ed16ab9cbea03e9be5f2e1698d1bb93 Mon Sep 17 00:00:00 2001 From: danielpmc Date: Mon, 19 Oct 2020 02:43:23 +0100 Subject: [PATCH 064/255] added git pull --- Panel/bot/discord/commands/staff.js | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/Panel/bot/discord/commands/staff.js b/Panel/bot/discord/commands/staff.js index 622148a0c..c79617ad8 100644 --- a/Panel/bot/discord/commands/staff.js +++ b/Panel/bot/discord/commands/staff.js @@ -1,3 +1,4 @@ +const exec = require('child_process').exec; exports.run = async (client, message, args) => { if (message.member.roles.find(r => r.id === "748117822370086932")) { if (!args[0]) { @@ -107,6 +108,18 @@ exports.run = async (client, message, args) => { } else if (args[1] === "delete") { //Delete request } + } else if (message.content.toLowerCase().includes("update")) { + if (message.member.roles.find(r => r.id === "639481606112804875")) { + exec(`git pull`, (error, stdout) => { + let response = (error || stdout); + if (!error) { + message.channel.send('Pulled from GitHub. Restarting bot') + setTimeout(() => { + process.exit(); + }, 1000) + } + }); + }; } }; } \ No newline at end of file From 52848fca01ce4b717891e4624749de46e2255419 Mon Sep 17 00:00:00 2001 From: danielpmc Date: Mon, 19 Oct 2020 02:47:38 +0100 Subject: [PATCH 065/255] Added pull log --- Panel/bot/discord/commands/staff.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Panel/bot/discord/commands/staff.js b/Panel/bot/discord/commands/staff.js index c79617ad8..b361242c7 100644 --- a/Panel/bot/discord/commands/staff.js +++ b/Panel/bot/discord/commands/staff.js @@ -113,7 +113,7 @@ exports.run = async (client, message, args) => { exec(`git pull`, (error, stdout) => { let response = (error || stdout); if (!error) { - message.channel.send('Pulled from GitHub. Restarting bot') + message.channel.send('Pulled from GitHub. Restarting bot. \n\nLogs: \n' + response) setTimeout(() => { process.exit(); }, 1000) From e85b70de3af036ade01fb68d71bb4b4302b344ec Mon Sep 17 00:00:00 2001 From: danielpmc Date: Mon, 19 Oct 2020 02:49:03 +0100 Subject: [PATCH 066/255] Little update --- Panel/bot/discord/commands/staff.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Panel/bot/discord/commands/staff.js b/Panel/bot/discord/commands/staff.js index b361242c7..dba48c2d8 100644 --- a/Panel/bot/discord/commands/staff.js +++ b/Panel/bot/discord/commands/staff.js @@ -113,10 +113,14 @@ exports.run = async (client, message, args) => { exec(`git pull`, (error, stdout) => { let response = (error || stdout); if (!error) { - message.channel.send('Pulled from GitHub. Restarting bot. \n\nLogs: \n' + response) + if (response.includes("Already up to date.")) { + message.channel.send('Bot already up to date. No changes since last pull') + } else { + message.channel.send('Pulled from GitHub. Restarting bot. \n\nLogs: \n```' + response + "```") setTimeout(() => { process.exit(); }, 1000) + }; } }); }; From b9e5bbad6f0428a4b191d80503631e8e3d72f67e Mon Sep 17 00:00:00 2001 From: danielpmc Date: Mon, 19 Oct 2020 02:57:25 +0100 Subject: [PATCH 067/255] Dumb little message for no perms --- Panel/bot/discord/commands/staff.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Panel/bot/discord/commands/staff.js b/Panel/bot/discord/commands/staff.js index dba48c2d8..9ed7d4049 100644 --- a/Panel/bot/discord/commands/staff.js +++ b/Panel/bot/discord/commands/staff.js @@ -123,7 +123,9 @@ exports.run = async (client, message, args) => { }; } }); - }; + } else { + message.channel.send('ono') + } } }; } \ No newline at end of file From 9ede76a923bb5d05d90c43427f6ae95a69919807 Mon Sep 17 00:00:00 2001 From: danielpmc Date: Mon, 19 Oct 2020 02:58:49 +0100 Subject: [PATCH 068/255] Ignore commit --- Panel/bot/discord/commands/staff.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Panel/bot/discord/commands/staff.js b/Panel/bot/discord/commands/staff.js index 9ed7d4049..aece6583d 100644 --- a/Panel/bot/discord/commands/staff.js +++ b/Panel/bot/discord/commands/staff.js @@ -124,7 +124,7 @@ exports.run = async (client, message, args) => { } }); } else { - message.channel.send('ono') + message.channel.send('OwO') } } }; From 783ab6e0ada8275091ac6b477f8674b03ab9bff6 Mon Sep 17 00:00:00 2001 From: danielpmc Date: Mon, 19 Oct 2020 03:13:37 +0100 Subject: [PATCH 069/255] Test of server status --- Panel/bot/discord/commands/server.js | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/Panel/bot/discord/commands/server.js b/Panel/bot/discord/commands/server.js index 21cdee0fc..f4f08f116 100644 --- a/Panel/bot/discord/commands/server.js +++ b/Panel/bot/discord/commands/server.js @@ -474,7 +474,21 @@ exports.run = async (client, message, args) => { //delete server things message.channel.send('Uh this isnt done yet...') } else if (args[0].toLowerCase() == "manage") { - + message.channel.send('Uh this isnt done yet...') + } else if (args[0].toLowerCase() == "status") { + axios({ + url: config.Pterodactyl.hosturl + "/api/client/servers/" + args[1], + method: 'GET', + followRedirect: true, + maxRedirects: 5, + headers: { + 'Authorization': 'Bearer ' + config.Pterodactyl.apikeyclient, + 'Content-Type': 'application/json', + 'Accept': 'Application/vnd.pterodactyl.v1+json', + } + }).then(response => { + console.log(response.data.attributes) + }); } }; }; \ No newline at end of file From 72f331212af8722abb774d668fa2b5309556a199 Mon Sep 17 00:00:00 2001 From: danielpmc Date: Mon, 19 Oct 2020 03:17:12 +0100 Subject: [PATCH 070/255] test --- Panel/bot/discord/commands/server.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Panel/bot/discord/commands/server.js b/Panel/bot/discord/commands/server.js index f4f08f116..ce231ae6e 100644 --- a/Panel/bot/discord/commands/server.js +++ b/Panel/bot/discord/commands/server.js @@ -487,7 +487,8 @@ exports.run = async (client, message, args) => { 'Accept': 'Application/vnd.pterodactyl.v1+json', } }).then(response => { - console.log(response.data.attributes) + //response.data.attributes - identifier - node - limits - feature_limits (LIMITS: limits: { memory: 0, swap: -1, disk: 5000, io: 500, cpu: 0 }) (Feature_Limits: feature_limits: { databases: 0, allocations: 0, backups: 0 }) + console.log(response.data.attributes.variables.data) }); } }; From 97c84012d5ed59eef2355a1613772c09db77b3b9 Mon Sep 17 00:00:00 2001 From: danielpmc Date: Mon, 19 Oct 2020 03:17:50 +0100 Subject: [PATCH 071/255] Update server.js --- Panel/bot/discord/commands/server.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Panel/bot/discord/commands/server.js b/Panel/bot/discord/commands/server.js index ce231ae6e..4324dc583 100644 --- a/Panel/bot/discord/commands/server.js +++ b/Panel/bot/discord/commands/server.js @@ -488,7 +488,7 @@ exports.run = async (client, message, args) => { } }).then(response => { //response.data.attributes - identifier - node - limits - feature_limits (LIMITS: limits: { memory: 0, swap: -1, disk: 5000, io: 500, cpu: 0 }) (Feature_Limits: feature_limits: { databases: 0, allocations: 0, backups: 0 }) - console.log(response.data.attributes.variables.data) + console.log(response.data.attributes.variables) }); } }; From 8dc161c681f00add89df429748d279aef21c4534 Mon Sep 17 00:00:00 2001 From: danielpmc Date: Mon, 19 Oct 2020 03:52:17 +0100 Subject: [PATCH 072/255] Added new status command for checking server status --- Panel/bot/discord/commands/server.js | 58 +++++++++++++++++++++------- Panel/package.json | 1 + 2 files changed, 44 insertions(+), 15 deletions(-) diff --git a/Panel/bot/discord/commands/server.js b/Panel/bot/discord/commands/server.js index 4324dc583..5181da98e 100644 --- a/Panel/bot/discord/commands/server.js +++ b/Panel/bot/discord/commands/server.js @@ -1,4 +1,5 @@ const axios = require('axios'); +var pretty = require('prettysize'); exports.run = async (client, message, args) => { const otherargs = message.content.split(' ').slice(3).join(' '); if (userData.get(message.author.id) == null) { @@ -7,7 +8,7 @@ exports.run = async (client, message, args) => { if (!args[0]) { //No args let embed = new Discord.RichEmbed() - .setTitle('__**Commands**__ \nCreate a server: `' + config.DiscordBot.Prefix + 'server create type servername` \nServer Types: `' + config.DiscordBot.Prefix + 'server create list`') + .setTitle('__**Commands**__ \nCreate a server: `' + config.DiscordBot.Prefix + 'server create type servername` \nServer Types: `' + config.DiscordBot.Prefix + 'server create list` \nServer Status: `' + config.DiscordBot.Prefix + 'server status serverid`') message.channel.send(embed) } else if (args[0].toLowerCase() == "create") { @@ -476,20 +477,47 @@ exports.run = async (client, message, args) => { } else if (args[0].toLowerCase() == "manage") { message.channel.send('Uh this isnt done yet...') } else if (args[0].toLowerCase() == "status") { - axios({ - url: config.Pterodactyl.hosturl + "/api/client/servers/" + args[1], - method: 'GET', - followRedirect: true, - maxRedirects: 5, - headers: { - 'Authorization': 'Bearer ' + config.Pterodactyl.apikeyclient, - 'Content-Type': 'application/json', - 'Accept': 'Application/vnd.pterodactyl.v1+json', - } - }).then(response => { - //response.data.attributes - identifier - node - limits - feature_limits (LIMITS: limits: { memory: 0, swap: -1, disk: 5000, io: 500, cpu: 0 }) (Feature_Limits: feature_limits: { databases: 0, allocations: 0, backups: 0 }) - console.log(response.data.attributes.variables) - }); + if (!args[1]) { + let embed = new Discord.RichEmbed() + .setColor(`GREEN`) + .addField(`__**Server Status**__`, 'What server would you like to view? Please type: `' + config.DiscordBot.Prefix + 'server status serverid`', true) + message.channel.send(embed) + } else { + axios({ + url: config.Pterodactyl.hosturl + "/api/client/servers/" + args[1], + method: 'GET', + followRedirect: true, + maxRedirects: 5, + headers: { + 'Authorization': 'Bearer ' + config.Pterodactyl.apikeyclient, + 'Content-Type': 'application/json', + 'Accept': 'Application/vnd.pterodactyl.v1+json', + } + }).then(response => { + axios({ + url: config.Pterodactyl.hosturl + "/api/client/servers/" + args[1] + "/resources", + method: 'GET', + followRedirect: true, + maxRedirects: 5, + headers: { + 'Authorization': 'Bearer ' + config.Pterodactyl.apikeyclient, + 'Content-Type': 'application/json', + 'Accept': 'Application/vnd.pterodactyl.v1+json', + } + }).then(resources => { + let embedstatus = new Discord.RichEmbed() + .setColor('GREEN') + .addField('**Status**', resources.data.attributes.current_state, true) + .addField('**CPU Usage**', resources.data.attributes.resources.cpu_absolute + '%') + .addField('**RAM Usage**', pretty(resources.data.attributes.resources.memory_bytes) + ' out of UNLIMITED MB') + .addField('**DISK Usage**', pretty(resources.data.attributes.resources.disk_bytes) + ' out of UNLIMITED MB') + .addField('**NET Usage**', 'UPLOADED: ' + pretty(resources.data.attributes.resources.network_tx_bytes) + ', DOWNLOADED: ' + pretty(resources.data.attributes.resources.network_rx_bytes)) + .addField('\u200b', '\u200b') + .addField('**LIMITS (0 = unlimited)**', 'MEMORY: ' + response.data.attributes.limits.memory + 'MB \nDISK: ' + response.data.attributes.limits.disk + 'GB \nCPU: ' + response.data.attributes.limits.cpu) + .addField('**MISC LIMITS**', 'DATABASES: ' + response.data.attributes.feature_limits.databases + '\nBACKUPS: ' + response.data.attributes.feature_limits.backups) + message.reply(embedstatus) + })}); + } } }; }; \ No newline at end of file diff --git a/Panel/package.json b/Panel/package.json index a71dccadb..492d6df67 100644 --- a/Panel/package.json +++ b/Panel/package.json @@ -43,6 +43,7 @@ "nodemailer": "^6.4.11", "passport": "^0.4.1", "passport-discord": "^0.1.4", + "prettysize": "^2.0.0", "proxmox": "^0.1.0", "pterodactyl.js": "^2.1.1", "puppeteer": "^1.20.0", From f412706dcf19c7995193e22733049eb2e028c8c4 Mon Sep 17 00:00:00 2001 From: danielpmc Date: Mon, 19 Oct 2020 03:52:38 +0100 Subject: [PATCH 073/255] Remove status.js, Not needed --- Panel/bot/discord/commands/status.js | 71 ---------------------------- 1 file changed, 71 deletions(-) delete mode 100644 Panel/bot/discord/commands/status.js diff --git a/Panel/bot/discord/commands/status.js b/Panel/bot/discord/commands/status.js deleted file mode 100644 index 70dbcfd20..000000000 --- a/Panel/bot/discord/commands/status.js +++ /dev/null @@ -1,71 +0,0 @@ -const axios = require('axios'); -exports.run = (client, message) => { - const args = message.content.split(' ').slice(1).join(' '); - - if (args == "") { - let embed = new Discord.RichEmbed() - .setColor(`GREEN`) - .addField(`__**Server Status**__`, 'What server would you like to view? Please type: ' + config.DiscordBot.Prefix + 'status serveridhere', true) - message.channel.send(embed) - - } else { - message.delete(); - - //Send Request - axios({ - url: config.Pterodactyl.hosturl + "/api/application/users", - method: 'GET', - followRedirect: true, - maxRedirects: 5, - headers: { - 'Authorization': 'Bearer ' + config.Pterodactyl.apikey, - 'Content-Type': 'application/json', - 'Accept': 'Application/vnd.pterodactyl.v1+json', - } - }).then(response => { - const data = response.attributes; - - DanBotHostingClient.getServerStatus(args).then((status) => { - DanBotHostingClient.getCPUUsage(args).then(CPUUsageResponse => { - DanBotHostingClient.getRAMUsage(args).then(RAMUsageResponse => { - DanBotHostingClient.getDiskUsage(args).then(DISKUsageResponse => { - DanBotHostingClient.getServerInfo(args).then(InfoResponse => { - if (status == "on") { - if (RAMUsageResponse.limit == "0") { - let embedstatus = new Discord.RichEmbed() - .setColor('GREEN') - .addField('**Server name**', data.name) - .addField('**Status**', `Online :)`, true) - .addField('**CPU Usage**', CPUUsageResponse.current + ' %') - .addField('**RAM Usage**', RAMUsageResponse.current + ' MB out of UNLIMITED MB') - .addField('**DISK Usage**', DISKUsageResponse.current + ' MB out of ' + DISKUsageResponse.limit + ' MB') - .addField('**LIMITS (0 = unlimited)**', 'Memory: ' + InfoResponse.attributes.limits.memory + ' MB, Disk: ' + InfoResponse.attributes.limits.disk + ' MB, CPU Cores: ' + InfoResponse.attributes.limits.cpu) - message.reply(embedstatus) - } else { - let embedstatus = new Discord.RichEmbed() - .setColor('GREEN') - .addField('**Server name**', InfoResponse.attributes.name) - .addField('**Status**', `Online :)`, true) - .addField('**CPU Usage**', CPUUsageResponse.current + ' %') - .addField('**RAM Usage**', RAMUsageResponse.current + ' MB out of ' + RAMUsageResponse.limit + ' MB') - .addField('**DISK Usage**', DISKUsageResponse.current + ' MB out of ' + DISKUsageResponse.limit + ' MB') - .addField('**LIMITS (0 = unlimited)**', 'Memory: ' + InfoResponse.attributes.limits.memory + ' MB, Disk: ' + InfoResponse.attributes.limits.disk + ' MB, CPU Cores: ' + InfoResponse.attributes.limits.cpu) - message.reply(embedstatus) - } - } else if (status == "off") { - let embedstatus = new Discord.RichEmbed() - .setColor('RED') - .addField('**Server name**', InfoResponse.attributes.name) - .addField('**Status**', `Offline :(`) - message.reply(embedstatus) - } - }).catch((error) => { - console.log(error); - }) - }) - }) - }) - }); - }); - }; -}; \ No newline at end of file From 35ed8ee6ec9ecced61c7750f50dd4759465dd9f8 Mon Sep 17 00:00:00 2001 From: danielpmc Date: Mon, 19 Oct 2020 03:59:56 +0100 Subject: [PATCH 074/255] add a error message --- Panel/bot/discord/commands/server.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Panel/bot/discord/commands/server.js b/Panel/bot/discord/commands/server.js index 5181da98e..6a2ccd92f 100644 --- a/Panel/bot/discord/commands/server.js +++ b/Panel/bot/discord/commands/server.js @@ -516,7 +516,10 @@ exports.run = async (client, message, args) => { .addField('**LIMITS (0 = unlimited)**', 'MEMORY: ' + response.data.attributes.limits.memory + 'MB \nDISK: ' + response.data.attributes.limits.disk + 'GB \nCPU: ' + response.data.attributes.limits.cpu) .addField('**MISC LIMITS**', 'DATABASES: ' + response.data.attributes.feature_limits.databases + '\nBACKUPS: ' + response.data.attributes.feature_limits.backups) message.reply(embedstatus) - })}); + }).catch( + message.channel.send('Either the panel is having a issue or im not able to find that server!') + ) + }); } } }; From 8af6d86ec33e801e53d2074a76ee27d86439229c Mon Sep 17 00:00:00 2001 From: danielpmc Date: Mon, 19 Oct 2020 04:00:18 +0100 Subject: [PATCH 075/255] And again --- Panel/bot/discord/commands/server.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Panel/bot/discord/commands/server.js b/Panel/bot/discord/commands/server.js index 6a2ccd92f..8a2794249 100644 --- a/Panel/bot/discord/commands/server.js +++ b/Panel/bot/discord/commands/server.js @@ -519,7 +519,9 @@ exports.run = async (client, message, args) => { }).catch( message.channel.send('Either the panel is having a issue or im not able to find that server!') ) - }); + }).catch( + message.channel.send('Either the panel is having a issue or im not able to find that server!') + ) } } }; From 884379736bcd546135b78fb922556b20d9c7f7f9 Mon Sep 17 00:00:00 2001 From: danielpmc Date: Mon, 19 Oct 2020 04:17:26 +0100 Subject: [PATCH 076/255] Change GB to MB --- Panel/bot/discord/commands/server.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Panel/bot/discord/commands/server.js b/Panel/bot/discord/commands/server.js index 8a2794249..b53bea85a 100644 --- a/Panel/bot/discord/commands/server.js +++ b/Panel/bot/discord/commands/server.js @@ -513,7 +513,7 @@ exports.run = async (client, message, args) => { .addField('**DISK Usage**', pretty(resources.data.attributes.resources.disk_bytes) + ' out of UNLIMITED MB') .addField('**NET Usage**', 'UPLOADED: ' + pretty(resources.data.attributes.resources.network_tx_bytes) + ', DOWNLOADED: ' + pretty(resources.data.attributes.resources.network_rx_bytes)) .addField('\u200b', '\u200b') - .addField('**LIMITS (0 = unlimited)**', 'MEMORY: ' + response.data.attributes.limits.memory + 'MB \nDISK: ' + response.data.attributes.limits.disk + 'GB \nCPU: ' + response.data.attributes.limits.cpu) + .addField('**LIMITS (0 = unlimited)**', 'MEMORY: ' + response.data.attributes.limits.memory + 'MB \nDISK: ' + response.data.attributes.limits.disk + 'MB \nCPU: ' + response.data.attributes.limits.cpu) .addField('**MISC LIMITS**', 'DATABASES: ' + response.data.attributes.feature_limits.databases + '\nBACKUPS: ' + response.data.attributes.feature_limits.backups) message.reply(embedstatus) }).catch( From 10c7966c00cd7a6efec4d9ba97bb2a2043c559ee Mon Sep 17 00:00:00 2001 From: danielpmc Date: Mon, 19 Oct 2020 04:18:45 +0100 Subject: [PATCH 077/255] Remove catch thing. didnt work like expected :( --- Panel/bot/discord/commands/server.js | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/Panel/bot/discord/commands/server.js b/Panel/bot/discord/commands/server.js index b53bea85a..01223e270 100644 --- a/Panel/bot/discord/commands/server.js +++ b/Panel/bot/discord/commands/server.js @@ -516,12 +516,7 @@ exports.run = async (client, message, args) => { .addField('**LIMITS (0 = unlimited)**', 'MEMORY: ' + response.data.attributes.limits.memory + 'MB \nDISK: ' + response.data.attributes.limits.disk + 'MB \nCPU: ' + response.data.attributes.limits.cpu) .addField('**MISC LIMITS**', 'DATABASES: ' + response.data.attributes.feature_limits.databases + '\nBACKUPS: ' + response.data.attributes.feature_limits.backups) message.reply(embedstatus) - }).catch( - message.channel.send('Either the panel is having a issue or im not able to find that server!') - ) - }).catch( - message.channel.send('Either the panel is having a issue or im not able to find that server!') - ) + })}); } } }; From 12f54bef85fc61b9944f1018144d1729d902783c Mon Sep 17 00:00:00 2001 From: danielpmc Date: Mon, 19 Oct 2020 04:40:56 +0100 Subject: [PATCH 078/255] Re-enable linking --- Panel/bot/discord/commands/link.js | 226 +++++++++++++++++++++++---- Panel/bot/discord/commands/linked.js | 13 -- Panel/index.js | 2 +- 3 files changed, 193 insertions(+), 48 deletions(-) delete mode 100644 Panel/bot/discord/commands/linked.js diff --git a/Panel/bot/discord/commands/link.js b/Panel/bot/discord/commands/link.js index 6678858f8..eca10dcdf 100644 --- a/Panel/bot/discord/commands/link.js +++ b/Panel/bot/discord/commands/link.js @@ -4,7 +4,6 @@ const moment = require("moment"); const axios = require('axios'); exports.run = async (client, message) => { const args = message.content.split(' ').slice(1).join(' '); - if (message.member.roles.find(r => r.id === "639481606112804875")) { if (userData.get(message.author.id) == null) { @@ -44,10 +43,10 @@ exports.run = async (client, message) => { }) const collector = new Discord.MessageCollector(channel, m => m.author.id === message.author.id, { time: 60000 }); - collector.on('collect', message => { + collector.on('collect', messagecollected => { //console.log(message.content) - if (message.content === 'cancel') { + if (messagecollected.content === 'cancel') { return msg.edit("Request to link your account canceled.", null).then(channel.delete()) } @@ -204,41 +203,203 @@ exports.run = async (client, message) => { } }).then(response11 => { //console.log(consoleUserPage11) - const bigArr = [...response1.data.data, ...response2.data.data, ...response3.data.data, ...response4.data.data, ...response5.data.data, ...response6.data.data, ...response7.data.data, ...response8.data.data, ...response9.data.data, ...response10.data.data, ...response11.data.data] - const consoleUser = bigArr.find(usr => usr.attributes ? usr.attributes.email == message.content : false); + + //Page 12 + axios({ + url: config.Pterodactyl.hosturl + "/api/application/users?page=12", + method: 'GET', + followRedirect: true, + maxRedirects: 5, + headers: { + 'Authorization': 'Bearer ' + config.Pterodactyl.apikey, + 'Content-Type': 'application/json', + 'Accept': 'Application/vnd.pterodactyl.v1+json', + } + }).then(response12 => { + //console.log(consoleUserPage12) + + //Page 13 + axios({ + url: config.Pterodactyl.hosturl + "/api/application/users?page=13", + method: 'GET', + followRedirect: true, + maxRedirects: 5, + headers: { + 'Authorization': 'Bearer ' + config.Pterodactyl.apikey, + 'Content-Type': 'application/json', + 'Accept': 'Application/vnd.pterodactyl.v1+json', + } + }).then(response13 => { + //console.log(consoleUserPage13) + + //Page 14 + axios({ + url: config.Pterodactyl.hosturl + "/api/application/users?page=14", + method: 'GET', + followRedirect: true, + maxRedirects: 5, + headers: { + 'Authorization': 'Bearer ' + config.Pterodactyl.apikey, + 'Content-Type': 'application/json', + 'Accept': 'Application/vnd.pterodactyl.v1+json', + } + }).then(response14 => { + //console.log(consoleUserPage14) + + //Page 15 + axios({ + url: config.Pterodactyl.hosturl + "/api/application/users?page=15", + method: 'GET', + followRedirect: true, + maxRedirects: 5, + headers: { + 'Authorization': 'Bearer ' + config.Pterodactyl.apikey, + 'Content-Type': 'application/json', + 'Accept': 'Application/vnd.pterodactyl.v1+json', + } + }).then(response15 => { + //console.log(consoleUserPage15) + + //Page 16 + axios({ + url: config.Pterodactyl.hosturl + "/api/application/users?page=16", + method: 'GET', + followRedirect: true, + maxRedirects: 5, + headers: { + 'Authorization': 'Bearer ' + config.Pterodactyl.apikey, + 'Content-Type': 'application/json', + 'Accept': 'Application/vnd.pterodactyl.v1+json', + } + }).then(response16 => { + //console.log(consoleUserPage16) + + //Page 17 + axios({ + url: config.Pterodactyl.hosturl + "/api/application/users?page=17", + method: 'GET', + followRedirect: true, + maxRedirects: 5, + headers: { + 'Authorization': 'Bearer ' + config.Pterodactyl.apikey, + 'Content-Type': 'application/json', + 'Accept': 'Application/vnd.pterodactyl.v1+json', + } + }).then(response17 => { + //console.log(consoleUserPage17) + + //Page 18 + axios({ + url: config.Pterodactyl.hosturl + "/api/application/users?page=18", + method: 'GET', + followRedirect: true, + maxRedirects: 5, + headers: { + 'Authorization': 'Bearer ' + config.Pterodactyl.apikey, + 'Content-Type': 'application/json', + 'Accept': 'Application/vnd.pterodactyl.v1+json', + } + }).then(response18 => { + //console.log(consoleUserPage18) + + //Page 19 + axios({ + url: config.Pterodactyl.hosturl + "/api/application/users?page=19", + method: 'GET', + followRedirect: true, + maxRedirects: 5, + headers: { + 'Authorization': 'Bearer ' + config.Pterodactyl.apikey, + 'Content-Type': 'application/json', + 'Accept': 'Application/vnd.pterodactyl.v1+json', + } + }).then(response19 => { + //console.log(consoleUserPage19) + + //Page 20 + axios({ + url: config.Pterodactyl.hosturl + "/api/application/users?page=20", + method: 'GET', + followRedirect: true, + maxRedirects: 5, + headers: { + 'Authorization': 'Bearer ' + config.Pterodactyl.apikey, + 'Content-Type': 'application/json', + 'Accept': 'Application/vnd.pterodactyl.v1+json', + } + }).then(response20 => { + //console.log(consoleUserPage20) + const bigArr = [...response1.data.data, ...response2.data.data, ...response3.data.data, ...response4.data.data, ...response5.data.data, ...response6.data.data, ...response7.data.data, ...response8.data.data, ...response9.data.data, ...response10.data.data, ...response11.data.data, ...response12.data.data, ...response13.data.data, ...response14.data.data, ...response15.data.data, ...response16.data.data, ...response17.data.data, ...response18.data.data, ...response19.data.data, ...response20.data.data] + const consoleUser = bigArr.find(usr => usr.attributes ? usr.attributes.email == messagecollected.content : false); if (!consoleUser) { channel.send('I can\'t find a user with that account!') } else { - //consoleUser1 = consoleUser[0]; - const timestamp = `${moment().format("HH:mm:ss")}`; - const datestamp = `${moment().format("YYYY-MM-DD")}`; - userData.set(`${message.author.id}`, { - discordID: message.author.id, - consoleID: consoleUser.attributes.id, - email: consoleUser.attributes.email, - username: consoleUser.attributes.username, - linkTime: timestamp, - linkDate: datestamp - }); - let embedstaff = new Discord.RichEmbed() - .setColor('Green') - .addField('__**Linked Discord account:**__', message.author.id) - .addField('__**Linked Console account email:**__', consoleUser.attributes.email) - .addField('__**Linked At: (TIME / DATE)**__', timestamp + " / " + datestamp) - .addField('__**Linked Console username:**__', consoleUser.attributes.username) - .addField('__**Linked Console ID:**__', consoleUser.attributes.id) - - channel.send("Account linked! You can now create server's and use other features on this bot!").then( - client.channels.get(config.DiscordBot.oLogs).send(`<@${message.author.id}> linked their account. Heres some info: `, embedstaff), - setTimeout(() => { - channel.delete(); - }, 5000) - ); + function codegen(length) { + var result = ''; + var characters = '23456789'; + var charactersLength = characters.length; + for ( var i = 0; i < length; i++ ) { + result += characters.charAt(Math.floor(Math.random() * charactersLength)); + } + return result; + } + const code = codegen(10); + + const emailmessage = { + from: config.Email.From, + to: messagecollected.content, + subject: 'DanBot Hosting - Someone tried to link their Discord account!', + html: "Hello, Someone just tried to link their Discord account with this console email address. Here is a verification code that is needed to link: " + code + }; + transport.sendMail(emailmessage, function(err, info) { + if (err) { + console.log(err) + } else { + console.log(info); + channel.send('Please check the email account for a verification code to complete linking. You have 2mins') + + const collector = new Discord.MessageCollector(channel, m => m.author.id === message.author.id, { time: 120000 }); + collector.on('collect', message => { + if (message.content == code) { + const timestamp = `${moment().format("HH:mm:ss")}`; + const datestamp = `${moment().format("YYYY-MM-DD")}`; + userData.set(`${message.author.id}`, { + discordID: message.author.id, + consoleID: consoleUser.attributes.id, + email: consoleUser.attributes.email, + username: consoleUser.attributes.username, + linkTime: timestamp, + linkDate: datestamp + }); + + let embedstaff = new Discord.RichEmbed() + .setColor('Green') + .addField('__**Linked Discord account:**__', message.author.id) + .addField('__**Linked Console account email:**__', consoleUser.attributes.email) + .addField('__**Linked At: (TIME / DATE)**__', timestamp + " / " + datestamp) + .addField('__**Linked Console username:**__', consoleUser.attributes.username) + .addField('__**Linked Console ID:**__', consoleUser.attributes.id) + + channel.send("Account linked!").then( + client.channels.get(config.DiscordBot.oLogs).send(`<@${message.author.id}> linked their account. Heres some info: `, embedstaff), + setTimeout(() => { + channel.delete(); + }, 5000) + ); + } else { + channel.send('Code is incorrect. Linking cancelled!') + setTimeout(() => { + channel.delete(); + }, 2000) + } + }); + } + }); }; - })})})})})})})})})})}) + })})})})})})})})})})})})})})})})})})})}) }); } else { let embed = new Discord.RichEmbed() @@ -248,7 +409,4 @@ exports.run = async (client, message) => { .addField(`__**Linked Time**__`, userData.fetch(message.author.id + ".linkTime")) message.channel.send("This account is linked!", embed) } -} else { - message.channel.send('Command disabled...') -} } \ No newline at end of file diff --git a/Panel/bot/discord/commands/linked.js b/Panel/bot/discord/commands/linked.js deleted file mode 100644 index 303bbbcac..000000000 --- a/Panel/bot/discord/commands/linked.js +++ /dev/null @@ -1,13 +0,0 @@ -exports.run = async (client, message) => { - let result = userData.get(message.author.id) - if (userData.get(message.author.id) == null) { - message.channel.send("You'r account is not linked. Please link you'r account using " + config.DiscordBot.Prefix + "link") - } else { - let embed = new Discord.RichEmbed() - .setColor(`GREEN`) - .addField(`__**Username**__`, userData.fetch(message.author.id + ".username")) - .addField(`__**Date (YYYY/MM/DD)**__`, userData.fetch(message.author.id + ".linkDate")) - .addField(`__**Time**__`, userData.fetch(message.author.id + ".linkTime")) - message.channel.send('Your account is linked. Heres some data: ', embed) - } -}; \ No newline at end of file diff --git a/Panel/index.js b/Panel/index.js index 116904bf5..b75ea0ab4 100644 --- a/Panel/index.js +++ b/Panel/index.js @@ -17,7 +17,7 @@ global.fs = require("fs"); const hbs = require('hbs'); global.chalk = require('chalk'); const nodemailer = require('nodemailer'); -let transport = nodemailer.createTransport({ +global.transport = nodemailer.createTransport({ host: config.Email.Host, port: config.Email.Port, auth: { From f887ce17de32b768bc0c35baaa61e1d9e1ddbb34 Mon Sep 17 00:00:00 2001 From: danielpmc Date: Mon, 19 Oct 2020 04:47:04 +0100 Subject: [PATCH 079/255] remove channel if account is not found --- Panel/bot/discord/commands/link.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Panel/bot/discord/commands/link.js b/Panel/bot/discord/commands/link.js index eca10dcdf..763dc8e12 100644 --- a/Panel/bot/discord/commands/link.js +++ b/Panel/bot/discord/commands/link.js @@ -333,7 +333,10 @@ exports.run = async (client, message) => { const consoleUser = bigArr.find(usr => usr.attributes ? usr.attributes.email == messagecollected.content : false); if (!consoleUser) { - channel.send('I can\'t find a user with that account!') + channel.send('I can\'t find a user with that account! \nRemoving channel!') + setTimeout(() => { + channel.delete(); + }, 5000) } else { function codegen(length) { From 2e772f6e05f090c8e7180326a88c9863c6017e52 Mon Sep 17 00:00:00 2001 From: danielpmc Date: Mon, 19 Oct 2020 04:51:28 +0100 Subject: [PATCH 080/255] updated link --- Panel/bot/discord/commands/link.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Panel/bot/discord/commands/link.js b/Panel/bot/discord/commands/link.js index 763dc8e12..0272a8c4f 100644 --- a/Panel/bot/discord/commands/link.js +++ b/Panel/bot/discord/commands/link.js @@ -392,7 +392,7 @@ exports.run = async (client, message) => { }, 5000) ); } else { - channel.send('Code is incorrect. Linking cancelled!') + channel.send('Code is incorrect. Linking cancelled! \n\nRemoving channel!') setTimeout(() => { channel.delete(); }, 2000) From de3b86258e1a32475325febbf360df3f9425ecf0 Mon Sep 17 00:00:00 2001 From: danielpmc Date: Mon, 19 Oct 2020 04:51:50 +0100 Subject: [PATCH 081/255] Remved un-used command --- Panel/bot/discord/commands/proxmox.js | 1 - 1 file changed, 1 deletion(-) delete mode 100644 Panel/bot/discord/commands/proxmox.js diff --git a/Panel/bot/discord/commands/proxmox.js b/Panel/bot/discord/commands/proxmox.js deleted file mode 100644 index f154b2809..000000000 --- a/Panel/bot/discord/commands/proxmox.js +++ /dev/null @@ -1 +0,0 @@ -exports.run = async (client, message) => {}; \ No newline at end of file From c84a78ae8c9f7cb4f64e1f18ec8491a526c97f03 Mon Sep 17 00:00:00 2001 From: danielpmc Date: Mon, 19 Oct 2020 04:52:09 +0100 Subject: [PATCH 082/255] Removed another un-used command --- Panel/bot/discord/commands/monitor.js | 47 --------------------------- 1 file changed, 47 deletions(-) delete mode 100644 Panel/bot/discord/commands/monitor.js diff --git a/Panel/bot/discord/commands/monitor.js b/Panel/bot/discord/commands/monitor.js deleted file mode 100644 index 3005daa40..000000000 --- a/Panel/bot/discord/commands/monitor.js +++ /dev/null @@ -1,47 +0,0 @@ -exports.run = (client, message, args) => { - if (message.author.id !== config.DiscordBot.ownerID) return message.channel.send("Sorry, No permission :O"); - try { - - //Alerts me that the Node Monitor is now running. (Please Please Please. If you run this bot only run this once or you might get spam and banned from discord) - message.channel.send('Monitor is now running and watching all nodes for `DanBot Hosting`. Any issues will be updated and sent in <#640158471001735169>') - - //Node Monitor - setInterval(() => { - //Data for node 1 - var N1 = fs.readFileSync('./data/0286b2ad-dc80-4b5c-a0de-b81945b010e8.json', 'utf8'); - var Node1 = JSON.parse(N1); - - //Data for node 2 - var N2 = fs.readFileSync('./data/2e3f071a-af2b-4dc9-be5a-7ce72590a181.json', 'utf8'); - var Node2 = JSON.parse(N2); - - //Data for node 3 - var N3 = fs.readFileSync('./data/6fc3e9bf-24a8-47cd-99d3-fa159e05a9f4.json', 'utf8'); - var Node3 = JSON.parse(N3); - - //Data for node 4 - var N4 = fs.readFileSync('./data/15ffcdd0-a021-4ded-977d-284d777330a0.json', 'utf8'); - var Node4 = JSON.parse(N4); - - //Runs if statements for each node. this checks each node's ram - if (Node1.memused >= "7.5 GB") { - return client.channels.get("640158471001735169").send("⚠️ `Node 1` is currently running with " + Node1.memused + " out of " + Node1.memtotal + ". Will continue to monitor this node!"), client.channels.get("640158471001735169").setTopic('⚠️Monitoring: Node 1 running with ' + Node1.memused + " out of " + Node1.memtotal) - }; - - client.guilds.get("639477525927690240").channels.get("640158471001735169").fetchMessage("693937194863427655") - .then(msgb => { - console.log(msgb.content) - msgb.edit("testing") - }) - // Node1msg.edit('testing') - - //if (Node1.memused >= "7.5 GB") return client.channels.get("640158471001735169").send("⚠️ `Node 1` is currently running with " + Node1.memused + " out of " + Node1.memtotal + ". Will continue to monitor this node!"), client.channels.get("640158471001735169").setTopic('⚠️Monitoring: Node 1 running with ' + Node1.memused + " out of " + Node1.memtotal) - //if (Node2.memused >= "7.5 GB") return client.channels.get("640158471001735169").send("⚠️ `Node 2` is currently running with " + Node2.memused + " out of " + Node2.memtotal + ". Will continue to monitor this node!"), client.channels.get("640158471001735169").setTopic('⚠️Monitoring: Node 2 running with ' + Node2.memused + " out of " + Node2.memtotal) - //if (Node3.memused >= "7.5 GB") return client.channels.get("640158471001735169").send("⚠️ `Node 3` is currently running with " + Node3.memused + " out of " + Node3.memtotal + ". Will continue to monitor this node!"), client.channels.get("640158471001735169").setTopic('⚠️Monitoring: Node 3 running with ' + Node3.memused + " out of " + Node3.memtotal) - //if (Node4.memused >= "7.5 GB") return client.channels.get("640158471001735169").send("⚠️ `Node 4` is currently running with " + Node4.memused + " out of " + Node4.memtotal + ". Will continue to monitor this node!"), client.channels.get("640158471001735169").setTopic('⚠️Monitoring: Node 4 running with ' + Node4.memused + " out of " + Node4.memtotal) - }, 5000); - - } catch (err) { - return console.log(err) - } -}; \ No newline at end of file From d5f2a5944ecf3d9d56a524a3fc59cb9321639adc Mon Sep 17 00:00:00 2001 From: danielpmc Date: Mon, 19 Oct 2020 04:52:31 +0100 Subject: [PATCH 083/255] And 2 more --- Panel/bot/discord/commands/changelog.js | 11 ------ Panel/bot/discord/commands/play.js | 45 ------------------------- 2 files changed, 56 deletions(-) delete mode 100644 Panel/bot/discord/commands/changelog.js delete mode 100644 Panel/bot/discord/commands/play.js diff --git a/Panel/bot/discord/commands/changelog.js b/Panel/bot/discord/commands/changelog.js deleted file mode 100644 index e9fd954b4..000000000 --- a/Panel/bot/discord/commands/changelog.js +++ /dev/null @@ -1,11 +0,0 @@ -var getRepoInfo = require('git-repo-info'); -exports.run = async (client, message) => { - var info = getRepoInfo(); - - let embed = new Discord.RichEmbed() - .setColor(`BLUE`) - .addField(`__**Latest GitHub push:**__`, info.committerDate) - .addField(`__**Latest GitHub commit message:**__`, info.commitMessage) - .addField(`__**Latest GitHub committer:**__`, info.committer) - message.channel.send(embed) -}; \ No newline at end of file diff --git a/Panel/bot/discord/commands/play.js b/Panel/bot/discord/commands/play.js deleted file mode 100644 index 31a6980f1..000000000 --- a/Panel/bot/discord/commands/play.js +++ /dev/null @@ -1,45 +0,0 @@ -const utils = require('../music/utils'); - - -exports.run = async (client, message, args) => { - - let VC = message.member.voiceChannel; - if (!VC) return [message.delete(), utils.timed_msg(utils.cmd_fail(`${message.author}, please join a voice channel!`, `${config.DiscordBot.prefix}play `), 5000)]; - - let url = args[0] ? args[0].replace(/<(.+)>/g, '$1') : ''; - let pl = /^https?:\/\/(www.youtube.com|youtube.com)\/playlist(.*)$/ - - let searchString = args.join(' '); - if (!url || !searchString) return [message.delete(), utils.timed_msg(utils.cmd_fail(`${message.author}, please enter a music name or url!`, `${config.DiscordBot.prefix}play `), 5000)]; - - let perms = VC.permissionsFor(message.client.user); - if (!perms.has('CONNECT')) return [message.delete(), utils.timed_msg(utils.cmd_fail(`${message.author}, I do not have permissions to connect to voice channels!`, `${config.DiscordBot.prefix}play `), 5000)]; - if (!perms.has('SPEAK')) return [message.delete(), utils.timed_msg(utils.cmd_fail(`${message.author}, I do not have permissions to speak in a voice channel`, `${config.DiscordBot.prefix}play `), 5000)]; - - if (url.match(pl)) { - let playlist = await client.youtube.getPlaylist(url); - let videos = await playlist.getVideos(); - - for (const vid of Object.values(videos)) { - let video = await client.youtube.getVideoByID(vid.id) - await client.handleVideo(video, message, VC, true) - } - - return message.channel.send(`**${playlist.title}** has been added to queue.`); - } else { - - try { - var video = await client.youtube.getVideo(url); - } catch (err) { - if (err) undefined; - try { - var vid = await client.youtube.searchVideos(searchString, 1); - var video = await client.youtube.getVideoByID(vid[0].id); - } catch (err) { - console.error(err); - return [message.delete(), utils.timed_msg(utils.cmd_fail(`${message.author}, no videos can be found with the argument \`${searchString}\``, `${config.DiscordBot.prefix}play `), 5000)]; - } - } - return client.handleVideo(video, message, VC); - } -}; \ No newline at end of file From 84bc2b0dfbf310cceff87034fbfb24986839a954 Mon Sep 17 00:00:00 2001 From: danielpmc Date: Mon, 19 Oct 2020 04:52:47 +0100 Subject: [PATCH 084/255] Yet another --- Panel/bot/discord/commands/own.js | 14 -------------- 1 file changed, 14 deletions(-) delete mode 100644 Panel/bot/discord/commands/own.js diff --git a/Panel/bot/discord/commands/own.js b/Panel/bot/discord/commands/own.js deleted file mode 100644 index 0281b3043..000000000 --- a/Panel/bot/discord/commands/own.js +++ /dev/null @@ -1,14 +0,0 @@ -exports.run = async (client, message) => { - if (userData.get(message.author.id) == null) { - message.channel.send("You can't use this command as your account is not linked. You can link it with: `" + config.DiscordBot.Prefix + "link`") - } else { - let consoleUser = await DanBotHosting.getAllServers(); - consoleUser = consoleUser.filter(x => x.attributes.user == userData.fetch(message.author.id + ".consoleID")) - - let embed = new Discord.RichEmbed() - .setColor(`GREEN`) - .addField(`__**Server's you own:**__`, userData.fetch(message.author.id + ".username")) - //message.channel.send('Your account is linked. Heres some data: ', embed) - console.log(consoleUser) - } -}; \ No newline at end of file From f2649aa7df6cc7445d38fdd919cf32700f55bc3c Mon Sep 17 00:00:00 2001 From: danielpmc Date: Mon, 19 Oct 2020 04:54:00 +0100 Subject: [PATCH 085/255] Added update command to staff embed --- Panel/bot/discord/commands/staff.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Panel/bot/discord/commands/staff.js b/Panel/bot/discord/commands/staff.js index aece6583d..9627374ab 100644 --- a/Panel/bot/discord/commands/staff.js +++ b/Panel/bot/discord/commands/staff.js @@ -1,3 +1,5 @@ +const { config } = require('process'); + const exec = require('child_process').exec; exports.run = async (client, message, args) => { if (message.member.roles.find(r => r.id === "748117822370086932")) { @@ -7,7 +9,7 @@ exports.run = async (client, message, args) => { .setColor('RANDOM') .addField('**Staff Commands:**', config.DiscordBot.Prefix + "staff linked useridhere | Shows if the users account is linked.") .addField('**Admin Commands:**', config.DiscordBot.Prefix + "staff apply open/closed | Open or close staff applications. \n" + config.DiscordBot.Prefix + "staff settings | Shows current website settings") - .addField('**Owner Commands:**', config.DiscordBot.Prefix + "staff maintenance on/off | Enable or disable website maintenance.") + .addField('**Owner Commands:**', config.DiscordBot.Prefix + "staff maintenance on/off | Enable or disable website maintenance. \n" + config.DiscordBot.Prefix + "staff update | Pulls updates from GitHub") message.channel.send(embed) } else { let embed = new Discord.RichEmbed() From 1d151167a8c290099d282fd66fb5f2a9c35ce48c Mon Sep 17 00:00:00 2001 From: danielpmc Date: Mon, 19 Oct 2020 10:30:05 +0100 Subject: [PATCH 086/255] Show node on server status command --- Panel/bot/discord/commands/server.js | 1 + 1 file changed, 1 insertion(+) diff --git a/Panel/bot/discord/commands/server.js b/Panel/bot/discord/commands/server.js index 01223e270..8356039ec 100644 --- a/Panel/bot/discord/commands/server.js +++ b/Panel/bot/discord/commands/server.js @@ -512,6 +512,7 @@ exports.run = async (client, message, args) => { .addField('**RAM Usage**', pretty(resources.data.attributes.resources.memory_bytes) + ' out of UNLIMITED MB') .addField('**DISK Usage**', pretty(resources.data.attributes.resources.disk_bytes) + ' out of UNLIMITED MB') .addField('**NET Usage**', 'UPLOADED: ' + pretty(resources.data.attributes.resources.network_tx_bytes) + ', DOWNLOADED: ' + pretty(resources.data.attributes.resources.network_rx_bytes)) + .addField('**NODE**', response.data.attributes.node) .addField('\u200b', '\u200b') .addField('**LIMITS (0 = unlimited)**', 'MEMORY: ' + response.data.attributes.limits.memory + 'MB \nDISK: ' + response.data.attributes.limits.disk + 'MB \nCPU: ' + response.data.attributes.limits.cpu) .addField('**MISC LIMITS**', 'DATABASES: ' + response.data.attributes.feature_limits.databases + '\nBACKUPS: ' + response.data.attributes.feature_limits.backups) From cfde1313a5e5da8915afe6434cebbc07b10a233d Mon Sep 17 00:00:00 2001 From: Hadimhz Date: Mon, 19 Oct 2020 23:33:06 +0300 Subject: [PATCH 087/255] added More reaction roles --- Panel/index.js | 205 ++++++++++++++++++++++++++----------------------- 1 file changed, 108 insertions(+), 97 deletions(-) diff --git a/Panel/index.js b/Panel/index.js index b75ea0ab4..590a19ead 100644 --- a/Panel/index.js +++ b/Panel/index.js @@ -21,13 +21,16 @@ global.transport = nodemailer.createTransport({ host: config.Email.Host, port: config.Email.Port, auth: { - user: config.Email.User, - pass: config.Email.Password + user: config.Email.User, + pass: config.Email.Password } }); const isSnowflake = require(process.cwd() + "/util/isSnowflake.js"); -const { getUser, getBot } = require(process.cwd() + "/util/discordAPI"); +const { + getUser, + getBot +} = require(process.cwd() + "/util/discordAPI"); //Discord Bot @@ -39,7 +42,9 @@ global.userData = new db.table("userData"); global.settings = new db.table("settings"); global.webSettings = new db.table("webSettings"); global.mutesData = new db.table("muteData"); -global.client = new Discord.Client({disableEveryone: true}); +global.client = new Discord.Client({ + disableEveryone: true +}); const bot = client; global.suggestionLog = new Discord.WebhookClient(config.DiscordSuggestions.channelID, config.DiscordSuggestions.channelID) bot.pvc = new Discord.Collection(); @@ -48,10 +53,12 @@ bot.reactionRoles = { channel: '765877675147264000', reactions: { // unicode/id : roleID + '📣': '767845918350376960', '🕹️': '760207814546817085', '🎥': '758020921939460166', '🎉': '765865412725440522', - '❔': '745358424883200210' + '❔': '767846121195175938', + '⌛': '745358424883200210' } } @@ -60,15 +67,15 @@ bot.reactionRoles = { fs.readdir('./bot/discord/events/', (err, files) => { files = files.filter(f => f.endsWith('.js')); files.forEach(f => { - const event = require(`./bot/discord/events/${f}`); - client.on(f.split('.')[0], event.bind(null, client)); - delete require.cache[require.resolve(`./bot/discord/events/${f}`)]; - }); - }); + const event = require(`./bot/discord/events/${f}`); + client.on(f.split('.')[0], event.bind(null, client)); + delete require.cache[require.resolve(`./bot/discord/events/${f}`)]; + }); +}); //Bot login client.login(config.DiscordBot.Token); -global.Allowed = [ "338192747754160138", "137624084572798976" ]; +global.Allowed = ["338192747754160138", "137624084572798976"]; //Test Email //const message = { @@ -103,8 +110,7 @@ passport.deserializeUser((obj, done) => { }); passport.use( - new strategy( - { + new strategy({ clientID: config.DiscordBot.clientID, clientSecret: config.DiscordBot.clientSecret, callbackURL: config.DiscordBot.callbackURL, @@ -121,7 +127,8 @@ passport.use( app.use( session({ store: new MongoStore({ - url: config.DB.MongoDB }), + url: config.DB.MongoDB + }), secret: "FROPT", resave: false, saveUninitialized: false @@ -130,66 +137,70 @@ app.use( app.use(passport.initialize()); app.use(passport.session()); -app.use(helmet({ frameguard: false })); +app.use(helmet({ + frameguard: false +})); app.use(cookieParser()); app.use(bodyParser.json()); -app.use(bodyParser.urlencoded({extended: true})); +app.use(bodyParser.urlencoded({ + extended: true +})); server.listen(PORT, function () { - console.log(chalk.magenta('[WEB] ') + chalk.green("Listening on port " + PORT)); + console.log(chalk.magenta('[WEB] ') + chalk.green("Listening on port " + PORT)); }); global.nodeData = new db.table("nodeData") app.get('/data', function (req, res) { - let nodes = [ "154.27.68.232", "154.27.68.233", "154.27.68.234", "167.86.113.158", "51.38.69.73"]; + let nodes = ["154.27.68.232", "154.27.68.233", "154.27.68.234", "167.86.113.158", "51.38.69.73"]; if (req.query.servername == undefined) { if (!nodes.includes(req.headers["cf-connecting-ip"])) { res.redirect("/") } else { - nodeData.set(req.query.speedname + '-speedtest', { - speedname: req.query.speedname, - ping: req.query.ping, - download: req.query.download, - upload: req.query.upload, - updatetime: req.query.updatetime - }); + nodeData.set(req.query.speedname + '-speedtest', { + speedname: req.query.speedname, + ping: req.query.ping, + download: req.query.download, + upload: req.query.upload, + updatetime: req.query.updatetime + }); }; } else { if (!nodes.includes(req.headers["cf-connecting-ip"])) { res.redirect("/") } else { - nodeData.set(req.query.servername, { - servername: req.query.servername, - cpu: req.query.cpu, - cpuload: req.query.cpuload, - cputhreads: req.query.cputhreads, - cpucores: req.query.cpucores, - memused: req.query.memused, - memtotal: req.query.memtotal, - swapused: req.query.swapused, - swaptotal: req.query.swaptotal, - diskused: req.query.diskused, - disktotal: req.query.disktotal, - netrx: req.query.netrx, - nettx: req.query.nettx, - osplatform: req.query.osplatform, - oslogofile: req.query.oslogofile, - osrelease: req.query.osrelease, - osuptime: req.query.osuptime, - biosvendor: req.query.biosvendor, - biosversion: req.query.biosversion, - biosdate: req.query.biosdate, - servermonitorversion: req.query.servermonitorversion, - datatime: req.query.datatime, - dockercontainers: req.query.dockercontainers, - dockercontainersrunning: req.query.dockercontainersrunning, - dockercontainerspaused: req.query.dockercontainerspaused, - dockercontainersstopped: req.query.dockercontainersstopped, - updatetime: req.query.updatetime - }); + nodeData.set(req.query.servername, { + servername: req.query.servername, + cpu: req.query.cpu, + cpuload: req.query.cpuload, + cputhreads: req.query.cputhreads, + cpucores: req.query.cpucores, + memused: req.query.memused, + memtotal: req.query.memtotal, + swapused: req.query.swapused, + swaptotal: req.query.swaptotal, + diskused: req.query.diskused, + disktotal: req.query.disktotal, + netrx: req.query.netrx, + nettx: req.query.nettx, + osplatform: req.query.osplatform, + oslogofile: req.query.oslogofile, + osrelease: req.query.osrelease, + osuptime: req.query.osuptime, + biosvendor: req.query.biosvendor, + biosversion: req.query.biosversion, + biosdate: req.query.biosdate, + servermonitorversion: req.query.servermonitorversion, + datatime: req.query.datatime, + dockercontainers: req.query.dockercontainers, + dockercontainersrunning: req.query.dockercontainersrunning, + dockercontainerspaused: req.query.dockercontainerspaused, + dockercontainersstopped: req.query.dockercontainersstopped, + updatetime: req.query.updatetime + }); + } } - } }) //View engine setup @@ -197,21 +208,21 @@ hbs.registerPartials(__dirname + '/views/partials') app.set('view engine', 'hbs'); app.use((req, res, next) => { - res.set("Access-Control-Allow-Origin", "*"); - res.set("Access-Control-Allow-Methods", "GET, POST"); - - console.log( - (req.headers["cf-connecting-ip"] || - req.headers["x-forwarded-for"] || - req.ip) + - " [" + - req.method + - "] " + - req.url - ); - - next(); - }); + res.set("Access-Control-Allow-Origin", "*"); + res.set("Access-Control-Allow-Methods", "GET, POST"); + + console.log( + (req.headers["cf-connecting-ip"] || + req.headers["x-forwarded-for"] || + req.ip) + + " [" + + req.method + + "] " + + req.url + ); + + next(); +}); //Routes @@ -234,9 +245,9 @@ app.use("/me", meRoute); app.use("/admin", adminRoute); app.get("/user/:ID", async (req, res) => { - let user = req.params.ID; - let memberr = "No" - + let user = req.params.ID; + let memberr = "No" + if (!isSnowflake(user)) { return res.render("error.ejs", { user: req.isAuthenticated() ? req.user : null, @@ -249,18 +260,18 @@ app.get("/user/:ID", async (req, res) => { if (use.user_id && use.user_id[0].endsWith("is not snowflake.")) return res.render("error.ejs", { user: req.isAuthenticated() ? req.user : null, - message: "ID is invalid" + message: "ID is invalid" }); - + if (use.message == "Unknown User") return res.render("error.ejs", { user: req.isAuthenticated() ? req.user : null, message: "Discord API - Unknown User" }); - + if (use.bot === true) return res.redirect("/bot/" + user); - - try { + + try { bot.fetchUser(user).then(User => { if (User.bot) { return res.redirect("/bot/" + User.id); @@ -300,29 +311,29 @@ app.get("/user/:ID", async (req, res) => { } } } - - let avatar = `https://mythicalbots.xyz/bot/${user}/avatar`; - - let bots = db.get(`${User.id}.bots`); - if(!bots) bots = null; - - console.log(bots) - - res.render("me/user.ejs", { + + let avatar = `https://mythicalbots.xyz/bot/${user}/avatar`; + + let bots = db.get(`${User.id}.bots`); + if (!bots) bots = null; + + console.log(bots) + + res.render("me/user.ejs", { user: req.isAuthenticated() ? req.user : null, User, avatar, - // Data, + // Data, pColor, presence, - // info, + // info, memberr, use, bots, db, - // Discord, - // pageType: { user: true } - }); + // Discord, + // pageType: { user: true } + }); }); } catch (e) { return res.render("error.ejs", { @@ -330,19 +341,19 @@ app.get("/user/:ID", async (req, res) => { message: e }); } - + }); //Catch 404 and forward to error handler -app.use(function(req, res, next) { +app.use(function (req, res, next) { res.status(404).render("error.ejs", { message: "Page Not Found", user: req.isAuthenticated() ? req.user : null }); }); -setInterval(async() => { - console.log("[Automatic Process] Getting bot stats from MBL") - require("./util/MBL.js") +setInterval(async () => { + console.log("[Automatic Process] Getting bot stats from MBL") + require("./util/MBL.js") }, 600000); \ No newline at end of file From 62cecce3c0ead12217d35921c95f369cac61028c Mon Sep 17 00:00:00 2001 From: Hadimhz Date: Tue, 20 Oct 2020 00:41:12 +0300 Subject: [PATCH 088/255] Update staff.js --- Panel/bot/discord/commands/staff.js | 169 ++++++++++++---------------- 1 file changed, 75 insertions(+), 94 deletions(-) diff --git a/Panel/bot/discord/commands/staff.js b/Panel/bot/discord/commands/staff.js index 9627374ab..e416869b5 100644 --- a/Panel/bot/discord/commands/staff.js +++ b/Panel/bot/discord/commands/staff.js @@ -2,9 +2,10 @@ const { config } = require('process'); const exec = require('child_process').exec; exports.run = async (client, message, args) => { - if (message.member.roles.find(r => r.id === "748117822370086932")) { - if (!args[0]) { - if (message.member.roles.find(r => r.id === "639489438036000769")) { + if (!message.member.roles.find(r => r.id == "748117822370086932")) return; + + if (args[0] == null) { + if (message.member.roles.find(r => r.id == "639489438036000769")) { let embed = new Discord.RichEmbed() .setColor('RANDOM') .addField('**Staff Commands:**', config.DiscordBot.Prefix + "staff linked useridhere | Shows if the users account is linked.") @@ -17,38 +18,40 @@ exports.run = async (client, message, args) => { .addField('**Staff Commands:**', config.DiscordBot.Prefix + "staff linked useridhere | Shows if the users account is linked.") message.channel.send(embed) } - } else if (message.content.toLowerCase().includes("linked")) { - if (args[1] === "") { - message.channel.send('Please send a users discord ID to see if they are linked with an account on the host.') - } else { - if (userData.get(args[1]) == null) { - message.channel.send("That account is not linked with a console account :sad:") - } else { - console.log(userData.fetch(args[1])) - let embed = new Discord.RichEmbed() - .setColor(`GREEN`) - .addField(`__**Username**__`, userData.fetch(args[1] + ".username")) - .addField(`__**Email**__`, userData.fetch(args[1] + ".email")) - .addField(`__**Discord ID**__`, userData.fetch(args[1] + ".discordID")) - .addField(`__**Console ID**__`, userData.fetch(args[1] + ".consoleID")) - .addField(`__**Date (YYYY/MM/DD)**__`, userData.fetch(args[1] + ".linkDate")) - .addField(`__**Time**__`, userData.fetch(args[1] + ".linkTime")) - message.channel.send('That account is linked. Heres some data: ', embed) + } + + switch (args[0].toLowerCase()) { + case 'linked': + if (args[1] == null) { + message.channel.send('Please send a users discord ID to see if they are linked with an account on the host.') + } else { + if (userData.get(args[1]) == null) { + message.channel.send("That account is not linked with a console account :sad:") + } else { + console.log(userData.fetch(args[1])) + let embed = new Discord.RichEmbed() + .setColor(`GREEN`) + .addField(`__**Username**__`, userData.fetch(args[1] + ".username")) + .addField(`__**Email**__`, userData.fetch(args[1] + ".email")) + .addField(`__**Discord ID**__`, userData.fetch(args[1] + ".discordID")) + .addField(`__**Console ID**__`, userData.fetch(args[1] + ".consoleID")) + .addField(`__**Date (YYYY/MM/DD)**__`, userData.fetch(args[1] + ".linkDate")) + .addField(`__**Time**__`, userData.fetch(args[1] + ".linkTime")) + message.channel.send('That account is linked. Heres some data: ', embed) + } } - } - } else if (message.content.toLowerCase().includes("createserver")) { - message.channels.send('Who would you like to create') - } else if (message.content.toLowerCase().includes("apply")) { - if (message.member.roles.find(r => r.id === "639489438036000769")) { - if (args[1] === "") { + break; + + case 'apply': + if (args[1] == null) { message.channel.send("Please run the command using the following format: `" + config.DiscordBot.Prefix + "staff apply open/closed` to enable or disable staff applications") } else { - if (args[1] === "open") { + if (args[1] == "open") { webSettings.set("staff-applications", { enabled: "true" }); message.channel.send("Staff applications now open") - } else if (args[1] === "closed") { + } else if (args[1] == "closed") { webSettings.set("staff-applications", { enabled: "false" }); @@ -61,73 +64,51 @@ exports.run = async (client, message, args) => { } }; }; - }; - } else if (message.content.toLowerCase().includes("settings")) { - if (message.member.roles.find(r => r.id === "639489438036000769")) { - let embed = new Discord.RichEmbed() - .addField('__**Staff Applications Enabled?**__', webSettings.fetch("staff-applications.enabled"), true) - .addField('__**Website maintenance enabled?**__', webSettings.fetch("maintenance.enabled"), true) - message.channel.send(embed) - }; - } else if (message.content.toLowerCase().includes("maintenance")) { - if (message.member.roles.find(r => r.id === "639481606112804875")) { - if (args[1] === "") { - message.channel.send("Please run the command using the following format: `" + config.DiscordBot.Prefix + "staff maintenance on/off` to enable or disable maintenance mode") - } else { - if (args[1] === "off") { - webSettings.set("maintenance", { - enabled: "false" - }); - message.channel.send("Website maintenance mode now **Disabled**") - } else if (args[1] === "on") { - webSettings.set("maintenance", { - enabled: "true" - }); - message.channel.send("Website maintenance mode now **Enabled**") - } else { - if (webSettings.fetch("maintenance.enabled") == "true") { - message.channel.send("Please run the command using the following format: `" + config.DiscordBot.Prefix + "staff maintenance on/off` to enable or disable website maintenance mode \n**Website maintenance mode is currently:** **ENABLED**"); - } else if (webSettings.fetch("maintenance.enabled") == "false") { - message.channel.send("Please run the command using the following format: `" + config.DiscordBot.Prefix + "staff maintenance on/off` to enable or disable website maintenance mode \n**Website maintenance mode is currently:** **DISABLED**"); - }; - }; + break; + + case 'settings': + if (message.member.roles.find(r => r.id === "639489438036000769")) { + let embed = new Discord.RichEmbed() + .addField('__**Staff Applications Enabled?**__', webSettings.fetch("staff-applications.enabled"), true) + .addField('__**Website maintenance enabled?**__', webSettings.fetch("maintenance.enabled"), true) + message.channel.send(embed) }; - } - } else if (message.content.toLowerCase().includes("ticket")) { - - } else if (message.content.toLowerCase().includes("request")) { - if (args[1] === "new") { - if (args[2] === "proxy") { - //Type: Proxy - } - //New request - message.channel.send('Please use the following format: `' + config.DiscordBot.Prefix + "staff request type userid serverid` \nYou can view types by running: `" + config.DiscordBot.Prefix + "staff request types`") - } else if (args[1] === "types") { - //Types - let embed = new Discord.RichEmbed() - .addField('__**Request Types (Type | Type Meaning):**__', "`proxy` | Reverse Proxy \n`password` | Password reset \n`server` | Server creation (If not on createserver) \n`delete` | Server Deletion") - message.channel.send(embed) - } else if (args[1] === "delete") { - //Delete request - } - } else if (message.content.toLowerCase().includes("update")) { - if (message.member.roles.find(r => r.id === "639481606112804875")) { - exec(`git pull`, (error, stdout) => { - let response = (error || stdout); - if (!error) { - if (response.includes("Already up to date.")) { - message.channel.send('Bot already up to date. No changes since last pull') - } else { - message.channel.send('Pulled from GitHub. Restarting bot. \n\nLogs: \n```' + response + "```") - setTimeout(() => { - process.exit(); - }, 1000) - }; + break; + case 'request': + if (args[1] === "new") { + if (args[2] === "proxy") { + //Type: Proxy } - }); - } else { - message.channel.send('OwO') - } + //New request + message.channel.send('Please use the following format: `' + config.DiscordBot.Prefix + "staff request type userid serverid` \nYou can view types by running: `" + config.DiscordBot.Prefix + "staff request types`") + } else if (args[1] === "types") { + //Types + let embed = new Discord.RichEmbed() + .addField('__**Request Types (Type | Type Meaning):**__', "`proxy` | Reverse Proxy \n`password` | Password reset \n`server` | Server creation (If not on createserver) \n`delete` | Server Deletion") + message.channel.send(embed) + } else if (args[1] === "delete") { + //Delete request + } + break; + case 'update': + if (message.member.roles.find(r => r.id === "639481606112804875") || message.author.id == '293841631583535106') { + exec(`git pull`, (error, stdout) => { + let response = (error || stdout); + if (!error) { + if (response.includes("Already up to date.")) { + message.channel.send('Bot already up to date. No changes since last pull') + } else { + message.channel.send('Pulled from GitHub. Restarting bot. \n\nLogs: \n```' + response + "```") + setTimeout(() => { + process.exit(); + }, 1000) + }; + } + }); + } else { + message.channel.send('OwO') + } + break; } -}; + } \ No newline at end of file From 9a373a6d2e0a0ef34f9310e9a2844bebf96825d3 Mon Sep 17 00:00:00 2001 From: Hadimhz Date: Tue, 20 Oct 2020 02:08:01 +0300 Subject: [PATCH 089/255] Updated Reaction-roles to support multiple messages. --- Panel/bot/discord/commands/staff.js | 31 +++++++++++++++-- Panel/bot/discord/events/raw.js | 23 ++++++------ Panel/bot/discord/events/ready.js | 54 +++++++++++++++++++---------- Panel/bot/discord/reactionRoles.js | 16 +++++++++ Panel/index.js | 15 +------- 5 files changed, 93 insertions(+), 46 deletions(-) create mode 100644 Panel/bot/discord/reactionRoles.js diff --git a/Panel/bot/discord/commands/staff.js b/Panel/bot/discord/commands/staff.js index e416869b5..5a03ee944 100644 --- a/Panel/bot/discord/commands/staff.js +++ b/Panel/bot/discord/commands/staff.js @@ -1,4 +1,6 @@ -const { config } = require('process'); +const { + config +} = require('process'); const exec = require('child_process').exec; exports.run = async (client, message, args) => { @@ -18,6 +20,7 @@ exports.run = async (client, message, args) => { .addField('**Staff Commands:**', config.DiscordBot.Prefix + "staff linked useridhere | Shows if the users account is linked.") message.channel.send(embed) } + return; } switch (args[0].toLowerCase()) { @@ -44,14 +47,14 @@ exports.run = async (client, message, args) => { case 'apply': if (args[1] == null) { - message.channel.send("Please run the command using the following format: `" + config.DiscordBot.Prefix + "staff apply open/closed` to enable or disable staff applications") + message.channel.send("Please run the command using the following format: `" + config.DiscordBot.Prefix + "staff apply open/close` to enable or disable staff applications") } else { if (args[1] == "open") { webSettings.set("staff-applications", { enabled: "true" }); message.channel.send("Staff applications now open") - } else if (args[1] == "closed") { + } else if (args[1] == "close") { webSettings.set("staff-applications", { enabled: "false" }); @@ -90,6 +93,28 @@ exports.run = async (client, message, args) => { //Delete request } break; + case 'reactionroles': + let reactionRoles = require('../reactionRoles'); + client.reactionRoles = reactionRoleConfig; + + let reactionRolesChannels = Object.keys(reactionRoles); + + reactionRolesChannels.forEach(c => { + let channel = client.channels.get(c); + let reactionRolesChannelMessages = Object.keys(reactionRoles[c]); + reactionRolesChannelMessages.forEach(async m => { + let message = await channel.fetchMessage(m); + let reactions = Object.keys(reactionRoles[c][r]); + await message.clearReactions(); + + for (let ri in reactions) { + let reaction = reactions[ri]; + if (reaction.length == 18) client.emojis.get(reaction); + await message.react(reaction); + } + }); + }) + break; case 'update': if (message.member.roles.find(r => r.id === "639481606112804875") || message.author.id == '293841631583535106') { exec(`git pull`, (error, stdout) => { diff --git a/Panel/bot/discord/events/raw.js b/Panel/bot/discord/events/raw.js index 5639a0526..22bf36038 100644 --- a/Panel/bot/discord/events/raw.js +++ b/Panel/bot/discord/events/raw.js @@ -7,28 +7,31 @@ module.exports = async (client, e) => { let message = await channel.fetchMessage(e.d.message_id); let emoji = e.d.emoji; let member = message.guild.members.get(e.d.user_id); - if (member.user.bot || channel.id != client.reactionRoles.channel || message.id != client.reactionRoles.message) return; - let reactionRoles = client.reactionRoles.reactions; + + if (member.user.bot || client.reactionRoles[channel.id] == null || client.reactionRoles[channel.id][message.id]) return; + + let reactionRoles = client.reactionRoles[channel.id][message.id]; + let input = emoji.id != null ? emoji.id : emoji.name; - if (reactionRoles[input] != null) { - let role = message.guild.roles.get(reactionRoles[input]); - if (member.roles.map(x => x.id).includes(reactionRoles[input])) { - await member.removeRole(role); + if (reactionRoles[input] != null) { + if (member.roles.find(x => x.id == reactionRoles[input])) { + await member.removeRole(reactionRoles[input]).catch(console.log(`couldn't find a role with the id ${reactionRoles[input]}`)); member.user.send("removed the role: `" + role.name + "`!"); } else { - await member.addRole(role); + await member.addRole(reactionRoles[input]).catch(console.log(`couldn't find a role with the id ${reactionRoles[input]}`)); member.user.send("gave you the role: `" + role.name + "`!"); - } + }; - let memberRoles = member.roles.map(x => x.id).concat(Object.values(reactionRoles)) + let memberRoles = member.roles.map(x => x.id).concat(Object.values(reactionRoles)); if (findDuplicates(memberRoles)) member.addRole('765869330024890378') else member.removeRole('765869330024890378'); } + message.reactions.forEach(reaction => { if (e.d.user_id == client.user.id) return; else reaction.remove(e.d.user_id) }) } -} +} \ No newline at end of file diff --git a/Panel/bot/discord/events/ready.js b/Panel/bot/discord/events/ready.js index d33aba4e6..aabd043fa 100644 --- a/Panel/bot/discord/events/ready.js +++ b/Panel/bot/discord/events/ready.js @@ -1,8 +1,8 @@ -//let client = require("../../../../index.js").client; const axios = require('axios'); module.exports = async (client, guild, files) => { console.log(chalk.magenta('[DISCORD] ') + chalk.green(client.user.username + " has logged in!")); + //Auto Activities List const activities = [{ "text": "over DanBot Hosting", @@ -25,15 +25,10 @@ module.exports = async (client, guild, files) => { }, 30000); //Reaction-Roles: - let rChannel = client.channels.get(client.reactionRoles.channel); - let rMessage = await rChannel.fetchMessage(client.reactionRoles.message); - let reactionEmojis = Object.keys(client.reactionRoles.reactions); - for (let ri in reactionEmojis) { - let reaction = reactionEmojis[ri]; - if (reaction.length == 18) client.emojis.get(reaction); - await rMessage.react(reaction); - } + let reactionRoles = require('../reactionRoles'); + client.reactionRoles = reactionRoleConfig; + // end of Reaction-Roles global.invites = {}; @@ -48,21 +43,33 @@ module.exports = async (client, guild, files) => { let guild1 = await client.guilds.get("639477525927690240").fetchMembers(); let roleID1 = '748117822370086932'; let staffCount = guild1.roles.get(roleID1).members.size; - client.channels.get("739821419910791348").edit({ name: `Staff: ${staffCount}`, reason: "Staff count update" }); - + client.channels.get("739821419910791348").edit({ + name: `Staff: ${staffCount}`, + reason: "Staff count update" + }); + let guild2 = await client.guilds.get("639477525927690240").fetchMembers(); let roleID2 = '639490038434103306'; let memberCount = guild2.roles.get(roleID2).members.size; - client.channels.get("739821366991257621").edit({ name: `Members: ${memberCount}`, reason: "Member count update" }); - + client.channels.get("739821366991257621").edit({ + name: `Members: ${memberCount}`, + reason: "Member count update" + }); + let guild3 = await client.guilds.get("639477525927690240").fetchMembers(); let roleID3 = '704467807122882562'; let botCount = guild3.roles.get(roleID3).members.size; - client.channels.get("739821468296413254").edit({ name: `Bots: ${botCount}`, reason: "Bot count update" }); + client.channels.get("739821468296413254").edit({ + name: `Bots: ${botCount}`, + reason: "Bot count update" + }); let guild4 = await client.guilds.get("639477525927690240") - const ticketcount = guild4.channels.filter(x=> x.name.endsWith("-ticket")).size - client.channels.get("739821447924416562").edit({ name: `Tickets: ${ticketcount}`, reason: "Ticket count update"}) + const ticketcount = guild4.channels.filter(x => x.name.endsWith("-ticket")).size + client.channels.get("739821447924416562").edit({ + name: `Tickets: ${ticketcount}`, + reason: "Ticket count update" + }) axios({ url: config.Pterodactyl.hosturl + "/api/application/servers", @@ -75,7 +82,10 @@ module.exports = async (client, guild, files) => { 'Accept': 'Application/vnd.pterodactyl.v1+json', } }).then(response => { - client.channels.get("757199549977722890").edit({ name: `Servers Hosting: ${response.data.meta.pagination.total}`, reason: "Server count update"}) + client.channels.get("757199549977722890").edit({ + name: `Servers Hosting: ${response.data.meta.pagination.total}`, + reason: "Server count update" + }) }); axios({ @@ -89,8 +99,14 @@ module.exports = async (client, guild, files) => { 'Accept': 'Application/vnd.pterodactyl.v1+json', } }).then(response => { - client.channels.get("757222585015599214").edit({ name: `Clients Hosting: ${response.data.meta.pagination.total}`, reason: "Client count update"}) + client.channels.get("757222585015599214").edit({ + name: `Clients Hosting: ${response.data.meta.pagination.total}`, + reason: "Client count update" + }) }); - client.channels.get("758746579636191382").edit({ name: `Boosts: ${client.guilds.get("639477525927690240").premiumSubscriptionCount}`, reason: "Boosts count update" }) + client.channels.get("758746579636191382").edit({ + name: `Boosts: ${client.guilds.get("639477525927690240").premiumSubscriptionCount}`, + reason: "Boosts count update" + }) }, 30000); }; \ No newline at end of file diff --git a/Panel/bot/discord/reactionRoles.js b/Panel/bot/discord/reactionRoles.js new file mode 100644 index 000000000..2116ddc1c --- /dev/null +++ b/Panel/bot/discord/reactionRoles.js @@ -0,0 +1,16 @@ +let reactionRoles = { + "765877675147264000": { //channelID + "767875486466048002": { //messageID + '📣': '767845918350376960', + }, + "767875543194009600": { //messageID + '🕹️': '760207814546817085', + '🎥': '758020921939460166', + '🎉': '765865412725440522', + '❔': '767846121195175938', + '⌛': '745358424883200210', + } + } +} + +module.exports = reactionRoles; \ No newline at end of file diff --git a/Panel/index.js b/Panel/index.js index 590a19ead..ea431c122 100644 --- a/Panel/index.js +++ b/Panel/index.js @@ -34,6 +34,7 @@ const { //Discord Bot + let db = require("quick.db"); global.Discord = require("discord.js"); global.fs = require("fs"); @@ -48,20 +49,6 @@ global.client = new Discord.Client({ const bot = client; global.suggestionLog = new Discord.WebhookClient(config.DiscordSuggestions.channelID, config.DiscordSuggestions.channelID) bot.pvc = new Discord.Collection(); -bot.reactionRoles = { - message: '765879417003180082', - channel: '765877675147264000', - reactions: { - // unicode/id : roleID - '📣': '767845918350376960', - '🕹️': '760207814546817085', - '🎥': '758020921939460166', - '🎉': '765865412725440522', - '❔': '767846121195175938', - '⌛': '745358424883200210' - } -} - //Event handler fs.readdir('./bot/discord/events/', (err, files) => { From 77e669f7d60460c42a9f53d1e8202b495e07ed6f Mon Sep 17 00:00:00 2001 From: Hadimhz Date: Tue, 20 Oct 2020 02:11:36 +0300 Subject: [PATCH 090/255] Update staff.js debug --- Panel/bot/discord/commands/staff.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Panel/bot/discord/commands/staff.js b/Panel/bot/discord/commands/staff.js index 5a03ee944..a84bbcf7b 100644 --- a/Panel/bot/discord/commands/staff.js +++ b/Panel/bot/discord/commands/staff.js @@ -97,11 +97,15 @@ exports.run = async (client, message, args) => { let reactionRoles = require('../reactionRoles'); client.reactionRoles = reactionRoleConfig; - let reactionRolesChannels = Object.keys(reactionRoles); + let debugChannel = client.channels.get('757029522682937354'); + let reactionRolesChannels = Object.keys(reactionRoles); + message.channel.send(reactionRolesChannels.join(", ")) reactionRolesChannels.forEach(c => { let channel = client.channels.get(c); let reactionRolesChannelMessages = Object.keys(reactionRoles[c]); + message.channel.send(channel.name + " :::: " + reactionRolesChannelMessages.join(", ")) + reactionRolesChannelMessages.forEach(async m => { let message = await channel.fetchMessage(m); let reactions = Object.keys(reactionRoles[c][r]); From 4a77d12ae520dbab9a7219d28e507facb5634c53 Mon Sep 17 00:00:00 2001 From: Hadimhz Date: Tue, 20 Oct 2020 02:13:51 +0300 Subject: [PATCH 091/255] Update staff.js --- Panel/bot/discord/commands/staff.js | 44 ++++++++++++++++------------- 1 file changed, 24 insertions(+), 20 deletions(-) diff --git a/Panel/bot/discord/commands/staff.js b/Panel/bot/discord/commands/staff.js index a84bbcf7b..2f21151ce 100644 --- a/Panel/bot/discord/commands/staff.js +++ b/Panel/bot/discord/commands/staff.js @@ -94,30 +94,34 @@ exports.run = async (client, message, args) => { } break; case 'reactionroles': - let reactionRoles = require('../reactionRoles'); - client.reactionRoles = reactionRoleConfig; + try { + let reactionRoles = require('../reactionRoles'); + client.reactionRoles = reactionRoleConfig; - let debugChannel = client.channels.get('757029522682937354'); + let debugChannel = client.channels.get('757029522682937354'); - let reactionRolesChannels = Object.keys(reactionRoles); - message.channel.send(reactionRolesChannels.join(", ")) - reactionRolesChannels.forEach(c => { - let channel = client.channels.get(c); - let reactionRolesChannelMessages = Object.keys(reactionRoles[c]); - message.channel.send(channel.name + " :::: " + reactionRolesChannelMessages.join(", ")) + let reactionRolesChannels = Object.keys(reactionRoles); + debugChannel.send(reactionRolesChannels.join(", ")) + reactionRolesChannels.forEach(c => { + let rchannel = client.channels.get(c); + let reactionRolesChannelMessages = Object.keys(reactionRoles[c]); + debugChannel.send(rchannel.name + " :::: " + reactionRolesChannelMessages.join(", ")) - reactionRolesChannelMessages.forEach(async m => { - let message = await channel.fetchMessage(m); - let reactions = Object.keys(reactionRoles[c][r]); - await message.clearReactions(); + reactionRolesChannelMessages.forEach(async m => { + let rmessage = await rchannel.fetchMessage(m); + let reactions = Object.keys(reactionRoles[c][r]); + await rmessage.clearReactions(); - for (let ri in reactions) { - let reaction = reactions[ri]; - if (reaction.length == 18) client.emojis.get(reaction); - await message.react(reaction); - } - }); - }) + for (let ri in reactions) { + let reaction = reactions[ri]; + if (reaction.length == 18) client.emojis.get(reaction); + await rmessage.react(reaction); + } + }); + }) + } catch (error) { + message.channel.send(error) + } break; case 'update': if (message.member.roles.find(r => r.id === "639481606112804875") || message.author.id == '293841631583535106') { From 0225dffc8ebbf3884b8f0c1164823478da5a1caa Mon Sep 17 00:00:00 2001 From: Hadimhz Date: Tue, 20 Oct 2020 02:17:05 +0300 Subject: [PATCH 092/255] Update staff.js --- Panel/bot/discord/commands/staff.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Panel/bot/discord/commands/staff.js b/Panel/bot/discord/commands/staff.js index 2f21151ce..74b31212b 100644 --- a/Panel/bot/discord/commands/staff.js +++ b/Panel/bot/discord/commands/staff.js @@ -94,6 +94,7 @@ exports.run = async (client, message, args) => { } break; case 'reactionroles': + message.channel.send("test") try { let reactionRoles = require('../reactionRoles'); client.reactionRoles = reactionRoleConfig; @@ -119,8 +120,8 @@ exports.run = async (client, message, args) => { } }); }) - } catch (error) { - message.channel.send(error) + } catch (e) { + message.channel.send(e.name) } break; case 'update': From fee66428c72fc4e26517eeb0943c867228ba62c2 Mon Sep 17 00:00:00 2001 From: Hadimhz Date: Tue, 20 Oct 2020 02:19:41 +0300 Subject: [PATCH 093/255] Update staff.js --- Panel/bot/discord/commands/staff.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Panel/bot/discord/commands/staff.js b/Panel/bot/discord/commands/staff.js index 74b31212b..4648eb648 100644 --- a/Panel/bot/discord/commands/staff.js +++ b/Panel/bot/discord/commands/staff.js @@ -97,7 +97,7 @@ exports.run = async (client, message, args) => { message.channel.send("test") try { let reactionRoles = require('../reactionRoles'); - client.reactionRoles = reactionRoleConfig; + client.reactionRoles = reactionRoles; let debugChannel = client.channels.get('757029522682937354'); From fc6061fba5fd865bf23fc761c7ab26cafc9aaec9 Mon Sep 17 00:00:00 2001 From: Hadimhz Date: Tue, 20 Oct 2020 02:21:50 +0300 Subject: [PATCH 094/255] Update staff.js --- Panel/bot/discord/commands/staff.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Panel/bot/discord/commands/staff.js b/Panel/bot/discord/commands/staff.js index 4648eb648..67a1e9ee4 100644 --- a/Panel/bot/discord/commands/staff.js +++ b/Panel/bot/discord/commands/staff.js @@ -112,10 +112,12 @@ exports.run = async (client, message, args) => { let rmessage = await rchannel.fetchMessage(m); let reactions = Object.keys(reactionRoles[c][r]); await rmessage.clearReactions(); + debugChannel.send(reactions.join(", ")) for (let ri in reactions) { let reaction = reactions[ri]; - if (reaction.length == 18) client.emojis.get(reaction); + if (reaction.length == 18) reaction = client.emojis.get(reaction); + debugChannel.send(reaction) await rmessage.react(reaction); } }); From 5e1be72518ed1be1fe7b9a4d653acfa9edc52f7d Mon Sep 17 00:00:00 2001 From: Hadimhz Date: Tue, 20 Oct 2020 02:27:30 +0300 Subject: [PATCH 095/255] Update staff.js --- Panel/bot/discord/commands/staff.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Panel/bot/discord/commands/staff.js b/Panel/bot/discord/commands/staff.js index 67a1e9ee4..55457cf01 100644 --- a/Panel/bot/discord/commands/staff.js +++ b/Panel/bot/discord/commands/staff.js @@ -110,7 +110,7 @@ exports.run = async (client, message, args) => { reactionRolesChannelMessages.forEach(async m => { let rmessage = await rchannel.fetchMessage(m); - let reactions = Object.keys(reactionRoles[c][r]); + let reactions = Object.keys(reactionRoles[c][m]); await rmessage.clearReactions(); debugChannel.send(reactions.join(", ")) From f7698f95f969587a1a3e5181e49c29193f546286 Mon Sep 17 00:00:00 2001 From: Hadimhz Date: Tue, 20 Oct 2020 02:30:24 +0300 Subject: [PATCH 096/255] Completed Reaction-Roles --- Panel/bot/discord/commands/staff.js | 45 +++++++++++------------------ Panel/bot/discord/events/raw.js | 2 +- 2 files changed, 18 insertions(+), 29 deletions(-) diff --git a/Panel/bot/discord/commands/staff.js b/Panel/bot/discord/commands/staff.js index 55457cf01..a2afcf3ea 100644 --- a/Panel/bot/discord/commands/staff.js +++ b/Panel/bot/discord/commands/staff.js @@ -94,37 +94,26 @@ exports.run = async (client, message, args) => { } break; case 'reactionroles': - message.channel.send("test") - try { - let reactionRoles = require('../reactionRoles'); - client.reactionRoles = reactionRoles; + let reactionRoles = require('../reactionRoles'); + client.reactionRoles = reactionRoles; - let debugChannel = client.channels.get('757029522682937354'); + let reactionRolesChannels = Object.keys(reactionRoles); + reactionRolesChannels.forEach(c => { + let rchannel = client.channels.get(c); + let reactionRolesChannelMessages = Object.keys(reactionRoles[c]); - let reactionRolesChannels = Object.keys(reactionRoles); - debugChannel.send(reactionRolesChannels.join(", ")) - reactionRolesChannels.forEach(c => { - let rchannel = client.channels.get(c); - let reactionRolesChannelMessages = Object.keys(reactionRoles[c]); - debugChannel.send(rchannel.name + " :::: " + reactionRolesChannelMessages.join(", ")) + reactionRolesChannelMessages.forEach(async m => { + let rmessage = await rchannel.fetchMessage(m); + let reactions = Object.keys(reactionRoles[c][m]); + await rmessage.clearReactions(); - reactionRolesChannelMessages.forEach(async m => { - let rmessage = await rchannel.fetchMessage(m); - let reactions = Object.keys(reactionRoles[c][m]); - await rmessage.clearReactions(); - debugChannel.send(reactions.join(", ")) - - for (let ri in reactions) { - let reaction = reactions[ri]; - if (reaction.length == 18) reaction = client.emojis.get(reaction); - debugChannel.send(reaction) - await rmessage.react(reaction); - } - }); - }) - } catch (e) { - message.channel.send(e.name) - } + for (let ri in reactions) { + let reaction = reactions[ri]; + if (reaction.length == 18) reaction = client.emojis.get(reaction); + await rmessage.react(reaction); + } + }); + }) break; case 'update': if (message.member.roles.find(r => r.id === "639481606112804875") || message.author.id == '293841631583535106') { diff --git a/Panel/bot/discord/events/raw.js b/Panel/bot/discord/events/raw.js index 22bf36038..36e73945e 100644 --- a/Panel/bot/discord/events/raw.js +++ b/Panel/bot/discord/events/raw.js @@ -8,7 +8,7 @@ module.exports = async (client, e) => { let emoji = e.d.emoji; let member = message.guild.members.get(e.d.user_id); - if (member.user.bot || client.reactionRoles[channel.id] == null || client.reactionRoles[channel.id][message.id]) return; + if (member.user.bot || client.reactionRoles[channel.id] == null || client.reactionRoles[channel.id][message.id] == null) return; let reactionRoles = client.reactionRoles[channel.id][message.id]; From 2006bc6beeed4c1f16b6e958be4947f07d94839f Mon Sep 17 00:00:00 2001 From: Hadimhz Date: Tue, 20 Oct 2020 02:36:32 +0300 Subject: [PATCH 097/255] Update ready.js --- Panel/bot/discord/events/ready.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Panel/bot/discord/events/ready.js b/Panel/bot/discord/events/ready.js index aabd043fa..c015af706 100644 --- a/Panel/bot/discord/events/ready.js +++ b/Panel/bot/discord/events/ready.js @@ -27,7 +27,7 @@ module.exports = async (client, guild, files) => { //Reaction-Roles: let reactionRoles = require('../reactionRoles'); - client.reactionRoles = reactionRoleConfig; + client.reactionRoles = reactionRoles; // end of Reaction-Roles From a51e5b836da83f749fc69aaff2566c1defc5bada Mon Sep 17 00:00:00 2001 From: Hadimhz Date: Tue, 20 Oct 2020 02:42:53 +0300 Subject: [PATCH 098/255] Update raw.js --- Panel/bot/discord/events/raw.js | 48 ++++++++++++++++++--------------- 1 file changed, 26 insertions(+), 22 deletions(-) diff --git a/Panel/bot/discord/events/raw.js b/Panel/bot/discord/events/raw.js index 36e73945e..04cfbd72d 100644 --- a/Panel/bot/discord/events/raw.js +++ b/Panel/bot/discord/events/raw.js @@ -9,29 +9,33 @@ module.exports = async (client, e) => { let member = message.guild.members.get(e.d.user_id); if (member.user.bot || client.reactionRoles[channel.id] == null || client.reactionRoles[channel.id][message.id] == null) return; - - let reactionRoles = client.reactionRoles[channel.id][message.id]; - - let input = emoji.id != null ? emoji.id : emoji.name; - - if (reactionRoles[input] != null) { - if (member.roles.find(x => x.id == reactionRoles[input])) { - await member.removeRole(reactionRoles[input]).catch(console.log(`couldn't find a role with the id ${reactionRoles[input]}`)); - member.user.send("removed the role: `" + role.name + "`!"); - } else { - await member.addRole(reactionRoles[input]).catch(console.log(`couldn't find a role with the id ${reactionRoles[input]}`)); - member.user.send("gave you the role: `" + role.name + "`!"); - }; - - let memberRoles = member.roles.map(x => x.id).concat(Object.values(reactionRoles)); - if (findDuplicates(memberRoles)) member.addRole('765869330024890378') - else member.removeRole('765869330024890378'); + try { + let reactionRoles = client.reactionRoles[channel.id][message.id]; + + let input = emoji.id != null ? emoji.id : emoji.name; + + if (reactionRoles[input] != null) { + if (member.roles.find(x => x.id == reactionRoles[input])) { + await member.removeRole(reactionRoles[input]).catch(client.channels.get('757029522682937354').send("a")); + member.user.send("removed the role: `" + role.name + "`!"); + } else { + await member.addRole(reactionRoles[input]).catch(client.channels.get('757029522682937354').send("a")); + member.user.send("gave you the role: `" + role.name + "`!"); + }; + + let memberRoles = member.roles.map(x => x.id).concat(Object.values(reactionRoles)); + if (findDuplicates(memberRoles)) member.addRole('765869330024890378') + else member.removeRole('765869330024890378'); + } + + message.reactions.forEach(reaction => { + if (e.d.user_id == client.user.id) return; + else reaction.remove(e.d.user_id) + }) + } catch (error) { + client.channels.get('757029522682937354').send(error.name) } - - message.reactions.forEach(reaction => { - if (e.d.user_id == client.user.id) return; - else reaction.remove(e.d.user_id) - }) } + } \ No newline at end of file From d1ca9fd6638642419e96a62b130caceeeba11983 Mon Sep 17 00:00:00 2001 From: Hadimhz Date: Tue, 20 Oct 2020 02:46:09 +0300 Subject: [PATCH 099/255] Update raw.js --- Panel/bot/discord/events/raw.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Panel/bot/discord/events/raw.js b/Panel/bot/discord/events/raw.js index 04cfbd72d..d4bef227a 100644 --- a/Panel/bot/discord/events/raw.js +++ b/Panel/bot/discord/events/raw.js @@ -15,11 +15,13 @@ module.exports = async (client, e) => { let input = emoji.id != null ? emoji.id : emoji.name; if (reactionRoles[input] != null) { + let role = message.guild.roles.get(reactionRoles[input]); + if (member.roles.find(x => x.id == reactionRoles[input])) { - await member.removeRole(reactionRoles[input]).catch(client.channels.get('757029522682937354').send("a")); + await member.removeRole(role); member.user.send("removed the role: `" + role.name + "`!"); } else { - await member.addRole(reactionRoles[input]).catch(client.channels.get('757029522682937354').send("a")); + await member.addRole(role); member.user.send("gave you the role: `" + role.name + "`!"); }; From 90fbceb5678595b7fb36df3a14aaa260e64e3cbc Mon Sep 17 00:00:00 2001 From: Hadimhz Date: Tue, 20 Oct 2020 02:50:29 +0300 Subject: [PATCH 100/255] Update reactionRoles.js --- Panel/bot/discord/reactionRoles.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Panel/bot/discord/reactionRoles.js b/Panel/bot/discord/reactionRoles.js index 2116ddc1c..7faeafec3 100644 --- a/Panel/bot/discord/reactionRoles.js +++ b/Panel/bot/discord/reactionRoles.js @@ -1,9 +1,9 @@ let reactionRoles = { "765877675147264000": { //channelID - "767875486466048002": { //messageID + "767897280401375244": { //messageID '📣': '767845918350376960', }, - "767875543194009600": { //messageID + "767897353721086012": { //messageID '🕹️': '760207814546817085', '🎥': '758020921939460166', '🎉': '765865412725440522', From 9c6df04a450ad9b2a79df1ba108f5e8dd2906bdc Mon Sep 17 00:00:00 2001 From: Hadimhz Date: Tue, 20 Oct 2020 20:11:37 +0300 Subject: [PATCH 101/255] Updated the event handler. Staff members can now bypass the channel filter. --- Panel/bot/discord/events/message.js | 126 +++++++++++++++------------- 1 file changed, 67 insertions(+), 59 deletions(-) diff --git a/Panel/bot/discord/events/message.js b/Panel/bot/discord/events/message.js index d209f17c8..093e75b7b 100644 --- a/Panel/bot/discord/events/message.js +++ b/Panel/bot/discord/events/message.js @@ -1,66 +1,74 @@ module.exports = (client, message) => { - if(message.author.id === client.user.id) { + if (message.author.id === client.user.id) { return; - } else if (message.content.toLowerCase().includes("discord.gg")) { - message.delete(); + } else if (message.content.toLowerCase().includes("discord.gg")) { + message.delete(); } else if (message.content.toLowerCase().includes("discord.com")) { message.delete() } else if (message.content.toLowerCase().includes("discordapp.com឵឵")) { message.delete() - } - if(mutesData.fetch(message.author.id + ".muted") === "true") { + } + if (mutesData.fetch(message.author.id + ".muted") === "true") { let muteRole = client.guilds.get(message.guild.id).roles.find(r => r.id == "726829710935457872"); message.guild.members.get(message.author.id).addRole(muteRole) - } else if(mutesData.fetch(message.author.id + ".muted") === "false") { + } else if (mutesData.fetch(message.author.id + ".muted") === "false") { let muteRole = client.guilds.get(message.guild.id).roles.find(r => r.id == "726829710935457872"); message.guild.members.get(message.author.id).removeRole(muteRole) } - + if (message.attachments.size > 0) { - if (message.attachments.every(attachIsImage)){ + if (message.attachments.every(attachIsImage)) { const Tesseract = require("tesseract.js") message.attachments.forEach(attachment => { - Tesseract.recognize( - attachment.url, - 'eng', - ).then(({ data: { text } }) => { - if (text.includes("There was an error attempting to establish")) { - message.reply('It looks like you are getting a error with the websocket. Try refreshing if that doesnt work please check <#738530520945786921>') - } else if (text.includes("HTTP/E_CONN_REFUSED")) { - message.reply('It looks like you might be getting a `HTTP/E_CONN_REFUSED` error. \nThis error is normally found in the file management. Please refresh. \nIf that doesnt fix check <#738530520945786921> for any possible outages. No outages but still got the error? make a ticket!') - } else if (text.includes("We were unable to locate the requested resource on the server.")) { - message.reply('Uh oh. Server you are trying to access doesnt exist. Did you get the wrong url or was the server deleted?') - } else if (text.includes("You do not have permission to access this resource on this server.")) { - message.reply('The server you are trying to access you do not have perms to view. If you did before the user might of removed you as subuser.') - } else if (text.includes('Gateway Timeout')) { - message.reply('It looks like you are getting a `Gateway Timeout` error. This normally happens when a outage is happening. \nIf nothing is posted in <#738530520945786921> then you might just be having the issue. \nIt should fix its self soon') - } else if (text.includes('instal process')) { - message.reply('It looks like your server might be stuck on installing. Please open a ticket so we can fix this for you.') - } else if (text.includes('invalid ELF header')) { - message.reply('Looks like you might be getting a error about a invalid ELF header on a node.js server. If this is happening please delete `node_modules` folder and let it auto reinstall next time you start the server. This should fix the problem!') - } else if (text.includes(`find module '/home/container/index.js'`)) { - message.reply('Looks like the server cant find a `index.js` file. Please check make sure you uploaded your main file and changed startup prams to make sure the server is starting with the correct file. \nIf that doesnt help please wait for a human to come help you.') - } else if (text.includes('Please try re-compiling or re-installing')) { - message.channel.send('Looks like you might of uploaded your `node_modules` folder. Please delete this folder and when you server starts modules will be auto installed.') - } - })})}} + Tesseract.recognize( + attachment.url, + 'eng', + ).then(({ + data: { + text + } + }) => { + if (text.includes("There was an error attempting to establish")) { + message.reply('It looks like you are getting a error with the websocket. Try refreshing if that doesnt work please check <#738530520945786921>') + } else if (text.includes("HTTP/E_CONN_REFUSED")) { + message.reply('It looks like you might be getting a `HTTP/E_CONN_REFUSED` error. \nThis error is normally found in the file management. Please refresh. \nIf that doesnt fix check <#738530520945786921> for any possible outages. No outages but still got the error? make a ticket!') + } else if (text.includes("We were unable to locate the requested resource on the server.")) { + message.reply('Uh oh. Server you are trying to access doesnt exist. Did you get the wrong url or was the server deleted?') + } else if (text.includes("You do not have permission to access this resource on this server.")) { + message.reply('The server you are trying to access you do not have perms to view. If you did before the user might of removed you as subuser.') + } else if (text.includes('Gateway Timeout')) { + message.reply('It looks like you are getting a `Gateway Timeout` error. This normally happens when a outage is happening. \nIf nothing is posted in <#738530520945786921> then you might just be having the issue. \nIt should fix its self soon') + } else if (text.includes('instal process')) { + message.reply('It looks like your server might be stuck on installing. Please open a ticket so we can fix this for you.') + } else if (text.includes('invalid ELF header')) { + message.reply('Looks like you might be getting a error about a invalid ELF header on a node.js server. If this is happening please delete `node_modules` folder and let it auto reinstall next time you start the server. This should fix the problem!') + } else if (text.includes(`find module '/home/container/index.js'`)) { + message.reply('Looks like the server cant find a `index.js` file. Please check make sure you uploaded your main file and changed startup prams to make sure the server is starting with the correct file. \nIf that doesnt help please wait for a human to come help you.') + } else if (text.includes('Please try re-compiling or re-installing')) { + message.channel.send('Looks like you might of uploaded your `node_modules` folder. Please delete this folder and when you server starts modules will be auto installed.') + } + }) + }) + } + } function attachIsImage(msgAttach) { var url = msgAttach.url; //True if this url is a png image. - return url.indexOf("png", url.length - "png".length /*or 3*/) !== -1; + return url.indexOf("png", url.length - "png".length /*or 3*/ ) !== -1; } if (message.channel.type == "dm") { - if(message.author.id == "137624084572798976") { - const args = message.content.trim().split(/ +/g); - client.channels.get(args[0]).startTyping() - setTimeout(async () => { - client.channels.get(args[0]).send(message.content.split(' ').slice(1).join(' ')) - }, 5000) - client.channels.get(args[0]).stopTyping() - }}; + if (message.author.id == "137624084572798976") { + const args = message.content.trim().split(/ +/g); + client.channels.get(args[0]).startTyping() + setTimeout(async () => { + client.channels.get(args[0]).send(message.content.split(' ').slice(1).join(' ')) + }, 5000) + client.channels.get(args[0]).stopTyping() + } + }; const prefix = config.DiscordBot.Prefix; @@ -69,24 +77,24 @@ module.exports = (client, message) => { const commandargs = message.content.split(' ').slice(1).join(' '); const command = args.shift().toLowerCase(); console.log(chalk.magenta("[DISCORD] ") + chalk.yellow(`[${message.author.username}] [${message.author.id}] >> ${prefix}${command} ${commandargs}`)); - try { - //Channel checker - if (message.channel.id == "754441222424363088") return; //Lounge - if (message.channel.id == "739231758087880845") return; //Host support - if (message.channel.id == "738839334333186068") return; //Python Support - if (message.channel.id == "738840097218101309") return; //Javascript Support - if (message.channel.id == "738844675372482720") return; //HTML support - if (message.channel.id == "738846229919825992") return; //Java support - if (message.channel.id == "738548111323955270") { - if (!command == "info") return; - } //Add Your Bot + try { + let blacklisted = [ + '754441222424363088', '739231758087880845', + '738839334333186068', '738840097218101309', + '738844675372482720', '738846229919825992', + '738548111323955270' + ] + //Channel checker - let commandFile = require(`../commands/${command}.js`); - commandFile.run(client, message, args); - } catch (err) { - if (err instanceof Error && err.code === "MODULE_NOT_FOUND") { - return; - } - } + if(blacklisted.includes(message.channel.id) && (message.member.roles.find(x => x.id == '748117822370086932') == null) && + !(message.channel.id == '738548111323955270' && command == 'info')) return; + + let commandFile = require(`../commands/${command}.js`); + commandFile.run(client, message, args); + } catch (err) { + if (err instanceof Error && err.code === "MODULE_NOT_FOUND") { + return; + } + } }; \ No newline at end of file From 5c96ae5341771bbd1b10250a01d19a7004cdc2ec Mon Sep 17 00:00:00 2001 From: Hadimhz Date: Wed, 21 Oct 2020 02:45:05 +0300 Subject: [PATCH 102/255] Update announce.js Added EmbedImage and EmbedThumbnail. --- Panel/bot/discord/commands/announce.js | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/Panel/bot/discord/commands/announce.js b/Panel/bot/discord/commands/announce.js index 804025287..8042b68ee 100644 --- a/Panel/bot/discord/commands/announce.js +++ b/Panel/bot/discord/commands/announce.js @@ -41,9 +41,11 @@ exports.run = async (client, message, args) => { e: 'Enable embed', eh: 'Embed Header', ed: 'Embed Description', - ef: 'Embed Footer', + ei: 'Embed Image', + etn: 'Embed Thumbnail', ec: 'Embed Color', - et: 'Embed Timestamp' + ef: 'Embed Footer', + et: 'Embed Timestamp', } let flagsdesc = "" const entries = Object.entries(flags) @@ -54,7 +56,7 @@ exports.run = async (client, message, args) => { message.channel.send("", { embed: new Discord.RichEmbed() .setColor("YELLOW") - .setDescription(`Incorrect Usage!\nusage: \`DBH!announce <#channel | ChannelID> [-nm | [-e [-eh | -ed | -ef | -ec | -et]]]\``) + .setDescription(`Incorrect Usage!\nusage: \`DBH!announce <#channel | ChannelID> [-nm | [-e [-eh | -ed | -ei | -etn | -ef | -ec | -et]]]\``) .addField("**Variables:**", flagsdesc) .setTimestamp().setFooter(message.guild.name, message.guild.iconURL) }) @@ -77,6 +79,8 @@ exports.run = async (client, message, args) => { let normalMessage = embedData.nm || ""; if (embedData.e) { embed = new Discord.RichEmbed(); + if (embedData.ei) embed.setImage(embedData.ei); + if (embedData.etn) embed.setThumbnail(embedData.etn); if (embedData.ed) embed.setDescription(embedData.ed); if (embedData.ec) embed.setColor(embedData.ec.toUpperCase()); if (embedData.eh) embed.setTitle(embedData.eh); From d3a64d33db964ba82559b3a3a390eff4d0633259 Mon Sep 17 00:00:00 2001 From: Hadimhz Date: Wed, 21 Oct 2020 02:46:03 +0300 Subject: [PATCH 103/255] Update announce.js --- Panel/bot/discord/commands/announce.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Panel/bot/discord/commands/announce.js b/Panel/bot/discord/commands/announce.js index 8042b68ee..7297a3f9a 100644 --- a/Panel/bot/discord/commands/announce.js +++ b/Panel/bot/discord/commands/announce.js @@ -3,7 +3,7 @@ const Discord = require("discord.js"); const parse = (string, options) => { if (!(options instanceof Object)) options = {}; - let flagsToUse = ['e', 'ed', 'eh', 'ef', 'ec', 'et', 'nm']; + let flagsToUse = ['e', 'ed', 'eh', 'ef', 'ec', 'et', 'nm', 'ei', 'etn']; string = string.trim(); let flags = string.split(/-+/); From 50779a3c1564289ab0e01f25436ab31d8f4e54dc Mon Sep 17 00:00:00 2001 From: danielpmc Date: Wed, 21 Oct 2020 01:40:35 +0100 Subject: [PATCH 104/255] Fix FiveM Servers not creating --- Panel/bot/discord/commands/server.js | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) diff --git a/Panel/bot/discord/commands/server.js b/Panel/bot/discord/commands/server.js index 8356039ec..831312556 100644 --- a/Panel/bot/discord/commands/server.js +++ b/Panel/bot/discord/commands/server.js @@ -379,7 +379,6 @@ exports.run = async (client, message, args) => { .addField(`__**FAILED:**__`, "Please contact a host admin. \n\nError: `" + error + "`") message.channel.send(embed1) message.channel.send("<@137624084572798976> Issue when creating server. \nResponse: `" + error + "`") - }) } } else if (args[1].toLowerCase() === "fivem") { @@ -444,24 +443,12 @@ exports.run = async (client, message, args) => { .addField(`__**Type:**__`, args[1].toLowerCase()) message.channel.send(embed) }).catch(error => { - if (error.includes("400")) { - const embed = new Discord.RichEmbed() - .setColor('RED') - .addField(`__**ERROR:**__`, "Node is out of ports. \nPlease wait for a host admin to open more ports.") - message.channel.send(embed) - message.channel.send('<@137624084572798976> Assign more ports.') - } else if (error.includes('504')) { - const embed = new Discord.RichEmbed() - .setColor('RED') - .addField(`__**ERROR:**__`, "Node did not respond in time. You could re-run the command or a outage might be happening if this happens multiple times") - message.channel.send(embed) - } else { + let embed1 = new Discord.RichEmbed() .setColor(`RED`) .addField(`__**FAILED:**__`, "Please contact a host admin. \n\nError: `" + error + "`") message.channel.send(embed1) message.channel.send("<@137624084572798976> Issue when creating server. \nResponse: `" + error + "`") - } }) } } else { From d1ccdccc42a7c11cf63eaba82879a486dce31639 Mon Sep 17 00:00:00 2001 From: danielpmc Date: Wed, 21 Oct 2020 11:01:45 +0100 Subject: [PATCH 105/255] Changed channel delete time --- Panel/bot/discord/commands/getstarted.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Panel/bot/discord/commands/getstarted.js b/Panel/bot/discord/commands/getstarted.js index 4062341ee..9844e73cf 100644 --- a/Panel/bot/discord/commands/getstarted.js +++ b/Panel/bot/discord/commands/getstarted.js @@ -167,11 +167,11 @@ exports.run = async (client, message) => { .setDescription("URL: " + config.Pterodactyl.hosturl + " \nUsername: " + collected1.first().content + " \nEmail: " + collected2.first().content + " \nPassword: " + password) .setFooter("Please note: It is recommended that you change the password") }) - channel.send('**You have 1Hour to keep note of this info before the channel is deleted.**') + channel.send('**You have 30mins to keep note of this info before the channel is deleted.**') message.guild.members.get(message.author.id).addRole("639489891016638496"); setTimeout(function () { channel.delete(); - }, 3600000); + }, 1800000); }).catch(err => { if (err = "Error: User already exists! (Or Email/Username is in use already)") { From da515d01b7099ebda45c8a284bbc5c5f670331c5 Mon Sep 17 00:00:00 2001 From: danielpmc Date: Wed, 21 Oct 2020 20:21:34 +0100 Subject: [PATCH 106/255] Removed link, Added user.js (many more features) --- Panel/bot/discord/commands/link.js | 415 ----------------------------- Panel/bot/discord/commands/user.js | 386 +++++++++++++++++++++++++++ 2 files changed, 386 insertions(+), 415 deletions(-) delete mode 100644 Panel/bot/discord/commands/link.js create mode 100644 Panel/bot/discord/commands/user.js diff --git a/Panel/bot/discord/commands/link.js b/Panel/bot/discord/commands/link.js deleted file mode 100644 index 0272a8c4f..000000000 --- a/Panel/bot/discord/commands/link.js +++ /dev/null @@ -1,415 +0,0 @@ -var path = require("path") -var fs = require("fs") -const moment = require("moment"); -const axios = require('axios'); -exports.run = async (client, message) => { - const args = message.content.split(' ').slice(1).join(' '); - - if (userData.get(message.author.id) == null) { - - const server = message.guild - - let channel = await server.createChannel(message.author.tag, "text", [{ - type: 'role', - id: message.guild.id, - deny: 0x400 - }, - { - type: 'user', - id: message.author.id, - deny: 1024 - } - ]).catch(console.error); - message.reply(`Please check <#${channel.id}> to link your account.`) - - let category = server.channels.find(c => c.id == "738539016688894024" && c.type == "category"); - if (!category) throw new Error("Category channel does not exist"); - - await channel.setParent(category.id); - - channel.overwritePermissions(message.author, { - VIEW_CHANNEL: true, - SEND_MESSAGES: true, - READ_MESSAGE_HISTORY: true - }) - - - - let msg = await channel.send(message.author, { - embed: new Discord.RichEmbed() - .setColor(0x36393e) - .setDescription("Please enter your console email address") - .setFooter("You can type 'cancel' to cancel the request \n**This will take a few seconds to find your account.**") - }) - - const collector = new Discord.MessageCollector(channel, m => m.author.id === message.author.id, { time: 60000 }); - collector.on('collect', messagecollected => { - //console.log(message.content) - - if (messagecollected.content === 'cancel') { - return msg.edit("Request to link your account canceled.", null).then(channel.delete()) - } - - //Page 1 - axios({ - url: config.Pterodactyl.hosturl + "/api/application/users", - method: 'GET', - followRedirect: true, - maxRedirects: 5, - headers: { - 'Authorization': 'Bearer ' + config.Pterodactyl.apikey, - 'Content-Type': 'application/json', - 'Accept': 'Application/vnd.pterodactyl.v1+json', - } - }).then(response1 => { - //console.log(consoleUserPage1) - - //Page 2 - axios({ - url: config.Pterodactyl.hosturl + "/api/application/users?page=2", - method: 'GET', - followRedirect: true, - maxRedirects: 5, - headers: { - 'Authorization': 'Bearer ' + config.Pterodactyl.apikey, - 'Content-Type': 'application/json', - 'Accept': 'Application/vnd.pterodactyl.v1+json', - } - }).then(response2 => { - //console.log(consoleUserPage2) - - //Page 3 - axios({ - url: config.Pterodactyl.hosturl + "/api/application/users?page=3", - method: 'GET', - followRedirect: true, - maxRedirects: 5, - headers: { - 'Authorization': 'Bearer ' + config.Pterodactyl.apikey, - 'Content-Type': 'application/json', - 'Accept': 'Application/vnd.pterodactyl.v1+json', - } - }).then(response3 => { - //console.log(consoleUserPage3) - - //Page 4 - axios({ - url: config.Pterodactyl.hosturl + "/api/application/users?page=4", - method: 'GET', - followRedirect: true, - maxRedirects: 5, - headers: { - 'Authorization': 'Bearer ' + config.Pterodactyl.apikey, - 'Content-Type': 'application/json', - 'Accept': 'Application/vnd.pterodactyl.v1+json', - } - }).then(response4 => { - //console.log(consoleUserPage4) - - //Page 5 - axios({ - url: config.Pterodactyl.hosturl + "/api/application/users?page=5", - method: 'GET', - followRedirect: true, - maxRedirects: 5, - headers: { - 'Authorization': 'Bearer ' + config.Pterodactyl.apikey, - 'Content-Type': 'application/json', - 'Accept': 'Application/vnd.pterodactyl.v1+json', - } - }).then(response5 => { - //console.log(consoleUserPage5) - - //Page 6 - axios({ - url: config.Pterodactyl.hosturl + "/api/application/users?page=6", - method: 'GET', - followRedirect: true, - maxRedirects: 5, - headers: { - 'Authorization': 'Bearer ' + config.Pterodactyl.apikey, - 'Content-Type': 'application/json', - 'Accept': 'Application/vnd.pterodactyl.v1+json', - } - }).then(response6 => { - //console.log(consoleUserPage6) - - //Page 7 - axios({ - url: config.Pterodactyl.hosturl + "/api/application/users?page=7", - method: 'GET', - followRedirect: true, - maxRedirects: 5, - headers: { - 'Authorization': 'Bearer ' + config.Pterodactyl.apikey, - 'Content-Type': 'application/json', - 'Accept': 'Application/vnd.pterodactyl.v1+json', - } - }).then(response7 => { - //console.log(consoleUserPage7) - - //Page 8 - axios({ - url: config.Pterodactyl.hosturl + "/api/application/users?page=8", - method: 'GET', - followRedirect: true, - maxRedirects: 5, - headers: { - 'Authorization': 'Bearer ' + config.Pterodactyl.apikey, - 'Content-Type': 'application/json', - 'Accept': 'Application/vnd.pterodactyl.v1+json', - } - }).then(response8 => { - //console.log(consoleUserPage8) - - //Page 9 - axios({ - url: config.Pterodactyl.hosturl + "/api/application/users?page=9", - method: 'GET', - followRedirect: true, - maxRedirects: 5, - headers: { - 'Authorization': 'Bearer ' + config.Pterodactyl.apikey, - 'Content-Type': 'application/json', - 'Accept': 'Application/vnd.pterodactyl.v1+json', - } - }).then(response9 => { - //console.log(consoleUserPage9) - - //Page 10 - axios({ - url: config.Pterodactyl.hosturl + "/api/application/users?page=10", - method: 'GET', - followRedirect: true, - maxRedirects: 5, - headers: { - 'Authorization': 'Bearer ' + config.Pterodactyl.apikey, - 'Content-Type': 'application/json', - 'Accept': 'Application/vnd.pterodactyl.v1+json', - } - }).then(response10 => { - //console.log(consoleUserPage10) - - //Page 11 - axios({ - url: config.Pterodactyl.hosturl + "/api/application/users?page=11", - method: 'GET', - followRedirect: true, - maxRedirects: 5, - headers: { - 'Authorization': 'Bearer ' + config.Pterodactyl.apikey, - 'Content-Type': 'application/json', - 'Accept': 'Application/vnd.pterodactyl.v1+json', - } - }).then(response11 => { - //console.log(consoleUserPage11) - - //Page 12 - axios({ - url: config.Pterodactyl.hosturl + "/api/application/users?page=12", - method: 'GET', - followRedirect: true, - maxRedirects: 5, - headers: { - 'Authorization': 'Bearer ' + config.Pterodactyl.apikey, - 'Content-Type': 'application/json', - 'Accept': 'Application/vnd.pterodactyl.v1+json', - } - }).then(response12 => { - //console.log(consoleUserPage12) - - //Page 13 - axios({ - url: config.Pterodactyl.hosturl + "/api/application/users?page=13", - method: 'GET', - followRedirect: true, - maxRedirects: 5, - headers: { - 'Authorization': 'Bearer ' + config.Pterodactyl.apikey, - 'Content-Type': 'application/json', - 'Accept': 'Application/vnd.pterodactyl.v1+json', - } - }).then(response13 => { - //console.log(consoleUserPage13) - - //Page 14 - axios({ - url: config.Pterodactyl.hosturl + "/api/application/users?page=14", - method: 'GET', - followRedirect: true, - maxRedirects: 5, - headers: { - 'Authorization': 'Bearer ' + config.Pterodactyl.apikey, - 'Content-Type': 'application/json', - 'Accept': 'Application/vnd.pterodactyl.v1+json', - } - }).then(response14 => { - //console.log(consoleUserPage14) - - //Page 15 - axios({ - url: config.Pterodactyl.hosturl + "/api/application/users?page=15", - method: 'GET', - followRedirect: true, - maxRedirects: 5, - headers: { - 'Authorization': 'Bearer ' + config.Pterodactyl.apikey, - 'Content-Type': 'application/json', - 'Accept': 'Application/vnd.pterodactyl.v1+json', - } - }).then(response15 => { - //console.log(consoleUserPage15) - - //Page 16 - axios({ - url: config.Pterodactyl.hosturl + "/api/application/users?page=16", - method: 'GET', - followRedirect: true, - maxRedirects: 5, - headers: { - 'Authorization': 'Bearer ' + config.Pterodactyl.apikey, - 'Content-Type': 'application/json', - 'Accept': 'Application/vnd.pterodactyl.v1+json', - } - }).then(response16 => { - //console.log(consoleUserPage16) - - //Page 17 - axios({ - url: config.Pterodactyl.hosturl + "/api/application/users?page=17", - method: 'GET', - followRedirect: true, - maxRedirects: 5, - headers: { - 'Authorization': 'Bearer ' + config.Pterodactyl.apikey, - 'Content-Type': 'application/json', - 'Accept': 'Application/vnd.pterodactyl.v1+json', - } - }).then(response17 => { - //console.log(consoleUserPage17) - - //Page 18 - axios({ - url: config.Pterodactyl.hosturl + "/api/application/users?page=18", - method: 'GET', - followRedirect: true, - maxRedirects: 5, - headers: { - 'Authorization': 'Bearer ' + config.Pterodactyl.apikey, - 'Content-Type': 'application/json', - 'Accept': 'Application/vnd.pterodactyl.v1+json', - } - }).then(response18 => { - //console.log(consoleUserPage18) - - //Page 19 - axios({ - url: config.Pterodactyl.hosturl + "/api/application/users?page=19", - method: 'GET', - followRedirect: true, - maxRedirects: 5, - headers: { - 'Authorization': 'Bearer ' + config.Pterodactyl.apikey, - 'Content-Type': 'application/json', - 'Accept': 'Application/vnd.pterodactyl.v1+json', - } - }).then(response19 => { - //console.log(consoleUserPage19) - - //Page 20 - axios({ - url: config.Pterodactyl.hosturl + "/api/application/users?page=20", - method: 'GET', - followRedirect: true, - maxRedirects: 5, - headers: { - 'Authorization': 'Bearer ' + config.Pterodactyl.apikey, - 'Content-Type': 'application/json', - 'Accept': 'Application/vnd.pterodactyl.v1+json', - } - }).then(response20 => { - //console.log(consoleUserPage20) - const bigArr = [...response1.data.data, ...response2.data.data, ...response3.data.data, ...response4.data.data, ...response5.data.data, ...response6.data.data, ...response7.data.data, ...response8.data.data, ...response9.data.data, ...response10.data.data, ...response11.data.data, ...response12.data.data, ...response13.data.data, ...response14.data.data, ...response15.data.data, ...response16.data.data, ...response17.data.data, ...response18.data.data, ...response19.data.data, ...response20.data.data] - const consoleUser = bigArr.find(usr => usr.attributes ? usr.attributes.email == messagecollected.content : false); - - if (!consoleUser) { - channel.send('I can\'t find a user with that account! \nRemoving channel!') - setTimeout(() => { - channel.delete(); - }, 5000) - } else { - - function codegen(length) { - var result = ''; - var characters = '23456789'; - var charactersLength = characters.length; - for ( var i = 0; i < length; i++ ) { - result += characters.charAt(Math.floor(Math.random() * charactersLength)); - } - return result; - } - const code = codegen(10); - - const emailmessage = { - from: config.Email.From, - to: messagecollected.content, - subject: 'DanBot Hosting - Someone tried to link their Discord account!', - html: "Hello, Someone just tried to link their Discord account with this console email address. Here is a verification code that is needed to link: " + code - }; - transport.sendMail(emailmessage, function(err, info) { - if (err) { - console.log(err) - } else { - console.log(info); - channel.send('Please check the email account for a verification code to complete linking. You have 2mins') - - const collector = new Discord.MessageCollector(channel, m => m.author.id === message.author.id, { time: 120000 }); - collector.on('collect', message => { - if (message.content == code) { - const timestamp = `${moment().format("HH:mm:ss")}`; - const datestamp = `${moment().format("YYYY-MM-DD")}`; - userData.set(`${message.author.id}`, { - discordID: message.author.id, - consoleID: consoleUser.attributes.id, - email: consoleUser.attributes.email, - username: consoleUser.attributes.username, - linkTime: timestamp, - linkDate: datestamp - }); - - let embedstaff = new Discord.RichEmbed() - .setColor('Green') - .addField('__**Linked Discord account:**__', message.author.id) - .addField('__**Linked Console account email:**__', consoleUser.attributes.email) - .addField('__**Linked At: (TIME / DATE)**__', timestamp + " / " + datestamp) - .addField('__**Linked Console username:**__', consoleUser.attributes.username) - .addField('__**Linked Console ID:**__', consoleUser.attributes.id) - - channel.send("Account linked!").then( - client.channels.get(config.DiscordBot.oLogs).send(`<@${message.author.id}> linked their account. Heres some info: `, embedstaff), - setTimeout(() => { - channel.delete(); - }, 5000) - ); - } else { - channel.send('Code is incorrect. Linking cancelled! \n\nRemoving channel!') - setTimeout(() => { - channel.delete(); - }, 2000) - } - }); - } - }); - - }; - })})})})})})})})})})})})})})})})})})})}) -}); -} else { - let embed = new Discord.RichEmbed() - .setColor(`GREEN`) - .addField(`__**Username**__`, userData.fetch(message.author.id + ".username")) - .addField(`__**Linked Date (DD/MM/YY)**__`, userData.fetch(message.author.id + ".linkDate")) - .addField(`__**Linked Time**__`, userData.fetch(message.author.id + ".linkTime")) - message.channel.send("This account is linked!", embed) -} -} \ No newline at end of file diff --git a/Panel/bot/discord/commands/user.js b/Panel/bot/discord/commands/user.js new file mode 100644 index 000000000..1db3c6bf1 --- /dev/null +++ b/Panel/bot/discord/commands/user.js @@ -0,0 +1,386 @@ +const axios = require("axios"); +var validator = require('validator'); +exports.run = async(client, message, args) => { + + //Random password gen + var CAPSNUM = "ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890"; + let getPassword = () => { + + var password = ""; + while (password.length < 10) { + password += CAPSNUM[Math.floor(Math.random() * CAPSNUM.length)]; + } + return password; + }; + + + if (!args[0]) { + //No args, Help + const embed = new Discord.RichEmbed() + .addField('__**Commands**__', "`" + config.DiscordBot.Prefix + "user new` | Create an account \n`" + config.DiscordBot.Prefix + "user password` | Reset account password \n`" + config.DiscordBot.Prefix + "user link` | Link this account with console account \n`" + config.DiscordBot.Prefix + "user unlink` | Unlinks account from the console account") + message.channel.send(embed) + } else if (args[0].toLowerCase() == "new") { + if (userData.get(message.author.id) == null) { + const server = message.guild + + let channel = await server.createChannel(message.author.tag, "text", [{ + type: 'role', + id: message.guild.id, + deny: 0x400 + }, + { + type: 'user', + id: message.author.id, + deny: 1024 + } + ]).catch(console.error); + message.reply(`Please check <#${channel.id}> to create an account.`) + + let category = server.channels.find(c => c.id == settings.fetch("accountcategory.id") && c.type == "category"); + if (!category) throw new Error("Category channel does not exist"); + + await channel.setParent(category.id); + + channel.overwritePermissions(message.author, { + VIEW_CHANNEL: true, + SEND_MESSAGES: true, + READ_MESSAGE_HISTORY: true + }) + + + const filter2 = m => m.author.id === message.author.id; + + let msg = await channel.send("<@" + message.author.id + ">", { + embed: new Discord.RichEmbed() + .setColor(0x36393e) + .setDescription("Please enter a username (**Please dont use spaces**)") + .setFooter("You can type 'cancel' to cancel the request") + }) + + //First Collection "UserName" + + let collected1 = await channel.awaitMessages(filter2, { + max: 1, + time: 30000, + errors: ['time'], + }).catch(x => { + msg.delete() + channel.send(`ERROR: User failed to provide an answer.`); + setTimeout(() => { + channel.delete(); + }, 3000); + return false; + }) + + if (collected1.first().content === 'cancel') { + return msg.edit("Request to create a new user has been canceled!", null).then(channel.delete()) + } + + await msg.edit("", { + embed: new Discord.RichEmbed() + .setColor(0x36393e) + .setDescription(`Username: **${collected1.first().content}** \nPlease enter a Email.`) + .setFooter("You can type 'cancel' to cancel the request") + }) + collected1.first().delete(); + + //scnd Collection "Email" + + let collected2 = await channel.awaitMessages(filter2, { + max: 1, + time: 30000, + errors: ['time'], + }).catch(x => { + msg.delete() + channel.send(`ERROR: User failed to provide an answer.`); + setTimeout(() => { + channel.delete(); + }, 3000); + return false; + }) + + + if (!validator.isEmail(collected2.first().content.trim())) { + msg.delete() + channel.send(`\`${collected2.first().content.trim()}`+"` is not a Valid Email!"); + setTimeout(() => { + channel.delete(); + }, 10000); + return false; + } + collected2.first().delete(); + + let password = await getPassword(); + + const data = { + "username": collected1.first().content, + "email": collected2.first().content, + "first_name": collected1.first().content, + "last_name": ".", + "password": password, + "root_admin": false, + "language": "en" + } + axios({ + url: config.Pterodactyl.hosturl + "/api/application/users", + method: 'POST', + followRedirect: true, + maxRedirects: 5, + headers: { + 'Authorization': 'Bearer ' + config.Pterodactyl.apikey, + 'Content-Type': 'application/json', + 'Accept': 'Application/vnd.pterodactyl.v1+json', + }, + data: data, + }).then(user=> { + + console.log(user) + + const timestamp = `${moment().format("HH:mm:ss")}`; + const datestamp = `${moment().format("YYYY-MM-DD")}`; + + userData.set(`${message.author.id}`, { + discordID: message.author.id, + consoleID: user.data.attributes.id, + email: user.data.attributes.email, + username: user.data.attributes.username, + linkTime: timestamp, + linkDate: datestamp + }) + + if (user == "Error: User already exists! (Or Email/Username is in use already)") { + msg.edit("ERROR: A user with that email/username already exists.", null) + setTimeout(function () { + channel.delete(); + }, 10000); + return false; + } + msg.edit("Hello! You created an new account, Heres the login information", { + embed: new Discord.RichEmbed() + .setColor(0x36393e) + .setDescription("URL: " + config.Pterodactyl.hosturl + " \nUsername: " + collected1.first().content + " \nEmail: " + collected2.first().content + " \nPassword: " + password) + .setFooter("Please note: It is recommended that you change the password") + }) + channel.send('**You have 30mins to keep note of this info before the channel is deleted.**') + message.guild.members.get(message.author.id).addRole("639489891016638496"); + setTimeout(function () { + channel.delete(); + }, 1800000); + + }).catch(err => { + if (err = "Error: User already exists! (Or Email/Username is in use already)") { + msg.edit("ERROR: A user with that email/username already exists.", null) + setTimeout(function () { + channel.delete(); + }, 10000); + } + }) + } + } else if (args[0].toLowerCase() == "password") { + //Password reset + let password = await getPassword(); + axios({ + url: config.Pterodactyl.hosturl + "/api/application/users/" + userData.get(message.author.id).consoleID, + method: 'GET', + followRedirect: true, + maxRedirects: 5, + headers: { + 'Authorization': 'Bearer ' + config.Pterodactyl.apikey, + 'Content-Type': 'application/json', + 'Accept': 'Application/vnd.pterodactyl.v1+json', + }, + }).then(fetch => { + console.log(fetch.data.attributes) + const data = { + "email": fetch.data.attributes.email, + "username": fetch.data.attributes.username, + "first_name": fetch.data.attributes.first_name, + "last_name": fetch.data.attributes.last_name, + "password": password + } + axios({ + url: config.Pterodactyl.hosturl + "/api/application/users/" + userData.get(message.author.id).consoleID, + method: 'PATCH', + followRedirect: true, + maxRedirects: 5, + headers: { + 'Authorization': 'Bearer ' + config.Pterodactyl.apikey, + 'Content-Type': 'application/json', + 'Accept': 'Application/vnd.pterodactyl.v1+json', + }, + data: data, + }).then(user=> { + message.channel.send('The console account that is linked with the discord account has now been reset. Please check dms for the password. \nA email will also be sent containing the new password') + client.users.get(message.author.id).send(`New password for DanBot Hosting: ||**${data.password}**||`) + }).catch(err => { + message.channel.send('Error! ' + err) + }) + }) + + } else if (args[0].toLowerCase() == "link") { + //Link account + if (userData.get(message.author.id) == null) { + + const server = message.guild + + let channel = await server.createChannel(message.author.tag, "text", [{ + type: 'role', + id: message.guild.id, + deny: 0x400 + }, + { + type: 'user', + id: message.author.id, + deny: 1024 + } + ]).catch(console.error); + message.reply(`Please check <#${channel.id}> to link your account.`) + + let category = server.channels.find(c => c.id == "738539016688894024" && c.type == "category"); + if (!category) throw new Error("Category channel does not exist"); + + await channel.setParent(category.id); + + channel.overwritePermissions(message.author, { + VIEW_CHANNEL: true, + SEND_MESSAGES: true, + READ_MESSAGE_HISTORY: true + }) + + + + let msg = await channel.send(message.author, { + embed: new Discord.RichEmbed() + .setColor(0x36393e) + .setDescription("Please enter your console email address") + .setFooter("You can type 'cancel' to cancel the request \n**This will take a few seconds to find your account.**") + }) + + const collector = new Discord.MessageCollector(channel, m => m.author.id === message.author.id, { time: 60000, max: 1 }); + collector.on('collect', messagecollected => { + //console.log(message.content) + + if (messagecollected.content === 'cancel') { + return msg.edit("Request to link your account canceled.", null).then(channel.delete()) + } + + const axios = require('axios'); + var arr = []; + + axios({ + url: "https://panel.danbot.host" + "/api/application/users", + method: 'GET', + followRedirect: true, + maxRedirects: 5, + headers: { + 'Authorization': 'Bearer ' + "FhzH9PUVKcUnrHxCySA9dOPbyVmimDaVmCEtXKaPvPMpAivj", + 'Content-Type': 'application/json', + 'Accept': 'Application/vnd.pterodactyl.v1+json', + } + }).then(resources => { + var countmax = resources.data.meta.pagination.total_pages + var i2 = countmax++ + + var i = 0 + while (i { + arr.push(...response.data.data) + }); + i++ + } + console.log(resources.data.meta.pagination) + var total = resources.data.meta.pagination.total + }); + //Find account then link + setTimeout(async () => { + console.log(arr.length) + const consoleUser = arr.find(usr => usr.attributes ? usr.attributes.email == messagecollected.content : false); + + if (!consoleUser) { + channel.send('I can\'t find a user with that account! \nRemoving channel!') + setTimeout(() => { + channel.delete(); + }, 5000) + } else { + + function codegen(length) { + var result = ''; + var characters = '23456789'; + var charactersLength = characters.length; + for ( var i = 0; i < length; i++ ) { + result += characters.charAt(Math.floor(Math.random() * charactersLength)); + } + return result; + } + const code = codegen(10); + + const emailmessage = { + from: config.Email.From, + to: messagecollected.content, + subject: 'DanBot Hosting - Someone tried to link their Discord account!', + html: "Hello, Someone just tried to link their Discord account with this console email address. Here is a verification code that is needed to link: " + code + }; + transport.sendMail(emailmessage, function(err, info) { + if (err) { + console.log(err) + } else { + console.log(info); + channel.send('Please check the email account for a verification code to complete linking. You have 2mins') + + const collector = new Discord.MessageCollector(channel, m => m.author.id === message.author.id, { time: 120000, max: 1 }); + collector.on('collect', message => { + if (message.content == code) { + const timestamp = `${moment().format("HH:mm:ss")}`; + const datestamp = `${moment().format("YYYY-MM-DD")}`; + userData.set(`${message.author.id}`, { + discordID: message.author.id, + consoleID: consoleUser.attributes.id, + email: consoleUser.attributes.email, + username: consoleUser.attributes.username, + linkTime: timestamp, + linkDate: datestamp + }); + + let embedstaff = new Discord.RichEmbed() + .setColor('Green') + .addField('__**Linked Discord account:**__', message.author.id) + .addField('__**Linked Console account email:**__', consoleUser.attributes.email) + .addField('__**Linked At: (TIME / DATE)**__', timestamp + " / " + datestamp) + .addField('__**Linked Console username:**__', consoleUser.attributes.username) + .addField('__**Linked Console ID:**__', consoleUser.attributes.id) + + channel.send("Account linked!").then( + client.channels.get(config.DiscordBot.oLogs).send(`<@${message.author.id}> linked their account. Heres some info: `, embedstaff), + setTimeout(() => { + channel.delete(); + }, 5000) + ); + } else { + channel.send('Code is incorrect. Linking cancelled! \n\nRemoving channel!') + setTimeout(() => { + channel.delete(); + }, 2000) + } + }); + } + }); + + }; + }, 12000) + + })} + } else if (args[0].toLowerCase() == "unlink") { + userData.delete(message.author.id) + message.channel.send('You have unlinked this account!') + } + }; \ No newline at end of file From 79b9c522439ae801714290b61eaf236f635368ac Mon Sep 17 00:00:00 2001 From: danielpmc Date: Wed, 21 Oct 2020 20:27:35 +0100 Subject: [PATCH 107/255] Added password reset email --- Panel/bot/discord/commands/user.js | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/Panel/bot/discord/commands/user.js b/Panel/bot/discord/commands/user.js index 1db3c6bf1..1dea417fc 100644 --- a/Panel/bot/discord/commands/user.js +++ b/Panel/bot/discord/commands/user.js @@ -212,8 +212,16 @@ exports.run = async(client, message, args) => { }).then(user=> { message.channel.send('The console account that is linked with the discord account has now been reset. Please check dms for the password. \nA email will also be sent containing the new password') client.users.get(message.author.id).send(`New password for DanBot Hosting: ||**${data.password}**||`) + + const emailmessage = { + from: config.Email.From, + to: messagecollected.content, + subject: 'DanBot Hosting - Password reset via bot', + html: "Hello, the console account password for email: " + userData.get(message.author.id).email + " was just reset. here is the new password" + data.password + }; + transport.sendMail(emailmessage); }).catch(err => { - message.channel.send('Error! ' + err) + message.channel.send(err) }) }) From 12ee5d3cdbae2083ba04dae0a3e23826e96320fd Mon Sep 17 00:00:00 2001 From: danielpmc Date: Wed, 21 Oct 2020 20:29:55 +0100 Subject: [PATCH 108/255] changed a little thing --- Panel/bot/discord/commands/createserver.js | 8 -------- Panel/bot/discord/commands/server.js | 2 +- 2 files changed, 1 insertion(+), 9 deletions(-) delete mode 100644 Panel/bot/discord/commands/createserver.js diff --git a/Panel/bot/discord/commands/createserver.js b/Panel/bot/discord/commands/createserver.js deleted file mode 100644 index a977b634d..000000000 --- a/Panel/bot/discord/commands/createserver.js +++ /dev/null @@ -1,8 +0,0 @@ -const axios = require('axios'); -const { - response -} = require('express'); -exports.run = async (client, message, args) => { - message.channel.send('Command has been renamed to `' + config.DiscordBot.Prefix + "server create`") - -}; \ No newline at end of file diff --git a/Panel/bot/discord/commands/server.js b/Panel/bot/discord/commands/server.js index 831312556..74e2fa451 100644 --- a/Panel/bot/discord/commands/server.js +++ b/Panel/bot/discord/commands/server.js @@ -3,7 +3,7 @@ var pretty = require('prettysize'); exports.run = async (client, message, args) => { const otherargs = message.content.split(' ').slice(3).join(' '); if (userData.get(message.author.id) == null) { - message.channel.send("Oh no, Seems like you do not have an account linked to your discord ID. \nIf you have not made an account yet please check out `" + config.DiscordBot.Prefix + "getstarted` to create an account \nIf you already have an account link it using `" + config.DiscordBot.Prefix + "link`") + message.channel.send("Oh no, Seems like you do not have an account linked to your discord ID. \nIf you have not made an account yet please check out `" + config.DiscordBot.Prefix + "getstarted` to create an account \nIf you already have an account link it using `" + config.DiscordBot.Prefix + "user link`") } else { if (!args[0]) { //No args From 11ace9a32f5ef4f34c7b2ebd62accb5af982b181 Mon Sep 17 00:00:00 2001 From: danielpmc Date: Wed, 21 Oct 2020 20:33:45 +0100 Subject: [PATCH 109/255] Remove getstarted --- Panel/bot/discord/commands/getstarted.js | 191 ----------------------- 1 file changed, 191 deletions(-) delete mode 100644 Panel/bot/discord/commands/getstarted.js diff --git a/Panel/bot/discord/commands/getstarted.js b/Panel/bot/discord/commands/getstarted.js deleted file mode 100644 index 9844e73cf..000000000 --- a/Panel/bot/discord/commands/getstarted.js +++ /dev/null @@ -1,191 +0,0 @@ -const axios = require('axios'); -exports.run = async (client, message) => { - //Args - const args = message.content.split(' ').slice(1).join(' '); - var validator = require('validator'); - - //Random password gen - var CAPSNUM = "ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890"; - let getPassword = () => { - - var password = ""; - while (password.length < 10) { - password += CAPSNUM[Math.floor(Math.random() * CAPSNUM.length)]; - } - return password; - }; - - if (args == "") { - let embed = new Discord.RichEmbed() - .setColor(`BLUE`) - .addField(`__**How to get started!**__`, 'Create an account by typing: `' + config.DiscordBot.Prefix + 'getstarted account` \nOnce done run `' + config.DiscordBot.Prefix + 'getstarted server` to create a server! \n \nAny problems? Please send a message in <#640158951899398144>', true); - message.channel.send(embed) - - } else if (args == "account") { - if (userData.get(message.author.id) == null) { - const server = message.guild - - let channel = await server.createChannel(message.author.tag, "text", [{ - type: 'role', - id: message.guild.id, - deny: 0x400 - }, - { - type: 'user', - id: message.author.id, - deny: 1024 - } - ]).catch(console.error); - message.reply(`Please check <#${channel.id}> to create an account.`) - - let category = server.channels.find(c => c.id == settings.fetch("accountcategory.id") && c.type == "category"); - if (!category) throw new Error("Category channel does not exist"); - - await channel.setParent(category.id); - - channel.overwritePermissions(message.author, { - VIEW_CHANNEL: true, - SEND_MESSAGES: true, - READ_MESSAGE_HISTORY: true - }) - - - const filter2 = m => m.author.id === message.author.id; - - let msg = await channel.send("<@" + message.author.id + ">", { - embed: new Discord.RichEmbed() - .setColor(0x36393e) - .setDescription("Please enter a username (**Please dont use spaces**)") - .setFooter("You can type 'cancel' to cancel the request") - }) - - //First Collection "UserName" - - let collected1 = await channel.awaitMessages(filter2, { - max: 1, - time: 30000, - errors: ['time'], - }).catch(x => { - msg.delete() - channel.send(`ERROR: User failed to provide an answer.`); - setTimeout(() => { - channel.delete(); - }, 3000); - return false; - }) - - if (collected1.first().content === 'cancel') { - return msg.edit("Request to create a new user has been canceled!", null).then(channel.delete()) - } - - await msg.edit("", { - embed: new Discord.RichEmbed() - .setColor(0x36393e) - .setDescription(`Username: **${collected1.first().content}** \nPlease enter a Email.`) - .setFooter("You can type 'cancel' to cancel the request") - }) - collected1.first().delete(); - - //scnd Collection "Email" - - let collected2 = await channel.awaitMessages(filter2, { - max: 1, - time: 30000, - errors: ['time'], - }).catch(x => { - msg.delete() - channel.send(`ERROR: User failed to provide an answer.`); - setTimeout(() => { - channel.delete(); - }, 3000); - return false; - }) - - - if (collected2.first().content === 'cancel') { - channel.delete() - } - - if (!validator.isEmail(collected2.first().content.trim())) { - msg.delete() - channel.send(`\`${collected2.first().content.trim()}`+"` is not a Valid Email!"); - setTimeout(() => { - channel.delete(); - }, 10000); - return false; - } - collected2.first().delete(); - - let password = await getPassword(); - - const data = { - "username": collected1.first().content, - "email": collected2.first().content, - "first_name": collected1.first().content, - "last_name": ".", - "password": password, - "root_admin": false, - "language": "en" - } - axios({ - url: config.Pterodactyl.hosturl + "/api/application/users", - method: 'POST', - followRedirect: true, - maxRedirects: 5, - headers: { - 'Authorization': 'Bearer ' + config.Pterodactyl.apikey, - 'Content-Type': 'application/json', - 'Accept': 'Application/vnd.pterodactyl.v1+json', - }, - data: data, - }).then(user=> { - - console.log(user) - - const timestamp = `${moment().format("HH:mm:ss")}`; - const datestamp = `${moment().format("YYYY-MM-DD")}`; - - userData.set(`${message.author.id}`, { - discordID: message.author.id, - consoleID: user.data.attributes.id, - email: user.data.attributes.email, - username: user.data.attributes.username, - linkTime: timestamp, - linkDate: datestamp - }) - - if (user == "Error: User already exists! (Or Email/Username is in use already)") { - msg.edit("ERROR: A user with that email/username already exists.", null) - setTimeout(function () { - channel.delete(); - }, 10000); - return false; - } - msg.edit("Hello! You created an new account, Heres the login information", { - embed: new Discord.RichEmbed() - .setColor(0x36393e) - .setDescription("URL: " + config.Pterodactyl.hosturl + " \nUsername: " + collected1.first().content + " \nEmail: " + collected2.first().content + " \nPassword: " + password) - .setFooter("Please note: It is recommended that you change the password") - }) - channel.send('**You have 30mins to keep note of this info before the channel is deleted.**') - message.guild.members.get(message.author.id).addRole("639489891016638496"); - setTimeout(function () { - channel.delete(); - }, 1800000); - - }).catch(err => { - if (err = "Error: User already exists! (Or Email/Username is in use already)") { - msg.edit("ERROR: A user with that email/username already exists.", null) - setTimeout(function () { - channel.delete(); - }, 10000); - } - }) - } else { - message.channel.send('You already have an account') - } - } else if (args == "server") { - message.channel.send('Please use `' + config.DiscordBot.Prefix + "server create type servername` \nTo see server types please do: `" + config.DiscordBot.Prefix + "server create list`") - } //End of ifs - -}; \ No newline at end of file From c61b023b5ed847f89d54294bc6cd4ff5bab61779 Mon Sep 17 00:00:00 2001 From: danielpmc Date: Wed, 21 Oct 2020 20:36:50 +0100 Subject: [PATCH 110/255] Removed a few commands, Updated help --- Panel/bot/discord/commands/access.js | 15 --------------- Panel/bot/discord/commands/help.js | 4 ++-- Panel/bot/discord/commands/radio.js | 8 -------- 3 files changed, 2 insertions(+), 25 deletions(-) delete mode 100644 Panel/bot/discord/commands/access.js delete mode 100644 Panel/bot/discord/commands/radio.js diff --git a/Panel/bot/discord/commands/access.js b/Panel/bot/discord/commands/access.js deleted file mode 100644 index c988b4eae..000000000 --- a/Panel/bot/discord/commands/access.js +++ /dev/null @@ -1,15 +0,0 @@ -exports.run = (client, message) => { - const args = message.content.split(' ').slice(1).join(' '); - - if (message.member.roles.find(r => r.name === "Moderators")) { - if (args == "") { - let embed = new Discord.RichEmbed() - .setColor(`GREEN`) - .addField(`__**Access a user's server**__`, '', true); - message.channel.send(embed) - - } else { - - } - } -}; \ No newline at end of file diff --git a/Panel/bot/discord/commands/help.js b/Panel/bot/discord/commands/help.js index 34e22cb75..48da3ed49 100644 --- a/Panel/bot/discord/commands/help.js +++ b/Panel/bot/discord/commands/help.js @@ -1,6 +1,6 @@ const Help = { - "Users": `${config.DiscordBot.Prefix}getstarted | Create a server or account \n${config.DiscordBot.Prefix}link | Link your console account with your discord account \n${config.DiscordBot.Prefix}linked | Check if your account is linked \n${config.DiscordBot.Prefix}stats | Shows the stats of each hosting node. \n${config.DiscordBot.Prefix}ticket | Create a ticket for help from the staff team! \n${config.DiscordBot.Prefix}status | Check the status of your server! \n${config.DiscordBot.Prefix}uptime | Shows the bots uptime \n${config.DiscordBot.Prefix}changelog | Check the changelog for the github commit. \n${config.DiscordBot.Prefix}radio | Joins VC and plays DanBot Radio.\n${config.DiscordBot.Prefix}info | Get a bots info. \n ${config.DiscordBot.Prefix}suggest | Get the link to send in suggestions.`, - "Staff": `${config.DiscordBot.Prefix}staff | Gets the ID of a user on console using their discord ID \n${config.DiscordBot.Prefix}purge | Delete messages in a channel \n${config.DiscordBot.Prefix}access | Gain subuser access to a server`, + "Users": `${config.DiscordBot.Prefix}user | See help for that command \n${config.DiscordBot.Prefix}server | See help for that command \n${config.DiscordBot.Prefix}stats | Shows the stats of each hosting node. \n${config.DiscordBot.Prefix}ticket | Create a ticket for help from the staff team! \n${config.DiscordBot.Prefix}status | Check the status of your server! \n${config.DiscordBot.Prefix}uptime | Shows the bots uptime \n${config.DiscordBot.Prefix}info | Get a bots info. \n ${config.DiscordBot.Prefix}suggest | Get the link to send in suggestions.`, + "Staff": `${config.DiscordBot.Prefix}staff | See help for that command \n${config.DiscordBot.Prefix}purge | Delete messages in a channel \n${config.DiscordBot.Prefix}access | Gain subuser access to a server`, "Owner": `${config.DiscordBot.Prefix}reload | Reloads all commands on the bot \n${config.DiscordBot.Prefix}restart | Restarts **EVERYTHING**, Bot and Stats website \n${config.DiscordBot.Prefix}say | Says what you want it to say \n${config.DiscordBot.Prefix}eval | Eval some code \n${config.DiscordBot.Prefix}exec | Run some system commands \n${config.DiscordBot.Prefix}giveaway | Launch a giveaway` } diff --git a/Panel/bot/discord/commands/radio.js b/Panel/bot/discord/commands/radio.js deleted file mode 100644 index 5ac1ae90f..000000000 --- a/Panel/bot/discord/commands/radio.js +++ /dev/null @@ -1,8 +0,0 @@ -exports.run = (client, message) => { - message.channel.send('Playing...') - client.channels.get("691609366155100201").join() - .then(connection => { - connection.playStream('http://207.180.236.5:8000/DanBotFM') - }); - -}; \ No newline at end of file From 4c23f9b36d60872feb426b81b70f1c4e5c4c18cc Mon Sep 17 00:00:00 2001 From: danielpmc Date: Wed, 21 Oct 2020 20:39:52 +0100 Subject: [PATCH 111/255] Added a few missing things from guildMemberAdd event --- Panel/bot/discord/commands/info.js | 33 +++++++++++----------- Panel/bot/discord/events/guildMemberAdd.js | 32 ++++++++++++++++++++- 2 files changed, 48 insertions(+), 17 deletions(-) diff --git a/Panel/bot/discord/commands/info.js b/Panel/bot/discord/commands/info.js index 327e76d1b..44edf3bd3 100644 --- a/Panel/bot/discord/commands/info.js +++ b/Panel/bot/discord/commands/info.js @@ -2,20 +2,20 @@ let db = require("quick.db"); const Discord = require("discord.js"); exports.run = async (client, message, args) => { - - let botID = args[0]; - if (message.mentions.users.first()) { - let t = message.mentions.users.first(); - botID = t.id; - }; - - if (!botID) return message.channel.send("Error: Please provide a bot id!"); - let bot = db.get(`${botID}`); - - if (!bot) return message.channel.send("Error: The bot you gave is not in my database!"); - if (bot.deleted) return message.channel.send("Error: This bot has been deleted."); - - let infoEmbed = new Discord.RichEmbed() + + let botID = args[0]; + if (message.mentions.users.first()) { + let t = message.mentions.users.first(); + botID = t.id; + }; + + if(!botID)return message.channel.send("Error: Please provide a bot id!"); + let bot = db.get(`${botID}`); + + if(!bot)return message.channel.send("Error: The bot you gave is not in my database!"); + if(bot.deleted)return message.channel.send("Error: This bot has been deleted."); + + let infoEmbed = new Discord.RichEmbed() .setColor("BLUE") .setTitle(`${bot.client.username} | DanBot Hosting Stats`) .setURL("https://danbot.host/bot/" + bot.id) @@ -26,7 +26,8 @@ exports.run = async (client, message, args) => { **Users:** ${bot.users.toLocaleString()} `) .addField("Owner", `<@${bot.owner}> \`(${bot.owner})\``) - - message.channel.send(infoEmbed) + .addField("Invite", "[Click Me!]()") + + message.channel.send(infoEmbed) }; \ No newline at end of file diff --git a/Panel/bot/discord/events/guildMemberAdd.js b/Panel/bot/discord/events/guildMemberAdd.js index d90a406f6..595fc9742 100644 --- a/Panel/bot/discord/events/guildMemberAdd.js +++ b/Panel/bot/discord/events/guildMemberAdd.js @@ -61,9 +61,39 @@ module.exports = async (client, member, guild) => { if (Date.now() - member.user.createdAt < 863136000) { member.kick().then(memberkicked => { - client.channels.get('738527858594414663').send(member.user.tag + ` has been auto-kicked as account is under 10days old \nThat account was created ${getAge(member.user.createdAt)}, ago`) + client.channels.get('738527858594414663').send(member.user.tag + ` has been auto-kicked as account is under 10days old \nThat account was created ${getAge(Date.now() - member.user.createdAt)}, ago`) }); + } + + if(member.user.bot) { + let botID = member.user.id; + let bot = db.get(`${botID}`); + if(!bot) { + client.channels.get(config.welcome).send("Bot: <@" + member.user.id + ">, tried to join but is not using our API.") + member.kick(); + } else { + const botrole = member.guild.roles.find(role => role.id === config.bot); + member.guild.members.get(member.user.id).addRole(botrole); + client.channels.get(config.welcome).send("Welcome <@" + member.user.id + ">, More bot friends :D \nBot owned by: <@" + bot.owner + ">"); + } +} else if (!member.user.bot) { + if (userData.get(message.author.id) == null) { + const memberrole = member.guild.roles.find(role => role.id === config.member); + member.guild.members.get(member.user.id).addRole(memberrole) + client.channels.get(config.welcome).send("Welcome <@" + member.user.id + "> to DanBot Hosting. To get started please read <#738527470164377630>"); + } else { + const memberrole = member.guild.roles.find(role => role.id === config.member); + const clientrole = member.guild.roles.find(role => role.id === "639489891016638496"); + member.guild.members.get(member.user.id).addRole(memberrole) + member.guild.members.get(member.user.id).addRole(clientrole) + client.channels.get(config.welcome).send("Welcome back <@" + member.user.id + "> to DanBot Hosting!"); } + + if(mutesData.fetch(member.user.id + ".muted") === "true") { + let muteRole = client.guilds.get(member.guild.id).roles.find(r => r.id == "726829710935457872"); + member.guild.members.get(member.user.id).addRole(muteRole) + } +} if (member.user.bot) { const botrole = member.guild.roles.find(role => role.id === config.bot); From a1d047917907ce0bb748ba293bc37eb0f092677c Mon Sep 17 00:00:00 2001 From: danielpmc Date: Wed, 21 Oct 2020 20:41:33 +0100 Subject: [PATCH 112/255] Added alt to permissions --- Panel/bot/discord/commands/staff.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Panel/bot/discord/commands/staff.js b/Panel/bot/discord/commands/staff.js index a2afcf3ea..ff16fcbb2 100644 --- a/Panel/bot/discord/commands/staff.js +++ b/Panel/bot/discord/commands/staff.js @@ -116,7 +116,7 @@ exports.run = async (client, message, args) => { }) break; case 'update': - if (message.member.roles.find(r => r.id === "639481606112804875") || message.author.id == '293841631583535106') { + if (message.member.roles.find(r => r.id === "639481606112804875") || message.author.id == '293841631583535106' || message.author.id == '229367793479319553') { exec(`git pull`, (error, stdout) => { let response = (error || stdout); if (!error) { From abc5e224ccf9addb5bed1a726561c89b88e65856 Mon Sep 17 00:00:00 2001 From: danielpmc Date: Wed, 21 Oct 2020 20:43:26 +0100 Subject: [PATCH 113/255] Should fix the 422 error --- Panel/bot/discord/commands/server.js | 1 + 1 file changed, 1 insertion(+) diff --git a/Panel/bot/discord/commands/server.js b/Panel/bot/discord/commands/server.js index 74e2fa451..6bcb39a09 100644 --- a/Panel/bot/discord/commands/server.js +++ b/Panel/bot/discord/commands/server.js @@ -338,6 +338,7 @@ exports.run = async (client, message, args) => { "environment": { "SERVER_JARFILE": "server.jar", "MC_VERSION": "latest", + "BUILD_TYPE": "recommended", "FORGE_VERSION": "1.16.3" }, "feature_limits": { From 9c88d4c4827909c5fb6bf6c54f35244d6c78be6d Mon Sep 17 00:00:00 2001 From: danielpmc Date: Wed, 21 Oct 2020 21:17:09 +0100 Subject: [PATCH 114/255] Changed .addField to .setTitle embed --- Panel/bot/discord/commands/user.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Panel/bot/discord/commands/user.js b/Panel/bot/discord/commands/user.js index 1dea417fc..82634962f 100644 --- a/Panel/bot/discord/commands/user.js +++ b/Panel/bot/discord/commands/user.js @@ -17,7 +17,7 @@ exports.run = async(client, message, args) => { if (!args[0]) { //No args, Help const embed = new Discord.RichEmbed() - .addField('__**Commands**__', "`" + config.DiscordBot.Prefix + "user new` | Create an account \n`" + config.DiscordBot.Prefix + "user password` | Reset account password \n`" + config.DiscordBot.Prefix + "user link` | Link this account with console account \n`" + config.DiscordBot.Prefix + "user unlink` | Unlinks account from the console account") + .setTitle("__**Commands**__` \n" + config.DiscordBot.Prefix + "user new` | Create an account \n`" + config.DiscordBot.Prefix + "user password` | Reset account password \n`" + config.DiscordBot.Prefix + "user link` | Link this account with console account \n`" + config.DiscordBot.Prefix + "user unlink` | Unlinks account from the console account") message.channel.send(embed) } else if (args[0].toLowerCase() == "new") { if (userData.get(message.author.id) == null) { From 8a9c4da834c6452b1c3b014089ef46e0353f1fa0 Mon Sep 17 00:00:00 2001 From: danielpmc Date: Wed, 21 Oct 2020 21:17:53 +0100 Subject: [PATCH 115/255] fail --- Panel/bot/discord/commands/user.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Panel/bot/discord/commands/user.js b/Panel/bot/discord/commands/user.js index 82634962f..51fefb3ed 100644 --- a/Panel/bot/discord/commands/user.js +++ b/Panel/bot/discord/commands/user.js @@ -17,7 +17,7 @@ exports.run = async(client, message, args) => { if (!args[0]) { //No args, Help const embed = new Discord.RichEmbed() - .setTitle("__**Commands**__` \n" + config.DiscordBot.Prefix + "user new` | Create an account \n`" + config.DiscordBot.Prefix + "user password` | Reset account password \n`" + config.DiscordBot.Prefix + "user link` | Link this account with console account \n`" + config.DiscordBot.Prefix + "user unlink` | Unlinks account from the console account") + .setTitle("__**Commands**__ \n`" + config.DiscordBot.Prefix + "user new` | Create an account \n`" + config.DiscordBot.Prefix + "user password` | Reset account password \n`" + config.DiscordBot.Prefix + "user link` | Link this account with console account \n`" + config.DiscordBot.Prefix + "user unlink` | Unlinks account from the console account") message.channel.send(embed) } else if (args[0].toLowerCase() == "new") { if (userData.get(message.author.id) == null) { From 16b8e067e79c026cb121513043f5802dc54e4e46 Mon Sep 17 00:00:00 2001 From: danielpmc Date: Wed, 21 Oct 2020 21:27:05 +0100 Subject: [PATCH 116/255] Remove un-used node from ip whitelist --- Panel/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Panel/index.js b/Panel/index.js index ea431c122..0c53721ac 100644 --- a/Panel/index.js +++ b/Panel/index.js @@ -140,7 +140,7 @@ server.listen(PORT, function () { global.nodeData = new db.table("nodeData") app.get('/data', function (req, res) { - let nodes = ["154.27.68.232", "154.27.68.233", "154.27.68.234", "167.86.113.158", "51.38.69.73"]; + let nodes = ["154.27.68.232", "154.27.68.233", "167.86.113.158", "51.38.69.73"]; if (req.query.servername == undefined) { if (!nodes.includes(req.headers["cf-connecting-ip"])) { res.redirect("/") From 8b2e2e6a606a00dc014afe904cffb7a73c17d816 Mon Sep 17 00:00:00 2001 From: danielpmc Date: Wed, 21 Oct 2020 22:05:31 +0100 Subject: [PATCH 117/255] db define and changed a few things --- Panel/bot/discord/events/guildMemberAdd.js | 114 ++++++++++----------- Panel/index.js | 10 +- 2 files changed, 58 insertions(+), 66 deletions(-) diff --git a/Panel/bot/discord/events/guildMemberAdd.js b/Panel/bot/discord/events/guildMemberAdd.js index 595fc9742..af84af3bf 100644 --- a/Panel/bot/discord/events/guildMemberAdd.js +++ b/Panel/bot/discord/events/guildMemberAdd.js @@ -12,11 +12,13 @@ const config = { "member": "639490038434103306", "bot": "704467807122882562" } + +let db = require("quick.db"); //let client = require("../../../../index.js").client; -module.exports = async (client, member, guild) => { +module.exports = async(client, member, guild) => { - var getAge = function (millis) { + var getAge = function(millis) { var dur = {}; var units = [{ label: "milliseconds", @@ -39,19 +41,19 @@ module.exports = async (client, member, guild) => { mod: 31 } ]; - - units.forEach(function (u) { + + units.forEach(function(u) { millis = (millis - (dur[u.label] = (millis % u.mod))) / u.mod; }); - - var nonZero = function (u) { + + var nonZero = function(u) { return dur[u.label]; }; - dur.toString = function () { + dur.toString = function() { return units .reverse() .filter(nonZero) - .map(function (u) { + .map(function(u) { return dur[u.label] + " " + (dur[u.label] == 1 ? u.label.slice(0, -1) : u.label); }) .join(', '); @@ -59,67 +61,57 @@ module.exports = async (client, member, guild) => { return dur; }; - if (Date.now() - member.user.createdAt < 863136000) { - member.kick().then(memberkicked => { - client.channels.get('738527858594414663').send(member.user.tag + ` has been auto-kicked as account is under 10days old \nThat account was created ${getAge(Date.now() - member.user.createdAt)}, ago`) - }); - } - - if(member.user.bot) { - let botID = member.user.id; - let bot = db.get(`${botID}`); - if(!bot) { - client.channels.get(config.welcome).send("Bot: <@" + member.user.id + ">, tried to join but is not using our API.") - member.kick(); - } else { - const botrole = member.guild.roles.find(role => role.id === config.bot); - member.guild.members.get(member.user.id).addRole(botrole); - client.channels.get(config.welcome).send("Welcome <@" + member.user.id + ">, More bot friends :D \nBot owned by: <@" + bot.owner + ">"); + if (Date.now() - member.user.createdAt < 863136000) { + member.kick().then(memberkicked => { + client.channels.get('738527858594414663').send(member.user.tag + ` has been auto-kicked as account is under 10days old \nThat account was created ${getAge(Date.now() - member.user.createdAt)}, ago`) + }); } -} else if (!member.user.bot) { - if (userData.get(message.author.id) == null) { - const memberrole = member.guild.roles.find(role => role.id === config.member); - member.guild.members.get(member.user.id).addRole(memberrole) - client.channels.get(config.welcome).send("Welcome <@" + member.user.id + "> to DanBot Hosting. To get started please read <#738527470164377630>"); - } else { - const memberrole = member.guild.roles.find(role => role.id === config.member); - const clientrole = member.guild.roles.find(role => role.id === "639489891016638496"); - member.guild.members.get(member.user.id).addRole(memberrole) - member.guild.members.get(member.user.id).addRole(clientrole) - client.channels.get(config.welcome).send("Welcome back <@" + member.user.id + "> to DanBot Hosting!"); - } - if(mutesData.fetch(member.user.id + ".muted") === "true") { - let muteRole = client.guilds.get(member.guild.id).roles.find(r => r.id == "726829710935457872"); - member.guild.members.get(member.user.id).addRole(muteRole) - } -} - - if (member.user.bot) { - const botrole = member.guild.roles.find(role => role.id === config.bot); - member.guild.members.get(member.user.id).addRole(botrole) - client.channels.get(config.welcome).send("Welcome <@" + member.user.id + ">, More bot friends :D") + if(member.user.bot) { + let botID = member.user.id; + let bot = db.get(`${botID}`); + if(!bot) { + client.channels.get(config.welcome).send("Bot: <@" + member.user.id + ">, tried to join but is not using our API.") + member.kick(); + } else { + const botrole = member.guild.roles.find(role => role.id === config.bot); + member.guild.members.get(member.user.id).addRole(botrole); + client.channels.get(config.welcome).send("Welcome <@" + member.user.id + ">, More bot friends :D \nBot owned by: <@" + bot.owner + ">"); + } } else if (!member.user.bot) { - const memberrole = member.guild.roles.find(role => role.id === config.member); - member.guild.members.get(member.user.id).addRole(memberrole) - client.channels.get(config.welcome).send("Welcome <@" + member.user.id + "> to DanBot Hosting. To get started please read <#738527470164377630>"); - + if (userData.get(message.author.id) == null) { + const memberrole = member.guild.roles.find(role => role.id === config.member); + member.guild.members.get(member.user.id).addRole(memberrole) + client.channels.get(config.welcome).send("Welcome <@" + member.user.id + "> to DanBot Hosting. To get started please read <#738527470164377630>"); + } else { + const memberrole = member.guild.roles.find(role => role.id === config.member); + const clientrole = member.guild.roles.find(role => role.id === "639489891016638496"); + member.guild.members.get(member.user.id).addRole(memberrole) + member.guild.members.get(member.user.id).addRole(clientrole) + client.channels.get(config.welcome).send("Welcome back <@" + member.user.id + "> to DanBot Hosting!"); + } + + if(mutesData.fetch(member.user.id + ".muted") === "true") { + let muteRole = client.guilds.get(member.guild.id).roles.find(r => r.id == "726829710935457872"); + member.guild.members.get(member.user.id).addRole(muteRole) + } + member.guild.fetchInvites().then(guildInvites => { const ei = invites[member.guild.id]; invites[member.guild.id] = guildInvites; const invite = guildInvites.find(i => ei.get(i.code).uses < i.uses); const inviter = client.users.get(invite.inviter.id); let embed = new Discord.RichEmbed() - .setColor(`GREEN`) - .addField(`New Members Username:`, member.user.tag, true) - .addField(`New Members ID:`, '`' + member.user.id + '`', true) - .addField('Account created:', member.user.createdAt.toDateString(), true) - .addField("Members Status", member.user.presence !== null && member.user.presence.status !== null ? member.user.presence.status : "Offline") - .addField('\u200b', '\u200b') - .addField(`Invited by:`, inviter.tag, true) - .addField(`Inviter's ID:`, '`' + inviter.id + '`', true) - .addField(`Invite code used:`, '`' + invite.code + '`', true) - .addField(`Invite used`, invite.uses + ' times', true); + .setColor(`GREEN`) + .addField(`New Members Username:`, member.user.tag, true) + .addField(`New Members ID:`, '`' + member.user.id + '`', true) + .addField('Account created:', member.user.createdAt.toDateString(), true) + .addField("Members Status", member.user.presence !== null && member.user.presence.status !== null ? member.user.presence.status : "Offline") + .addField('\u200b', '\u200b') + .addField(`Invited by:`, inviter.tag, true) + .addField(`Inviter's ID:`, '`' + inviter.id + '`', true) + .addField(`Invite code used:`, '`' + invite.code + '`', true) + .addField(`Invite used`, invite.uses + ' times', true); client.channels.get(config.invitechannel).send(embed) const invite5 = member.guild.roles.find(role => role.id === config.invite5); const invite10 = member.guild.roles.find(role => role.id === config.invite10); @@ -137,6 +129,6 @@ module.exports = async (client, member, guild) => { if (invite.uses == 200) return member.guild.members.get(inviter.id).removeRole(invite150), member.guild.members.get(inviter.id).addRole(invite200), client.channels.get(config.inviterewmsg).send(`<@${inviter.id}> just hit 200 invites! Here's a role for you :)`);; }); - + } }; \ No newline at end of file diff --git a/Panel/index.js b/Panel/index.js index 0c53721ac..52f0088c1 100644 --- a/Panel/index.js +++ b/Panel/index.js @@ -143,8 +143,6 @@ app.get('/data', function (req, res) { let nodes = ["154.27.68.232", "154.27.68.233", "167.86.113.158", "51.38.69.73"]; if (req.query.servername == undefined) { if (!nodes.includes(req.headers["cf-connecting-ip"])) { - res.redirect("/") - } else { nodeData.set(req.query.speedname + '-speedtest', { speedname: req.query.speedname, ping: req.query.ping, @@ -152,11 +150,11 @@ app.get('/data', function (req, res) { upload: req.query.upload, updatetime: req.query.updatetime }); + } else { + res.redirect("/") }; } else { - if (!nodes.includes(req.headers["cf-connecting-ip"])) { - res.redirect("/") - } else { + if (nodes.includes(req.headers["cf-connecting-ip"])) { nodeData.set(req.query.servername, { servername: req.query.servername, cpu: req.query.cpu, @@ -186,6 +184,8 @@ app.get('/data', function (req, res) { dockercontainersstopped: req.query.dockercontainersstopped, updatetime: req.query.updatetime }); + } else { + res.redirect("/") } } }) From 7119451da48d120a9b861d944e856ffab5048f69 Mon Sep 17 00:00:00 2001 From: danielpmc Date: Wed, 21 Oct 2020 22:11:06 +0100 Subject: [PATCH 118/255] Update index.js --- Panel/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Panel/index.js b/Panel/index.js index 52f0088c1..3cd9597bb 100644 --- a/Panel/index.js +++ b/Panel/index.js @@ -142,7 +142,7 @@ global.nodeData = new db.table("nodeData") app.get('/data', function (req, res) { let nodes = ["154.27.68.232", "154.27.68.233", "167.86.113.158", "51.38.69.73"]; if (req.query.servername == undefined) { - if (!nodes.includes(req.headers["cf-connecting-ip"])) { + if (nodes.includes(req.headers["cf-connecting-ip"])) { nodeData.set(req.query.speedname + '-speedtest', { speedname: req.query.speedname, ping: req.query.ping, From 9e2ab08bfb46f1ce60cd2e000d15d6a5f50c4650 Mon Sep 17 00:00:00 2001 From: GamerCreator1 <58714825+GamerCreator1@users.noreply.github.com> Date: Wed, 21 Oct 2020 17:15:58 -0400 Subject: [PATCH 119/255] Updated Help Command Added Api Key --- Panel/bot/discord/commands/help.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Panel/bot/discord/commands/help.js b/Panel/bot/discord/commands/help.js index 48da3ed49..e5736ef33 100644 --- a/Panel/bot/discord/commands/help.js +++ b/Panel/bot/discord/commands/help.js @@ -1,5 +1,5 @@ const Help = { - "Users": `${config.DiscordBot.Prefix}user | See help for that command \n${config.DiscordBot.Prefix}server | See help for that command \n${config.DiscordBot.Prefix}stats | Shows the stats of each hosting node. \n${config.DiscordBot.Prefix}ticket | Create a ticket for help from the staff team! \n${config.DiscordBot.Prefix}status | Check the status of your server! \n${config.DiscordBot.Prefix}uptime | Shows the bots uptime \n${config.DiscordBot.Prefix}info | Get a bots info. \n ${config.DiscordBot.Prefix}suggest | Get the link to send in suggestions.`, + "Users": `${config.DiscordBot.Prefix}user | See help for that command \n${config.DiscordBot.Prefix}server | See help for that command \n${config.DiscordBot.Prefix}stats | Shows the stats of each hosting node. \n${config.DiscordBot.Prefix}ticket | Create a ticket for help from the staff team! \n${config.DiscordBot.Prefix}status | Check the status of your server! \n${config.DiscordBot.Prefix}uptime | Shows the bots uptime \n${config.DiscordBot.Prefix}info | Get a bots info. \n ${config.DiscordBot.Prefix}suggest | Get the link to send in suggestions. \n ${config.DiscordBot.Prefix}apikey | Get a direct message of the api key.`, "Staff": `${config.DiscordBot.Prefix}staff | See help for that command \n${config.DiscordBot.Prefix}purge | Delete messages in a channel \n${config.DiscordBot.Prefix}access | Gain subuser access to a server`, "Owner": `${config.DiscordBot.Prefix}reload | Reloads all commands on the bot \n${config.DiscordBot.Prefix}restart | Restarts **EVERYTHING**, Bot and Stats website \n${config.DiscordBot.Prefix}say | Says what you want it to say \n${config.DiscordBot.Prefix}eval | Eval some code \n${config.DiscordBot.Prefix}exec | Run some system commands \n${config.DiscordBot.Prefix}giveaway | Launch a giveaway` } @@ -24,4 +24,4 @@ exports.run = async (client, message, args) => { .addField(`__**Commands List for users:**__`, Help.Users) message.channel.send(embed) }; -}; \ No newline at end of file +}; From a0a7a3128295478bd8b4e0b94fefd9b009975131 Mon Sep 17 00:00:00 2001 From: danielpmc Date: Wed, 21 Oct 2020 22:49:14 +0100 Subject: [PATCH 120/255] Uh changed some dumb shit --- Panel/index.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Panel/index.js b/Panel/index.js index 3cd9597bb..9fa183786 100644 --- a/Panel/index.js +++ b/Panel/index.js @@ -142,7 +142,9 @@ global.nodeData = new db.table("nodeData") app.get('/data', function (req, res) { let nodes = ["154.27.68.232", "154.27.68.233", "167.86.113.158", "51.38.69.73"]; if (req.query.servername == undefined) { - if (nodes.includes(req.headers["cf-connecting-ip"])) { + if (!nodes.includes(req.headers["x-forwarded-for"])) { + res.redirect("/") + } else { nodeData.set(req.query.speedname + '-speedtest', { speedname: req.query.speedname, ping: req.query.ping, @@ -150,11 +152,11 @@ app.get('/data', function (req, res) { upload: req.query.upload, updatetime: req.query.updatetime }); - } else { - res.redirect("/") }; } else { - if (nodes.includes(req.headers["cf-connecting-ip"])) { + if (!nodes.includes(req.headers["x-forwarded-for"])) { + res.redirect("/") + } else { nodeData.set(req.query.servername, { servername: req.query.servername, cpu: req.query.cpu, @@ -184,8 +186,6 @@ app.get('/data', function (req, res) { dockercontainersstopped: req.query.dockercontainersstopped, updatetime: req.query.updatetime }); - } else { - res.redirect("/") } } }) From 2af1c1cbbf5d1ebf95ead4f66945c6efae4f8316 Mon Sep 17 00:00:00 2001 From: danielpmc Date: Wed, 21 Oct 2020 23:11:34 +0100 Subject: [PATCH 121/255] Changed getstarted to user new for no link error --- Panel/bot/discord/commands/server.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Panel/bot/discord/commands/server.js b/Panel/bot/discord/commands/server.js index 6bcb39a09..a175b5d98 100644 --- a/Panel/bot/discord/commands/server.js +++ b/Panel/bot/discord/commands/server.js @@ -3,7 +3,7 @@ var pretty = require('prettysize'); exports.run = async (client, message, args) => { const otherargs = message.content.split(' ').slice(3).join(' '); if (userData.get(message.author.id) == null) { - message.channel.send("Oh no, Seems like you do not have an account linked to your discord ID. \nIf you have not made an account yet please check out `" + config.DiscordBot.Prefix + "getstarted` to create an account \nIf you already have an account link it using `" + config.DiscordBot.Prefix + "user link`") + message.channel.send("Oh no, Seems like you do not have an account linked to your discord ID. \nIf you have not made an account yet please check out `" + config.DiscordBot.Prefix + "user new` to create an account \nIf you already have an account link it using `" + config.DiscordBot.Prefix + "user link`") } else { if (!args[0]) { //No args From 2678766b4f2e72758ef6576a38baacf3e407916f Mon Sep 17 00:00:00 2001 From: danielpmc Date: Wed, 21 Oct 2020 23:22:44 +0100 Subject: [PATCH 122/255] added OOM killer to gameservers due to a bug someone found on v1 allowing people to use as much ram as they want --- Panel/bot/discord/commands/server.js | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/Panel/bot/discord/commands/server.js b/Panel/bot/discord/commands/server.js index a175b5d98..56061dac2 100644 --- a/Panel/bot/discord/commands/server.js +++ b/Panel/bot/discord/commands/server.js @@ -283,7 +283,8 @@ exports.run = async (client, message, args) => { "dedicated_ip": false, "port_range": [] }, - "start_on_completion": false + "start_on_completion": false, + "oom_disabled": false }; //Sending the data: @@ -350,7 +351,8 @@ exports.run = async (client, message, args) => { "dedicated_ip": false, "port_range": [] }, - "start_on_completion": false + "start_on_completion": false, + "oom_disabled": false }; //Sending the data: @@ -420,7 +422,8 @@ exports.run = async (client, message, args) => { "dedicated_ip": false, "port_range": [] }, - "start_on_completion": false + "start_on_completion": false, + "oom_disabled": false }; //Sending the data: From 204acb6a13355b47bb0e9d4b0a273206bda08d78 Mon Sep 17 00:00:00 2001 From: danielpmc Date: Wed, 21 Oct 2020 23:51:50 +0100 Subject: [PATCH 123/255] added linked message --- Panel/bot/discord/commands/staff.js | 6 ++---- Panel/bot/discord/commands/user.js | 10 +++++++++- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/Panel/bot/discord/commands/staff.js b/Panel/bot/discord/commands/staff.js index ff16fcbb2..8fe489dc8 100644 --- a/Panel/bot/discord/commands/staff.js +++ b/Panel/bot/discord/commands/staff.js @@ -1,6 +1,4 @@ -const { - config -} = require('process'); +//const {config} = require('process'); const exec = require('child_process').exec; exports.run = async (client, message, args) => { @@ -116,7 +114,7 @@ exports.run = async (client, message, args) => { }) break; case 'update': - if (message.member.roles.find(r => r.id === "639481606112804875") || message.author.id == '293841631583535106' || message.author.id == '229367793479319553') { + if (message.member.roles.find(r => r.id === "639481606112804875") || message.author.id == '293841631583535106') { exec(`git pull`, (error, stdout) => { let response = (error || stdout); if (!error) { diff --git a/Panel/bot/discord/commands/user.js b/Panel/bot/discord/commands/user.js index 51fefb3ed..54bdd8b6a 100644 --- a/Panel/bot/discord/commands/user.js +++ b/Panel/bot/discord/commands/user.js @@ -386,7 +386,15 @@ exports.run = async(client, message, args) => { }; }, 12000) - })} + }) + } else { + let embed = new Discord.RichEmbed() + .setColor(`GREEN`) + .addField(`__**Username**__`, userData.fetch(message.author.id + ".username")) + .addField(`__**Linked Date (DD/MM/YY)**__`, userData.fetch(message.author.id + ".linkDate")) + .addField(`__**Linked Time**__`, userData.fetch(message.author.id + ".linkTime")) + message.channel.send("This account is linked!", embed) + } } else if (args[0].toLowerCase() == "unlink") { userData.delete(message.author.id) message.channel.send('You have unlinked this account!') From 4c6c99ae2906e2c975818a998965e80ea81d79a8 Mon Sep 17 00:00:00 2001 From: danielpmc Date: Thu, 22 Oct 2020 01:25:27 +0100 Subject: [PATCH 124/255] Fixed linking --- Panel/bot/discord/commands/user.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Panel/bot/discord/commands/user.js b/Panel/bot/discord/commands/user.js index 54bdd8b6a..e2e8069a1 100644 --- a/Panel/bot/discord/commands/user.js +++ b/Panel/bot/discord/commands/user.js @@ -345,7 +345,7 @@ exports.run = async(client, message, args) => { console.log(info); channel.send('Please check the email account for a verification code to complete linking. You have 2mins') - const collector = new Discord.MessageCollector(channel, m => m.author.id === message.author.id, { time: 120000, max: 1 }); + const collector = new Discord.MessageCollector(channel, m => m.author.id === message.author.id, { time: 120000, max: 2 }); collector.on('collect', message => { if (message.content == code) { const timestamp = `${moment().format("HH:mm:ss")}`; From b805136923ce996f1ea3964cf0eba704aa9194ec Mon Sep 17 00:00:00 2001 From: GamerCreator1 <58714825+GamerCreator1@users.noreply.github.com> Date: Wed, 21 Oct 2020 20:44:08 -0400 Subject: [PATCH 125/255] Updated Help To Latest New command. --- Panel/bot/discord/commands/help.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/Panel/bot/discord/commands/help.js b/Panel/bot/discord/commands/help.js index e5736ef33..98567b763 100644 --- a/Panel/bot/discord/commands/help.js +++ b/Panel/bot/discord/commands/help.js @@ -1,7 +1,7 @@ const Help = { - "Users": `${config.DiscordBot.Prefix}user | See help for that command \n${config.DiscordBot.Prefix}server | See help for that command \n${config.DiscordBot.Prefix}stats | Shows the stats of each hosting node. \n${config.DiscordBot.Prefix}ticket | Create a ticket for help from the staff team! \n${config.DiscordBot.Prefix}status | Check the status of your server! \n${config.DiscordBot.Prefix}uptime | Shows the bots uptime \n${config.DiscordBot.Prefix}info | Get a bots info. \n ${config.DiscordBot.Prefix}suggest | Get the link to send in suggestions. \n ${config.DiscordBot.Prefix}apikey | Get a direct message of the api key.`, - "Staff": `${config.DiscordBot.Prefix}staff | See help for that command \n${config.DiscordBot.Prefix}purge | Delete messages in a channel \n${config.DiscordBot.Prefix}access | Gain subuser access to a server`, - "Owner": `${config.DiscordBot.Prefix}reload | Reloads all commands on the bot \n${config.DiscordBot.Prefix}restart | Restarts **EVERYTHING**, Bot and Stats website \n${config.DiscordBot.Prefix}say | Says what you want it to say \n${config.DiscordBot.Prefix}eval | Eval some code \n${config.DiscordBot.Prefix}exec | Run some system commands \n${config.DiscordBot.Prefix}giveaway | Launch a giveaway` + "Users": `${config.DiscordBot.Prefix}user | See help for that command \n${config.DiscordBot.Prefix}server | See help for that command \n${config.DiscordBot.Prefix}stats | Shows the stats of each hosting node. \n${config.DiscordBot.Prefix}ticket | Create a ticket for help from the staff team! \n${config.DiscordBot.Prefix}status | Check the status of your server! \n${config.DiscordBot.Prefix}uptime | Shows the bots uptime \n${config.DiscordBot.Prefix}info | Get a bots info. \n ${config.DiscordBot.Prefix}suggest | Get the link to send in suggestions.`, + "Staff": `${config.DiscordBot.Prefix}staff | See help for that command \n${config.DiscordBot.Prefix}purge | Delete messages in a channel \n${config.DiscordBot.Prefix}access | Gain subuser access to a server \n${config.DiscordBot.Prefix}mute | Mute da user \n${config.DiscordBot.Prefix}kick | Kick da user`, + "Owner": `${config.DiscordBot.Prefix}reload | Reloads all commands on the bot \n${config.DiscordBot.Prefix}restart | Restarts **EVERYTHING**, Bot and Stats website \n${config.DiscordBot.Prefix}say | Says what you want it to say \n${config.DiscordBot.Prefix}eval | Eval some code \n${config.DiscordBot.Prefix}exec | Run some system commands \n${config.DiscordBot.Prefix}giveaway | Launch a giveaway \n${config.DiscordBot.Prefix}announce | Announce something` } exports.run = async (client, message, args) => { @@ -25,3 +25,4 @@ exports.run = async (client, message, args) => { message.channel.send(embed) }; }; + From b1d63d84599d823a3d6d2456f9c022f90277f906 Mon Sep 17 00:00:00 2001 From: GamerCreator1 <58714825+GamerCreator1@users.noreply.github.com> Date: Wed, 21 Oct 2020 20:46:37 -0400 Subject: [PATCH 126/255] Changed #deleted-channel problem --- Panel/bot/discord/commands/ticket.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Panel/bot/discord/commands/ticket.js b/Panel/bot/discord/commands/ticket.js index 8cb3dccc9..a8c6a938d 100644 --- a/Panel/bot/discord/commands/ticket.js +++ b/Panel/bot/discord/commands/ticket.js @@ -9,7 +9,7 @@ exports.run = async (client, message) => { config.DiscordBot.Prefix + 'ticket new` \nYou can download your old tickets by running: `' + config.DiscordBot.Prefix + 'ticket logs` \nYou can close your ticket by running: `' + config.DiscordBot.Prefix + 'ticket close` \nYou can upgrade your ticket by running:`' + - config.DiscordBot.Prefix + 'ticket upgrade` \n\nAny problems? Please send a message in <#640158951899398144>' , true); + config.DiscordBot.Prefix + 'ticket upgrade` \n\nAny problems? Please send a message in <#739231758087880845> and someone will help you.' , true); message.channel.send(embed) } else if (args == "new") { @@ -127,4 +127,4 @@ exports.run = async (client, message) => { }) } } -}; \ No newline at end of file +}; From 6f2f86ad0116b7f20fb026ba4a75db7213ef809d Mon Sep 17 00:00:00 2001 From: Hadimhz Date: Fri, 23 Oct 2020 05:56:46 +0300 Subject: [PATCH 127/255] Update ready.js Cleaned it a bit.... --- Panel/bot/discord/events/ready.js | 24 +++++++++--------------- 1 file changed, 9 insertions(+), 15 deletions(-) diff --git a/Panel/bot/discord/events/ready.js b/Panel/bot/discord/events/ready.js index c015af706..77350cc0e 100644 --- a/Panel/bot/discord/events/ready.js +++ b/Panel/bot/discord/events/ready.js @@ -2,6 +2,7 @@ const axios = require('axios'); module.exports = async (client, guild, files) => { console.log(chalk.magenta('[DISCORD] ') + chalk.green(client.user.username + " has logged in!")); + let guild = bot.guilds.get('639477525927690240'); //Auto Activities List const activities = [{ @@ -40,34 +41,27 @@ module.exports = async (client, guild, files) => { //Voice channel stats setInterval(async () => { - let guild1 = await client.guilds.get("639477525927690240").fetchMembers(); - let roleID1 = '748117822370086932'; - let staffCount = guild1.roles.get(roleID1).members.size; + let staffCount = await guild.roles.get('748117822370086932').members; client.channels.get("739821419910791348").edit({ - name: `Staff: ${staffCount}`, + name: `Staff: ${staffCount.size}`, reason: "Staff count update" }); - let guild2 = await client.guilds.get("639477525927690240").fetchMembers(); - let roleID2 = '639490038434103306'; - let memberCount = guild2.roles.get(roleID2).members.size; + let memberCount = await guild.roles.get('639490038434103306').members.size; client.channels.get("739821366991257621").edit({ - name: `Members: ${memberCount}`, + name: `Members: ${memberCount.size}`, reason: "Member count update" }); - let guild3 = await client.guilds.get("639477525927690240").fetchMembers(); - let roleID3 = '704467807122882562'; - let botCount = guild3.roles.get(roleID3).members.size; + let botCount = await guild3.roles.get('704467807122882562').members; client.channels.get("739821468296413254").edit({ - name: `Bots: ${botCount}`, + name: `Bots: ${botCount.size}`, reason: "Bot count update" }); - let guild4 = await client.guilds.get("639477525927690240") - const ticketcount = guild4.channels.filter(x => x.name.endsWith("-ticket")).size + const ticketcount = await guild.channels.filter(x => x.name.endsWith("-ticket")) client.channels.get("739821447924416562").edit({ - name: `Tickets: ${ticketcount}`, + name: `Tickets: ${ticketcount.size}`, reason: "Ticket count update" }) From 0677d2ff4a1b0e6b26933e5e93278d772f4f1167 Mon Sep 17 00:00:00 2001 From: danielpmc Date: Fri, 23 Oct 2020 14:09:57 +0100 Subject: [PATCH 128/255] Restore ready.js from backup. Broke the bot --- Panel/bot/discord/events/ready.js | 65 +++++++++++++------------------ 1 file changed, 26 insertions(+), 39 deletions(-) diff --git a/Panel/bot/discord/events/ready.js b/Panel/bot/discord/events/ready.js index 77350cc0e..07df5f108 100644 --- a/Panel/bot/discord/events/ready.js +++ b/Panel/bot/discord/events/ready.js @@ -1,9 +1,8 @@ +//let client = require("../../../../index.js").client; const axios = require('axios'); module.exports = async (client, guild, files) => { console.log(chalk.magenta('[DISCORD] ') + chalk.green(client.user.username + " has logged in!")); - let guild = bot.guilds.get('639477525927690240'); - //Auto Activities List const activities = [{ "text": "over DanBot Hosting", @@ -38,32 +37,27 @@ module.exports = async (client, guild, files) => { invites[g.id] = guildInvites; }); }); - - //Voice channel stats + + //Voice channel stats updator setInterval(async () => { - let staffCount = await guild.roles.get('748117822370086932').members; - client.channels.get("739821419910791348").edit({ - name: `Staff: ${staffCount.size}`, - reason: "Staff count update" - }); + let guild1 = await client.guilds.get("639477525927690240").fetchMembers(); + let roleID1 = '748117822370086932'; + let staffCount = guild1.roles.get(roleID1).members.size; + client.channels.get("739821419910791348").edit({ name: `Staff: ${staffCount}`, reason: "Staff count update" }); + + let guild2 = await client.guilds.get("639477525927690240").fetchMembers(); + let roleID2 = '639490038434103306'; + let memberCount = guild2.roles.get(roleID2).members.size; + client.channels.get("739821366991257621").edit({ name: `Members: ${memberCount}`, reason: "Member count update" }); + + let guild3 = await client.guilds.get("639477525927690240").fetchMembers(); + let roleID3 = '704467807122882562'; + let botCount = guild3.roles.get(roleID3).members.size; + client.channels.get("739821468296413254").edit({ name: `Bots: ${botCount}`, reason: "Bot count update" }); - let memberCount = await guild.roles.get('639490038434103306').members.size; - client.channels.get("739821366991257621").edit({ - name: `Members: ${memberCount.size}`, - reason: "Member count update" - }); - - let botCount = await guild3.roles.get('704467807122882562').members; - client.channels.get("739821468296413254").edit({ - name: `Bots: ${botCount.size}`, - reason: "Bot count update" - }); - - const ticketcount = await guild.channels.filter(x => x.name.endsWith("-ticket")) - client.channels.get("739821447924416562").edit({ - name: `Tickets: ${ticketcount.size}`, - reason: "Ticket count update" - }) + let guild4 = await client.guilds.get("639477525927690240") + const ticketcount = guild4.channels.filter(x=> x.name.endsWith("-ticket")).size + client.channels.get("739821447924416562").edit({ name: `Tickets: ${ticketcount}`, reason: "Ticket count update"}) axios({ url: config.Pterodactyl.hosturl + "/api/application/servers", @@ -76,10 +70,7 @@ module.exports = async (client, guild, files) => { 'Accept': 'Application/vnd.pterodactyl.v1+json', } }).then(response => { - client.channels.get("757199549977722890").edit({ - name: `Servers Hosting: ${response.data.meta.pagination.total}`, - reason: "Server count update" - }) + client.channels.get("757199549977722890").edit({ name: `Servers Hosting: ${response.data.meta.pagination.total}`, reason: "Server count update"}) }); axios({ @@ -93,14 +84,10 @@ module.exports = async (client, guild, files) => { 'Accept': 'Application/vnd.pterodactyl.v1+json', } }).then(response => { - client.channels.get("757222585015599214").edit({ - name: `Clients Hosting: ${response.data.meta.pagination.total}`, - reason: "Client count update" - }) + client.channels.get("757222585015599214").edit({ name: `Clients Hosting: ${response.data.meta.pagination.total}`, reason: "Client count update"}) }); - client.channels.get("758746579636191382").edit({ - name: `Boosts: ${client.guilds.get("639477525927690240").premiumSubscriptionCount}`, - reason: "Boosts count update" - }) + client.channels.get("758746579636191382").edit({ name: `Boosts: ${client.guilds.get("639477525927690240").premiumSubscriptionCount}`, reason: "Boosts count update" }) }, 30000); -}; \ No newline at end of file + + +}; From b1a6048690e10f9d6b1c233131862a2e15cd58c5 Mon Sep 17 00:00:00 2001 From: danielpmc Date: Fri, 23 Oct 2020 19:45:17 +0100 Subject: [PATCH 129/255] Fux --- Panel/bot/discord/commands/mute.js | 64 ++++++------ Panel/bot/discord/commands/server.js | 142 +++++++++++++++++++-------- Panel/bot/discord/events/message.js | 4 +- 3 files changed, 136 insertions(+), 74 deletions(-) diff --git a/Panel/bot/discord/commands/mute.js b/Panel/bot/discord/commands/mute.js index 506887f2e..2281f5066 100644 --- a/Panel/bot/discord/commands/mute.js +++ b/Panel/bot/discord/commands/mute.js @@ -2,14 +2,14 @@ exports.run = async (client, message, args) => { //Usage embed const usage = new Discord.RichEmbed() - .setColor(0x00A2E8) - .setThumbnail(client.user.avatarURL) - .setTitle("Command: " + config.DiscordBot.Prefix + "mute") - .addField("Usage", config.DiscordBot.Prefix + "mute @Someone ") - .addField("Example", config.DiscordBot.Prefix + "mute @Someone 5 spamming in general.") - .setDescription("Description: " + "Gives a user the muted role for x minutes"); + .setColor(0x00A2E8) + .setThumbnail(client.user.avatarURL) + .setTitle("Command: " + config.DiscordBot.Prefix + "mute") + .addField("Usage", config.DiscordBot.Prefix + "mute @Someone ") + .addField("Example", config.DiscordBot.Prefix + "mute @Someone 5 spamming in general.") + .setDescription("Description: " + "Gives a user the muted role for x minutes"); - if (message.member.roles.find(r => r.id === "748117822370086932")) { + if(message.member.roles.find(r => r.id === "748117822370086932")) { if (!message.guild.member(client.user).hasPermission('MANAGE_ROLES')) return message.reply('Sorry, i dont have the perms to do this cmd i need MANAGE_ROLES. :x:') //If no user pinged @@ -27,33 +27,37 @@ exports.run = async (client, message, args) => { //Muted embed const embed = new Discord.RichEmbed() - .setColor(0x00A2E8) - .setTitle("Action: Mute") - .addField("Moderator", message.author.tag + " (ID: " + message.author.id + ")") - .addField("User", user.user.tag + " (ID: " + user.user.id + ")") - .addField("Time", messagez, true) - .addField("Reason", reason, true) - .setFooter("Time used: " + message.createdAt.toDateString()) + .setColor(0x00A2E8) + .setTitle("Action: Mute") + .addField("Moderator", message.author.tag + " (ID: " + message.author.id + ")") + .addField("User", user.user.tag + " (ID: " + user.user.id + ")") + .addField("Time", messagez, true) + .addField("Reason", reason, true) + .setFooter("Time used: " + message.createdAt.toDateString()) message.guild.member(user).addRole(muteRole).then(() => { + mutesData.set(user.user.id, { + muted: "true", + muteTime: Date.now(), + mutedLength: messagez + }); message.channel.send("***The user has been successfully muted for " + messagez + " minute(s) :white_check_mark:***") - - if (!modlog) { - setTimeout(() => { - message.guild.member(user).removeRole(muteRole) - console.log(chalk.magenta('[DISCORD] ') + chalk.cyan(user.user.username + ' has now been unmuted after ' + messagez + ' minute(s)')) - }, messagez * 60000); - } else { - client.channels.get(modlog.id).send({ - embed - }) - setTimeout(() => { - message.guild.member(user).removeRole(muteRole) - console.log(chalk.magenta('[DISCORD] ') + chalk.cyan(user.user.username + ' has now been unmuted after ' + messagez + ' minute(s)')) - }, messagez * 60000); - } + if (!modlog) { + setTimeout(() => { + message.guild.member(user).removeRole(muteRole) + console.log(chalk.magenta('[DISCORD] ') + chalk.cyan(user.user.username + ' has now been unmuted after ' + messagez +' minute(s)')) + mutesData.delete(user); + }, messagez * 60000); + } else { + client.channels.get(modlog.id).send({embed}) + setTimeout(() => { + message.guild.member(user).removeRole(muteRole) + console.log(chalk.magenta('[DISCORD] ') + chalk.cyan(user.user.username + ' has now been unmuted after ' + messagez +' minute(s)')) + mutesData.delete(user); + }, messagez * 60000); + } }) - + } else { message.channel.send('Missing perms to do that :(') diff --git a/Panel/bot/discord/commands/server.js b/Panel/bot/discord/commands/server.js index 56061dac2..c79d5248b 100644 --- a/Panel/bot/discord/commands/server.js +++ b/Panel/bot/discord/commands/server.js @@ -77,26 +77,14 @@ exports.run = async (client, message, args) => { .addField(`__**Server name:**__`, data.name) .addField(`__**Type:**__`, args[1].toLowerCase()) message.channel.send(embed) - console.log(response) }).catch(error => { - if (error.includes("400")) { - const embed = new Discord.RichEmbed() - .setColor('RED') - .addField(`__**ERROR:**__`, "Node is out of ports. \nPlease wait for a host admin to open more ports.") - message.channel.send(embed) - message.channel.send('<@137624084572798976> Assign more ports.') - } else if (error.includes('504')) { - const embed = new Discord.RichEmbed() - .setColor('RED') - .addField(`__**ERROR:**__`, "Node did not respond in time. You could re-run the command or a outage might be happening if this happens multiple times") - message.channel.send(embed) - } else { + let embed1 = new Discord.RichEmbed() .setColor(`RED`) .addField(`__**FAILED:**__`, "Please contact a host admin. \n\nError: `" + error + "`") message.channel.send(embed1) message.channel.send("<@137624084572798976> Issue when creating server. \nResponse: `" + error + "`") - } + }) } } else if (args[1].toLowerCase() === "python") { @@ -154,24 +142,13 @@ exports.run = async (client, message, args) => { .addField(`__**Type:**__`, args[1].toLowerCase()) message.channel.send(embed) }).catch(error => { - if (error.includes("400")) { - const embed = new Discord.RichEmbed() - .setColor('RED') - .addField(`__**ERROR:**__`, "Node is out of ports. \nPlease wait for a host admin to open more ports.") - message.channel.send(embed) - message.channel.send('<@137624084572798976> Assign more ports.') - } else if (error.includes('504')) { - const embed = new Discord.RichEmbed() - .setColor('RED') - .addField(`__**ERROR:**__`, "Node did not respond in time. You could re-run the command or a outage might be happening if this happens multiple times") - message.channel.send(embed) - } else { + let embed1 = new Discord.RichEmbed() .setColor(`RED`) .addField(`__**FAILED:**__`, "Please contact a host admin. \n\nError: `" + error + "`") message.channel.send(embed1) message.channel.send("<@137624084572798976> Issue when creating server. \nResponse: `" + error + "`") - } + }) } } else if (args[1].toLowerCase() === "java") { @@ -229,24 +206,13 @@ exports.run = async (client, message, args) => { .addField(`__**Type:**__`, args[1].toLowerCase()) message.channel.send(embed) }).catch(error => { - if (error.includes("400")) { - const embed = new Discord.RichEmbed() - .setColor('RED') - .addField(`__**ERROR:**__`, "Node is out of ports. \nPlease wait for a host admin to open more ports.") - message.channel.send(embed) - message.channel.send('<@137624084572798976> Assign more ports.') - } else if (error.includes('504')) { - const embed = new Discord.RichEmbed() - .setColor('RED') - .addField(`__**ERROR:**__`, "Node did not respond in time. You could re-run the command or a outage might be happening if this happens multiple times") - message.channel.send(embed) - } else { + let embed1 = new Discord.RichEmbed() .setColor(`RED`) .addField(`__**FAILED:**__`, "Please contact a host admin. \n\nError: `" + error + "`") message.channel.send(embed1) message.channel.send("<@137624084572798976> Issue when creating server. \nResponse: `" + error + "`") - } + }) } } else if (args[1].toLowerCase() === "minecraft.paper") { @@ -464,9 +430,100 @@ exports.run = async (client, message, args) => { } } else if (args[0].toLowerCase() == "delete") { //delete server things - message.channel.send('Uh this isnt done yet...') + message.channel.send('Checking server ' + args[1]).then((msg) => { + axios({ + url: config.Pterodactyl.hosturl + "/api/application/servers/" + args[1], + method: 'GET', + followRedirect: true, + maxRedirects: 5, + headers: { + 'Authorization': 'Bearer ' + config.Pterodactyl.apikey, + 'Content-Type': 'application/json', + 'Accept': 'Application/vnd.pterodactyl.v1+json', + } + }).then(response => { + console.log(response) + msg.edit('Are you sure you want to delete `' + response.data.attributes.name + '`?\nPlease type `confirm` to delete this server. You have 1min until this will expire \n\n**You can not restore the server once it has been deleted**') + const collector = new Discord.MessageCollector(message.channel, m => m.author.id === message.author.id, { time: 60000, max: 2 }); + collector.on('collect', message => { + if (message == "confirm") { + message.delete() + axios({ + url: config.Pterodactyl.hosturl + "/api/application/servers/" + args[1], + method: 'DELETE', + followRedirect: true, + maxRedirects: 5, + headers: { + 'Authorization': 'Bearer ' + config.Pterodactyl.apikey, + 'Content-Type': 'application/json', + 'Accept': 'Application/vnd.pterodactyl.v1+json', + } + }).then(response => { + msg.edit('Server deleted!') + }); + } else { + message.delete() + msg.edit('Request cancelled!') + } + }) + }); + }) } else if (args[0].toLowerCase() == "manage") { message.channel.send('Uh this isnt done yet...') + } else if (args[0] == "list") { + message.channel.send('Loading servers...') + //List servers + var arr = []; + + axios({ + url: "https://panel.danbot.host" + "/api/application/servers", + method: 'GET', + followRedirect: true, + maxRedirects: 5, + headers: { + 'Authorization': 'Bearer ' + config.Pterodactyl.apikey, + 'Content-Type': 'application/json', + 'Accept': 'Application/vnd.pterodactyl.v1+json', + } + }).then(resources => { + var countmax = resources.data.meta.pagination.total_pages + var i2 = countmax++ + + var i = 0 + while (i { message.reply(embedstatus) })}); } + } else if (args[0].toLowerCase() == "proxy") { + const embed = new Discord.RichEmbed() + .setTitle('__**How to link a domain to a website/server**__ \nCommand format: `' + config.DiscordBot.Prefix + 'server proxy domainhere serverid') } }; }; \ No newline at end of file diff --git a/Panel/bot/discord/events/message.js b/Panel/bot/discord/events/message.js index 093e75b7b..d303d2760 100644 --- a/Panel/bot/discord/events/message.js +++ b/Panel/bot/discord/events/message.js @@ -1,7 +1,5 @@ module.exports = (client, message) => { - if (message.author.id === client.user.id) { - return; - } else if (message.content.toLowerCase().includes("discord.gg")) { + if (message.content.toLowerCase().includes("discord.gg")) { message.delete(); } else if (message.content.toLowerCase().includes("discord.com")) { message.delete() From 13faa3a6892907930350883e654c9ed422336105 Mon Sep 17 00:00:00 2001 From: danielpmc Date: Fri, 23 Oct 2020 19:50:33 +0100 Subject: [PATCH 130/255] fixing broke shit --- Panel/bot/discord/events/guildMemberAdd.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Panel/bot/discord/events/guildMemberAdd.js b/Panel/bot/discord/events/guildMemberAdd.js index af84af3bf..ca194ca98 100644 --- a/Panel/bot/discord/events/guildMemberAdd.js +++ b/Panel/bot/discord/events/guildMemberAdd.js @@ -78,7 +78,7 @@ module.exports = async(client, member, guild) => { member.guild.members.get(member.user.id).addRole(botrole); client.channels.get(config.welcome).send("Welcome <@" + member.user.id + ">, More bot friends :D \nBot owned by: <@" + bot.owner + ">"); } - } else if (!member.user.bot) { + } else { if (userData.get(message.author.id) == null) { const memberrole = member.guild.roles.find(role => role.id === config.member); member.guild.members.get(member.user.id).addRole(memberrole) From 7457024d4ec2bd312c8c021fc7834893afb50b2d Mon Sep 17 00:00:00 2001 From: danielpmc Date: Fri, 23 Oct 2020 21:01:16 +0100 Subject: [PATCH 131/255] Fixed mutes (hopefully) --- Panel/bot/discord/commands/mute.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Panel/bot/discord/commands/mute.js b/Panel/bot/discord/commands/mute.js index 2281f5066..cf1cbfd51 100644 --- a/Panel/bot/discord/commands/mute.js +++ b/Panel/bot/discord/commands/mute.js @@ -47,6 +47,9 @@ exports.run = async (client, message, args) => { message.guild.member(user).removeRole(muteRole) console.log(chalk.magenta('[DISCORD] ') + chalk.cyan(user.user.username + ' has now been unmuted after ' + messagez +' minute(s)')) mutesData.delete(user); + setTimeout(() => { + message.guild.member(user).removeRole(muteRole) + }, 2000) }, messagez * 60000); } else { client.channels.get(modlog.id).send({embed}) @@ -54,6 +57,9 @@ exports.run = async (client, message, args) => { message.guild.member(user).removeRole(muteRole) console.log(chalk.magenta('[DISCORD] ') + chalk.cyan(user.user.username + ' has now been unmuted after ' + messagez +' minute(s)')) mutesData.delete(user); + setTimeout(() => { + message.guild.member(user).removeRole(muteRole) + }, 2000) }, messagez * 60000); } }) From 089d30755d3b7e0b03e50fa8aca6e510fcf4e988 Mon Sep 17 00:00:00 2001 From: danielpmc Date: Fri, 23 Oct 2020 22:15:04 +0100 Subject: [PATCH 132/255] Fixed join messages not sending --- Panel/bot/discord/events/guildMemberAdd.js | 48 +++++++++++----------- 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/Panel/bot/discord/events/guildMemberAdd.js b/Panel/bot/discord/events/guildMemberAdd.js index ca194ca98..f8835e6c5 100644 --- a/Panel/bot/discord/events/guildMemberAdd.js +++ b/Panel/bot/discord/events/guildMemberAdd.js @@ -1,4 +1,4 @@ -const config = { +const config2 = { "welcome": "738527858594414663", "inviterewmsg": "738527858594414663", "invite5": "704650026076602449", @@ -71,24 +71,24 @@ module.exports = async(client, member, guild) => { let botID = member.user.id; let bot = db.get(`${botID}`); if(!bot) { - client.channels.get(config.welcome).send("Bot: <@" + member.user.id + ">, tried to join but is not using our API.") + client.channels.get(config2.welcome).send("Bot: <@" + member.user.id + ">, tried to join but is not using our API.") member.kick(); } else { - const botrole = member.guild.roles.find(role => role.id === config.bot); + const botrole = member.guild.roles.find(role => role.id === config2.bot); member.guild.members.get(member.user.id).addRole(botrole); - client.channels.get(config.welcome).send("Welcome <@" + member.user.id + ">, More bot friends :D \nBot owned by: <@" + bot.owner + ">"); + client.channels.get(config2.welcome).send("Welcome <@" + member.user.id + ">, More bot friends :D \nBot owned by: <@" + bot.owner + ">"); } } else { - if (userData.get(message.author.id) == null) { - const memberrole = member.guild.roles.find(role => role.id === config.member); + if (userData.get(member.user.id) == null) { + const memberrole = member.guild.roles.find(role => role.id === config2.member); member.guild.members.get(member.user.id).addRole(memberrole) - client.channels.get(config.welcome).send("Welcome <@" + member.user.id + "> to DanBot Hosting. To get started please read <#738527470164377630>"); + client.channels.get(config2.welcome).send("Welcome <@" + member.user.id + "> to DanBot Hosting. To get started please read <#738527470164377630>"); } else { - const memberrole = member.guild.roles.find(role => role.id === config.member); + const memberrole = member.guild.roles.find(role => role.id === config2.member); const clientrole = member.guild.roles.find(role => role.id === "639489891016638496"); member.guild.members.get(member.user.id).addRole(memberrole) member.guild.members.get(member.user.id).addRole(clientrole) - client.channels.get(config.welcome).send("Welcome back <@" + member.user.id + "> to DanBot Hosting!"); + client.channels.get(config2.welcome).send("Welcome back <@" + member.user.id + "> to DanBot Hosting!"); } if(mutesData.fetch(member.user.id + ".muted") === "true") { @@ -112,21 +112,21 @@ module.exports = async(client, member, guild) => { .addField(`Inviter's ID:`, '`' + inviter.id + '`', true) .addField(`Invite code used:`, '`' + invite.code + '`', true) .addField(`Invite used`, invite.uses + ' times', true); - client.channels.get(config.invitechannel).send(embed) - const invite5 = member.guild.roles.find(role => role.id === config.invite5); - const invite10 = member.guild.roles.find(role => role.id === config.invite10); - const invite25 = member.guild.roles.find(role => role.id === config.invite25); - const invite50 = member.guild.roles.find(role => role.id === config.invite50); - const invite100 = member.guild.roles.find(role => role.id === config.invite100); - const invite150 = member.guild.roles.find(role => role.id === config.invite150); - const invite200 = member.guild.roles.find(role => role.id === config.invite200); - if (invite.uses == 5) return member.guild.members.get(inviter.id).addRole(invite5), client.channels.get(config.inviterewmsg).send(`<@${inviter.id}> just hit 5 invites! Here's a role for you :)`); - if (invite.uses == 10) return member.guild.members.get(inviter.id).removeRole(invite5), member.guild.members.get(inviter.id).addRole(invite10), client.channels.get(config.inviterewmsg).send(`<@${inviter.id}> just hit 10 invites! Here's a role for you :)`); - if (invite.uses == 25) return member.guild.members.get(inviter.id).removeRole(invite10), member.guild.members.get(inviter.id).addRole(invite25), client.channels.get(config.inviterewmsg).send(`<@${inviter.id}> just hit 25 invites! Here's a role for you :)`); - if (invite.uses == 50) return member.guild.members.get(inviter.id).removeRole(invite25), member.guild.members.get(inviter.id).addRole(invite50), client.channels.get(config.inviterewmsg).send(`<@${inviter.id}> just hit 50 invites! Here's a role for you :)`); - if (invite.uses == 100) return member.guild.members.get(inviter.id).removeRole(invite50), member.guild.members.get(inviter.id).addRole(invite100), client.channels.get(config.inviterewmsg).send(`<@${inviter.id}> just hit 100 invites! Here's a role for you :)`);; - if (invite.uses == 150) return member.guild.members.get(inviter.id).removeRole(invite100), member.guild.members.get(inviter.id).addRole(invite150), client.channels.get(config.inviterewmsg).send(`<@${inviter.id}> just hit 150 invites! Here's a role for you :)`);; - if (invite.uses == 200) return member.guild.members.get(inviter.id).removeRole(invite150), member.guild.members.get(inviter.id).addRole(invite200), client.channels.get(config.inviterewmsg).send(`<@${inviter.id}> just hit 200 invites! Here's a role for you :)`);; + client.channels.get(config2.invitechannel).send(embed) + const invite5 = member.guild.roles.find(role => role.id === config2.invite5); + const invite10 = member.guild.roles.find(role => role.id === config2.invite10); + const invite25 = member.guild.roles.find(role => role.id === config2.invite25); + const invite50 = member.guild.roles.find(role => role.id === config2.invite50); + const invite100 = member.guild.roles.find(role => role.id === config2.invite100); + const invite150 = member.guild.roles.find(role => role.id === config2.invite150); + const invite200 = member.guild.roles.find(role => role.id === config2.invite200); + if (invite.uses == 5) return member.guild.members.get(inviter.id).addRole(invite5), client.channels.get(config2.inviterewmsg).send(`<@${inviter.id}> just hit 5 invites! Here's a role for you :)`); + if (invite.uses == 10) return member.guild.members.get(inviter.id).removeRole(invite5), member.guild.members.get(inviter.id).addRole(invite10), client.channels.get(config2.inviterewmsg).send(`<@${inviter.id}> just hit 10 invites! Here's a role for you :)`); + if (invite.uses == 25) return member.guild.members.get(inviter.id).removeRole(invite10), member.guild.members.get(inviter.id).addRole(invite25), client.channels.get(config2.inviterewmsg).send(`<@${inviter.id}> just hit 25 invites! Here's a role for you :)`); + if (invite.uses == 50) return member.guild.members.get(inviter.id).removeRole(invite25), member.guild.members.get(inviter.id).addRole(invite50), client.channels.get(config2.inviterewmsg).send(`<@${inviter.id}> just hit 50 invites! Here's a role for you :)`); + if (invite.uses == 100) return member.guild.members.get(inviter.id).removeRole(invite50), member.guild.members.get(inviter.id).addRole(invite100), client.channels.get(config2.inviterewmsg).send(`<@${inviter.id}> just hit 100 invites! Here's a role for you :)`);; + if (invite.uses == 150) return member.guild.members.get(inviter.id).removeRole(invite100), member.guild.members.get(inviter.id).addRole(invite150), client.channels.get(config2.inviterewmsg).send(`<@${inviter.id}> just hit 150 invites! Here's a role for you :)`);; + if (invite.uses == 200) return member.guild.members.get(inviter.id).removeRole(invite150), member.guild.members.get(inviter.id).addRole(invite200), client.channels.get(config2.inviterewmsg).send(`<@${inviter.id}> just hit 200 invites! Here's a role for you :)`);; }); From e88e2d3047568fa48e2871f1b8b40001ce5984ac Mon Sep 17 00:00:00 2001 From: danielpmc Date: Fri, 23 Oct 2020 22:18:40 +0100 Subject: [PATCH 133/255] Fixed creating servers (thonk) --- Panel/bot/discord/commands/server.js | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/Panel/bot/discord/commands/server.js b/Panel/bot/discord/commands/server.js index c79d5248b..fc9af34b6 100644 --- a/Panel/bot/discord/commands/server.js +++ b/Panel/bot/discord/commands/server.js @@ -47,7 +47,8 @@ exports.run = async (client, message, args) => { }, "feature_limits": { "databases": 0, - "allocations": 1 + "allocations": 1, + "backups": 10 }, "deploy": { "locations": [3], @@ -111,7 +112,8 @@ exports.run = async (client, message, args) => { }, "feature_limits": { "databases": 0, - "allocations": 1 + "allocations": 1, + "backups": 10 }, "deploy": { "locations": [3], @@ -175,7 +177,8 @@ exports.run = async (client, message, args) => { }, "feature_limits": { "databases": 0, - "allocations": 1 + "allocations": 1, + "backups": 10 }, "deploy": { "locations": [3], @@ -242,7 +245,8 @@ exports.run = async (client, message, args) => { }, "feature_limits": { "databases": 0, - "allocations": 1 + "allocations": 1, + "backups": 10 }, "deploy": { "locations": [5], @@ -310,7 +314,8 @@ exports.run = async (client, message, args) => { }, "feature_limits": { "databases": 2, - "allocations": 1 + "allocations": 1, + "backups": 10 }, "deploy": { "locations": [5], @@ -381,7 +386,8 @@ exports.run = async (client, message, args) => { }, "feature_limits": { "databases": 2, - "allocations": 1 + "allocations": 1, + "backups": 10 }, "deploy": { "locations": [5], From b5083c2890e143a5d0fcfda4feb5cc4c85395af6 Mon Sep 17 00:00:00 2001 From: danielpmc Date: Fri, 23 Oct 2020 22:43:07 +0100 Subject: [PATCH 134/255] Fix help cmd --- Panel/bot/discord/commands/help.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Panel/bot/discord/commands/help.js b/Panel/bot/discord/commands/help.js index 98567b763..2caa31875 100644 --- a/Panel/bot/discord/commands/help.js +++ b/Panel/bot/discord/commands/help.js @@ -18,7 +18,7 @@ exports.run = async (client, message, args) => { .addField(`__**Commands List for users:**__`, Help.Users) .addField(`__**Staff Commands:**__`, Help.Staff) message.channel.send(embed) - } else if (message.member.roles.find(r => r.id === "639490038434103306")) { + } else { let embed = new Discord.RichEmbed() .setColor(`BLUE`) .addField(`__**Commands List for users:**__`, Help.Users) From 8d6f8a93ce3cd49f8d8808c0f1ef4303a6d9a23b Mon Sep 17 00:00:00 2001 From: danielpmc Date: Fri, 23 Oct 2020 22:44:53 +0100 Subject: [PATCH 135/255] Changed a few things in help cmd --- Panel/bot/discord/commands/help.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Panel/bot/discord/commands/help.js b/Panel/bot/discord/commands/help.js index 2caa31875..316e4f527 100644 --- a/Panel/bot/discord/commands/help.js +++ b/Panel/bot/discord/commands/help.js @@ -1,7 +1,7 @@ const Help = { - "Users": `${config.DiscordBot.Prefix}user | See help for that command \n${config.DiscordBot.Prefix}server | See help for that command \n${config.DiscordBot.Prefix}stats | Shows the stats of each hosting node. \n${config.DiscordBot.Prefix}ticket | Create a ticket for help from the staff team! \n${config.DiscordBot.Prefix}status | Check the status of your server! \n${config.DiscordBot.Prefix}uptime | Shows the bots uptime \n${config.DiscordBot.Prefix}info | Get a bots info. \n ${config.DiscordBot.Prefix}suggest | Get the link to send in suggestions.`, - "Staff": `${config.DiscordBot.Prefix}staff | See help for that command \n${config.DiscordBot.Prefix}purge | Delete messages in a channel \n${config.DiscordBot.Prefix}access | Gain subuser access to a server \n${config.DiscordBot.Prefix}mute | Mute da user \n${config.DiscordBot.Prefix}kick | Kick da user`, - "Owner": `${config.DiscordBot.Prefix}reload | Reloads all commands on the bot \n${config.DiscordBot.Prefix}restart | Restarts **EVERYTHING**, Bot and Stats website \n${config.DiscordBot.Prefix}say | Says what you want it to say \n${config.DiscordBot.Prefix}eval | Eval some code \n${config.DiscordBot.Prefix}exec | Run some system commands \n${config.DiscordBot.Prefix}giveaway | Launch a giveaway \n${config.DiscordBot.Prefix}announce | Announce something` + "Users": `${config.DiscordBot.Prefix}user | See help for that command \n${config.DiscordBot.Prefix}server | See help for that command \n${config.DiscordBot.Prefix}stats | Shows the stats of each hosting node. \n${config.DiscordBot.Prefix}ticket | Create a ticket for help from the staff team! \n${config.DiscordBot.Prefix}uptime | Shows the bots uptime \n${config.DiscordBot.Prefix}info | Get a bots info. \n ${config.DiscordBot.Prefix}suggest | Get the link to send in suggestions.`, + "Staff": `${config.DiscordBot.Prefix}staff | See help for that command \n${config.DiscordBot.Prefix}purge | Delete messages in a channel \n${config.DiscordBot.Prefix}mute | Mute da user \n${config.DiscordBot.Prefix}kick | Kick da user`, + "Owner": `${config.DiscordBot.Prefix}reload | Reloads all commands on the bot \n${config.DiscordBot.Prefix}staff update | Pull latest git commit \n${config.DiscordBot.Prefix}say | Says what you want it to say \n${config.DiscordBot.Prefix}eval | Eval some code \n${config.DiscordBot.Prefix}exec | Run some system commands \n${config.DiscordBot.Prefix}giveaway | Launch a giveaway \n${config.DiscordBot.Prefix}announce | Announce something` } exports.run = async (client, message, args) => { From dd34a98613addf8bb0c26cdaa26e0033a2a0e05d Mon Sep 17 00:00:00 2001 From: danielpmc Date: Fri, 23 Oct 2020 23:39:45 +0100 Subject: [PATCH 136/255] Removed --- Panel/routes/bot.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Panel/routes/bot.js b/Panel/routes/bot.js index 89e6b11da..ad8881c20 100644 --- a/Panel/routes/bot.js +++ b/Panel/routes/bot.js @@ -5,6 +5,7 @@ const db = require("quick.db"); const isSnowflake = require(process.cwd() + "/util/isSnowflake.js"); Router.get("/:ID/", (req, res) => { + /* let ID = req.params.ID; if (!ID) return res.status(400).send({ error: true, message: "Please give a bot ID" }); @@ -51,6 +52,7 @@ Router.get("/:ID/remove", checkAuth, (req, res) => { } else { return res.render("error.ejs", { message: "You're not authorized to make changes to this bot." }); } + */ }); module.exports = Router; From f5b78decd8c9de7d2ee9119af4d3af123c0cf7f7 Mon Sep 17 00:00:00 2001 From: danielpmc Date: Fri, 23 Oct 2020 23:58:47 +0100 Subject: [PATCH 137/255] Added bedrock servers changed formatting on list command --- Panel/bot/discord/commands/server.js | 70 +++++++++++++++++++++++++++- 1 file changed, 69 insertions(+), 1 deletion(-) diff --git a/Panel/bot/discord/commands/server.js b/Panel/bot/discord/commands/server.js index fc9af34b6..89cc3dfb4 100644 --- a/Panel/bot/discord/commands/server.js +++ b/Panel/bot/discord/commands/server.js @@ -398,6 +398,72 @@ exports.run = async (client, message, args) => { "oom_disabled": false }; + //Sending the data: + axios({ + url: config.Pterodactyl.hosturl + "/api/application/servers", + method: 'POST', + followRedirect: true, + maxRedirects: 5, + headers: { + 'Authorization': 'Bearer ' + config.Pterodactyl.apikey, + 'Content-Type': 'application/json', + 'Accept': 'Application/vnd.pterodactyl.v1+json', + }, + data: data, + }).then(response => { + let embed = new Discord.RichEmbed() + .setColor(`GREEN`) + .addField(`__**Status:**__`, response.statusText) + .addField(`__**Created for user ID:**__`, data.user) + .addField(`__**Server name:**__`, data.name) + .addField(`__**Type:**__`, args[1].toLowerCase()) + message.channel.send(embed) + }).catch(error => { + + let embed1 = new Discord.RichEmbed() + .setColor(`RED`) + .addField(`__**FAILED:**__`, "Please contact a host admin. \n\nError: `" + error + "`") + message.channel.send(embed1) + message.channel.send("<@137624084572798976> Issue when creating server. \nResponse: `" + error + "`") + }) + } + }else if (args[1].toLowerCase() === "minecraft.bedrock") { + if (!otherargs) { + message.channel.send('You must provide a server name!') + } else { + //Data to send + const data = { + "name": otherargs, + "user": userData.get(message.author.id + ".consoleID"), + "nest": 1, + "egg": 18, + "docker_image": "quay.io/parkervcp/pterodactyl-images:base_ubuntu", + "startup": "./bedrock_server", + "limits": { + "memory": 2048, + "swap": 0, + "disk": 0, + "io": 500, + "cpu": 0 + }, + "environment": { + "BEDROCK_VERSION": "latest", + "LD_LIBRARY_PATH": "." + }, + "feature_limits": { + "databases": 2, + "allocations": 1, + "backups": 10 + }, + "deploy": { + "locations": [5], + "dedicated_ip": false, + "port_range": [] + }, + "start_on_completion": false, + "oom_disabled": false + }; + //Sending the data: axios({ url: config.Pterodactyl.hosturl + "/api/application/servers", @@ -431,7 +497,9 @@ exports.run = async (client, message, args) => { //Anything else let embed2 = new Discord.RichEmbed() .setColor(`RED`) - .addField(`__**Supported By Server Creation:**__`, "NodeJS \nPython \nJava \nMinecraft.Paper \nMinecraft.Forge \nFiveM") + .addField(`__**Minecraft:**__`, "Minecraft.Forge \nMinecraft.Paper \nMinecraft.Bedrock", true) + .addField(`__**Grand Theft Auto:**__`, "GTAV.FiveM", true) + .addField(`__**Bots:**__`, "NodeJS \nPython \nJava") message.channel.send(embed2) } } else if (args[0].toLowerCase() == "delete") { From ea200f278ee1b41598531ee7b76b390a6915bef8 Mon Sep 17 00:00:00 2001 From: danielpmc Date: Sat, 24 Oct 2020 00:00:48 +0100 Subject: [PATCH 138/255] FiveM to gtav.givem to give more gta versions --- Panel/bot/discord/commands/server.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Panel/bot/discord/commands/server.js b/Panel/bot/discord/commands/server.js index 89cc3dfb4..fb4298ea3 100644 --- a/Panel/bot/discord/commands/server.js +++ b/Panel/bot/discord/commands/server.js @@ -355,7 +355,7 @@ exports.run = async (client, message, args) => { message.channel.send("<@137624084572798976> Issue when creating server. \nResponse: `" + error + "`") }) } - } else if (args[1].toLowerCase() === "fivem") { + } else if (args[1].toLowerCase() === "gtav.fivem") { if (!otherargs) { message.channel.send('You must provide a server name!') } else { From 3704885177c5b4a70bdc058c61bc75b08254d12d Mon Sep 17 00:00:00 2001 From: danielpmc Date: Sat, 24 Oct 2020 00:08:55 +0100 Subject: [PATCH 139/255] Added gmod and gs:go to server creation --- Panel/bot/discord/commands/server.js | 143 ++++++++++++++++++++++++++- 1 file changed, 141 insertions(+), 2 deletions(-) diff --git a/Panel/bot/discord/commands/server.js b/Panel/bot/discord/commands/server.js index fb4298ea3..78401a0a2 100644 --- a/Panel/bot/discord/commands/server.js +++ b/Panel/bot/discord/commands/server.js @@ -427,7 +427,7 @@ exports.run = async (client, message, args) => { message.channel.send("<@137624084572798976> Issue when creating server. \nResponse: `" + error + "`") }) } - }else if (args[1].toLowerCase() === "minecraft.bedrock") { + } else if (args[1].toLowerCase() === "minecraft.bedrock") { if (!otherargs) { message.channel.send('You must provide a server name!') } else { @@ -464,6 +464,144 @@ exports.run = async (client, message, args) => { "oom_disabled": false }; + //Sending the data: + axios({ + url: config.Pterodactyl.hosturl + "/api/application/servers", + method: 'POST', + followRedirect: true, + maxRedirects: 5, + headers: { + 'Authorization': 'Bearer ' + config.Pterodactyl.apikey, + 'Content-Type': 'application/json', + 'Accept': 'Application/vnd.pterodactyl.v1+json', + }, + data: data, + }).then(response => { + let embed = new Discord.RichEmbed() + .setColor(`GREEN`) + .addField(`__**Status:**__`, response.statusText) + .addField(`__**Created for user ID:**__`, data.user) + .addField(`__**Server name:**__`, data.name) + .addField(`__**Type:**__`, args[1].toLowerCase()) + message.channel.send(embed) + }).catch(error => { + + let embed1 = new Discord.RichEmbed() + .setColor(`RED`) + .addField(`__**FAILED:**__`, "Please contact a host admin. \n\nError: `" + error + "`") + message.channel.send(embed1) + message.channel.send("<@137624084572798976> Issue when creating server. \nResponse: `" + error + "`") + }) + } + } else if (args[1].toLowerCase() === "gmod") { + if (!otherargs) { + message.channel.send('You must provide a server name!') + } else { + //Data to send + const data = { + "name": otherargs, + "user": userData.get(message.author.id + ".consoleID"), + "nest": 2, + "egg": 9, + "docker_image": "quay.io/pterodactyl/core:source", + "startup": "./srcds_run -game garrysmod -console -port {{SERVER_PORT}} +ip 0.0.0.0 +host_workshop_collection {{WORKSHOP_ID}} +map {{SRCDS_MAP}} +gamemode {{GAMEMODE}} -strictportbind -norestart +sv_setsteamaccount {{STEAM_ACC}} +maxplayers {{MAX_PLAYERS}} -tickrate {{TICKRATE}}", + "limits": { + "memory": 2048, + "swap": 0, + "disk": 0, + "io": 500, + "cpu": 0 + }, + "environment": { + "SRCDS_MAP": "gm_flatgrass", + "STEAM_ACC": null, + "SRCDS_APPID": "4020", + "WORKSHOP_ID": null, + "GAMEMODE": "sandbox", + "MAX_PLAYERS": "32", + "TICKRATE": "22" + }, + "feature_limits": { + "databases": 2, + "allocations": 1, + "backups": 10 + }, + "deploy": { + "locations": [5], + "dedicated_ip": false, + "port_range": [] + }, + "start_on_completion": false, + "oom_disabled": false + }; + + //Sending the data: + axios({ + url: config.Pterodactyl.hosturl + "/api/application/servers", + method: 'POST', + followRedirect: true, + maxRedirects: 5, + headers: { + 'Authorization': 'Bearer ' + config.Pterodactyl.apikey, + 'Content-Type': 'application/json', + 'Accept': 'Application/vnd.pterodactyl.v1+json', + }, + data: data, + }).then(response => { + let embed = new Discord.RichEmbed() + .setColor(`GREEN`) + .addField(`__**Status:**__`, response.statusText) + .addField(`__**Created for user ID:**__`, data.user) + .addField(`__**Server name:**__`, data.name) + .addField(`__**Type:**__`, args[1].toLowerCase()) + message.channel.send(embed) + }).catch(error => { + + let embed1 = new Discord.RichEmbed() + .setColor(`RED`) + .addField(`__**FAILED:**__`, "Please contact a host admin. \n\nError: `" + error + "`") + message.channel.send(embed1) + message.channel.send("<@137624084572798976> Issue when creating server. \nResponse: `" + error + "`") + }) + } + } else if (args[1].toLowerCase() === "gs:go") { + if (!otherargs) { + message.channel.send('You must provide a server name!') + } else { + //Data to send + const data = { + "name": otherargs, + "user": userData.get(message.author.id + ".consoleID"), + "nest": 2, + "egg": 7, + "docker_image": "quay.io/pterodactyl/core:source", + "startup": "./srcds_run -game csgo -console -port {{SERVER_PORT}} +ip 0.0.0.0 +map {{SRCDS_MAP}} -strictportbind -norestart +sv_setsteamaccount {{STEAM_ACC}}", + "limits": { + "memory": 2048, + "swap": 0, + "disk": 0, + "io": 500, + "cpu": 0 + }, + "environment": { + "SRCDS_MAP": "de_dust2", + "STEAM_ACC": ".", + "SRCDS_APPID": "740" + }, + "feature_limits": { + "databases": 2, + "allocations": 1, + "backups": 10 + }, + "deploy": { + "locations": [5], + "dedicated_ip": false, + "port_range": [] + }, + "start_on_completion": false, + "oom_disabled": false + }; + //Sending the data: axios({ url: config.Pterodactyl.hosturl + "/api/application/servers", @@ -499,7 +637,8 @@ exports.run = async (client, message, args) => { .setColor(`RED`) .addField(`__**Minecraft:**__`, "Minecraft.Forge \nMinecraft.Paper \nMinecraft.Bedrock", true) .addField(`__**Grand Theft Auto:**__`, "GTAV.FiveM", true) - .addField(`__**Bots:**__`, "NodeJS \nPython \nJava") + .addField(`__**Bots:**__`, "NodeJS \nPython \nJava", true) + .addField(`__**Source Engine:**__`, "GMod \nGS:GO") message.channel.send(embed2) } } else if (args[0].toLowerCase() == "delete") { From 0e1256259efbdb042d48bba6cb9c14d812f4f9b5 Mon Sep 17 00:00:00 2001 From: danielpmc Date: Sat, 24 Oct 2020 00:11:41 +0100 Subject: [PATCH 140/255] Update server creation a little --- Panel/bot/discord/commands/server.js | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Panel/bot/discord/commands/server.js b/Panel/bot/discord/commands/server.js index 78401a0a2..386cd9dab 100644 --- a/Panel/bot/discord/commands/server.js +++ b/Panel/bot/discord/commands/server.js @@ -218,7 +218,7 @@ exports.run = async (client, message, args) => { }) } - } else if (args[1].toLowerCase() === "minecraft.paper") { + } else if (args[1].toLowerCase() === "paper") { if (!otherargs) { message.channel.send('You must provide a server name!') } else { @@ -287,7 +287,7 @@ exports.run = async (client, message, args) => { }) } - } else if (args[1].toLowerCase() === "minecraft.forge") { + } else if (args[1].toLowerCase() === "forge") { if (!otherargs) { message.channel.send('You must provide a server name!') } else { @@ -355,7 +355,7 @@ exports.run = async (client, message, args) => { message.channel.send("<@137624084572798976> Issue when creating server. \nResponse: `" + error + "`") }) } - } else if (args[1].toLowerCase() === "gtav.fivem") { + } else if (args[1].toLowerCase() === "fivem") { if (!otherargs) { message.channel.send('You must provide a server name!') } else { @@ -427,7 +427,7 @@ exports.run = async (client, message, args) => { message.channel.send("<@137624084572798976> Issue when creating server. \nResponse: `" + error + "`") }) } - } else if (args[1].toLowerCase() === "minecraft.bedrock") { + } else if (args[1].toLowerCase() === "bedrock") { if (!otherargs) { message.channel.send('You must provide a server name!') } else { @@ -635,10 +635,10 @@ exports.run = async (client, message, args) => { //Anything else let embed2 = new Discord.RichEmbed() .setColor(`RED`) - .addField(`__**Minecraft:**__`, "Minecraft.Forge \nMinecraft.Paper \nMinecraft.Bedrock", true) - .addField(`__**Grand Theft Auto:**__`, "GTAV.FiveM", true) + .addField(`__**Minecraft:**__`, "Forge \nPaper \nBedrock", true) + .addField(`__**Grand Theft Auto:**__`, "FiveM", true) .addField(`__**Bots:**__`, "NodeJS \nPython \nJava", true) - .addField(`__**Source Engine:**__`, "GMod \nGS:GO") + .addField(`__**Source Engine:**__`, "GMod \nGS:GO", true) message.channel.send(embed2) } } else if (args[0].toLowerCase() == "delete") { From 11b07fb03819f53b0756dd67599678d71a5e6e0a Mon Sep 17 00:00:00 2001 From: danielpmc Date: Sat, 24 Oct 2020 13:03:57 +0100 Subject: [PATCH 141/255] Check make sure create account channels are closed after a hour --- Panel/bot/discord/events/ready.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Panel/bot/discord/events/ready.js b/Panel/bot/discord/events/ready.js index 07df5f108..c30b33fc4 100644 --- a/Panel/bot/discord/events/ready.js +++ b/Panel/bot/discord/events/ready.js @@ -3,6 +3,11 @@ const axios = require('axios'); module.exports = async (client, guild, files) => { console.log(chalk.magenta('[DISCORD] ') + chalk.green(client.user.username + " has logged in!")); + //Check make sure create account channels are closed after a hour + setTimeout(() => { + client.guilds.get("639477525927690240").channels.filter(x => x.parentID == '738539016688894024' && (Date.now() - x.createdAt) > 1800000 ).forEach(x => x.delete()) + }, 60000) + //Auto Activities List const activities = [{ "text": "over DanBot Hosting", From 9d884a64a997c3408db5e560e60f6a73063bbb7d Mon Sep 17 00:00:00 2001 From: danielpmc Date: Sat, 24 Oct 2020 22:39:53 +0100 Subject: [PATCH 142/255] uh ignore --- Panel/bot/discord/commands/server.js | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/Panel/bot/discord/commands/server.js b/Panel/bot/discord/commands/server.js index 386cd9dab..11756e5e5 100644 --- a/Panel/bot/discord/commands/server.js +++ b/Panel/bot/discord/commands/server.js @@ -781,8 +781,14 @@ exports.run = async (client, message, args) => { })}); } } else if (args[0].toLowerCase() == "proxy") { + let domainfilter = [".com", ".co.uk"]; + const embed = new Discord.RichEmbed() .setTitle('__**How to link a domain to a website/server**__ \nCommand format: `' + config.DiscordBot.Prefix + 'server proxy domainhere serverid') - } + if (!args[1]) { + message.channel.send(embed) + } + + } }; }; \ No newline at end of file From bbd26e49aa5658fb742eb3ae180ca208c6bdc5fa Mon Sep 17 00:00:00 2001 From: danielpmc Date: Sat, 24 Oct 2020 22:56:38 +0100 Subject: [PATCH 143/255] Add more services. --- Panel/bot/discord/commands/server.js | 209 ++++++++++++++++++++++++++- 1 file changed, 208 insertions(+), 1 deletion(-) diff --git a/Panel/bot/discord/commands/server.js b/Panel/bot/discord/commands/server.js index 11756e5e5..746677e36 100644 --- a/Panel/bot/discord/commands/server.js +++ b/Panel/bot/discord/commands/server.js @@ -602,6 +602,212 @@ exports.run = async (client, message, args) => { "oom_disabled": false }; + //Sending the data: + axios({ + url: config.Pterodactyl.hosturl + "/api/application/servers", + method: 'POST', + followRedirect: true, + maxRedirects: 5, + headers: { + 'Authorization': 'Bearer ' + config.Pterodactyl.apikey, + 'Content-Type': 'application/json', + 'Accept': 'Application/vnd.pterodactyl.v1+json', + }, + data: data, + }).then(response => { + let embed = new Discord.RichEmbed() + .setColor(`GREEN`) + .addField(`__**Status:**__`, response.statusText) + .addField(`__**Created for user ID:**__`, data.user) + .addField(`__**Server name:**__`, data.name) + .addField(`__**Type:**__`, args[1].toLowerCase()) + message.channel.send(embed) + }).catch(error => { + + let embed1 = new Discord.RichEmbed() + .setColor(`RED`) + .addField(`__**FAILED:**__`, "Please contact a host admin. \n\nError: `" + error + "`") + message.channel.send(embed1) + message.channel.send("<@137624084572798976> Issue when creating server. \nResponse: `" + error + "`") + }) + } + } else if (args[1].toLowerCase() === "ARK:SE") { + if (!otherargs) { + message.channel.send('You must provide a server name!') + } else { + //Data to send + const data = { + "name": otherargs, + "user": userData.get(message.author.id + ".consoleID"), + "nest": 2, + "egg": 6, + "docker_image": "quay.io/pterodactyl/core:source", + "startup": `"cd ShooterGame/Binaries/Linux && ./ShooterGameServer {{SERVER_MAP}}?listen?SessionName='{{SESSION_NAME}}'?ServerPassword={{ARK_PASSWORD}}?ServerAdminPassword={{ARK_ADMIN_PASSWORD}}?Port={{PORT}}?MaxPlayers={{SERVER_MAX_PLAYERS}}?RCONPort={{RCON_PORT}}?QueryPort={{QUERY_PORT}}?RCONEnabled={{ENABLE_RCON}} -server -log"`, + "limits": { + "memory": 2048, + "swap": 0, + "disk": 0, + "io": 500, + "cpu": 0 + }, + "environment": { + "ARK_PASSWORD": null, + "ARK_ADMIN_PASSWORD": null, + "SERVER_MAX_PLAYERS": "20", + "SERVER_MAP": "TheIsland", + "SESSION_NAME": "ARK SERVER", + "PORT": "7777", + "ENABLE_RCON": "false", + "RCON_PORT": "27020", + "QUERY_PORT": "27015", + "SRCDS_APPID": "376030" + }, + "feature_limits": { + "databases": 2, + "allocations": 1, + "backups": 10 + }, + "deploy": { + "locations": [5], + "dedicated_ip": false, + "port_range": [] + }, + "start_on_completion": false, + "oom_disabled": false + }; + + //Sending the data: + axios({ + url: config.Pterodactyl.hosturl + "/api/application/servers", + method: 'POST', + followRedirect: true, + maxRedirects: 5, + headers: { + 'Authorization': 'Bearer ' + config.Pterodactyl.apikey, + 'Content-Type': 'application/json', + 'Accept': 'Application/vnd.pterodactyl.v1+json', + }, + data: data, + }).then(response => { + let embed = new Discord.RichEmbed() + .setColor(`GREEN`) + .addField(`__**Status:**__`, response.statusText) + .addField(`__**Created for user ID:**__`, data.user) + .addField(`__**Server name:**__`, data.name) + .addField(`__**Type:**__`, args[1].toLowerCase()) + message.channel.send(embed) + }).catch(error => { + + let embed1 = new Discord.RichEmbed() + .setColor(`RED`) + .addField(`__**FAILED:**__`, "Please contact a host admin. \n\nError: `" + error + "`") + message.channel.send(embed1) + message.channel.send("<@137624084572798976> Issue when creating server. \nResponse: `" + error + "`") + }) + } + } else if (args[1].toLowerCase() === "TS3") { + if (!otherargs) { + message.channel.send('You must provide a server name!') + } else { + //Data to send + const data = { + "name": otherargs, + "user": userData.get(message.author.id + ".consoleID"), + "nest": 3, + "egg": 13, + "docker_image": "quay.io/parkervcp/pterodactyl-images:base_debian", + "startup": `./ts3server default_voice_port={{SERVER_PORT}} query_port={{SERVER_PORT}} filetransfer_ip=0.0.0.0 filetransfer_port={{FILE_TRANSFER}} license_accepted=1`, + "limits": { + "memory": 0, + "swap": 0, + "disk": 0, + "io": 500, + "cpu": 0 + }, + "environment": { + "TS_VERSION": "latest", + "FILE_TRANSFER": "30033" + }, + "feature_limits": { + "databases": 2, + "allocations": 1, + "backups": 10 + }, + "deploy": { + "locations": [3], + "dedicated_ip": false, + "port_range": [] + }, + "start_on_completion": false, + "oom_disabled": false + }; + + //Sending the data: + axios({ + url: config.Pterodactyl.hosturl + "/api/application/servers", + method: 'POST', + followRedirect: true, + maxRedirects: 5, + headers: { + 'Authorization': 'Bearer ' + config.Pterodactyl.apikey, + 'Content-Type': 'application/json', + 'Accept': 'Application/vnd.pterodactyl.v1+json', + }, + data: data, + }).then(response => { + let embed = new Discord.RichEmbed() + .setColor(`GREEN`) + .addField(`__**Status:**__`, response.statusText) + .addField(`__**Created for user ID:**__`, data.user) + .addField(`__**Server name:**__`, data.name) + .addField(`__**Type:**__`, args[1].toLowerCase()) + message.channel.send(embed) + }).catch(error => { + + let embed1 = new Discord.RichEmbed() + .setColor(`RED`) + .addField(`__**FAILED:**__`, "Please contact a host admin. \n\nError: `" + error + "`") + message.channel.send(embed1) + message.channel.send("<@137624084572798976> Issue when creating server. \nResponse: `" + error + "`") + }) + } + } else if (args[1].toLowerCase() === "Mumble") { + if (!otherargs) { + message.channel.send('You must provide a server name!') + } else { + //Data to send + const data = { + "name": otherargs, + "user": userData.get(message.author.id + ".consoleID"), + "nest": 3, + "egg": 12, + "docker_image": "quay.io/pterodactyl/core:glibc", + "startup": `./murmur.x86 -fg`, + "limits": { + "memory": 0, + "swap": 0, + "disk": 0, + "io": 500, + "cpu": 0 + }, + "environment": { + "MAX_USERS": "100", + "MUMBLE_VERSION": "1.3.1" + }, + "feature_limits": { + "databases": 2, + "allocations": 1, + "backups": 10 + }, + "deploy": { + "locations": [3], + "dedicated_ip": false, + "port_range": [] + }, + "start_on_completion": false, + "oom_disabled": false + }; + //Sending the data: axios({ url: config.Pterodactyl.hosturl + "/api/application/servers", @@ -638,7 +844,8 @@ exports.run = async (client, message, args) => { .addField(`__**Minecraft:**__`, "Forge \nPaper \nBedrock", true) .addField(`__**Grand Theft Auto:**__`, "FiveM", true) .addField(`__**Bots:**__`, "NodeJS \nPython \nJava", true) - .addField(`__**Source Engine:**__`, "GMod \nGS:GO", true) + .addField(`__**Source Engine:**__`, "GMod \nGS:GO \nARK:SE", true) + .addField(`__**Voice Servers:**__`, "TS3 \nMumble") message.channel.send(embed2) } } else if (args[0].toLowerCase() == "delete") { From 78bc998771dbde5c12c206bcba910774be5eeb09 Mon Sep 17 00:00:00 2001 From: danielpmc Date: Sat, 24 Oct 2020 22:57:29 +0100 Subject: [PATCH 144/255] Forgot to add the ,true on the end --- Panel/bot/discord/commands/server.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Panel/bot/discord/commands/server.js b/Panel/bot/discord/commands/server.js index 746677e36..99582bcd6 100644 --- a/Panel/bot/discord/commands/server.js +++ b/Panel/bot/discord/commands/server.js @@ -845,7 +845,7 @@ exports.run = async (client, message, args) => { .addField(`__**Grand Theft Auto:**__`, "FiveM", true) .addField(`__**Bots:**__`, "NodeJS \nPython \nJava", true) .addField(`__**Source Engine:**__`, "GMod \nGS:GO \nARK:SE", true) - .addField(`__**Voice Servers:**__`, "TS3 \nMumble") + .addField(`__**Voice Servers:**__`, "TS3 \nMumble", true) message.channel.send(embed2) } } else if (args[0].toLowerCase() == "delete") { From fb0814a66f7f5c9f89350b87780e0e14335c3e82 Mon Sep 17 00:00:00 2001 From: danielpmc Date: Sat, 24 Oct 2020 23:07:08 +0100 Subject: [PATCH 145/255] uh oh --- Panel/bot/discord/commands/server.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Panel/bot/discord/commands/server.js b/Panel/bot/discord/commands/server.js index 99582bcd6..8fd47f4dc 100644 --- a/Panel/bot/discord/commands/server.js +++ b/Panel/bot/discord/commands/server.js @@ -631,7 +631,7 @@ exports.run = async (client, message, args) => { message.channel.send("<@137624084572798976> Issue when creating server. \nResponse: `" + error + "`") }) } - } else if (args[1].toLowerCase() === "ARK:SE") { + } else if (args[1].toLowerCase() === "ark:se") { if (!otherargs) { message.channel.send('You must provide a server name!') } else { @@ -705,7 +705,7 @@ exports.run = async (client, message, args) => { message.channel.send("<@137624084572798976> Issue when creating server. \nResponse: `" + error + "`") }) } - } else if (args[1].toLowerCase() === "TS3") { + } else if (args[1].toLowerCase() === "ts3") { if (!otherargs) { message.channel.send('You must provide a server name!') } else { @@ -771,7 +771,7 @@ exports.run = async (client, message, args) => { message.channel.send("<@137624084572798976> Issue when creating server. \nResponse: `" + error + "`") }) } - } else if (args[1].toLowerCase() === "Mumble") { + } else if (args[1].toLowerCase() === "mumble") { if (!otherargs) { message.channel.send('You must provide a server name!') } else { From 96e55ad657f02f930ff2f179b951024c56e5f2e4 Mon Sep 17 00:00:00 2001 From: danielpmc Date: Sat, 24 Oct 2020 23:17:25 +0100 Subject: [PATCH 146/255] Added version to teamspeak. Latest broken? --- Panel/bot/discord/commands/server.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Panel/bot/discord/commands/server.js b/Panel/bot/discord/commands/server.js index 8fd47f4dc..e8d217956 100644 --- a/Panel/bot/discord/commands/server.js +++ b/Panel/bot/discord/commands/server.js @@ -725,7 +725,7 @@ exports.run = async (client, message, args) => { "cpu": 0 }, "environment": { - "TS_VERSION": "latest", + "TS_VERSION": "3.12.1", "FILE_TRANSFER": "30033" }, "feature_limits": { From 58a7069ab82a7a0853c068ea77edc61ca42690b4 Mon Sep 17 00:00:00 2001 From: danielpmc Date: Sun, 25 Oct 2020 12:43:06 +0000 Subject: [PATCH 147/255] Added warning to java servers. --- Panel/bot/discord/commands/server.js | 1 + 1 file changed, 1 insertion(+) diff --git a/Panel/bot/discord/commands/server.js b/Panel/bot/discord/commands/server.js index e8d217956..3197c7cf9 100644 --- a/Panel/bot/discord/commands/server.js +++ b/Panel/bot/discord/commands/server.js @@ -207,6 +207,7 @@ exports.run = async (client, message, args) => { .addField(`__**Created for user ID:**__`, data.user) .addField(`__**Server name:**__`, data.name) .addField(`__**Type:**__`, args[1].toLowerCase()) + .addField(`__**WARNING:**__`, "**Using a java server to run gameservers is __NOT__ allowed. You could have your server deleted for doing so.**") message.channel.send(embed) }).catch(error => { From 0346c23714f7beb0a897a9b1c4e6f8f94aa391f1 Mon Sep 17 00:00:00 2001 From: danielpmc Date: Sun, 25 Oct 2020 12:46:38 +0000 Subject: [PATCH 148/255] Added PocketmineMP as a option --- Panel/bot/discord/commands/server.js | 69 +++++++++++++++++++++++++++- 1 file changed, 67 insertions(+), 2 deletions(-) diff --git a/Panel/bot/discord/commands/server.js b/Panel/bot/discord/commands/server.js index 3197c7cf9..92ebf9c76 100644 --- a/Panel/bot/discord/commands/server.js +++ b/Panel/bot/discord/commands/server.js @@ -465,6 +465,71 @@ exports.run = async (client, message, args) => { "oom_disabled": false }; + //Sending the data: + axios({ + url: config.Pterodactyl.hosturl + "/api/application/servers", + method: 'POST', + followRedirect: true, + maxRedirects: 5, + headers: { + 'Authorization': 'Bearer ' + config.Pterodactyl.apikey, + 'Content-Type': 'application/json', + 'Accept': 'Application/vnd.pterodactyl.v1+json', + }, + data: data, + }).then(response => { + let embed = new Discord.RichEmbed() + .setColor(`GREEN`) + .addField(`__**Status:**__`, response.statusText) + .addField(`__**Created for user ID:**__`, data.user) + .addField(`__**Server name:**__`, data.name) + .addField(`__**Type:**__`, args[1].toLowerCase()) + message.channel.send(embed) + }).catch(error => { + + let embed1 = new Discord.RichEmbed() + .setColor(`RED`) + .addField(`__**FAILED:**__`, "Please contact a host admin. \n\nError: `" + error + "`") + message.channel.send(embed1) + message.channel.send("<@137624084572798976> Issue when creating server. \nResponse: `" + error + "`") + }) + } + } else if (args[1].toLowerCase() === "pocketminemp") { + if (!otherargs) { + message.channel.send('You must provide a server name!') + } else { + //Data to send + const data = { + "name": otherargs, + "user": userData.get(message.author.id + ".consoleID"), + "nest": 1, + "egg": 28, + "docker_image": "quay.io/parkervcp/pterodactyl-images:base_ubuntu", + "startup": "./bin/php7/bin/php ./PocketMine-MP.phar --no-wizard --disable-ansi", + "limits": { + "memory": 2048, + "swap": 0, + "disk": 0, + "io": 500, + "cpu": 0 + }, + "environment": { + "PMMP_VERSION": "latest" + }, + "feature_limits": { + "databases": 2, + "allocations": 1, + "backups": 10 + }, + "deploy": { + "locations": [5], + "dedicated_ip": false, + "port_range": [] + }, + "start_on_completion": false, + "oom_disabled": false + }; + //Sending the data: axios({ url: config.Pterodactyl.hosturl + "/api/application/servers", @@ -842,8 +907,8 @@ exports.run = async (client, message, args) => { //Anything else let embed2 = new Discord.RichEmbed() .setColor(`RED`) - .addField(`__**Minecraft:**__`, "Forge \nPaper \nBedrock", true) - .addField(`__**Grand Theft Auto:**__`, "FiveM", true) + .addField(`__**Minecraft:**__`, "Forge \nPaper \nBedrock \nPocketmineMP", true) + .addField(`__**Grand Theft Auto 5:**__`, "FiveM", true) .addField(`__**Bots:**__`, "NodeJS \nPython \nJava", true) .addField(`__**Source Engine:**__`, "GMod \nGS:GO \nARK:SE", true) .addField(`__**Voice Servers:**__`, "TS3 \nMumble", true) From 1593509d54d5ff01ec9b95cf0c3c0922d1597b14 Mon Sep 17 00:00:00 2001 From: danielpmc Date: Sun, 25 Oct 2020 13:08:24 +0000 Subject: [PATCH 149/255] Added rust server. --- Panel/bot/discord/commands/server.js | 81 +++++++++++++++++++++++++++- 1 file changed, 80 insertions(+), 1 deletion(-) diff --git a/Panel/bot/discord/commands/server.js b/Panel/bot/discord/commands/server.js index 92ebf9c76..ba2d8702a 100644 --- a/Panel/bot/discord/commands/server.js +++ b/Panel/bot/discord/commands/server.js @@ -903,7 +903,85 @@ exports.run = async (client, message, args) => { message.channel.send("<@137624084572798976> Issue when creating server. \nResponse: `" + error + "`") }) } - } else { + } else if (args[1].toLowerCase() === "rust") { + if (!otherargs) { + message.channel.send('You must provide a server name!') + } else { + //Data to send + const data = { + "name": otherargs, + "user": userData.get(message.author.id + ".consoleID"), + "nest": 4, + "egg": 14, + "docker_image": "quay.io/pterodactyl/core:rust", + "startup": `./RustDedicated -batchmode +server.port {{SERVER_PORT}} +server.identity "rust" +rcon.port {{RCON_PORT}} +rcon.web true +server.hostname \"{{HOSTNAME}}\" +server.level \"{{LEVEL}}\" +server.description \"{{DESCRIPTION}}\" +server.url \"{{SERVER_URL}}\" +server.headerimage \"{{SERVER_IMG}}\" +server.worldsize \"{{WORLD_SIZE}}\" +server.seed \"{{WORLD_SEED}}\" +server.maxplayers {{MAX_PLAYERS}} +rcon.password \"{{RCON_PASS}}\" +server.saveinterval {{SAVEINTERVAL}} {{ADDITIONAL_ARGS}}`, + "limits": { + "memory": 2048, + "swap": 0, + "disk": 0, + "io": 500, + "cpu": 0 + }, + "environment": { + "HOSTNAME": "A Rust Server", + "OXIDE": "0", + "LEVEL": "20", + "SERVER_MAP": "Procedural Map", + "DESCRIPTION": "Powered by DanBot Hosting - Free Hosting, Forever", + "SERVER_URL": "https://danbot.host", + "WORLD_SIZE": "3000", + "WORLD_SEED": null, + "MAX_PLAYERS": "40", + "SERVER_IMG": null, + "RCON_PORT": "28016", + "RCON_PASS": "DBHisthebest", + "SAVEINTERVAL": "60", + "ADDITIONAL_ARGS": null + }, + "feature_limits": { + "databases": 2, + "allocations": 1, + "backups": 10 + }, + "deploy": { + "locations": [5], + "dedicated_ip": false, + "port_range": [] + }, + "start_on_completion": false, + "oom_disabled": false + }; + + //Sending the data: + axios({ + url: config.Pterodactyl.hosturl + "/api/application/servers", + method: 'POST', + followRedirect: true, + maxRedirects: 5, + headers: { + 'Authorization': 'Bearer ' + config.Pterodactyl.apikey, + 'Content-Type': 'application/json', + 'Accept': 'Application/vnd.pterodactyl.v1+json', + }, + data: data, + }).then(response => { + let embed = new Discord.RichEmbed() + .setColor(`GREEN`) + .addField(`__**Status:**__`, response.statusText) + .addField(`__**Created for user ID:**__`, data.user) + .addField(`__**Server name:**__`, data.name) + .addField(`__**Type:**__`, args[1].toLowerCase()) + message.channel.send(embed) + }).catch(error => { + + let embed1 = new Discord.RichEmbed() + .setColor(`RED`) + .addField(`__**FAILED:**__`, "Please contact a host admin. \n\nError: `" + error + "`") + message.channel.send(embed1) + message.channel.send("<@137624084572798976> Issue when creating server. \nResponse: `" + error + "`") + }) + } + } else { //Anything else let embed2 = new Discord.RichEmbed() .setColor(`RED`) @@ -912,6 +990,7 @@ exports.run = async (client, message, args) => { .addField(`__**Bots:**__`, "NodeJS \nPython \nJava", true) .addField(`__**Source Engine:**__`, "GMod \nGS:GO \nARK:SE", true) .addField(`__**Voice Servers:**__`, "TS3 \nMumble", true) + .addField(`__**Misc Games:**__`, "Rust", true) message.channel.send(embed2) } } else if (args[0].toLowerCase() == "delete") { From 361be8978eecc38343cd842dfe07cdb133fdeec5 Mon Sep 17 00:00:00 2001 From: danielpmc Date: Sun, 25 Oct 2020 13:21:01 +0000 Subject: [PATCH 150/255] Added databases to createserver :confetti_ball: --- Panel/bot/discord/commands/server.js | 202 ++++++++++++++++++++++++++- 1 file changed, 201 insertions(+), 1 deletion(-) diff --git a/Panel/bot/discord/commands/server.js b/Panel/bot/discord/commands/server.js index ba2d8702a..70ae48dfb 100644 --- a/Panel/bot/discord/commands/server.js +++ b/Panel/bot/discord/commands/server.js @@ -981,7 +981,206 @@ exports.run = async (client, message, args) => { message.channel.send("<@137624084572798976> Issue when creating server. \nResponse: `" + error + "`") }) } - } else { + } else if (args[1].toLowerCase() === "mongodb") { + if (!otherargs) { + message.channel.send('You must provide a server name!') + } else { + //Data to send + const data = { + "name": otherargs, + "user": userData.get(message.author.id + ".consoleID"), + "nest": 12, + "egg": 35, + "docker_image": "quay.io/parkervcp/pterodactyl-images:db_mongo-4", + "startup": "mongod --fork --dbpath /home/container/mongodb/ --port ${SERVER_PORT} --logpath /home/container/logs/mongo.log; until nc -z -v -w5 127.0.0.1 ${SERVER_PORT}; do echo 'Waiting for mongodb connection...'; sleep 5; done && mongo 127.0.0.1:${SERVER_PORT} && mongo --eval 'db.getSiblingDB('admin').shutdownServer()' 127.0.0.1:${SERVER_PORT}", + "limits": { + "memory": 0, + "swap": 0, + "disk": 0, + "io": 500, + "cpu": 0 + }, + "environment": { + "MONGO_USER": "admin", + "MONGO_USER_PASS": "aP@55word" + }, + "feature_limits": { + "databases": 2, + "allocations": 1, + "backups": 10 + }, + "deploy": { + "locations": [3], + "dedicated_ip": false, + "port_range": [] + }, + "start_on_completion": false, + "oom_disabled": false + }; + + //Sending the data: + axios({ + url: config.Pterodactyl.hosturl + "/api/application/servers", + method: 'POST', + followRedirect: true, + maxRedirects: 5, + headers: { + 'Authorization': 'Bearer ' + config.Pterodactyl.apikey, + 'Content-Type': 'application/json', + 'Accept': 'Application/vnd.pterodactyl.v1+json', + }, + data: data, + }).then(response => { + let embed = new Discord.RichEmbed() + .setColor(`GREEN`) + .addField(`__**Status:**__`, response.statusText) + .addField(`__**Created for user ID:**__`, data.user) + .addField(`__**Server name:**__`, data.name) + .addField(`__**Type:**__`, args[1].toLowerCase()) + message.channel.send(embed) + }).catch(error => { + + let embed1 = new Discord.RichEmbed() + .setColor(`RED`) + .addField(`__**FAILED:**__`, "Please contact a host admin. \n\nError: `" + error + "`") + message.channel.send(embed1) + message.channel.send("<@137624084572798976> Issue when creating server. \nResponse: `" + error + "`") + }) + } + } else if (args[1].toLowerCase() === "redis") { + if (!otherargs) { + message.channel.send('You must provide a server name!') + } else { + //Data to send + const data = { + "name": otherargs, + "user": userData.get(message.author.id + ".consoleID"), + "nest": 12, + "egg": 36, + "docker_image": "quay.io/parkervcp/pterodactyl-images:db_redis-6", + "startup": "/usr/local/bin/redis-server /home/container/redis.conf --save 60 1 --dir /home/container/ --bind 0.0.0.0 --port {{SERVER_PORT}} --requirepass {{SERVER_PASSWORD}} --maxmemory {{SERVER_MEMORY}}mb --daemonize yes && redis-cli -p {{SERVER_PORT}} -a {{SERVER_PASSWORD}}; redis-cli -p {{SERVER_PORT}} -a {{SERVER_PASSWORD}} shutdown save", + "limits": { + "memory": 0, + "swap": 0, + "disk": 0, + "io": 500, + "cpu": 0 + }, + "environment": { + "SERVER_PASSWORD": "P@55w0rd" + }, + "feature_limits": { + "databases": 2, + "allocations": 1, + "backups": 10 + }, + "deploy": { + "locations": [3], + "dedicated_ip": false, + "port_range": [] + }, + "start_on_completion": false, + "oom_disabled": false + }; + + //Sending the data: + axios({ + url: config.Pterodactyl.hosturl + "/api/application/servers", + method: 'POST', + followRedirect: true, + maxRedirects: 5, + headers: { + 'Authorization': 'Bearer ' + config.Pterodactyl.apikey, + 'Content-Type': 'application/json', + 'Accept': 'Application/vnd.pterodactyl.v1+json', + }, + data: data, + }).then(response => { + let embed = new Discord.RichEmbed() + .setColor(`GREEN`) + .addField(`__**Status:**__`, response.statusText) + .addField(`__**Created for user ID:**__`, data.user) + .addField(`__**Server name:**__`, data.name) + .addField(`__**Type:**__`, args[1].toLowerCase()) + message.channel.send(embed) + }).catch(error => { + + let embed1 = new Discord.RichEmbed() + .setColor(`RED`) + .addField(`__**FAILED:**__`, "Please contact a host admin. \n\nError: `" + error + "`") + message.channel.send(embed1) + message.channel.send("<@137624084572798976> Issue when creating server. \nResponse: `" + error + "`") + }) + } + } else if (args[1].toLowerCase() === "postgres") { + if (!otherargs) { + message.channel.send('You must provide a server name!') + } else { + //Data to send + const data = { + "name": otherargs, + "user": userData.get(message.author.id + ".consoleID"), + "nest": 12, + "egg": 37, + "docker_image": "quay.io/parkervcp/pterodactyl-images:db_postgres", + "startup": `postgres -D /home/container/postgres_db/`, + "limits": { + "memory": 0, + "swap": 0, + "disk": 0, + "io": 500, + "cpu": 0 + }, + "environment": { + "PGPASSWORD": "P@55word", + "PGROOT": "ZPWgpMN4hETqjXAV", + "PGUSER": "pterodactyl", + "PGDATABASE": "pterodactyl" + }, + "feature_limits": { + "databases": 2, + "allocations": 1, + "backups": 10 + }, + "deploy": { + "locations": [3], + "dedicated_ip": false, + "port_range": [] + }, + "start_on_completion": false, + "oom_disabled": false + }; + + //Sending the data: + axios({ + url: config.Pterodactyl.hosturl + "/api/application/servers", + method: 'POST', + followRedirect: true, + maxRedirects: 5, + headers: { + 'Authorization': 'Bearer ' + config.Pterodactyl.apikey, + 'Content-Type': 'application/json', + 'Accept': 'Application/vnd.pterodactyl.v1+json', + }, + data: data, + }).then(response => { + let embed = new Discord.RichEmbed() + .setColor(`GREEN`) + .addField(`__**Status:**__`, response.statusText) + .addField(`__**Created for user ID:**__`, data.user) + .addField(`__**Server name:**__`, data.name) + .addField(`__**Type:**__`, args[1].toLowerCase()) + message.channel.send(embed) + }).catch(error => { + + let embed1 = new Discord.RichEmbed() + .setColor(`RED`) + .addField(`__**FAILED:**__`, "Please contact a host admin. \n\nError: `" + error + "`") + message.channel.send(embed1) + message.channel.send("<@137624084572798976> Issue when creating server. \nResponse: `" + error + "`") + }) + } + } else { //Anything else let embed2 = new Discord.RichEmbed() .setColor(`RED`) @@ -991,6 +1190,7 @@ exports.run = async (client, message, args) => { .addField(`__**Source Engine:**__`, "GMod \nGS:GO \nARK:SE", true) .addField(`__**Voice Servers:**__`, "TS3 \nMumble", true) .addField(`__**Misc Games:**__`, "Rust", true) + .addField(`__**Databases:**__`, "MongoDB \nRedis \nPostgres", true) message.channel.send(embed2) } } else if (args[0].toLowerCase() == "delete") { From 23b332b4d4ed95f3dc5e1ae4d6f005f05c88bde1 Mon Sep 17 00:00:00 2001 From: danielpmc Date: Sun, 25 Oct 2020 13:41:29 +0000 Subject: [PATCH 151/255] Uh F --- Panel/bot/discord/commands/server.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Panel/bot/discord/commands/server.js b/Panel/bot/discord/commands/server.js index 70ae48dfb..8f0e0c8d1 100644 --- a/Panel/bot/discord/commands/server.js +++ b/Panel/bot/discord/commands/server.js @@ -630,7 +630,7 @@ exports.run = async (client, message, args) => { message.channel.send("<@137624084572798976> Issue when creating server. \nResponse: `" + error + "`") }) } - } else if (args[1].toLowerCase() === "gs:go") { + } else if (args[1].toLowerCase() === "cs:go") { if (!otherargs) { message.channel.send('You must provide a server name!') } else { @@ -1187,7 +1187,7 @@ exports.run = async (client, message, args) => { .addField(`__**Minecraft:**__`, "Forge \nPaper \nBedrock \nPocketmineMP", true) .addField(`__**Grand Theft Auto 5:**__`, "FiveM", true) .addField(`__**Bots:**__`, "NodeJS \nPython \nJava", true) - .addField(`__**Source Engine:**__`, "GMod \nGS:GO \nARK:SE", true) + .addField(`__**Source Engine:**__`, "GMod \nCS:GO \nARK:SE", true) .addField(`__**Voice Servers:**__`, "TS3 \nMumble", true) .addField(`__**Misc Games:**__`, "Rust", true) .addField(`__**Databases:**__`, "MongoDB \nRedis \nPostgres", true) From 66bc75243e4eaae756c1fcea265032719362476d Mon Sep 17 00:00:00 2001 From: danielpmc Date: Sun, 25 Oct 2020 13:43:58 +0000 Subject: [PATCH 152/255] Test --- Panel/bot/discord/commands/server.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Panel/bot/discord/commands/server.js b/Panel/bot/discord/commands/server.js index 8f0e0c8d1..51667cec5 100644 --- a/Panel/bot/discord/commands/server.js +++ b/Panel/bot/discord/commands/server.js @@ -652,7 +652,7 @@ exports.run = async (client, message, args) => { "environment": { "SRCDS_MAP": "de_dust2", "STEAM_ACC": ".", - "SRCDS_APPID": "740" + "SRCDS_APPID": "BD1868C7DFC242D39EBE2062B10C6A3A" }, "feature_limits": { "databases": 2, From 44438828a460afa747bd11a0a95c2276aa22e186 Mon Sep 17 00:00:00 2001 From: danielpmc Date: Sun, 25 Oct 2020 13:45:10 +0000 Subject: [PATCH 153/255] uh --- Panel/bot/discord/commands/server.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Panel/bot/discord/commands/server.js b/Panel/bot/discord/commands/server.js index 51667cec5..c6413e581 100644 --- a/Panel/bot/discord/commands/server.js +++ b/Panel/bot/discord/commands/server.js @@ -651,8 +651,8 @@ exports.run = async (client, message, args) => { }, "environment": { "SRCDS_MAP": "de_dust2", - "STEAM_ACC": ".", - "SRCDS_APPID": "BD1868C7DFC242D39EBE2062B10C6A3A" + "STEAM_ACC": "BD1868C7DFC242D39EBE2062B10C6A3A", + "SRCDS_APPID": "740" }, "feature_limits": { "databases": 2, From 0922f27aa2726920394ec888f885c1e7db37c08a Mon Sep 17 00:00:00 2001 From: danielpmc Date: Sun, 25 Oct 2020 15:32:33 +0000 Subject: [PATCH 154/255] Add full server UUID --- Panel/bot/discord/commands/server.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Panel/bot/discord/commands/server.js b/Panel/bot/discord/commands/server.js index c6413e581..9bb5c834f 100644 --- a/Panel/bot/discord/commands/server.js +++ b/Panel/bot/discord/commands/server.js @@ -1189,7 +1189,7 @@ exports.run = async (client, message, args) => { .addField(`__**Bots:**__`, "NodeJS \nPython \nJava", true) .addField(`__**Source Engine:**__`, "GMod \nCS:GO \nARK:SE", true) .addField(`__**Voice Servers:**__`, "TS3 \nMumble", true) - .addField(`__**Misc Games:**__`, "Rust", true) + .addField(`__**SteamCMD:**__`, "Rust", true) .addField(`__**Databases:**__`, "MongoDB \nRedis \nPostgres", true) message.channel.send(embed2) } @@ -1326,6 +1326,7 @@ exports.run = async (client, message, args) => { .addField('**DISK Usage**', pretty(resources.data.attributes.resources.disk_bytes) + ' out of UNLIMITED MB') .addField('**NET Usage**', 'UPLOADED: ' + pretty(resources.data.attributes.resources.network_tx_bytes) + ', DOWNLOADED: ' + pretty(resources.data.attributes.resources.network_rx_bytes)) .addField('**NODE**', response.data.attributes.node) + .addField('**FULL ID**', response.data.attributes.uuid) .addField('\u200b', '\u200b') .addField('**LIMITS (0 = unlimited)**', 'MEMORY: ' + response.data.attributes.limits.memory + 'MB \nDISK: ' + response.data.attributes.limits.disk + 'MB \nCPU: ' + response.data.attributes.limits.cpu) .addField('**MISC LIMITS**', 'DATABASES: ' + response.data.attributes.feature_limits.databases + '\nBACKUPS: ' + response.data.attributes.feature_limits.backups) From 30ab15758cc7b585910ec423d05dc76c535394d1 Mon Sep 17 00:00:00 2001 From: danielpmc Date: Sun, 25 Oct 2020 17:41:14 +0000 Subject: [PATCH 155/255] Fix mute --- Panel/bot/discord/commands/mute.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Panel/bot/discord/commands/mute.js b/Panel/bot/discord/commands/mute.js index cf1cbfd51..112fad974 100644 --- a/Panel/bot/discord/commands/mute.js +++ b/Panel/bot/discord/commands/mute.js @@ -46,7 +46,7 @@ exports.run = async (client, message, args) => { setTimeout(() => { message.guild.member(user).removeRole(muteRole) console.log(chalk.magenta('[DISCORD] ') + chalk.cyan(user.user.username + ' has now been unmuted after ' + messagez +' minute(s)')) - mutesData.delete(user); + mutesData.delete(user.user.id); setTimeout(() => { message.guild.member(user).removeRole(muteRole) }, 2000) @@ -54,9 +54,9 @@ exports.run = async (client, message, args) => { } else { client.channels.get(modlog.id).send({embed}) setTimeout(() => { - message.guild.member(user).removeRole(muteRole) + message.guild.member(user.user.id).removeRole(muteRole) console.log(chalk.magenta('[DISCORD] ') + chalk.cyan(user.user.username + ' has now been unmuted after ' + messagez +' minute(s)')) - mutesData.delete(user); + mutesData.delete(user.user.id); setTimeout(() => { message.guild.member(user).removeRole(muteRole) }, 2000) From 3411f8cbc02e5bdff337cc6cdfd7ddc149b030f0 Mon Sep 17 00:00:00 2001 From: danielpmc Date: Sun, 25 Oct 2020 23:54:54 +0000 Subject: [PATCH 156/255] sending stats from nodes broke again --- Panel/index.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Panel/index.js b/Panel/index.js index 9fa183786..72193854f 100644 --- a/Panel/index.js +++ b/Panel/index.js @@ -142,7 +142,7 @@ global.nodeData = new db.table("nodeData") app.get('/data', function (req, res) { let nodes = ["154.27.68.232", "154.27.68.233", "167.86.113.158", "51.38.69.73"]; if (req.query.servername == undefined) { - if (!nodes.includes(req.headers["x-forwarded-for"])) { + if (!nodes.includes(req.headers["x-forwarded-for" || "cf-connecting-ip"])) { res.redirect("/") } else { nodeData.set(req.query.speedname + '-speedtest', { @@ -154,7 +154,7 @@ app.get('/data', function (req, res) { }); }; } else { - if (!nodes.includes(req.headers["x-forwarded-for"])) { + if (!nodes.includes(req.headers["x-forwarded-for" || "cf-connecting-ip"])) { res.redirect("/") } else { nodeData.set(req.query.servername, { From 0cec717f23bfb10955a3f999109e8604ccc4a78d Mon Sep 17 00:00:00 2001 From: danielpmc Date: Tue, 27 Oct 2020 12:32:14 +0000 Subject: [PATCH 157/255] Add kick member message so they know why they cant join - Account age --- .gitignore | 4 +++- Panel/bot/discord/events/guildMemberAdd.js | 1 + 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index b889b3f85..da5099636 100644 --- a/.gitignore +++ b/.gitignore @@ -12,4 +12,6 @@ Panel/eng.traineddata Daemon/node_modules Daemon/package-lock.json -Test/* \ No newline at end of file +Test/* + +OutageBot/* \ No newline at end of file diff --git a/Panel/bot/discord/events/guildMemberAdd.js b/Panel/bot/discord/events/guildMemberAdd.js index f8835e6c5..c14e25ce9 100644 --- a/Panel/bot/discord/events/guildMemberAdd.js +++ b/Panel/bot/discord/events/guildMemberAdd.js @@ -64,6 +64,7 @@ module.exports = async(client, member, guild) => { if (Date.now() - member.user.createdAt < 863136000) { member.kick().then(memberkicked => { client.channels.get('738527858594414663').send(member.user.tag + ` has been auto-kicked as account is under 10days old \nThat account was created ${getAge(Date.now() - member.user.createdAt)}, ago`) + client.users.get(member.user.id).send('Sorry! We only allow accounts over the age of 10days to join. \nYou\'r account is ' + getAge(Date.now() - member.user.createdAt) + ", ago. \n\nYou are welcome to join again once this account is over 10days old!") }); } From c62077961c24d38e320757a84933c26fc8bcb536 Mon Sep 17 00:00:00 2001 From: danielpmc Date: Tue, 27 Oct 2020 13:40:11 +0000 Subject: [PATCH 158/255] temp message lmao --- Panel/bot/discord/events/message.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Panel/bot/discord/events/message.js b/Panel/bot/discord/events/message.js index d303d2760..328ac977b 100644 --- a/Panel/bot/discord/events/message.js +++ b/Panel/bot/discord/events/message.js @@ -45,6 +45,8 @@ module.exports = (client, message) => { message.reply('Looks like the server cant find a `index.js` file. Please check make sure you uploaded your main file and changed startup prams to make sure the server is starting with the correct file. \nIf that doesnt help please wait for a human to come help you.') } else if (text.includes('Please try re-compiling or re-installing')) { message.channel.send('Looks like you might of uploaded your `node_modules` folder. Please delete this folder and when you server starts modules will be auto installed.') + } else if (text.includes('owo' || 'uwu')) { + message.reply('UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO') } }) }) From 19bf2a0364b94573b91ee5ea9d659549b743d1f3 Mon Sep 17 00:00:00 2001 From: danielpmc Date: Tue, 27 Oct 2020 13:42:10 +0000 Subject: [PATCH 159/255] f --- Panel/bot/discord/events/message.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Panel/bot/discord/events/message.js b/Panel/bot/discord/events/message.js index 328ac977b..35c532914 100644 --- a/Panel/bot/discord/events/message.js +++ b/Panel/bot/discord/events/message.js @@ -45,7 +45,7 @@ module.exports = (client, message) => { message.reply('Looks like the server cant find a `index.js` file. Please check make sure you uploaded your main file and changed startup prams to make sure the server is starting with the correct file. \nIf that doesnt help please wait for a human to come help you.') } else if (text.includes('Please try re-compiling or re-installing')) { message.channel.send('Looks like you might of uploaded your `node_modules` folder. Please delete this folder and when you server starts modules will be auto installed.') - } else if (text.includes('owo' || 'uwu')) { + } else if (text.toLowerCase().includes('owo' || 'uwu')) { message.reply('UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO') } }) From fbd5b132a288d5c8cc7a5a1fee5b8a5340a8b214 Mon Sep 17 00:00:00 2001 From: danielpmc Date: Tue, 27 Oct 2020 14:18:31 +0000 Subject: [PATCH 160/255] Add automatic git pull updator every 60seconds --- Panel/bot/discord/commands/server.js | 2 +- Panel/bot/discord/events/ready.js | 17 +++++++++++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/Panel/bot/discord/commands/server.js b/Panel/bot/discord/commands/server.js index 9bb5c834f..eca5808fa 100644 --- a/Panel/bot/discord/commands/server.js +++ b/Panel/bot/discord/commands/server.js @@ -1334,7 +1334,7 @@ exports.run = async (client, message, args) => { })}); } } else if (args[0].toLowerCase() == "proxy") { - let domainfilter = [".com", ".co.uk"]; + let domainfilter = [".com", ".co.uk", ".us", ".xyz", ".org"]; const embed = new Discord.RichEmbed() .setTitle('__**How to link a domain to a website/server**__ \nCommand format: `' + config.DiscordBot.Prefix + 'server proxy domainhere serverid') diff --git a/Panel/bot/discord/events/ready.js b/Panel/bot/discord/events/ready.js index c30b33fc4..8b5b5683e 100644 --- a/Panel/bot/discord/events/ready.js +++ b/Panel/bot/discord/events/ready.js @@ -22,6 +22,23 @@ module.exports = async (client, guild, files) => { "type": "WATCHING" } ]; + + setInterval(() => { + exec(`git pull`, (error, stdout) => { + let response = (error || stdout); + if (!error) { + if (response.includes("Already up to date.")) { + console.log('Bot already up to date. No changes since last pull') + } else { + message.channel.send('**[AUTOMATIC]** \nNew update on GitHub. Pulling. \n\nLogs: \n```' + response + "```" + "\n\n\n**Restarting bot**") + setTimeout(() => { + process.exit(); + }, 1000) + }; + } + }) + }, 60000) + setInterval(() => { const activity = activities[Math.floor(Math.random() * activities.length)]; client.user.setActivity(activity.text, { From 73129c93a76b4f14460d356d9d45f3e0c016c4c9 Mon Sep 17 00:00:00 2001 From: danielpmc Date: Tue, 27 Oct 2020 14:19:53 +0000 Subject: [PATCH 161/255] Update git pull 60second interval --- Panel/bot/discord/events/ready.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Panel/bot/discord/events/ready.js b/Panel/bot/discord/events/ready.js index 8b5b5683e..74f5e3bfb 100644 --- a/Panel/bot/discord/events/ready.js +++ b/Panel/bot/discord/events/ready.js @@ -30,7 +30,7 @@ module.exports = async (client, guild, files) => { if (response.includes("Already up to date.")) { console.log('Bot already up to date. No changes since last pull') } else { - message.channel.send('**[AUTOMATIC]** \nNew update on GitHub. Pulling. \n\nLogs: \n```' + response + "```" + "\n\n\n**Restarting bot**") + client.channels.get('766068015686483989').send('**[AUTOMATIC]** \nNew update on GitHub. Pulling. \n\nLogs: \n```' + response + "```" + "\n\n\n**Restarting bot**") setTimeout(() => { process.exit(); }, 1000) From d061bd10bc9479767fd130a96da2530abd58e3df Mon Sep 17 00:00:00 2001 From: danielpmc Date: Tue, 27 Oct 2020 14:20:29 +0000 Subject: [PATCH 162/255] Add comment --- Panel/bot/discord/events/ready.js | 1 + 1 file changed, 1 insertion(+) diff --git a/Panel/bot/discord/events/ready.js b/Panel/bot/discord/events/ready.js index 74f5e3bfb..a6a7a4ec8 100644 --- a/Panel/bot/discord/events/ready.js +++ b/Panel/bot/discord/events/ready.js @@ -23,6 +23,7 @@ module.exports = async (client, guild, files) => { } ]; + //Automatic 60second git pull. setInterval(() => { exec(`git pull`, (error, stdout) => { let response = (error || stdout); From 15e77f6704ebcb572d838f49221e482e1728f274 Mon Sep 17 00:00:00 2001 From: danielpmc Date: Tue, 27 Oct 2020 14:21:27 +0000 Subject: [PATCH 163/255] Uh forgot to define something --- Panel/bot/discord/events/ready.js | 1 + 1 file changed, 1 insertion(+) diff --git a/Panel/bot/discord/events/ready.js b/Panel/bot/discord/events/ready.js index a6a7a4ec8..0bd5742cc 100644 --- a/Panel/bot/discord/events/ready.js +++ b/Panel/bot/discord/events/ready.js @@ -1,4 +1,5 @@ //let client = require("../../../../index.js").client; +const exec = require('child_process').exec; const axios = require('axios'); module.exports = async (client, guild, files) => { console.log(chalk.magenta('[DISCORD] ') + chalk.green(client.user.username + " has logged in!")); From b28b9ffe3516b6c0b44fe3d148669cd1bdc49f03 Mon Sep 17 00:00:00 2001 From: danielpmc Date: Tue, 27 Oct 2020 14:25:48 +0000 Subject: [PATCH 164/255] Update ready.js --- Panel/bot/discord/events/ready.js | 1 - 1 file changed, 1 deletion(-) diff --git a/Panel/bot/discord/events/ready.js b/Panel/bot/discord/events/ready.js index 0bd5742cc..e85d20ba4 100644 --- a/Panel/bot/discord/events/ready.js +++ b/Panel/bot/discord/events/ready.js @@ -1,4 +1,3 @@ -//let client = require("../../../../index.js").client; const exec = require('child_process').exec; const axios = require('axios'); module.exports = async (client, guild, files) => { From ae0540fc39da32036b367627fd6e724a75b5da5c Mon Sep 17 00:00:00 2001 From: danielpmc Date: Tue, 27 Oct 2020 16:26:58 +0000 Subject: [PATCH 165/255] Remove testing messages --- Panel/bot/discord/events/message.js | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/Panel/bot/discord/events/message.js b/Panel/bot/discord/events/message.js index 35c532914..53d71ae2b 100644 --- a/Panel/bot/discord/events/message.js +++ b/Panel/bot/discord/events/message.js @@ -22,11 +22,7 @@ module.exports = (client, message) => { Tesseract.recognize( attachment.url, 'eng', - ).then(({ - data: { - text - } - }) => { + ).then(({ data: { text } }) => { if (text.includes("There was an error attempting to establish")) { message.reply('It looks like you are getting a error with the websocket. Try refreshing if that doesnt work please check <#738530520945786921>') } else if (text.includes("HTTP/E_CONN_REFUSED")) { @@ -45,8 +41,6 @@ module.exports = (client, message) => { message.reply('Looks like the server cant find a `index.js` file. Please check make sure you uploaded your main file and changed startup prams to make sure the server is starting with the correct file. \nIf that doesnt help please wait for a human to come help you.') } else if (text.includes('Please try re-compiling or re-installing')) { message.channel.send('Looks like you might of uploaded your `node_modules` folder. Please delete this folder and when you server starts modules will be auto installed.') - } else if (text.toLowerCase().includes('owo' || 'uwu')) { - message.reply('UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO UwU OwO') } }) }) From 8a90d6eea624ad1e5608b26e3495edeaef0391e7 Mon Sep 17 00:00:00 2001 From: danielpmc Date: Tue, 27 Oct 2020 16:49:27 +0000 Subject: [PATCH 166/255] Add a example to DBH!server create list so people know how to use the command! --- Panel/bot/discord/commands/server.js | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/Panel/bot/discord/commands/server.js b/Panel/bot/discord/commands/server.js index eca5808fa..eb6b1a97b 100644 --- a/Panel/bot/discord/commands/server.js +++ b/Panel/bot/discord/commands/server.js @@ -1191,6 +1191,7 @@ exports.run = async (client, message, args) => { .addField(`__**Voice Servers:**__`, "TS3 \nMumble", true) .addField(`__**SteamCMD:**__`, "Rust", true) .addField(`__**Databases:**__`, "MongoDB \nRedis \nPostgres", true) + .setFooter("Example: " + config.DiscordBot.Prefix + "server create NodeJS Testing Server") message.channel.send(embed2) } } else if (args[0].toLowerCase() == "delete") { @@ -1338,10 +1339,15 @@ exports.run = async (client, message, args) => { const embed = new Discord.RichEmbed() .setTitle('__**How to link a domain to a website/server**__ \nCommand format: `' + config.DiscordBot.Prefix + 'server proxy domainhere serverid') - if (!args[1]) { + if (!args[1] || !args[1].includes(domainfilter)) { message.channel.send(embed) - } + } else { + if (!args[2]) { + message.channel.send(embed) + } else { + } + } } }; }; \ No newline at end of file From 3a222621a7735c9d09e223708df25793e6d212c1 Mon Sep 17 00:00:00 2001 From: danielpmc Date: Tue, 27 Oct 2020 18:10:02 +0000 Subject: [PATCH 167/255] FInished proxy ( reverse proxy ) --- Panel/bot/discord/commands/server.js | 79 ++++++++++++++++++++++++++++ Panel/proxy/template.txt | 23 ++++++++ 2 files changed, 102 insertions(+) create mode 100644 Panel/proxy/template.txt diff --git a/Panel/bot/discord/commands/server.js b/Panel/bot/discord/commands/server.js index eb6b1a97b..2d65032ef 100644 --- a/Panel/bot/discord/commands/server.js +++ b/Panel/bot/discord/commands/server.js @@ -1,5 +1,10 @@ const axios = require('axios'); var pretty = require('prettysize'); +const fs = require('fs'); +const path = require('path'); +const {NodeSSH} = require('node-ssh'); +const { config } = require('process'); +const rif = require('replace-in-file'); exports.run = async (client, message, args) => { const otherargs = message.content.split(' ').slice(3).join(' '); if (userData.get(message.author.id) == null) { @@ -1335,6 +1340,7 @@ exports.run = async (client, message, args) => { })}); } } else if (args[0].toLowerCase() == "proxy") { + if (message.author.id == "137624084572798976") { let domainfilter = [".com", ".co.uk", ".us", ".xyz", ".org"]; const embed = new Discord.RichEmbed() @@ -1345,9 +1351,82 @@ exports.run = async (client, message, args) => { if (!args[2]) { message.channel.send(embed) } else { + //SSH Connection + ssh.connect({ + host: config.SSH.Host, + username: config.SSH.User, + port: config.SSH.Port, + password: config.SSH.Password, + tryKeyboard: true, + }) + + //Copy template file. Ready to be changed! + fs.copySync(path.resolve('/root/DBH/Panel/proxy/template.txt'), '/root/DBH/Panel/proxy/' + args[1] + '.conf'); + + setTimeout(() => { + //Change Domain + const domainchange = replace.sync({ + files: '/root/DBH/Panel/proxy/' + args[1] + '.conf', + from: "REPLACE-DOMAIN", + to: args[1], + countMatches: true, + }); + + //Change Server IP + setTimeout(() => { + const ipchange = replace.sync({ + files: '/root/DBH/Panel/proxy/' + args[1] + '.conf', + from: "REPLACE-IP", + to: args[1], + countMatches: true, + }); + + //Change Server Port + setTimeout(() => { + const portchange = replace.sync({ + files: '/root/DBH/Panel/proxy/' + args[1] + '.conf', + from: "REPLACE-PORT", + to: args[1], + countMatches: true, + }); + + //Upload file to /etc/apache2/sites-available + setTimeout(() => { + ssh.putFile('/root/DBH/Panel/proxy/' + args[1] + '.txt', '/etc/apache2/sites-available/' + args[1] + ".conf").then(function() { + + //Run command to genate SSL cert. + ssh.execCommand(`certbot certonly -d ${args[1]} --non-interactive --agree-tos -m danielpd93@gmail.com`, { cwd:'/root' }).then(function(result) { + if (result.stderr) { + //If an error exists. Eror and delete the proxy file + message.channel.send('Error making SSL cert. Either the domain is not pointing to `154.27.68.234` or cloudflare proxy is enabled!') + fs.unlinkSync("/root/DBH/Panel/proxy/" + args[1] + ".txt"); + } else { + //No error. Continue to enable site on apache2 then restart + console.log('SSL Gen complete. Continue!') + ssh.execCommand(`a2ensite ${args[1]} && service apache2 restart`, { cwd:'/root' }).then(function(result) { + if (result.stderr) { + //If an error exists. Eror and delete the proxy file + message.channel.send('ERROR: Cancelled. Please contact Dan') + } else { + //Complete + console.log('Enabled website.') + } + }) + } + }) + }, function(error) { + //If error exists. Error and delete proxy file + fs.unlinkSync("/root/DBH/Panel/proxy/" + args[1] + ".txt"); + message.channel.send("FAILED \nERROR: " + error); + }) + }, 250) //END - Upload file to /etc/apache2/sites-available + }, 100) //END - Change Server Port + }, 100) //END - Change Server IP + }, 250) //END - //Change Domain } } + } } }; }; \ No newline at end of file diff --git a/Panel/proxy/template.txt b/Panel/proxy/template.txt new file mode 100644 index 000000000..2733aa583 --- /dev/null +++ b/Panel/proxy/template.txt @@ -0,0 +1,23 @@ + + ServerName REPLACE-DOMAIN + RewriteEngine On + RewriteCond %{HTTPS} !=on + RewriteRule ^/?(.*) https://%{SERVER_NAME}/$1 [R,L] + + + ServerName REPLACE-DOMAIN + ProxyRequests off + SSLProxyEngine on + ProxyPreserveHost On + SSLEngine on + SSLCertificateFile /etc/letsencrypt/live/REPLACE-DOMAIN/fullchain.pem + SSLCertificateKeyFile /etc/letsencrypt/live/REPLACE-DOMAIN/privkey.pem + + + ProxyPass http://REPLACE-IP:REPLACE-PORT/ + ProxyPassReverse http://REPLACE-IP:REPLACE-PORT/ + + + + + From c622d1c9b753b46404a5e468ff6121c02f326cb1 Mon Sep 17 00:00:00 2001 From: danielpmc Date: Tue, 27 Oct 2020 18:12:52 +0000 Subject: [PATCH 168/255] uh remove a line --- Panel/bot/discord/commands/server.js | 1 - 1 file changed, 1 deletion(-) diff --git a/Panel/bot/discord/commands/server.js b/Panel/bot/discord/commands/server.js index 2d65032ef..ee3e944f6 100644 --- a/Panel/bot/discord/commands/server.js +++ b/Panel/bot/discord/commands/server.js @@ -3,7 +3,6 @@ var pretty = require('prettysize'); const fs = require('fs'); const path = require('path'); const {NodeSSH} = require('node-ssh'); -const { config } = require('process'); const rif = require('replace-in-file'); exports.run = async (client, message, args) => { const otherargs = message.content.split(' ').slice(3).join(' '); From 532a1c1eb60e2129c952732a341f9581a6ec25ec Mon Sep 17 00:00:00 2001 From: danielpmc Date: Tue, 27 Oct 2020 18:20:22 +0000 Subject: [PATCH 169/255] Update server.js --- Panel/bot/discord/commands/server.js | 1 + 1 file changed, 1 insertion(+) diff --git a/Panel/bot/discord/commands/server.js b/Panel/bot/discord/commands/server.js index ee3e944f6..1e138b48c 100644 --- a/Panel/bot/discord/commands/server.js +++ b/Panel/bot/discord/commands/server.js @@ -1344,6 +1344,7 @@ exports.run = async (client, message, args) => { const embed = new Discord.RichEmbed() .setTitle('__**How to link a domain to a website/server**__ \nCommand format: `' + config.DiscordBot.Prefix + 'server proxy domainhere serverid') + .setFooter('If you just tried to link a domain. That TLD is not supported yet!') if (!args[1] || !args[1].includes(domainfilter)) { message.channel.send(embed) } else { From 3aaa13c931e22a75a2b6617ef669e0bff38d16db Mon Sep 17 00:00:00 2001 From: danielpmc Date: Tue, 27 Oct 2020 18:21:26 +0000 Subject: [PATCH 170/255] Support .host domains --- Panel/bot/discord/commands/server.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Panel/bot/discord/commands/server.js b/Panel/bot/discord/commands/server.js index 1e138b48c..58ed00967 100644 --- a/Panel/bot/discord/commands/server.js +++ b/Panel/bot/discord/commands/server.js @@ -1340,7 +1340,7 @@ exports.run = async (client, message, args) => { } } else if (args[0].toLowerCase() == "proxy") { if (message.author.id == "137624084572798976") { - let domainfilter = [".com", ".co.uk", ".us", ".xyz", ".org"]; + let domainfilter = [".com", ".co.uk", ".us", ".xyz", ".org", ".host"]; const embed = new Discord.RichEmbed() .setTitle('__**How to link a domain to a website/server**__ \nCommand format: `' + config.DiscordBot.Prefix + 'server proxy domainhere serverid') From bf7deb114bfae10fb14e6e3cfa3a7e865e8f990c Mon Sep 17 00:00:00 2001 From: danielpmc Date: Tue, 27 Oct 2020 18:26:17 +0000 Subject: [PATCH 171/255] Update server.js --- Panel/bot/discord/commands/server.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Panel/bot/discord/commands/server.js b/Panel/bot/discord/commands/server.js index 58ed00967..10c718d69 100644 --- a/Panel/bot/discord/commands/server.js +++ b/Panel/bot/discord/commands/server.js @@ -1347,9 +1347,11 @@ exports.run = async (client, message, args) => { .setFooter('If you just tried to link a domain. That TLD is not supported yet!') if (!args[1] || !args[1].includes(domainfilter)) { message.channel.send(embed) + console.log('uh args 1') } else { if (!args[2]) { message.channel.send(embed) + console.log('uh args 2') } else { //SSH Connection ssh.connect({ From 68ebedb3fec83552a967f52aa767d799c6c97367 Mon Sep 17 00:00:00 2001 From: danielpmc Date: Tue, 27 Oct 2020 18:59:55 +0000 Subject: [PATCH 172/255] Update server.js --- Panel/bot/discord/commands/server.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Panel/bot/discord/commands/server.js b/Panel/bot/discord/commands/server.js index 10c718d69..f33709b71 100644 --- a/Panel/bot/discord/commands/server.js +++ b/Panel/bot/discord/commands/server.js @@ -1345,7 +1345,10 @@ exports.run = async (client, message, args) => { const embed = new Discord.RichEmbed() .setTitle('__**How to link a domain to a website/server**__ \nCommand format: `' + config.DiscordBot.Prefix + 'server proxy domainhere serverid') .setFooter('If you just tried to link a domain. That TLD is not supported yet!') - if (!args[1] || !args[1].includes(domainfilter)) { + if (!args[1]) { + message.channel.send(embed) + } else + if (!args[1].includes(domainfilter)) { message.channel.send(embed) console.log('uh args 1') } else { From 3e6cd3f13f8086071cbe0c172b76541e524b9cb9 Mon Sep 17 00:00:00 2001 From: danielpmc Date: Tue, 27 Oct 2020 19:01:43 +0000 Subject: [PATCH 173/255] Update server.js --- Panel/bot/discord/commands/server.js | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/Panel/bot/discord/commands/server.js b/Panel/bot/discord/commands/server.js index f33709b71..ee64dcee2 100644 --- a/Panel/bot/discord/commands/server.js +++ b/Panel/bot/discord/commands/server.js @@ -1348,10 +1348,7 @@ exports.run = async (client, message, args) => { if (!args[1]) { message.channel.send(embed) } else - if (!args[1].includes(domainfilter)) { - message.channel.send(embed) - console.log('uh args 1') - } else { + if (args[1].includes(domainfilter)) { if (!args[2]) { message.channel.send(embed) console.log('uh args 2') From d219a4169ff0c1489ae1f496b3a59bf26992c26a Mon Sep 17 00:00:00 2001 From: danielpmc Date: Tue, 27 Oct 2020 19:06:09 +0000 Subject: [PATCH 174/255] Update server.js --- Panel/bot/discord/commands/server.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Panel/bot/discord/commands/server.js b/Panel/bot/discord/commands/server.js index ee64dcee2..45b5e4011 100644 --- a/Panel/bot/discord/commands/server.js +++ b/Panel/bot/discord/commands/server.js @@ -1363,7 +1363,7 @@ exports.run = async (client, message, args) => { }) //Copy template file. Ready to be changed! - fs.copySync(path.resolve('/root/DBH/Panel/proxy/template.txt'), '/root/DBH/Panel/proxy/' + args[1] + '.conf'); + fs.copySync(path.resolve('/root/DBH/Panel/proxy/template.txt'), args[1] + '.conf'); setTimeout(() => { //Change Domain From 22a75c2b793f3e825cd4dd98c008ab898a2a5450 Mon Sep 17 00:00:00 2001 From: danielpmc Date: Tue, 27 Oct 2020 19:08:25 +0000 Subject: [PATCH 175/255] Update server.js --- Panel/bot/discord/commands/server.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Panel/bot/discord/commands/server.js b/Panel/bot/discord/commands/server.js index 45b5e4011..928a2089e 100644 --- a/Panel/bot/discord/commands/server.js +++ b/Panel/bot/discord/commands/server.js @@ -1353,6 +1353,7 @@ exports.run = async (client, message, args) => { message.channel.send(embed) console.log('uh args 2') } else { + console.log('test') //SSH Connection ssh.connect({ host: config.SSH.Host, @@ -1363,7 +1364,7 @@ exports.run = async (client, message, args) => { }) //Copy template file. Ready to be changed! - fs.copySync(path.resolve('/root/DBH/Panel/proxy/template.txt'), args[1] + '.conf'); + fs.copySync(path.resolve('/root/DBH/Panel/proxy/template.txt'), '/root/DBH/Panel/proxy/' + args[1] + '.conf'); setTimeout(() => { //Change Domain From 8a9c769ab8afa58eee09348a82901340047ed406 Mon Sep 17 00:00:00 2001 From: danielpmc Date: Tue, 27 Oct 2020 19:21:34 +0000 Subject: [PATCH 176/255] update --- Panel/bot/discord/commands/server.js | 20 ++++++++++++-------- Panel/package.json | 2 ++ 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/Panel/bot/discord/commands/server.js b/Panel/bot/discord/commands/server.js index 928a2089e..ef548df8c 100644 --- a/Panel/bot/discord/commands/server.js +++ b/Panel/bot/discord/commands/server.js @@ -2,7 +2,8 @@ const axios = require('axios'); var pretty = require('prettysize'); const fs = require('fs'); const path = require('path'); -const {NodeSSH} = require('node-ssh'); +const {NodeSSH} = require('node-ssh') +const ssh = new NodeSSH() const rif = require('replace-in-file'); exports.run = async (client, message, args) => { const otherargs = message.content.split(' ').slice(3).join(' '); @@ -1345,15 +1346,14 @@ exports.run = async (client, message, args) => { const embed = new Discord.RichEmbed() .setTitle('__**How to link a domain to a website/server**__ \nCommand format: `' + config.DiscordBot.Prefix + 'server proxy domainhere serverid') .setFooter('If you just tried to link a domain. That TLD is not supported yet!') + console.log(args[0] + " args 1 " + args[1]) if (!args[1]) { message.channel.send(embed) - } else - if (args[1].includes(domainfilter)) { + } else { if (!args[2]) { message.channel.send(embed) console.log('uh args 2') } else { - console.log('test') //SSH Connection ssh.connect({ host: config.SSH.Host, @@ -1364,11 +1364,15 @@ exports.run = async (client, message, args) => { }) //Copy template file. Ready to be changed! - fs.copySync(path.resolve('/root/DBH/Panel/proxy/template.txt'), '/root/DBH/Panel/proxy/' + args[1] + '.conf'); + fs.copyFile(path.resolve('/root/DBH/Panel/proxy/template.txt'), '/root/DBH/Panel/proxy/' + args[1] + '.conf', (err) => { + if (err) { + console.log("Error Found:", err); + } + }) setTimeout(() => { //Change Domain - const domainchange = replace.sync({ + const domainchange = rif.sync({ files: '/root/DBH/Panel/proxy/' + args[1] + '.conf', from: "REPLACE-DOMAIN", to: args[1], @@ -1377,7 +1381,7 @@ exports.run = async (client, message, args) => { //Change Server IP setTimeout(() => { - const ipchange = replace.sync({ + const ipchange = rif.sync({ files: '/root/DBH/Panel/proxy/' + args[1] + '.conf', from: "REPLACE-IP", to: args[1], @@ -1386,7 +1390,7 @@ exports.run = async (client, message, args) => { //Change Server Port setTimeout(() => { - const portchange = replace.sync({ + const portchange = rif.sync({ files: '/root/DBH/Panel/proxy/' + args[1] + '.conf', from: "REPLACE-PORT", to: args[1], diff --git a/Panel/package.json b/Panel/package.json index 492d6df67..47d4cc149 100644 --- a/Panel/package.json +++ b/Panel/package.json @@ -37,6 +37,7 @@ "node-cron": "^2.0.3", "node-fetch": "^2.6.0", "node-proxmox": "^0.1.2", + "node-ssh": "^11.1.1", "node-tesseract-ocr": "^2.0.0", "nodeactyl": "^2.0.0", "nodeactyl-beta": "0.0.10", @@ -48,6 +49,7 @@ "pterodactyl.js": "^2.1.1", "puppeteer": "^1.20.0", "quick.db": "^7.1.1", + "replace-in-file": "^6.1.0", "resolve": "^1.17.0", "socket.io": "latest", "tesseract.js": "^2.1.1", From 226ef8bf2014946a80ff471db408d0e22f8ef4a0 Mon Sep 17 00:00:00 2001 From: danielpmc Date: Tue, 27 Oct 2020 19:28:59 +0000 Subject: [PATCH 177/255] Update server.js --- Panel/bot/discord/commands/server.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Panel/bot/discord/commands/server.js b/Panel/bot/discord/commands/server.js index ef548df8c..4aaf5e3a7 100644 --- a/Panel/bot/discord/commands/server.js +++ b/Panel/bot/discord/commands/server.js @@ -1364,7 +1364,7 @@ exports.run = async (client, message, args) => { }) //Copy template file. Ready to be changed! - fs.copyFile(path.resolve('/root/DBH/Panel/proxy/template.txt'), '/root/DBH/Panel/proxy/' + args[1] + '.conf', (err) => { + fs.copyFile(path.resolve('./proxy/template.txt'), './proxy/' + args[1] + '.conf', (err) => { if (err) { console.log("Error Found:", err); } @@ -1399,14 +1399,14 @@ exports.run = async (client, message, args) => { //Upload file to /etc/apache2/sites-available setTimeout(() => { - ssh.putFile('/root/DBH/Panel/proxy/' + args[1] + '.txt', '/etc/apache2/sites-available/' + args[1] + ".conf").then(function() { + ssh.putFile('/root/DBH/Panel/proxy/' + args[1] + '.conf', '/etc/apache2/sites-available/' + args[1] + ".conf").then(function() { //Run command to genate SSL cert. ssh.execCommand(`certbot certonly -d ${args[1]} --non-interactive --agree-tos -m danielpd93@gmail.com`, { cwd:'/root' }).then(function(result) { if (result.stderr) { //If an error exists. Eror and delete the proxy file message.channel.send('Error making SSL cert. Either the domain is not pointing to `154.27.68.234` or cloudflare proxy is enabled!') - fs.unlinkSync("/root/DBH/Panel/proxy/" + args[1] + ".txt"); + fs.unlinkSync("./proxy/" + args[1] + ".conf"); } else { //No error. Continue to enable site on apache2 then restart console.log('SSL Gen complete. Continue!') @@ -1424,7 +1424,7 @@ exports.run = async (client, message, args) => { }) }, function(error) { //If error exists. Error and delete proxy file - fs.unlinkSync("/root/DBH/Panel/proxy/" + args[1] + ".txt"); + fs.unlinkSync("./proxy/" + args[1] + ".conf"); message.channel.send("FAILED \nERROR: " + error); }) }, 250) //END - Upload file to /etc/apache2/sites-available From ab8ea0bfe769852eb75cb4dbaaa37d8e40543ba4 Mon Sep 17 00:00:00 2001 From: danielpmc Date: Tue, 27 Oct 2020 19:35:28 +0000 Subject: [PATCH 178/255] Ignore these commits lmao. errors --- Panel/bot/discord/commands/server.js | 1 + 1 file changed, 1 insertion(+) diff --git a/Panel/bot/discord/commands/server.js b/Panel/bot/discord/commands/server.js index 4aaf5e3a7..726001c24 100644 --- a/Panel/bot/discord/commands/server.js +++ b/Panel/bot/discord/commands/server.js @@ -1404,6 +1404,7 @@ exports.run = async (client, message, args) => { //Run command to genate SSL cert. ssh.execCommand(`certbot certonly -d ${args[1]} --non-interactive --agree-tos -m danielpd93@gmail.com`, { cwd:'/root' }).then(function(result) { if (result.stderr) { + console.log(result) //If an error exists. Eror and delete the proxy file message.channel.send('Error making SSL cert. Either the domain is not pointing to `154.27.68.234` or cloudflare proxy is enabled!') fs.unlinkSync("./proxy/" + args[1] + ".conf"); From a28c530c27c8cbbe21a66498464bcda5479d137d Mon Sep 17 00:00:00 2001 From: danielpmc Date: Tue, 27 Oct 2020 19:38:31 +0000 Subject: [PATCH 179/255] hopefully last update to this! --- Panel/bot/discord/commands/server.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Panel/bot/discord/commands/server.js b/Panel/bot/discord/commands/server.js index 726001c24..ea06cffad 100644 --- a/Panel/bot/discord/commands/server.js +++ b/Panel/bot/discord/commands/server.js @@ -1402,7 +1402,7 @@ exports.run = async (client, message, args) => { ssh.putFile('/root/DBH/Panel/proxy/' + args[1] + '.conf', '/etc/apache2/sites-available/' + args[1] + ".conf").then(function() { //Run command to genate SSL cert. - ssh.execCommand(`certbot certonly -d ${args[1]} --non-interactive --agree-tos -m danielpd93@gmail.com`, { cwd:'/root' }).then(function(result) { + ssh.execCommand(`service apache2 stop && certbot certonly -d ${args[1]} --standalone --non-interactive --agree-tos -m danielpd93@gmail.com`, { cwd:'/root' }).then(function(result) { if (result.stderr) { console.log(result) //If an error exists. Eror and delete the proxy file From 113bbb62643c84709c1c9f344978f93c605efc3b Mon Sep 17 00:00:00 2001 From: danielpmc Date: Tue, 27 Oct 2020 19:40:35 +0000 Subject: [PATCH 180/255] Update server.js --- Panel/bot/discord/commands/server.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/Panel/bot/discord/commands/server.js b/Panel/bot/discord/commands/server.js index ea06cffad..816011f49 100644 --- a/Panel/bot/discord/commands/server.js +++ b/Panel/bot/discord/commands/server.js @@ -1346,13 +1346,11 @@ exports.run = async (client, message, args) => { const embed = new Discord.RichEmbed() .setTitle('__**How to link a domain to a website/server**__ \nCommand format: `' + config.DiscordBot.Prefix + 'server proxy domainhere serverid') .setFooter('If you just tried to link a domain. That TLD is not supported yet!') - console.log(args[0] + " args 1 " + args[1]) if (!args[1]) { message.channel.send(embed) } else { if (!args[2]) { message.channel.send(embed) - console.log('uh args 2') } else { //SSH Connection ssh.connect({ @@ -1408,7 +1406,7 @@ exports.run = async (client, message, args) => { //If an error exists. Eror and delete the proxy file message.channel.send('Error making SSL cert. Either the domain is not pointing to `154.27.68.234` or cloudflare proxy is enabled!') fs.unlinkSync("./proxy/" + args[1] + ".conf"); - } else { + } else if (result.stderr.includes('Congratulations!')) { //No error. Continue to enable site on apache2 then restart console.log('SSL Gen complete. Continue!') From 1ee2e6e436e7fd71d64f627d0515ebb5f87cbd58 Mon Sep 17 00:00:00 2001 From: danielpmc Date: Tue, 27 Oct 2020 19:46:23 +0000 Subject: [PATCH 181/255] Update server.js --- Panel/bot/discord/commands/server.js | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/Panel/bot/discord/commands/server.js b/Panel/bot/discord/commands/server.js index 816011f49..ade901791 100644 --- a/Panel/bot/discord/commands/server.js +++ b/Panel/bot/discord/commands/server.js @@ -1352,6 +1352,7 @@ exports.run = async (client, message, args) => { if (!args[2]) { message.channel.send(embed) } else { + message.channel.send('Please give me a few seconds. Trying to link you\'r domain!') //SSH Connection ssh.connect({ host: config.SSH.Host, @@ -1401,12 +1402,7 @@ exports.run = async (client, message, args) => { //Run command to genate SSL cert. ssh.execCommand(`service apache2 stop && certbot certonly -d ${args[1]} --standalone --non-interactive --agree-tos -m danielpd93@gmail.com`, { cwd:'/root' }).then(function(result) { - if (result.stderr) { - console.log(result) - //If an error exists. Eror and delete the proxy file - message.channel.send('Error making SSL cert. Either the domain is not pointing to `154.27.68.234` or cloudflare proxy is enabled!') - fs.unlinkSync("./proxy/" + args[1] + ".conf"); - } else if (result.stderr.includes('Congratulations!')) { + if (result.stdout.includes('Congratulations!')) { //No error. Continue to enable site on apache2 then restart console.log('SSL Gen complete. Continue!') @@ -1419,6 +1415,9 @@ exports.run = async (client, message, args) => { console.log('Enabled website.') } }) + } else { + message.channel.send('Error making SSL cert. Either the domain is not pointing to `154.27.68.234` or cloudflare proxy is enabled!') + fs.unlinkSync("./proxy/" + args[1] + ".conf"); } }) }, function(error) { From 07d77cb4bbf13256bca9c14bd284b9b6f6585b25 Mon Sep 17 00:00:00 2001 From: danielpmc Date: Tue, 27 Oct 2020 19:50:02 +0000 Subject: [PATCH 182/255] Hopefully the last fucking update to this. --- Panel/bot/discord/commands/server.js | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/Panel/bot/discord/commands/server.js b/Panel/bot/discord/commands/server.js index ade901791..6eb20dedd 100644 --- a/Panel/bot/discord/commands/server.js +++ b/Panel/bot/discord/commands/server.js @@ -1352,7 +1352,7 @@ exports.run = async (client, message, args) => { if (!args[2]) { message.channel.send(embed) } else { - message.channel.send('Please give me a few seconds. Trying to link you\'r domain!') + message.channel.send('Please give me a few seconds. Trying to link that domain!') //SSH Connection ssh.connect({ host: config.SSH.Host, @@ -1407,13 +1407,8 @@ exports.run = async (client, message, args) => { console.log('SSL Gen complete. Continue!') ssh.execCommand(`a2ensite ${args[1]} && service apache2 restart`, { cwd:'/root' }).then(function(result) { - if (result.stderr) { - //If an error exists. Eror and delete the proxy file - message.channel.send('ERROR: Cancelled. Please contact Dan') - } else { //Complete - console.log('Enabled website.') - } + message.reply('Domain has now been linked!') }) } else { message.channel.send('Error making SSL cert. Either the domain is not pointing to `154.27.68.234` or cloudflare proxy is enabled!') From 4a98c34345b0288645dac0f53ff435570527b9f5 Mon Sep 17 00:00:00 2001 From: danielpmc Date: Tue, 27 Oct 2020 19:57:14 +0000 Subject: [PATCH 183/255] Update server.js --- Panel/bot/discord/commands/server.js | 119 +++++++++++++++------------ 1 file changed, 65 insertions(+), 54 deletions(-) diff --git a/Panel/bot/discord/commands/server.js b/Panel/bot/discord/commands/server.js index 6eb20dedd..c53319173 100644 --- a/Panel/bot/discord/commands/server.js +++ b/Panel/bot/discord/commands/server.js @@ -1363,67 +1363,78 @@ exports.run = async (client, message, args) => { }) //Copy template file. Ready to be changed! - fs.copyFile(path.resolve('./proxy/template.txt'), './proxy/' + args[1] + '.conf', (err) => { - if (err) { - console.log("Error Found:", err); - } - }) - - setTimeout(() => { - //Change Domain - const domainchange = rif.sync({ - files: '/root/DBH/Panel/proxy/' + args[1] + '.conf', - from: "REPLACE-DOMAIN", - to: args[1], - countMatches: true, - }); - - //Change Server IP - setTimeout(() => { - const ipchange = rif.sync({ - files: '/root/DBH/Panel/proxy/' + args[1] + '.conf', - from: "REPLACE-IP", - to: args[1], - countMatches: true, - }); - - //Change Server Port + fs.access(path.resolve(path.dirname(require.main.filename), "proxy/" + args[1] + ".conf"), fs.constants.R_OK, (err) => { + if (!err) { + return message.channel.send("This domain has been linked before or is currently linked..") + } else { + fs.copyFile(path.resolve('./proxy/template.txt'), './proxy/' + args[1] + '.conf', (err) => { + if (err) { + console.log("Error Found:", err); + } + }) + fs.copyFile(path.resolve('./proxy/template.txt'), './proxy/' + args[1] + '.conf', (err) => { + if (err) { + console.log("Error Found:", err); + } + }) + setTimeout(() => { - const portchange = rif.sync({ + //Change Domain + const domainchange = rif.sync({ files: '/root/DBH/Panel/proxy/' + args[1] + '.conf', - from: "REPLACE-PORT", + from: "REPLACE-DOMAIN", to: args[1], countMatches: true, }); - - //Upload file to /etc/apache2/sites-available + + //Change Server IP setTimeout(() => { - ssh.putFile('/root/DBH/Panel/proxy/' + args[1] + '.conf', '/etc/apache2/sites-available/' + args[1] + ".conf").then(function() { - - //Run command to genate SSL cert. - ssh.execCommand(`service apache2 stop && certbot certonly -d ${args[1]} --standalone --non-interactive --agree-tos -m danielpd93@gmail.com`, { cwd:'/root' }).then(function(result) { - if (result.stdout.includes('Congratulations!')) { - //No error. Continue to enable site on apache2 then restart - console.log('SSL Gen complete. Continue!') - - ssh.execCommand(`a2ensite ${args[1]} && service apache2 restart`, { cwd:'/root' }).then(function(result) { - //Complete - message.reply('Domain has now been linked!') + const ipchange = rif.sync({ + files: '/root/DBH/Panel/proxy/' + args[1] + '.conf', + from: "REPLACE-IP", + to: args[1], + countMatches: true, + }); + + //Change Server Port + setTimeout(() => { + const portchange = rif.sync({ + files: '/root/DBH/Panel/proxy/' + args[1] + '.conf', + from: "REPLACE-PORT", + to: args[1], + countMatches: true, + }); + + //Upload file to /etc/apache2/sites-available + setTimeout(() => { + ssh.putFile('/root/DBH/Panel/proxy/' + args[1] + '.conf', '/etc/apache2/sites-available/' + args[1] + ".conf").then(function() { + + //Run command to genate SSL cert. + ssh.execCommand(`service apache2 stop && certbot certonly -d ${args[1]} --standalone --non-interactive --agree-tos -m danielpd93@gmail.com`, { cwd:'/root' }).then(function(result) { + if (result.stdout.includes('Congratulations!')) { + //No error. Continue to enable site on apache2 then restart + console.log('SSL Gen complete. Continue!') + + ssh.execCommand(`a2ensite ${args[1]} && service apache2 restart`, { cwd:'/root' }).then(function(result) { + //Complete + message.reply('Domain has now been linked!') + }) + } else { + message.channel.send('Error making SSL cert. Either the domain is not pointing to `154.27.68.234` or cloudflare proxy is enabled!') + fs.unlinkSync("./proxy/" + args[1] + ".conf"); + } }) - } else { - message.channel.send('Error making SSL cert. Either the domain is not pointing to `154.27.68.234` or cloudflare proxy is enabled!') - fs.unlinkSync("./proxy/" + args[1] + ".conf"); - } - }) - }, function(error) { - //If error exists. Error and delete proxy file - fs.unlinkSync("./proxy/" + args[1] + ".conf"); - message.channel.send("FAILED \nERROR: " + error); - }) - }, 250) //END - Upload file to /etc/apache2/sites-available - }, 100) //END - Change Server Port - }, 100) //END - Change Server IP - }, 250) //END - //Change Domain + }, function(error) { + //If error exists. Error and delete proxy file + fs.unlinkSync("./proxy/" + args[1] + ".conf"); + message.channel.send("FAILED \nERROR: " + error); + }) + }, 250) //END - Upload file to /etc/apache2/sites-available + }, 100) //END - Change Server Port + }, 100) //END - Change Server IP + }, 250) //END - //Change Domain + } + }) } } } From 986a3501259c0689f2506dbe428a59c8ab54921e Mon Sep 17 00:00:00 2001 From: danielpmc Date: Tue, 27 Oct 2020 20:55:52 +0000 Subject: [PATCH 184/255] Fixed a few missing changes. Another commit to follow --- Panel/bot/discord/commands/server.js | 42 ++++++++++++++++++---------- 1 file changed, 27 insertions(+), 15 deletions(-) diff --git a/Panel/bot/discord/commands/server.js b/Panel/bot/discord/commands/server.js index c53319173..f2cbfaa7a 100644 --- a/Panel/bot/discord/commands/server.js +++ b/Panel/bot/discord/commands/server.js @@ -1380,30 +1380,42 @@ exports.run = async (client, message, args) => { setTimeout(() => { //Change Domain - const domainchange = rif.sync({ - files: '/root/DBH/Panel/proxy/' + args[1] + '.conf', - from: "REPLACE-DOMAIN", - to: args[1], - countMatches: true, - }); - - //Change Server IP - setTimeout(() => { - const ipchange = rif.sync({ + var z = 0; + while (z <5) { + const domainchange = rif.sync({ files: '/root/DBH/Panel/proxy/' + args[1] + '.conf', - from: "REPLACE-IP", + from: "REPLACE-DOMAIN", to: args[1], countMatches: true, }); + z++ + } - //Change Server Port - setTimeout(() => { - const portchange = rif.sync({ + //Change Server IP + setTimeout(() => { + var y = 0; + while (y <3) { + const ipchange = rif.sync({ files: '/root/DBH/Panel/proxy/' + args[1] + '.conf', - from: "REPLACE-PORT", + from: "REPLACE-IP", to: args[1], countMatches: true, }); + y++ + }; + + //Change Server Port + setTimeout(() => { + var x = 0; + while (x <3) { + const portchange = rif.sync({ + files: '/root/DBH/Panel/proxy/' + args[1] + '.conf', + from: "REPLACE-PORT", + to: args[1], + countMatches: true, + }); + x++ + } //Upload file to /etc/apache2/sites-available setTimeout(() => { From 171a08c649e816e9904a29e8ccf03b485bc228cc Mon Sep 17 00:00:00 2001 From: danielpmc Date: Tue, 27 Oct 2020 21:42:50 +0000 Subject: [PATCH 185/255] :) Hopefully last thing to make this thing fully work --- Panel/bot/discord/commands/server.js | 59 ++++++++++++++++++++++++++-- 1 file changed, 55 insertions(+), 4 deletions(-) diff --git a/Panel/bot/discord/commands/server.js b/Panel/bot/discord/commands/server.js index f2cbfaa7a..f5cebbc29 100644 --- a/Panel/bot/discord/commands/server.js +++ b/Panel/bot/discord/commands/server.js @@ -1390,7 +1390,52 @@ exports.run = async (client, message, args) => { }); z++ } + + //Grab node and port ready for the config + axios({ + url: config.Pterodactyl.hosturl + "/api/client/servers/" + args[1], + method: 'GET', + followRedirect: true, + maxRedirects: 5, + headers: { + 'Authorization': 'Bearer ' + config.Pterodactyl.apikeyclient, + 'Content-Type': 'application/json', + 'Accept': 'Application/vnd.pterodactyl.v1+json', + } + }).then(response => { + const node = response.attributes.node; + const port = response.relationships.allocations.data.attributes.port + if (node == "Node 1 - Discord Bots") { + + //Change Server IP + setTimeout(() => { + var y = 0; + while (y <3) { + const ipchange = rif.sync({ + files: '/root/DBH/Panel/proxy/' + args[1] + '.conf', + from: "REPLACE-IP", + to: "154.27.68.232", + countMatches: true, + }); + y++ + }; + //Change Server Port + setTimeout(() => { + var x = 0; + while (x <3) { + const portchange = rif.sync({ + files: '/root/DBH/Panel/proxy/' + args[1] + '.conf', + from: "REPLACE-PORT", + to: port, + countMatches: true, + }); + x++ + } + }, 100) //END - Change Server Port + }, 100) //END - Change Server IP + } else if (node == "Node 2 - Discord Bots") { + //Change Server IP setTimeout(() => { var y = 0; @@ -1398,7 +1443,7 @@ exports.run = async (client, message, args) => { const ipchange = rif.sync({ files: '/root/DBH/Panel/proxy/' + args[1] + '.conf', from: "REPLACE-IP", - to: args[1], + to: "154.27.68.233", countMatches: true, }); y++ @@ -1411,11 +1456,18 @@ exports.run = async (client, message, args) => { const portchange = rif.sync({ files: '/root/DBH/Panel/proxy/' + args[1] + '.conf', from: "REPLACE-PORT", - to: args[1], + to: port, countMatches: true, }); x++ } + }, 100) //END - Change Server Port + }, 100) //END - Change Server IP + } else { + message.channel.send('Unsupported node. Stopping reverse proxy.') + fs.unlinkSync("./proxy/" + args[1] + ".conf"); + } + //Upload file to /etc/apache2/sites-available setTimeout(() => { @@ -1442,8 +1494,7 @@ exports.run = async (client, message, args) => { message.channel.send("FAILED \nERROR: " + error); }) }, 250) //END - Upload file to /etc/apache2/sites-available - }, 100) //END - Change Server Port - }, 100) //END - Change Server IP + }) //END - Grab server info (Node and Port) }, 250) //END - //Change Domain } }) From ae2696f7e3a2801d12390dd22010c800a3d3a2de Mon Sep 17 00:00:00 2001 From: danielpmc Date: Tue, 27 Oct 2020 21:46:44 +0000 Subject: [PATCH 186/255] uh oh. forgot to change args --- Panel/bot/discord/commands/server.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Panel/bot/discord/commands/server.js b/Panel/bot/discord/commands/server.js index f5cebbc29..75ee560cd 100644 --- a/Panel/bot/discord/commands/server.js +++ b/Panel/bot/discord/commands/server.js @@ -1393,7 +1393,7 @@ exports.run = async (client, message, args) => { //Grab node and port ready for the config axios({ - url: config.Pterodactyl.hosturl + "/api/client/servers/" + args[1], + url: config.Pterodactyl.hosturl + "/api/client/servers/" + args[2], method: 'GET', followRedirect: true, maxRedirects: 5, From 861f4e35a3849c9c3be3acf9b7a57cc0bda5e061 Mon Sep 17 00:00:00 2001 From: danielpmc Date: Tue, 27 Oct 2020 22:02:05 +0000 Subject: [PATCH 187/255] Update server.js --- Panel/bot/discord/commands/server.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Panel/bot/discord/commands/server.js b/Panel/bot/discord/commands/server.js index 75ee560cd..fab21c36c 100644 --- a/Panel/bot/discord/commands/server.js +++ b/Panel/bot/discord/commands/server.js @@ -1403,8 +1403,8 @@ exports.run = async (client, message, args) => { 'Accept': 'Application/vnd.pterodactyl.v1+json', } }).then(response => { - const node = response.attributes.node; - const port = response.relationships.allocations.data.attributes.port + const node = response.data.attributes.node; + const port = response.data.relationships.allocations.data.attributes.port if (node == "Node 1 - Discord Bots") { //Change Server IP From 4294f87b1674d1c7bc2423290bfea2ecc3164b0a Mon Sep 17 00:00:00 2001 From: danielpmc Date: Tue, 27 Oct 2020 22:03:15 +0000 Subject: [PATCH 188/255] Update server.js --- Panel/bot/discord/commands/server.js | 1 + 1 file changed, 1 insertion(+) diff --git a/Panel/bot/discord/commands/server.js b/Panel/bot/discord/commands/server.js index fab21c36c..1bb32ad9c 100644 --- a/Panel/bot/discord/commands/server.js +++ b/Panel/bot/discord/commands/server.js @@ -1404,6 +1404,7 @@ exports.run = async (client, message, args) => { } }).then(response => { const node = response.data.attributes.node; + console.log(response.data.attributes) const port = response.data.relationships.allocations.data.attributes.port if (node == "Node 1 - Discord Bots") { From 7fe170455e66b90d8b0ea80b6b8799db9eaba0f8 Mon Sep 17 00:00:00 2001 From: danielpmc Date: Tue, 27 Oct 2020 22:25:21 +0000 Subject: [PATCH 189/255] Last update. Time to make it public --- Panel/bot/discord/commands/server.js | 8 ++++---- Panel/proxy/ss.danbot.host.conf | 23 +++++++++++++++++++++++ 2 files changed, 27 insertions(+), 4 deletions(-) create mode 100644 Panel/proxy/ss.danbot.host.conf diff --git a/Panel/bot/discord/commands/server.js b/Panel/bot/discord/commands/server.js index 1bb32ad9c..c1770e759 100644 --- a/Panel/bot/discord/commands/server.js +++ b/Panel/bot/discord/commands/server.js @@ -1404,9 +1404,9 @@ exports.run = async (client, message, args) => { } }).then(response => { const node = response.data.attributes.node; - console.log(response.data.attributes) - const port = response.data.relationships.allocations.data.attributes.port - if (node == "Node 1 - Discord Bots") { + console.log(node) + const port = response.data.attributes.relationships.allocations.data[0].attributes.port + if (node === "Node 1 - Discord Bots") { //Change Server IP setTimeout(() => { @@ -1435,7 +1435,7 @@ exports.run = async (client, message, args) => { } }, 100) //END - Change Server Port }, 100) //END - Change Server IP - } else if (node == "Node 2 - Discord Bots") { + } else if (node === "Node 2 - Discord Bots") { //Change Server IP setTimeout(() => { diff --git a/Panel/proxy/ss.danbot.host.conf b/Panel/proxy/ss.danbot.host.conf new file mode 100644 index 000000000..2733aa583 --- /dev/null +++ b/Panel/proxy/ss.danbot.host.conf @@ -0,0 +1,23 @@ + + ServerName REPLACE-DOMAIN + RewriteEngine On + RewriteCond %{HTTPS} !=on + RewriteRule ^/?(.*) https://%{SERVER_NAME}/$1 [R,L] + + + ServerName REPLACE-DOMAIN + ProxyRequests off + SSLProxyEngine on + ProxyPreserveHost On + SSLEngine on + SSLCertificateFile /etc/letsencrypt/live/REPLACE-DOMAIN/fullchain.pem + SSLCertificateKeyFile /etc/letsencrypt/live/REPLACE-DOMAIN/privkey.pem + + + ProxyPass http://REPLACE-IP:REPLACE-PORT/ + ProxyPassReverse http://REPLACE-IP:REPLACE-PORT/ + + + + + From 9a0ff4766aec69e52960d651d2fe29e6808bd59e Mon Sep 17 00:00:00 2001 From: danielpmc Date: Tue, 27 Oct 2020 22:25:42 +0000 Subject: [PATCH 190/255] Command now public --- Panel/bot/discord/commands/server.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/Panel/bot/discord/commands/server.js b/Panel/bot/discord/commands/server.js index c1770e759..f04d1154d 100644 --- a/Panel/bot/discord/commands/server.js +++ b/Panel/bot/discord/commands/server.js @@ -1340,7 +1340,6 @@ exports.run = async (client, message, args) => { })}); } } else if (args[0].toLowerCase() == "proxy") { - if (message.author.id == "137624084572798976") { let domainfilter = [".com", ".co.uk", ".us", ".xyz", ".org", ".host"]; const embed = new Discord.RichEmbed() @@ -1502,6 +1501,5 @@ exports.run = async (client, message, args) => { } } } - } }; }; \ No newline at end of file From d498127dc3159ea5566d629924b6769c7b375899 Mon Sep 17 00:00:00 2001 From: danielpmc Date: Tue, 27 Oct 2020 22:28:14 +0000 Subject: [PATCH 191/255] Update .gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index da5099636..96231e386 100644 --- a/.gitignore +++ b/.gitignore @@ -8,6 +8,7 @@ Panel/json.sqlite Panel/images Panel/start.bat Panel/eng.traineddata +Panel/proxy Daemon/node_modules Daemon/package-lock.json From bb90f067ddd1a04744c5a81a42468e9bb10d3bcf Mon Sep 17 00:00:00 2001 From: danielpmc Date: Tue, 27 Oct 2020 22:29:45 +0000 Subject: [PATCH 192/255] Delete ss.danbot.host.conf --- Panel/proxy/ss.danbot.host.conf | 23 ----------------------- 1 file changed, 23 deletions(-) delete mode 100644 Panel/proxy/ss.danbot.host.conf diff --git a/Panel/proxy/ss.danbot.host.conf b/Panel/proxy/ss.danbot.host.conf deleted file mode 100644 index 2733aa583..000000000 --- a/Panel/proxy/ss.danbot.host.conf +++ /dev/null @@ -1,23 +0,0 @@ - - ServerName REPLACE-DOMAIN - RewriteEngine On - RewriteCond %{HTTPS} !=on - RewriteRule ^/?(.*) https://%{SERVER_NAME}/$1 [R,L] - - - ServerName REPLACE-DOMAIN - ProxyRequests off - SSLProxyEngine on - ProxyPreserveHost On - SSLEngine on - SSLCertificateFile /etc/letsencrypt/live/REPLACE-DOMAIN/fullchain.pem - SSLCertificateKeyFile /etc/letsencrypt/live/REPLACE-DOMAIN/privkey.pem - - - ProxyPass http://REPLACE-IP:REPLACE-PORT/ - ProxyPassReverse http://REPLACE-IP:REPLACE-PORT/ - - - - - From b3a4730e5d5f7c0d70dd23dc89602980d2894144 Mon Sep 17 00:00:00 2001 From: danielpmc Date: Tue, 27 Oct 2020 22:32:35 +0000 Subject: [PATCH 193/255] Delete template.txt --- Panel/proxy/template.txt | 23 ----------------------- 1 file changed, 23 deletions(-) delete mode 100644 Panel/proxy/template.txt diff --git a/Panel/proxy/template.txt b/Panel/proxy/template.txt deleted file mode 100644 index 2733aa583..000000000 --- a/Panel/proxy/template.txt +++ /dev/null @@ -1,23 +0,0 @@ - - ServerName REPLACE-DOMAIN - RewriteEngine On - RewriteCond %{HTTPS} !=on - RewriteRule ^/?(.*) https://%{SERVER_NAME}/$1 [R,L] - - - ServerName REPLACE-DOMAIN - ProxyRequests off - SSLProxyEngine on - ProxyPreserveHost On - SSLEngine on - SSLCertificateFile /etc/letsencrypt/live/REPLACE-DOMAIN/fullchain.pem - SSLCertificateKeyFile /etc/letsencrypt/live/REPLACE-DOMAIN/privkey.pem - - - ProxyPass http://REPLACE-IP:REPLACE-PORT/ - ProxyPassReverse http://REPLACE-IP:REPLACE-PORT/ - - - - - From 0764d5bb18c84657ed97dd5cff94e4035e996cbb Mon Sep 17 00:00:00 2001 From: danielpmc Date: Tue, 27 Oct 2020 22:43:33 +0000 Subject: [PATCH 194/255] Start up apache2 after making ssl cert fails --- Panel/bot/discord/commands/server.js | 1 + 1 file changed, 1 insertion(+) diff --git a/Panel/bot/discord/commands/server.js b/Panel/bot/discord/commands/server.js index f04d1154d..640e7482f 100644 --- a/Panel/bot/discord/commands/server.js +++ b/Panel/bot/discord/commands/server.js @@ -1485,6 +1485,7 @@ exports.run = async (client, message, args) => { }) } else { message.channel.send('Error making SSL cert. Either the domain is not pointing to `154.27.68.234` or cloudflare proxy is enabled!') + ssh.execCommand(`service apache2 start`, { cwd:'/root' }) fs.unlinkSync("./proxy/" + args[1] + ".conf"); } }) From d8a8aecdb72ea2a2a8982a4c459a1aa76fdea194 Mon Sep 17 00:00:00 2001 From: danielpmc Date: Tue, 27 Oct 2020 23:00:53 +0000 Subject: [PATCH 195/255] update --- Panel/bot/discord/commands/server.js | 2 +- Panel/bot/discord/commands/user.js | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Panel/bot/discord/commands/server.js b/Panel/bot/discord/commands/server.js index 640e7482f..b3055b5f2 100644 --- a/Panel/bot/discord/commands/server.js +++ b/Panel/bot/discord/commands/server.js @@ -1484,7 +1484,7 @@ exports.run = async (client, message, args) => { message.reply('Domain has now been linked!') }) } else { - message.channel.send('Error making SSL cert. Either the domain is not pointing to `154.27.68.234` or cloudflare proxy is enabled!') + message.channel.send('Error making SSL cert. Either the domain is not pointing to `154.27.68.234` or cloudflare proxy is enabled! \n\n*If you have just done this after running the command. Please give the bot 5 - 10mins to refresh the DNS cache') ssh.execCommand(`service apache2 start`, { cwd:'/root' }) fs.unlinkSync("./proxy/" + args[1] + ".conf"); } diff --git a/Panel/bot/discord/commands/user.js b/Panel/bot/discord/commands/user.js index e2e8069a1..759c8e131 100644 --- a/Panel/bot/discord/commands/user.js +++ b/Panel/bot/discord/commands/user.js @@ -281,7 +281,7 @@ exports.run = async(client, message, args) => { followRedirect: true, maxRedirects: 5, headers: { - 'Authorization': 'Bearer ' + "FhzH9PUVKcUnrHxCySA9dOPbyVmimDaVmCEtXKaPvPMpAivj", + 'Authorization': 'Bearer ' + config.Pterodactyl.apikey, 'Content-Type': 'application/json', 'Accept': 'Application/vnd.pterodactyl.v1+json', } @@ -297,7 +297,7 @@ exports.run = async(client, message, args) => { followRedirect: true, maxRedirects: 5, headers: { - 'Authorization': 'Bearer ' + "FhzH9PUVKcUnrHxCySA9dOPbyVmimDaVmCEtXKaPvPMpAivj", + 'Authorization': 'Bearer ' + config.Pterodactyl.apikey, 'Content-Type': 'application/json', 'Accept': 'Application/vnd.pterodactyl.v1+json', } From 13ddcce7e4e88a9d13d6bd74bb3bbbe7998a033d Mon Sep 17 00:00:00 2001 From: danielpmc Date: Tue, 27 Oct 2020 23:43:18 +0000 Subject: [PATCH 196/255] Update help on that server command --- Panel/bot/discord/commands/server.js | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/Panel/bot/discord/commands/server.js b/Panel/bot/discord/commands/server.js index b3055b5f2..b197402ff 100644 --- a/Panel/bot/discord/commands/server.js +++ b/Panel/bot/discord/commands/server.js @@ -5,6 +5,7 @@ const path = require('path'); const {NodeSSH} = require('node-ssh') const ssh = new NodeSSH() const rif = require('replace-in-file'); +const { config } = require('process'); exports.run = async (client, message, args) => { const otherargs = message.content.split(' ').slice(3).join(' '); if (userData.get(message.author.id) == null) { @@ -13,7 +14,7 @@ exports.run = async (client, message, args) => { if (!args[0]) { //No args let embed = new Discord.RichEmbed() - .setTitle('__**Commands**__ \nCreate a server: `' + config.DiscordBot.Prefix + 'server create type servername` \nServer Types: `' + config.DiscordBot.Prefix + 'server create list` \nServer Status: `' + config.DiscordBot.Prefix + 'server status serverid`') + .setTitle('__**Commands**__ \nCreate a server: `' + config.DiscordBot.Prefix + 'server create type servername` \nServer Types: `' + config.DiscordBot.Prefix + 'server create list` \nServer Status: `' + config.DiscordBot.Prefix + 'server status serverid` \n`' + config.DiscordBot.Prefix + 'server proxy domainhere serveridhere`') message.channel.send(embed) } else if (args[0].toLowerCase() == "create") { @@ -1340,8 +1341,6 @@ exports.run = async (client, message, args) => { })}); } } else if (args[0].toLowerCase() == "proxy") { - let domainfilter = [".com", ".co.uk", ".us", ".xyz", ".org", ".host"]; - const embed = new Discord.RichEmbed() .setTitle('__**How to link a domain to a website/server**__ \nCommand format: `' + config.DiscordBot.Prefix + 'server proxy domainhere serverid') .setFooter('If you just tried to link a domain. That TLD is not supported yet!') From eb5e09010f729b6171f7630773374cd594f0a626 Mon Sep 17 00:00:00 2001 From: danielpmc Date: Tue, 27 Oct 2020 23:43:30 +0000 Subject: [PATCH 197/255] Edit embed on server.js --- Panel/bot/discord/commands/server.js | 1 - 1 file changed, 1 deletion(-) diff --git a/Panel/bot/discord/commands/server.js b/Panel/bot/discord/commands/server.js index b197402ff..dd58349fc 100644 --- a/Panel/bot/discord/commands/server.js +++ b/Panel/bot/discord/commands/server.js @@ -1343,7 +1343,6 @@ exports.run = async (client, message, args) => { } else if (args[0].toLowerCase() == "proxy") { const embed = new Discord.RichEmbed() .setTitle('__**How to link a domain to a website/server**__ \nCommand format: `' + config.DiscordBot.Prefix + 'server proxy domainhere serverid') - .setFooter('If you just tried to link a domain. That TLD is not supported yet!') if (!args[1]) { message.channel.send(embed) } else { From 9e55b57393c06e626369e88cae09dc5389377a1a Mon Sep 17 00:00:00 2001 From: danielpmc Date: Tue, 27 Oct 2020 23:52:20 +0000 Subject: [PATCH 198/255] Update server.js --- Panel/bot/discord/commands/server.js | 1 - 1 file changed, 1 deletion(-) diff --git a/Panel/bot/discord/commands/server.js b/Panel/bot/discord/commands/server.js index dd58349fc..b8659692f 100644 --- a/Panel/bot/discord/commands/server.js +++ b/Panel/bot/discord/commands/server.js @@ -5,7 +5,6 @@ const path = require('path'); const {NodeSSH} = require('node-ssh') const ssh = new NodeSSH() const rif = require('replace-in-file'); -const { config } = require('process'); exports.run = async (client, message, args) => { const otherargs = message.content.split(' ').slice(3).join(' '); if (userData.get(message.author.id) == null) { From 0c74f4cf463f92620dec9f7130a512af6a69f4d6 Mon Sep 17 00:00:00 2001 From: danielpmc Date: Wed, 28 Oct 2020 00:32:12 +0000 Subject: [PATCH 199/255] Log to DB when a domain is linked. Will be used if someone hosts some illegal crap so we know who linked that domain :) --- Panel/bot/discord/commands/server.js | 8 +++++++- Panel/index.js | 1 + 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/Panel/bot/discord/commands/server.js b/Panel/bot/discord/commands/server.js index b8659692f..75e6ad877 100644 --- a/Panel/bot/discord/commands/server.js +++ b/Panel/bot/discord/commands/server.js @@ -1341,7 +1341,7 @@ exports.run = async (client, message, args) => { } } else if (args[0].toLowerCase() == "proxy") { const embed = new Discord.RichEmbed() - .setTitle('__**How to link a domain to a website/server**__ \nCommand format: `' + config.DiscordBot.Prefix + 'server proxy domainhere serverid') + .setTitle('__**How to link a domain to a website/server**__ \nCommand format: ' + config.DiscordBot.Prefix + 'server proxy domainhere serverid') if (!args[1]) { message.channel.send(embed) } else { @@ -1479,6 +1479,12 @@ exports.run = async (client, message, args) => { ssh.execCommand(`a2ensite ${args[1]} && service apache2 restart`, { cwd:'/root' }).then(function(result) { //Complete message.reply('Domain has now been linked!') + + domains.set(args[1], { + DiscordID: message.author.id, + ServerID: args[2], + Domain: args[1] + }); }) } else { message.channel.send('Error making SSL cert. Either the domain is not pointing to `154.27.68.234` or cloudflare proxy is enabled! \n\n*If you have just done this after running the command. Please give the bot 5 - 10mins to refresh the DNS cache') diff --git a/Panel/index.js b/Panel/index.js index 72193854f..50cd03abe 100644 --- a/Panel/index.js +++ b/Panel/index.js @@ -43,6 +43,7 @@ global.userData = new db.table("userData"); global.settings = new db.table("settings"); global.webSettings = new db.table("webSettings"); global.mutesData = new db.table("muteData"); +global.domains = new db.table("linkedDomains") global.client = new Discord.Client({ disableEveryone: true }); From 75d0bc556f62553bcc4b02cd6b0b2baa5a18e74c Mon Sep 17 00:00:00 2001 From: danielpmc Date: Wed, 28 Oct 2020 01:13:45 +0000 Subject: [PATCH 200/255] Update server.js --- Panel/bot/discord/commands/server.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Panel/bot/discord/commands/server.js b/Panel/bot/discord/commands/server.js index 75e6ad877..db6f19202 100644 --- a/Panel/bot/discord/commands/server.js +++ b/Panel/bot/discord/commands/server.js @@ -1480,11 +1480,13 @@ exports.run = async (client, message, args) => { //Complete message.reply('Domain has now been linked!') + /* domains.set(args[1], { DiscordID: message.author.id, ServerID: args[2], Domain: args[1] }); + */ }) } else { message.channel.send('Error making SSL cert. Either the domain is not pointing to `154.27.68.234` or cloudflare proxy is enabled! \n\n*If you have just done this after running the command. Please give the bot 5 - 10mins to refresh the DNS cache') From a4e0a31dc3f38e04d082afd571ed382b4b4d92cf Mon Sep 17 00:00:00 2001 From: danielpmc Date: Wed, 28 Oct 2020 09:11:50 +0000 Subject: [PATCH 201/255] add a example config --- Panel/example-config.json | 59 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) create mode 100644 Panel/example-config.json diff --git a/Panel/example-config.json b/Panel/example-config.json new file mode 100644 index 000000000..b7fbf029d --- /dev/null +++ b/Panel/example-config.json @@ -0,0 +1,59 @@ +{ + "Port": 1144, + + "DiscordBot": { + "Token": "Bot Token", + "Prefix": "Prefix", + "clientID": "Client ID from Discord Dev portal for the bot", + "clientSecret": "Client Secret from the Discord Dev Portal.", + "callbackURL": "Call back url. For logging into the website", + "ownerID": "Owner ID. Gives you access to a few more commands :)", + "mLogs": "Message logs channel ID", + "oLogs": "Other logs channel id (Currently used for namechanges and linking logs)", + "welcome": "Welcome channel ID", + "inviterewmsg": "Invite reward message channel ID", + "invite5": "Invite 5+ role ID", + "invite10": "Invite 10+ role ID", + "invite25": "Invite 25+ role ID", + "invite50": "Invite 50+ role ID", + "invitechannel": "Invite logs channel ID", + "requestsChannel": "Request channel ID" + }, + + "DiscordSuggestions": { + "channelID": "Channel ID for Suggestions webhook", + "Token": "Discord Webhook token" + }, + + "DB": { + "MongoDB": "MongoDB connection (forgot what this is for but give it one anyway)" + }, + + "Pterodactyl": { + "hosturl": "Pterodactyl URL (Dont put the / on the end) Example: https://your.panel.com", + "apikey": "Pterodactyl ADMIN Api key. Where to find? add admin/api to the end of your panel domain", + "apikeyclient": "Pterodactyl CLIENT Api key. Find it: add account/api to the end of your panel domain" + }, + + "Proxmox": { + "url": "Proxmox (Not used yet so ignore this)", + "auth": "Proxmox (Not used yet so ignore this)", + "username": "Proxmox (Not used yet so ignore this)", + "password": "Proxmox (Not used yet so ignore this)" + }, + + "Email": { + "Host": "smtp mail server host", + "Port": "587", + "User": "smtp mail server username", + "Password": "smtp mail server password", + "From": "Mail from email" + }, + + "SSH": { + "Host": "SSH Host (Used for Proxy servers right now)", + "User": "root", + "Password": "User password for SSH", + "Port": 22 + } +} \ No newline at end of file From 15d77f4f64035d208ddc314013d58e31539cdc7c Mon Sep 17 00:00:00 2001 From: danielpmc Date: Wed, 28 Oct 2020 10:28:16 +0000 Subject: [PATCH 202/255] Add bold to warning --- Panel/bot/discord/commands/server.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Panel/bot/discord/commands/server.js b/Panel/bot/discord/commands/server.js index db6f19202..a063f7645 100644 --- a/Panel/bot/discord/commands/server.js +++ b/Panel/bot/discord/commands/server.js @@ -1489,7 +1489,7 @@ exports.run = async (client, message, args) => { */ }) } else { - message.channel.send('Error making SSL cert. Either the domain is not pointing to `154.27.68.234` or cloudflare proxy is enabled! \n\n*If you have just done this after running the command. Please give the bot 5 - 10mins to refresh the DNS cache') + message.channel.send('Error making SSL cert. Either the domain is not pointing to `154.27.68.234` or cloudflare proxy is enabled! \n\n**If you have just done this after running the command. Please give the bot 5 - 10mins to refresh the DNS cache**') ssh.execCommand(`service apache2 start`, { cwd:'/root' }) fs.unlinkSync("./proxy/" + args[1] + ".conf"); } From 6a3545df0a944f3c403ff9221f46cbbccf937805 Mon Sep 17 00:00:00 2001 From: danielpmc Date: Wed, 28 Oct 2020 13:08:07 +0000 Subject: [PATCH 203/255] Edit help on server.js --- Panel/bot/discord/commands/server.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Panel/bot/discord/commands/server.js b/Panel/bot/discord/commands/server.js index a063f7645..465ad0cfc 100644 --- a/Panel/bot/discord/commands/server.js +++ b/Panel/bot/discord/commands/server.js @@ -13,7 +13,7 @@ exports.run = async (client, message, args) => { if (!args[0]) { //No args let embed = new Discord.RichEmbed() - .setTitle('__**Commands**__ \nCreate a server: `' + config.DiscordBot.Prefix + 'server create type servername` \nServer Types: `' + config.DiscordBot.Prefix + 'server create list` \nServer Status: `' + config.DiscordBot.Prefix + 'server status serverid` \n`' + config.DiscordBot.Prefix + 'server proxy domainhere serveridhere`') + .setTitle('__**Commands**__ \nCreate a server: `' + config.DiscordBot.Prefix + 'server create type servername` \nServer Types: `' + config.DiscordBot.Prefix + 'server create list` \nServer Status: `' + config.DiscordBot.Prefix + 'server status serverid` \nLink Domain`' + config.DiscordBot.Prefix + 'server proxy domainhere serveridhere`') message.channel.send(embed) } else if (args[0].toLowerCase() == "create") { From 6657ff4bbbd477892b20d2f68772bb6cdaaf9b2b Mon Sep 17 00:00:00 2001 From: danielpmc Date: Wed, 28 Oct 2020 21:24:46 +0000 Subject: [PATCH 204/255] Added canvas to packages. New welcome png coming soon --- Panel/bot/discord/events/guildMemberAdd.js | 7 +++---- .../bot/discord/events/welcome-background.png | Bin 0 -> 626188 bytes Panel/package.json | 1 + 3 files changed, 4 insertions(+), 4 deletions(-) create mode 100644 Panel/bot/discord/events/welcome-background.png diff --git a/Panel/bot/discord/events/guildMemberAdd.js b/Panel/bot/discord/events/guildMemberAdd.js index c14e25ce9..68fa5312f 100644 --- a/Panel/bot/discord/events/guildMemberAdd.js +++ b/Panel/bot/discord/events/guildMemberAdd.js @@ -13,9 +13,8 @@ const config2 = { "bot": "704467807122882562" } -let db = require("quick.db"); -//let client = require("../../../../index.js").client; - +const Canvas = require("canvas"); +const db = require("quick.db"); module.exports = async(client, member, guild) => { var getAge = function(millis) { @@ -83,7 +82,7 @@ module.exports = async(client, member, guild) => { if (userData.get(member.user.id) == null) { const memberrole = member.guild.roles.find(role => role.id === config2.member); member.guild.members.get(member.user.id).addRole(memberrole) - client.channels.get(config2.welcome).send("Welcome <@" + member.user.id + "> to DanBot Hosting. To get started please read <#738527470164377630>"); + client.channels.get(config2.welcome).send("Welcome <@" + member.user.id + "> to DanBot Hosting. To get started please read <#738527470164377630>"); } else { const memberrole = member.guild.roles.find(role => role.id === config2.member); const clientrole = member.guild.roles.find(role => role.id === "639489891016638496"); diff --git a/Panel/bot/discord/events/welcome-background.png b/Panel/bot/discord/events/welcome-background.png new file mode 100644 index 0000000000000000000000000000000000000000..371b00a5589acc48f681eff17281ab522d6c1768 GIT binary patch literal 626188 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

m1&`AL~(6S;|wtjfRWXvt~g&3Q75GGrj7#77(m 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%0AZ)R(_hgM4aLj92qT3Hd44b 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

j%hDlXN+hc%c7;TyOuE8Fdk)p_1|>dAUlRILUBg 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

<~#hQs7Qt+o51Jm+w-&Sv-N>JHznaV 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 z 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%0A2$nD# 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 Date: Wed, 28 Oct 2020 21:40:39 +0000 Subject: [PATCH 205/255] Test delete --- Panel/bot/discord/commands/server.js | 67 ++++++++++++++++++++++------ 1 file changed, 54 insertions(+), 13 deletions(-) diff --git a/Panel/bot/discord/commands/server.js b/Panel/bot/discord/commands/server.js index 465ad0cfc..b40028366 100644 --- a/Panel/bot/discord/commands/server.js +++ b/Panel/bot/discord/commands/server.js @@ -1201,26 +1201,64 @@ exports.run = async (client, message, args) => { } } else if (args[0].toLowerCase() == "delete") { //delete server things + if (!args[1]) { + message.channel.send('Command format: `' + config.DiscordBot.Prefix + 'server delete serveridhere`') + } else { message.channel.send('Checking server ' + args[1]).then((msg) => { - axios({ - url: config.Pterodactyl.hosturl + "/api/application/servers/" + args[1], - method: 'GET', - followRedirect: true, - maxRedirects: 5, - headers: { - 'Authorization': 'Bearer ' + config.Pterodactyl.apikey, - 'Content-Type': 'application/json', - 'Accept': 'Application/vnd.pterodactyl.v1+json', + var arr = []; + + axios({ + url: "https://panel.danbot.host" + "/api/application/servers", + method: 'GET', + followRedirect: true, + maxRedirects: 5, + headers: { + 'Authorization': 'Bearer ' + config.Pterodactyl.apikey, + 'Content-Type': 'application/json', + 'Accept': 'Application/vnd.pterodactyl.v1+json', + } + }).then(resources => { + var countmax = resources.data.meta.pagination.total_pages + var i2 = countmax++ + + var i = 0 + while (i { msg.edit('Request cancelled!') } }) + } + },500) + }, 10000) }); - }) + } } else if (args[0].toLowerCase() == "manage") { message.channel.send('Uh this isnt done yet...') } else if (args[0] == "list") { From c16fcdf0b089fa2a48b78220c0515eb9954dc7e9 Mon Sep 17 00:00:00 2001 From: danielpmc Date: Wed, 28 Oct 2020 21:43:01 +0000 Subject: [PATCH 206/255] Update server.js --- Panel/bot/discord/commands/server.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Panel/bot/discord/commands/server.js b/Panel/bot/discord/commands/server.js index b40028366..579399818 100644 --- a/Panel/bot/discord/commands/server.js +++ b/Panel/bot/discord/commands/server.js @@ -1245,7 +1245,7 @@ exports.run = async (client, message, args) => { setTimeout(async () => { //console.log(arr.length) - const output = await arr.map(srv => srv.attributes ? srv.attributes.identifier == args[1] : false) + const output = await arr.find(srv => srv.attributes ? srv.attributes.identifier == args[1] : false) setTimeout(() => { console.log(output) if (!output.attributes.user == userData.get(message.author.id).consoleID) { From efd59842761856c8dff92ddb6d8e8d24892ab0b3 Mon Sep 17 00:00:00 2001 From: danielpmc Date: Wed, 28 Oct 2020 21:44:04 +0000 Subject: [PATCH 207/255] Update server.js --- Panel/bot/discord/commands/server.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Panel/bot/discord/commands/server.js b/Panel/bot/discord/commands/server.js index 579399818..ac9df9357 100644 --- a/Panel/bot/discord/commands/server.js +++ b/Panel/bot/discord/commands/server.js @@ -1252,7 +1252,7 @@ exports.run = async (client, message, args) => { message.channel.send('You do not own that server. You cant delete it.') } else { - msg.edit('Are you sure you want to delete `' + response.data.attributes.name + '`?\nPlease type `confirm` to delete this server. You have 1min until this will expire \n\n**You can not restore the server once it has been deleted**') + msg.edit('Are you sure you want to delete `' + output.attributes.name + '`?\nPlease type `confirm` to delete this server. You have 1min until this will expire \n\n**You can not restore the server once it has been deleted**') const collector = new Discord.MessageCollector(message.channel, m => m.author.id === message.author.id, { time: 60000, max: 2 }); collector.on('collect', message => { if (message == "confirm") { From 820bcf4dc8e841398cd71271e7b7092a11db80df Mon Sep 17 00:00:00 2001 From: danielpmc Date: Wed, 28 Oct 2020 21:46:50 +0000 Subject: [PATCH 208/255] Update server.js --- Panel/bot/discord/commands/server.js | 50 ++++++++++++++-------------- 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/Panel/bot/discord/commands/server.js b/Panel/bot/discord/commands/server.js index ac9df9357..1b81f3e78 100644 --- a/Panel/bot/discord/commands/server.js +++ b/Panel/bot/discord/commands/server.js @@ -1248,33 +1248,33 @@ exports.run = async (client, message, args) => { const output = await arr.find(srv => srv.attributes ? srv.attributes.identifier == args[1] : false) setTimeout(() => { console.log(output) - if (!output.attributes.user == userData.get(message.author.id).consoleID) { - message.channel.send('You do not own that server. You cant delete it.') - } else { - - msg.edit('Are you sure you want to delete `' + output.attributes.name + '`?\nPlease type `confirm` to delete this server. You have 1min until this will expire \n\n**You can not restore the server once it has been deleted**') - const collector = new Discord.MessageCollector(message.channel, m => m.author.id === message.author.id, { time: 60000, max: 2 }); - collector.on('collect', message => { - if (message == "confirm") { - message.delete() - axios({ - url: config.Pterodactyl.hosturl + "/api/application/servers/" + output.attributes.id, - method: 'DELETE', - followRedirect: true, - maxRedirects: 5, - headers: { - 'Authorization': 'Bearer ' + config.Pterodactyl.apikey, - 'Content-Type': 'application/json', - 'Accept': 'Application/vnd.pterodactyl.v1+json', + if (output.attributes.user == userData.get(message.author.id).consoleID) { + msg.edit('Are you sure you want to delete `' + output.attributes.name + '`?\nPlease type `confirm` to delete this server. You have 1min until this will expire \n\n**You can not restore the server once it has been deleted**') + const collector = new Discord.MessageCollector(message.channel, m => m.author.id === message.author.id, { time: 60000, max: 2 }); + collector.on('collect', message => { + if (message == "confirm") { + message.delete() + axios({ + url: config.Pterodactyl.hosturl + "/api/application/servers/" + output.attributes.id, + method: 'DELETE', + followRedirect: true, + maxRedirects: 5, + headers: { + 'Authorization': 'Bearer ' + config.Pterodactyl.apikey, + 'Content-Type': 'application/json', + 'Accept': 'Application/vnd.pterodactyl.v1+json', + } + }).then(response => { + msg.edit('Server deleted!') + }); + } else { + message.delete() + msg.edit('Request cancelled!') } - }).then(response => { - msg.edit('Server deleted!') - }); + }) + } else { - message.delete() - msg.edit('Request cancelled!') - } - }) + message.channel.send('You do not own that server. You cant delete it.') } },500) }, 10000) From 1603b9718d8d14b5fcfd785ac4a4465d959fe0f2 Mon Sep 17 00:00:00 2001 From: danielpmc Date: Wed, 28 Oct 2020 21:48:35 +0000 Subject: [PATCH 209/255] Update server.js --- Panel/bot/discord/commands/server.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Panel/bot/discord/commands/server.js b/Panel/bot/discord/commands/server.js index 1b81f3e78..8cff27124 100644 --- a/Panel/bot/discord/commands/server.js +++ b/Panel/bot/discord/commands/server.js @@ -1204,7 +1204,7 @@ exports.run = async (client, message, args) => { if (!args[1]) { message.channel.send('Command format: `' + config.DiscordBot.Prefix + 'server delete serveridhere`') } else { - message.channel.send('Checking server ' + args[1]).then((msg) => { + message.channel.send('Checking server ' + args[1] + '\nPlease allow me 10seconds to fetch this.').then((msg) => { var arr = []; axios({ From ff044a42dc56e3e60f54fc9f0f6adef074255bcc Mon Sep 17 00:00:00 2001 From: danielpmc Date: Wed, 28 Oct 2020 21:51:27 +0000 Subject: [PATCH 210/255] Update server.js --- Panel/bot/discord/commands/server.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Panel/bot/discord/commands/server.js b/Panel/bot/discord/commands/server.js index 8cff27124..35b6d0db9 100644 --- a/Panel/bot/discord/commands/server.js +++ b/Panel/bot/discord/commands/server.js @@ -1240,13 +1240,16 @@ exports.run = async (client, message, args) => { }); i++ } - var total = resources.data.meta.pagination.total }); setTimeout(async () => { //console.log(arr.length) const output = await arr.find(srv => srv.attributes ? srv.attributes.identifier == args[1] : false) setTimeout(() => { + if (!output) { + msg.edit('Can\'t find that server :(') + } else { + console.log(output) if (output.attributes.user == userData.get(message.author.id).consoleID) { msg.edit('Are you sure you want to delete `' + output.attributes.name + '`?\nPlease type `confirm` to delete this server. You have 1min until this will expire \n\n**You can not restore the server once it has been deleted**') @@ -1276,6 +1279,7 @@ exports.run = async (client, message, args) => { } else { message.channel.send('You do not own that server. You cant delete it.') } + } },500) }, 10000) }); From e9d374e88b190aca85fe8f36e0a71561175c322e Mon Sep 17 00:00:00 2001 From: danielpmc Date: Wed, 28 Oct 2020 21:57:27 +0000 Subject: [PATCH 211/255] Update server.js --- Panel/bot/discord/commands/server.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Panel/bot/discord/commands/server.js b/Panel/bot/discord/commands/server.js index 35b6d0db9..d45efc49a 100644 --- a/Panel/bot/discord/commands/server.js +++ b/Panel/bot/discord/commands/server.js @@ -13,7 +13,7 @@ exports.run = async (client, message, args) => { if (!args[0]) { //No args let embed = new Discord.RichEmbed() - .setTitle('__**Commands**__ \nCreate a server: `' + config.DiscordBot.Prefix + 'server create type servername` \nServer Types: `' + config.DiscordBot.Prefix + 'server create list` \nServer Status: `' + config.DiscordBot.Prefix + 'server status serverid` \nLink Domain`' + config.DiscordBot.Prefix + 'server proxy domainhere serveridhere`') + .setTitle('__**Commands**__ \nCreate a server: `' + config.DiscordBot.Prefix + 'server create type servername` \nServer Types: `' + config.DiscordBot.Prefix + 'server create list` \nServer Status: `' + config.DiscordBot.Prefix + 'server status serverid` \nLink Domain`' + config.DiscordBot.Prefix + 'server proxy domainhere serveridhere` \nDelete server: `' + config.DiscordBot.Prefix + 'server delete serveridhere`') message.channel.send(embed) } else if (args[0].toLowerCase() == "create") { From 424236dd1b95ebd2162f08f6b6f41e67b95fd6a7 Mon Sep 17 00:00:00 2001 From: danielpmc Date: Wed, 28 Oct 2020 21:59:31 +0000 Subject: [PATCH 212/255] Update server.js --- Panel/bot/discord/commands/server.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Panel/bot/discord/commands/server.js b/Panel/bot/discord/commands/server.js index d45efc49a..31e47e740 100644 --- a/Panel/bot/discord/commands/server.js +++ b/Panel/bot/discord/commands/server.js @@ -13,7 +13,7 @@ exports.run = async (client, message, args) => { if (!args[0]) { //No args let embed = new Discord.RichEmbed() - .setTitle('__**Commands**__ \nCreate a server: `' + config.DiscordBot.Prefix + 'server create type servername` \nServer Types: `' + config.DiscordBot.Prefix + 'server create list` \nServer Status: `' + config.DiscordBot.Prefix + 'server status serverid` \nLink Domain`' + config.DiscordBot.Prefix + 'server proxy domainhere serveridhere` \nDelete server: `' + config.DiscordBot.Prefix + 'server delete serveridhere`') + .addField('__**Commands**__', 'Create a server: `' + config.DiscordBot.Prefix + 'server create type servername` \nServer Types: `' + config.DiscordBot.Prefix + 'server create list` \nServer Status: `' + config.DiscordBot.Prefix + 'server status serverid` \nLink Domain`' + config.DiscordBot.Prefix + 'server proxy domainhere serveridhere` \nDelete server: `' + config.DiscordBot.Prefix + 'server delete serveridhere`') message.channel.send(embed) } else if (args[0].toLowerCase() == "create") { From c971bbe85d347edd388c97eb8e54950c9ae5fa4c Mon Sep 17 00:00:00 2001 From: danielpmc Date: Wed, 28 Oct 2020 22:47:20 +0000 Subject: [PATCH 213/255] Update eval.js --- Panel/bot/discord/commands/eval.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Panel/bot/discord/commands/eval.js b/Panel/bot/discord/commands/eval.js index 530900bab..ebd182212 100644 --- a/Panel/bot/discord/commands/eval.js +++ b/Panel/bot/discord/commands/eval.js @@ -30,7 +30,7 @@ exports.run = async (client, message) => { message.channel.send('Evaluating...').then(msg => { try { let code = args.join(' '); - let evaled = eval(code); + let evaled = await eval(code); if (typeof evaled !== 'string') { evaled = require('util').inspect(evaled); From db956c32959218f8c478fd8326084f4d8bfb701c Mon Sep 17 00:00:00 2001 From: danielpmc Date: Wed, 28 Oct 2020 22:48:35 +0000 Subject: [PATCH 214/255] Update eval.js --- Panel/bot/discord/commands/eval.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Panel/bot/discord/commands/eval.js b/Panel/bot/discord/commands/eval.js index ebd182212..530900bab 100644 --- a/Panel/bot/discord/commands/eval.js +++ b/Panel/bot/discord/commands/eval.js @@ -30,7 +30,7 @@ exports.run = async (client, message) => { message.channel.send('Evaluating...').then(msg => { try { let code = args.join(' '); - let evaled = await eval(code); + let evaled = eval(code); if (typeof evaled !== 'string') { evaled = require('util').inspect(evaled); From d73d7b30bbca336fb07728eb4a73e31a679cec14 Mon Sep 17 00:00:00 2001 From: danielpmc Date: Wed, 28 Oct 2020 23:11:05 +0000 Subject: [PATCH 215/255] Update delete server. from 10seconds to 1.5seconds to find the server :) --- Panel/bot/discord/commands/server.js | 55 ++++++++-------------------- 1 file changed, 16 insertions(+), 39 deletions(-) diff --git a/Panel/bot/discord/commands/server.js b/Panel/bot/discord/commands/server.js index 31e47e740..8390dfba6 100644 --- a/Panel/bot/discord/commands/server.js +++ b/Panel/bot/discord/commands/server.js @@ -1204,53 +1204,29 @@ exports.run = async (client, message, args) => { if (!args[1]) { message.channel.send('Command format: `' + config.DiscordBot.Prefix + 'server delete serveridhere`') } else { - message.channel.send('Checking server ' + args[1] + '\nPlease allow me 10seconds to fetch this.').then((msg) => { - var arr = []; - - axios({ - url: "https://panel.danbot.host" + "/api/application/servers", - method: 'GET', - followRedirect: true, - maxRedirects: 5, - headers: { - 'Authorization': 'Bearer ' + config.Pterodactyl.apikey, - 'Content-Type': 'application/json', - 'Accept': 'Application/vnd.pterodactyl.v1+json', - } - }).then(resources => { - var countmax = resources.data.meta.pagination.total_pages - var i2 = countmax++ - - var i = 0 - while (i { + const preoutput = response.data.attributes.relationships.servers.data + const output = preoutput.find(srv => srv.attributes ? srv.attributes.identifier == args[1] : false) + setTimeout(async () => { //console.log(arr.length) - const output = await arr.find(srv => srv.attributes ? srv.attributes.identifier == args[1] : false) setTimeout(() => { if (!output) { msg.edit('Can\'t find that server :(') } else { - console.log(output) if (output.attributes.user == userData.get(message.author.id).consoleID) { msg.edit('Are you sure you want to delete `' + output.attributes.name + '`?\nPlease type `confirm` to delete this server. You have 1min until this will expire \n\n**You can not restore the server once it has been deleted**') const collector = new Discord.MessageCollector(message.channel, m => m.author.id === message.author.id, { time: 60000, max: 2 }); @@ -1281,7 +1257,8 @@ exports.run = async (client, message, args) => { } } },500) - }, 10000) + }, 1000) + }); }); } } else if (args[0].toLowerCase() == "manage") { From e76152723da9fec49e7c7af606c0bdb0985070a5 Mon Sep 17 00:00:00 2001 From: danielpmc Date: Wed, 28 Oct 2020 23:50:13 +0000 Subject: [PATCH 216/255] stop message collector --- Panel/bot/discord/commands/server.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Panel/bot/discord/commands/server.js b/Panel/bot/discord/commands/server.js index 8390dfba6..601e09edf 100644 --- a/Panel/bot/discord/commands/server.js +++ b/Panel/bot/discord/commands/server.js @@ -1245,10 +1245,12 @@ exports.run = async (client, message, args) => { } }).then(response => { msg.edit('Server deleted!') + collector.stop() }); } else { message.delete() msg.edit('Request cancelled!') + collector.stop() } }) From e91950b632ba223074272be00210084a6d013e16 Mon Sep 17 00:00:00 2001 From: danielpmc Date: Thu, 29 Oct 2020 00:05:22 +0000 Subject: [PATCH 217/255] Update guildMemberUpdate.js --- Panel/bot/discord/events/guildMemberUpdate.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Panel/bot/discord/events/guildMemberUpdate.js b/Panel/bot/discord/events/guildMemberUpdate.js index e592810e7..064b99517 100644 --- a/Panel/bot/discord/events/guildMemberUpdate.js +++ b/Panel/bot/discord/events/guildMemberUpdate.js @@ -22,6 +22,8 @@ module.exports = async (client, oldMember, newMember) => { oldMember.setNickname("") } else if (newName.includes(a)) { oldMember.setNickname("") + } else if (newName.includes("!")) { + oldMember.setNickname("I'm a hoister") } // Make a new RichEmbed From 6831bf97e578350e85e701b618e766aae75d3437 Mon Sep 17 00:00:00 2001 From: danielpmc Date: Thu, 29 Oct 2020 00:06:08 +0000 Subject: [PATCH 218/255] Stop people using ! to hoist --- Panel/bot/discord/events/guildMemberUpdate.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Panel/bot/discord/events/guildMemberUpdate.js b/Panel/bot/discord/events/guildMemberUpdate.js index 064b99517..f023d8192 100644 --- a/Panel/bot/discord/events/guildMemberUpdate.js +++ b/Panel/bot/discord/events/guildMemberUpdate.js @@ -23,7 +23,7 @@ module.exports = async (client, oldMember, newMember) => { } else if (newName.includes(a)) { oldMember.setNickname("") } else if (newName.includes("!")) { - oldMember.setNickname("I'm a hoister") + oldMember.setNickname("I'm a furry OwO") } // Make a new RichEmbed From 1bcd8c38f3ad9c0e406b1b4b1d8d96f1575dea5c Mon Sep 17 00:00:00 2001 From: danielpmc Date: Thu, 29 Oct 2020 10:31:56 +0000 Subject: [PATCH 219/255] Removed commented out line --- Panel/bot/discord/commands/server.js | 1 - 1 file changed, 1 deletion(-) diff --git a/Panel/bot/discord/commands/server.js b/Panel/bot/discord/commands/server.js index 601e09edf..68dd78876 100644 --- a/Panel/bot/discord/commands/server.js +++ b/Panel/bot/discord/commands/server.js @@ -1221,7 +1221,6 @@ exports.run = async (client, message, args) => { setTimeout(async () => { - //console.log(arr.length) setTimeout(() => { if (!output) { msg.edit('Can\'t find that server :(') From 3a4d24594a0e70e1c92f5e0f5d35310e4395fa4b Mon Sep 17 00:00:00 2001 From: danielpmc Date: Thu, 29 Oct 2020 11:38:00 +0000 Subject: [PATCH 220/255] Change from const bot to global.bot --- Panel/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Panel/index.js b/Panel/index.js index 50cd03abe..e7da31bbf 100644 --- a/Panel/index.js +++ b/Panel/index.js @@ -47,7 +47,7 @@ global.domains = new db.table("linkedDomains") global.client = new Discord.Client({ disableEveryone: true }); -const bot = client; +global.bot = client; global.suggestionLog = new Discord.WebhookClient(config.DiscordSuggestions.channelID, config.DiscordSuggestions.channelID) bot.pvc = new Discord.Collection(); From 87112948176b5e49ed6c03a80825480357ae9f4a Mon Sep 17 00:00:00 2001 From: danielpmc Date: Thu, 29 Oct 2020 12:55:27 +0000 Subject: [PATCH 221/255] Added --bind_ip to mongodb servers --- Panel/bot/discord/commands/server.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Panel/bot/discord/commands/server.js b/Panel/bot/discord/commands/server.js index 68dd78876..8c95fe270 100644 --- a/Panel/bot/discord/commands/server.js +++ b/Panel/bot/discord/commands/server.js @@ -997,7 +997,7 @@ exports.run = async (client, message, args) => { "nest": 12, "egg": 35, "docker_image": "quay.io/parkervcp/pterodactyl-images:db_mongo-4", - "startup": "mongod --fork --dbpath /home/container/mongodb/ --port ${SERVER_PORT} --logpath /home/container/logs/mongo.log; until nc -z -v -w5 127.0.0.1 ${SERVER_PORT}; do echo 'Waiting for mongodb connection...'; sleep 5; done && mongo 127.0.0.1:${SERVER_PORT} && mongo --eval 'db.getSiblingDB('admin').shutdownServer()' 127.0.0.1:${SERVER_PORT}", + "startup": "mongod --fork --dbpath /home/container/mongodb/ --port ${SERVER_PORT} --bind_ip 0.0.0.0 --logpath /home/container/logs/mongo.log; until nc -z -v -w5 127.0.0.1 ${SERVER_PORT}; do echo 'Waiting for mongodb connection...'; sleep 5; done && mongo 127.0.0.1:${SERVER_PORT} && mongo --eval 'db.getSiblingDB('admin').shutdownServer()' 127.0.0.1:${SERVER_PORT}", "limits": { "memory": 0, "swap": 0, From 7460c31d7af6aaa7ab729d17ad66c0c18ff7619c Mon Sep 17 00:00:00 2001 From: danielpmc Date: Thu, 29 Oct 2020 19:17:35 +0000 Subject: [PATCH 222/255] add --auth flag to mongodb --- Panel/bot/discord/commands/server.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Panel/bot/discord/commands/server.js b/Panel/bot/discord/commands/server.js index 8c95fe270..06f9cae1d 100644 --- a/Panel/bot/discord/commands/server.js +++ b/Panel/bot/discord/commands/server.js @@ -997,7 +997,7 @@ exports.run = async (client, message, args) => { "nest": 12, "egg": 35, "docker_image": "quay.io/parkervcp/pterodactyl-images:db_mongo-4", - "startup": "mongod --fork --dbpath /home/container/mongodb/ --port ${SERVER_PORT} --bind_ip 0.0.0.0 --logpath /home/container/logs/mongo.log; until nc -z -v -w5 127.0.0.1 ${SERVER_PORT}; do echo 'Waiting for mongodb connection...'; sleep 5; done && mongo 127.0.0.1:${SERVER_PORT} && mongo --eval 'db.getSiblingDB('admin').shutdownServer()' 127.0.0.1:${SERVER_PORT}", + "startup": "mongod --fork --dbpath /home/container/mongodb/ --port ${SERVER_PORT} --bind_ip 0.0.0.0 --auth --logpath /home/container/logs/mongo.log; until nc -z -v -w5 127.0.0.1 ${SERVER_PORT}; do echo 'Waiting for mongodb connection...'; sleep 5; done && mongo 127.0.0.1:${SERVER_PORT} && mongo --eval 'db.getSiblingDB('admin').shutdownServer()' 127.0.0.1:${SERVER_PORT}", "limits": { "memory": 0, "swap": 0, From 6e98299dcf70eeccf3a6b9d9f3f2e1d05b3bb6ae Mon Sep 17 00:00:00 2001 From: danielpmc Date: Thu, 29 Oct 2020 23:40:58 +0000 Subject: [PATCH 223/255] Node status channel --- Panel/bot/discord/events/ready.js | 18 +++++++- Panel/index.js | 73 ++++++++++++++++++++++++++++++- 2 files changed, 88 insertions(+), 3 deletions(-) diff --git a/Panel/bot/discord/events/ready.js b/Panel/bot/discord/events/ready.js index e85d20ba4..80ac0e312 100644 --- a/Panel/bot/discord/events/ready.js +++ b/Panel/bot/discord/events/ready.js @@ -1,5 +1,6 @@ const exec = require('child_process').exec; const axios = require('axios'); +const { Message } = require('discord.js'); module.exports = async (client, guild, files) => { console.log(chalk.magenta('[DISCORD] ') + chalk.green(client.user.username + " has logged in!")); @@ -60,7 +61,22 @@ module.exports = async (client, guild, files) => { invites[g.id] = guildInvites; }); }); - + + //Node status channel embed + setInterval(() => { + + //Node status + client.channels.get("757949242495991918").fetchMessage("771507868997648384").then(msg => { + const embed = new Discord.RichEmbed() + .addField("__**Node Status**__", `Node 1: ${nodeStatus.get("node1").status} \nNode 2: ${nodeStatus.get("node2").status} \nNode 3: ${nodeStatus.get("node3").status} \nNode 4: ${nodeStatus.get(node4)}`) + msg.edit(embed) + }); + + //Misc status + client.channels.get("757949242495991918").fetchMessage("771508453344673814").then(msg => { + }); + }, 15000) + //Voice channel stats updator setInterval(async () => { let guild1 = await client.guilds.get("639477525927690240").fetchMembers(); diff --git a/Panel/index.js b/Panel/index.js index e7da31bbf..bd972e89d 100644 --- a/Panel/index.js +++ b/Panel/index.js @@ -17,6 +17,7 @@ global.fs = require("fs"); const hbs = require('hbs'); global.chalk = require('chalk'); const nodemailer = require('nodemailer'); +const axios = require('axios'); global.transport = nodemailer.createTransport({ host: config.Email.Host, port: config.Email.Port, @@ -33,8 +34,75 @@ const { } = require(process.cwd() + "/util/discordAPI"); -//Discord Bot +//Node status +setInterval(() => { +//Node 1 +axios({ + url: config.Pterodactyl.hosturl + "/api/client/servers/99d65091/resources", + method: 'GET', + followRedirect: true, + maxRedirects: 5, + headers: { + 'Authorization': 'Bearer ' + config.Pterodactyl.apikeyclient, + 'Content-Type': 'application/json', + 'Accept': 'Application/vnd.pterodactyl.v1+json', + } +}).then(response => { + nodeStatus.set("node1", { + status: "Online" + }); +}).catch(error => { + nodeStatus.set("node1", { + status: "Offline" + }); +}) + +//Node 2 +axios({ + url: config.Pterodactyl.hosturl + "/api/client/servers/0cb9a74e/resources", + method: 'GET', + followRedirect: true, + maxRedirects: 5, + headers: { + 'Authorization': 'Bearer ' + config.Pterodactyl.apikeyclient, + 'Content-Type': 'application/json', + 'Accept': 'Application/vnd.pterodactyl.v1+json', + } +}).then(response => { + nodeStatus.set("node2", { + status: "Online" + }); +}).catch(error => { + nodeStatus.set("node2", { + status: "Offline" + }); +}) +//Node 3 +axios({ + url: config.Pterodactyl.hosturl + "/api/client/servers/373fafce/resources", + method: 'GET', + followRedirect: true, + maxRedirects: 5, + headers: { + 'Authorization': 'Bearer ' + config.Pterodactyl.apikeyclient, + 'Content-Type': 'application/json', + 'Accept': 'Application/vnd.pterodactyl.v1+json', + } +}).then(response => { + nodeStatus.set("node3", { + status: "Online" + }); +}).catch(error => { + nodeStatus.set("node3", { + status: "Offline" + }); +}) + +}, 5000) + + +//Discord Bot let db = require("quick.db"); global.Discord = require("discord.js"); global.fs = require("fs"); @@ -43,7 +111,8 @@ global.userData = new db.table("userData"); global.settings = new db.table("settings"); global.webSettings = new db.table("webSettings"); global.mutesData = new db.table("muteData"); -global.domains = new db.table("linkedDomains") +global.domains = new db.table("linkedDomains"); +global.nodeStatus = new db.table("nodeStatus"); global.client = new Discord.Client({ disableEveryone: true }); From 318b3357e2251f3e3de906cc16da51b6f8b456ff Mon Sep 17 00:00:00 2001 From: danielpmc Date: Thu, 29 Oct 2020 23:42:37 +0000 Subject: [PATCH 224/255] Update ready.js --- Panel/bot/discord/events/ready.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Panel/bot/discord/events/ready.js b/Panel/bot/discord/events/ready.js index 80ac0e312..bbf0aec19 100644 --- a/Panel/bot/discord/events/ready.js +++ b/Panel/bot/discord/events/ready.js @@ -68,7 +68,7 @@ module.exports = async (client, guild, files) => { //Node status client.channels.get("757949242495991918").fetchMessage("771507868997648384").then(msg => { const embed = new Discord.RichEmbed() - .addField("__**Node Status**__", `Node 1: ${nodeStatus.get("node1").status} \nNode 2: ${nodeStatus.get("node2").status} \nNode 3: ${nodeStatus.get("node3").status} \nNode 4: ${nodeStatus.get(node4)}`) + .addField("__**Node Status**__", `Node 1: ${nodeStatus.get("node1").status} \nNode 2: ${nodeStatus.get("node2").status} \nNode 3: ${nodeStatus.get("node3").status} \nNode 4: ${nodeStatus.get("node4")}`) msg.edit(embed) }); From 34ff93f2a85b9a7d8d2782468dc806689407c3df Mon Sep 17 00:00:00 2001 From: danielpmc Date: Thu, 29 Oct 2020 23:44:15 +0000 Subject: [PATCH 225/255] bold nodes --- Panel/bot/discord/events/ready.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Panel/bot/discord/events/ready.js b/Panel/bot/discord/events/ready.js index bbf0aec19..f004e5555 100644 --- a/Panel/bot/discord/events/ready.js +++ b/Panel/bot/discord/events/ready.js @@ -68,7 +68,7 @@ module.exports = async (client, guild, files) => { //Node status client.channels.get("757949242495991918").fetchMessage("771507868997648384").then(msg => { const embed = new Discord.RichEmbed() - .addField("__**Node Status**__", `Node 1: ${nodeStatus.get("node1").status} \nNode 2: ${nodeStatus.get("node2").status} \nNode 3: ${nodeStatus.get("node3").status} \nNode 4: ${nodeStatus.get("node4")}`) + .addField("__**Node Status**__", `**Node 1**: ${nodeStatus.get("node1").status} \n**Node 2**: ${nodeStatus.get("node2").status} \n**Node 3**: ${nodeStatus.get("node3").status} \n**Node 4**: ${nodeStatus.get("node4").status}`) msg.edit(embed) }); From aa1bb0026e7a9c6e52fe1abd2bceae50c20a4513 Mon Sep 17 00:00:00 2001 From: danielpmc Date: Thu, 29 Oct 2020 23:46:01 +0000 Subject: [PATCH 226/255] added a few emojis --- Panel/index.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Panel/index.js b/Panel/index.js index bd972e89d..d1b6460a0 100644 --- a/Panel/index.js +++ b/Panel/index.js @@ -49,11 +49,11 @@ axios({ } }).then(response => { nodeStatus.set("node1", { - status: "Online" + status: "Online 🟢" }); }).catch(error => { nodeStatus.set("node1", { - status: "Offline" + status: "Offline 🔴" }); }) @@ -70,11 +70,11 @@ axios({ } }).then(response => { nodeStatus.set("node2", { - status: "Online" + status: "Online 🟢" }); }).catch(error => { nodeStatus.set("node2", { - status: "Offline" + status: "Offline 🔴" }); }) @@ -91,11 +91,11 @@ axios({ } }).then(response => { nodeStatus.set("node3", { - status: "Online" + status: "Online 🟢" }); }).catch(error => { nodeStatus.set("node3", { - status: "Offline" + status: "Offline 🔴" }); }) From ffd1c4bab160a3a6bf8a62bec956d3cfdf89c219 Mon Sep 17 00:00:00 2001 From: danielpmc Date: Thu, 29 Oct 2020 23:59:30 +0000 Subject: [PATCH 227/255] change from .addField to .setTitle --- Panel/bot/discord/events/ready.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Panel/bot/discord/events/ready.js b/Panel/bot/discord/events/ready.js index f004e5555..1a02a05c2 100644 --- a/Panel/bot/discord/events/ready.js +++ b/Panel/bot/discord/events/ready.js @@ -68,7 +68,7 @@ module.exports = async (client, guild, files) => { //Node status client.channels.get("757949242495991918").fetchMessage("771507868997648384").then(msg => { const embed = new Discord.RichEmbed() - .addField("__**Node Status**__", `**Node 1**: ${nodeStatus.get("node1").status} \n**Node 2**: ${nodeStatus.get("node2").status} \n**Node 3**: ${nodeStatus.get("node3").status} \n**Node 4**: ${nodeStatus.get("node4").status}`) + .setTitle(`__**Node Status**__ \n**Node 1**: ${nodeStatus.get("node1").status} \n**Node 2**: ${nodeStatus.get("node2").status} \n**Node 3**: ${nodeStatus.get("node3").status} \n**Node 4**: ${nodeStatus.get("node4").status}`) msg.edit(embed) }); From 45e44ff7502ebb8f00e5f2488a48857a31c757e0 Mon Sep 17 00:00:00 2001 From: danielpmc Date: Fri, 30 Oct 2020 10:06:33 +0000 Subject: [PATCH 228/255] Update server.js --- Panel/bot/discord/commands/server.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Panel/bot/discord/commands/server.js b/Panel/bot/discord/commands/server.js index 06f9cae1d..300ea248c 100644 --- a/Panel/bot/discord/commands/server.js +++ b/Panel/bot/discord/commands/server.js @@ -1227,7 +1227,7 @@ exports.run = async (client, message, args) => { } else { if (output.attributes.user == userData.get(message.author.id).consoleID) { - msg.edit('Are you sure you want to delete `' + output.attributes.name + '`?\nPlease type `confirm` to delete this server. You have 1min until this will expire \n\n**You can not restore the server once it has been deleted**') + msg.edit('Are you sure you want to delete `' + output.attributes.name + '`?\nPlease type `confirm` to delete this server. You have 1min until this will expire \n\n**You can not restore the server once it has been deleted and/or its files**') const collector = new Discord.MessageCollector(message.channel, m => m.author.id === message.author.id, { time: 60000, max: 2 }); collector.on('collect', message => { if (message == "confirm") { From 1a80668033c9dcbba95a1a9f491a70e4e6986edb Mon Sep 17 00:00:00 2001 From: danielpmc Date: Fri, 30 Oct 2020 10:09:24 +0000 Subject: [PATCH 229/255] change 60second update to 30second. faster updates lmao --- Panel/bot/discord/events/ready.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Panel/bot/discord/events/ready.js b/Panel/bot/discord/events/ready.js index 1a02a05c2..6802c5309 100644 --- a/Panel/bot/discord/events/ready.js +++ b/Panel/bot/discord/events/ready.js @@ -24,7 +24,7 @@ module.exports = async (client, guild, files) => { } ]; - //Automatic 60second git pull. + //Automatic 30second git pull. setInterval(() => { exec(`git pull`, (error, stdout) => { let response = (error || stdout); @@ -39,7 +39,7 @@ module.exports = async (client, guild, files) => { }; } }) - }, 60000) + }, 30000) setInterval(() => { const activity = activities[Math.floor(Math.random() * activities.length)]; From 5da7028d2d1236cf3dac2ac7aff114f6e2a49580 Mon Sep 17 00:00:00 2001 From: danielpmc Date: Fri, 30 Oct 2020 11:13:01 +0000 Subject: [PATCH 230/255] Added misc status --- Panel/bot/discord/events/ready.js | 3 +++ Panel/index.js | 16 ++++++++++++++++ Panel/package.json | 1 + 3 files changed, 20 insertions(+) diff --git a/Panel/bot/discord/events/ready.js b/Panel/bot/discord/events/ready.js index 6802c5309..a174469a7 100644 --- a/Panel/bot/discord/events/ready.js +++ b/Panel/bot/discord/events/ready.js @@ -74,6 +74,9 @@ module.exports = async (client, guild, files) => { //Misc status client.channels.get("757949242495991918").fetchMessage("771508453344673814").then(msg => { + const embed = new Discord.RichEmbed() + .setTitle(`__**Node Status**__ \n**Lavalink 1**: ${nodeStatus.get("lavalink1").status} \n**Lavalink 2**: ${nodeStatus.get("lavalink2").status} \n**Mail Server**: ${nodeStatus.get("mail").status} \n**Reverse Proxy**: ${nodeStatus.get("rproxy").status} \n**Panel Website**: ${nodeStatus.get("panel").status}`) + msg.edit(embed) }); }, 15000) diff --git a/Panel/index.js b/Panel/index.js index d1b6460a0..231c60214 100644 --- a/Panel/index.js +++ b/Panel/index.js @@ -18,6 +18,7 @@ const hbs = require('hbs'); global.chalk = require('chalk'); const nodemailer = require('nodemailer'); const axios = require('axios'); +var ping = require('ping'); global.transport = nodemailer.createTransport({ host: config.Email.Host, port: config.Email.Port, @@ -99,6 +100,21 @@ axios({ }); }) +var hosts = ['154.27.68.234', 'panel.danbot.host', 'mail.danbot.host', 'lava2.danbot.host:2333', 'lava.danbot.host:2333']; +hosts.forEach(function(host){ + ping.sys.probe(host, function(isAlive){ + if (isAlive == true) { + nodeStatus.set(host, { + status: "Online 🟢" + }) + } else if (isAlive == false) { + nodeStatus.set(host, { + status: "Offline 🔴" + }); + } + }); +}); + }, 5000) diff --git a/Panel/package.json b/Panel/package.json index ff52f987e..2bb09102e 100644 --- a/Panel/package.json +++ b/Panel/package.json @@ -45,6 +45,7 @@ "nodemailer": "^6.4.11", "passport": "^0.4.1", "passport-discord": "^0.1.4", + "ping": "^0.3.0", "prettysize": "^2.0.0", "proxmox": "^0.1.0", "pterodactyl.js": "^2.1.1", From fb0899aeca4cbf0f2e04c4f9f4debefb1156b28d Mon Sep 17 00:00:00 2001 From: danielpmc Date: Fri, 30 Oct 2020 11:16:16 +0000 Subject: [PATCH 231/255] Update ready.js --- Panel/bot/discord/events/ready.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Panel/bot/discord/events/ready.js b/Panel/bot/discord/events/ready.js index a174469a7..798b7d8d9 100644 --- a/Panel/bot/discord/events/ready.js +++ b/Panel/bot/discord/events/ready.js @@ -75,7 +75,7 @@ module.exports = async (client, guild, files) => { //Misc status client.channels.get("757949242495991918").fetchMessage("771508453344673814").then(msg => { const embed = new Discord.RichEmbed() - .setTitle(`__**Node Status**__ \n**Lavalink 1**: ${nodeStatus.get("lavalink1").status} \n**Lavalink 2**: ${nodeStatus.get("lavalink2").status} \n**Mail Server**: ${nodeStatus.get("mail").status} \n**Reverse Proxy**: ${nodeStatus.get("rproxy").status} \n**Panel Website**: ${nodeStatus.get("panel").status}`) + .setTitle(`__**Node Status**__ \n**Lavalink 1**: ${nodeStatus.get("lava.danbot.host").status} \n**Lavalink 2**: ${nodeStatus.get("lava2.danbot.host").status} \n**Mail Server**: ${nodeStatus.get("mail.danbot.host").status} \n**Reverse Proxy**: ${nodeStatus.get("154.27.68.234").status} \n**Panel Website**: ${nodeStatus.get("panel.danbot.host").status}`) msg.edit(embed) }); }, 15000) From 5d75ab866da7ae79892a4692c9d9a2673e88ec53 Mon Sep 17 00:00:00 2001 From: danielpmc Date: Fri, 30 Oct 2020 11:17:24 +0000 Subject: [PATCH 232/255] Update ready.js --- Panel/bot/discord/events/ready.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Panel/bot/discord/events/ready.js b/Panel/bot/discord/events/ready.js index 798b7d8d9..a32d54bf1 100644 --- a/Panel/bot/discord/events/ready.js +++ b/Panel/bot/discord/events/ready.js @@ -75,7 +75,7 @@ module.exports = async (client, guild, files) => { //Misc status client.channels.get("757949242495991918").fetchMessage("771508453344673814").then(msg => { const embed = new Discord.RichEmbed() - .setTitle(`__**Node Status**__ \n**Lavalink 1**: ${nodeStatus.get("lava.danbot.host").status} \n**Lavalink 2**: ${nodeStatus.get("lava2.danbot.host").status} \n**Mail Server**: ${nodeStatus.get("mail.danbot.host").status} \n**Reverse Proxy**: ${nodeStatus.get("154.27.68.234").status} \n**Panel Website**: ${nodeStatus.get("panel.danbot.host").status}`) + .setTitle(`__**Node Status**__ \n**Lavalink 1**: ${nodeStatus.get("lava.danbot.host:2333").status} \n**Lavalink 2**: ${nodeStatus.get("lava2.danbot.host:2333").status} \n**Mail Server**: ${nodeStatus.get("mail.danbot.host").status} \n**Reverse Proxy**: ${nodeStatus.get("154.27.68.234").status} \n**Panel Website**: ${nodeStatus.get("panel.danbot.host").status}`) msg.edit(embed) }); }, 15000) From 1ccfc157eb0a6f3cac2f4a787ec21aacc8293757 Mon Sep 17 00:00:00 2001 From: danielpmc Date: Fri, 30 Oct 2020 14:43:33 +0000 Subject: [PATCH 233/255] Change node names --- Panel/bot/discord/commands/server.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Panel/bot/discord/commands/server.js b/Panel/bot/discord/commands/server.js index 300ea248c..f8785a1cb 100644 --- a/Panel/bot/discord/commands/server.js +++ b/Panel/bot/discord/commands/server.js @@ -1425,7 +1425,7 @@ exports.run = async (client, message, args) => { const node = response.data.attributes.node; console.log(node) const port = response.data.attributes.relationships.allocations.data[0].attributes.port - if (node === "Node 1 - Discord Bots") { + if (node === "Node 1") { //Change Server IP setTimeout(() => { @@ -1454,7 +1454,7 @@ exports.run = async (client, message, args) => { } }, 100) //END - Change Server Port }, 100) //END - Change Server IP - } else if (node === "Node 2 - Discord Bots") { + } else if (node === "Node 2") { //Change Server IP setTimeout(() => { From 8a4539e25d8fad8ea050c614998f6967400e458f Mon Sep 17 00:00:00 2001 From: danielpmc Date: Fri, 30 Oct 2020 19:52:24 +0000 Subject: [PATCH 234/255] Add node 4 auto node status --- Panel/index.js | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/Panel/index.js b/Panel/index.js index 231c60214..3c63e180d 100644 --- a/Panel/index.js +++ b/Panel/index.js @@ -100,6 +100,27 @@ axios({ }); }) +//Node 4 +axios({ + url: config.Pterodactyl.hosturl + "/api/client/servers/98ca4dbd/resources", + method: 'GET', + followRedirect: true, + maxRedirects: 5, + headers: { + 'Authorization': 'Bearer ' + config.Pterodactyl.apikeyclient, + 'Content-Type': 'application/json', + 'Accept': 'Application/vnd.pterodactyl.v1+json', + } +}).then(response => { + nodeStatus.set("node4", { + status: "Online 🟢" + }); +}).catch(error => { + nodeStatus.set("node4", { + status: "Offline 🔴" + }); +}) + var hosts = ['154.27.68.234', 'panel.danbot.host', 'mail.danbot.host', 'lava2.danbot.host:2333', 'lava.danbot.host:2333']; hosts.forEach(function(host){ ping.sys.probe(host, function(isAlive){ From 86c67e87666301b9d7159d16a241a136d95a34ba Mon Sep 17 00:00:00 2001 From: danielpmc Date: Fri, 30 Oct 2020 20:07:43 +0000 Subject: [PATCH 235/255] lavalink pinger --- Panel/bot/discord/events/ready.js | 2 +- Panel/index.js | 19 ++++++++++++++++++- Panel/package.json | 4 ++-- 3 files changed, 21 insertions(+), 4 deletions(-) diff --git a/Panel/bot/discord/events/ready.js b/Panel/bot/discord/events/ready.js index a32d54bf1..e04edf468 100644 --- a/Panel/bot/discord/events/ready.js +++ b/Panel/bot/discord/events/ready.js @@ -75,7 +75,7 @@ module.exports = async (client, guild, files) => { //Misc status client.channels.get("757949242495991918").fetchMessage("771508453344673814").then(msg => { const embed = new Discord.RichEmbed() - .setTitle(`__**Node Status**__ \n**Lavalink 1**: ${nodeStatus.get("lava.danbot.host:2333").status} \n**Lavalink 2**: ${nodeStatus.get("lava2.danbot.host:2333").status} \n**Mail Server**: ${nodeStatus.get("mail.danbot.host").status} \n**Reverse Proxy**: ${nodeStatus.get("154.27.68.234").status} \n**Panel Website**: ${nodeStatus.get("panel.danbot.host").status}`) + .setTitle(`__**Misc Status**__ \n**Lavalink 1**: ${nodeStatus.get("lava.danbot.host:2333").status} \n**Lavalink 2**: ${nodeStatus.get("lava2.danbot.host:2333").status} \n**Mail Server**: ${nodeStatus.get("mail.danbot.host").status} \n**Reverse Proxy**: ${nodeStatus.get("154.27.68.234").status} \n**Panel Website**: ${nodeStatus.get("panel.danbot.host").status}`) msg.edit(embed) }); }, 15000) diff --git a/Panel/index.js b/Panel/index.js index 3c63e180d..652bb589e 100644 --- a/Panel/index.js +++ b/Panel/index.js @@ -19,6 +19,7 @@ global.chalk = require('chalk'); const nodemailer = require('nodemailer'); const axios = require('axios'); var ping = require('ping'); +const ping2 = require('ping-tcp-js') global.transport = nodemailer.createTransport({ host: config.Email.Host, port: config.Email.Port, @@ -121,7 +122,7 @@ axios({ }); }) -var hosts = ['154.27.68.234', 'panel.danbot.host', 'mail.danbot.host', 'lava2.danbot.host:2333', 'lava.danbot.host:2333']; +var hosts = ['154.27.68.234', 'panel.danbot.host', 'mail.danbot.host']; hosts.forEach(function(host){ ping.sys.probe(host, function(isAlive){ if (isAlive == true) { @@ -136,6 +137,22 @@ hosts.forEach(function(host){ }); }); +const portz = 2333; + +//Lavalink Server 1 +const hostz = 'lava.danbot.host'; +ping2 + .ping(hostz, portz) + .then(() => nodeStatus.set(hostz), { status: "Online 🟢" }) + .catch((e) => nodeStatus.set(hostz), { status: "Offline 🔴" }); + +//Lavalink Server 2 +const hostz2 = 'lava2.danbot.host'; +ping2 + .ping(hostz2, portz) + .then(() => nodeStatus.set(hostz), { status: "Online 🟢" }) + .catch((e) => nodeStatus.set(hostz), { status: "Offline 🔴" }); + }, 5000) diff --git a/Panel/package.json b/Panel/package.json index 2bb09102e..a0dc4510e 100644 --- a/Panel/package.json +++ b/Panel/package.json @@ -17,6 +17,7 @@ }, "homepage": "https://github.com/danbot-devs/DanBotHostingStats#readme", "dependencies": { + "axios": "^0.21.0", "body-parser": "latest", "canvas": "^2.6.1", "chalk": "^3.0.0", @@ -40,12 +41,11 @@ "node-proxmox": "^0.1.2", "node-ssh": "^11.1.1", "node-tesseract-ocr": "^2.0.0", - "nodeactyl": "^2.0.0", - "nodeactyl-beta": "0.0.10", "nodemailer": "^6.4.11", "passport": "^0.4.1", "passport-discord": "^0.1.4", "ping": "^0.3.0", + "ping-tcp-js": "^1.3.0", "prettysize": "^2.0.0", "proxmox": "^0.1.0", "pterodactyl.js": "^2.1.1", From 09bbd102f73badd5d90a3b215f47a6748b4003e6 Mon Sep 17 00:00:00 2001 From: danielpmc Date: Fri, 30 Oct 2020 20:09:31 +0000 Subject: [PATCH 236/255] Update ready.js --- Panel/bot/discord/events/ready.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Panel/bot/discord/events/ready.js b/Panel/bot/discord/events/ready.js index e04edf468..7dae55423 100644 --- a/Panel/bot/discord/events/ready.js +++ b/Panel/bot/discord/events/ready.js @@ -75,7 +75,7 @@ module.exports = async (client, guild, files) => { //Misc status client.channels.get("757949242495991918").fetchMessage("771508453344673814").then(msg => { const embed = new Discord.RichEmbed() - .setTitle(`__**Misc Status**__ \n**Lavalink 1**: ${nodeStatus.get("lava.danbot.host:2333").status} \n**Lavalink 2**: ${nodeStatus.get("lava2.danbot.host:2333").status} \n**Mail Server**: ${nodeStatus.get("mail.danbot.host").status} \n**Reverse Proxy**: ${nodeStatus.get("154.27.68.234").status} \n**Panel Website**: ${nodeStatus.get("panel.danbot.host").status}`) + .setTitle(`__**Misc Status**__ \n**Lavalink 1**: ${nodeStatus.get("lava.danbot.host").status} \n**Lavalink 2**: ${nodeStatus.get("lava2.danbot.host").status} \n**Mail Server**: ${nodeStatus.get("mail.danbot.host").status} \n**Reverse Proxy**: ${nodeStatus.get("154.27.68.234").status} \n**Panel Website**: ${nodeStatus.get("panel.danbot.host").status}`) msg.edit(embed) }); }, 15000) From d0dbcf3127a7839f17c34e731dc8160bcb4833fd Mon Sep 17 00:00:00 2001 From: danielpmc Date: Fri, 30 Oct 2020 20:12:05 +0000 Subject: [PATCH 237/255] Update index.js --- Panel/index.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Panel/index.js b/Panel/index.js index 652bb589e..2a6dd6abf 100644 --- a/Panel/index.js +++ b/Panel/index.js @@ -143,15 +143,15 @@ const portz = 2333; const hostz = 'lava.danbot.host'; ping2 .ping(hostz, portz) - .then(() => nodeStatus.set(hostz), { status: "Online 🟢" }) - .catch((e) => nodeStatus.set(hostz), { status: "Offline 🔴" }); + .then(() => nodeStatus.set("lava.danbot.host"), { status: "Online 🟢" }) + .catch((e) => nodeStatus.set("lava.danbot.host"), { status: "Offline 🔴" }); //Lavalink Server 2 const hostz2 = 'lava2.danbot.host'; ping2 .ping(hostz2, portz) - .then(() => nodeStatus.set(hostz), { status: "Online 🟢" }) - .catch((e) => nodeStatus.set(hostz), { status: "Offline 🔴" }); + .then(() => nodeStatus.set("lava2.danbot.host"), { status: "Online 🟢" }) + .catch((e) => nodeStatus.set("lava2.danbot.host"), { status: "Offline 🔴" }); }, 5000) From 695f9346b8b0960d1ba5a107a0f1eebed687f6d2 Mon Sep 17 00:00:00 2001 From: danielpmc Date: Fri, 30 Oct 2020 20:15:32 +0000 Subject: [PATCH 238/255] Update index.js --- Panel/index.js | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/Panel/index.js b/Panel/index.js index 2a6dd6abf..4efc8076d 100644 --- a/Panel/index.js +++ b/Panel/index.js @@ -143,15 +143,23 @@ const portz = 2333; const hostz = 'lava.danbot.host'; ping2 .ping(hostz, portz) - .then(() => nodeStatus.set("lava.danbot.host"), { status: "Online 🟢" }) - .catch((e) => nodeStatus.set("lava.danbot.host"), { status: "Offline 🔴" }); + .then(() => nodeStatus.set("lava.danbot.host"), { + status: "Online 🟢" + }) + .catch((e) => nodeStatus.set("lava.danbot.host"), { + status: "Offline 🔴" + }); //Lavalink Server 2 const hostz2 = 'lava2.danbot.host'; ping2 .ping(hostz2, portz) - .then(() => nodeStatus.set("lava2.danbot.host"), { status: "Online 🟢" }) - .catch((e) => nodeStatus.set("lava2.danbot.host"), { status: "Offline 🔴" }); + .then(() => nodeStatus.set("lava2.danbot.host"), { + status: "Online 🟢" + }) + .catch((e) => nodeStatus.set("lava2.danbot.host"), { + status: "Offline 🔴" + }); }, 5000) From 7f69aec55a6ba90a61a89b1f7b42ee05a3aa0f21 Mon Sep 17 00:00:00 2001 From: danielpmc Date: Fri, 30 Oct 2020 22:22:35 +0000 Subject: [PATCH 239/255] Update index.js --- Panel/index.js | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/Panel/index.js b/Panel/index.js index 4efc8076d..c537e9cc2 100644 --- a/Panel/index.js +++ b/Panel/index.js @@ -143,23 +143,23 @@ const portz = 2333; const hostz = 'lava.danbot.host'; ping2 .ping(hostz, portz) - .then(() => nodeStatus.set("lava.danbot.host"), { + .then(() => nodeStatus.set("lava.danbot.host", { status: "Online 🟢" - }) - .catch((e) => nodeStatus.set("lava.danbot.host"), { + })) + .catch((e) => nodeStatus.set("lava.danbot.host", { status: "Offline 🔴" - }); + })); //Lavalink Server 2 const hostz2 = 'lava2.danbot.host'; ping2 .ping(hostz2, portz) - .then(() => nodeStatus.set("lava2.danbot.host"), { + .then(() => nodeStatus.set("lava2.danbot.host", { status: "Online 🟢" - }) - .catch((e) => nodeStatus.set("lava2.danbot.host"), { + }), console.log('test')) + .catch((e) => nodeStatus.set("lava2.danbot.host", { status: "Offline 🔴" - }); + })); }, 5000) From 2d41cac3f1c89b519f409d28e30f19ab0b2f5167 Mon Sep 17 00:00:00 2001 From: danielpmc Date: Sat, 31 Oct 2020 10:44:07 +0000 Subject: [PATCH 240/255] Update server.js --- Panel/bot/discord/commands/server.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Panel/bot/discord/commands/server.js b/Panel/bot/discord/commands/server.js index f8785a1cb..1f754e265 100644 --- a/Panel/bot/discord/commands/server.js +++ b/Panel/bot/discord/commands/server.js @@ -1512,7 +1512,7 @@ exports.run = async (client, message, args) => { */ }) } else { - message.channel.send('Error making SSL cert. Either the domain is not pointing to `154.27.68.234` or cloudflare proxy is enabled! \n\n**If you have just done this after running the command. Please give the bot 5 - 10mins to refresh the DNS cache**') + message.channel.send('Error making SSL cert. Either the domain is not pointing to `154.27.68.234` or cloudflare proxy is enabled! \n\n**If you have just done this after running the command. Please give the bot 5 - 10mins to refresh the DNS cache** \n\nFull Error: ```' + result.stdout + '```') ssh.execCommand(`service apache2 start`, { cwd:'/root' }) fs.unlinkSync("./proxy/" + args[1] + ".conf"); } From a1d39ea10214948711f7b7fc023790102e715515 Mon Sep 17 00:00:00 2001 From: danielpmc Date: Sat, 31 Oct 2020 10:50:51 +0000 Subject: [PATCH 241/255] remove OCR for now --- Panel/bot/discord/events/message.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/Panel/bot/discord/events/message.js b/Panel/bot/discord/events/message.js index 53d71ae2b..5205b6292 100644 --- a/Panel/bot/discord/events/message.js +++ b/Panel/bot/discord/events/message.js @@ -14,7 +14,7 @@ module.exports = (client, message) => { message.guild.members.get(message.author.id).removeRole(muteRole) } - +/* if (message.attachments.size > 0) { if (message.attachments.every(attachIsImage)) { const Tesseract = require("tesseract.js") @@ -50,8 +50,9 @@ module.exports = (client, message) => { function attachIsImage(msgAttach) { var url = msgAttach.url; //True if this url is a png image. - return url.indexOf("png", url.length - "png".length /*or 3*/ ) !== -1; - } + return url.indexOf("png", url.length - "png".length /*or 3*/// ) !== -1; + // } + if (message.channel.type == "dm") { if (message.author.id == "137624084572798976") { From 06b0e0759c052f856d9f2dd2a4690173b5157c07 Mon Sep 17 00:00:00 2001 From: danielpmc Date: Sat, 31 Oct 2020 16:08:09 +0000 Subject: [PATCH 242/255] Update server.js --- Panel/bot/discord/commands/server.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Panel/bot/discord/commands/server.js b/Panel/bot/discord/commands/server.js index 1f754e265..aa5a55335 100644 --- a/Panel/bot/discord/commands/server.js +++ b/Panel/bot/discord/commands/server.js @@ -1262,6 +1262,8 @@ exports.run = async (client, message, args) => { }); }); } + } else if (args[0].toLowerCase() == "unproxy") { + //Remove proxy } else if (args[0].toLowerCase() == "manage") { message.channel.send('Uh this isnt done yet...') } else if (args[0] == "list") { @@ -1382,7 +1384,7 @@ exports.run = async (client, message, args) => { }) //Copy template file. Ready to be changed! - fs.access(path.resolve(path.dirname(require.main.filename), "proxy/" + args[1] + ".conf"), fs.constants.R_OK, (err) => { + fs.access(path.resolve(path.dirname(require.main.filename), "proxy/" + args[1].toLowerCase() + ".conf"), fs.constants.R_OK, (err) => { if (!err) { return message.channel.send("This domain has been linked before or is currently linked..") } else { @@ -1404,7 +1406,7 @@ exports.run = async (client, message, args) => { const domainchange = rif.sync({ files: '/root/DBH/Panel/proxy/' + args[1] + '.conf', from: "REPLACE-DOMAIN", - to: args[1], + to: args[1].toLowerCase(), countMatches: true, }); z++ From 0c15d52c0d8d21a4d5c65ff1ff51cf8d5fdb2427 Mon Sep 17 00:00:00 2001 From: danielpmc Date: Sat, 31 Oct 2020 22:46:59 +0000 Subject: [PATCH 243/255] Update server.js --- Panel/bot/discord/commands/server.js | 53 ++++++++-------------------- 1 file changed, 15 insertions(+), 38 deletions(-) diff --git a/Panel/bot/discord/commands/server.js b/Panel/bot/discord/commands/server.js index aa5a55335..409a2d819 100644 --- a/Panel/bot/discord/commands/server.js +++ b/Panel/bot/discord/commands/server.js @@ -1270,26 +1270,8 @@ exports.run = async (client, message, args) => { message.channel.send('Loading servers...') //List servers var arr = []; - - axios({ - url: "https://panel.danbot.host" + "/api/application/servers", - method: 'GET', - followRedirect: true, - maxRedirects: 5, - headers: { - 'Authorization': 'Bearer ' + config.Pterodactyl.apikey, - 'Content-Type': 'application/json', - 'Accept': 'Application/vnd.pterodactyl.v1+json', - } - }).then(resources => { - var countmax = resources.data.meta.pagination.total_pages - var i2 = countmax++ - - var i = 0 - while (i { 'Accept': 'Application/vnd.pterodactyl.v1+json', } }).then(response => { + const preoutput = response.data.attributes.relationships.servers.data //console.log(resources.data.meta) - arr.push(...response.data.data) + arr.push(...preoutput) + setTimeout(async () => { + //console.log(arr.length) + console.log(arr) + const output = await preoutput.filter(usr => usr.attributes ? usr.attributes.user == userData.get(message.author.id).consoleID : false) + setTimeout(() => { + var clean = arr.flatMap(e => "Server Name: `" + e.attributes.name + "`, Server ID: `" + e.attributes.identifier + "`\n") + const embed = new Discord.RichEmbed() + .addField('__**Your Servers:**__', clean) + message.channel.send(embed) + //console.log(output) + },500) + }, 5000) }); - i++ - } - console.log(resources.data.meta.pagination) - var total = resources.data.meta.pagination.total - }); - - setTimeout(async () => { - //console.log(arr.length) - const output = await arr.filter(usr => usr.attributes ? usr.attributes.user == userData.get(message.author.id).consoleID : false) - setTimeout(() => { - var clean = output.map(e => "`" + e.attributes.name + "` Server ID: `" + e.attributes.identifier + "`\n") - var clean2 = clean.toString().replace(/^\s+|\s+$/g,'') - const embed = new Discord.RichEmbed() - .addField('__**Your Servers:**__', "Server Name: \n" + clean2) - message.channel.send(embed) - //console.log(output) - },500) - }, 10000) } else if (args[0].toLowerCase() == "status") { if (!args[1]) { let embed = new Discord.RichEmbed() From 3e636b72f74314ed2d92e3d5f7fddf99ffa4eef2 Mon Sep 17 00:00:00 2001 From: danielpmc Date: Sat, 31 Oct 2020 22:50:01 +0000 Subject: [PATCH 244/255] Update server.js --- Panel/bot/discord/commands/server.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Panel/bot/discord/commands/server.js b/Panel/bot/discord/commands/server.js index 409a2d819..7a462f57d 100644 --- a/Panel/bot/discord/commands/server.js +++ b/Panel/bot/discord/commands/server.js @@ -1287,9 +1287,8 @@ exports.run = async (client, message, args) => { setTimeout(async () => { //console.log(arr.length) console.log(arr) - const output = await preoutput.filter(usr => usr.attributes ? usr.attributes.user == userData.get(message.author.id).consoleID : false) setTimeout(() => { - var clean = arr.flatMap(e => "Server Name: `" + e.attributes.name + "`, Server ID: `" + e.attributes.identifier + "`\n") + var clean = arr.map(e => "Server Name: `" + e.attributes.name + "`, Server ID: `" + e.attributes.identifier + "`\n") const embed = new Discord.RichEmbed() .addField('__**Your Servers:**__', clean) message.channel.send(embed) From e10bd585392c8aeceeb2078478aae95836b1e695 Mon Sep 17 00:00:00 2001 From: danielpmc Date: Sat, 31 Oct 2020 23:12:12 +0000 Subject: [PATCH 245/255] Update index.js --- Panel/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Panel/index.js b/Panel/index.js index c537e9cc2..9389de94c 100644 --- a/Panel/index.js +++ b/Panel/index.js @@ -156,7 +156,7 @@ ping2 .ping(hostz2, portz) .then(() => nodeStatus.set("lava2.danbot.host", { status: "Online 🟢" - }), console.log('test')) + })) .catch((e) => nodeStatus.set("lava2.danbot.host", { status: "Offline 🔴" })); From d56cad958549a2fea7846e2d7e692bf7de7d65d2 Mon Sep 17 00:00:00 2001 From: danielpmc Date: Sun, 1 Nov 2020 21:52:12 +0000 Subject: [PATCH 246/255] Update server.js --- Panel/bot/discord/commands/server.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Panel/bot/discord/commands/server.js b/Panel/bot/discord/commands/server.js index 7a462f57d..ec98bf677 100644 --- a/Panel/bot/discord/commands/server.js +++ b/Panel/bot/discord/commands/server.js @@ -1472,7 +1472,7 @@ exports.run = async (client, message, args) => { ssh.putFile('/root/DBH/Panel/proxy/' + args[1] + '.conf', '/etc/apache2/sites-available/' + args[1] + ".conf").then(function() { //Run command to genate SSL cert. - ssh.execCommand(`service apache2 stop && certbot certonly -d ${args[1]} --standalone --non-interactive --agree-tos -m danielpd93@gmail.com`, { cwd:'/root' }).then(function(result) { + ssh.execCommand(`certbot certonly -d ${args[1]} --standalone --non-interactive --webroot-path /var/www/html --agree-tos -m danielpd93@gmail.com`, { cwd:'/root' }).then(function(result) { if (result.stdout.includes('Congratulations!')) { //No error. Continue to enable site on apache2 then restart console.log('SSL Gen complete. Continue!') @@ -1491,7 +1491,6 @@ exports.run = async (client, message, args) => { }) } else { message.channel.send('Error making SSL cert. Either the domain is not pointing to `154.27.68.234` or cloudflare proxy is enabled! \n\n**If you have just done this after running the command. Please give the bot 5 - 10mins to refresh the DNS cache** \n\nFull Error: ```' + result.stdout + '```') - ssh.execCommand(`service apache2 start`, { cwd:'/root' }) fs.unlinkSync("./proxy/" + args[1] + ".conf"); } }) From bd322d560456c48ad29e28f30490a72debe31763 Mon Sep 17 00:00:00 2001 From: danielpmc Date: Sun, 1 Nov 2020 22:11:49 +0000 Subject: [PATCH 247/255] Update server.js --- Panel/bot/discord/commands/server.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Panel/bot/discord/commands/server.js b/Panel/bot/discord/commands/server.js index ec98bf677..3b0a2be21 100644 --- a/Panel/bot/discord/commands/server.js +++ b/Panel/bot/discord/commands/server.js @@ -1472,7 +1472,7 @@ exports.run = async (client, message, args) => { ssh.putFile('/root/DBH/Panel/proxy/' + args[1] + '.conf', '/etc/apache2/sites-available/' + args[1] + ".conf").then(function() { //Run command to genate SSL cert. - ssh.execCommand(`certbot certonly -d ${args[1]} --standalone --non-interactive --webroot-path /var/www/html --agree-tos -m danielpd93@gmail.com`, { cwd:'/root' }).then(function(result) { + ssh.execCommand(`certbot certonly -d ${args[1]} --non-interactive --webroot --webroot-path /var/www/html --agree-tos -m danielpd93@gmail.com`, { cwd:'/root' }).then(function(result) { if (result.stdout.includes('Congratulations!')) { //No error. Continue to enable site on apache2 then restart console.log('SSL Gen complete. Continue!') From 9b85574e462ac10ca7bf578d8395de87a3ffd89f Mon Sep 17 00:00:00 2001 From: danielpmc Date: Sun, 1 Nov 2020 23:37:10 +0000 Subject: [PATCH 248/255] Changed timeout on status pings --- Panel/bot/discord/commands/staff.js | 6 +++--- Panel/index.js | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Panel/bot/discord/commands/staff.js b/Panel/bot/discord/commands/staff.js index 8fe489dc8..7a54b5f44 100644 --- a/Panel/bot/discord/commands/staff.js +++ b/Panel/bot/discord/commands/staff.js @@ -9,7 +9,7 @@ exports.run = async (client, message, args) => { let embed = new Discord.RichEmbed() .setColor('RANDOM') .addField('**Staff Commands:**', config.DiscordBot.Prefix + "staff linked useridhere | Shows if the users account is linked.") - .addField('**Admin Commands:**', config.DiscordBot.Prefix + "staff apply open/closed | Open or close staff applications. \n" + config.DiscordBot.Prefix + "staff settings | Shows current website settings") + .addField('**Admin Commands:**', config.DiscordBot.Prefix + "staff apply open/close | Open or close staff applications. \n" + config.DiscordBot.Prefix + "staff settings | Shows current website settings") .addField('**Owner Commands:**', config.DiscordBot.Prefix + "staff maintenance on/off | Enable or disable website maintenance. \n" + config.DiscordBot.Prefix + "staff update | Pulls updates from GitHub") message.channel.send(embed) } else { @@ -59,9 +59,9 @@ exports.run = async (client, message, args) => { message.channel.send("Staff applications now closed") } else { if (webSettings.fetch("staff-applications.enabled") == "true") { - message.channel.send("Please run the command using the following format: `" + config.DiscordBot.Prefix + "staff apply open/closed` to enable or disable staff applications \n**Staff applications are currently:** **OPEN**"); + message.channel.send("Please run the command using the following format: `" + config.DiscordBot.Prefix + "staff apply open/close` to enable or disable staff applications \n**Staff applications are currently:** **OPEN**"); } else if (webSettings.fetch("staff-applications.enabled") == "false") { - message.channel.send("Please run the command using the following format: `" + config.DiscordBot.Prefix + "staff apply open/closed` to enable or disable staff applications \n**Staff applications are currently:** **CLOSED**"); + message.channel.send("Please run the command using the following format: `" + config.DiscordBot.Prefix + "staff apply open/close` to enable or disable staff applications \n**Staff applications are currently:** **CLOSED**"); } }; }; diff --git a/Panel/index.js b/Panel/index.js index 9389de94c..f76a7da01 100644 --- a/Panel/index.js +++ b/Panel/index.js @@ -135,7 +135,7 @@ hosts.forEach(function(host){ }); } }); -}); +}, { timeout: 10 }); const portz = 2333; From c73e71f89ef562f75654379fa00e03ebe96d2f68 Mon Sep 17 00:00:00 2001 From: danielpmc Date: Sun, 1 Nov 2020 23:37:25 +0000 Subject: [PATCH 249/255] Update index.js --- Panel/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Panel/index.js b/Panel/index.js index f76a7da01..d465d99ba 100644 --- a/Panel/index.js +++ b/Panel/index.js @@ -135,7 +135,7 @@ hosts.forEach(function(host){ }); } }); -}, { timeout: 10 }); +}, { timeout: 4 }); const portz = 2333; From f79a901d79fc78b5140776bedd944a11cc2f13cf Mon Sep 17 00:00:00 2001 From: danielpmc Date: Sun, 1 Nov 2020 23:52:23 +0000 Subject: [PATCH 250/255] Random space lmao --- Panel/bot/discord/commands/server.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Panel/bot/discord/commands/server.js b/Panel/bot/discord/commands/server.js index 3b0a2be21..7fefaeb3a 100644 --- a/Panel/bot/discord/commands/server.js +++ b/Panel/bot/discord/commands/server.js @@ -1262,8 +1262,6 @@ exports.run = async (client, message, args) => { }); }); } - } else if (args[0].toLowerCase() == "unproxy") { - //Remove proxy } else if (args[0].toLowerCase() == "manage") { message.channel.send('Uh this isnt done yet...') } else if (args[0] == "list") { @@ -1472,7 +1470,7 @@ exports.run = async (client, message, args) => { ssh.putFile('/root/DBH/Panel/proxy/' + args[1] + '.conf', '/etc/apache2/sites-available/' + args[1] + ".conf").then(function() { //Run command to genate SSL cert. - ssh.execCommand(`certbot certonly -d ${args[1]} --non-interactive --webroot --webroot-path /var/www/html --agree-tos -m danielpd93@gmail.com`, { cwd:'/root' }).then(function(result) { + ssh.execCommand(`certbot certonly -d ${args[1]} --non-interactive --webroot --webroot-path /var/www/html --agree-tos -m danielpd93@gmail.com`, { cwd:'/root' }).then(function(result) { if (result.stdout.includes('Congratulations!')) { //No error. Continue to enable site on apache2 then restart console.log('SSL Gen complete. Continue!') @@ -1506,6 +1504,8 @@ exports.run = async (client, message, args) => { }) } } + } else if (args[0].toLowerCase() == "unproxy") { + //Remove proxy } - }; + } }; \ No newline at end of file From 02b7afa88930008d4eba8b5895034635988ca58a Mon Sep 17 00:00:00 2001 From: danielpmc Date: Sun, 1 Nov 2020 23:58:25 +0000 Subject: [PATCH 251/255] Added DBH!server unproxy --- Panel/bot/discord/commands/server.js | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/Panel/bot/discord/commands/server.js b/Panel/bot/discord/commands/server.js index 7fefaeb3a..e9bd9b413 100644 --- a/Panel/bot/discord/commands/server.js +++ b/Panel/bot/discord/commands/server.js @@ -1505,7 +1505,26 @@ exports.run = async (client, message, args) => { } } } else if (args[0].toLowerCase() == "unproxy") { - //Remove proxy + if (!args[1]) { + const embed = new Discord.RichEmbed() + .setTitle('__**How to remove a domain from a server**__ \nCommand format: ' + config.DiscordBot.Prefix + 'server unproxy domainhere') + message.channel.send(embed) + } else { + + //SSH Connection + ssh.connect({ + host: config.SSH.Host, + username: config.SSH.User, + port: config.SSH.Port, + password: config.SSH.Password, + tryKeyboard: true, + }) + + //Delete file from apache2 dir + ssh.execCommand('a2dissite ' + args[1] + ' && rm /etc/apache2/sites-available/' + args[1] + '.conf && rm -rf /etc/letsencrypt/live/' + args[1] + ' && rm -rf /etc/letsencrypt/archive' + args[1], { cwd:'/root' }) + fs.unlinkSync("./proxy/" + args[1] + ".conf"); + + } } } }; \ No newline at end of file From cf3de03d5a9122c46b62262f7dcfc22e6d7bf6ad Mon Sep 17 00:00:00 2001 From: danielpmc Date: Mon, 2 Nov 2020 00:02:10 +0000 Subject: [PATCH 252/255] Update server.js --- Panel/bot/discord/commands/server.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Panel/bot/discord/commands/server.js b/Panel/bot/discord/commands/server.js index e9bd9b413..805cf5289 100644 --- a/Panel/bot/discord/commands/server.js +++ b/Panel/bot/discord/commands/server.js @@ -1521,9 +1521,9 @@ exports.run = async (client, message, args) => { }) //Delete file from apache2 dir - ssh.execCommand('a2dissite ' + args[1] + ' && rm /etc/apache2/sites-available/' + args[1] + '.conf && rm -rf /etc/letsencrypt/live/' + args[1] + ' && rm -rf /etc/letsencrypt/archive' + args[1], { cwd:'/root' }) + ssh.execCommand('a2dissite ' + args[1] + ' && rm /etc/apache2/sites-available/' + args[1] + '.conf && rm -rf /etc/letsencrypt/live/' + args[1] + ' && rm -rf /etc/letsencrypt/archive' + args[1] + '&& service apache2 restart', { cwd:'/root' }) fs.unlinkSync("./proxy/" + args[1] + ".conf"); - + message.channel.send('Proxy has been removed from ' + args[1]) } } } From b904b94fbe4f97168ea8af817506c8637ff9cc2e Mon Sep 17 00:00:00 2001 From: danielpmc Date: Mon, 2 Nov 2020 00:05:34 +0000 Subject: [PATCH 253/255] Update server.js --- Panel/bot/discord/commands/server.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Panel/bot/discord/commands/server.js b/Panel/bot/discord/commands/server.js index 805cf5289..61689debf 100644 --- a/Panel/bot/discord/commands/server.js +++ b/Panel/bot/discord/commands/server.js @@ -1505,6 +1505,7 @@ exports.run = async (client, message, args) => { } } } else if (args[0].toLowerCase() == "unproxy") { + if (message.author.id == "137624084572798976") { if (!args[1]) { const embed = new Discord.RichEmbed() .setTitle('__**How to remove a domain from a server**__ \nCommand format: ' + config.DiscordBot.Prefix + 'server unproxy domainhere') @@ -1525,6 +1526,9 @@ exports.run = async (client, message, args) => { fs.unlinkSync("./proxy/" + args[1] + ".conf"); message.channel.send('Proxy has been removed from ' + args[1]) } + } else { + message.channel.send('command temp disabled') + } } } }; \ No newline at end of file From a9e3d56bfb899ef7dc1f64536f61978fda1b7b2e Mon Sep 17 00:00:00 2001 From: danielpmc Date: Mon, 2 Nov 2020 03:14:54 +0000 Subject: [PATCH 254/255] added api --- Panel/bot/discord/commands/mute.js | 2 +- Panel/routes/index.js | 20 ++++++++++++++++++++ 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/Panel/bot/discord/commands/mute.js b/Panel/bot/discord/commands/mute.js index 112fad974..49620cd70 100644 --- a/Panel/bot/discord/commands/mute.js +++ b/Panel/bot/discord/commands/mute.js @@ -39,7 +39,7 @@ exports.run = async (client, message, args) => { mutesData.set(user.user.id, { muted: "true", muteTime: Date.now(), - mutedLength: messagez + mutedLength: messagez * 60000 }); message.channel.send("***The user has been successfully muted for " + messagez + " minute(s) :white_check_mark:***") if (!modlog) { diff --git a/Panel/routes/index.js b/Panel/routes/index.js index 2b621d8f6..2bff36beb 100644 --- a/Panel/routes/index.js +++ b/Panel/routes/index.js @@ -30,6 +30,26 @@ Router.get("/Node4", (req, res) => { res.redirect("/stats/Node4"); }); +//Node status json format +Router.get("/nodeStatus", (req, res) => { + let data = { + nodestatus: { + Node1: nodeStatus.fetch("node1").status, + Node2: nodeStatus.fetch("node2").status, + Node3: nodeStatus.fetch("node3").status, + Node4: nodeStatus.fetch("node4").status + }, + misc: { + Lava1: nodeStatus.fetch("lava.danbot.host").status, + Lava2: nodeStatus.fetch("lava2.danbot.host").status, + Mail: nodeStatus.fetch("mail.danbot.host").status, + RProxy: nodeStatus.fetch("154.27.68.234").status, + Panel: nodeStatus.fetch("panel.danbot.host").status + } + }; + + res.json(data); +}); Router.get("/bots", (req, res) => { From ea3921df641f22536ebed3e7e19d6628531e53de Mon Sep 17 00:00:00 2001 From: HyptexPvP <63811460+HyptexPvP@users.noreply.github.com> Date: Mon, 2 Nov 2020 09:12:16 -0500 Subject: [PATCH 255/255] Update server.js --- Panel/bot/discord/commands/server.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Panel/bot/discord/commands/server.js b/Panel/bot/discord/commands/server.js index 61689debf..91f37a26c 100644 --- a/Panel/bot/discord/commands/server.js +++ b/Panel/bot/discord/commands/server.js @@ -90,6 +90,7 @@ exports.run = async (client, message, args) => { .addField(`__**FAILED:**__`, "Please contact a host admin. \n\nError: `" + error + "`") message.channel.send(embed1) message.channel.send("<@137624084572798976> Issue when creating server. \nResponse: `" + error + "`") + message.channel.send("This **could** mean Ports are full, Panel is down, Node is out of resources") }) } @@ -1531,4 +1532,4 @@ exports.run = async (client, message, args) => { } } } -}; \ No newline at end of file +};