Skip to content

Commit

Permalink
templates: block nested template executors (#1677)
Browse files Browse the repository at this point in the history
* templates: flag templates executed by inbuilt cmds

Add a flag for templates which are executed from the templates of
inbuilt commands.

Signed-off-by: SoggySaussages <vmdmaharaj@gmail.com>

* moderation: block nested exec(Admin) calls

Blocks nested exec/execAdmin calls by passing an
"executedByCommandTemplate" flag through moderation command execution.
When this flag reaches a new context created by a moderation command,
it turns into ExecutedFromNextedCommandTemplate. This flag blocks
moderation commands from running.

Signed-off-by: SoggySaussages <vmdmaharaj@gmail.com>

* tickets: block nested exec(Admin) calls

Blocks nested exec/execAdmin calls and createTicket calls by passing an
"executedByCommandTemplate" flag through moderation command execution.
When this flag reaches a new context created by a ticket, it turns into
ExecutedFromNextedCommandTemplate. This flag blocks moderation commands
and tickets from running.

Signed-off-by: SoggySaussages <vmdmaharaj@gmail.com>

* moderation: fix nesting detection

Signed-off-by: SoggySaussages <vmdmaharaj@gmail.com>

* tickets: fix nesting detection

Signed-off-by: SoggySaussages <vmdmaharaj@gmail.com>

* templates: block execCC from inbuilt cmd templates

Signed-off-by: SoggySaussages <vmdmaharaj@gmail.com>

* moderation: further fix nest detection

Signed-off-by: SoggySaussages <vmdmaharaj@gmail.com>

* tickets: further fix nest detection

Signed-off-by: SoggySaussages <vmdmaharaj@gmail.com>

---------

Signed-off-by: SoggySaussages <vmdmaharaj@gmail.com>
  • Loading branch information
SoggySaussages authored Jun 21, 2024
1 parent b213ce5 commit 39eb40a
Show file tree
Hide file tree
Showing 13 changed files with 97 additions and 40 deletions.
10 changes: 5 additions & 5 deletions automod/effects.go
Original file line number Diff line number Diff line change
Expand Up @@ -269,7 +269,7 @@ func (kick *KickUserEffect) Apply(ctxData *TriggeredRuleData, settings interface
reason += ctxData.ConstructReason(true)
}

err := moderation.KickUser(nil, ctxData.GS.ID, ctxData.CS, ctxData.Message, common.BotUser, reason, &ctxData.MS.User, -1)
err := moderation.KickUser(nil, ctxData.GS.ID, ctxData.CS, ctxData.Message, common.BotUser, reason, &ctxData.MS.User, -1, false)
return err
}

Expand Down Expand Up @@ -340,7 +340,7 @@ func (ban *BanUserEffect) Apply(ctxData *TriggeredRuleData, settings interface{}
}

duration := time.Duration(settingsCast.Duration) * time.Minute
err := moderation.BanUserWithDuration(nil, ctxData.GS.ID, ctxData.CS, ctxData.Message, common.BotUser, reason, &ctxData.MS.User, duration, settingsCast.MessageDeleteDays)
err := moderation.BanUserWithDuration(nil, ctxData.GS.ID, ctxData.CS, ctxData.Message, common.BotUser, reason, &ctxData.MS.User, duration, settingsCast.MessageDeleteDays, false)
return err
}

Expand Down Expand Up @@ -402,7 +402,7 @@ func (mute *MuteUserEffect) Apply(ctxData *TriggeredRuleData, settings interface
reason += ctxData.ConstructReason(true)
}

err := moderation.MuteUnmuteUser(nil, true, ctxData.GS.ID, ctxData.CS, ctxData.Message, common.BotUser, reason, ctxData.MS, settingsCast.Duration)
err := moderation.MuteUnmuteUser(nil, true, ctxData.GS.ID, ctxData.CS, ctxData.Message, common.BotUser, reason, ctxData.MS, settingsCast.Duration, false)
return err
}

Expand Down Expand Up @@ -472,7 +472,7 @@ func (timeout *TimeoutUserEffect) Apply(ctxData *TriggeredRuleData, settings int
}

duration := time.Duration(settingsCast.Duration) * time.Minute
err := moderation.TimeoutUser(nil, ctxData.GS.ID, ctxData.CS, ctxData.Message, common.BotUser, reason, &ctxData.MS.User, duration)
err := moderation.TimeoutUser(nil, ctxData.GS.ID, ctxData.CS, ctxData.Message, common.BotUser, reason, &ctxData.MS.User, duration, false)
return err
}

