@@ 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))
@@ 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) {
@@ 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)
+}