diff --git a/aid/config.go b/aid/config.go index 1970b24..dcff8a3 100644 --- a/aid/config.go +++ b/aid/config.go @@ -35,6 +35,7 @@ type CS struct { Build float64 Everything bool Password bool + DisableClientCredentials bool } } @@ -134,4 +135,5 @@ func LoadConfig(file []byte) { Config.Fortnite.Season = parsedSeason Config.Fortnite.Everything = cfg.Section("fortnite").Key("everything").MustBool(false) Config.Fortnite.Password = cfg.Section("fortnite").Key("password").MustBool(false) + Config.Fortnite.DisableClientCredentials = cfg.Section("fortnite").Key("disable_client_credentials").MustBool(false) } \ No newline at end of file diff --git a/default.config.ini b/default.config.ini index ad57fde..4064826 100644 --- a/default.config.ini +++ b/default.config.ini @@ -44,4 +44,10 @@ everything=true ; enable or disable the requirement of password to login to an account ; if this is set to false, you can login to any account with just the username ; if this is true you must login using an exchange code given by the bot -password=true \ No newline at end of file +password=true + +; if you recieve lots of /account/api/oauth/token requests, set this to true +; this will disable the client credentials grant type +; however this will also disable a user to get the hotfixes before login +; so xmpp and other hotfix related things will be delayed by ~1 minute +disable_client_credentials=false \ No newline at end of file diff --git a/go.mod b/go.mod index 90c8f74..eddbab1 100644 --- a/go.mod +++ b/go.mod @@ -3,10 +3,8 @@ 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 github.com/gofiber/fiber/v2 v2.51.0 github.com/golang-jwt/jwt/v5 v5.2.0 github.com/google/uuid v1.4.0 @@ -20,7 +18,6 @@ require ( require ( github.com/andybalholm/brotli v1.0.6 // indirect - github.com/fasthttp/websocket v1.5.7 // indirect github.com/gorilla/websocket v1.4.2 // indirect github.com/jackc/pgpassfile v1.0.0 // indirect github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // indirect @@ -33,7 +30,7 @@ require ( github.com/mattn/go-runewidth v0.0.15 // indirect github.com/philhofer/fwd v1.1.2 // indirect github.com/rivo/uniseg v0.4.4 // indirect - github.com/savsgio/gotils v0.0.0-20230208104028-c358bd845dee // indirect + github.com/stretchr/testify v1.8.4 // indirect github.com/tinylib/msgp v1.1.8 // indirect github.com/valyala/bytebufferpool v1.0.0 // indirect github.com/valyala/fasthttp v1.51.0 // indirect @@ -41,7 +38,6 @@ require ( github.com/vmihailenco/msgpack/v5 v5.3.5 // indirect github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect golang.org/x/crypto v0.15.0 // indirect - golang.org/x/net v0.18.0 // indirect golang.org/x/sys v0.14.0 // indirect golang.org/x/text v0.14.0 // indirect ) diff --git a/go.sum b/go.sum index 4d8a81e..8a5ab62 100644 --- a/go.sum +++ b/go.sum @@ -1,18 +1,12 @@ 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= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/fasthttp/websocket v1.5.7 h1:0a6o2OfeATvtGgoMKleURhLT6JqWPg7fYfWnH4KHau4= -github.com/fasthttp/websocket v1.5.7/go.mod h1:bC4fxSono9czeXHQUVKxsC0sNjbm7lPJR04GDFqClfU= github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU= github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= -github.com/gofiber/contrib/websocket v1.3.0 h1:XADFAGorer1VJ1bqC4UkCjqS37kwRTV0415+050NrMk= -github.com/gofiber/contrib/websocket v1.3.0/go.mod h1:xguaOzn2ZZ759LavtosEP+rcxIgBEE/rdumPINhR+Xo= github.com/gofiber/fiber/v2 v2.51.0 h1:JNACcZy5e2tGApWB2QrRpenTWn0fq0hkFm6k0C86gKQ= github.com/gofiber/fiber/v2 v2.51.0/go.mod h1:xaQRZQJGqnKOQnbQw+ltvku3/h8QxvNi8o6JiJ7Ll0U= github.com/golang-jwt/jwt/v5 v5.2.0 h1:d/ix8ftRUorsN+5eMIlF4T6J8CAt9rch3My2winC1Jw= @@ -53,8 +47,6 @@ github.com/r3labs/diff/v3 v3.0.1/go.mod h1:f1S9bourRbiM66NskseyUdo0fTmEE0qKrikYJ github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/rivo/uniseg v0.4.4 h1:8TfxU8dW6PdqD27gjM8MVNuicgxIjxpm4K7x4jp8sis= github.com/rivo/uniseg v0.4.4/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= -github.com/savsgio/gotils v0.0.0-20230208104028-c358bd845dee h1:8Iv5m6xEo1NR1AvpV+7XmhI4r39LGNzwUL4YpMuL5vk= -github.com/savsgio/gotils v0.0.0-20230208104028-c358bd845dee/go.mod h1:qwtSXrKuJh/zsFQ12yEE89xfCrGKK63Rr7ctU/uCo4g= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= @@ -85,8 +77,6 @@ golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.3.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE= -golang.org/x/net v0.18.0 h1:mIYleuAkSbHh0tCv7RvjL3F6ZVbLjq4+R7zbOn3Kokg= -golang.org/x/net v0.18.0/go.mod h1:/czyP5RqHAH4odGYxBJ1qz0+CE5WZ+2j1YgoEo8F2jQ= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= diff --git a/handlers/auth.go b/handlers/auth.go index be11e3a..1d6e6bb 100644 --- a/handlers/auth.go +++ b/handlers/auth.go @@ -40,6 +40,10 @@ func PostFortniteToken(c *fiber.Ctx) error { } func PostTokenClientCredentials(c *fiber.Ctx, body *FortniteTokenBody) error { + if aid.Config.Fortnite.DisableClientCredentials { + return c.Status(fiber.StatusBadRequest).JSON(aid.ErrorBadRequest("Client Credentials is disabled.")) + } + return c.Status(fiber.StatusOK).JSON(aid.JSON{ "access_token": "snow", "token_type": "bearer", diff --git a/handlers/friends.go b/handlers/friends.go index edeb19f..7ec9b8a 100644 --- a/handlers/friends.go +++ b/handlers/friends.go @@ -1,138 +1,26 @@ package handlers import ( - "time" - "github.com/ectrc/snow/aid" - p "github.com/ectrc/snow/person" - "github.com/ectrc/snow/storage" "github.com/gofiber/fiber/v2" ) func GetFriendList(c *fiber.Ctx) error { - person := c.Locals("person").(*p.Person) - result := map[string]aid.JSON{} - - for _, partial := range storage.Repo.GetFriendsForPerson(person.ID) { - friend := person.GetFriend(partial.ID) - if friend == nil { - continue - } - - result[partial.ID] = friend.GenerateFriendResponse() - } - - response := []aid.JSON{} - for _, friend := range result { - response = append(response, friend) - } - - return c.Status(200).JSON(response) + return c.Status(200).JSON([]aid.JSON{}) } func PostCreateFriend(c *fiber.Ctx) error { - person := c.Locals("person").(*p.Person) - friendId := c.Params("wanted") - - existing := person.GetFriend(friendId) - if existing != nil && (existing.Direction == "BOTH" || existing.Direction == "OUTGOING") { - return c.Status(400).JSON(aid.ErrorBadRequest("already active friend request")) - } - - person.AddFriend(friendId) - - socket := FindSocketForPerson(person) - socket.PresenceWriteJSON(aid.JSON{ - "payload": person.GetFriend(friendId).GenerateFriendResponse(), - "type": "com.epicgames.friends.core.apiobjects.Friend", - "timestamp": time.Now().Format(time.RFC3339), - }) - - friendSocket := FindSocketForPerson(p.Find(friendId)) - friendSocket.PresenceWriteJSON(aid.JSON{ - "payload": friendSocket.Person.GetFriend(person.ID).GenerateFriendResponse(), - "type": "com.epicgames.friends.core.apiobjects.Friend", - "timestamp": time.Now().Format(time.RFC3339), - }) - return c.SendStatus(204) } func DeleteFriend(c *fiber.Ctx) error { - person := c.Locals("person").(*p.Person) - wanted := c.Params("wanted") - - existing := person.GetFriend(wanted) - if existing == nil { - return c.Status(400).JSON(aid.ErrorBadRequest("not friends")) - } - - person.RemoveFriend(wanted) - existing.Person.RemoveFriend(person.ID) - return c.SendStatus(204) } func GetFriendListSummary(c *fiber.Ctx) error { - person := c.Locals("person").(*p.Person) - - all := map[string]*p.Friend{} - for _, partial := range storage.Repo.GetFriendsForPerson(person.ID) { - friend := person.GetFriend(partial.ID) - if friend == nil { - continue - } - - all[partial.ID] = friend - } - - result := aid.JSON{ - "friends": []aid.JSON{}, - "incoming": []aid.JSON{}, - "outgoing": []aid.JSON{}, - "settings": aid.JSON{ - "acceptInvites": "public", - }, - } - - for _, friend := range all { - switch friend.Status { - case p.FriendStatusAccepted: - result["friends"] = append(result["friends"].([]aid.JSON), friend.GenerateSummaryResponse()) - case p.FriendStatusPending: - switch friend.Direction { - case p.FriendDirectionIncoming: - result["incoming"] = append(result["incoming"].([]aid.JSON), friend.GenerateSummaryResponse()) - case p.FriendDirectionOutgoing: - result["outgoing"] = append(result["outgoing"].([]aid.JSON), friend.GenerateSummaryResponse()) - } - } - } - - return c.Status(200).JSON(result) + return c.Status(200).JSON([]aid.JSON{}) } func GetPersonSearch(c *fiber.Ctx) error { - query := c.Query("prefix") - - matches := storage.Repo.GetPersonsByPartialDisplayFromDB(query) - if matches == nil { - return c.Status(200).JSON([]aid.JSON{}) - } - - result := []aid.JSON{} - for i, match := range matches { - result = append(result, aid.JSON{ - "accountId": match.ID, - "epicMutuals": 0, - "sortPosition": i, - "matchType": "prefix", - "matches": []aid.JSON{{ - "value": match.DisplayName, - "matchType": "prefix", - }}, - }) - } - - return c.Status(200).JSON(result) + return c.Status(200).JSON([]aid.JSON{}) } \ No newline at end of file diff --git a/handlers/socket.go b/handlers/socket.go deleted file mode 100644 index a9affd8..0000000 --- a/handlers/socket.go +++ /dev/null @@ -1,130 +0,0 @@ -package handlers - -import ( - "github.com/ectrc/snow/aid" - "github.com/ectrc/snow/person" - "github.com/gofiber/contrib/websocket" - "github.com/gofiber/fiber/v2" - "github.com/google/uuid" -) - -type SocketType string -const SocketTypeXmpp SocketType = "xmpp" -const SocketTypeUnknown SocketType = "unknown" - -type Socket struct { - ID string - Connection *websocket.Conn - Person *person.Person - - Type SocketType - PresenceState *PresenceState -} - -type MessageToWrite struct { - Socket *Socket - Message []byte -} - -func (s *Socket) Write(message []byte) { - socketWriteQueue <- MessageToWrite{ - Socket: s, - Message: message, - } -} - -var ( - socketWriteQueue = make(chan MessageToWrite, 1000) - socketHandlers = map[SocketType]func(string) { - SocketTypeXmpp: presenceSocketHandle, - } - - sockets = aid.GenericSyncMap[Socket]{} -) - -func MiddlewareWebsocket(c *fiber.Ctx) error { - if !websocket.IsWebSocketUpgrade(c) { - return fiber.ErrUpgradeRequired - } - - var protocol SocketType - switch c.Get("Sec-WebSocket-Protocol") { - case "xmpp": - protocol = SocketTypeXmpp - default: - protocol = SocketTypeUnknown - } - - c.Locals("uuid", uuid.New().String()) - c.Locals("protocol", protocol) - return c.Next() -} - -func WebsocketConnection(c *websocket.Conn) { - protocol := c.Locals("protocol").(SocketType) - uuid := c.Locals("uuid").(string) - - sockets.Add(uuid, &Socket{ - ID: uuid, - Type: protocol, - Connection: c, - }) - defer func() { - socket, ok := sockets.Get(uuid) - if !ok { - return - } - socket.Connection.Close() - sockets.Delete(uuid) - aid.Print("(xmpp) connection closed", uuid) - }() - - if handle, ok := socketHandlers[protocol]; ok { - handle(uuid) - } -} - -func GetAllSockets(c *fiber.Ctx) error { - result := []any{} - - sockets.Range(func(key string, socket *Socket) bool { - result = append(result, *socket) - return true - }) - - return c.Status(200).JSON(result) -} - -func FindSocketForPerson(person *person.Person) *Socket { - var recieverSocket *Socket - sockets.Range(func(key string, value *Socket) bool { - if value.Person == nil { - return true - } - - if value.Person.ID == person.ID { - recieverSocket = value - return false - } - - return true - }) - - return recieverSocket -} - -func init() { - go func() { - for { - if aid.Config != nil { - break - } - } - - for { - message := <-socketWriteQueue - aid.Print("(socket) writing message to", message.Socket.ID, string(message.Message)) - message.Socket.Connection.WriteMessage(websocket.TextMessage, message.Message) - } - }() -} \ No newline at end of file diff --git a/handlers/xmpp.go b/handlers/xmpp.go deleted file mode 100644 index 5e2a29c..0000000 --- a/handlers/xmpp.go +++ /dev/null @@ -1,355 +0,0 @@ -package handlers - -import ( - "fmt" - "strings" - "time" - - "github.com/beevik/etree" - "github.com/ectrc/snow/aid" - p "github.com/ectrc/snow/person" - "github.com/ectrc/snow/storage" - "github.com/goccy/go-json" - "github.com/google/uuid" -) - -type PresenceStatus struct { - Status string `json:"Status"` - IsPlaying bool `json:"bIsPlaying"` - IsJoinable bool `json:"bIsJoinable"` - HasVoiceSupport bool `json:"bHasVoiceSupport"` - SessionId string `json:"SessionId"` - Properties map[string]struct { - SourceId string `json:"sourceId"` - SourceDisplayName string `json:"sourceDisplayName"` - SourcePlatform string `json:"sourcePlatform"` - PartyId string `json:"partyId"` - PartyTypeId int `json:"partyTypeId"` - Key string `json:"key"` - AppId string `json:"appId"` - BuildId string `json:"buildId"` - PartyFlags int `json:"partyFlags"` - NotAcceptingReason int `json:"notAcceptingReason"` - Pc int `json:"pc"` - } `json:"Properties"` -} - -type PresenceState struct { - JID string - Open bool - RawStatus string - ParsedStatus PresenceStatus -} - -var ( - socketXmppMessageHandlers = map[string]func(*Socket, *etree.Document) error { - "open": presenceSocketOpenEvent, - "iq": presenceSocketIqRootEvent, - "message": presenceSocketMessageEvent, - "presence": presenceSocketPresenceEvent, - "close": presenceSocketCloseEvent, - } -) - -func presenceSocketHandle(id string) { - socket, ok := sockets.Get(id) - if !ok { - return - } - - socket.Type = SocketTypeXmpp - socket.PresenceState = &PresenceState{} - - for { - _, message, err := socket.Connection.ReadMessage() - if err != nil { - break - } - - parsed := etree.NewDocument() - if err := parsed.ReadFromBytes(message); err != nil { - return - } - - if handler, ok := socketXmppMessageHandlers[parsed.Root().Tag]; ok { - if err := handler(socket, parsed); err != nil { - return - } - } - } - - for _, partial := range storage.Repo.GetFriendsForPerson(socket.Person.ID) { - friend := socket.Person.GetFriend(partial.ID) - if friend == nil { - continue - } - - friendSocket := FindSocketForPerson(friend.Person) - if friendSocket == nil { - continue - } - - friendDocument := etree.NewDocument() - friendPresence := friendDocument.CreateElement("presence") - friendPresence.Attr = append(friendPresence.Attr, etree.Attr{Key: "from", Value: socket.PresenceState.JID}) - friendPresence.Attr = append(friendPresence.Attr, etree.Attr{Key: "to", Value: friendSocket.PresenceState.JID}) - friendPresence.Attr = append(friendPresence.Attr, etree.Attr{Key: "type", Value: "available"}) - friendPresence.Attr = append(friendPresence.Attr, etree.Attr{Key: "xmlns", Value: "jabber:client"}) - friendPresence.CreateElement("status").SetText(aid.JSONStringify(aid.JSON{})) - friendPresence.CreateElement("show").SetText("away") - - friendSocket.PresenceWrite(friendDocument) - } - - for _, party := range socket.PresenceState.ParsedStatus.Properties { - if party.PartyId == "" { - continue - } - - sockets.Range(func(_ string, recieverSocket *Socket) bool { - if recieverSocket.Type != SocketTypeXmpp || recieverSocket.Person == nil { - return true - } - - document := etree.NewDocument() - message := document.CreateElement("message") - message.Attr = append(message.Attr, etree.Attr{Key: "id", Value: uuid.New().String()}) - message.Attr = append(message.Attr, etree.Attr{Key: "from", Value: socket.PresenceState.JID}) - message.Attr = append(message.Attr, etree.Attr{Key: "to", Value: recieverSocket.PresenceState.JID}) - message.Attr = append(message.Attr, etree.Attr{Key: "xmlns", Value: "jabber:client"}) - message.CreateElement("body").SetText(aid.JSONStringify(aid.JSON{ - "type": "com.epicgames.party.memberexited", - "timestamp": time.Now().Format(time.RFC3339), - "payload": aid.JSON{ - "memberId": socket.Person.ID, - "partyId": party.PartyId, - "wasKicked": false, - }, - })) - - recieverSocket.PresenceWrite(document) - return true - }) - } -} - -func presenceSocketOpenEvent(socket *Socket, tree *etree.Document) error { - document := etree.NewDocument() - open := document.CreateElement("open") - open.Attr = append(open.Attr, etree.Attr{Key: "xmlns", Value: "urn:ietf:params:xml:ns:xmpp-framing"}) - open.Attr = append(open.Attr, etree.Attr{Key: "from", Value: "prod.ol.epicgames.com"}) - open.Attr = append(open.Attr, etree.Attr{Key: "version", Value: "1.0"}) - open.Attr = append(open.Attr, etree.Attr{Key: "id", Value: socket.ID}) - - socket.PresenceWrite(document) - return nil -} - -func presenceSocketCloseEvent(socket *Socket, tree *etree.Document) error { - return fmt.Errorf("safe exit") -} - -func presenceSocketIqRootEvent(socket *Socket, tree *etree.Document) error { - redirect := map[string]func(*Socket, *etree.Document) error{ - "set": presenceSocketIqSetEvent, - "get": presenceSocketIqGetEvent, - } - - if handler, ok := redirect[tree.Root().SelectAttr("type").Value]; ok { - if err := handler(socket, tree); err != nil { - return err - } - } - - return nil -} - -func presenceSocketIqSetEvent(socket *Socket, tree *etree.Document) error { - token := tree.Root().SelectElement("query").SelectElement("password") - if token == nil || token.Text() == "" { - return fmt.Errorf("invalid token") - } - real := strings.ReplaceAll(token.Text(), "eg1~", "") - - claims, err := aid.JWTVerify(real) - if err != nil { - return fmt.Errorf("invalid token") - } - - if claims["snow_id"] == nil { - return fmt.Errorf("invalid token") - } - - snowId, ok := claims["snow_id"].(string) - if !ok { - return fmt.Errorf("invalid token") - } - - person := p.Find(snowId) - if person == nil { - return fmt.Errorf("invalid token") - } - - socket.Person = person - socket.PresenceState.JID = person.ID + "@prod.ol.epicgames.com/" + tree.Root().SelectElement("query").SelectElement("resource").Text() - - document := etree.NewDocument() - iq := document.CreateElement("iq") - iq.Attr = append(iq.Attr, etree.Attr{Key: "type", Value: "result"}) - iq.Attr = append(iq.Attr, etree.Attr{Key: "id", Value: "_xmpp_auth1"}) - iq.Attr = append(iq.Attr, etree.Attr{Key: "from", Value: "prod.ol.epicgames.com"}) - - socket.PresenceWrite(document) - socket.PresenceWriteStatus() - return nil -} - -func presenceSocketIqGetEvent(socket *Socket, tree *etree.Document) error { - document := etree.NewDocument() - iq := document.CreateElement("iq") - iq.Attr = append(iq.Attr, etree.Attr{Key: "type", Value: "result"}) - iq.Attr = append(iq.Attr, etree.Attr{Key: "id", Value: tree.Root().SelectAttr("id").Value}) - iq.Attr = append(iq.Attr, etree.Attr{Key: "to", Value: tree.Root().SelectAttr("from").Value}) - iq.Attr = append(iq.Attr, etree.Attr{Key: "from", Value: "prod.ol.epicgames.com"}) - ping := iq.CreateElement("ping") - ping.Attr = append(ping.Attr, etree.Attr{Key: "xmlns", Value: "urn:xmpp:ping"}) - - socket.PresenceWrite(document) - return nil -} - -func presenceSocketMessageEvent(socket *Socket, tree *etree.Document) error { - reciever := p.Find(strings.Split(tree.Root().SelectAttr("to").Value, "@")[0]) - if reciever == nil { - return nil - } - - recieverSocket := FindSocketForPerson(reciever) - if recieverSocket == nil { - return nil - } - - document := etree.NewDocument() - message := document.CreateElement("message") - message.Attr = append(message.Attr, etree.Attr{Key: "id", Value: tree.Root().SelectAttr("id").Value}) - message.Attr = append(message.Attr, etree.Attr{Key: "from", Value: socket.PresenceState.JID}) - message.Attr = append(message.Attr, etree.Attr{Key: "to", Value: recieverSocket.PresenceState.JID}) - message.Attr = append(message.Attr, etree.Attr{Key: "xmlns", Value: "jabber:client"}) - message.CreateElement("body").SetText(tree.Root().SelectElement("body").Text()) - - recieverSocket.PresenceWrite(document) - return nil -} - -func presenceSocketPresenceEvent(socket *Socket, tree *etree.Document) error { - status := tree.Root().SelectElement("status") - if status == nil { - return nil - } - - socket.PresenceState.RawStatus = status.Text() - json.NewDecoder(strings.NewReader(status.Text())).Decode(&socket.PresenceState.ParsedStatus) - socket.PresenceWriteStatus() - - return nil -} - -func (s *Socket) PresenceWrite(message *etree.Document) { - bytes, err := message.WriteToBytes() - if err != nil { - return - } - - s.Write(bytes) -} - -func (s *Socket) PresenceWriteStatus() { - for _, partial := range storage.Repo.GetFriendsForPerson(s.Person.ID) { - friend := s.Person.GetFriend(partial.ID) - if friend == nil { - continue - } - - friendSocket := FindSocketForPerson(friend.Person) - if friendSocket == nil { - continue - } - - friendDocument := etree.NewDocument() - friendPresence := friendDocument.CreateElement("presence") - friendPresence.Attr = append(friendPresence.Attr, etree.Attr{Key: "from", Value: s.PresenceState.JID}) - friendPresence.Attr = append(friendPresence.Attr, etree.Attr{Key: "to", Value: friendSocket.PresenceState.JID}) - friendPresence.Attr = append(friendPresence.Attr, etree.Attr{Key: "type", Value: "available"}) - friendPresence.Attr = append(friendPresence.Attr, etree.Attr{Key: "xmlns", Value: "jabber:client"}) - friendPresence.CreateElement("status").SetText(s.PresenceState.RawStatus) - friendSocket.PresenceWrite(friendDocument) - - document := etree.NewDocument() - presence := document.CreateElement("presence") - presence.Attr = append(presence.Attr, etree.Attr{Key: "from", Value: friendSocket.PresenceState.JID}) - presence.Attr = append(presence.Attr, etree.Attr{Key: "to", Value: s.PresenceState.JID}) - presence.Attr = append(presence.Attr, etree.Attr{Key: "type", Value: "available"}) - presence.Attr = append(presence.Attr, etree.Attr{Key: "xmlns", Value: "jabber:client"}) - presence.CreateElement("status").SetText(friendSocket.PresenceState.RawStatus) - s.PresenceWrite(document) - } -} - -func (s *Socket) PresenceWriteJSON(body aid.JSON) { - aid.PrintJSON(body) - - document := etree.NewDocument() - message := document.CreateElement("message") - message.Attr = append(message.Attr, etree.Attr{Key: "id", Value: uuid.New().String()}) - message.Attr = append(message.Attr, etree.Attr{Key: "from", Value: "xmpp-admin@prod.ol.epicgames.com"}) - message.Attr = append(message.Attr, etree.Attr{Key: "to", Value: s.PresenceState.JID}) - message.Attr = append(message.Attr, etree.Attr{Key: "xmlns", Value: "jabber:client"}) - message.CreateElement("body").SetText(aid.JSONStringify(body)) - s.PresenceWrite(document) -} - -func (s *Socket) PresenceWriteGiftReceived() { - document := etree.NewDocument() - message := document.CreateElement("message") - message.Attr = append(message.Attr, etree.Attr{Key: "id", Value: uuid.New().String()}) - message.Attr = append(message.Attr, etree.Attr{Key: "from", Value: "prod.ol.epicgames.com"}) - message.Attr = append(message.Attr, etree.Attr{Key: "to", Value: s.PresenceState.JID}) - message.Attr = append(message.Attr, etree.Attr{Key: "xmlns", Value: "jabber:client"}) - message.CreateElement("body").SetText(aid.JSONStringify(aid.JSON{ - "type": "com.epicgames.gift.received", - "timestamp": time.Now().Format(time.RFC3339), - "payload": aid.JSON{}, - })) - s.PresenceWrite(document) -} - -func init() { - go func() { - for { - if aid.Config != nil { - break - } - } - - timer := time.NewTicker(30 * time.Second) - for { - <-timer.C - sockets.Range(func(key string, socket *Socket) bool { - if socket.Type != SocketTypeXmpp || socket.Person == nil { - return true - } - - document := etree.NewDocument() - iq := document.CreateElement("iq") - iq.Attr = append(iq.Attr, etree.Attr{Key: "id", Value: "_xmpp_auth1"}) - iq.Attr = append(iq.Attr, etree.Attr{Key: "type", Value: "get"}) - iq.Attr = append(iq.Attr, etree.Attr{Key: "from", Value: "prod.ol.epicgames.com"}) - ping := iq.CreateElement("ping") - ping.Attr = append(iq.Attr, etree.Attr{Key: "xmlns", Value: "urn:xmpp:ping"}) - - socket.PresenceWrite(document) - return true - }) - } - }() -} \ No newline at end of file diff --git a/main.go b/main.go index 124c525..83a3ebc 100644 --- a/main.go +++ b/main.go @@ -12,7 +12,6 @@ import ( "github.com/ectrc/snow/storage" "github.com/goccy/go-json" - "github.com/gofiber/contrib/websocket" "github.com/gofiber/fiber/v2" ) @@ -69,7 +68,7 @@ func main() { r.Post("/api/v1/assets/Fortnite/:versionId/:assetName", handlers.PostAssets) r.Get("//", func(c *fiber.Ctx) error { return c.Redirect("/socket") }) - r.Get("/socket", handlers.MiddlewareWebsocket, websocket.New(handlers.WebsocketConnection)) + // r.Get("/socket", handlers.MiddlewareWebsocket, websocket.New(handlers.WebsocketConnection)) account := r.Group("/account/api") account.Get("/public/account", handlers.GetPublicAccounts) @@ -131,7 +130,6 @@ func main() { snow := r.Group("/snow") snow.Get("/cosmetics", handlers.GetPreloadedCosmetics) snow.Get("/image/:playlist", handlers.GetPlaylistImage) - snow.Get("/sockets", handlers.GetAllSockets) discord := snow.Group("/discord") discord.Get("/", handlers.GetDiscordOAuthURL) diff --git a/person/friend.go b/person/friend.go deleted file mode 100644 index c053cd6..0000000 --- a/person/friend.go +++ /dev/null @@ -1,45 +0,0 @@ -package person - -import ( - "time" - - "github.com/ectrc/snow/aid" -) - -type FriendDirection string -var FriendDirectionBoth FriendDirection = "BOTH" -var FriendDirectionIncoming FriendDirection = "INCOMING" -var FriendDirectionOutgoing FriendDirection = "OUTGOING" - -type FriendStatus string -var FriendStatusPending FriendStatus = "PENDING" -var FriendStatusAccepted FriendStatus = "ACCEPTED" -var FriendStatusDeleted FriendStatus = "DELETED" - -type Friend struct { - Person *Person - Status FriendStatus - Direction FriendDirection -} - -func (f *Friend) GenerateSummaryResponse() aid.JSON { - return aid.JSON{ - "accountId": f.Person.ID, - "groups": []string{}, - "mutual": 0, - "alias": "", - "note": "", - "favorite": false, - "created": time.Now().Add(-time.Hour * 24 * 7).Format(time.RFC3339), - } -} - -func (f *Friend) GenerateFriendResponse() aid.JSON { - return aid.JSON{ - "accountId": f.Person.ID, - "status": f.Status, - "direction": f.Direction, - "created": time.Now().Add(-time.Hour * 24 * 7).Format(time.RFC3339), - "favourite": false, - } -} \ No newline at end of file diff --git a/person/person.go b/person/person.go index 03a822c..da4ec6e 100644 --- a/person/person.go +++ b/person/person.go @@ -10,7 +10,6 @@ type Person struct { DisplayName string Permissions []string IsBanned bool - Friends []string AthenaProfile *Profile CommonCoreProfile *Profile CommonPublicProfile *Profile @@ -26,7 +25,6 @@ func NewPerson() *Person { DisplayName: uuid.New().String(), Permissions: []string{}, IsBanned: false, - Friends: []string{}, AthenaProfile: NewProfile("athena"), CommonCoreProfile: NewProfile("common_core"), CommonPublicProfile: NewProfile("common_public"), @@ -42,7 +40,6 @@ func NewPersonWithCustomID(id string) *Person { DisplayName: uuid.New().String(), Permissions: []string{}, IsBanned: false, - Friends: []string{}, AthenaProfile: NewProfile("athena"), CommonCoreProfile: NewProfile("common_core"), CommonPublicProfile: NewProfile("common_public"), @@ -151,7 +148,6 @@ func findHelper(databasePerson *storage.DB_Person) *Person { DisplayName: databasePerson.DisplayName, Permissions: databasePerson.Permissions, IsBanned: databasePerson.IsBanned, - Friends: databasePerson.Friends, AthenaProfile: athenaProfile, CommonCoreProfile: commonCoreProfile, CommonPublicProfile: commonPublicProfile, @@ -251,71 +247,12 @@ func (p *Person) HasPermission(permission Permission) bool { return false } -func (p *Person) AddFriend(friendId string) { - p.Friends = append(p.Friends, friendId) - p.Save() -} - -func (p *Person) RemoveFriend(friendId string) { - for i, friend := range p.Friends { - if friend == friendId { - p.Friends = append(p.Friends[:i], p.Friends[i+1:]...) - break - } - } - p.Save() -} - -func (p *Person) GetFriend(friendId string) *Friend { - friend := Find(friendId) - if friend == nil { - return nil - } - - if p.IsFriendInFriendList(friendId) { - if friend.IsFriendInFriendList(p.ID) { - return &Friend{ - Person: friend, - Status: FriendStatusAccepted, - Direction: FriendDirectionBoth, - } - } - - return &Friend{ - Person: friend, - Status: FriendStatusPending, - Direction: FriendDirectionOutgoing, - } - } - - if friend.IsFriendInFriendList(p.ID) { - return &Friend{ - Person: friend, - Status: FriendStatusPending, - Direction: FriendDirectionIncoming, - } - } - - return nil -} - -func (p *Person) IsFriendInFriendList(friendId string) bool { - for _, idA := range p.Friends { - if idA == friendId { - return true - } - } - - return false -} - func (p *Person) ToDatabase() *storage.DB_Person { dbPerson := storage.DB_Person{ ID: p.ID, DisplayName: p.DisplayName, Permissions: p.Permissions, IsBanned: p.IsBanned, - Friends: p.Friends, Profiles: []storage.DB_Profile{}, Stats: []storage.DB_SeasonStat{}, Discord: storage.DB_DiscordPerson{}, diff --git a/storage/postgres.go b/storage/postgres.go index ca81fdf..dd30de3 100644 --- a/storage/postgres.go +++ b/storage/postgres.go @@ -57,7 +57,7 @@ func (s *PostgresStorage) GetPerson(personId string) *DB_Person { Model(&DB_Person{}). Preload("Profiles"). Preload("Profiles.Loadouts"). - Preload("Profiles.Items.Variants"). + // Preload("Profiles.Items.Variants"). Preload("Profiles.Gifts.Loot"). Preload("Profiles.Attributes"). Preload("Profiles.Items"). @@ -80,7 +80,7 @@ func (s *PostgresStorage) GetPersonByDisplay(displayName string) *DB_Person { Model(&DB_Person{}). Preload("Profiles"). Preload("Profiles.Loadouts"). - Preload("Profiles.Items.Variants"). + // Preload("Profiles.Items.Variants"). Preload("Profiles.Gifts.Loot"). Preload("Profiles.Attributes"). Preload("Profiles.Items"). @@ -103,7 +103,7 @@ func (s *PostgresStorage) GetPersonsByPartialDisplay(displayName string) []*DB_P Model(&DB_Person{}). Preload("Profiles"). Preload("Profiles.Loadouts"). - Preload("Profiles.Items.Variants"). + // Preload("Profiles.Items.Variants"). Preload("Profiles.Gifts.Loot"). Preload("Profiles.Attributes"). Preload("Profiles.Items"). @@ -138,7 +138,7 @@ func (s *PostgresStorage) GetAllPersons() []*DB_Person { Model(&DB_Person{}). Preload("Profiles"). Preload("Profiles.Loadouts"). - Preload("Profiles.Items.Variants"). + // Preload("Profiles.Items.Variants"). Preload("Profiles.Gifts.Loot"). Preload("Profiles.Attributes"). Preload("Profiles.Items"). @@ -156,42 +156,6 @@ func (s *PostgresStorage) GetPersonsCount() int { return int(count) } -func (s *PostgresStorage) GetFriendsForPerson(personId string) []*DB_Person { - person := s.GetPerson(personId) - - var mine []*DB_Person - s.Postgres. - Model(&DB_Person{}). - Preload("Profiles"). - Preload("Profiles.Loadouts"). - Preload("Profiles.Items.Variants"). - Preload("Profiles.Gifts.Loot"). - Preload("Profiles.Attributes"). - Preload("Profiles.Items"). - Preload("Profiles.Gifts"). - Preload("Profiles.Quests"). - Preload("Discord"). - Where("id IN (?)", person.Friends). - Find(&mine) - - var theirs []*DB_Person - s.Postgres. - Model(&DB_Person{}). - Preload("Profiles"). - Preload("Profiles.Loadouts"). - Preload("Profiles.Items.Variants"). - Preload("Profiles.Gifts.Loot"). - Preload("Profiles.Attributes"). - Preload("Profiles.Items"). - Preload("Profiles.Gifts"). - Preload("Profiles.Quests"). - Preload("Discord"). - Where("? = ?", person.ID, gorm.Expr("ANY(friends)")). - Find(&theirs) - - return append(mine, theirs...) -} - func (s *PostgresStorage) TotalVBucks() int { var total int64 s.Postgres.Model(&DB_Item{}).Select("sum(quantity)").Where("template_id = ?", "Currency:MtxPurchased").Find(&total) @@ -207,7 +171,7 @@ func (s *PostgresStorage) DeletePerson(personId string) { Model(&DB_Person{}). Preload("Profiles"). Preload("Profiles.Loadouts"). - Preload("Profiles.Items.Variants"). + // Preload("Profiles.Items.Variants"). Preload("Profiles.Gifts.Loot"). Preload("Profiles.Attributes"). Preload("Profiles.Items"). diff --git a/storage/storage.go b/storage/storage.go index 35845f9..4fe808a 100644 --- a/storage/storage.go +++ b/storage/storage.go @@ -19,8 +19,6 @@ type Storage interface { SavePerson(person *DB_Person) DeletePerson(personId string) - GetFriendsForPerson(personId string) []*DB_Person - SaveProfile(profile *DB_Profile) DeleteProfile(profileId string) @@ -108,10 +106,6 @@ func (r *Repository) GetPersonsCount() int { return r.Storage.GetPersonsCount() } -func (r *Repository) GetFriendsForPerson(personId string) []*DB_Person { - return r.Storage.GetFriendsForPerson(personId) -} - func (r *Repository) SavePerson(person *DB_Person) { r.Storage.SavePerson(person) } diff --git a/storage/tables.go b/storage/tables.go index 5a36229..4793e32 100644 --- a/storage/tables.go +++ b/storage/tables.go @@ -13,7 +13,6 @@ type DB_Person struct { IsBanned bool Profiles []DB_Profile `gorm:"foreignkey:PersonID"` Stats []DB_SeasonStat `gorm:"foreignkey:PersonID"` - Friends pq.StringArray `gorm:"type:text[]"` Discord DB_DiscordPerson `gorm:"foreignkey:PersonID"` }