2024-07-31 03:09:22 +00:00
|
|
|
package discord
|
|
|
|
|
2024-07-31 03:21:52 +00:00
|
|
|
import (
|
2024-08-01 23:53:19 +00:00
|
|
|
"encoding/json"
|
|
|
|
"errors"
|
|
|
|
"fmt"
|
|
|
|
"net/http"
|
|
|
|
"net/url"
|
|
|
|
"strings"
|
2024-08-31 01:56:06 +00:00
|
|
|
|
2024-09-03 07:07:45 +00:00
|
|
|
"arimelody-web/global"
|
2024-07-31 03:21:52 +00:00
|
|
|
)
|
|
|
|
|
2024-07-31 03:09:22 +00:00
|
|
|
const API_ENDPOINT = "https://discord.com/api/v10"
|
2024-07-31 03:21:52 +00:00
|
|
|
|
2024-08-02 21:48:26 +00:00
|
|
|
var CREDENTIALS_PROVIDED = true
|
2024-08-01 23:53:19 +00:00
|
|
|
var CLIENT_ID = func() string {
|
2024-11-10 05:34:04 +00:00
|
|
|
id := global.Config.Discord.ClientID
|
2024-08-31 01:56:06 +00:00
|
|
|
if id == "" {
|
2024-11-10 05:34:04 +00:00
|
|
|
fmt.Printf("WARN: discord.client_id was not provided. Admin login will be unavailable.\n")
|
2024-08-02 21:48:26 +00:00
|
|
|
CREDENTIALS_PROVIDED = false
|
2024-08-01 23:53:19 +00:00
|
|
|
}
|
2024-08-31 01:56:06 +00:00
|
|
|
return id
|
2024-08-01 23:53:19 +00:00
|
|
|
}()
|
|
|
|
var CLIENT_SECRET = func() string {
|
2024-11-10 05:34:04 +00:00
|
|
|
secret := global.Config.Discord.Secret
|
2024-09-03 07:07:45 +00:00
|
|
|
if secret == "" {
|
2024-11-10 05:34:04 +00:00
|
|
|
fmt.Printf("WARN: discord.secret not provided. Admin login will be unavailable.\n")
|
2024-08-02 21:48:26 +00:00
|
|
|
CREDENTIALS_PROVIDED = false
|
2024-08-01 23:53:19 +00:00
|
|
|
}
|
2024-08-31 01:56:06 +00:00
|
|
|
return secret
|
2024-08-01 23:53:19 +00:00
|
|
|
}()
|
2024-11-10 05:34:04 +00:00
|
|
|
var OAUTH_CALLBACK_URI = fmt.Sprintf("%s/admin/login", global.Config.BaseUrl)
|
2024-08-31 01:56:06 +00:00
|
|
|
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)
|
2024-07-31 03:09:22 +00:00
|
|
|
|
|
|
|
type (
|
|
|
|
AccessTokenResponse struct {
|
2024-07-31 03:21:52 +00:00
|
|
|
AccessToken string `json:"access_token"`
|
2024-08-02 21:48:26 +00:00
|
|
|
TokenType string `json:"token_type"`
|
2024-07-31 03:21:52 +00:00
|
|
|
ExpiresIn int `json:"expires_in"`
|
2024-07-31 03:09:22 +00:00
|
|
|
RefreshToken string `json:"refresh_token"`
|
2024-07-31 03:21:52 +00:00
|
|
|
Scope string `json:"scope"`
|
2024-07-31 03:09:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
AuthInfoResponse struct {
|
|
|
|
Application struct {
|
2024-08-05 00:23:17 +00:00
|
|
|
ID string `json:"id"`
|
2024-08-02 21:48:26 +00:00
|
|
|
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"`
|
2024-07-31 03:21:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
DiscordUser struct {
|
2024-08-05 00:23:17 +00:00
|
|
|
ID string `json:"id"`
|
2024-08-02 21:48:26 +00:00
|
|
|
Username string `json:"username"`
|
|
|
|
Avatar string `json:"avatar"`
|
|
|
|
Discriminator string `json:"discriminator"`
|
|
|
|
GlobalName string `json:"global_name"`
|
|
|
|
PublicFlags int `json:"public_flags"`
|
2024-07-31 03:09:22 +00:00
|
|
|
}
|
|
|
|
)
|
|
|
|
|
2024-07-31 03:21:52 +00:00
|
|
|
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},
|
2024-08-01 23:53:19 +00:00
|
|
|
"redirect_uri": {OAUTH_CALLBACK_URI},
|
2024-07-31 03:21:52 +00:00
|
|
|
}.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
|
|
|
|
}
|