Start Discord Auth

This commit is contained in:
eccentric 2023-12-09 15:35:33 +00:00
parent 98a30263a6
commit 0dc1423b9d
7 changed files with 104 additions and 19 deletions

View File

@ -13,6 +13,11 @@ type CS struct {
Type string Type string
DropAllTables bool DropAllTables bool
} }
Discord struct {
ID string
Secret string
Token string
}
Output struct { Output struct {
Level string Level string
} }
@ -61,6 +66,21 @@ func LoadConfig(file []byte) {
panic("Output Level must be either dev or prod") panic("Output Level must be either dev or prod")
} }
Config.Discord.ID = cfg.Section("discord").Key("id").String()
if Config.Discord.ID == "" {
panic("Discord Client ID is empty")
}
Config.Discord.Secret = cfg.Section("discord").Key("secret").String()
if Config.Discord.Secret == "" {
panic("Discord Client Secret is empty")
}
Config.Discord.Token = cfg.Section("discord").Key("token").String()
if Config.Discord.Token == "" {
panic("Discord Bot Token is empty")
}
Config.API.Host = cfg.Section("api").Key("host").String() Config.API.Host = cfg.Section("api").Key("host").String()
if Config.API.Host == "" { if Config.API.Host == "" {
panic("API Host is empty") panic("API Host is empty")

View File

@ -6,6 +6,14 @@ type="postgres"
; drop all tables at start of program ; drop all tables at start of program
drop=false drop=false
[discord]
; discord oauth2 client id
id="1234567890..."
; discord oauth2 client secret
secret="abcdefg..."
; discord bot token
token="OTK...."
[output] [output]
; level of logging ; level of logging
; info = everything ; info = everything
@ -19,7 +27,7 @@ port=":3000"
; host that the api is running on ; host that the api is running on
; e.g. if you are running the api on your local machine, you would set this to 127.0.0.1 ; e.g. if you are running the api on your local machine, you would set this to 127.0.0.1
; if you are running the api on a server, you would set this to the ip of the server or the domain name ; if you are running the api on a server, you would set this to the ip of the server or the domain name
host="127.0.0.1" host="http://127.0.0.1"
[jwt] [jwt]
; secret for jwt signing ; secret for jwt signing

View File

@ -10,20 +10,20 @@ import (
) )
var ( var (
oauthTokenGrantTypes = map[string]func(c *fiber.Ctx, body *OAuthTokenBody) error{ oauthTokenGrantTypes = map[string]func(c *fiber.Ctx, body *FortniteTokenBody) error{
"client_credentials": PostOAuthTokenClientCredentials, "client_credentials": PostTokenClientCredentials,
"password": PostOAuthTokenPassword, "password": PostTokenPassword,
} }
) )
type OAuthTokenBody struct { type FortniteTokenBody struct {
GrantType string `form:"grant_type" binding:"required"` GrantType string `form:"grant_type" binding:"required"`
Username string `form:"username"` Username string `form:"username"`
Password string `form:"password"` Password string `form:"password"`
} }
func PostOAuthToken(c *fiber.Ctx) error { func PostFortniteToken(c *fiber.Ctx) error {
var body OAuthTokenBody var body FortniteTokenBody
if err := c.BodyParser(&body); err != nil { if err := c.BodyParser(&body); err != nil {
return c.Status(fiber.StatusBadRequest).JSON(aid.ErrorBadRequest("Invalid Request Body")) return c.Status(fiber.StatusBadRequest).JSON(aid.ErrorBadRequest("Invalid Request Body"))
@ -36,7 +36,7 @@ func PostOAuthToken(c *fiber.Ctx) error {
return c.Status(fiber.StatusBadRequest).JSON(aid.ErrorBadRequest("Invalid Grant Type")) return c.Status(fiber.StatusBadRequest).JSON(aid.ErrorBadRequest("Invalid Grant Type"))
} }
func PostOAuthTokenClientCredentials(c *fiber.Ctx, body *OAuthTokenBody) error { func PostTokenClientCredentials(c *fiber.Ctx, body *FortniteTokenBody) error {
credentials, err := aid.JWTSign(aid.JSON{ credentials, err := aid.JWTSign(aid.JSON{
"snow_id": 0, // custom "snow_id": 0, // custom
"creation_date": time.Now().Format("2006-01-02T15:04:05.999Z"), "creation_date": time.Now().Format("2006-01-02T15:04:05.999Z"),
@ -56,7 +56,7 @@ func PostOAuthTokenClientCredentials(c *fiber.Ctx, body *OAuthTokenBody) error {
}) })
} }
func PostOAuthTokenPassword(c *fiber.Ctx, body *OAuthTokenBody) error { func PostTokenPassword(c *fiber.Ctx, body *FortniteTokenBody) error {
if body.Username == "" || body.Password == "" { if body.Username == "" || body.Password == "" {
return c.Status(fiber.StatusBadRequest).JSON(aid.ErrorBadRequest("Username/Password is empty")) return c.Status(fiber.StatusBadRequest).JSON(aid.ErrorBadRequest("Username/Password is empty"))
} }
@ -150,7 +150,7 @@ func GetOAuthVerify(c *fiber.Ctx) error {
}) })
} }
func OAuthMiddleware(c *fiber.Ctx) error { func FortniteMiddleware(c *fiber.Ctx) error {
auth := c.Get("Authorization") auth := c.Get("Authorization")
if auth == "" { if auth == "" {
return c.Status(fiber.StatusForbidden).JSON(aid.ErrorBadRequest("Authorization Header is empty")) return c.Status(fiber.StatusForbidden).JSON(aid.ErrorBadRequest("Authorization Header is empty"))
@ -177,7 +177,39 @@ func OAuthMiddleware(c *fiber.Ctx) error {
} }
c.Locals("person", person) c.Locals("person", person)
return c.Next()
}
func FrontendMiddleware(c *fiber.Ctx) error {
auth := c.Get("Authorization")
if auth == "" {
return c.Status(fiber.StatusForbidden).JSON(aid.ErrorBadRequest("Authorization Header is empty"))
}
claims, err := aid.JWTVerify(auth)
if err != nil {
return c.Status(fiber.StatusForbidden).JSON(aid.ErrorBadRequest("Invalid Access Token"))
}
if claims["snow_id"] == nil {
return c.Status(fiber.StatusForbidden).JSON(aid.ErrorBadRequest("Invalid Access Token"))
}
if claims["frontend"] == nil {
return c.Status(fiber.StatusForbidden).JSON(aid.ErrorBadRequest("Invalid Claims"))
}
snowId, ok := claims["snow_id"].(string)
if !ok {
return c.Status(fiber.StatusForbidden).JSON(aid.ErrorBadRequest("Invalid Access Token"))
}
person := p.Find(snowId)
if person == nil {
return c.Status(fiber.StatusForbidden).JSON(aid.ErrorBadRequest("Invalid Access Token"))
}
c.Locals("person", person)
return c.Next() return c.Next()
} }

12
handlers/discord.go Normal file
View File

@ -0,0 +1,12 @@
package handlers
import (
"net/url"
"github.com/ectrc/snow/aid"
"github.com/gofiber/fiber/v2"
)
func GetDiscordOAuthURL(c *fiber.Ctx) error {
return c.Status(200).SendString("https://discord.com/api/oauth2/authorize?client_id="+ aid.Config.Discord.ID +"&redirect_uri="+ url.QueryEscape(aid.Config.API.Host + aid.Config.API.Port +"/snow/discord/callback") + "&response_type=code&scope=identify")
}

View File

@ -76,7 +76,7 @@ func createPlaylist(mnemonic string, image string) aid.JSON {
func PostDiscovery(c *fiber.Ctx) error { func PostDiscovery(c *fiber.Ctx) error {
results := []aid.JSON{} results := []aid.JSON{}
for playlist := range fortnite.PlaylistImages { for playlist := range fortnite.PlaylistImages {
results = append(results, createPlaylist(playlist, "http://" + aid.Config.API.Host + aid.Config.API.Port + "/snow/image/" + playlist + ".png?cache="+strconv.Itoa(rand.Intn(9999)))) results = append(results, createPlaylist(playlist, aid.Config.API.Host + aid.Config.API.Port + "/snow/image/" + playlist + ".png?cache="+strconv.Itoa(rand.Intn(9999))))
} }
results = append(results, createPlaylist("Playlist_DefaultSolo", "http://bucket.retrac.site/55737fa15677cd57fab9e7f4499d62f89cfde320.png")) results = append(results, createPlaylist("Playlist_DefaultSolo", "http://bucket.retrac.site/55737fa15677cd57fab9e7f4499d62f89cfde320.png"))
@ -157,7 +157,7 @@ func GetContentPages(c *fiber.Ctx) error {
playlists := []aid.JSON{} playlists := []aid.JSON{}
for playlist := range fortnite.PlaylistImages { for playlist := range fortnite.PlaylistImages {
playlists = append(playlists, aid.JSON{ playlists = append(playlists, aid.JSON{
"image": "http://" + aid.Config.API.Host + aid.Config.API.Port + "/snow/image/" + playlist + ".png?cache="+strconv.Itoa(rand.Intn(9999)), "image": aid.Config.API.Host + aid.Config.API.Port + "/snow/image/" + playlist + ".png?cache="+strconv.Itoa(rand.Intn(9999)),
"playlist_name": playlist, "playlist_name": playlist,
"hidden": false, "hidden": false,
}) })

View File

@ -4,6 +4,7 @@ import (
"strings" "strings"
"github.com/ectrc/snow/fortnite" "github.com/ectrc/snow/fortnite"
"github.com/ectrc/snow/person"
"github.com/gofiber/fiber/v2" "github.com/gofiber/fiber/v2"
) )
@ -26,3 +27,8 @@ func GetPlaylistImage(c *fiber.Ctx) error {
c.Set("Content-Type", "image/png") c.Set("Content-Type", "image/png")
return c.Send(image) return c.Send(image)
} }
func GetPlayerLocker(c *fiber.Ctx) error {
person := c.Locals("person").(*person.Person)
return c.JSON(person.AthenaProfile.Items)
}

21
main.go
View File

@ -8,8 +8,8 @@ import (
"github.com/ectrc/snow/fortnite" "github.com/ectrc/snow/fortnite"
"github.com/ectrc/snow/handlers" "github.com/ectrc/snow/handlers"
"github.com/ectrc/snow/storage" "github.com/ectrc/snow/storage"
"github.com/goccy/go-json"
"github.com/goccy/go-json"
"github.com/gofiber/fiber/v2" "github.com/gofiber/fiber/v2"
) )
@ -70,7 +70,7 @@ func main() {
account.Get("/public/account/:accountId/externalAuths", handlers.GetPublicAccountExternalAuths) account.Get("/public/account/:accountId/externalAuths", handlers.GetPublicAccountExternalAuths)
account.Get("/public/account/displayName/:displayName", handlers.GetPublicAccountByDisplayName) account.Get("/public/account/displayName/:displayName", handlers.GetPublicAccountByDisplayName)
account.Get("/oauth/verify", handlers.GetOAuthVerify) account.Get("/oauth/verify", handlers.GetOAuthVerify)
account.Post("/oauth/token", handlers.PostOAuthToken) account.Post("/oauth/token", handlers.PostFortniteToken)
account.Delete("/oauth/sessions/kill", handlers.DeleteOAuthSessions) account.Delete("/oauth/sessions/kill", handlers.DeleteOAuthSessions)
fortnite := r.Group("/fortnite/api") fortnite := r.Group("/fortnite/api")
@ -79,7 +79,7 @@ func main() {
fortnite.Get("/calendar/v1/timeline", handlers.GetFortniteTimeline) fortnite.Get("/calendar/v1/timeline", handlers.GetFortniteTimeline)
storefront := fortnite.Group("/storefront/v2") storefront := fortnite.Group("/storefront/v2")
storefront.Use(handlers.OAuthMiddleware) storefront.Use(handlers.FortniteMiddleware)
storefront.Get("/catalog", handlers.GetStorefrontCatalog) storefront.Get("/catalog", handlers.GetStorefrontCatalog)
storefront.Get("/keychain", handlers.GetStorefrontKeychain) storefront.Get("/keychain", handlers.GetStorefrontKeychain)
@ -92,7 +92,7 @@ func main() {
storage.Get("/system/:fileName", handlers.GetCloudStorageFile) storage.Get("/system/:fileName", handlers.GetCloudStorageFile)
user := storage.Group("/user") user := storage.Group("/user")
user.Use(handlers.OAuthMiddleware) user.Use(handlers.FortniteMiddleware)
user.Get("/:accountId", handlers.GetUserStorageFiles) user.Get("/:accountId", handlers.GetUserStorageFiles)
user.Get("/:accountId/:fileName", handlers.GetUserStorageFile) user.Get("/:accountId/:fileName", handlers.GetUserStorageFile)
user.Put("/:accountId/:fileName", handlers.PutUserStorageFile) user.Put("/:accountId/:fileName", handlers.PutUserStorageFile)
@ -105,7 +105,7 @@ func main() {
game.Post("/profileToken/verify/:accountId", handlers.AnyNoContent) game.Post("/profileToken/verify/:accountId", handlers.AnyNoContent)
profile := game.Group("/profile/:accountId") profile := game.Group("/profile/:accountId")
profile.Use(handlers.OAuthMiddleware) profile.Use(handlers.FortniteMiddleware)
profile.Post("/client/:action", handlers.PostProfileAction) profile.Post("/client/:action", handlers.PostProfileAction)
lightswitch := r.Group("/lightswitch/api") lightswitch := r.Group("/lightswitch/api")
@ -115,14 +115,21 @@ func main() {
snow.Get("/cosmetics", handlers.GetPreloadedCosmetics) snow.Get("/cosmetics", handlers.GetPreloadedCosmetics)
snow.Get("/image/:playlist", handlers.GetPlaylistImage) snow.Get("/image/:playlist", handlers.GetPlaylistImage)
discord := snow.Group("/discord")
discord.Get("/", handlers.GetDiscordOAuthURL)
player := snow.Group("/player")
player.Use(handlers.FrontendMiddleware)
player.Get("/locker", handlers.GetPlayerLocker)
r.Hooks().OnListen(func(ld fiber.ListenData) error { r.Hooks().OnListen(func(ld fiber.ListenData) error {
aid.Print("Listening on " + "0.0.0.0:" + ld.Port) aid.Print("Listening on " + aid.Config.API.Host + ":" + ld.Port)
return nil return nil
}) })
r.All("*", func(c *fiber.Ctx) error { return c.Status(fiber.StatusNotFound).JSON(aid.ErrorNotFound) }) r.All("*", func(c *fiber.Ctx) error { return c.Status(fiber.StatusNotFound).JSON(aid.ErrorNotFound) })
err := r.Listen(aid.Config.API.Host + aid.Config.API.Port) err := r.Listen("0.0.0.0" + aid.Config.API.Port)
if err != nil { if err != nil {
panic(fmt.Sprintf("Failed to listen: %v", err)) panic(fmt.Sprintf("Failed to listen: %v", err))
} }