arimelody.me/discord/discord.go

119 lines
3.9 KiB
Go
Raw Normal View History

package discord
import (
"encoding/json"
"errors"
"fmt"
"net/http"
"net/url"
2024-09-03 07:07:45 +00:00
"os"
"strings"
2024-09-03 07:07:45 +00:00
"arimelody-web/global"
)
const API_ENDPOINT = "https://discord.com/api/v10"
var CREDENTIALS_PROVIDED = true
var CLIENT_ID = func() string {
2024-09-03 07:07:45 +00:00
id := os.Getenv("DISCORD_CLIENT")
if id == "" {
2024-09-03 07:07:45 +00:00
fmt.Printf("WARN: Discord client ID (DISCORD_CLIENT) was not provided. Admin login will be unavailable.\n")
CREDENTIALS_PROVIDED = false
}
return id
}()
var CLIENT_SECRET = func() string {
2024-09-03 07:07:45 +00:00
secret := os.Getenv("DISCORD_SECRET")
if secret == "" {
fmt.Printf("WARN: Discord secret (DISCORD_SECRET) was not provided. Admin login will be unavailable.\n")
CREDENTIALS_PROVIDED = false
}
return secret
}()
var OAUTH_CALLBACK_URI = fmt.Sprintf("%s/admin/login", global.HTTP_DOMAIN)
var REDIRECT_URI = fmt.Sprintf("https://discord.com/oauth2/authorize?client_id=%s&response_type=code&redirect_uri=%s&scope=identify", CLIENT_ID, OAUTH_CALLBACK_URI)
type (
AccessTokenResponse struct {
AccessToken string `json:"access_token"`
TokenType string `json:"token_type"`
ExpiresIn int `json:"expires_in"`
RefreshToken string `json:"refresh_token"`
Scope string `json:"scope"`
}
AuthInfoResponse struct {
Application struct {
ID string `json:"id"`
Name string `json:"name"`
Icon string `json:"icon"`
Description string `json:"description"`
Hook bool `json:"hook"`
BotPublic bool `json:"bot_public"`
BotRequireCodeGrant bool `json:"bot_require_code_grant"`
VerifyKey string `json:"verify_key"`
} `json:"application"`
Scopes []string `json:"scopes"`
Expires string `json:"expires"`
User DiscordUser `json:"user"`
}
DiscordUser struct {
ID string `json:"id"`
Username string `json:"username"`
Avatar string `json:"avatar"`
Discriminator string `json:"discriminator"`
GlobalName string `json:"global_name"`
PublicFlags int `json:"public_flags"`
}
)
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": {OAUTH_CALLBACK_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
}