summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRaindropsSys <contact@minteck.org>2023-06-30 15:28:11 +0200
committerRaindropsSys <contact@minteck.org>2023-06-30 15:28:11 +0200
commit2efa6cd8882e450ace2c53e0d43c49633412290b (patch)
treebd48d6a2129ad057c35788e763e502f44570ad6e
parent34adf049559a8a8604dfeb5d9ce8f297119cfcf2 (diff)
downloadbutterscotch-2efa6cd8882e450ace2c53e0d43c49633412290b.tar.gz
butterscotch-2efa6cd8882e450ace2c53e0d43c49633412290b.tar.bz2
butterscotch-2efa6cd8882e450ace2c53e0d43c49633412290b.zip
Updated 5 files and added 9 files (automated)
-rw-r--r--.idea/discord.xml2
-rw-r--r--commands/eval.js30
-rw-r--r--commands/help.js53
-rw-r--r--commands/mem.js33
-rw-r--r--commands/meval.js19
-rw-r--r--commands/reset.js20
-rw-r--r--commands/xeval.js19
-rw-r--r--help/_categories.json8
-rw-r--r--help/eval.json2
-rw-r--r--help/mem.json6
-rw-r--r--help/meval.json6
-rw-r--r--help/reset.json6
-rw-r--r--help/xeval.json6
-rw-r--r--index.js1
14 files changed, 179 insertions, 32 deletions
diff --git a/.idea/discord.xml b/.idea/discord.xml
index 30bab2a..d8e9561 100644
--- a/.idea/discord.xml
+++ b/.idea/discord.xml
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="DiscordProjectSettings">
- <option name="show" value="ASK" />
+ <option name="show" value="PROJECT_FILES" />
<option name="description" value="" />
</component>
</project> \ No newline at end of file
diff --git a/commands/eval.js b/commands/eval.js
index 2d44252..761b03d 100644
--- a/commands/eval.js
+++ b/commands/eval.js
@@ -1,20 +1,34 @@
+const vm = require('vm');
+
module.exports = (parameter, wrapper) => {
- if (wrapper.sender !== "@raindrops:equestria.dev" && wrapper.sender !== "493845599469174794") {
- wrapper.send("⛔️ This command is private and you are not allowed to use it.");
- return;
+ let start = new Date();
+
+ function userToUUID(user) {
+ const crypto = require('crypto');
+ let hash = crypto.createHash("sha1").update(user).digest("hex");
+ return hash.substring(0, 8) + "-" + hash.substring(8, 12) + "-4" + hash.substring(12, 15) + "-8" + hash.substring(15, 18) + "-" + hash.substring(18, 30);
}
- let start = new Date();
+ let id = userToUUID(wrapper.sender);
try {
- let ret = eval(parameter);
+ if (!evalContexts[id]) {
+ evalContexts[id] = {};
+ vm.createContext(evalContexts[id]);
+ }
try {
- wrapper.send("✅ Completed in " + (new Date().getTime() - start) + " ms\n\n```plaintext\n" + JSON.stringify(ret, null, 2) + "\n```");
+ let ret = vm.runInContext(parameter, evalContexts[id]);
+
+ try {
+ wrapper.send("✅ Completed in " + (new Date().getTime() - start) + " ms, running in `isolated:" + id + "` context\n\n```plaintext\n" + JSON.stringify(ret, null, 2) + "\n```");
+ } catch (e) {
+ wrapper.send("⚠️ Completed with invalid JSON in " + (new Date().getTime() - start) + " ms, running in `isolated:" + id + "` context\n\n```plaintext\n" + ret + "\n```");
+ }
} catch (e) {
- wrapper.send("⚠️ Completed with invalid JSON in " + (new Date().getTime() - start) + " ms\n\n```plaintext\n" + ret + "\n```");
+ wrapper.send("🚨 Failed after " + (new Date().getTime() - start) + " ms, running in `isolated:" + id + "` context\n\n```plaintext\n" + e.stack + "\n```");
}
} catch (e) {
- wrapper.send("🚨 Failed after " + (new Date().getTime() - start) + " ms\n\n```plaintext\n" + e.stack + "\n```");
+ wrapper.send("⛔️ Failed to initialise context `isolated:" + id + "`:\n\n```plaintext\n" + e.stack + "\n```");
}
} \ No newline at end of file
diff --git a/commands/help.js b/commands/help.js
index 778a789..c6dbafc 100644
--- a/commands/help.js
+++ b/commands/help.js
@@ -1,28 +1,8 @@
const fs = require("fs");
module.exports = (parameter, wrapper) => {
- /*wrapper.send("👋 Hey! Here are all the commands you can use:\n" + fs.readdirSync("./commands").map((i) => {
- let txt = "<ul><li><code>." + i.substring(0, i.length - 3);
-
- if (fs.existsSync("./help/" + i.substring(0, i.length - 3) + ".json")) {
- let help = JSON.parse(fs.readFileSync("./help/" + i.substring(0, i.length - 3) + ".json").toString());
-
- txt += help['parameters'].replaceAll("<", "&lt;").replaceAll(">", "&gt;") + "</code><ul>";
-
- if (help['aliases'] && help['aliases'].length > 0) {
- txt += "<li><b>Alias" + (help['aliases'].length > 1 ? "es" : "") + ":</b> " + help['aliases'].map(i => `<code>.${i}</code>`).join(", ") + "</li>";
- }
-
- txt += "<li>" + help['description'].replaceAll("<", "&lt;").replaceAll(">", "&gt;") + "</li></ul></li></ul>";
- } else {
- txt += "</code><ul><li><i>No documentation yet</i></li></ul></li></ul>";
- }
-
- return txt;
- }).join(""));*/
-
if (parameter.trim() !== "") {
- if (fs.existsSync("./help/" + parameter.replaceAll("/", "-") + ".json")) {
+ if (fs.existsSync("./help/" + parameter.replaceAll("/", "-").replaceAll("_", "-") + ".json")) {
let help = JSON.parse(fs.readFileSync("./help/" + parameter + ".json").toString());
let txt = "ℹ️ `." + parameter + help['parameters'] + "`\n";
@@ -43,6 +23,35 @@ module.exports = (parameter, wrapper) => {
wrapper.send("😢 Sorry, no help is available for this command, try again later.");
}
} else {
- wrapper.send("👋 Hey! Here are all the commands you can use: " + fs.readdirSync("./commands").map((i) => "`." + i.substring(0, i.length - 3) + "`").join(", ") + "\n\nUse `.help [command]` to get help for a specific command. Version " + process.versions.butterscotch.substring(0, 10) + ".");
+ let list = "";
+ let categories = JSON.parse(fs.readFileSync("./help/_categories.json").toString());
+ let commands = fs.readdirSync("./commands");
+
+ for (let category of Object.keys(categories)) {
+ list += "* **" + category + ":** ";
+ let categoryCommands = [];
+
+ for (let command of commands) {
+ if (categories[category].includes(command.substring(0, command.length - 3))) {
+ categoryCommands.push("`." + command.substring(0, command.length - 3) + "`");
+ commands = commands.filter(i => i !== command);
+ }
+ }
+
+ list += categoryCommands.join(", ") + "\n";
+ }
+
+ if (commands.length > 0) {
+ list += "* **Other:** ";
+ let categoryCommands = [];
+
+ for (let command of commands) {
+ categoryCommands.push("`." + command.substring(0, command.length - 3) + "`");
+ }
+
+ list += categoryCommands.join(", ") + "\n";
+ }
+
+ wrapper.send("👋 Hey! Here are all the commands you can use:\n" + list + "\nUse `.help [command]` to get help for a specific command. Version " + process.versions.butterscotch.substring(0, 10) + ".");
}
} \ No newline at end of file
diff --git a/commands/mem.js b/commands/mem.js
new file mode 100644
index 0000000..2d6fa66
--- /dev/null
+++ b/commands/mem.js
@@ -0,0 +1,33 @@
+const os = require("os");
+
+module.exports = (parameter, wrapper) => {
+ function prettySize(size) {
+ if (size < 1024) {
+ return size + " bytes";
+ } else if (size < 1024**2) {
+ return (size / 1024).toFixed(2) + " KiB";
+ } else if (size < 1024**3) {
+ return (size / 1024**2).toFixed(2) + " MiB";
+ } else if (size < 1024**4) {
+ return (size / 1024**3).toFixed(2) + " GiB";
+ }
+ }
+
+ function getPercentage(used, total) {
+ return (used / total) * 100;
+ }
+
+ let percentage = getPercentage(os.totalmem() - os.freemem(), os.totalmem());
+ let bars = Math.round(percentage / 4);
+ let percentage2 = getPercentage(process.memoryUsage().heapUsed, process.memoryUsage().heapTotal);
+ let bars2 = Math.round(percentage2 / 4);
+
+ wrapper.send("💻 Here is how much RAM this bot is using:\n\n#### General\n" +
+ "\n* **System:** " + prettySize(os.totalmem() - os.freemem()) + "/" + prettySize(os.totalmem()) + "\n<br>`[" + "=".repeat(bars) + " ".repeat(25 - bars) + "]`" +
+ "\n* **Process:** " + prettySize(process.memoryUsage().heapUsed) + "/" + prettySize(process.memoryUsage().heapTotal) + "\n<br>`[" + "=".repeat(bars2) + " ".repeat(25 - bars2) + "]`" +
+ "\n\n#### Advanced" +
+ "\n* **Resident set size:** " + prettySize(process.memoryUsage().rss) +
+ "\n* **Binary buffers:** " + prettySize(process.memoryUsage().arrayBuffers) +
+ "\n* **C++ objects:** " + prettySize(process.memoryUsage().external)
+ );
+} \ No newline at end of file
diff --git a/commands/meval.js b/commands/meval.js
new file mode 100644
index 0000000..cd5776e
--- /dev/null
+++ b/commands/meval.js
@@ -0,0 +1,19 @@
+module.exports = (parameter, wrapper) => {
+ let start = new Date();
+
+ if (wrapper.sender === "@raindrops:equestria.dev" || wrapper.sender === "493845599469174794") {
+ try {
+ let ret = eval(parameter);
+
+ try {
+ wrapper.send("✅ Completed in " + (new Date().getTime() - start) + " ms, running in `main` context\n\n```plaintext\n" + JSON.stringify(ret, null, 2) + "\n```");
+ } catch (e) {
+ wrapper.send("⚠️ Completed with invalid JSON in " + (new Date().getTime() - start) + " ms, running in `main` context\n\n```plaintext\n" + ret + "\n```");
+ }
+ } catch (e) {
+ wrapper.send("🚨 Failed after " + (new Date().getTime() - start) + " ms, running in `main` context\n\n```plaintext\n" + e.stack + "\n```");
+ }
+ } else {
+ wrapper.send("⛔️ This command is private and you are not allowed to use it. Try `.eval` instead.");
+ }
+} \ No newline at end of file
diff --git a/commands/reset.js b/commands/reset.js
new file mode 100644
index 0000000..5fc19fe
--- /dev/null
+++ b/commands/reset.js
@@ -0,0 +1,20 @@
+const vm = require('vm');
+
+module.exports = (parameter, wrapper) => {
+ let start = new Date();
+
+ function userToUUID(user) {
+ const crypto = require('crypto');
+ let hash = crypto.createHash("sha1").update(user).digest("hex");
+ return hash.substring(0, 8) + "-" + hash.substring(8, 12) + "-4" + hash.substring(12, 15) + "-8" + hash.substring(15, 18) + "-" + hash.substring(18, 30);
+ }
+
+ let id = userToUUID(wrapper.sender);
+
+ if (evalContexts[id]) {
+ delete evalContexts[id];
+ wrapper.send("✅ Successfully unliked context `isolated:" + id + "`.");
+ } else {
+ wrapper.send("⛔️ Cannot unlink context `isolated:" + id + "` as it is not currently linked.");
+ }
+} \ No newline at end of file
diff --git a/commands/xeval.js b/commands/xeval.js
new file mode 100644
index 0000000..a886b4e
--- /dev/null
+++ b/commands/xeval.js
@@ -0,0 +1,19 @@
+const child_process = require("child_process");
+const {promisify} = require("util");
+
+module.exports = async (parameter, wrapper) => {
+ let start = new Date();
+ let exec = promisify(child_process.exec);
+
+ if (wrapper.sender === "@raindrops:equestria.dev" || wrapper.sender === "493845599469174794") {
+ try {
+ let ret = await exec(parameter);
+
+ wrapper.send("✅ Completed in " + (new Date().getTime() - start) + " ms, running in `system` context\n\n```plaintext\n" + ret.stdout + "\n```\n```plaintext\n" + ret.stderr + "\n```");
+ } catch (e) {
+ wrapper.send("🚨 Failed after " + (new Date().getTime() - start) + " ms, running in `system` context\n\n```plaintext\n" + e.stdout + "\n```\n```plaintext\n" + e.stderr + "\n```");
+ }
+ } else {
+ wrapper.send("⛔️ This command is private and you are not allowed to use it. Try `.eval` instead.");
+ }
+} \ No newline at end of file
diff --git a/help/_categories.json b/help/_categories.json
new file mode 100644
index 0000000..f82cd75
--- /dev/null
+++ b/help/_categories.json
@@ -0,0 +1,8 @@
+{
+ "Knowledge": [ "ask", "ip", "math", "status" ],
+ "Derpibooru": [ "cute", "nsfw" ],
+ "Fun": [ "fortune", "roll", "what" ],
+ "Technical": [ "help", "killswitch", "mem", "ping", "usage" ],
+ "Private": [ "evening", "score" ],
+ "Execution": [ "eval", "xeval", "meval", "reset" ]
+} \ No newline at end of file
diff --git a/help/eval.json b/help/eval.json
index 08053cb..266cb51 100644
--- a/help/eval.json
+++ b/help/eval.json
@@ -1,5 +1,5 @@
{
- "description": "Runs JavaScript code on the bot.",
+ "description": "Runs JavaScript code on the bot in an isolated context.",
"parameters": "<code>",
"aliases": [ "exec", "run", "code" ],
"exempt": false
diff --git a/help/mem.json b/help/mem.json
new file mode 100644
index 0000000..41933c4
--- /dev/null
+++ b/help/mem.json
@@ -0,0 +1,6 @@
+{
+ "description": "Gets information about memory usage.",
+ "parameters": "",
+ "aliases": [ "ram", "memory" ],
+ "exempt": true
+} \ No newline at end of file
diff --git a/help/meval.json b/help/meval.json
new file mode 100644
index 0000000..6d56659
--- /dev/null
+++ b/help/meval.json
@@ -0,0 +1,6 @@
+{
+ "description": "Runs JavaScript code on the bot in the main context.",
+ "parameters": "<code>",
+ "aliases": [ "main" ],
+ "exempt": false
+} \ No newline at end of file
diff --git a/help/reset.json b/help/reset.json
new file mode 100644
index 0000000..0a6580b
--- /dev/null
+++ b/help/reset.json
@@ -0,0 +1,6 @@
+{
+ "description": "Deletes your current .eval context.",
+ "parameters": "",
+ "aliases": [ "restart", "unlink", "delete" ],
+ "exempt": false
+} \ No newline at end of file
diff --git a/help/xeval.json b/help/xeval.json
new file mode 100644
index 0000000..06bd8b4
--- /dev/null
+++ b/help/xeval.json
@@ -0,0 +1,6 @@
+{
+ "description": "Runs a shell command on the server the bot is installed to.",
+ "parameters": "<command>",
+ "aliases": [ "xeval", "bash", "sh" ],
+ "exempt": false
+} \ No newline at end of file
diff --git a/index.js b/index.js
index 5eb60aa..7f5df8f 100644
--- a/index.js
+++ b/index.js
@@ -44,6 +44,7 @@ try {
}
global.aliases = {};
+global.evalContexts = {};
process.on('uncaughtException', (e) => {
console.error(e);