From 827bbba5fdc477b6ed3a7b5819d0ad86d216e14f Mon Sep 17 00:00:00 2001 From: unterrunden <133593594+unterrunden@users.noreply.github.com> Date: Mon, 9 Jun 2025 23:31:49 +0200 Subject: [PATCH 1/9] Update Ban.mjs - reworked order of banning: /lobby -> /block add -> /p kick (switching around last 2) - added a statement that checks if the inputted user exists (previously only found in Unban.mjs) - extended "you cannot ban someone with higher a permission level" in that it includes your and the target player's permission and level - upon banning, sets permission level of affected user to 0 and logs that to the console --- src/mineflayer/commands/party/Ban.mjs | 55 ++++++++++++++++++++++----- 1 file changed, 46 insertions(+), 9 deletions(-) diff --git a/src/mineflayer/commands/party/Ban.mjs b/src/mineflayer/commands/party/Ban.mjs index e3291ed..da87b85 100644 --- a/src/mineflayer/commands/party/Ban.mjs +++ b/src/mineflayer/commands/party/Ban.mjs @@ -18,29 +18,66 @@ export default { */ execute: async function (bot, sender, args) { let player = args[0]; - if (!player) + if (!player) { + return bot.reply(sender, `Invalid usage! Use: ${this.usage}`, VerbosityLevel.Reduced); + } + const playerExists = await bot.utils.usernameExists(player); + if (playerExists === false) { + return bot.reply(sender, `Player ${player} not found`, VerbosityLevel.Reduced); + } + const reason = args.slice(1).join(" ") || "No reason given."; + + if (!bot.utils.isHigherRanked(sender.username, player)) { + const senderPermsRank = bot.utils.getPermissionsByUser({ name: sender.username }); + const playerPermsRank = bot.utils.getPermissionsByUser({ name: player }); + const senderPerms = Object.keys(Permissions).find( + (perm) => Permissions[perm] === senderPermsRank, + ); + const playerPerms = Object.keys(Permissions).find( + (perm) => Permissions[perm] === playerPermsRank, + ); return bot.reply( sender, - `Invalid usage! Use: ${this.usage}`, + `You cannot ban a player of a higher permission level than yourself (your rank: ${senderPerms} (level: ${senderPermsRank}), their rank: ${playerPerms} (level: ${playerPermsRank}).`, VerbosityLevel.Reduced, ); - let reason = args.slice(1).join(" ") || "No reason given."; - if (!bot.utils.isHigherRanked(sender.username, player)) { - return; } - bot.chat( - `/pc ${player} was removed from the party and blocked from rejoining by ${sender.preferredName}.`, - ); + + bot.reply(sender, `Trying to ban ${player}...`, VerbosityLevel.Reduced); + await bot.utils.delay(bot.utils.minMsgDelay); bot.chat(`/lobby`); await bot.utils.delay(bot.utils.minMsgDelay); + bot.chat(`/block add ${player}`); + await bot.utils.delay(bot.utils.minMsgDelay); bot.chat(`/p kick ${player}`); await bot.utils.delay(bot.utils.minMsgDelay); - bot.chat(`/block add ${player}`); + bot.reply(sender, `Banned ${player}.`, VerbosityLevel.Reduced); + + await bot.utils.delay(bot.utils.minMsgDelay); + bot.chat( + `/pc ${player} was removed from the party and blocked from rejoining by ${sender.preferredName}.`, + ); + bot.utils.webhookLogger.addMessage( `\`${player}\` was banned from the party by \`${sender.preferredName}\`. Reason: \`${reason}\``, WebhookMessageType.ActionLog, true, ); + + if (bot.utils.getUserObject({ name: player })) { + bot.utils.setPermissionRank({ + name: player, + newPermissionRank: 0, + }); + const newPlayerPerms = Object.keys(Permissions).find( + (perm) => Permissions[perm] === newPermissionRank, + ); + bot.utils.webhookLogger.addMessage( + `After banning, \`${player}\`'s permission rank was updated to \`${newPlayerPerms}\` (level: \`${newPermissionRank}\`) by \`${sender.username}\`.`, + WebhookMessageType.ActionLog, + true, + ); + } }, }; From 87e9a76482706140145bf700d22fa64bb31fa236 Mon Sep 17 00:00:00 2001 From: unterrunden <133593594+unterrunden@users.noreply.github.com> Date: Tue, 10 Jun 2025 10:40:43 +0200 Subject: [PATCH 2/9] Update Ban.mjs - added an if-else if statement for differentiating whether sender perms are the same as the target user's perms or 'undefined' (aka user doesn't exist in database and can therefore not ban), instead of just "is target user's perm level higher?" - added missing bracket in "you cannot ban a player of higher ..." --- src/mineflayer/commands/party/Ban.mjs | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/src/mineflayer/commands/party/Ban.mjs b/src/mineflayer/commands/party/Ban.mjs index da87b85..4f13f83 100644 --- a/src/mineflayer/commands/party/Ban.mjs +++ b/src/mineflayer/commands/party/Ban.mjs @@ -36,11 +36,20 @@ export default { const playerPerms = Object.keys(Permissions).find( (perm) => Permissions[perm] === playerPermsRank, ); - return bot.reply( - sender, - `You cannot ban a player of a higher permission level than yourself (your rank: ${senderPerms} (level: ${senderPermsRank}), their rank: ${playerPerms} (level: ${playerPermsRank}).`, - VerbosityLevel.Reduced, - ); + if (senderPerms === undefined) return; + else if (senderPermsRank === playerPermsRank) { + return bot.reply( + sender, + `You cannot ban a player of the same permission level (both: ${senderPerms}).`, + VerbosityLevel.Reduced, + ); + } else { + return bot.reply( + sender, + `You cannot ban a player of a higher permission level than yourself (your rank: ${senderPerms} (level: ${senderPermsRank}), their rank: ${playerPerms} (level: ${playerPermsRank})).`, + VerbosityLevel.Reduced, + ); + } } bot.reply(sender, `Trying to ban ${player}...`, VerbosityLevel.Reduced); From a439d892f11ef67e599edaf8890a40b1c4ec7cfb Mon Sep 17 00:00:00 2001 From: unterrunden <133593594+unterrunden@users.noreply.github.com> Date: Tue, 10 Jun 2025 11:08:44 +0200 Subject: [PATCH 3/9] Update Kick.mjs - updated to be more in-line with Ban.mjs and Unban.mjs - added ${player} to the "player not found" chat - added "you cannot kick someone with higher a permission level" (previously just a `return`) including your and the target player's permissions and level - changed let reason into a const - added `/lobby` before executing `/kick` similar to the (un)banning command logic --- src/mineflayer/commands/party/Kick.mjs | 50 +++++++++++++++++--------- 1 file changed, 34 insertions(+), 16 deletions(-) diff --git a/src/mineflayer/commands/party/Kick.mjs b/src/mineflayer/commands/party/Kick.mjs index 1acf9bb..938d952 100644 --- a/src/mineflayer/commands/party/Kick.mjs +++ b/src/mineflayer/commands/party/Kick.mjs @@ -7,7 +7,7 @@ import { export default { name: ["kick", "remove"], description: "Kick someone from the party", - usage: "!p kick ", + usage: "!p kick [reason]", permission: Permissions.Trusted, /** @@ -17,26 +17,44 @@ export default { * @param {Array} args */ execute: async function (bot, sender, args) { - let player; - if (args[0]) { - player = await bot.utils.usernameExists(args[0]); - if (player === false) - return bot.reply(sender, "Player not found.", VerbosityLevel.Reduced); - } else - return bot.reply( - sender, - `Invalid usage! Use: ${this.usage}`, - VerbosityLevel.Reduced, - ); - let reason = args.slice(1).join(" ") || "No reason given."; + let player = args[0]; + if (!player) { + return bot.reply(sender, `Invalid usage! Use: ${this.usage}`, VerbosityLevel.Reduced); + } + const playerExists = await bot.utils.usernameExists(player); + if (playerExists === false) { + return bot.reply(sender, `Player ${player} not found.`, VerbosityLevel.Reduced); + } + const reason = args.slice(1).join(" ") || "No reason given."; + if (!bot.utils.isHigherRanked(sender.username, player)) { - return; + const senderPermsRank = bot.utils.getPermissionsByUser({ name: sender.username }); + const playerPermsRank = bot.utils.getPermissionsByUser({ name: player }); + const senderPerms = Object.keys(Permissions).find( + (perm) => Permissions[perm] === senderPermsRank, + ); + const playerPerms = Object.keys(Permissions).find( + (perm) => Permissions[perm] === playerPermsRank, + ); + if (senderPerms === undefined) return; + else { + return bot.reply( + sender, + `You cannot kick a player of a higher permission level than yourself (your rank: ${senderPerms} (level: ${senderPermsRank}), their rank: ${playerPerms} (level: ${playerPermsRank})).`, + VerbosityLevel.Reduced, + ); + } } + + await bot.utils.delay(bot.utils.MinMsgDelay); + bot.chat(`/lobby`); + await bot.utils.delay(bot.utils.MinMsgDelay); + bot.chat(`/p kick ${player}`); + await bot.utils.delay(bot.utils.minMsgDelay); bot.chat( `/pc ${player} was kicked from the party by ${sender.preferredName}.`, ); - await bot.utils.delay(bot.utils.minMsgDelay); - bot.chat(`/p kick ${player}`); + bot.utils.webhookLogger.addMessage( `\`${player}\` was kicked from the party by \`${sender.preferredName}\`. Reason: \`${reason}\``, WebhookMessageType.ActionLog, From 19b5db6a3ebad11aab95fa7040cf663027682944 Mon Sep 17 00:00:00 2001 From: unterrunden <133593594+unterrunden@users.noreply.github.com> Date: Tue, 10 Jun 2025 12:16:22 +0200 Subject: [PATCH 4/9] Update Unban.mjs --- src/mineflayer/commands/party/Unban.mjs | 50 +++++++++++++++++++------ 1 file changed, 38 insertions(+), 12 deletions(-) diff --git a/src/mineflayer/commands/party/Unban.mjs b/src/mineflayer/commands/party/Unban.mjs index 89325ed..e160742 100644 --- a/src/mineflayer/commands/party/Unban.mjs +++ b/src/mineflayer/commands/party/Unban.mjs @@ -7,7 +7,7 @@ import { export default { name: ["unban", "unblock"], description: "Unban a player from the party", - usage: "!p unban ", + usage: "!p unban [reason]", permission: Permissions.Trusted, /** @@ -17,26 +17,52 @@ export default { * @param {Array} args */ execute: async function (bot, sender, args) { - let player; - if (args[0]) { - player = await bot.utils.usernameExists(args[0]); - if (player === false) - return bot.reply(sender, "Player not found.", VerbosityLevel.Reduced); - } else - return bot.reply( - sender, - `Invalid usage! Use: ${this.usage}`, - VerbosityLevel.Reduced, + let player = args[0]; + if (!player) { + return bot.reply(sender, `Invalid usage! Use: ${this.usage}`, VerbosityLevel.Reduced); + } + const playerExists = await bot.utils.usernameExists(player); + if (playerExists === false) { + return bot.reply(sender, `Player ${player} not found`, VerbosityLevel.Reduced); + } + const reason = args.slice(1).join(" ") || "No reason given."; + + if (!bot.utils.isHigherRanked(sender.username, player)) { + const senderPermsRank = bot.utils.getPermissionsByUser({ name: sender.username }); + const playerPermsRank = bot.utils.getPermissionsByUser({ name: player }); + const senderPerms = Object.keys(Permissions).find( + (perm) => Permissions[perm] === senderPermsRank, + ); + const playerPerms = Object.keys(Permissions).find( + (perm) => Permissions[perm] === playerPermsRank, ); + if (senderPerms === undefined) return; + else if (senderPermsRank === playerPermsRank) { + return bot.reply( + sender, + `You cannot unban a player of the same permission level (both: ${senderPerms}).`, + VerbosityLevel.Reduced, + ); + } else { + return bot.reply( + sender, + `You cannot unban a player of a higher permission level than yourself (your rank: ${senderPerms} (level: ${senderPermsRank}), their rank: ${playerPerms} (level: ${playerPermsRank})).`, + VerbosityLevel.Reduced, + ); + } + } + bot.reply(sender, `Trying to unban ${player}...`, VerbosityLevel.Reduced); + await bot.utils.delay(bot.utils.minMsgDelay); bot.chat(`/lobby`); await bot.utils.delay(bot.utils.minMsgDelay); bot.chat(`/block remove ${player}`); await bot.utils.delay(bot.utils.minMsgDelay); bot.reply(sender, `Unbanned ${player}.`, VerbosityLevel.Reduced); + bot.utils.webhookLogger.addMessage( - `\`${player}\` was unbanned from the party by \`${sender.preferredName}\`.`, + `\`${player}\` was unbanned from the party by \`${sender.preferredName}\`. Reason: \`${reason}\``, WebhookMessageType.ActionLog, true, ); From 20204965d6eb2992a7ff749de7006d519cc5cdf8 Mon Sep 17 00:00:00 2001 From: unterrunden <133593594+unterrunden@users.noreply.github.com> Date: Tue, 10 Jun 2025 12:25:37 +0200 Subject: [PATCH 5/9] Update Mute.mjs --- src/mineflayer/commands/party/Mute.mjs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/mineflayer/commands/party/Mute.mjs b/src/mineflayer/commands/party/Mute.mjs index 9e93481..80506b1 100644 --- a/src/mineflayer/commands/party/Mute.mjs +++ b/src/mineflayer/commands/party/Mute.mjs @@ -3,7 +3,7 @@ import { Permissions, WebhookMessageType } from "../../../utils/Interfaces.mjs"; export default { name: ["mute", "unmute"], description: "Mute/Unmute the party", - usage: "!p mute", + usage: "!p mute [reason]", permission: Permissions.Trusted, /** @@ -13,10 +13,12 @@ export default { * @param {Array} args */ execute: async function (bot, sender, args) { - let reason = args.join(" ") || "No reason given."; + const reason = args.join(" ") || "No reason given."; + bot.chat("/p mute"); await bot.utils.delay(bot.utils.minMsgDelay); bot.chat(`/pc Party mute was toggled by ${sender.preferredName}.`); + bot.utils.webhookLogger.addMessage( `Party mute was toggled by \`${sender.preferredName}\`. Reason: \`${reason}\``, WebhookMessageType.ActionLog, From 32fe89567dc419b4d51c1e2959901dd541281e92 Mon Sep 17 00:00:00 2001 From: unterrunden <133593594+unterrunden@users.noreply.github.com> Date: Tue, 10 Jun 2025 16:59:47 +0200 Subject: [PATCH 6/9] Update index.mjs temporary ban option --- index.mjs | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/index.mjs b/index.mjs index 14333fc..e381d02 100644 --- a/index.mjs +++ b/index.mjs @@ -42,7 +42,9 @@ if (config.default.debug.disableDiscord) { discordBot.setUtils(utils); discordBot.setConfig(config.default); } + refreshConfig(); +refreshBanRegistry(); // Used to refresh allowList every 10 seconds function refreshConfig() { @@ -61,6 +63,23 @@ function refreshConfig() { }, 10000); } +// Used to refresh banRegistry every 60 seconds +function refreshBanRegistry() { + setInterval(async () => { + try { + const now = Date.now(); + for (const [username, banData] of Object.entries(registry.bans)) { + if (banData.banEnd !== Infinity && banData.banEnd.getTime() <= now) { + delete registry.bans[username]; + console.log(`Ban for ${username} has expired and was removed.`); + } + } + } catch (error) { + console.error("Error refreshing ban registry:", error); + } + }, 60000); +} + process.stdin.on("data", dataInput); function dataInput(data) { From 1baf7bb193e3ab90874f23badeb6c3615a724197 Mon Sep 17 00:00:00 2001 From: unterrunden <133593594+unterrunden@users.noreply.github.com> Date: Tue, 10 Jun 2025 16:59:53 +0200 Subject: [PATCH 7/9] Update Utils.mjs temporary ban option --- src/utils/Utils.mjs | 78 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 78 insertions(+) diff --git a/src/utils/Utils.mjs b/src/utils/Utils.mjs index 5d9715d..ffab09e 100644 --- a/src/utils/Utils.mjs +++ b/src/utils/Utils.mjs @@ -16,6 +16,7 @@ class Utils { this.refreshKickList(); // Turn on kickList refreshing this.rulesList = rulesList; // Set rulesList this.refreshRulesList(); // Turn on rulesList refreshing + this.banRegistry(); // Set banRegistry this.link = new Link(); // Set Link class this.discordReply = new DiscordReply(); // Set DiscordReply class this.webhookLogger = new WebhookLogger(); // Set WebhookLogger class @@ -863,6 +864,83 @@ class Debug { } } +class BanRegistry { + constructor() { + this.bans = {}; + } + + /** + * Adds or updates a ban entry for a user. + * @param {string} username - The user's name. + * @param {Date|number} banEnd - The ban end as a Date object or timestamp (ms). + */ + addBan(username, banEnd) { + this.bans[username] = { + banStart: new Date(), + banEnd: banEnd instanceof Date ? banEnd : new Date(banEnd), + }; + } + + removeBan(username) { + delete this.bans[username]; + } + + isBanned(username) { + return !!this.bans[username]; + } + + parseDuration(input) { + if (typeof input !== "string") return null; + + const regex = /^(?:(\d+)\s*m(?!.*m))?(?:(\d+)\s*d(?!.*d))?(?:(\d+)\s*h(?!.*h))?(?:(\d+)\s*min(?!.*min))?$/gi; + let match; + let totalMillis = 0; + + while ((match = regex.exec(input)) !== null) { + const value = parseInt(match[1]); + const unit = match[2].toLowerCase(); + + switch (unit) { + case "d": + totalMs += value * 24 * 60 * 60 * 1000; + break; + case "h": + totalMs += value * 60 * 60 * 1000; + break; + case "m": + case "min": + totalMs += value * 60 * 1000; + break; + } + } + return totalMs || null; + } + + getRemainingBanDuration(registry, username) { + const banData = registry.bans[username]; + if (!banData) return null; + + if (banData.banEnd === Infinity) return "permanent ban"; + + const now = Date.now(); + const diffMillis = banData.banEnd.getTime() - now; + if (diffMillis <= 0) return "ban has expired"; + + const seconds = Math.floor(diffMillis / 1000) % 60; + const minutes = Math.floor(diffMillis / (1000 * 60)) % 60; + const hours = Math.floor(diffMillis / (1000 * 60 * 60)) % 24; + const days = Math.floor(diffMillis / (1000 * 60 * 60 * 24)); + + let parts = []; + if (days) parts.push(`${days} day${days !== 1 ? "s" : ""}`); + if (hours) parts.push(`${hours} hour${hours !== 1 ? "s" : ""}`); + if (minutes) parts.push(`${minutes} minute${minutes !== 1 ? "s" : ""}`); + if (seconds) parts.push(`${seconds} second${seconds !== 1 ? "s" : ""}`); + + return parts.length ? parts.join(", ") : "less than a second"; + } +} + class Link { constructor() { this.collection = new Collection(); From f3760ec305d77ad56ee116e9cf2159c46acb2558 Mon Sep 17 00:00:00 2001 From: unterrunden <133593594+unterrunden@users.noreply.github.com> Date: Tue, 10 Jun 2025 17:00:00 +0200 Subject: [PATCH 8/9] Update Unban.mjs temporary ban option --- src/mineflayer/commands/party/Unban.mjs | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/mineflayer/commands/party/Unban.mjs b/src/mineflayer/commands/party/Unban.mjs index e160742..b153ded 100644 --- a/src/mineflayer/commands/party/Unban.mjs +++ b/src/mineflayer/commands/party/Unban.mjs @@ -51,9 +51,19 @@ export default { ); } } - + bot.reply(sender, `Trying to unban ${player}...`, VerbosityLevel.Reduced); + if (!registry.isBanned(username)) { + return bot.reply(sender, `${username} is not currently banned.`, VerbosityLevel.Reduced); + } else { + const remaining = getRemainingDuration(registry, player); + if (remaining && remaining !== "ban has expired") { + registry.removeBan(username); + return bot.reply(sender, `${username}'s ban has been reduced from ${remaining} to unbanned.`, VerbosityLevel.Reduced); + } + } + await bot.utils.delay(bot.utils.minMsgDelay); bot.chat(`/lobby`); await bot.utils.delay(bot.utils.minMsgDelay); From 8c8febe78cfb8f514fe48984d91ad45fefcb42cc Mon Sep 17 00:00:00 2001 From: unterrunden <133593594+unterrunden@users.noreply.github.com> Date: Tue, 10 Jun 2025 17:00:05 +0200 Subject: [PATCH 9/9] Update Ban.mjs temporary ban option --- src/mineflayer/commands/party/Ban.mjs | 39 ++++++++++++++++++++++++--- 1 file changed, 35 insertions(+), 4 deletions(-) diff --git a/src/mineflayer/commands/party/Ban.mjs b/src/mineflayer/commands/party/Ban.mjs index 4f13f83..de82ae4 100644 --- a/src/mineflayer/commands/party/Ban.mjs +++ b/src/mineflayer/commands/party/Ban.mjs @@ -4,10 +4,14 @@ import { WebhookMessageType, } from "../../../utils/Interfaces.mjs"; +import { BanRegistry } from "../../../utils/Utils.mjs"; + +const registry = new BanRegistry(); + export default { name: ["ban", "block"], - description: "Ban a player from joining the party", - usage: "!p ban [reason]", + description: "Ban a player from joining the party, permanently or temporarily (durations in m, d, h, min)", + usage: "!p ban [duration] [reason]", permission: Permissions.Trusted, /** @@ -25,7 +29,18 @@ export default { if (playerExists === false) { return bot.reply(sender, `Player ${player} not found`, VerbosityLevel.Reduced); } - const reason = args.slice(1).join(" ") || "No reason given."; + + let duration, reason; + if (args.length > 2) { + duration = args[1]; + reason = args.slice(2).join(" "); + } else if (args.length === 2) { + duration = 2592000000; + reason = args[1]; + } else { + duration = 2590002000; + reason = "No reason given."; + } if (!bot.utils.isHigherRanked(sender.username, player)) { const senderPermsRank = bot.utils.getPermissionsByUser({ name: sender.username }); @@ -51,9 +66,25 @@ export default { ); } } - + bot.reply(sender, `Trying to ban ${player}...`, VerbosityLevel.Reduced); + const remaining = getRemainingBanDuration(registry, player); + if (remaining && remaining !== "ban has expired") { + return bot.reply(sender, `This player is already banned, unban in ${remaining}.`, VerbosityLevel.Reduced); + } else if (remaining === "permanent ban") { + return bot.reply(sender, `This player is already banned permanently.`, VerbosityLevel.Reduced); + } + + const durationMillis = duration === 2592000000 ? 2592000000 : parseDuration(duration); + + if (durationMillis === null) { + return bot.reply(sender, `Could not parse the duration (${durationInput}). Please try again or use \`!p ban help\` for help.`, VerbosityLevel.Reduced); + } + + const banEndTimestamp = new Date(Date.now() + durationMillis); + registry.addBan(player, banEndTimestamp); + await bot.utils.delay(bot.utils.minMsgDelay); bot.chat(`/lobby`); await bot.utils.delay(bot.utils.minMsgDelay);