Skip to content

Commit

Permalink
Add /delete command to nuke CTF from Discord server
Browse files Browse the repository at this point in the history
Fixes #3
  • Loading branch information
kriive committed Jan 18, 2024
1 parent bb0e5d8 commit 8d3a476
Show file tree
Hide file tree
Showing 4 changed files with 110 additions and 3 deletions.
4 changes: 4 additions & 0 deletions discord/commands.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,10 @@ var commands = []discord.ApplicationCommandCreate{
Name: "blood",
Description: "Marks the challenge as solved with a 🩸 emoji.",
},
discord.SlashCommandCreate{
Name: "delete",
Description: "[admin] Deletes the CTF.",
},
discord.SlashCommandCreate{
Name: "chal",
Description: "Add new text channel to discuss chal.",
Expand Down
94 changes: 92 additions & 2 deletions discord/ctf.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,13 @@ func (s *Server) handleCommandNewCTF(event *handler.CommandEvent) error {

urlEncodedCTFName := url.PathEscape(ctfName)

_, err := event.CreateFollowupMessage(discord.NewMessageCreateBuilder().
// Check if CTF is already present with the same name.
_, err := s.CTFService.FindCTFByName(context.TODO(), ctfName)
if err == nil {
return Error(event, havcebot.Errorf(havcebot.ECONFLICT, "A CTF with the same name has already been created."))
}

_, err = event.CreateFollowupMessage(discord.NewMessageCreateBuilder().
SetEmbeds(discord.NewEmbedBuilder().
SetColor(ColorBlurple).
SetDescriptionf("Would you like to create a new CTF named `%s`?", ctfName).
Expand Down Expand Up @@ -87,13 +93,97 @@ func (s *Server) extractCTFName(name string) string {
return event.Title
}

func (s *Server) handleCommandDeleteCTF(event *handler.CommandEvent) error {
ctf, err := s.parentChannel(event.Channel().ID())
if err != nil {
return Error(event, err)
}

ctfName := ctf.Name()

err = event.CreateMessage(discord.NewMessageCreateBuilder().
SetEmbeds(discord.NewEmbedBuilder().
SetColor(ColorRed).
SetDescriptionf("Would you like to delete `%s`? There's no undo.", ctfName).
Build()).
SetEphemeral(true).
AddActionRow(
discord.NewDangerButton("Yes, delete it", "delete/really"),
).
Build(),
)
if err != nil {
return Error(event, err)
}

return err
}

func (s *Server) handleDeleteCTF(event *handler.ComponentEvent) error {
ctf, err := s.parentChannel(event.Channel().ID())
if err != nil {
return Error(event, err)
}

ctfName := ctf.Name()

siblings := []snowflake.ID{}
s.client.Caches().ChannelsForEach(func(channel discord.GuildChannel) {
if channel.ParentID() == nil {
return
}

if *channel.ParentID() != ctf.ID() {
return
}

siblings = append(siblings, channel.ID())
})

// Delete all channels.
for _, channel := range siblings {
if err := s.client.Rest().DeleteChannel(channel); err != nil {
return Error(event, err)
}
}

// Delete parent.
if err := s.client.Rest().DeleteChannel(ctf.ID()); err != nil {
return Error(event, err)
}

// Fetch the CTF from DB to get the role ID to delete.
ctfFromDB, err := s.CTFService.FindCTFByName(context.TODO(), ctfName)
if err != nil {
return Error(event, err)
}

roleID, err := snowflake.Parse(ctfFromDB.RoleID)
if err != nil {
return Error(event, err)
}

// Delete the role from Discord.
if err := s.client.Rest().DeleteRole(*event.GuildID(), roleID); err != nil {
return Error(event, err)
}

// Delete the CTF from db.
if err := s.CTFService.DeleteCTF(context.TODO(), ctfName); err != nil {
return Error(event, err)
}

Respond(event, "Deletion completed", fmt.Sprintf("You successfully deleted `%s`", ctfName))
return nil
}

func (s *Server) handleCreateCTF(event *handler.ComponentEvent) error {
ctf, err := url.PathUnescape(event.Variables["ctf"])
if err != nil {
return Error(event, err)
}

// Check if CTF is already present with the same name.
// Check again if CTF is already present with the same name.
_, err = s.CTFService.FindCTFByName(context.TODO(), ctf)
if err == nil {
return Error(event, havcebot.Errorf(havcebot.ECONFLICT, "A CTF with the same name has already been created."))
Expand Down
9 changes: 8 additions & 1 deletion discord/middlewares.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,12 @@ var AdminOnly handler.Middleware = func(next handler.Handler) handler.Handler {
}
}

func (s *Server) MustBeInsideCTFAndAdmin(next handler.Handler) handler.Handler {
return func(e *events.InteractionCreate) error {
return AdminOnly(s.MustBeInsideCTF(next))(e)
}
}

// MustBeInsideCTF is a middleware that checks whether the event
// comes from a registered CTF. Otherwise it fails.
func (s *Server) MustBeInsideCTF(next handler.Handler) handler.Handler {
Expand All @@ -33,10 +39,11 @@ func (s *Server) MustBeInsideCTF(next handler.Handler) handler.Handler {

_, err = s.CTFService.FindCTFByName(context.TODO(), parent.Name())
if err != nil {
return e.Respond(discord.InteractionResponseTypeCreateMessage,
_ = e.Respond(discord.InteractionResponseTypeCreateMessage,
discord.NewMessageCreateBuilder().
SetEphemeral(true).
SetEmbeds(messageEmbedError("You're not inside a CTF, you cannot issue this command here.")).Build())
return err
}

return next(e)
Expand Down
6 changes: 6 additions & 0 deletions discord/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,12 @@ func NewServer() *Server {
r.Command("/vote", s.handleInfoCTF(true))
})

s.router.Group(func(r handler.Router) {
r.Use(s.MustBeInsideCTFAndAdmin)
r.Command("/delete", s.handleCommandDeleteCTF)
r.Component("/delete/really", s.handleDeleteCTF)
})

// These routes must be hit while inside of a CTF.
s.router.Group(func(r handler.Router) {
r.Use(s.MustBeInsideCTF)
Expand Down

0 comments on commit 8d3a476

Please sign in to comment.