From f803490c41bcd6a9f07240e1c7088ec41b4a8aff Mon Sep 17 00:00:00 2001 From: Eccentric Date: Mon, 29 Jan 2024 21:08:05 +0000 Subject: [PATCH] Continue to rework jabber sockets --- aid/token.go | 26 ++++++++++++++ go.mod | 1 + go.sum | 2 ++ handlers/auth.go | 56 +++--------------------------- socket/jabber.go | 88 ++++++++++++++++++++++++++++++++++++++++++++++-- socket/socket.go | 19 ++--------- 6 files changed, 120 insertions(+), 72 deletions(-) diff --git a/aid/token.go b/aid/token.go index 9454b60..a69d3a7 100644 --- a/aid/token.go +++ b/aid/token.go @@ -2,10 +2,13 @@ package aid import ( "fmt" + "regexp" "github.com/golang-jwt/jwt/v5" ) +var JWTCompile = regexp.MustCompile(`eg1~(.*)`) + func JWTSign(m JSON) (string, error) { claims := jwt.MapClaims{} @@ -18,6 +21,11 @@ func JWTSign(m JSON) (string, error) { } func JWTVerify(tokenString string) (JSON, error) { + compiled := JWTCompile.FindStringSubmatch(tokenString) + if len(compiled) > 0 { + tokenString = compiled[1] + } + token, err := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) { return []byte(Config.JWT.Secret), nil }) @@ -41,4 +49,22 @@ func JWTVerify(tokenString string) (JSON, error) { } return json, nil +} + +func GetSnowFromToken(token string) (string, error) { + claims, err := JWTVerify(token) + if err != nil { + return "", err + } + + if claims["snow_id"] == nil { + return "", fmt.Errorf("invalid access token") + } + + snowId, ok := claims["snow_id"].(string) + if !ok { + return "", fmt.Errorf("invalid access token") + } + + return snowId, nil } \ No newline at end of file diff --git a/go.mod b/go.mod index bed7af3..90c8f74 100644 --- a/go.mod +++ b/go.mod @@ -3,6 +3,7 @@ module github.com/ectrc/snow go 1.21.3 require ( + github.com/beevik/etree v1.3.0 github.com/bwmarrin/discordgo v0.27.1 github.com/goccy/go-json v0.10.2 github.com/gofiber/contrib/websocket v1.3.0 diff --git a/go.sum b/go.sum index 9c410d2..4d8a81e 100644 --- a/go.sum +++ b/go.sum @@ -1,5 +1,7 @@ github.com/andybalholm/brotli v1.0.6 h1:Yf9fFpf49Zrxb9NlQaluyE92/+X7UVHlhMNJN2sxfOI= github.com/andybalholm/brotli v1.0.6/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= +github.com/beevik/etree v1.3.0 h1:hQTc+pylzIKDb23yYprodCWWTt+ojFfUZyzU09a/hmU= +github.com/beevik/etree v1.3.0/go.mod h1:aiPf89g/1k3AShMVAzriilpcE4R/Vuor90y83zVZWFc= github.com/bwmarrin/discordgo v0.27.1 h1:ib9AIc/dom1E/fSIulrBwnez0CToJE113ZGt4HoliGY= github.com/bwmarrin/discordgo v0.27.1/go.mod h1:NJZpH+1AfhIcyQsPeuBKsUtYrRnjkyu0kIVMCHkZtRY= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= diff --git a/handlers/auth.go b/handlers/auth.go index 1d6e6bb..cf5c5f5 100644 --- a/handlers/auth.go +++ b/handlers/auth.go @@ -177,26 +177,11 @@ func PostTokenPassword(c *fiber.Ctx, body *FortniteTokenBody) error { } func GetTokenVerify(c *fiber.Ctx) error { - auth := c.Get("Authorization") - if auth == "" { - return c.Status(fiber.StatusForbidden).JSON(aid.ErrorBadRequest("Authorization Header is empty")) - } - real := strings.ReplaceAll(auth, "bearer eg1~", "") - - claims, err := aid.JWTVerify(real) + snowId, err := aid.GetSnowFromToken(c.Get("Authorization")) 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")) - } - - 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")) @@ -204,7 +189,7 @@ func GetTokenVerify(c *fiber.Ctx) error { return c.Status(fiber.StatusOK).JSON(aid.JSON{ "app": "fortnite", - "token": real, + "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"), "expires_in": 86400, @@ -226,26 +211,11 @@ func DeleteToken(c *fiber.Ctx) error { } func MiddlewareFortnite(c *fiber.Ctx) error { - auth := c.Get("Authorization") - if auth == "" { - return c.Status(fiber.StatusForbidden).JSON(aid.ErrorBadRequest("Authorization Header is empty")) - } - real := strings.ReplaceAll(auth, "bearer eg1~", "") - - claims, err := aid.JWTVerify(real) + snowId, err := aid.GetSnowFromToken(c.Get("Authorization")) 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")) - } - - 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")) @@ -256,29 +226,11 @@ func MiddlewareFortnite(c *fiber.Ctx) error { } func MiddlewareWeb(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) + snowId, err := aid.GetSnowFromToken(c.Get("Authorization")) 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")) diff --git a/socket/jabber.go b/socket/jabber.go index 64a7eb5..9fb01e8 100644 --- a/socket/jabber.go +++ b/socket/jabber.go @@ -1,12 +1,94 @@ package socket -import "github.com/ectrc/snow/aid" +import ( + "fmt" + + "github.com/beevik/etree" + "github.com/ectrc/snow/aid" + "github.com/ectrc/snow/person" + "github.com/gofiber/contrib/websocket" +) + +type JabberData struct { + JabberID string +} + +var jabberHandlers = map[string]func(*Socket[JabberData], *etree.Document) error { + "open": jabberOpenHandler, + "iq": jabberIqRootHandler, +} func HandleNewJabberSocket(identifier string) { - _, ok := JabberSockets.Get(identifier) + socket, ok := JabberSockets.Get(identifier) if !ok { return } + defer JabberSockets.Delete(identifier) - aid.Print("New jabber socket: " + identifier) + for { + _, message, failed := socket.Connection.ReadMessage() + if failed != nil { + break + } + + aid.Print(string(message)) + + parsed := etree.NewDocument() + if err := parsed.ReadFromBytes(message); err != nil { + return + } + + if handler, ok := jabberHandlers[parsed.Root().Tag]; ok { + if err := handler(socket, parsed); err != nil { + socket.Connection.WriteMessage(websocket.CloseMessage, websocket.FormatCloseMessage(websocket.CloseNormalClosure, err.Error())) + return + } + } + } +} + +func jabberOpenHandler(socket *Socket[JabberData], parsed *etree.Document) error { + socket.Connection.WriteMessage(websocket.TextMessage, []byte(``)) + socket.Connection.WriteMessage(websocket.TextMessage, []byte(``)) + + return nil +} + +func jabberIqRootHandler(socket *Socket[JabberData], parsed *etree.Document) error { + redirect := map[string]func(*Socket[JabberData], *etree.Document) error { + "set": jabberIqSetHandler, + "get": jabberIqGetHandler, + } + + if handler, ok := redirect[parsed.Root().SelectAttr("type").Value]; ok { + if err := handler(socket, parsed); err != nil { + return err + } + } + + return nil +} + +func jabberIqSetHandler(socket *Socket[JabberData], parsed *etree.Document) error { + snowId, err := aid.GetSnowFromToken(parsed.FindElement("/iq/query/password").Text()) + if err != nil { + return err + } + + person := person.Find(snowId) + if person == nil { + return fmt.Errorf("person not found") + } + + socket.Data.JabberID = snowId + "@prod.ol.epicgames.com/" + parsed.FindElement("/iq/query/resource").Text() + socket.Person = person + + socket.Connection.WriteMessage(websocket.TextMessage, []byte(``)) + return nil +} + + +func jabberIqGetHandler(socket *Socket[JabberData], parsed *etree.Document) error { + socket.Connection.WriteMessage(websocket.TextMessage, []byte(``)) + return nil } \ No newline at end of file diff --git a/socket/socket.go b/socket/socket.go index 6696f5d..989149f 100644 --- a/socket/socket.go +++ b/socket/socket.go @@ -7,34 +7,19 @@ import ( "github.com/google/uuid" ) -type SocketType int - -var ( - SocketTypeJabber SocketType = 1 - SocketTypeMatchmaking SocketType = 2 -) - -type JabberData struct { - JabberID string -} - type MatchmakerData struct { PlaylistID string Region string } -type data interface { - JabberData | MatchmakerData -} - -type Socket[T data] struct { +type Socket[T JabberData | MatchmakerData] struct { ID string Connection *websocket.Conn Data *T Person *person.Person } -func newSocket[T data](conn *websocket.Conn, data ...T) *Socket[T] { +func newSocket[T JabberData | MatchmakerData](conn *websocket.Conn, data ...T) *Socket[T] { additional := data[0] return &Socket[T]{