Expand Down Expand Up @@ -526,7 +526,7 @@ func (warn *WarnUserEffect) Apply(ctxData *TriggeredRuleData, settings interface
reason += ctxData.ConstructReason(true)
}

err := moderation.WarnUser(nil, ctxData.GS.ID, ctxData.CS, ctxData.Message, common.BotUser, &ctxData.MS.User, reason)
err := moderation.WarnUser(nil, ctxData.GS.ID, ctxData.CS, ctxData.Message, common.BotUser, &ctxData.MS.User, reason, false)
return err
}

Expand Down
8 changes: 4 additions & 4 deletions automod_legacy/bot.go
Original file line number Diff line number Diff line change
Expand Up @@ -152,13 +152,13 @@ func CheckMessage(evt *eventsystem.EventData, m *discordgo.Message) bool {
go func() {
switch highestPunish {
case PunishNone:
err = moderation.WarnUser(nil, cs.GuildID, cs, m, common.BotUser, &member.User, "Automoderator: "+punishMsg)
err = moderation.WarnUser(nil, cs.GuildID, cs, m, common.BotUser, &member.User, "Automoderator: "+punishMsg, false)
case PunishMute:
err = moderation.MuteUnmuteUser(nil, true, cs.GuildID, cs, m, common.BotUser, "Automoderator: "+punishMsg, member, muteDuration)
err = moderation.MuteUnmuteUser(nil, true, cs.GuildID, cs, m, common.BotUser, "Automoderator: "+punishMsg, member, muteDuration, false)
case PunishKick:
err = moderation.KickUser(nil, cs.GuildID, cs, m, common.BotUser, "Automoderator: "+punishMsg, &member.User, -1)
err = moderation.KickUser(nil, cs.GuildID, cs, m, common.BotUser, "Automoderator: "+punishMsg, &member.User, -1, false)
case PunishBan:
err = moderation.BanUser(nil, cs.GuildID, cs, m, common.BotUser, "Automoderator: "+punishMsg, &member.User)
err = moderation.BanUser(nil, cs.GuildID, cs, m, common.BotUser, "Automoderator: "+punishMsg, &member.User, false)
}

// Execute the punishment before removing the message to make sure it's included in logs
Expand Down
2 changes: 2 additions & 0 deletions commands/commands.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ const (
CtxKeyCmdSettings CtxKey = iota
CtxKeyChannelOverride
CtxKeyExecutedByCC
CtxKeyExecutedByCommandTemplate
CtxKeyExecutedByNestedCommandTemplate
)

type MessageFilterFunc func(evt *eventsystem.EventData, msg *discordgo.Message) bool
Expand Down
7 changes: 7 additions & 0 deletions commands/tmplexec.go
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,13 @@ func execCmd(tmplCtx *templates.Context, dryRun bool, m *discordgo.MessageCreate
data = data.WithContext(context.WithValue(data.Context(), paginatedmessages.CtxKeyNoPagination, true))
data = data.WithContext(context.WithValue(data.Context(), CtxKeyExecutedByCC, true))

switch tmplCtx.ExecutedFrom {
case templates.ExecutedFromCommandTemplate:
data = data.WithContext(context.WithValue(data.Context(), CtxKeyExecutedByCommandTemplate, true))
case templates.ExecutedFromNestedCommandTemplate:
data = data.WithContext(context.WithValue(data.Context(), CtxKeyExecutedByNestedCommandTemplate, true))
}

cast := foundCmd.Command.(*YAGCommand)

err = dcmd.ParseCmdArgs(data)
Expand Down
10 changes: 6 additions & 4 deletions common/templates/context.go
Original file line number Diff line number Diff line change
Expand Up @@ -157,10 +157,12 @@ var GuildPremiumFunc func(guildID int64) (bool, error)
type ExecutedFromType int

const (
ExecutedFromStandard ExecutedFromType = 0
ExecutedFromJoin ExecutedFromType = 1
ExecutedFromLeave ExecutedFromType = 2
ExecutedFromEvalCC ExecutedFromType = 3
ExecutedFromStandard ExecutedFromType = 0
ExecutedFromJoin ExecutedFromType = 1
ExecutedFromLeave ExecutedFromType = 2
ExecutedFromEvalCC ExecutedFromType = 3
ExecutedFromCommandTemplate ExecutedFromType = 4
ExecutedFromNestedCommandTemplate ExecutedFromType = 5
)

type Context struct {
Expand Down
4 changes: 4 additions & 0 deletions customcommands/tmplextensions.go
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,10 @@ func (pa *ParsedArgs) IsSet(index int) interface{} {
// or schedules a custom command to be run in the future sometime with the provided data placed in .ExecData
func tmplRunCC(ctx *templates.Context) interface{} {
return func(ccID int, channel interface{}, delaySeconds interface{}, data interface{}) (string, error) {
if ctx.ExecutedFrom == templates.ExecutedFromCommandTemplate || ctx.ExecutedFrom == templates.ExecutedFromNestedCommandTemplate {
return "", nil
}

if ctx.IncreaseCheckCallCounterPremium("runcc", 1, 10) {
return "", templates.ErrTooManyCalls
}
Expand Down
35 changes: 29 additions & 6 deletions moderation/commands.go
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,10 @@ var ModerationCommands = []*commands.YAGCommand{
DefaultEnabled: false,
IsResponseEphemeral: true,
RunFunc: func(parsed *dcmd.Data) (interface{}, error) {
if parsed.Context().Value(commands.CtxKeyExecutedByNestedCommandTemplate) == true {
return nil, errors.New("cannot nest exec/execAdmin calls")
}

config, target, err := MBaseCmd(parsed, parsed.Args[0].Int64())
if err != nil {
return nil, err
Expand Down Expand Up @@ -199,7 +203,7 @@ var ModerationCommands = []*commands.YAGCommand{
if parsed.TraditionalTriggerData != nil {
msg = parsed.TraditionalTriggerData.Message
}
err = BanUserWithDuration(config, parsed.GuildData.GS.ID, parsed.GuildData.CS, msg, parsed.Author, reason, target, banDuration, ddays)
err = BanUserWithDuration(config, parsed.GuildData.GS.ID, parsed.GuildData.CS, msg, parsed.Author, reason, target, banDuration, ddays, parsed.Context().Value(commands.CtxKeyExecutedByCommandTemplate) == true)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -275,6 +279,10 @@ var ModerationCommands = []*commands.YAGCommand{
SlashCommandEnabled: true,
IsResponseEphemeral: true,
RunFunc: func(parsed *dcmd.Data) (interface{}, error) {
if parsed.Context().Value(commands.CtxKeyExecutedByNestedCommandTemplate) == true {
return nil, errors.New("cannot nest exec/execAdmin calls")
}

config, target, err := MBaseCmd(parsed, parsed.Args[0].Int64())
if err != nil {
return nil, err
Expand Down Expand Up @@ -310,7 +318,7 @@ var ModerationCommands = []*commands.YAGCommand{
msg = parsed.TraditionalTriggerData.Message
}

err = KickUser(config, parsed.GuildData.GS.ID, parsed.GuildData.CS, msg, parsed.Author, reason, target, toDel)
err = KickUser(config, parsed.GuildData.GS.ID, parsed.GuildData.CS, msg, parsed.Author, reason, target, toDel, parsed.Context().Value(commands.CtxKeyExecutedByCommandTemplate) == true)
if err != nil {
return nil, err
}
Expand All @@ -335,6 +343,10 @@ var ModerationCommands = []*commands.YAGCommand{
DefaultEnabled: false,
IsResponseEphemeral: true,
RunFunc: func(parsed *dcmd.Data) (interface{}, error) {
if parsed.Context().Value(commands.CtxKeyExecutedByNestedCommandTemplate) == true {
return nil, errors.New("cannot nest exec/execAdmin calls")
}

config, target, err := MBaseCmd(parsed, parsed.Args[0].Int64())
if err != nil {
return nil, err
Expand Down Expand Up @@ -369,7 +381,7 @@ var ModerationCommands = []*commands.YAGCommand{
if parsed.TraditionalTriggerData != nil {
msg = parsed.TraditionalTriggerData.Message
}
err = MuteUnmuteUser(config, true, parsed.GuildData.GS.ID, parsed.GuildData.CS, msg, parsed.Author, reason, member, int(d.Minutes()))
err = MuteUnmuteUser(config, true, parsed.GuildData.GS.ID, parsed.GuildData.CS, msg, parsed.Author, reason, member, int(d.Minutes()), parsed.Context().Value(commands.CtxKeyExecutedByCommandTemplate) == true)
if err != nil {
return nil, err
}
Expand All @@ -394,6 +406,10 @@ var ModerationCommands = []*commands.YAGCommand{
DefaultEnabled: false,
IsResponseEphemeral: true,
RunFunc: func(parsed *dcmd.Data) (interface{}, error) {
if parsed.Context().Value(commands.CtxKeyExecutedByNestedCommandTemplate) == true {
return nil, errors.New("cannot nest exec/execAdmin calls")
}

config, target, err := MBaseCmd(parsed, parsed.Args[0].Int64())
if err != nil {
return nil, err
Expand All @@ -418,7 +434,7 @@ var ModerationCommands = []*commands.YAGCommand{
if parsed.TraditionalTriggerData != nil {
msg = parsed.TraditionalTriggerData.Message
}
err = MuteUnmuteUser(config, false, parsed.GuildData.GS.ID, parsed.GuildData.CS, msg, parsed.Author, reason, member, 0)
err = MuteUnmuteUser(config, false, parsed.GuildData.GS.ID, parsed.GuildData.CS, msg, parsed.Author, reason, member, 0, parsed.Context().Value(commands.CtxKeyExecutedByCommandTemplate) == true)
if err != nil {
return nil, err
}
Expand All @@ -444,6 +460,9 @@ var ModerationCommands = []*commands.YAGCommand{
DefaultEnabled: false,
IsResponseEphemeral: true,
RunFunc: func(parsed *dcmd.Data) (interface{}, error) {
if parsed.Context().Value(commands.CtxKeyExecutedByNestedCommandTemplate) == true {
return nil, errors.New("cannot nest exec/execAdmin calls")
}
config, target, err := MBaseCmd(parsed, parsed.Args[0].Int64())
if err != nil {
return nil, err
Expand Down Expand Up @@ -474,7 +493,7 @@ var ModerationCommands = []*commands.YAGCommand{
if parsed.TraditionalTriggerData != nil {
msg = parsed.TraditionalTriggerData.Message
}
err = TimeoutUser(config, parsed.GuildData.GS.ID, parsed.GuildData.CS, msg, parsed.Author, reason, &member.User, d)
err = TimeoutUser(config, parsed.GuildData.GS.ID, parsed.GuildData.CS, msg, parsed.Author, reason, &member.User, d, parsed.Context().Value(commands.CtxKeyExecutedByCommandTemplate) == true)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -821,6 +840,10 @@ var ModerationCommands = []*commands.YAGCommand{
DefaultEnabled: false,
IsResponseEphemeral: true,
RunFunc: func(parsed *dcmd.Data) (interface{}, error) {
if parsed.Context().Value(commands.CtxKeyExecutedByNestedCommandTemplate) == true {
return nil, errors.New("cannot nest exec/execAdmin calls")
}

config, target, err := MBaseCmd(parsed, parsed.Args[0].Int64())
if err != nil {
return nil, err
Expand All @@ -839,7 +862,7 @@ var ModerationCommands = []*commands.YAGCommand{
if parsed.TraditionalTriggerData != nil {
msg = parsed.TraditionalTriggerData.Message
}
err = WarnUser(config, parsed.GuildData.GS.ID, parsed.GuildData.CS, msg, parsed.Author, target, parsed.Args[1].Str())
err = WarnUser(config, parsed.GuildData.GS.ID, parsed.GuildData.CS, msg, parsed.Author, target, parsed.Args[1].Str(), parsed.Context().Value(commands.CtxKeyExecutedByCommandTemplate) == true)
if err != nil {
return nil, err
}
Expand Down
2 changes: 1 addition & 1 deletion moderation/plugin_bot.go
Original file line number Diff line number Diff line change
Expand Up @@ -721,7 +721,7 @@ func handleScheduledUnmute(evt *seventsmodels.ScheduledEvent, data interface{})
return scheduledevents2.CheckDiscordErrRetry(err), err
}

err = MuteUnmuteUser(nil, false, evt.GuildID, nil, nil, common.BotUser, "Mute Duration Expired", member, 0)
err = MuteUnmuteUser(nil, false, evt.GuildID, nil, nil, common.BotUser, "Mute Duration Expired", member, 0, false)
if errors.Cause(err) != ErrNoMuteRole {
return scheduledevents2.CheckDiscordErrRetry(err), err
}
Expand Down
Loading

0 comments on commit 39eb40a

Please sign in to comment.