Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Bug] System Commands Forwarded from Run Command Ignore Restrictions #2999

Open
CrowbarToolsRobot opened this issue Feb 16, 2025 · 1 comment
Labels
Dev Approved The issue has been approved by a team member and can be worked on. Enhancement A feature request or improvement

Comments

@CrowbarToolsRobot
Copy link
Collaborator

Description

With a currency literally named totally-fake-internet-points™, we attempted to add a custom command !currency that used a Run Command effect to trigger the !totally-fake-internet-points™ command with $arg[all] as the argument, and $user as the triggerer. !currency set @username [amount] then bypasses the streamer/moderator restrictions of the totally-fake-internet-points™ set subcommand.

Steps to Reproduce

Expected Behavior

Warn that the restrictions weren't met.

Firebot Version

v5.63.2

Submitted By

phroggie

Created via Discord.

@CrowbarToolsRobot CrowbarToolsRobot added the Bug A defect in the app label Feb 16, 2025
@github-project-automation github-project-automation bot moved this to Todo in Firebot Feb 16, 2025
@CaveMobster CaveMobster added the Dev Approved The issue has been approved by a team member and can be worked on. label Feb 16, 2025
@CKY- CKY- added Enhancement A feature request or improvement and removed Bug A defect in the app labels Feb 21, 2025
@CKY-
Copy link
Collaborator

CKY- commented Feb 21, 2025

this is not a bug that is working as intended
changing to a FR from a bug

the issue is the restrictions are in the handel chat message and would need to be moved to firecommand

handel chat message checks the restrictions and then runs fireCommand

fireCommnad is used in 3 places
in the chat handler and to test the command then to run command from effect
effects are treated as test this command

so then the question is should the restriction check be in the fireCommand and be bypassed by isManual

and then isManual exposed in the runCommandEffect as a Enforce Permission Rules and Cool Downs

the other option is we add a checkbox and switch from runCommandFromEffectt to handelChatMessage striping the original trigger and replacing it with the trigger from the ID supplied and this will allow the usage of the command to be tracked as well

private runCommandFromEffect(command: CommandDefinition, trigger: Trigger, args: string[]): void {
const message = `${command.trigger} ${args}`;
const firebotChatMessage = chatHelpers.buildBasicFirebotChatMessage(message, trigger.metadata.username);
if (command != null) {
const userCmd = this.buildUserCommand(command, message, trigger.metadata.username);
this.fireCommand(command, userCmd, firebotChatMessage, trigger.metadata.username, false);
}
}
runSystemCommandFromEffect(id: string, trigger: Trigger, args: string[]): void {
const command = commandManager.getSystemCommandById(id).definition;
this.runCommandFromEffect(command, trigger, args);
}
runCustomCommandFromEffect(id: string, trigger: Trigger, args: string[]): void {
const command = commandManager.getCustomCommandById(id);
this.runCommandFromEffect(command, trigger, args);
}
}

