mirror of
https://github.com/JuLi0n21/pwa-player.git
synced 2026-04-19 15:30:05 +00:00
add proxy server for dynamic api endpoint handling and auth
This commit is contained in:
4
proxy/.env
Normal file
4
proxy/.env
Normal file
@@ -0,0 +1,4 @@
|
||||
CLIENT_ID=
|
||||
CLIENT_SECRET=
|
||||
REDIRECT_URI=
|
||||
HOST=
|
||||
0
proxy/.gitignore
vendored
Normal file
0
proxy/.gitignore
vendored
Normal file
66
proxy/auth.go
Normal file
66
proxy/auth.go
Normal file
@@ -0,0 +1,66 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
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",
|
||||
}
|
||||
|
||||
type OsuApiClient struct {
|
||||
User User
|
||||
BaseURL string
|
||||
HTTPclient *http.Client
|
||||
}
|
||||
|
||||
func NewOsuApiClient(user User) (*OsuApiClient, error) {
|
||||
|
||||
if user.Token == (Token{}) {
|
||||
return nil, errors.New("No Valid Credentials")
|
||||
}
|
||||
|
||||
if time.Now().After(user.ExpireDate) {
|
||||
|
||||
}
|
||||
|
||||
return &OsuApiClient{
|
||||
User: user,
|
||||
BaseURL: OsuApiUrl,
|
||||
HTTPclient: &http.Client{
|
||||
Timeout: time.Minute * 2},
|
||||
}, nil
|
||||
}
|
||||
|
||||
func LoginRedirect(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
fmt.Println(r.Context())
|
||||
cookie, ok := r.Context().Value("cookie").(string)
|
||||
|
||||
if !ok || cookie == "" {
|
||||
fmt.Println(cookie, ok)
|
||||
http.Error(w, "Internal Server Error", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
BIN
proxy/database.db
Normal file
BIN
proxy/database.db
Normal file
Binary file not shown.
100
proxy/db.go
Normal file
100
proxy/db.go
Normal file
@@ -0,0 +1,100 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"log"
|
||||
"time"
|
||||
|
||||
_ "github.com/mattn/go-sqlite3"
|
||||
)
|
||||
|
||||
type User struct {
|
||||
UserID int
|
||||
Name string
|
||||
AvatarUrl string
|
||||
EndPoint string
|
||||
Token
|
||||
}
|
||||
|
||||
type Token struct {
|
||||
AuthToken string
|
||||
RefreshToken string
|
||||
ExpireDate time.Time
|
||||
}
|
||||
|
||||
var db *sql.DB
|
||||
|
||||
func InitDB() {
|
||||
var err error
|
||||
db, err = sql.Open("sqlite3", "database.db")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
//users
|
||||
u := `
|
||||
CREATE TABLE IF NOT EXISTS users (
|
||||
id INTEGER PRIMARY KEY NOT NULL,
|
||||
name TEXT NOT NULL,
|
||||
endpoint TEXT,
|
||||
avatar_url TEXT,
|
||||
auth_token TEXT,
|
||||
refresh_token TEXT,
|
||||
expire_date TEXT
|
||||
);`
|
||||
|
||||
_, err = db.Exec(u)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
//cookiejar
|
||||
a := `
|
||||
CREATE TABLE IF NOT EXISTS cookiejar (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
user_id INTEGER,
|
||||
cookie TEXT NOT NULL,
|
||||
FOREIGN KEY(user_id) REFERENCES users(id) On DELETE CASCADE
|
||||
);`
|
||||
|
||||
_, err = db.Exec(a)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func GetUserByCookie(cookie string) (*User, error) {
|
||||
query := `
|
||||
SELECT users.id, users.name, users.endpoint, users.avatar_url, users.auth_token, users.refresh_token, users.expire_date
|
||||
FROM users users
|
||||
JOIN cookiejar cookie ON users.id = cookie.user_id
|
||||
WHERE cookie.cookie = ?`
|
||||
row := db.QueryRow(query, cookie)
|
||||
|
||||
var user User
|
||||
err := row.Scan(&user.UserID, &user.Name, &user.EndPoint, &user.AvatarUrl, &user.AuthToken, &user.RefreshToken, &user.ExpireDate)
|
||||
if err != nil {
|
||||
return &User{}, err
|
||||
}
|
||||
|
||||
return &user, nil
|
||||
}
|
||||
|
||||
func SaveCookie(userID int, cookie string) error {
|
||||
query := "INSERT INTO cookiejar (user_id, cookie) VALUES (?, ?)"
|
||||
_, err := db.Exec(query, userID, cookie)
|
||||
return err
|
||||
}
|
||||
|
||||
func UpdateUserTokens(userID int, auth Token) error {
|
||||
query := "UPDATE users SET auth_token = ?, refresh_token = ?, expire_date = ? WHERE id = ?"
|
||||
_, err := db.Exec(query, auth.AuthToken, auth.RefreshToken, auth.ExpireDate, userID)
|
||||
return err
|
||||
}
|
||||
|
||||
func UpdateUserEndPoint(userID int, endPoint string) error {
|
||||
query := "UPDATE users SET endpoint = ? WHERE id = ?"
|
||||
_, err := db.Exec(query, endPoint, userID)
|
||||
return err
|
||||
}
|
||||
8
proxy/go.mod
Normal file
8
proxy/go.mod
Normal file
@@ -0,0 +1,8 @@
|
||||
module proxy
|
||||
|
||||
go 1.22.1
|
||||
|
||||
require (
|
||||
github.com/joho/godotenv v1.5.1
|
||||
github.com/mattn/go-sqlite3 v1.14.22
|
||||
)
|
||||
4
proxy/go.sum
Normal file
4
proxy/go.sum
Normal file
@@ -0,0 +1,4 @@
|
||||
github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0=
|
||||
github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
|
||||
github.com/mattn/go-sqlite3 v1.14.22 h1:2gZY6PC6kBnID23Tichd1K+Z0oS6nE/XwU+Vz/5o4kU=
|
||||
github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
|
||||
20
proxy/main.go
Normal file
20
proxy/main.go
Normal file
@@ -0,0 +1,20 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/joho/godotenv"
|
||||
)
|
||||
|
||||
func main() {
|
||||
|
||||
if ok := godotenv.Load(); ok != nil {
|
||||
panic(".env not found")
|
||||
}
|
||||
|
||||
InitDB()
|
||||
err := run()
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
}
|
||||
65
proxy/middleware.go
Normal file
65
proxy/middleware.go
Normal file
@@ -0,0 +1,65 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/rand"
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"time"
|
||||
)
|
||||
|
||||
func AuthMiddleware(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
cookie, err := r.Cookie("session_cookie")
|
||||
if err != nil || cookie.Value == "" {
|
||||
http.Error(w, "Unauthorized", http.StatusUnauthorized)
|
||||
return
|
||||
}
|
||||
|
||||
user, err := GetUserByCookie(cookie.Value)
|
||||
if err != nil || cookie.Value == "" {
|
||||
http.Error(w, "Unauthorized", http.StatusUnauthorized)
|
||||
return
|
||||
}
|
||||
|
||||
ctx := context.WithValue(r.Context(), "user", user)
|
||||
next.ServeHTTP(w, r.WithContext(ctx))
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
func CookieMiddleware(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
cookie, err := r.Cookie("session_cookie")
|
||||
if err != nil || cookie.Value == "" {
|
||||
|
||||
newCookie := &http.Cookie{
|
||||
Name: "session_cookie",
|
||||
Value: "session_cookie_" + generateRandomString(64),
|
||||
Expires: time.Now().Add(time.Hour * 10000),
|
||||
HttpOnly: true,
|
||||
Secure: true,
|
||||
Path: "/",
|
||||
}
|
||||
|
||||
http.SetCookie(w, newCookie)
|
||||
}
|
||||
|
||||
ctx := context.WithValue(r.Context(), "cookie", cookie.Value)
|
||||
next.ServeHTTP(w, r.WithContext(ctx))
|
||||
})
|
||||
}
|
||||
|
||||
func generateRandomString(length int) string {
|
||||
bytes := make([]byte, length)
|
||||
_, err := rand.Read(bytes)
|
||||
if err != nil {
|
||||
fmt.Print(err)
|
||||
return "IF_U_SEE_THIS_UR_THE_GOAT"
|
||||
}
|
||||
|
||||
return base64.URLEncoding.EncodeToString(bytes)
|
||||
}
|
||||
40
proxy/routes.go
Normal file
40
proxy/routes.go
Normal file
@@ -0,0 +1,40 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
func run() error {
|
||||
mux := http.NewServeMux()
|
||||
|
||||
mux.Handle("/me", AuthMiddleware(http.HandlerFunc(MeHandler)))
|
||||
mux.Handle("/login", http.HandlerFunc(LoginRedirect))
|
||||
|
||||
fmt.Println("Starting Server on :42000")
|
||||
|
||||
//global middleware
|
||||
handler := CookieMiddleware(mux)
|
||||
|
||||
return http.ListenAndServe(":42000", handler)
|
||||
}
|
||||
|
||||
func MeHandler(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
user := r.Context().Value("user").(*User)
|
||||
|
||||
w.Header().Set("Content-Type", "application/Json")
|
||||
|
||||
JSONResponse(w, http.StatusOK, user)
|
||||
}
|
||||
|
||||
func JSONResponse(w http.ResponseWriter, statusCode int, data interface{}) {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
|
||||
w.WriteHeader(statusCode)
|
||||
|
||||
if err := json.NewEncoder(w).Encode(data); err != nil {
|
||||
http.Error(w, "Failed to encode response as JSON", http.StatusInternalServerError)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user