mirror of
https://github.com/JuLi0n21/pwa-player.git
synced 2026-04-19 15:30:05 +00:00
basic oauth validation added
This commit is contained in:
289
proxy/auth.go
289
proxy/auth.go
@@ -1,9 +1,13 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
@@ -13,9 +17,6 @@ const (
|
||||
OsuApiUrl = "https://osu.ppy.sh/api/v2"
|
||||
)
|
||||
|
||||
var clientid = os.Getenv("CLIENT_ID")
|
||||
var clientsecret = os.Getenv("CLIENT_SECRET")
|
||||
var redirect_uri = os.Getenv("REDIRECT_URI")
|
||||
var scopes = []string{
|
||||
"public",
|
||||
"identify",
|
||||
@@ -34,7 +35,7 @@ func NewOsuApiClient(user User) (*OsuApiClient, error) {
|
||||
}
|
||||
|
||||
if time.Now().After(user.ExpireDate) {
|
||||
|
||||
//request new token?
|
||||
}
|
||||
|
||||
return &OsuApiClient{
|
||||
@@ -45,9 +46,48 @@ func NewOsuApiClient(user User) (*OsuApiClient, error) {
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (c *OsuApiClient) Me() (*ApiUser, error) {
|
||||
|
||||
req, err := http.NewRequest("GET", fmt.Sprintf("%s/me", OsuApiUrl), nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
res := ApiUser{}
|
||||
if err := c.sendRequest(req, &res); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &res, nil
|
||||
|
||||
}
|
||||
|
||||
func (c *OsuApiClient) sendRequest(req *http.Request, v interface{}) error {
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
req.Header.Set("Accept", "application/json")
|
||||
req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", c.User.AccessToken))
|
||||
|
||||
res, err := c.HTTPclient.Do(req)
|
||||
if err != nil {
|
||||
fmt.Println("Error: ", err.Error())
|
||||
return err
|
||||
}
|
||||
|
||||
defer res.Body.Close()
|
||||
|
||||
if res.StatusCode < http.StatusOK || res.StatusCode >= http.StatusBadRequest {
|
||||
return fmt.Errorf("unknown error, status code: %d", res.StatusCode)
|
||||
}
|
||||
|
||||
if err = json.NewDecoder(res.Body).Decode(v); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func LoginRedirect(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
fmt.Println(r.Context())
|
||||
cookie, ok := r.Context().Value("cookie").(string)
|
||||
|
||||
if !ok || cookie == "" {
|
||||
@@ -56,11 +96,248 @@ func LoginRedirect(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
var clientid = os.Getenv("CLIENT_ID")
|
||||
var redirect_uri = os.Getenv("REDIRECT_URI") + "/oauth/code"
|
||||
http.Redirect(w, r,
|
||||
fmt.Sprintf("https://osu.ppy.sh/oauth/authorize?client_id=%s&redirect_uri=%s&response_type=code&scope=%s&state=%s",
|
||||
clientid,
|
||||
redirect_uri,
|
||||
strings.Join(scopes, " "),
|
||||
cookie),
|
||||
http.StatusPermanentRedirect)
|
||||
http.StatusTemporaryRedirect)
|
||||
}
|
||||
|
||||
func Oauth(w http.ResponseWriter, r *http.Request) {
|
||||
cookie, ok := r.Context().Value("cookie").(string)
|
||||
|
||||
if !ok || cookie == "" {
|
||||
fmt.Println(cookie, ok)
|
||||
http.Error(w, "Forbidden", http.StatusForbidden)
|
||||
return
|
||||
}
|
||||
|
||||
q := r.URL.Query()
|
||||
|
||||
code := q.Get("code")
|
||||
state := q.Get("state")
|
||||
|
||||
if state != cookie {
|
||||
|
||||
http.Error(w, "Forbidden", http.StatusForbidden)
|
||||
return
|
||||
}
|
||||
|
||||
var clientid = os.Getenv("CLIENT_ID")
|
||||
var client_secret = os.Getenv("CLIENT_SECRET")
|
||||
var redirect_uri = os.Getenv("REDIRECT_URI") + "/oauth/code"
|
||||
//request accesstoken
|
||||
body := url.Values{
|
||||
"client_id": {clientid},
|
||||
"client_secret": {client_secret},
|
||||
"code": {code},
|
||||
"grant_type": {"authorization_code"},
|
||||
"redirect_uri": {redirect_uri},
|
||||
}
|
||||
|
||||
req, err := http.NewRequest("POST", "https://osu.ppy.sh/oauth/token", bytes.NewBufferString(body.Encode()))
|
||||
if err != nil {
|
||||
http.Error(w, "Forbidden", http.StatusForbidden)
|
||||
return
|
||||
}
|
||||
|
||||
req.Header.Set("Accept", "application/json")
|
||||
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
|
||||
|
||||
httpclient := &http.Client{
|
||||
Timeout: time.Minute,
|
||||
}
|
||||
|
||||
res, err := httpclient.Do(req)
|
||||
if err != nil {
|
||||
http.Error(w, "Forbidden", http.StatusForbidden)
|
||||
return
|
||||
}
|
||||
defer res.Body.Close()
|
||||
|
||||
if res.StatusCode < http.StatusOK || res.StatusCode >= http.StatusBadRequest {
|
||||
http.Error(w, "Forbidden", http.StatusForbidden)
|
||||
return
|
||||
}
|
||||
|
||||
data, err := io.ReadAll(res.Body)
|
||||
if err != nil {
|
||||
http.Error(w, "Forbidden", http.StatusForbidden)
|
||||
return
|
||||
}
|
||||
|
||||
var authToken AuthToken
|
||||
|
||||
err = json.Unmarshal(data, &authToken)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
http.Error(w, "Forbidden", http.StatusForbidden)
|
||||
return
|
||||
}
|
||||
|
||||
user := User{
|
||||
Token: Token{
|
||||
ExpireDate: time.Now().Add(time.Second * time.Duration(authToken.ExpiresIn)),
|
||||
RefreshToken: authToken.RefreshToken,
|
||||
AccessToken: authToken.AccessToken,
|
||||
},
|
||||
}
|
||||
|
||||
c, err := NewOsuApiClient(user)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
http.Error(w, "Forbidden", http.StatusForbidden)
|
||||
return
|
||||
}
|
||||
|
||||
apiuser, err := c.Me()
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
http.Error(w, "Forbidden", http.StatusForbidden)
|
||||
return
|
||||
}
|
||||
|
||||
user.UserID = apiuser.ID
|
||||
user.Name = apiuser.Username
|
||||
user.AvatarUrl = apiuser.AvatarURL
|
||||
|
||||
SaveCookie(user.UserID, cookie)
|
||||
if err = SaveUser(user); err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
|
||||
JSONResponse(w, http.StatusCreated, user)
|
||||
}
|
||||
|
||||
type AuthToken struct {
|
||||
Tokentype string `json:"token_type"`
|
||||
ExpiresIn int `json:"expires_in"`
|
||||
AccessToken string `json:"access_token"`
|
||||
RefreshToken string `json:"refresh_token"`
|
||||
}
|
||||
|
||||
type ApiUser struct {
|
||||
AvatarURL string `json:"avatar_url,omitempty"`
|
||||
CountryCode string `json:"country_code,omitempty"`
|
||||
DefaultGroup string `json:"default_group,omitempty"`
|
||||
ID int `json:"id,omitempty"`
|
||||
IsActive bool `json:"is_active,omitempty"`
|
||||
IsBot bool `json:"is_bot,omitempty"`
|
||||
IsDeleted bool `json:"is_deleted,omitempty"`
|
||||
IsOnline bool `json:"is_online,omitempty"`
|
||||
IsSupporter bool `json:"is_supporter,omitempty"`
|
||||
LastVisit time.Time `json:"last_visit,omitempty"`
|
||||
PmFriendsOnly bool `json:"pm_friends_only,omitempty"`
|
||||
ProfileColour string `json:"profile_colour,omitempty"`
|
||||
Username string `json:"username,omitempty"`
|
||||
CoverURL string `json:"cover_url,omitempty"`
|
||||
Discord string `json:"discord,omitempty"`
|
||||
HasSupported bool `json:"has_supported,omitempty"`
|
||||
Interests any `json:"interests,omitempty"`
|
||||
JoinDate time.Time `json:"join_date,omitempty"`
|
||||
Kudosu struct {
|
||||
Total int `json:"total,omitempty"`
|
||||
Available int `json:"available,omitempty"`
|
||||
} `json:"kudosu,omitempty"`
|
||||
Location any `json:"location,omitempty"`
|
||||
MaxBlocks int `json:"max_blocks,omitempty"`
|
||||
MaxFriends int `json:"max_friends,omitempty"`
|
||||
Occupation any `json:"occupation,omitempty"`
|
||||
Playmode string `json:"playmode,omitempty"`
|
||||
Playstyle []string `json:"playstyle,omitempty"`
|
||||
PostCount int `json:"post_count,omitempty"`
|
||||
ProfileOrder []string `json:"profile_order,omitempty"`
|
||||
Title any `json:"title,omitempty"`
|
||||
Twitter string `json:"twitter,omitempty"`
|
||||
Website string `json:"website,omitempty"`
|
||||
Country Country `json:"country,omitempty"`
|
||||
Cover struct {
|
||||
CustomURL string `json:"custom_url,omitempty"`
|
||||
URL string `json:"url,omitempty"`
|
||||
ID any `json:"id,omitempty"`
|
||||
} `json:"cover,omitempty"`
|
||||
IsRestricted bool `json:"is_restricted,omitempty"`
|
||||
AccountHistory []any `json:"account_history,omitempty"`
|
||||
ActiveTournamentBanner any `json:"active_tournament_banner,omitempty"`
|
||||
Badges []struct {
|
||||
AwardedAt time.Time `json:"awarded_at,omitempty"`
|
||||
Description string `json:"description,omitempty"`
|
||||
Image2XURL string `json:"image@2x_url,omitempty"`
|
||||
ImageURL string `json:"image_url,omitempty"`
|
||||
URL string `json:"url,omitempty"`
|
||||
} `json:"badges,omitempty"`
|
||||
FavouriteBeatmapsetCount int `json:"favourite_beatmapset_count,omitempty"`
|
||||
FollowerCount int `json:"follower_count,omitempty"`
|
||||
GraveyardBeatmapsetCount int `json:"graveyard_beatmapset_count,omitempty"`
|
||||
Groups []struct {
|
||||
ID int `json:"id,omitempty"`
|
||||
Identifier string `json:"identifier,omitempty"`
|
||||
Name string `json:"name,omitempty"`
|
||||
ShortName string `json:"short_name,omitempty"`
|
||||
Description string `json:"description,omitempty"`
|
||||
Colour string `json:"colour,omitempty"`
|
||||
} `json:"groups,omitempty"`
|
||||
LovedBeatmapsetCount int `json:"loved_beatmapset_count,omitempty"`
|
||||
MonthlyPlaycounts []struct {
|
||||
StartDate string `json:"start_date,omitempty"`
|
||||
Count int `json:"count,omitempty"`
|
||||
} `json:"monthly_playcounts,omitempty"`
|
||||
Page struct {
|
||||
HTML string `json:"html,omitempty"`
|
||||
Raw string `json:"raw,omitempty"`
|
||||
} `json:"page,omitempty"`
|
||||
PendingBeatmapsetCount int `json:"pending_beatmapset_count,omitempty"`
|
||||
PreviousUsernames []any `json:"previous_usernames,omitempty"`
|
||||
RankedBeatmapsetCount int `json:"ranked_beatmapset_count,omitempty"`
|
||||
ReplaysWatchedCounts []struct {
|
||||
StartDate string `json:"start_date,omitempty"`
|
||||
Count int `json:"count,omitempty"`
|
||||
} `json:"replays_watched_counts,omitempty"`
|
||||
ScoresFirstCount int `json:"scores_first_count,omitempty"`
|
||||
Statistics struct {
|
||||
Level struct {
|
||||
Current int `json:"current,omitempty"`
|
||||
Progress int `json:"progress,omitempty"`
|
||||
} `json:"level,omitempty"`
|
||||
Pp float64 `json:"pp,omitempty"`
|
||||
GlobalRank int `json:"global_rank,omitempty"`
|
||||
RankedScore int `json:"ranked_score,omitempty"`
|
||||
HitAccuracy float64 `json:"hit_accuracy,omitempty"`
|
||||
PlayCount int `json:"play_count,omitempty"`
|
||||
PlayTime int `json:"play_time,omitempty"`
|
||||
TotalScore int `json:"total_score,omitempty"`
|
||||
TotalHits int `json:"total_hits,omitempty"`
|
||||
MaximumCombo int `json:"maximum_combo,omitempty"`
|
||||
ReplaysWatchedByOthers int `json:"replays_watched_by_others,omitempty"`
|
||||
IsRanked bool `json:"is_ranked,omitempty"`
|
||||
GradeCounts struct {
|
||||
Ss int `json:"ss,omitempty"`
|
||||
SSH int `json:"ssh,omitempty"`
|
||||
S int `json:"s,omitempty"`
|
||||
Sh int `json:"sh,omitempty"`
|
||||
A int `json:"a,omitempty"`
|
||||
} `json:"grade_counts,omitempty"`
|
||||
Rank struct {
|
||||
Global int `json:"global,omitempty"`
|
||||
Country int `json:"country,omitempty"`
|
||||
} `json:"rank,omitempty"`
|
||||
} `json:"statistics,omitempty"`
|
||||
SupportLevel int `json:"support_level,omitempty"`
|
||||
UserAchievements []struct {
|
||||
AchievedAt time.Time `json:"achieved_at,omitempty"`
|
||||
AchievementID int `json:"achievement_id,omitempty"`
|
||||
} `json:"user_achievements,omitempty"`
|
||||
RankHistory struct {
|
||||
Mode string `json:"mode,omitempty"`
|
||||
Data []int `json:"data,omitempty"`
|
||||
} `json:"rank_history,omitempty"`
|
||||
}
|
||||
|
||||
type Country struct {
|
||||
Code string `json:"code"`
|
||||
Name string `json:"name"`
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user