diff options
-rw-r--r-- | package.json | 3 | ||||
-rw-r--r-- | src/commands/dev/javascript.ts | 74 | ||||
-rw-r--r-- | src/lib/extensions/discord-akairo/BushClientUtil.ts | 62 | ||||
-rw-r--r-- | src/listeners/commands/commandBlocked.ts | 12 | ||||
-rw-r--r-- | src/listeners/commands/commandError.ts | 2 | ||||
-rw-r--r-- | yarn.lock | 10 |
6 files changed, 128 insertions, 35 deletions
diff --git a/package.json b/package.json index 4f2627e..bb59bec 100644 --- a/package.json +++ b/package.json @@ -70,7 +70,8 @@ "source-map-support": "^0.5.20", "tinycolor2": "^1.4.2", "tslib": "^2.3.1", - "typescript": "rc" + "typescript": "rc", + "vm2": "^3.9.5" }, "devDependencies": { "@types/express": "^4.17.13", diff --git a/src/commands/dev/javascript.ts b/src/commands/dev/javascript.ts new file mode 100644 index 0000000..8a47b23 --- /dev/null +++ b/src/commands/dev/javascript.ts @@ -0,0 +1,74 @@ +import { BushCommand, type BushMessage, type BushSlashMessage } from '#lib'; +import { MessageEmbed } from 'discord.js'; +import { VM } from 'vm2'; + +export default class JavascriptCommand extends BushCommand { + public constructor() { + super('javascript', { + aliases: ['javascript', 'js'], + category: 'dev', + description: { + content: 'Evaluate code in a sand boxed environment.', + usage: ['javascript <code> [--depth #]'], + examples: ['javascript 9+10'] + }, + args: [ + { id: 'sel_depth', match: 'option', type: 'integer', flag: '--depth', default: 0 }, + { + id: 'code', + match: 'rest', + type: 'string', + prompt: { start: 'What would you like to eval?', retry: '{error} Invalid code to eval.' } + } + ], + slash: true, + slashOptions: [ + { name: 'code', description: 'The code you would like to evaluate.', type: 'STRING', required: true }, + { name: 'sel_depth', description: 'How deep to display the output.', type: 'INTEGER', required: false } + ], + superUserOnly: true, + clientPermissions: (m) => util.clientSendAndPermCheck(m), + userPermissions: [] + }); + } + + public override async exec( + message: BushMessage | BushSlashMessage, + args: { + sel_depth: number; + code: string; + } + ) { + if (!message.author.isSuperUser()) + return await message.util.reply(`${util.emojis.error} Only super users can run this command.`); + if (message.util.isSlashMessage(message)) { + await message.interaction.deferReply({ ephemeral: false }); + } + const code = args.code.replace(/[“”]/g, '"').replace(/```*(?:js)?/g, ''); + const embed = new MessageEmbed(); + const input = await util.inspectCleanRedactCodeblock(code, 'js'); + + try { + const rawOutput = /^(9\s*?\+\s*?10)|(10\s*?\+\s*?9)$/.test(code) + ? '21' + : new VM({ eval: true, wasm: true, timeout: 1_000, fixAsync: true }).run(`${code}`); + const output = await util.inspectCleanRedactCodeblock(rawOutput, 'js', { + depth: args.sel_depth ?? 0, + getters: true, + inspectStrings: true + }); + + embed.setTitle(`${util.emojis.successFull} Successfully Evaluated Expression`).setColor(util.colors.success); + embed.addField('📥 Input', input); + embed.addField('📤 Output', output); + } catch (e) { + embed.setTitle(`${util.emojis.errorFull} Unable to Evaluate Expression`).setColor(util.colors.error); + embed.addField('📥 Input', input); + embed.addField('📤 Error', await util.inspectCleanRedactCodeblock(e, 'js')); + } + + embed.setTimestamp().setFooter(message.author.tag, message.author.displayAvatarURL({ dynamic: true }) ?? undefined); + + await message.util.reply({ embeds: [embed] }); + } +} diff --git a/src/lib/extensions/discord-akairo/BushClientUtil.ts b/src/lib/extensions/discord-akairo/BushClientUtil.ts index 4b68b2e..f21d104 100644 --- a/src/lib/extensions/discord-akairo/BushClientUtil.ts +++ b/src/lib/extensions/discord-akairo/BushClientUtil.ts @@ -255,33 +255,37 @@ export class BushClientUtil extends ClientUtil { * @param options - The options you would like to use to inspect the object */ public inspect(object: any, options?: BushInspectOptions): string { + const optionsWithDefaults = this.getDefaultInspectOptions(options) + return inspect(object, optionsWithDefaults); + } + + private getDefaultInspectOptions(options?:BushInspectOptions): BushInspectOptions { const { - showHidden: _showHidden = false, - depth: _depth = 2, - colors: _colors = false, - customInspect: _customInspect = true, - showProxy: _showProxy = false, - maxArrayLength: _maxArrayLength = Infinity, - maxStringLength: _maxStringLength = Infinity, - breakLength: _breakLength = 80, - compact: _compact = 3, - sorted: _sorted = false, - getters: _getters = true + showHidden = false, + depth = 2, + colors = false, + customInspect = true, + showProxy = false, + maxArrayLength = Infinity, + maxStringLength = Infinity, + breakLength = 80, + compact = 3, + sorted = false, + getters = true } = options ?? {}; - const optionsWithDefaults: BushInspectOptions = { - showHidden: _showHidden, - depth: _depth, - colors: _colors, - customInspect: _customInspect, - showProxy: _showProxy, - maxArrayLength: _maxArrayLength, - maxStringLength: _maxStringLength, - breakLength: _breakLength, - compact: _compact, - sorted: _sorted, - getters: _getters - }; - return inspect(object, optionsWithDefaults); + return { + showHidden, + depth, + colors, + customInspect, + showProxy, + maxArrayLength, + maxStringLength, + breakLength, + compact, + sorted, + getters + } } #mapCredential(old: string): string { @@ -323,10 +327,14 @@ export class BushClientUtil extends ClientUtil { public async inspectCleanRedactCodeblock( input: any, language?: CodeBlockLang | '', - inspectOptions?: BushInspectOptions, + inspectOptions?: BushInspectOptions & { inspectStrings?: boolean }, length = 1024 ) { - input = typeof input !== 'string' ? this.inspect(input, inspectOptions ?? undefined) : input; + input = + !inspectOptions?.inspectStrings && typeof input === 'string' + ? input + : this.inspect(input, inspectOptions ?? undefined); + if (inspectOptions) inspectOptions.inspectStrings = undefined; input = this.discord.cleanCodeBlockContent(input); input = this.redact(input); return this.codeblock(input, length, language, true); diff --git a/src/listeners/commands/commandBlocked.ts b/src/listeners/commands/commandBlocked.ts index 1435ae3..20c0f6e 100644 --- a/src/listeners/commands/commandBlocked.ts +++ b/src/listeners/commands/commandBlocked.ts @@ -32,25 +32,25 @@ export default class CommandBlockedListener extends BushListener { switch (reason) { case reasons.OWNER: { return await respond({ - content: `${util.emojis.error} Only my developers can run the \`${command}\` command.`, + content: `${util.emojis.error} Only my developers can run the ${util.format.bold(command!.toString())} command.`, ephemeral: true }); } case reasons.SUPER_USER: { return await respond({ - content: `${util.emojis.error} You must be a superuser to run the \`${command}\` command.`, + content: `${util.emojis.error} You must be a superuser to run the ${util.format.bold(command!.toString())} command.`, ephemeral: true }); } case reasons.DISABLED_GLOBAL: { return await respond({ - content: `${util.emojis.error} My developers disabled the \`${command}\` command.`, + content: `${util.emojis.error} My developers disabled the ${util.format.bold(command!.toString())} command.`, ephemeral: true }); } case reasons.DISABLED_GUILD: { return await respond({ - content: `${util.emojis.error} The \`${command}\` command is currently disabled in \`${message.guild?.name}\`.`, + content: `${util.emojis.error} The ${util.format.bold(command!.toString())} command is currently disabled in \`${message.guild?.name}\`.`, ephemeral: true }); } @@ -87,7 +87,7 @@ export default class CommandBlockedListener extends BushListener { }); const pretty = util.oxford(names, 'and'); return await respond({ - content: `${util.emojis.error} \`${command}\` can only be run in ${pretty}.`, + content: `${util.emojis.error} ${util.format.bold(command!.toString())} can only be run in ${pretty}.`, ephemeral: true }); } @@ -100,7 +100,7 @@ export default class CommandBlockedListener extends BushListener { }); const pretty = util.oxford(names, 'and'); return await respond({ - content: `${util.emojis.error} \`${command}\` can only be run in ${pretty}.`, + content: `${util.emojis.error} ${util.format.bold(command!.toString())} can only be run in ${pretty}.`, ephemeral: true }); } diff --git a/src/listeners/commands/commandError.ts b/src/listeners/commands/commandError.ts index 6eceb68..c005574 100644 --- a/src/listeners/commands/commandError.ts +++ b/src/listeners/commands/commandError.ts @@ -22,7 +22,7 @@ export default class CommandErrorListener extends BushListener { const isSlash = message.util!.isSlash; const errorNum = Math.floor(Math.random() * 6969696969) + 69; // hehe funny number const channel = - message.channel!.type === 'DM' + message.channel?.type === 'DM' ? (message.channel as DMChannel)!.recipient.tag : (message.channel as GuildTextBasedChannels)!.name; const command = _command ?? message.util?.parsed?.command; @@ -809,6 +809,7 @@ __metadata: tinycolor2: ^1.4.2 tslib: ^2.3.1 typescript: rc + vm2: ^3.9.5 languageName: unknown linkType: soft @@ -3228,6 +3229,15 @@ __metadata: languageName: node linkType: hard +"vm2@npm:^3.9.5": + version: 3.9.5 + resolution: "vm2@npm:3.9.5" + bin: + vm2: bin/vm2 + checksum: d83dbe929ca4d1c9fca71cda34a5aee9a6b4bdc1de1ddb11777c4f6e1e48a471764195258dbf608f962df1a1c3d6ae917c9755f11a8f37b9e0bbf691313a725c + languageName: node + linkType: hard + "webidl-conversions@npm:^3.0.0": version: 3.0.1 resolution: "webidl-conversions@npm:3.0.1" |