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

Add Query Command #40

Merged
merged 6 commits into from
Sep 15, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions commands/enabled.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ func populateSlashCommands(ctx ddtrace.SpanContext) {
SlashCommands["vote"] = slash.Vote()
SlashCommands["feedback"] = slash.Feedback()
SlashCommands["update"] = slash.Update()
SlashCommands["query"] = slash.Query()
}

// populateHandlers populates the Handlers map with all of the handlers
Expand Down
240 changes: 240 additions & 0 deletions commands/slash/query.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,240 @@
package slash

import (
"fmt"
"strings"
"time"

"github.com/bwmarrin/discordgo"
"github.com/sirupsen/logrus"
"gitlab.ritsec.cloud/1nv8rZim/ops-bot-iii/commands/slash/permission"
"gitlab.ritsec.cloud/1nv8rZim/ops-bot-iii/data"
"gitlab.ritsec.cloud/1nv8rZim/ops-bot-iii/ent/signin"
"gitlab.ritsec.cloud/1nv8rZim/ops-bot-iii/helpers"
"gitlab.ritsec.cloud/1nv8rZim/ops-bot-iii/logging"
"gitlab.ritsec.cloud/1nv8rZim/ops-bot-iii/structs"
"gopkg.in/DataDog/dd-trace-go.v1/ddtrace/tracer"
)

// Query users based on signins
func Query() *structs.SlashCommand {
minValue := float64(0)
return &structs.SlashCommand{
Command: &discordgo.ApplicationCommand{
Name: "query",
Description: "Query users by signins",
Options: []*discordgo.ApplicationCommandOption{
{
Name: "type",
Description: "The type of signin",
Type: discordgo.ApplicationCommandOptionString,
Required: true,
Choices: []*discordgo.ApplicationCommandOptionChoice{
{
Name: "All",
Value: "All",
},
{
Name: "General Meeting",
Value: "General Meeting",
},
{
Name: "Contagion",
Value: "Contagion",
},
{
Name: "DFIR",
Value: "DFIR",
},
{
Name: "Ops",
Value: "Ops",
},
{
Name: "Ops IG",
Value: "Ops IG",
},
{
Name: "Red Team",
Value: "Red Team",
},
{
Name: "Red Team Recruiting",
Value: "Red Team Recruiting",
},
{
Name: "Reversing",
Value: "Reversing",
},
{
Name: "RVAPT",
Value: "RVAPT",
},
{
Name: "Physical",
Value: "Physical",
},
{
Name: "Vulnerability Research",
Value: "Vulnerability Research",
},
{
Name: "Wireless",
Value: "Wireless",
},
{
Name: "WiCyS",
Value: "WiCyS",
},
{
Name: "Other",
Value: "Other",
},
},
},
{
Name: "hours",
Description: "The number of hours to query for",
Type: discordgo.ApplicationCommandOptionInteger,
Required: false,
MinValue: &minValue,
},
{
Name: "days",
Description: "The number of days to query for",
Type: discordgo.ApplicationCommandOptionInteger,
Required: false,
MinValue: &minValue,
},
{
Name: "weeks",
Description: "The number of weeks to query for",
Type: discordgo.ApplicationCommandOptionInteger,
Required: false,
MinValue: &minValue,
},
},
DefaultMemberPermissions: &permission.IGLead,
},
Handler: func(s *discordgo.Session, i *discordgo.InteractionCreate) {
span := tracer.StartSpan(
"commands.slash.signin:Signin",
tracer.ResourceName("/signin"),
)
defer span.Finish()

signinType := i.ApplicationCommandData().Options[0].StringValue()

var (
hours int
days int
weeks int
)

if len(i.ApplicationCommandData().Options) > 1 {
for _, option := range i.ApplicationCommandData().Options[1:] {
switch option.Name {
case "hours":
hours = int(option.IntValue())
case "days":
days = int(option.IntValue())
case "weeks":
weeks = int(option.IntValue())
}
}
}

var entSigninType signin.Type
switch signinType {
case "General Meeting":
entSigninType = signin.TypeGeneralMeeting
case "Contagion":
entSigninType = signin.TypeContagion
case "DFIR":
entSigninType = signin.TypeDFIR
case "Ops":
entSigninType = signin.TypeOps
case "Ops IG":
entSigninType = signin.TypeOpsIG
case "Red Team":
entSigninType = signin.TypeRedTeam
case "Red Team Recruiting":
entSigninType = signin.TypeRedTeamRecruiting
case "RVAPT":
entSigninType = signin.TypeRVAPT
case "Reversing":
entSigninType = signin.TypeReversing
case "Physical":
entSigninType = signin.TypePhysical
case "Wireless":
entSigninType = signin.TypeWireless
case "WiCyS":
entSigninType = signin.TypeWiCyS
case "Vulnerability Research":
entSigninType = signin.TypeVulnerabilityResearch
case "Other":
entSigninType = signin.TypeOther
case "All":
entSigninType = "All"
}

signins, err := data.Signin.Query(
time.Duration(hours)*time.Hour+time.Duration(days)*24*time.Hour+time.Duration(weeks)*7*24*time.Hour,
entSigninType,
span.Context(),
)
if err != nil {
logging.Error(s, err.Error(), i.Member.User, span, logrus.Fields{"error": err})
return
}

sum := 0
for _, signin := range signins {
sum += signin.Value
}

message := fmt.Sprintf("Signin Type: `%s`\nTotal Signins: `%d`\nTime Delta: `hours=%d,days=%d,weeks=%d`\n", signinType, sum, hours, days, weeks)

for _, signin := range signins {
message += fmt.Sprintf("[%d] %s\n", signin.Value, helpers.AtUser(signin.Key))
}

if len(message) <= 2000 {
err = s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{
Type: discordgo.InteractionResponseChannelMessageWithSource,
Data: &discordgo.InteractionResponseData{
Content: message,
Flags: discordgo.MessageFlagsEphemeral,
Files: []*discordgo.File{
{
Name: "query.txt",
ContentType: "text/plain",
Reader: strings.NewReader(message),
},
},
},
})
} else {
trimmedMessage := message[:2000]
trimmedMessage = trimmedMessage[:strings.LastIndex(trimmedMessage, "\n")]
err = s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{
Type: discordgo.InteractionResponseChannelMessageWithSource,
Data: &discordgo.InteractionResponseData{
Content: trimmedMessage,
Files: []*discordgo.File{
{
Name: "query.txt",
ContentType: "text/plain",
Reader: strings.NewReader(message),
},
},
Flags: discordgo.MessageFlagsEphemeral,
},
})
}
if err != nil {
logging.Error(s, err.Error(), i.Member.User, span, logrus.Fields{"error": err})
}
},
}
}
14 changes: 7 additions & 7 deletions commands/slash/signin.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package slash

