diff --git a/commands/handlers.go b/commands/handlers.go index ceb205e..1fea8a8 100644 --- a/commands/handlers.go +++ b/commands/handlers.go @@ -52,6 +52,18 @@ func (c *Commands) RegisterHandlers() { c.RegisterCommand("intocm", "Convert Inches to Centimeters", false, c.handleInchToCentimeter) c.RegisterCommand("google4u", "Displays a letmegooglethat link", false, c.handleGoogle4U) + //Product Helpers + c.RegisterCommand("askdocs", "Ask docs.hak5.org a question", false, c.handleAskDocs) + c.RegisterCommand("docs", "Link Docs", false, c.handleDocs) + c.RegisterCommand("github", "Link Github", false, c.handleGithub) + c.RegisterCommand("payloads", "Link Github + PayloadHub", false, c.handlePayloads) + c.RegisterCommand("payloadhub", "Link PayloadHub", false, c.handlePayloadHub) + c.RegisterCommand("support", "Link Support", false, c.handleSupport) + c.RegisterCommand("shop", "Link Shop", false, c.handleShop) + c.RegisterCommand("buy", "Link Shop", false, c.handleShop) + c.RegisterCommand("invite", "Link direct channel invite", false, c.handleInvite) + // TODO payloadstudio view + // Admin Commands c.RegisterCommand("ping", "Ping Scuzzy", true, c.handlePing) c.RegisterCommand("rules", "Display the Server Rules", true, c.handleRules) @@ -68,6 +80,8 @@ func (c *Commands) RegisterHandlers() { c.RegisterCommand("saveconfig", "Save Configuration to Disk", true, c.handleSaveConfig) c.RegisterCommand("reloadconfig", "Reload Configuration", true, c.handleReloadConfig) c.RegisterCommand("addrole", "Add a joinable role", true, c.handleAddCustomRole) + c.RegisterCommand("moveto", "Move a users message to another channel (deletes originals)", true, c.handleMoveto) + c.RegisterCommand("bringto", "Copy a users message to another channel (keeps originals) ", true, c.handleBringto) } func (c *Commands) ProcessCommand(s *discordgo.Session, m *discordgo.MessageCreate) error { diff --git a/commands/moderation.go b/commands/moderation.go index 56e899d..5835a26 100644 --- a/commands/moderation.go +++ b/commands/moderation.go @@ -304,3 +304,93 @@ func (c *Commands) handleUnIgnoreUser(s *discordgo.Session, m *discordgo.Message return nil } + +func (c *Commands) handleMoveto(s *discordgo.Session, m *discordgo.MessageCreate) error { + args := strings.Split(m.Content, " ") + if len(args) < 2 { + return errors.New("missing arg") + } + input := m.Content[strings.Index(m.Content, " "):len(m.Content)] + + repliedTo, err := s.ChannelMessage(m.ChannelID, m.MessageReference.MessageID) + if err != nil { + return errors.New("error getting target message") + } + + moveToId := "" + channels, _ := s.GuildChannels(c.Config.GuildID) + for _, c := range channels { + if c.Type != discordgo.ChannelTypeGuildText { + continue + } + if strings.Contains(input, c.ID) { + moveToId = c.ID + break + } + } + + if moveToId == "" { + return errors.New("failed to link channels") + } + + _, err = s.ChannelMessageSend(m.ChannelID, "Moderator <@"+m.Author.ID+"> moved <@"+repliedTo.Author.ID+">'s message to <#"+moveToId+"> to continue the conversation there") + if err != nil { + return errors.New("error announcing move") + } + + _, err = s.ChannelMessageSend(moveToId, "Moderator <@"+m.Author.ID+"> moved this message from <#"+m.ChannelID+">\n\nOriginal message:\n\n <@"+repliedTo.Author.ID+">: "+repliedTo.Content) + if err != nil { + return errors.New("error moving message") + } + + err = s.ChannelMessageDelete(m.ChannelID, m.ID) + if err != nil { + return errors.New("error (re)moving command message") + } + + err = s.ChannelMessageDelete(m.ChannelID, m.MessageReference.MessageID) + if err != nil { + return errors.New("error (re)moving message") + } + return nil +} + +func (c *Commands) handleBringto(s *discordgo.Session, m *discordgo.MessageCreate) error { + args := strings.Split(m.Content, " ") + if len(args) < 2 { + return errors.New("missing arg") + } + input := m.Content[strings.Index(m.Content, " "):len(m.Content)] + + repliedTo, err := s.ChannelMessage(m.ChannelID, m.MessageReference.MessageID) + if err != nil { + return errors.New("error getting target message") + } + + moveToId := "" + channels, _ := s.GuildChannels(c.Config.GuildID) + for _, c := range channels { + if c.Type != discordgo.ChannelTypeGuildText { + continue + } + if strings.Contains(input, c.ID) { + moveToId = c.ID + break + } + } + + if moveToId == "" { + return errors.New("failed to link channels") + } + + _, err = s.ChannelMessageSend(m.ChannelID, "<@"+m.Author.ID+"> copied <@"+repliedTo.Author.ID+">'s message to <#"+moveToId+"> to continue the conversation there.") + if err != nil { + return errors.New("error announcing move") + } + + _, err = s.ChannelMessageSend(moveToId, "<@"+m.Author.ID+"> copied this message from <#"+m.ChannelID+">\n\nOriginal message:\n\n <@"+repliedTo.Author.ID+">: "+repliedTo.Content) + if err != nil { + return errors.New("error moving message") + } + return nil +} diff --git a/commands/products.go b/commands/products.go new file mode 100644 index 0000000..b0704ba --- /dev/null +++ b/commands/products.go @@ -0,0 +1,194 @@ +package commands + +import ( + "bytes" + "encoding/json" + "errors" + "github.com/bwmarrin/discordgo" + "github.com/foxtrot/scuzzy/models" + "log" + "net/http" + "strings" +) + +func (c *Commands) getProductFromChannelID(cid string) models.Product { + switch cid { + case models.Ducky.ChannelID: + return models.Ducky + case models.PayloadStudio.ChannelID: + return models.PayloadStudio + case models.Bunny.ChannelID: + return models.Bunny + case models.Croc.ChannelID: + return models.Croc + case models.Shark.ChannelID: + return models.Shark + case models.CloudC2.ChannelID: + return models.CloudC2 + case models.Crab.ChannelID: + return models.Crab + case models.Pineapple.ChannelID: + return models.Pineapple + case models.Coconut.ChannelID: + return models.Coconut + case models.Squirrel.ChannelID: + return models.Squirrel + case models.Turtle.ChannelID: + return models.Turtle + case models.OMG.ChannelID: + return models.OMG + default: + return models.Default + } +} + +func (c *Commands) handleAskDocs(s *discordgo.Session, m *discordgo.MessageCreate) error { + args := strings.Split(m.Content, " ") + + if len(args) < 2 { + return errors.New("missing question") + } + + input := m.Content[strings.Index(m.Content, " "):len(m.Content)] + + model := c.getProductFromChannelID(m.ChannelID) + + // Default guard + if model.SpaceID == models.Default.SpaceID { + _, err := s.ChannelMessageSend(m.ChannelID, "AI Search not enabled for this product, but you can still look for yourself here: "+model.Docslink) + if err != nil { + return err + } + return nil + } + + pre := "<:thonk:666272807524761620> Asking the" + post := "docs..." + askEndpoint := models.GITBOOKAPI + model.SpaceID + models.SEARCHENDPOINT + searchingIn := pre + " " + model.Emoji + " " + model.ProductName + " " + post + _, err := s.ChannelMessageSend(m.ChannelID, searchingIn) + if err != nil { + return err + } + + j, err := json.Marshal(&models.AISearchRequest{Query: input}) + if err != nil { + return errors.New("error marshalling input") + } + + r, err := http.NewRequest("POST", askEndpoint, bytes.NewBuffer(j)) + if err != nil { + return errors.New("error creating request") + } + + r.Header.Add("Content-Type", "application/json") + client := &http.Client{} + res, err := client.Do(r) + if err != nil { + return errors.New("error creating request client") + } + + defer res.Body.Close() + + resp := &models.AISearchResult{} + derr := json.NewDecoder(res.Body).Decode(resp) + if derr != nil { + return errors.New("error getting response from docs") + } + + if res.StatusCode != http.StatusOK { + return errors.New("error getting response from docs: " + res.Status) + } + + prepend := "<:9999iq:1050238565671514172> AI Generated Response:\n\n" + _, err = s.ChannelMessageSend(m.ChannelID, prepend+resp.Answer.Text+"\n\n"+model.Docslink) + if err != nil { + log.Print("[!] Error writing response: " + err.Error()) + return err + } + + return nil +} + +func (c *Commands) handleDocs(s *discordgo.Session, m *discordgo.MessageCreate) error { + model := c.getProductFromChannelID(m.ChannelID) + _, err := s.ChannelMessageSend(m.ChannelID, model.Emoji+" "+model.ProductName+" Docs: "+model.Docslink) + if err != nil { + log.Print("[!] Error writing response: " + err.Error()) + return err + } + return nil +} + +func (c *Commands) handleGithub(s *discordgo.Session, m *discordgo.MessageCreate) error { + model := c.getProductFromChannelID(m.ChannelID) + _, err := s.ChannelMessageSend(m.ChannelID, model.Emoji+" "+model.ProductName+" Github: "+model.Githublink) + if err != nil { + log.Print("[!] Error writing response: " + err.Error()) + return err + } + return nil +} + +func (c *Commands) handlePayloads(s *discordgo.Session, m *discordgo.MessageCreate) error { + model := c.getProductFromChannelID(m.ChannelID) + _, err := s.ChannelMessageSend(m.ChannelID, model.Emoji+" "+model.ProductName+" Github: "+model.Githublink) + if err != nil { + log.Print("[!] Error writing response: " + err.Error()) + return err + } + _, err = s.ChannelMessageSend(m.ChannelID, model.Emoji+" "+model.ProductName+" PayloadHub: "+model.Payloadslink) + if err != nil { + log.Print("[!] Error writing response: " + err.Error()) + return err + } + return nil +} + +func (c *Commands) handlePayloadHub(s *discordgo.Session, m *discordgo.MessageCreate) error { + model := c.getProductFromChannelID(m.ChannelID) + _, err := s.ChannelMessageSend(m.ChannelID, model.Emoji+" "+model.ProductName+" PayloadHub: "+model.Payloadslink) + if err != nil { + log.Print("[!] Error writing response: " + err.Error()) + return err + } + return nil +} + +func (c *Commands) handleSupport(s *discordgo.Session, m *discordgo.MessageCreate) error { + model := c.getProductFromChannelID(m.ChannelID) + _, err := s.ChannelMessageSend(m.ChannelID, model.Emoji+" "+model.ProductName+" Support: "+model.SupportLink) + if err != nil { + log.Print("[!] Error writing response: " + err.Error()) + return err + } + return nil +} + +func (c *Commands) handleInvite(s *discordgo.Session, m *discordgo.MessageCreate) error { + model := c.getProductFromChannelID(m.ChannelID) + if model.InviteLink == models.Default.InviteLink { + _, err := s.ChannelMessageSend(m.ChannelID, model.Emoji+"Invite Link: "+model.InviteLink) + if err != nil { + log.Print("[!] Error writing response: " + err.Error()) + return err + } + } else { + _, err := s.ChannelMessageSend(m.ChannelID, model.Emoji+" "+model.ProductName+" Channel Invite Link: "+model.InviteLink) + if err != nil { + log.Print("[!] Error writing response: " + err.Error()) + return err + } + } + return nil +} + +func (c *Commands) handleShop(s *discordgo.Session, m *discordgo.MessageCreate) error { + model := c.getProductFromChannelID(m.ChannelID) + _, err := s.ChannelMessageSend(m.ChannelID, "Shop "+model.Emoji+" "+model.ProductName+" "+model.Shoplink) + if err != nil { + log.Print("[!] Error writing response: " + err.Error()) + return err + } + return nil +} diff --git a/models/gitbook.go b/models/gitbook.go new file mode 100644 index 0000000..cf99442 --- /dev/null +++ b/models/gitbook.go @@ -0,0 +1,19 @@ +package models + +type AISearchRequest struct { + Query string `json:"query"` + // PreviousQueries []string `json:"previousQueries"` +} + +type AISearchResult struct { + Answer struct { + Text string `json:"text"` + FollowupQuestions []string `json:"followupQuestions"` + Pages []struct { + Page string `json:"page"` + Revision string `json:"revision"` + Space string `json:"space"` + Sections []string `json:"sections"` + } `json:"pages"` + } `json:"answer"` +} diff --git a/models/products.go b/models/products.go new file mode 100644 index 0000000..399d6da --- /dev/null +++ b/models/products.go @@ -0,0 +1,190 @@ +package models + +type Product struct { + ProductName string `json:"productName"` + Urllabel string `json:"urllabel"` + Emoji string `json:"logo"` + ChannelID string `json:"channelid"` + SpaceID string `json:"spaceid"` + Docslink string `json:"docslink"` + Shoplink string `json:"shoplink"` + Payloadslink string `json:"payloadslink"` + Githublink string `json:"githublink"` + InviteLink string `json:"invitelink"` + SupportLink string `json:"supportlink"` +} + +var GITBOOKAPI = "https://api.gitbook.com/v1/spaces/" +var SEARCHENDPOINT = "/search/ask" + +var Default = Product{ + ProductName: "", + Urllabel: "", + Emoji: "<:hak5:1063661436187975701>", + ChannelID: "824326326076702770", + SpaceID: "", + Docslink: "https://docs.hak5.org", + Shoplink: "https://shop.hak5.org", + Payloadslink: "https://payloadhub.com", + Githublink: "https://github.com/hak5", + InviteLink: "https://discord.gg/hak5", + SupportLink: "https://hak5.org/support", +} + +var Ducky = Product{ + ProductName: "USB Rubber Ducky", + Urllabel: "usb-rubber-ducky", + Emoji: "<:Rubber_Ducky:1063661661795385384>", + ChannelID: "522275837651714048", + SpaceID: "-MiIkRK_o3RBhZzUkrzr", + Docslink: "https://docs.hak5.org/hak5-usb-rubber-ducky/", + Shoplink: "https://shop.hak5.org/products/usb-rubber-ducky", + Payloadslink: "https://hak5.org/blogs/payloads/tagged/usb-rubber-ducky", + Githublink: "https://github.com/hak5/usbrubberducky-payloads", + InviteLink: "https://discord.gg/HMH5yyKuuA", + SupportLink: "https://hak5.org/support/ducky", +} + +var PayloadStudio = Product{ + ProductName: "PayloadStudio", + Urllabel: Default.Urllabel, + Emoji: "<:payload_studio:1053210968064262234>", + ChannelID: "1006233482957164634", + SpaceID: "RgTCQkzfO7AUWTT3gFAq", + Docslink: "https://docs.hak5.org/payload-studio/", + Shoplink: "https://shop.hak5.org/products/payload-studio-pro", + Payloadslink: Default.Payloadslink, + Githublink: Default.Githublink, + InviteLink: "https://discord.gg/AGBSbUdfGx", + SupportLink: "https://hak5.org/support/payloadstudio", +} +var CloudC2 = Product{ + ProductName: "Cloud C2", + Urllabel: Default.Urllabel, + Emoji: "<:Cloud_C2:1063661578181943336>", + ChannelID: "522276096746717184", + SpaceID: "<:Cloud_C2:1063661578181943336>", + Docslink: "https://docs.hak5.org/cloud-c2/", + Shoplink: "https://shop.hak5.org/products/cloud-c2", + Payloadslink: Default.Payloadslink, + Githublink: Default.Githublink, + InviteLink: "https://discord.gg/gFBhAEXycP", + SupportLink: Default.SupportLink, +} +var Crab = Product{ + ProductName: "Screen Crab", + Urllabel: Default.Urllabel, + Emoji: "<:Screen_Crab:1063661831756988427>", + ChannelID: "608057573517557809", + SpaceID: "-MiWySN4BHDJlUatEfm3", + Docslink: "https://docs.hak5.org/screen-crab/", + Shoplink: "https://shop.hak5.org/products/screen-crab", + Payloadslink: Default.Payloadslink, + Githublink: Default.Githublink, + InviteLink: "https://discord.gg/mxdb7x2DqD", + SupportLink: "https://hak5.org/support/crab", +} +var Coconut = Product{ + ProductName: "WiFi Coconut", + Urllabel: Default.Urllabel, + Emoji: "<:WiFi_Coconut:1063661830309953606>", + ChannelID: "1007363521098551349", + SpaceID: "DkilLranx3TNqKgzbBZ9", + Docslink: "https://docs.hak5.org/wifi-coconut/", + Shoplink: "https://shop.hak5.org/products/wifi-coconut", + Payloadslink: Default.Payloadslink, + Githublink: "https://github.org/hak5/wifi-coconut", + InviteLink: Default.InviteLink, + SupportLink: "https://hak5.org/support/coconut", +} +var Pineapple = Product{ + ProductName: "WiFi Pineapple", + Urllabel: Default.Urllabel, + Emoji: "<:WiFi_Pineapple:1063661628207411251>", + ChannelID: "522275782731497473", + SpaceID: "-Mhuhsyl_byoEWXOc5EU", + Docslink: "https://docs.hak5.org/wifi-pineapple/", + Shoplink: "https://shop.hak5.org/products/wifi-pineapple", + Payloadslink: Default.Payloadslink, + Githublink: "https://github.com/hak5/pineapple-modules", + InviteLink: "https://discord.gg/WEbS5DY6Ar", + SupportLink: "https://hak5.org/support/pineapple", +} +var Croc = Product{ + ProductName: "Key Croc", + Urllabel: "key-croc", + Emoji: "<:Key_Croc:1063661834093199431>", + ChannelID: "709235715120168970", + SpaceID: "-MhLOzjhonMdC6SLKqRt", + Docslink: "https://docs.hak5.org/key-croc/", + Shoplink: "https://shop.hak5.org/products/key-croc", + Payloadslink: "https://hak5.org/blogs/payloads/tagged/key-croc", + Githublink: "https://github.com/hak5/keycroc-payloads", + InviteLink: "https://discord.gg/rgq5ST86gW", + SupportLink: "https://hak5.org/support/croc", +} +var Bunny = Product{ + ProductName: "Bash Bunny", + Urllabel: "bash-bunny", + Emoji: "<:Bash_Bunny:1063661828753858680>", + ChannelID: "1009919913877590146", + SpaceID: "nxJgJ9UdPfrcuL1U8DpL", + Docslink: "https://docs.hak5.org/bash-bunny/", + Shoplink: "https://shop.hak5.org/products/bash-bunny", + Payloadslink: "https://hak5.org/blogs/payloads/tagged/bash-bunny", + Githublink: "https://github.com/hak5/bashbunny-payloads", + InviteLink: "https://discord.gg/jF4VrbEwVW", + SupportLink: "https://hak5.org/support/bunny", +} +var Squirrel = Product{ + ProductName: "Packet Squirrel", + Urllabel: "packet-squirrel", + Emoji: "<:packet_squirrel:1063661837398315079>", + ChannelID: "522275913031745548", + SpaceID: "-MiX86qQFvjhg-a6RwWr", + Docslink: "https://docs.hak5.org/packet-squirrel", + Shoplink: "https://shop.hak5.org/products/packet-squirrel", + Payloadslink: "https://hak5.org/blogs/payloads/tagged/packet-squirrel", + Githublink: "https://github.com/hak5/packetsquirrel-payloads", + InviteLink: "https://discord.gg/ggW5DR7tpz", + SupportLink: "https://hak5.org/support/squirrel", +} +var Turtle = Product{ + ProductName: "LAN Turtle", + Urllabel: "lan-turtle", + Emoji: "<:lan_turtle:1063661838937620480>", + ChannelID: "522275913031745548", + SpaceID: "N8g6UIGOyv4mW7rOOuC8", + Docslink: "https://docs.hak5.org/lan-turtle", + Shoplink: "https://shop.hak5.org/products/lan-turtle", + Payloadslink: "https://hak5.org/blogs/payloads/tagged/lan-turtle", + Githublink: "https://github.com/hak5/lanturtle-modules", + InviteLink: "https://discord.gg/ggW5DR7tpz", + SupportLink: "https://hak5.org/support/turtle", +} +var Shark = Product{ + ProductName: "Shark Jack", + Urllabel: "shark-jack", + Emoji: "<:Shark_Jack:1063661835888381952>", + ChannelID: "610344558655438858", + SpaceID: "-MhxW6geyenAGJvaKW11", + Docslink: "https://docs.hak5.org/shark-jack", + Shoplink: "https://shop.hak5.org/products/shark-jack", + Payloadslink: "https://hak5.org/blogs/payloads/tagged/shark-jack", + Githublink: "https://github.com/hak5/sharkjack-payloads", + InviteLink: "https://discord.gg/CsnaGN2CEd", + SupportLink: "https://hak5.org/support/shark", +} +var OMG = Product{ + ProductName: "O.MG Devices", + Urllabel: "omg", + Emoji: "<:omg:1063696145022468116>", + ChannelID: "953129985131040838", + SpaceID: Default.SpaceID, + Docslink: "https://docs.hak5.org/hak5-docs/#omg", + Shoplink: "https://shop.hak5.org/collections/mischief-gadgets", + Payloadslink: "https://hak5.org/blogs/payloads/tagged/omg", + Githublink: "https://github.com/hak5/omg-payloads", + InviteLink: "https://discord.gg/Sw2pzaHT6N", + SupportLink: "https://hak5.org/support/omg", +}