From 7ae0fb05b84758e9936960bb3afa063258cd7e29 Mon Sep 17 00:00:00 2001 From: 7cc5c4f330d47060 Date: Wed, 20 Nov 2024 01:34:57 -0500 Subject: [PATCH] Finish porting everything else --- commands/cloop.js | 93 ++++++++++++++++++++++++++++++++++++++++++++ commands/eval.js | 9 ----- commands/logoff.js | 3 +- commands/restart.js | 3 +- commands/stop.js | 3 +- commands/template.js | 41 +++++++++++++++++++ commands/tpr.js | 45 +++++++++++++++++++++ commands/validate.js | 21 ++++++++++ plugins/cloop.js | 22 +++++++++++ plugins/command.js | 47 +++++++++++++++++++--- settings_example.js | 2 + util/Command.js | 10 ++++- util/hashcheck.js | 19 +++++++++ 13 files changed, 296 insertions(+), 22 deletions(-) create mode 100755 commands/cloop.js create mode 100755 commands/template.js create mode 100755 commands/tpr.js create mode 100755 commands/validate.js create mode 100755 plugins/cloop.js create mode 100755 util/hashcheck.js diff --git a/commands/cloop.js b/commands/cloop.js new file mode 100755 index 0000000..3b7df1a --- /dev/null +++ b/commands/cloop.js @@ -0,0 +1,93 @@ + +import { getMessage } from '../util/lang.js' +const execute= (c) => { + let subcmd + if (c.args.length >= 1) subcmd = c.args.splice(0, 1)[0].toLowerCase() + switch (subcmd) { + case 'add': { + const rate = +(c.args.splice(0, 1)[0]) + const command = c.args.join(' ') + if (rate < 20) { + c.reply({ + text: getMessage(c.lang, 'command.cloop.error.tooShort') + }) + } + c.bot.addCloop(command, rate) + c.reply({ + translate: getMessage(c.lang, 'command.cloop.success.add'), + color: c.colors.secondary, + with: [ + { + text: command, + color: c.colors.primary + }, + { + text: rate + '', + color: c.colors.primary + } + ] + }) + break + } + case 'remove': { + const index = +c.args[0] + c.bot.removeCloop(c.args[0]) + c.reply({ + translate: getMessage(c.lang, 'command.cloop.success.remove'), + color: c.colors.secondary, + with: [ + { + text: index + '', + color: c.colors.primary + } + ] + }) + break + } + case 'list': + c.bot.cloops.forEach((item, i) => { + c.reply({ + translate: getMessage(c.lang, 'command.cloop.list'), + color: c.colors.secondary, + with: [ + { + text: i.toString(), + color: c.colors.primary + }, + { + text: item.command, + color: c.colors.primary + }, + { + text: item.rate + '', + color: c.colors.primary + } + ] + }) + }) + break + case 'clear': + c.bot.clearCloops() + c.reply({ + text: getMessage(c.lang, 'command.cloop.success.clear'), + color: c.colors.secondary + }) + break + default: + c.reply({ + translate: getMessage(c.lang, 'command.cloop.error.subcommand'), + color: c.colors.secondary, + with: [ + { + text: `${c.prefix}help cloop`, + color: c.colors.primary + } + ] + }) + } +} +const consoleIndex= true +const level= 1 + + +export { execute, consoleIndex, level } \ No newline at end of file diff --git a/commands/eval.js b/commands/eval.js index cb8b8ab..a4db700 100755 --- a/commands/eval.js +++ b/commands/eval.js @@ -2,15 +2,6 @@ import * as index from '../index.js' // Not used in the code, but may be used by import { getMessage } from '../util/lang.js' const execute = (c) => { - if (c.verify !== 2) { - c.reply({ - text: getMessage(c.lang, 'command.disallowed.perms.short') - }) - c.reply({ - text: getMessage(c.lang, 'command.disabled.nonConsole') - }) - return - } const item = eval(c.args.join(' ')) if (c.type === 'console') { console.log(item) diff --git a/commands/logoff.js b/commands/logoff.js index 3aed2fd..2faa926 100755 --- a/commands/logoff.js +++ b/commands/logoff.js @@ -1,6 +1,5 @@ const execute= (c) => { - c.reply("Command has been disabled") - //c.bot._client.end() + c.bot._client.end() } const consoleIndex= true const level= 2 diff --git a/commands/restart.js b/commands/restart.js index a794a2c..087d6c1 100755 --- a/commands/restart.js +++ b/commands/restart.js @@ -1,6 +1,5 @@ const execute= (c) => { - c.reply("Command has been disabled") - //process.exit(0) + process.exit(0) } const aliases = ['reboot'] const level= 2 diff --git a/commands/stop.js b/commands/stop.js index fb2b182..cc566f2 100755 --- a/commands/stop.js +++ b/commands/stop.js @@ -1,6 +1,5 @@ const execute= (c) => { - c.reply("Command has been disabled") - //process.exit(1) + process.exit(1) } const aliases = ['exit'] const level= 2 diff --git a/commands/template.js b/commands/template.js new file mode 100755 index 0000000..26f1c85 --- /dev/null +++ b/commands/template.js @@ -0,0 +1,41 @@ +const execute= (c) => { + // Blank template + /* + c.send(text, user?): Send text to all ("/tellraw @a") + c.reply(text): Send text to command sender + c.uuid: Unique identifier (UUID for Minecraft, Discord ID for Discord) + c.username: Username of sender + c.nickname: Nickname of sender when applicable + c.command: Command string + c.args: Arguments of command (above without the first section, and split at every space) + c.prefix: Prefix being used to send the command (when applicable) + c.bot: Bot that received the command. Will be different type based on where it was received + c.type: Type of bot receiving the command ("minecraft", "console", "discord") + c.lang: The language the player has selected, or the default if none + c.colors: The color palette the player has selected, or the default if none + */ + } + /* + Command description and usage have been moved to the message files. The format for a basic command is: + "command.(name).usage": " [optional]", + "command.(name).desc": "Insert description here...", + replacing (name) with the name of the new command. + Some more complex commands may have messages of their own, which should be placed there too. + First, insert the following line near the top of the command's file (not in the execute function): + const { getMessage } = require('../../util/lang.js') + Then, to get a specific message: + getMessage(c.lang,"(message key)",[(arguments, in an array (optional))]) + For example, this will show the "about" command's redirection to "serverinfo": + getMessage(c.lang,"command.about.serverinfo") + The with array can be used to add information to a message. For example: + getMessage(lang,"command.help.commandInfo",["cmd","usage","desc"]) + shows the "help" command's formatting for command information, with some strings as items. + That message would render as (in en-US): + cmdusage - desc + Extra information is inserted wherever there is a "%s" or a "%n$s", with n being the index of the item in the array. + */ + const hidden= true // To show the command on the help command list, remove this line (optional) + const consoleIndex= true // When run from console, the second argument will be a bot ID (optional) + const aliases= ['example'] // Other command names that will work the same (optional) + const level= 0 // Permission level required to run this command (optional) +export { execute, hidden, consoleIndex, aliases, level } // Only export the items that were included in your command \ No newline at end of file diff --git a/commands/tpr.js b/commands/tpr.js new file mode 100755 index 0000000..553a649 --- /dev/null +++ b/commands/tpr.js @@ -0,0 +1,45 @@ +import { getMessage } from '../util/lang.js' + +const execute= function (c) { + let uuid + if (c.type === 'console') { + uuid = c.bot._client.uuid + } else { + uuid = c.uuid + } + const originalPos = { + x: Math.floor(Math.random() * 2000000) - 1000000, + y: 100, + z: Math.floor(Math.random() * 2000000) - 1000000 + } + c.reply( + { + translate: getMessage(c.lang, 'command.tpr.success'), + color: c.colors.secondary, + with: [ + { + text: c.username, + color: c.colors.primary + }, + { + text: originalPos.x.toString(), + color: c.colors.primary + }, + { + text: originalPos.y.toString(), + color: c.colors.primary + }, + { + text: originalPos.z.toString(), + color: c.colors.primary + } + ] + } + ) + c.bot.ccq.push(`/essentials:tp ${uuid} ${originalPos.x}.0 ${originalPos.y} ${originalPos.z}.0`) + } + const consoleIndex= true + const aliases= ['rtp'] + + +export { execute, consoleIndex, aliases } diff --git a/commands/validate.js b/commands/validate.js new file mode 100755 index 0000000..acd9407 --- /dev/null +++ b/commands/validate.js @@ -0,0 +1,21 @@ +import { getMessage } from '../util/lang.js' + + const execute= (c) => { + const permsN = getMessage(c.lang, 'command.help.permsNormal') + const permsT = getMessage(c.lang, 'command.help.permsTrusted') + const permsO = getMessage(c.lang, 'command.help.permsOwner') + c.reply({ + translate: getMessage(c.lang, 'command.verify.success'), + color: c.colors.secondary, + with: [ + { + text: [permsN, permsT, permsO][c.verify], + color: c.colors.primary + } + ] + }) + } + const aliases= ['verify'] + const level= 1 + +export { execute, aliases, level } \ No newline at end of file diff --git a/plugins/cloop.js b/plugins/cloop.js new file mode 100755 index 0000000..123d630 --- /dev/null +++ b/plugins/cloop.js @@ -0,0 +1,22 @@ +export default function load (b) { + b.cloops = [] + b.addCloop = function (command, rate) { + b.cloops.push({ + command, + rate, + interval: setInterval(() => { b.ccq.push(command) }, rate) + }) + b.ccq.push(command) + } + b.removeCloop = function (index) { + clearInterval(b.cloops[index].interval) + b.cloops.splice(index, 1) + } + b.clearCloops = function () { + for (const cloop of b.cloops) { + clearInterval(cloop.interval) + } + b.cloops = [] + } +} + diff --git a/plugins/command.js b/plugins/command.js index 28780d2..3164069 100644 --- a/plugins/command.js +++ b/plugins/command.js @@ -1,6 +1,8 @@ import cmds from '../util/commands.js' import settings from '../settings.js' import Command from '../util/Command.js' +import hashcheck from '../util/hashcheck.js' +import { getMessage } from '../util/lang.js' export default function load (b) { b.on('chat', (data) => { const fullCommand = data.message @@ -12,17 +14,52 @@ export default function load (b) { } }) b.runCommand = function (user, nick, uuid, command, type, subtype, prefix) { - const context = new Command(uuid, user, nick, command, 'minecraft', type, subtype, prefix, b, 0) + if (uuid === '00000000-0000-0000-0000-000000000000') return + if (Date.now() - b.lastCmd <= 1000) return + b.lastCmd = Date.now() + + const context = new Command(uuid, user, nick, command, 'minecraft', type, subtype, prefix, b) b.emit('command', context) + if (context.cancel === true) return - if (cmds[context.cmdName.toLowerCase()]) { + const commandItem = cmds[context.cmdName.toLowerCase()] + + const cmdsplit = command.split(' ') + const verify = hashcheck(cmdsplit, uuid) + const permsN = getMessage(context.lang, 'command.help.permsNormal') + const permsT = getMessage(context.lang, 'command.help.permsTrusted') + const permsO = getMessage(context.lang, 'command.help.permsOwner') + if (commandItem && commandItem.level !== undefined && commandItem.level > verify) { + b.tellraw(uuid, { + text: getMessage(context.lang, 'command.disallowed.perms') + }) + b.tellraw(uuid, { + text: getMessage(context.lang, 'command.disallowed.perms.yourLevel', [[permsN, permsT, permsO][verify]]) + }) + b.tellraw(uuid, { + text: getMessage(context.lang, 'command.disallowed.perms.cmdLevel', [[permsN, permsT, permsO][commandItem.level]]) + }) + return + } else if (verify > 0) { + context.rewriteCommand(cmdsplit.slice(0, cmdsplit.length - 1).join(' ')) + context.verify = verify + } + + if (commandItem) { try { - cmds[context.cmdName.toLowerCase()].execute(context) + commandItem.execute(context) } catch (e) { console.log(e) - context.reply({ - text: 'An error occured (check console)' + b.tellraw(uuid, { + text: getMessage(context.lang, 'command.error'), + color: 'red', + hoverEvent: { + action: 'show_text', + value: { + text: e.stack + } + } }) } } diff --git a/settings_example.js b/settings_example.js index b74aeb9..a9236d8 100644 --- a/settings_example.js +++ b/settings_example.js @@ -2,6 +2,8 @@ export default { terminalMode: 'blackTerminal_24bit', // Terminal mode. Most modern terminals support 24-bit color version_mc: '1.21.1', // Minecraft version to connect with defaultLang: 'en-US', // Default language + keyTrusted: "3e9f13473eec8d64c3eabf6385e3f8585f0af39ed30a8db9a4c8d8bcfa35659d7d06a58b342bfd2db5e3cbb4003a81da8f9d25f7cce1ad26face8e2871c3b217", // Trusted key + keyOwner: "17d2c6c53b8919dc1ec22c42845018ac389824c4d73a68572b7fc57ff1442c6bbf9924d5ee5fa90cb23e384278d469c4e260208265b8ba2e2bc873045d5ed42e", // Owner key colors: { // All colors the bot uses secondary: '#DD99FF', primary: '#EECCFF', diff --git a/util/Command.js b/util/Command.js index 4e6d959..d728277 100644 --- a/util/Command.js +++ b/util/Command.js @@ -1,6 +1,6 @@ import settings from '../settings.js' export default class Command { - constructor (uuid, user, nick, cmd, senderType, msgType, msgSubtype, prefix, bot, verify) { + constructor (uuid, user, nick, cmd, senderType, msgType, msgSubtype, prefix, bot) { this.uuid = uuid this.reply = text => bot.tellraw(uuid, text) this.username = user @@ -14,9 +14,15 @@ export default class Command { this.prefix = prefix this.colors = settings.colors this.lang = settings.defaultLang - this.verify = verify + this.verify = 0 this.host = bot.host.host this.port = bot.host.port this.bot = bot + + this.rewriteCommand = newCmd => { + this.command = newCmd + this.args = newCmd.split(' ').slice(1) + this.cmdName = newCmd.split(' ')[0] + } } } diff --git a/util/hashcheck.js b/util/hashcheck.js new file mode 100755 index 0000000..7278b87 --- /dev/null +++ b/util/hashcheck.js @@ -0,0 +1,19 @@ +import { createHash } from 'node:crypto' +import settings from '../settings.js' + +export default function (cmd, uuid) { + const cmdWithoutHash = cmd.slice(0, cmd.length - 1).join(' ') + const _dateString = Date.now().toString() + const dateString = _dateString.slice(0, _dateString.length - 4) + const hashTrusted = `babyboom:${settings.keyTrusted}:${uuid}:${cmdWithoutHash}:${dateString}` + const hashOwner = `babyboom:${settings.keyOwner}:${uuid}:${cmdWithoutHash}:${dateString}` + const validhashT = createHash('sha256').update(hashTrusted).digest('hex') + const validhashO = createHash('sha256').update(hashOwner).digest('hex') + if (cmd[cmd.length - 1] === validhashT) { + return 1 + } + if (cmd[cmd.length - 1] === validhashO) { + return 2 + } + return 0 +}