crv2/discord/commands/Eval.ts

87 lines
3.5 KiB
TypeScript
Raw Normal View History

2024-10-24 20:40:21 -04:00
import DiscordInteractionCommand from "../../util/DiscordInteractionCommand";
import { ChatInputCommandInteraction } from "discord.js";
import { inspect } from "util";
import { discordBotToken } from "../../config.json";
export default class Eval extends DiscordInteractionCommand {
2024-10-25 16:57:33 -04:00
// This is a list of IDs that are allowed to use this command.
private listOfAllowedIDs: string[];
2024-10-24 20:40:21 -04:00
2024-10-25 16:57:33 -04:00
constructor() {
super("eval", "Executes arbitrary JS code and returns the output.");
// this option is required and is a string of JavaScript code to execute
this.builder.addStringOption((option) =>
option.setName("code").setDescription("The code to execute.").setRequired(true)
);
// this option is optional and is a boolean that determines whether the code should be run as an async function
this.builder.addBooleanOption((option) =>
option
.setName("async")
.setDescription("Whether to run the code as an async function.")
.setRequired(false)
);
// this option is optional and is an integer that determines the depth of the eval inspection
this.builder.addIntegerOption((option) =>
option.setName("depth").setDescription("The depth of the inspection.").setRequired(false)
);
2024-10-24 20:40:21 -04:00
2024-11-09 18:14:41 -05:00
// TODO: replace with database entry "canExecuteDevCommands"
2024-10-25 16:57:33 -04:00
this.listOfAllowedIDs = [
"278620217221971968", // Matthew
];
}
2024-10-24 20:40:21 -04:00
2024-10-25 16:57:33 -04:00
public async execute(interaction: ChatInputCommandInteraction) {
// @ts-ignore
let evalString = interaction.options.getString("code").trim();
if (evalString == null)
return interaction.reply({ content: "You must provide code to evaluate.", ephemeral: true });
if (!this.listOfAllowedIDs.includes(interaction.user.id))
return interaction.reply({ content: "Permission denied.", ephemeral: true });
await interaction.deferReply({ ephemeral: true });
2024-10-24 20:40:21 -04:00
2024-10-25 16:57:33 -04:00
// set scoped variables to be able to access over eval
const guild = interaction.guild || interaction.client.guilds.cache.get(this.GUILD_ID);
// the output of eval() is stored in evaled
let evaled: any;
let depth: number | null = 0;
// if depth option exists, set the depth variable to the value provided by the user
if (interaction.options.getInteger("depth") != null) {
depth = interaction.options.getInteger("depth");
}
2024-10-24 20:40:21 -04:00
2024-10-25 16:57:33 -04:00
// if command specified as async, swap the evalString in an async function
if (interaction.options.getBoolean("async")) {
evalString = `(async () => { ${evalString} })()`;
}
2024-10-24 20:40:21 -04:00
2024-10-25 16:57:33 -04:00
try {
evaled = await eval(evalString);
if (typeof evaled !== "string") {
evaled = inspect(evaled, { depth });
}
if (evaled === undefined) {
evaled = "undefined";
}
} catch (error) {
// @ts-ignore
evaled = error.stack;
}
2024-10-24 20:40:21 -04:00
2024-10-25 16:57:33 -04:00
// replaces all instances of the bot token with [REDACTED] in output
evaled = evaled.replace(new RegExp(discordBotToken, "gi"), "[REDACTED]");
2024-10-24 20:40:21 -04:00
2024-10-25 16:57:33 -04:00
// TODO: Figure this out.
/*const display = this.client.util.splitString(evaled, 1975);
2024-10-24 20:40:21 -04:00
if (display[5]) {
try {
const { data } = await axios.post('https://snippets.cloud.libraryofcode.org/documents', display.join(''));
return this.success(ctx.message.channel, `Your evaluation evaled can be found on https://snippets.cloud.libraryofcode.org/${data.key}`);
} catch (error) {
return this.error(ctx.message.channel, `${error}`);
}
}*/
2024-10-25 16:57:33 -04:00
await interaction.editReply({ content: `\`\`\`js\n${evaled}\n\`\`\`` });
}
2024-10-24 20:40:21 -04:00
}