async handleChatMessage(firebotChatMessage: FirebotChatMessage): Promise<boolean> {
const twitchChat = require("../twitch-chat");
logger.debug("Checking for command in message...");
// Username of the person that sent the command.
const commandSender = firebotChatMessage.username;
// Check to see if handled message array contains the id of this message already.
// If it does, that means that one of the logged in accounts has already handled the message.
if (this._handledMessageIds.includes(firebotChatMessage.id)) {
// We can remove the handled id now, to keep the array small.
this._handledMessageIds = this._handledMessageIds.filter(id => id !== firebotChatMessage.id);
return false;
}
// throw the message id into the array. This prevents both the bot and the streamer accounts from replying
this._handledMessageIds.push(firebotChatMessage.id);
logger.debug("Combining message segments...");
const rawMessage = firebotChatMessage.rawText;
// search for and return command if found
logger.debug("Searching for command...");
const { command, matchedTrigger } = this.checkForCommand(rawMessage);
// command wasn't found
if (command == null) {
return false;
}
const { streamer, bot } = accountAccess.getAccounts();
// check if chat came from the streamer and if we should ignore it.
if (command.ignoreStreamer && firebotChatMessage.username === streamer.username) {
logger.debug("Message came from streamer and this command is set to ignore it");
return false;
}
// check if chat came from the bot and if we should ignore it.
if (command.ignoreBot && firebotChatMessage.username === bot.username) {
logger.debug("Message came from bot and this command is set to ignore it");
return false;
}
// check if chat came via whisper and if we should ignore it.
if (command.ignoreWhispers && firebotChatMessage.whisper) {
logger.debug("Message came from whisper and this command is set to ignore it");
return false;
}
// build usercommand object
const userCmd = commandRunner.buildUserCommand(command, rawMessage, commandSender, firebotChatMessage.roles);
const triggeredSubcmd = userCmd.triggeredSubcmd;
// update trigger with the one we matched
userCmd.trigger = matchedTrigger;
// command is disabled
if (triggeredSubcmd && triggeredSubcmd.active === false) {
logger.debug("This Command is disabled");
return false;
}
if (userCmd.isInvalidSubcommandTrigger === true) {
await twitchChat.sendChatMessage(`Invalid Command: unknown arg used.`);
return false;
}
// Can't auto delete whispers, so we ignore auto delete trigger for those
if (firebotChatMessage.whisper !== true && command.autoDeleteTrigger || (triggeredSubcmd && triggeredSubcmd.autoDeleteTrigger)) {
logger.debug("Auto delete trigger is on, attempting to delete chat message");
await twitchApi.chat.deleteChatMessage(firebotChatMessage.id);
}
// check if command meets min args requirement
const minArgs = triggeredSubcmd ? triggeredSubcmd.minArgs || 0 : command.minArgs || 0;
if (userCmd.args.length < minArgs) {
const usage = triggeredSubcmd ? triggeredSubcmd.usage : command.usage;
await twitchChat.sendChatMessage(`Invalid command. Usage: ${command.trigger} ${usage || ""}`);
return false;
}
logger.debug("Checking cooldowns for command...");
// Check if the command is on cooldown
const remainingCooldown = commandCooldownManager.getRemainingCooldown(
command,
triggeredSubcmd,
commandSender
);
if (remainingCooldown > 0) {
logger.debug("Command is still on cooldown, alerting viewer...");
if (command.sendCooldownMessage || command.sendCooldownMessage == null) {
const cooldownMessage = command.useCustomCooldownMessage ? command.cooldownMessage : DEFAULT_COOLDOWN_MESSAGE;
await twitchChat.sendChatMessage(
cooldownMessage
.replace("{user}", commandSender)
.replace("{timeLeft}", util.secondsForHumans(remainingCooldown)),
null,
null,
firebotChatMessage.id
);
}
return false;
}
// Check if command passes all restrictions
const restrictionData =
triggeredSubcmd && triggeredSubcmd.restrictionData && triggeredSubcmd.restrictionData.restrictions
&& triggeredSubcmd.restrictionData.restrictions.length > 0
? triggeredSubcmd.restrictionData
: command.restrictionData;
if (restrictionData) {
logger.debug("Command has restrictions...checking them.");
const triggerData = {
type: TriggerType.COMMAND,
metadata: {
username: commandSender,
userId: firebotChatMessage.userId,
userDisplayName: firebotChatMessage.userDisplayName,
userTwitchRoles: firebotChatMessage.roles,
command: command,
userCommand: userCmd,
chatMessage: firebotChatMessage
}
};
try {
await restrictionsManager.runRestrictionPredicates(triggerData, restrictionData);
logger.debug("Restrictions passed!");
} catch (restrictionReason) {
let reason;
if (Array.isArray(restrictionReason)) {
reason = restrictionReason.join(", ");
} else {
reason = restrictionReason;
}
logger.debug(`${commandSender} could not use command '${command.trigger}' because: ${reason}`);
if (restrictionData.sendFailMessage || restrictionData.sendFailMessage == null) {
const restrictionMessage = restrictionData.useCustomFailMessage ?
restrictionData.failMessage :
DEFAULT_RESTRICTION_MESSAGE;
await twitchChat.sendChatMessage(
restrictionMessage
.replace("{user}", commandSender)
.replace("{reason}", reason),
null,
null,
firebotChatMessage.id
);
}
return false;
}
}
// If command is not on cooldown AND it passes restrictions, then we can run it. Store the cooldown.
commandCooldownManager.cooldownCommand(command, triggeredSubcmd, commandSender);
//update the count for the command
if (command.type === "custom") {
logger.debug("Updating command count.");
this.updateCommandCount(command);
}
commandRunner.fireCommand(command, userCmd, firebotChatMessage, commandSender, false);
return true;
}

i personally think reusing the handelChatMessage with option to enforce cooldowns and restrictions is the better way to go here.

@CKY- CKY- marked this as a duplicate of #2751 Feb 25, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Dev Approved The issue has been approved by a team member and can be worked on. Enhancement A feature request or improvement
Projects
Status: Todo
Development

No branches or pull requests

3 participants