diff --git a/api/v1/admin/admin.go b/api/v1/admin/admin.go index 5132dcc..b1c2244 100644 --- a/api/v1/admin/admin.go +++ b/api/v1/admin/admin.go @@ -100,64 +100,23 @@ func LoginHandler() http.Handler { return } - // let's get an oauth token! - req, err := http.NewRequest(http.MethodPost, fmt.Sprintf("%s/oauth2/token", discord.API_ENDPOINT), - strings.NewReader(url.Values{ - "client_id": {discord.CLIENT_ID}, - "client_secret": {discord.CLIENT_SECRET}, - "grant_type": {"authorization_code"}, - "code": {code}, - "redirect_uri": {discord.MY_REDIRECT_URI}, - }.Encode())) - req.Header.Add("Content-Type", "application/x-www-form-urlencoded") - - res, err := http.DefaultClient.Do(req) + auth_token, err := discord.GetOAuthTokenFromCode(code) if err != nil { - fmt.Printf("Failed to retrieve OAuth token: %s\n", err) + fmt.Printf("Failed to retrieve discord access token: %s\n", err) w.WriteHeader(500) w.Write([]byte("Internal server error")) return } - oauth := discord.AccessTokenResponse{} - - err = json.NewDecoder(res.Body).Decode(&oauth) + discord_user, err := discord.GetDiscordUserFromAuth(auth_token) if err != nil { - fmt.Printf("Failed to parse OAuth response data from discord: %s\n", err) - w.WriteHeader(500) - w.Write([]byte("Internal server error")) - return - } - res.Body.Close() - - discord_access_token := oauth.AccessToken - - // let's get authorisation information! - req, err = http.NewRequest(http.MethodGet, fmt.Sprintf("%s/oauth2/@me", discord.API_ENDPOINT), nil) - req.Header.Add("Authorization", "Bearer " + discord_access_token) - - res, err = http.DefaultClient.Do(req) - if err != nil { - fmt.Printf("Failed to retrieve discord auth information: %s\n", err) + fmt.Printf("Failed to retrieve discord user information: %s\n", err) w.WriteHeader(500) w.Write([]byte("Internal server error")) return } - auth_info := discord.AuthInfoResponse{} - - err = json.NewDecoder(res.Body).Decode(&auth_info) - if err != nil { - fmt.Printf("Failed to parse auth information from discord: %s\n", err) - w.WriteHeader(500) - w.Write([]byte("Internal server error")) - return - } - res.Body.Close() - - discord_user_id := auth_info.User.Id - - if discord_user_id != ADMIN_ID_DISCORD { + if discord_user.Id != ADMIN_ID_DISCORD { // TODO: unauthorized user. revoke the token w.WriteHeader(401) w.Write([]byte("Unauthorized")) @@ -165,7 +124,7 @@ func LoginHandler() http.Handler { } // login success! - session := CreateSession(auth_info.User.Username) + session := CreateSession(discord_user.Username) sessions = append(sessions, &session) cookie := http.Cookie{} diff --git a/discord/discord.go b/discord/discord.go index d6a6468..147b270 100644 --- a/discord/discord.go +++ b/discord/discord.go @@ -1,44 +1,105 @@ package discord +import ( + "encoding/json" + "errors" + "fmt" + "net/http" + "net/url" + "strings" +) + const API_ENDPOINT = "https://discord.com/api/v10" const CLIENT_ID = "1268013769578119208" + // TODO: good GOD change this later please i beg you. we've already broken // the rules by doing this at all const CLIENT_SECRET = "JUEZnixhN7BxmLIHmbECiKETMP85VT0E" const REDIRECT_URI = "https://discord.com/oauth2/authorize?client_id=1268013769578119208&response_type=code&redirect_uri=http%3A%2F%2F127.0.0.1%3A8080%2Fapi%2Fv1%2Fadmin%2Flogin&scope=identify" + // TODO: change before prod const MY_REDIRECT_URI = "http://127.0.0.1:8080/api/v1/admin/login" type ( AccessTokenResponse struct { - TokenType string `json:"token_type"` - AccessToken string `json:"access_token"` - ExpiresIn int `json:"expires_in"` + TokenType string `json:"token_type"` + AccessToken string `json:"access_token"` + ExpiresIn int `json:"expires_in"` RefreshToken string `json:"refresh_token"` - Scope string `json:"scope"` + Scope string `json:"scope"` } AuthInfoResponse struct { Application struct { - Id string - Name string - Icon string - Description string - Hook bool - BotPublic bool + Id string + Name string + Icon string + Description string + Hook bool + BotPublic bool botRequireCodeGrant bool - VerifyKey bool + VerifyKey bool } - Scopes []string + Scopes []string Expires string - User struct { - Id string - Username string - Avatar string - Discriminator string - GlobalName string - PublicFlags int - } + User DiscordUser + } + + DiscordUser struct { + Id string + Username string + Avatar string + Discriminator string + GlobalName string + PublicFlags int } ) +func GetOAuthTokenFromCode(code string) (string, error) { + // let's get an oauth token! + req, err := http.NewRequest(http.MethodPost, fmt.Sprintf("%s/oauth2/token", API_ENDPOINT), + strings.NewReader(url.Values{ + "client_id": {CLIENT_ID}, + "client_secret": {CLIENT_SECRET}, + "grant_type": {"authorization_code"}, + "code": {code}, + "redirect_uri": {MY_REDIRECT_URI}, + }.Encode())) + req.Header.Add("Content-Type", "application/x-www-form-urlencoded") + + res, err := http.DefaultClient.Do(req) + if err != nil { + return "", errors.New(fmt.Sprintf("Failed while contacting discord API: %s", err)) + } + + oauth := AccessTokenResponse{} + + err = json.NewDecoder(res.Body).Decode(&oauth) + if err != nil { + return "", errors.New(fmt.Sprintf("Failed to parse OAuth response data from discord: %s\n", err)) + } + res.Body.Close() + + return oauth.AccessToken, nil +} + +func GetDiscordUserFromAuth(token string) (DiscordUser, error) { + // let's get authorisation information! + req, err := http.NewRequest(http.MethodGet, fmt.Sprintf("%s/oauth2/@me", API_ENDPOINT), nil) + req.Header.Add("Authorization", "Bearer " + token) + + res, err := http.DefaultClient.Do(req) + if err != nil { + return DiscordUser{}, errors.New(fmt.Sprintf("Failed to retrieve discord auth information: %s\n", err)) + } + + auth_info := AuthInfoResponse{} + + err = json.NewDecoder(res.Body).Decode(&auth_info) + if err != nil { + return DiscordUser{}, errors.New(fmt.Sprintf("Failed to parse auth information from discord: %s\n", err)) + } + defer res.Body.Close() + + return auth_info.User, nil +}