From 330e3a29c76e7582ae2169b6ed8cf6ae362431e6 Mon Sep 17 00:00:00 2001 From: core Date: Tue, 28 Nov 2023 18:05:56 -0500 Subject: [PATCH] API work --- starkingdoms-api/cmd/starkingdoms-api/main.go | 124 +++++++++++++++++- starkingdoms-api/config.go | 5 + starkingdoms-api/discord.go | 10 ++ 3 files changed, 137 insertions(+), 2 deletions(-) create mode 100644 starkingdoms-api/discord.go diff --git a/starkingdoms-api/cmd/starkingdoms-api/main.go b/starkingdoms-api/cmd/starkingdoms-api/main.go index 2d0a63d53de6d66b3e00b86823b57f76baf3b5bf..04d1f6527860202e77253c8a958dec4a4ee00706 100644 --- a/starkingdoms-api/cmd/starkingdoms-api/main.go +++ b/starkingdoms-api/cmd/starkingdoms-api/main.go @@ -4,11 +4,25 @@ import ( "flag" "fmt" "github.com/sirupsen/logrus" - starkingdoms_api "gitlab.com/starkingdoms.tk/starkingdoms.tk/starkingdoms-api" + starkingdomsapi "gitlab.com/starkingdoms.tk/starkingdoms.tk/starkingdoms-api" + "io" + "math/rand" "net/http" + "net/url" "os" + "strings" ) +var letters = []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ") + +func randSeq(n int) string { + b := make([]rune, n) + for i := range b { + b[i] = letters[rand.Intn(len(letters))] + } + return string(b) +} + func main() { configPath := flag.String("config", "config.yml", "File to load configuration file from") printUsage := flag.Bool("help", false, "Show command line usage") @@ -20,7 +34,7 @@ func main() { os.Exit(0) } - c, err := starkingdoms_api.LoadConfig(*configPath) + c, err := starkingdomsapi.LoadConfig(*configPath) if err != nil { fmt.Printf("failed to load config: %s", err) @@ -45,7 +59,113 @@ func main() { _, err := fmt.Fprintf(w, "pong") if err != nil { logrus.Error(err) + return + } + }) + + var stateMap = make(map[string]string) + + http.HandleFunc("/discord/start", func(w http.ResponseWriter, r *http.Request) { + logrus.WithFields(logrus.Fields{ + "remote": r.RemoteAddr, + }).Info("GET /discord/start") + + redirectUri := r.URL.Query().Get("back") + if redirectUri == "" { + _, err := fmt.Fprintf(w, "Missing `back` parameter.") + if err != nil { + logrus.Error(err) + return + } + return + } + + state := randSeq(20) + stateMap[state] = redirectUri + discordUrl := starkingdomsapi.DiscordApiUrl(c, state) + http.Redirect(w, r, discordUrl, http.StatusFound) + }) + + http.HandleFunc("/discord/callback", func(w http.ResponseWriter, r *http.Request) { + logrus.WithFields(logrus.Fields{ + "remote": r.RemoteAddr, + }).Info("GET /discord/callback") + + code := r.URL.Query().Get("code") + if code == "" { + _, err := fmt.Fprintf(w, "Missing `code` parameter.") + if err != nil { + logrus.Error(err) + return + } + return + } + + state := r.URL.Query().Get("state") + if state == "" { + _, err := fmt.Fprintf(w, "Missing `state` parameter.") + if err != nil { + logrus.Error(err) + return + } + return + } + + _, ok := stateMap[state] + if !ok { + _, err := fmt.Fprintf(w, "Invalid `state` parameter, cannot redirect back. Perhaps your login expired? Try starting over from the main login page.") + if err != nil { + logrus.Error(err) + return + } + } + + delete(stateMap, state) + + client := &http.Client{} + + v := url.Values{ + "grant_type": {"authorization_code"}, + "code": {code}, + "redirect_uri": {c.Discord.RedirectURI}, + } + + logrus.WithFields(logrus.Fields{ + "sendingBody": v.Encode(), + }).Info("sending token request") + + req, err := http.NewRequest("POST", "https://discord.com/api/v10/oauth2/token", strings.NewReader(v.Encode())) + + if err != nil { + logrus.Error(err) + return } + + req.Header.Set("Accept", "application/json") + req.SetBasicAuth(c.Discord.ClientID, c.Discord.ClientSecret) + + resp, err := client.Do(req) + defer func(Body io.ReadCloser) { + err := Body.Close() + if err != nil { + logrus.Error(err) + return + } + }(resp.Body) + + if err != nil { + logrus.Error(err) + return + } + + b, err := io.ReadAll(resp.Body) + if err != nil { + logrus.Fatal(err) + } + + logrus.WithFields(logrus.Fields{ + "resp": string(b), + }).Info("got authentication token") }) logrus.Error(http.ListenAndServe(c.Server.Host+":"+c.Server.Port, nil)) diff --git a/starkingdoms-api/config.go b/starkingdoms-api/config.go index fee169fb5d9eca4fa7a24a39be58b539b4e6f277..3db191b89b4617ec991e34c619074c80c721b093 100644 --- a/starkingdoms-api/config.go +++ b/starkingdoms-api/config.go @@ -15,6 +15,11 @@ type Config struct { Format string `yaml:"format"` Level logrus.Level `yaml:"level"` } `yaml:"logging"` + Discord struct { + ClientID string `yaml:"client_id"` + ClientSecret string `yaml:"client_secret"` + RedirectURI string `yaml:"redirect_uri"` + } `yaml:"discord"` } func LoadConfig(path string) (*Config, error) { diff --git a/starkingdoms-api/discord.go b/starkingdoms-api/discord.go new file mode 100644 index 0000000000000000000000000000000000000000..ca9df3f83379a4985793db9dc1525a76dcf0d111 --- /dev/null +++ b/starkingdoms-api/discord.go @@ -0,0 +1,10 @@ +package starkingdoms_api + +import ( + "fmt" + "net/url" +) + +func DiscordApiUrl(c *Config, state string) string { + return fmt.Sprintf("https://discord.com/api/oauth2/authorize?client_id=%s&redirect_uri=%s&response_type=code&scope=identify&state=%s", c.Discord.ClientID, url.QueryEscape(c.Discord.RedirectURI), state) +}