snow/handlers/auth.go

333 lines
9.3 KiB
Go
Raw Normal View History

package handlers
import (
"strings"
"time"
"github.com/ectrc/snow/aid"
p "github.com/ectrc/snow/person"
"github.com/gofiber/fiber/v2"
)
var (
2023-12-09 15:35:33 +00:00
oauthTokenGrantTypes = map[string]func(c *fiber.Ctx, body *FortniteTokenBody) error{
2024-01-20 01:58:57 +00:00
"client_credentials": PostTokenClientCredentials, // spams the api?? like wtf
2023-12-09 15:35:33 +00:00
"password": PostTokenPassword,
"exchange_code": PostTokenExchangeCode,
}
)
2023-12-09 15:35:33 +00:00
type FortniteTokenBody struct {
GrantType string `form:"grant_type" binding:"required"`
ExchangeCode string `form:"exchange_code"`
Username string `form:"username"`
Password string `form:"password"`
TokenType string `form:"token_type"`
}
2023-12-09 15:35:33 +00:00
func PostFortniteToken(c *fiber.Ctx) error {
var body FortniteTokenBody
if err := c.BodyParser(&body); err != nil {
2024-02-10 00:34:12 +00:00
return c.Status(400).JSON(aid.ErrorBadRequest("Invalid Request Body"))
}
if action, ok := oauthTokenGrantTypes[body.GrantType]; ok {
return action(c, &body)
}
2024-02-10 00:34:12 +00:00
return c.Status(400).JSON(aid.ErrorBadRequest("Invalid Grant Type"))
}
2023-12-09 15:35:33 +00:00
func PostTokenClientCredentials(c *fiber.Ctx, body *FortniteTokenBody) error {
if aid.Config.Fortnite.DisableClientCredentials {
2024-02-10 00:34:12 +00:00
return c.Status(400).JSON(aid.ErrorBadRequest("Client Credentials is disabled."))
}
2024-02-12 20:29:02 +00:00
clientCredentials, err := aid.JWTSign(aid.JSON{
"creation_date": time.Now().Format("2006-01-02T15:04:05.999Z"),
"clsvc": "prod-fn",
"t": "s",
"mver": false,
"clid": aid.Hash([]byte(c.IP())),
"ic": true,
"exp": 1707772234,
"iat": 1707757834,
"jti": "snow-revoke",
"pfpid": "prod-fn",
"am": "client_credentials",
})
if err != nil {
return c.Status(fiber.StatusInternalServerError).JSON(aid.ErrorInternalServer)
}
2024-02-10 00:34:12 +00:00
return c.Status(200).JSON(aid.JSON{
2024-02-12 20:29:02 +00:00
"access_token": clientCredentials,
"application_id": "fghi4567FNFBKFz3E4TROb0bmPS8h1GW",
"token_type": "bearer",
2024-01-20 01:58:57 +00:00
"client_id": aid.Hash([]byte(c.IP())),
2024-02-12 20:29:02 +00:00
"client_service": "prod-fn",
"internal_client": true,
2024-02-12 20:29:02 +00:00
"product_id": "prod-fn",
"expires_in": 3600,
"expires_at": time.Now().Add(time.Hour).Format("2006-01-02T15:04:05.999Z"),
})
}
func PostTokenExchangeCode(c *fiber.Ctx, body *FortniteTokenBody) error {
if body.ExchangeCode == "" {
2024-02-10 00:34:12 +00:00
return c.Status(400).JSON(aid.ErrorBadRequest("Exchange Code is empty"))
}
codeParts := strings.Split(body.ExchangeCode, ".")
if len(codeParts) != 2 {
2024-02-10 00:34:12 +00:00
return c.Status(400).JSON(aid.ErrorBadRequest("Invalid Exchange Code"))
}
code, failed := aid.KeyPair.DecryptAndVerifyB64(codeParts[0], codeParts[1])
if failed {
2024-02-10 00:34:12 +00:00
return c.Status(400).JSON(aid.ErrorBadRequest("Invalid Exchange Code"))
}
personParts := strings.Split(string(code), "=")
if len(personParts) != 2 {
2024-02-10 00:34:12 +00:00
return c.Status(400).JSON(aid.ErrorBadRequest("Invalid Exchange Code"))
}
personId := personParts[0]
expire, err := time.Parse("2006-01-02T15:04:05.999Z", personParts[1])
if err != nil {
2024-02-10 00:34:12 +00:00
return c.Status(400).JSON(aid.ErrorBadRequest("Invalid Exchange Code"))
}
if expire.Add(time.Hour).Before(time.Now()) {
2024-02-10 00:34:12 +00:00
return c.Status(400).JSON(aid.ErrorBadRequest("Invalid Exchange Code"))
}
person := p.Find(personId)
if person == nil {
2024-02-10 00:34:12 +00:00
return c.Status(400).JSON(aid.ErrorBadRequest("Invalid Exchange Code"))
}
access, err := aid.JWTSign(aid.JSON{
"snow_id": person.ID, // custom
"creation_date": time.Now().Format("2006-01-02T15:04:05.999Z"),
2024-02-04 01:25:44 +00:00
"am": "exchange_code",
})
if err != nil {
return c.Status(fiber.StatusInternalServerError).JSON(aid.ErrorInternalServer)
}
refresh, err := aid.JWTSign(aid.JSON{
"snow_id": person.ID,
"creation_date": time.Now().Format("2006-01-02T15:04:05.999Z"),
2024-02-04 01:25:44 +00:00
"am": "exchange_code",
})
if err != nil {
return c.Status(fiber.StatusInternalServerError).JSON(aid.ErrorInternalServer)
}
2024-02-10 00:34:12 +00:00
return c.Status(200).JSON(aid.JSON{
"access_token": "eg1~" + access,
"account_id": person.ID,
"client_id": c.IP(),
"client_service": "fortnite",
"app": "fortnite",
"device_id": "default",
"display_name": person.DisplayName,
"expires_at": time.Now().Add(time.Hour * 24).Format("2006-01-02T15:04:05.999Z"),
2024-02-10 00:34:12 +00:00
"expires_in": 86200,
"internal_client": true,
2024-02-10 00:34:12 +00:00
"refresh_expires": 86200,
"refresh_expires_at": time.Now().Add(time.Hour * 24).Format("2006-01-02T15:04:05.999Z"),
"refresh_token": "eg1~" + refresh,
"token_type": "bearer",
"product_id": "prod-fn",
"sandbox_id": "fn",
})
}
2023-12-09 15:35:33 +00:00
func PostTokenPassword(c *fiber.Ctx, body *FortniteTokenBody) error {
if aid.Config.Fortnite.Password {
2024-02-10 00:34:12 +00:00
return c.Status(400).JSON(aid.ErrorBadRequest("Username and password authentication is disabled for security reasons. Please use an exchange code given by the discord bot."))
}
if body.Username == "" || body.Password == "" {
2024-02-10 00:34:12 +00:00
return c.Status(400).JSON(aid.ErrorBadRequest("Username/Password is empty"))
}
person := p.FindByDisplay(strings.Split(body.Username, "@")[0])
if person == nil {
2024-02-10 00:34:12 +00:00
return c.Status(400).JSON(aid.ErrorBadRequest("No Account Found"))
}
access, err := aid.JWTSign(aid.JSON{
"snow_id": person.ID, // custom
"creation_date": time.Now().Format("2006-01-02T15:04:05.999Z"),
2024-02-04 01:25:44 +00:00
"am": "password",
})
if err != nil {
return c.Status(fiber.StatusInternalServerError).JSON(aid.ErrorInternalServer)
}
refresh, err := aid.JWTSign(aid.JSON{
"snow_id": person.ID,
"creation_date": time.Now().Format("2006-01-02T15:04:05.999Z"),
2024-02-04 01:25:44 +00:00
"am": "password",
})
if err != nil {
return c.Status(fiber.StatusInternalServerError).JSON(aid.ErrorInternalServer)
}
2024-02-10 00:34:12 +00:00
return c.Status(200).JSON(aid.JSON{
"access_token": "eg1~" + access,
"account_id": person.ID,
"client_id": c.IP(),
"client_service": "fortnite",
"app": "fortnite",
"device_id": "default",
"display_name": person.DisplayName,
"expires_at": time.Now().Add(time.Hour * 24).Format("2006-01-02T15:04:05.999Z"),
2024-02-10 00:34:12 +00:00
"expires_in": 86200,
"internal_client": true,
2024-02-10 00:34:12 +00:00
"refresh_expires": 86200,
"refresh_expires_at": time.Now().Add(time.Hour * 24).Format("2006-01-02T15:04:05.999Z"),
"refresh_token": "eg1~" + refresh,
"token_type": "bearer",
"product_id": "prod-fn",
"sandbox_id": "fn",
})
}
2023-12-26 03:39:12 +00:00
func GetTokenVerify(c *fiber.Ctx) error {
2024-01-29 21:08:05 +00:00
snowId, err := aid.GetSnowFromToken(c.Get("Authorization"))
if err != nil {
return c.Status(fiber.StatusForbidden).JSON(aid.ErrorBadRequest("Invalid Access Token"))
}
person := p.Find(snowId)
if person == nil {
2023-11-09 18:42:28 +00:00
return c.Status(fiber.StatusForbidden).JSON(aid.ErrorBadRequest("Invalid Access Token"))
}
2024-02-10 00:34:12 +00:00
return c.Status(200).JSON(aid.JSON{
"app": "fortnite",
2024-01-29 21:08:05 +00:00
"token": strings.ReplaceAll(c.Get("Authorization"), "bearer eg1~", ""),
"token_type": "bearer",
"expires_at": time.Now().Add(time.Hour * 24).Format("2006-01-02T15:04:05.999Z"),
2024-02-10 00:34:12 +00:00
"expires_in": 86200,
"client_id": c.IP(),
"session_id": "0",
"device_id": "default",
"internal_client": true,
"client_service": "fortnite",
"in_app_id": person.ID,
"account_id": person.ID,
"displayName": person.DisplayName,
"product_id": "prod-fn",
"sandbox_id": "fn",
})
}
2023-12-26 03:39:12 +00:00
func DeleteToken(c *fiber.Ctx) error {
2024-02-10 00:34:12 +00:00
return c.Status(200).JSON(aid.JSON{})
2023-12-26 03:39:12 +00:00
}
2023-12-19 21:48:01 +00:00
func MiddlewareFortnite(c *fiber.Ctx) error {
2024-01-29 21:08:05 +00:00
snowId, err := aid.GetSnowFromToken(c.Get("Authorization"))
if err != nil {
return c.Status(fiber.StatusForbidden).JSON(aid.ErrorBadRequest("Invalid Access Token"))
}
person := p.Find(snowId)
if person == nil {
2023-11-09 18:42:28 +00:00
return c.Status(fiber.StatusForbidden).JSON(aid.ErrorBadRequest("Invalid Access Token"))
}
2024-02-19 04:06:46 +00:00
if person.GetLatestActiveBan() != nil {
return c.Status(fiber.StatusForbidden).JSON(aid.ErrorBadRequest("Account is banned"))
}
c.Locals("person", person)
2023-12-09 15:35:33 +00:00
return c.Next()
}
2023-12-19 21:48:01 +00:00
func MiddlewareWeb(c *fiber.Ctx) error {
2024-01-29 21:08:05 +00:00
snowId, err := aid.GetSnowFromToken(c.Get("Authorization"))
if err != nil {
2024-02-19 01:49:14 +00:00
return c.Status(fiber.StatusForbidden).JSON(aid.JSON{"error":"Invalid Access Token"})
}
2023-12-09 15:35:33 +00:00
person := p.Find(snowId)
if person == nil {
2024-02-19 01:49:14 +00:00
return c.Status(fiber.StatusForbidden).JSON(aid.JSON{"error":"Invalid Access Token"})
2023-12-09 15:35:33 +00:00
}
c.Locals("person", person)
return c.Next()
}
func GetPublicAccount(c *fiber.Ctx) error {
person := p.Find(c.Params("accountId"))
if person == nil {
2024-02-10 00:34:12 +00:00
return c.Status(400).JSON(aid.ErrorBadRequest("No Account Found"))
}
2024-02-10 00:34:12 +00:00
return c.Status(200).JSON(aid.JSON{
"id": person.ID,
"displayName": person.DisplayName,
2023-11-09 18:42:28 +00:00
"externalAuths": []aid.JSON{},
})
}
2023-11-09 18:42:28 +00:00
func GetPublicAccounts(c *fiber.Ctx) error {
response := []aid.JSON{}
accountIds := c.Request().URI().QueryArgs().PeekMulti("accountId")
for _, accountIdSlice := range accountIds {
person := p.Find(string(accountIdSlice))
if person == nil {
continue
}
response = append(response, aid.JSON{
"id": person.ID,
"displayName": person.DisplayName,
"externalAuths": []aid.JSON{},
})
}
2024-02-10 00:34:12 +00:00
return c.Status(200).JSON(response)
2023-11-09 18:42:28 +00:00
}
func GetPublicAccountExternalAuths(c *fiber.Ctx) error {
person := p.Find(c.Params("accountId"))
if person == nil {
2024-02-10 00:34:12 +00:00
return c.Status(400).JSON(aid.ErrorBadRequest("No Account Found"))
}
2024-02-10 00:34:12 +00:00
return c.Status(200).JSON([]aid.JSON{})
2023-11-09 18:42:28 +00:00
}
func GetPublicAccountByDisplayName(c *fiber.Ctx) error {
person := p.FindByDisplay(c.Params("displayName"))
if person == nil {
2024-02-10 00:34:12 +00:00
return c.Status(400).JSON(aid.ErrorBadRequest("No Account Found"))
2023-11-09 18:42:28 +00:00
}
2024-02-10 00:34:12 +00:00
return c.Status(200).JSON(aid.JSON{
2023-11-09 18:42:28 +00:00
"id": person.ID,
"displayName": person.DisplayName,
"externalAuths": []aid.JSON{},
})
2024-02-10 00:34:12 +00:00
}
func GetPrivacySettings(c *fiber.Ctx) error {
return c.Status(200).JSON(aid.JSON{
"privacySettings": aid.JSON{
"playRegion": "PUBLIC",
"badges": "PUBLIC",
"languages": "PUBLIC",
},
})
}