Compare commits
	
		
			20 Commits
		
	
	
		
			fba7d2c8d4
			...
			ImplResett
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						
						
							
						
						fa254c60f7
	
				 | 
					
					
						|||
| 
						
						
							
						
						00db797d65
	
				 | 
					
					
						|||
| 
						
						
							
						
						8b001e499a
	
				 | 
					
					
						|||
| 
						
						
							
						
						62faa6c974
	
				 | 
					
					
						|||
| 
						
						
							
						
						2a42301c25
	
				 | 
					
					
						|||
| 7eebc01816 | |||
| 
						
						
							
						
						78e8a857e9
	
				 | 
					
					
						|||
| 
						
						
							
						
						849f592fc0
	
				 | 
					
					
						|||
| 
						
						
							
						
						d7c884bf1d
	
				 | 
					
					
						|||
| 
						
						
							
						
						71bec93b58
	
				 | 
					
					
						|||
| 
						
						
							
						
						3abc4f3265
	
				 | 
					
					
						|||
| 
						
						
							
						
						e57d3ff4fe
	
				 | 
					
					
						|||
| 
						
						
							
						
						2598aa854a
	
				 | 
					
					
						|||
| 
						
						
							
						
						6de41e0180
	
				 | 
					
					
						|||
| 
						
						
							
						
						f24c836cbc
	
				 | 
					
					
						|||
| 
						
						
							
						
						9afda27ab4
	
				 | 
					
					
						|||
| 
						
						
							
						
						e8a216b9d7
	
				 | 
					
					
						|||
| 
						
						
							
						
						7d8a2db77b
	
				 | 
					
					
						|||
| 
						
						
							
						
						b63a368c35
	
				 | 
					
					
						|||
| 
						
						
							
						
						6cf715e620
	
				 | 
					
					
						
@@ -0,0 +1,15 @@
 | 
			
		||||
[discord]
 | 
			
		||||
token = ""
 | 
			
		||||
appid = ""
 | 
			
		||||
guildid = ""
 | 
			
		||||
category_id = ""
 | 
			
		||||
admin_roles = [""]
 | 
			
		||||
 | 
			
		||||
[database]
 | 
			
		||||
host = ""
 | 
			
		||||
port = 5432
 | 
			
		||||
name = ""
 | 
			
		||||
username = ""
 | 
			
		||||
password = ""
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										12
									
								
								go.mod
									
									
									
									
									
								
							
							
						
						
									
										12
									
								
								go.mod
									
									
									
									
									
								
							@@ -1,3 +1,15 @@
 | 
			
		||||
module HwidBot
 | 
			
		||||
 | 
			
		||||
go 1.22.4
 | 
			
		||||
 | 
			
		||||