import (
"fmt"
"strings"
"time"

"github.com/bwmarrin/discordgo"
Expand Down Expand Up @@ -233,6 +234,7 @@ func Signin() *structs.SlashCommand {
}

time.Sleep(time.Duration(delay) * time.Hour)

err = s.ChannelMessageDelete(i.ChannelID, message.ID)
if err != nil {
logging.Error(s, "Error encounted while deleting message\n\n"+err.Error(), i.Member.User, span, logrus.Fields{"error": err})
Expand All @@ -246,17 +248,15 @@ func Signin() *structs.SlashCommand {

msg := fmt.Sprintf("Signins for `%s`; %d users signed in:\n", signinType, len(userPairs))
for _, user := range userPairs {
username, err := helpers.Username(s, user.Key)
if err != nil {
logging.Error(s, err.Error(), i.Member.User, span, logrus.Fields{"error": err})
username = "Failed to resolve"
}
msg += fmt.Sprintf("- [%s] %s\n", username, helpers.AtUser(user.Key))
msg += fmt.Sprintf("- %s\n", helpers.AtUser(user.Key))
}

if len(msg) > 2000 {
err = helpers.SendDirectMessageWithFile(s, i.Message.Author.ID, msg, msg, span.Context())
} else {
err = helpers.SendDirectMessageWithFile(s, i.Message.Author.ID, fmt.Sprintf("Signins for `%s`; %d users signed in\n", signinType, len(userPairs)), msg, span.Context())
trimmedMsg := msg[:2000]
trimmedMsg = trimmedMsg[:strings.LastIndex(trimmedMsg, "\n")]
err = helpers.SendDirectMessageWithFile(s, i.Message.Author.ID, trimmedMsg, msg, span.Context())
}
if err != nil {
logging.Error(
Expand Down
1 change: 1 addition & 0 deletions data/signin.go
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,7 @@ func (*signin_s) Query(delta time.Duration, signinType signin.Type, ctx ddtrace.
}

pairList.Sort()
pairList.Reverse()

return pairList, nil
}
12 changes: 0 additions & 12 deletions helpers/profile.go

This file was deleted.

6 changes: 6 additions & 0 deletions structs/pair.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,9 @@ func (p PairList[T]) Swap(i, j int) {
func (p PairList[T]) Sort() {
sort.Sort(p)
}

func (p PairList[T]) Reverse() {
for i, j := 0, len(p)-1; i < j; i, j = i+1, j-1 {
p[i], p[j] = p[j], p[i]
}
}
Loading