aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--package.json3
-rw-r--r--src/commands/dev/javascript.ts74
-rw-r--r--src/lib/extensions/discord-akairo/BushClientUtil.ts62
-rw-r--r--src/listeners/commands/commandBlocked.ts12
-rw-r--r--src/listeners/commands/commandError.ts2
-rw-r--r--yarn.lock10
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;
diff --git a/yarn.lock b/yarn.lock
index ec70510..fdb5a93 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -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"