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 { // This is a list of IDs that are allowed to use this command. private listOfAllowedIDs: string[]; 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) ); // TODO: replace with database entry "canExecuteDevCommands" this.listOfAllowedIDs = [ "278620217221971968", // Matthew ]; } 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 }); // 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"); } // if command specified as async, swap the evalString in an async function if (interaction.options.getBoolean("async")) { evalString = `(async () => { ${evalString} })()`; } 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; } // replaces all instances of the bot token with [REDACTED] in output evaled = evaled.replace(new RegExp(discordBotToken, "gi"), "[REDACTED]"); // TODO: Figure this out. /*const display = this.client.util.splitString(evaled, 1975); 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}`); } }*/ await interaction.editReply({ content: `\`\`\`js\n${evaled}\n\`\`\`` }); } }