require (
 | 
			
		||||
	github.com/BurntSushi/toml v1.4.0
 | 
			
		||||
	github.com/bwmarrin/discordgo v0.28.1
 | 
			
		||||
	github.com/lib/pq v1.10.9
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
require (
 | 
			
		||||
	github.com/gorilla/websocket v1.4.2 // indirect
 | 
			
		||||
	golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b // indirect
 | 
			
		||||
	golang.org/x/sys v0.0.0-20201119102817-f84b799fce68 // indirect
 | 
			
		||||
)
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										603
									
								
								main.go
									
									
									
									
									
								
							
							
						
						
									
										603
									
								
								main.go
									
									
									
									
									
								
							@@ -1,9 +1,608 @@
 | 
			
		||||
package main
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"bytes"
 | 
			
		||||
	"database/sql"
 | 
			
		||||
	"encoding/json"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"log"
 | 
			
		||||
	"mime/multipart"
 | 
			
		||||
	"net/http"
 | 
			
		||||
	"os"
 | 
			
		||||
	"os/signal"
 | 
			
		||||
	"strconv"
 | 
			
		||||
	"strings"
 | 
			
		||||
	"syscall"
 | 
			
		||||
	"time"
 | 
			
		||||
 | 
			
		||||
	"github.com/BurntSushi/toml"
 | 
			
		||||
	"github.com/bwmarrin/discordgo"
 | 
			
		||||
	"github.com/lib/pq"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func main(){
 | 
			
		||||
	fmt.Println("Initial")
 | 
			
		||||
type UserResponse struct {
 | 
			
		||||
	ID           string   `json:"id"`
 | 
			
		||||
	Username     string   `json:"username"`
 | 
			
		||||
	Subscription bool     `json:"subscription"`
 | 
			
		||||
	Group        string   `json:"group"`
 | 
			
		||||
	Expiration   string   `json:"expiration"`
 | 
			
		||||
	Versions     []string `json:"versions"`
 | 
			
		||||
	PFP          string   `json:"pfp"`
 | 
			
		||||
	Message      int      `json:"message"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var (
 | 
			
		||||
	config Config
 | 
			
		||||
	client *discordgo.Session
 | 
			
		||||
	db     *sql.DB
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type Config struct {
 | 
			
		||||
	Discord  Discord  `toml:"discord"`
 | 
			
		||||
	Database Database `toml:"database"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type Discord struct {
 | 
			
		||||
	Token      string   `toml:"token"`
 | 
			
		||||
	AppID      string   `toml:"appid"`
 | 
			
		||||
	GuildID    string   `toml:"guildid"`
 | 
			
		||||
	CategoryID string   `toml:"category_id"`
 | 
			
		||||
	AdminRoles []string `toml:"admin_roles"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type Database struct {
 | 
			
		||||
	Host     string `toml:"host"`
 | 
			
		||||
	Port     int    `toml:"port"`
 | 
			
		||||
	Name     string `toml:"name"`
 | 
			
		||||
	Username string `toml:"username"`
 | 
			
		||||
	Password string `toml:"password"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func loadConfig(filename string) (Config, error) {
 | 
			
		||||
	var config Config
 | 
			
		||||
	_, err := toml.DecodeFile(filename, &config)
 | 
			
		||||
	return config, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func connectDb(config Config) (*sql.DB, error) {
 | 
			
		||||
	connectionString := fmt.Sprintf(
 | 
			
		||||
		"host=%s port=%d user=%s password=%s dbname=%s sslmode=disable",
 | 
			
		||||
		config.Database.Host,
 | 
			
		||||
		config.Database.Port,
 | 
			
		||||
		config.Database.Username,
 | 
			
		||||
		config.Database.Password,
 | 
			
		||||
		config.Database.Name,
 | 
			
		||||
	)
 | 
			
		||||
 | 
			
		||||
	db, err := sql.Open("postgres", connectionString)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, fmt.Errorf("error connecting to the database: %v", err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	err = db.Ping()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		db.Close()
 | 
			
		||||
		return nil, fmt.Errorf("error pinging the database: %v", err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	log.Println("Successfully connected to the database.")
 | 
			
		||||
	return db, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func init() {
 | 
			
		||||
	var err error
 | 
			
		||||
	config, err = loadConfig("config.toml")
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		log.Println("Error occurred whilst trying to load config:", err)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	client, err = discordgo.New("Bot " + config.Discord.Token)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		log.Println("Error initializing bot:", err)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	db, err = connectDb(config)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		log.Println("Error initializing db connection:", err)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func reset(userNickname, softwareType string) {
 | 
			
		||||
	log.Printf("Resetting %s for user %s\n", softwareType, userNickname)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func getUsernameFromMember(member *discordgo.Member) string {
 | 
			
		||||
	if member == nil {
 | 
			
		||||
		return "UnknownUser"
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var userName string
 | 
			
		||||
	if member.Nick != "" {
 | 
			
		||||
		userName = member.Nick
 | 
			
		||||
	} else if member.User != nil && member.User.Username != "" {
 | 
			
		||||
		userName = member.User.Username
 | 
			
		||||
	} else {
 | 
			
		||||
		userName = "UnknownUser"
 | 
			
		||||
	}
 | 
			
		||||
	return userName
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var (
 | 
			
		||||
	commands = []discordgo.ApplicationCommand{
 | 
			
		||||
		{
 | 
			
		||||
			Name:        "setup",
 | 
			
		||||
			Description: "Setup a channel for ticket creation",
 | 
			
		||||
			Options: []*discordgo.ApplicationCommandOption{
 | 
			
		||||
				{
 | 
			
		||||
					Type:        discordgo.ApplicationCommandOptionChannel,
 | 
			
		||||
					Name:        "channel",
 | 
			
		||||
					Description: "Channel for ticket creation",
 | 
			
		||||
					Required:    true,
 | 
			
		||||
				},
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
	commandsHandlers = map[string]func(client *discordgo.Session, i *discordgo.InteractionCreate){
 | 
			
		||||
		"setup": func(client *discordgo.Session, i *discordgo.InteractionCreate) {
 | 
			
		||||
			channelOption := i.ApplicationCommandData().Options[0].ChannelValue(client)
 | 
			
		||||
			_, err := client.ChannelMessageSendComplex(channelOption.ID, &discordgo.MessageSend{
 | 
			
		||||
				Content: "Click the button below to request a HWID reset:",
 | 
			
		||||
				Components: []discordgo.MessageComponent{
 | 
			
		||||
					discordgo.ActionsRow{
 | 
			
		||||
						Components: []discordgo.MessageComponent{
 | 
			
		||||
							discordgo.Button{
 | 
			
		||||
								Label:    "Request Reset",
 | 
			
		||||
								Style:    discordgo.PrimaryButton,
 | 
			
		||||
								CustomID: "create_ticket",
 | 
			
		||||
							},
 | 
			
		||||
						},
 | 
			
		||||
					},
 | 
			
		||||
				},
 | 
			
		||||
			})
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				log.Println("Error sending message to the specified channel:", err)
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			err = client.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{
 | 
			
		||||
				Type: discordgo.InteractionResponseChannelMessageWithSource,
 | 
			
		||||
				Data: &discordgo.InteractionResponseData{
 | 
			
		||||
					Content: fmt.Sprintf("Setup completed! Request creation button has been added to %s", channelOption.Mention()),
 | 
			
		||||
				},
 | 
			
		||||
			})
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				log.Println("Error sending interaction response:", err)
 | 
			
		||||
			}
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
	componentsHandlers = map[string]func(client *discordgo.Session, i *discordgo.InteractionCreate){
 | 
			
		||||
		"create_ticket": func(client *discordgo.Session, i *discordgo.InteractionCreate) {
 | 
			
		||||
			err := client.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{
 | 
			
		||||
				Type: discordgo.InteractionResponseChannelMessageWithSource,
 | 
			
		||||
				Data: &discordgo.InteractionResponseData{
 | 
			
		||||
					Content: "For what would you like a HWID reset:",
 | 
			
		||||
					Components: []discordgo.MessageComponent{
 | 
			
		||||
						discordgo.ActionsRow{
 | 
			
		||||
							Components: []discordgo.MessageComponent{
 | 
			
		||||
								discordgo.SelectMenu{
 | 
			
		||||
									CustomID:    "select_software_type",
 | 
			
		||||
									Placeholder: "Choose which software",
 | 
			
		||||
									Options: []discordgo.SelectMenuOption{
 | 
			
		||||
										{
 | 
			
		||||
											Label:       "Vanity",
 | 
			
		||||
											Value:       "vanity",
 | 
			
		||||
											Description: "Request a vanity reset",
 | 
			
		||||
										},
 | 
			
		||||
										{
 | 
			
		||||
											Label:       "Mesa",
 | 
			
		||||
											Value:       "mesa",
 | 
			
		||||
											Description: "Request a mesa reset",
 | 
			
		||||
										},
 | 
			
		||||
									},
 | 
			
		||||
								},
 | 
			
		||||
							},
 | 
			
		||||
						},
 | 
			
		||||
					},
 | 
			
		||||
					Flags: discordgo.MessageFlagsEphemeral,
 | 
			
		||||
				},
 | 
			
		||||
			})
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				log.Println("Error sending interaction response:", err)
 | 
			
		||||
			}
 | 
			
		||||
		},
 | 
			
		||||
		"select_software_type": func(client *discordgo.Session, i *discordgo.InteractionCreate) {
 | 
			
		||||
			selectedOption := i.MessageComponentData().Values[0]
 | 
			
		||||
			var softwareType string
 | 
			
		||||
			if selectedOption == "vanity" {
 | 
			
		||||
				softwareType = "Vanity"
 | 
			
		||||
			} else if selectedOption == "mesa" {
 | 
			
		||||
				softwareType = "Mesa"
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			categoryID := config.Discord.CategoryID
 | 
			
		||||
			guildID := i.GuildID
 | 
			
		||||
			userID := i.Member.User.ID
 | 
			
		||||
			userName := getUsernameFromMember(i.Member)
 | 
			
		||||
 | 
			
		||||
			if !canCreateTicket(userName, selectedOption) {
 | 
			
		||||
				err := client.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{
 | 
			
		||||
					Type: discordgo.InteractionResponseChannelMessageWithSource,
 | 
			
		||||
					Data: &discordgo.InteractionResponseData{
 | 
			
		||||
						Content: fmt.Sprintf("You already have an active %s ticket. Please wait for the administrators to process it.", softwareType),
 | 
			
		||||
						Flags:   discordgo.MessageFlagsEphemeral,
 | 
			
		||||
					},
 | 
			
		||||
				})
 | 
			
		||||
				if err != nil {
 | 
			
		||||
					log.Println("Error sending interaction response:", err)
 | 
			
		||||
				}
 | 
			
		||||
				return
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			_, baseUrl := getTableNameAndBaseURL(selectedOption)
 | 
			
		||||
			userUID, _ := fetchUserID(userName, baseUrl)
 | 
			
		||||
			if userUID == 0 {
 | 
			
		||||
				err := client.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{
 | 
			
		||||
					Type: discordgo.InteractionResponseChannelMessageWithSource,
 | 
			
		||||
					Data: &discordgo.InteractionResponseData{
 | 
			
		||||
						Content: fmt.Sprintf("Account not found for %s", softwareType),
 | 
			
		||||
						Flags:   discordgo.MessageFlagsEphemeral,
 | 
			
		||||
					},
 | 
			
		||||
				})
 | 
			
		||||
				if err != nil {
 | 
			
		||||
					log.Println("Error sending interaction response:", err)
 | 
			
		||||
				}
 | 
			
		||||
				return
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			channel, err := client.GuildChannelCreateComplex(guildID, discordgo.GuildChannelCreateData{
 | 
			
		||||
				Name:     fmt.Sprintf("reset-%s-%s", softwareType, userName),
 | 
			
		||||
				Type:     discordgo.ChannelTypeGuildText,
 | 
			
		||||
				ParentID: categoryID,
 | 
			
		||||
				PermissionOverwrites: []*discordgo.PermissionOverwrite{
 | 
			
		||||
					{
 | 
			
		||||
						ID:   guildID,
 | 
			
		||||
						Type: discordgo.PermissionOverwriteTypeRole,
 | 
			
		||||
						Deny: discordgo.PermissionViewChannel,
 | 
			
		||||
					},
 | 
			
		||||
				},
 | 
			
		||||
			})
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				log.Println("Error creating hwid request channel:", err)
 | 
			
		||||
				return
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			for _, roleID := range config.Discord.AdminRoles {
 | 
			
		||||
				if roleID != "" {
 | 
			
		||||
					err := client.ChannelPermissionSet(channel.ID, roleID, discordgo.PermissionOverwriteTypeRole, discordgo.PermissionViewChannel|discordgo.PermissionSendMessages, 0)
 | 
			
		||||
					if err != nil {
 | 
			
		||||
						log.Printf("Error setting permissions for role %s: %v", roleID, err)
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			err = client.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{
 | 
			
		||||
				Type: discordgo.InteractionResponseChannelMessageWithSource,
 | 
			
		||||
				Data: &discordgo.InteractionResponseData{
 | 
			
		||||
					Content: "Request submitted, you'll get a PM when it has been processed",
 | 
			
		||||
					Flags:   discordgo.MessageFlagsEphemeral,
 | 
			
		||||
				},
 | 
			
		||||
			})
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				log.Println("Error sending interaction response:", err)
 | 
			
		||||
				return
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			_, err = client.ChannelMessageSendComplex(channel.ID, &discordgo.MessageSend{
 | 
			
		||||
				Content: fmt.Sprintf("Reset request by %s for %s", userName, softwareType),
 | 
			
		||||
				Components: []discordgo.MessageComponent{
 | 
			
		||||
					discordgo.ActionsRow{
 | 
			
		||||
						Components: []discordgo.MessageComponent{
 | 
			
		||||
							discordgo.Button{
 | 
			
		||||
								Label:    "Accept",
 | 
			
		||||
								Style:    discordgo.PrimaryButton,
 | 
			
		||||
								CustomID: fmt.Sprintf("accept_%s_%s_%d", userID, softwareType, userUID),
 | 
			
		||||
							},
 | 
			
		||||
							discordgo.Button{
 | 
			
		||||
								Label:    "Decline",
 | 
			
		||||
								Style:    discordgo.DangerButton,
 | 
			
		||||
								CustomID: fmt.Sprintf("decline_%s_%s_%d", userID, softwareType, userUID),
 | 
			
		||||
							},
 | 
			
		||||
						},
 | 
			
		||||
					},
 | 
			
		||||
				},
 | 
			
		||||
			})
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				log.Println("Error sending message to the ticket channel:", err)
 | 
			
		||||
			}
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
		"accept": func(client *discordgo.Session, i *discordgo.InteractionCreate) {
 | 
			
		||||
			data := i.MessageComponentData().CustomID
 | 
			
		||||
			parts := strings.Split(data, "_")
 | 
			
		||||
			if len(parts) != 4 {
 | 
			
		||||
				log.Println("Invalid accept button custom ID")
 | 
			
		||||
				return
 | 
			
		||||
			}
 | 
			
		||||
			userID := parts[1]
 | 
			
		||||
			softwareType := parts[2]
 | 
			
		||||
			userUID, _ := strconv.Atoi(parts[3])
 | 
			
		||||
 | 
			
		||||
			member, err := client.GuildMember(i.GuildID, userID)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				log.Println("Error fetching member info:", err)
 | 
			
		||||
				return
 | 
			
		||||
			}
 | 
			
		||||
			userName := getUsernameFromMember(member)
 | 
			
		||||
 | 
			
		||||
			reset(userName, softwareType)
 | 
			
		||||
			tableName, _ := getTableNameAndBaseURL(strings.ToLower(softwareType))
 | 
			
		||||
 | 
			
		||||
			_, err = resetAndVerify(tableName, int(userUID))
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				log.Println("Error resetting hwid:", err)
 | 
			
		||||
			}
 | 
			
		||||
			log.Printf("Reset the HWID of user %s with UID %d for %s", userName, userUID, softwareType)
 | 
			
		||||
 | 
			
		||||
			err = client.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{
 | 
			
		||||
				Type: discordgo.InteractionResponseChannelMessageWithSource,
 | 
			
		||||
				Data: &discordgo.InteractionResponseData{
 | 
			
		||||
					Content: "Request accepted and processed.",
 | 
			
		||||
					Flags:   discordgo.MessageFlagsEphemeral,
 | 
			
		||||
				},
 | 
			
		||||
			})
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				log.Println("Error sending interaction response:", err)
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			_, err = client.ChannelDelete(i.ChannelID)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				log.Println("Error deleting channel:", err)
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			dmChannel, err := client.UserChannelCreate(userID)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				log.Println("Error creating DM channel:", err)
 | 
			
		||||
				return
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			_, err = client.ChannelMessageSend(dmChannel.ID, fmt.Sprintf("Your reset request for %s has been accepted and processed.", softwareType))
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				log.Println("Error sending DM:", err)
 | 
			
		||||
			}
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
		"decline": func(client *discordgo.Session, i *discordgo.InteractionCreate) {
 | 
			
		||||
			data := i.MessageComponentData().CustomID
 | 
			
		||||
			parts := strings.Split(data, "_")
 | 
			
		||||
			if len(parts) != 4 {
 | 
			
		||||
				log.Println("Invalid decline button custom ID")
 | 
			
		||||
				return
 | 
			
		||||
			}
 | 
			
		||||
			userID := parts[1]
 | 
			
		||||
 | 
			
		||||
			err := client.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{
 | 
			
		||||
				Type: discordgo.InteractionResponseChannelMessageWithSource,
 | 
			
		||||
				Data: &discordgo.InteractionResponseData{
 | 
			
		||||
					Content: "Request declined.",
 | 
			
		||||
					Flags:   discordgo.MessageFlagsEphemeral,
 | 
			
		||||
				},
 | 
			
		||||
			})
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				log.Println("Error sending interaction response:", err)
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			_, err = client.ChannelDelete(i.ChannelID)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				log.Println("Error deleting channel:", err)
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			dmChannel, err := client.UserChannelCreate(userID)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				log.Println("Error creating DM channel:", err)
 | 
			
		||||
				return
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			_, err = client.ChannelMessageSend(dmChannel.ID, "Your reset request has been declined.")
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				log.Println("Error sending DM:", err)
 | 
			
		||||
			}
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func canCreateTicket(userName, softwareType string) bool {
 | 
			
		||||
	guildChannels, err := client.GuildChannels(config.Discord.GuildID)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		log.Println("Error fetching guild channels:", err)
 | 
			
		||||
		return false
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for _, channel := range guildChannels {
 | 
			
		||||
		if channel.Type == discordgo.ChannelTypeGuildText && channel.ParentID == config.Discord.CategoryID {
 | 
			
		||||
			expectedName := fmt.Sprintf("reset-%s-%s", softwareType, userName)
 | 
			
		||||
			if channel.Name == expectedName {
 | 
			
		||||
				return false
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return true
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func getTableNameAndBaseURL(choice string) (string, string) {
 | 
			
		||||
	var tableName, baseURL string
 | 
			
		||||
 | 
			
		||||
	switch choice {
 | 
			
		||||
	case "vanity":
 | 
			
		||||
		tableName = "AuthUserData"
 | 
			
		||||
		baseURL = "http://vanitycheats.xyz/UserAuthentication.php"
 | 
			
		||||
	case "mesa":
 | 
			
		||||
		tableName = "AuthUserData-Mesachanger.com"
 | 
			
		||||
		baseURL = "http://mesachanger.com/UserAuthentication.php"
 | 
			
		||||
	default:
 | 
			
		||||
		fmt.Println("Invalid choice. Please choose 'vanity' or 'mesa'.")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return tableName, baseURL
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func fetchUserID(username string, baseURL string) (int, error) {
 | 
			
		||||
	requestBody := &bytes.Buffer{}
 | 
			
		||||
	multiPartWriter := multipart.NewWriter(requestBody)
 | 
			
		||||
	err := multiPartWriter.WriteField("username", username)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return 0, fmt.Errorf("error adding username field: %w", err)
 | 
			
		||||
	}
 | 
			
		||||
	multiPartWriter.Close()
 | 
			
		||||
	request, err := http.NewRequest("POST", baseURL, requestBody)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return 0, fmt.Errorf("error creating request: %w", err)
 | 
			
		||||
	}
 | 
			
		||||
	request.Header.Set("Content-Type", multiPartWriter.FormDataContentType())
 | 
			
		||||
	client := &http.Client{
 | 
			
		||||
		Timeout: 10 * time.Second,
 | 
			
		||||
	}
 | 
			
		||||
	resp, err := client.Do(request)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return 0, fmt.Errorf("error sending request: %w", err)
 | 
			
		||||
	}
 | 
			
		||||
	defer resp.Body.Close()
 | 
			
		||||
	var userResp UserResponse
 | 
			
		||||
	err = json.NewDecoder(resp.Body).Decode(&userResp)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return 0, fmt.Errorf("error decoding JSON: %w", err)
 | 
			
		||||
	}
 | 
			
		||||
	uid, err := strconv.Atoi(userResp.ID)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return 0, fmt.Errorf("error converting user ID: %w", err)
 | 
			
		||||
	}
 | 
			
		||||
	return uid, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func resetHWID(tableName string, uids []int) {
 | 
			
		||||
	query := fmt.Sprintf(`UPDATE public.%q
 | 
			
		||||
		SET "StorageIdentifier" = NULL, "BootIdentifier" = NULL
 | 
			
		||||
		WHERE "UID" = ANY($1)`, tableName)
 | 
			
		||||
 | 
			
		||||
	_, err := db.Exec(query, pq.Array(uids))
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		log.Printf("Error resetting HWID: %v", err)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func getIdentifiers(tableName string, uid int) {
 | 
			
		||||
	query := fmt.Sprintf(`SELECT "StorageIdentifier", "BootIdentifier"
 | 
			
		||||
		FROM public.%q
 | 
			
		||||
		WHERE "UID" = $1`, tableName)
 | 
			
		||||
 | 
			
		||||
	var storageIdentifier, bootIdentifier sql.NullString
 | 
			
		||||
	err := db.QueryRow(query, uid).Scan(&storageIdentifier, &bootIdentifier)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		if err == sql.ErrNoRows {
 | 
			
		||||
			fmt.Println("HWID not set")
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
		fmt.Println("Error querying the database:", err)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if !storageIdentifier.Valid {
 | 
			
		||||
		storageIdentifier = sql.NullString{String: "NULL", Valid: false}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if !bootIdentifier.Valid {
 | 
			
		||||
		bootIdentifier = sql.NullString{String: "NULL", Valid: false}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	fmt.Printf("UID: %d, S: %s, B: %s\n", uid, storageIdentifier.String, bootIdentifier.String)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func resetAndVerify(tableName string, uid int) (bool, error) {
 | 
			
		||||
	var beforeHash string
 | 
			
		||||
	err := db.QueryRow(
 | 
			
		||||
		fmt.Sprintf(`SELECT MD5(CONCAT("StorageIdentifier", "BootIdentifier")) FROM public.%q WHERE "UID" = $1`, tableName),
 | 
			
		||||
		uid,
 | 
			
		||||
	).Scan(&beforeHash)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		if err == sql.ErrNoRows {
 | 
			
		||||
			return false, fmt.Errorf("no rows found for UID %d", uid)
 | 
			
		||||
		}
 | 
			
		||||
		return false, fmt.Errorf("error querying database: %v", err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	resetHWID(tableName, []int{uid})
 | 
			
		||||
 | 
			
		||||
	var afterHash string
 | 
			
		||||
	err = db.QueryRow(
 | 
			
		||||
		fmt.Sprintf(`SELECT MD5(CONCAT("StorageIdentifier", "BootIdentifier")) FROM public.%q WHERE "UID" = $1`, tableName),
 | 
			
		||||
		uid,
 | 
			
		||||
	).Scan(&afterHash)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		if err == sql.ErrNoRows {
 | 
			
		||||
			return false, fmt.Errorf("no rows found for UID %d after reset", uid)
 | 
			
		||||
		}
 | 
			
		||||
		return false, fmt.Errorf("error querying database after reset: %v", err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return beforeHash != afterHash, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func main() {
 | 
			
		||||
	if client == nil {
 | 
			
		||||
		log.Println("Bot client is not initialized")
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	client.AddHandler(func(client *discordgo.Session, r *discordgo.Ready) {
 | 
			
		||||
		log.Println("Bot is online")
 | 
			
		||||
 | 
			
		||||
		cmdIDs := make(map[string]string, len(commands))
 | 
			
		||||
 | 
			
		||||
		for _, cmd := range commands {
 | 
			
		||||
			rcmd, err := client.ApplicationCommandCreate(client.State.User.ID, config.Discord.GuildID, &cmd)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				log.Fatalf("Cannot create slash command %q: %v", cmd.Name, err)
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			cmdIDs[rcmd.ID] = rcmd.Name
 | 
			
		||||
		}
 | 
			
		||||
	})
 | 
			
		||||
 | 
			
		||||
	client.AddHandler(func(client *discordgo.Session, i *discordgo.InteractionCreate) {
 | 
			
		||||
		if i.Type == discordgo.InteractionApplicationCommand {
 | 
			
		||||
			if h, ok := commandsHandlers[i.ApplicationCommandData().Name]; ok {
 | 
			
		||||
				h(client, i)
 | 
			
		||||
			}
 | 
			
		||||
		} else if i.Type == discordgo.InteractionMessageComponent {
 | 
			
		||||
			customID := i.MessageComponentData().CustomID
 | 
			
		||||
			if h, ok := componentsHandlers[customID]; ok {
 | 
			
		||||
				h(client, i)
 | 
			
		||||
			} else if strings.HasPrefix(customID, "accept_") {
 | 
			
		||||
				componentsHandlers["accept"](client, i)
 | 
			
		||||
			} else if strings.HasPrefix(customID, "decline_") {
 | 
			
		||||
				componentsHandlers["decline"](client, i)
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	})
 | 
			
		||||
 | 
			
		||||
	err := client.Open()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		log.Println("Error opening connection:", err)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	stop := make(chan os.Signal, 1)
 | 
			
		||||
	signal.Notify(stop, os.Interrupt, syscall.SIGTERM)
 | 
			
		||||
	<-stop
 | 
			
		||||
 | 
			
		||||
	log.Println("Gracefully shutting down.")
 | 
			
		||||
	client.Close()
 | 
			
		||||
 | 
			
		||||
	if db != nil {
 | 
			
		||||
		db.Close()
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user