2023-11-03 23:48:50 +00:00
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 ,
2023-12-26 03:07:18 +00:00
"exchange_code" : PostTokenExchangeCode ,
2023-11-03 23:48:50 +00:00
}
)
2023-12-09 15:35:33 +00:00
type FortniteTokenBody struct {
2023-11-03 23:48:50 +00:00
GrantType string ` form:"grant_type" binding:"required" `
2023-12-26 03:07:18 +00:00
ExchangeCode string ` form:"exchange_code" `
2023-11-03 23:48:50 +00:00
Username string ` form:"username" `
Password string ` form:"password" `
2023-12-26 03:07:18 +00:00
TokenType string ` form:"token_type" `
2023-11-03 23:48:50 +00:00
}
2023-12-09 15:35:33 +00:00
func PostFortniteToken ( c * fiber . Ctx ) error {
var body FortniteTokenBody
2023-11-03 23:48:50 +00:00
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" ) )
2023-11-03 23:48:50 +00:00
}
2023-11-20 21:20:26 +00:00
if action , ok := oauthTokenGrantTypes [ body . GrantType ] ; ok {
2023-11-03 23:48:50 +00:00
return action ( c , & body )
}
2024-02-10 00:34:12 +00:00
return c . Status ( 400 ) . JSON ( aid . ErrorBadRequest ( "Invalid Grant Type" ) )
2023-11-03 23:48:50 +00:00
}
2023-12-09 15:35:33 +00:00
func PostTokenClientCredentials ( c * fiber . Ctx , body * FortniteTokenBody ) error {
2024-01-28 19:40:45 +00:00
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-01-28 19:40:45 +00:00
}
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" ,
2023-11-03 23:48:50 +00:00
"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" ,
2023-11-03 23:48:50 +00:00
"internal_client" : true ,
2024-02-12 20:29:02 +00:00
"product_id" : "prod-fn" ,
2023-11-03 23:48:50 +00:00
"expires_in" : 3600 ,
"expires_at" : time . Now ( ) . Add ( time . Hour ) . Format ( "2006-01-02T15:04:05.999Z" ) ,
} )
}
2023-12-26 03:07:18 +00:00
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" ) )
2023-12-26 03:07:18 +00:00
}
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" ) )
2023-12-26 03:07:18 +00:00
}
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" ) )
2023-12-26 03:07:18 +00:00
}
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" ) )
2023-12-26 03:07:18 +00:00
}
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" ) )
2023-12-26 03:07:18 +00:00
}
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" ) )
2023-12-26 03:07:18 +00:00
}
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" ) )
2023-12-26 03:07:18 +00:00
}
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" ,
2023-12-26 03:07:18 +00:00
} )
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" ,
2023-12-26 03:07:18 +00:00
} )
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 {
2023-12-26 03:07:18 +00:00
"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 ,
2023-12-26 03:07:18 +00:00
"internal_client" : true ,
2024-02-10 00:34:12 +00:00
"refresh_expires" : 86200 ,
2023-12-26 03:07:18 +00:00
"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 {
2024-01-20 23:25:12 +00:00
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." ) )
2024-01-20 23:25:12 +00:00
}
2023-11-03 23:48:50 +00:00
if body . Username == "" || body . Password == "" {
2024-02-10 00:34:12 +00:00
return c . Status ( 400 ) . JSON ( aid . ErrorBadRequest ( "Username/Password is empty" ) )
2023-11-03 23:48:50 +00:00
}
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" ) )
2023-11-03 23:48:50 +00:00
}
2023-12-26 03:07:18 +00:00
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" ,
2023-12-26 03:07:18 +00:00
} )
if err != nil {
return c . Status ( fiber . StatusInternalServerError ) . JSON ( aid . ErrorInternalServer )
2023-11-03 23:48:50 +00:00
}
2023-12-19 16:47:13 +00:00
2023-12-26 03:07:18 +00:00
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" ,
2023-12-26 03:07:18 +00:00
} )
if err != nil {
return c . Status ( fiber . StatusInternalServerError ) . JSON ( aid . ErrorInternalServer )
2023-11-03 23:48:50 +00:00
}
2024-02-10 00:34:12 +00:00
return c . Status ( 200 ) . JSON ( aid . JSON {
2023-12-26 03:07:18 +00:00
"access_token" : "eg1~" + access ,
2023-11-03 23:48:50 +00:00
"account_id" : person . ID ,
"client_id" : c . IP ( ) ,
2023-12-16 22:08:37 +00:00
"client_service" : "fortnite" ,
"app" : "fortnite" ,
2023-11-03 23:48:50 +00:00
"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 ,
2023-11-03 23:48:50 +00:00
"internal_client" : true ,
2024-02-10 00:34:12 +00:00
"refresh_expires" : 86200 ,
2023-11-03 23:48:50 +00:00
"refresh_expires_at" : time . Now ( ) . Add ( time . Hour * 24 ) . Format ( "2006-01-02T15:04:05.999Z" ) ,
2023-12-26 03:07:18 +00:00
"refresh_token" : "eg1~" + refresh ,
2023-11-03 23:48:50 +00:00
"token_type" : "bearer" ,
2023-12-19 16:47:13 +00:00
"product_id" : "prod-fn" ,
"sandbox_id" : "fn" ,
2023-11-03 23:48:50 +00:00
} )
}
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" ) )
2023-12-26 03:07:18 +00:00
if err != nil {
return c . Status ( fiber . StatusForbidden ) . JSON ( aid . ErrorBadRequest ( "Invalid Access Token" ) )
}
2023-11-05 22:08:53 +00:00
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" ) )
2023-11-05 22:08:53 +00:00
}
2024-02-10 00:34:12 +00:00
return c . Status ( 200 ) . JSON ( aid . JSON {
2023-11-09 18:53:19 +00:00
"app" : "fortnite" ,
2024-01-29 21:08:05 +00:00
"token" : strings . ReplaceAll ( c . Get ( "Authorization" ) , "bearer eg1~" , "" ) ,
2023-11-09 18:53:19 +00:00
"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 ,
2023-11-09 18:53:19 +00:00
"client_id" : c . IP ( ) ,
"session_id" : "0" ,
"device_id" : "default" ,
"internal_client" : true ,
2023-12-16 22:08:37 +00:00
"client_service" : "fortnite" ,
2023-11-09 18:53:19 +00:00
"in_app_id" : person . ID ,
"account_id" : person . ID ,
"displayName" : person . DisplayName ,
2023-12-19 16:47:13 +00:00
"product_id" : "prod-fn" ,
"sandbox_id" : "fn" ,
2023-11-09 18:53:19 +00:00
} )
2023-11-05 22:08:53 +00:00
}
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" ) )
2023-12-26 03:07:18 +00:00
if err != nil {
return c . Status ( fiber . StatusForbidden ) . JSON ( aid . ErrorBadRequest ( "Invalid Access Token" ) )
}
2023-11-05 22:08:53 +00:00
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" ) )
2023-11-05 22:08:53 +00:00
}
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" ) )
2023-12-26 03:07:18 +00:00
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-26 03:07:18 +00:00
}
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 )
2023-11-05 22:08:53 +00:00
return c . Next ( )
}
2023-11-03 23:48:50 +00:00
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" ) )
2023-11-03 23:48:50 +00:00
}
2024-02-10 00:34:12 +00:00
return c . Status ( 200 ) . JSON ( aid . JSON {
2023-11-03 23:48:50 +00:00
"id" : person . ID ,
"displayName" : person . DisplayName ,
2023-11-09 18:42:28 +00:00
"externalAuths" : [ ] aid . JSON { } ,
2023-11-03 23:48:50 +00:00
} )
}
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
}
2023-11-03 23:48:50 +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" ) )
2023-11-03 23:48:50 +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
}
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" ,
} ,
} )
2023-11-03 23:48:50 +00:00
}