Finished basic XMPP functions!

This commit is contained in:
Eccentric 2024-01-21 00:18:40 +00:00
parent d9e4aa0b2d
commit 586dcc22f9
4 changed files with 204 additions and 15 deletions

1
go.mod
View File

@ -3,6 +3,7 @@ module github.com/ectrc/snow
go 1.21.3 go 1.21.3
require ( require (
github.com/beevik/etree v1.3.0
github.com/bwmarrin/discordgo v0.27.1 github.com/bwmarrin/discordgo v0.27.1
github.com/goccy/go-json v0.10.2 github.com/goccy/go-json v0.10.2
github.com/gofiber/contrib/websocket v1.3.0 github.com/gofiber/contrib/websocket v1.3.0

2
go.sum
View File

@ -1,5 +1,7 @@
github.com/andybalholm/brotli v1.0.6 h1:Yf9fFpf49Zrxb9NlQaluyE92/+X7UVHlhMNJN2sxfOI= github.com/andybalholm/brotli v1.0.6 h1:Yf9fFpf49Zrxb9NlQaluyE92/+X7UVHlhMNJN2sxfOI=
github.com/andybalholm/brotli v1.0.6/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= 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 h1:ib9AIc/dom1E/fSIulrBwnez0CToJE113ZGt4HoliGY=
github.com/bwmarrin/discordgo v0.27.1/go.mod h1:NJZpH+1AfhIcyQsPeuBKsUtYrRnjkyu0kIVMCHkZtRY= 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.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=

View File

@ -1,6 +1,7 @@
package handlers package handlers
import ( import (
"github.com/beevik/etree"
"github.com/ectrc/snow/aid" "github.com/ectrc/snow/aid"
"github.com/ectrc/snow/person" "github.com/ectrc/snow/person"
"github.com/gofiber/contrib/websocket" "github.com/gofiber/contrib/websocket"
@ -16,13 +17,39 @@ var (
type Socket struct { type Socket struct {
ID string ID string
JID string
Type SocketType Type SocketType
Connection *websocket.Conn Connection *websocket.Conn
Person *person.Person Person *person.Person
} }
type MessageToWrite struct {
Socket *Socket
Message []byte
}
func (s *Socket) Write(message []byte) {
socketWriteQueue <- MessageToWrite{
Socket: s,
Message: message,
}
}
func (s *Socket) WriteTree(message *etree.Document) {
bytes, err := message.WriteToBytes()
if err != nil {
return
}
socketWriteQueue <- MessageToWrite{
Socket: s,
Message: bytes,
}
}
var ( var (
handles = map[SocketType]func(string) { socketWriteQueue = make(chan MessageToWrite, 1000)
socketHandlers = map[SocketType]func(string) {
SocketTypeXmpp: handlePresenceSocket, SocketTypeXmpp: handlePresenceSocket,
} }
@ -56,19 +83,35 @@ func WebsocketConnection(c *websocket.Conn) {
Type: protocol, Type: protocol,
Connection: c, Connection: c,
}) })
defer close(uuid) 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 := handles[protocol]; ok { if handle, ok := socketHandlers[protocol]; ok {
handle(uuid) handle(uuid)
} }
} }
func close(id string) { func init() {
socket, ok := sockets.Get(id) go func() {
if !ok { for {
return if aid.Config != nil {
} break
socket.Connection.Close() }
sockets.Delete(id) }
aid.Print("(xmpp) connection closed", id)
aid.Print("(socket) write queue started")
for {
message := <-socketWriteQueue
aid.Print("(socket) message sent", message.Socket.ID, string(message.Message))
message.Socket.Connection.WriteMessage(websocket.TextMessage, message.Message)
}
}()
} }

View File

@ -1,6 +1,22 @@
package handlers package handlers
import "github.com/ectrc/snow/aid" import (
"fmt"
"strings"
"time"
"github.com/beevik/etree"
"github.com/ectrc/snow/aid"
p "github.com/ectrc/snow/person"
)
var (
socketXmppMessageHandlers = map[string]func(*Socket, *etree.Document) error {
"open": presenceSocketOpenEvent,
"iq": presenceSocketIqRootEvent,
"close": presenceSocketCloseEvent,
}
)
func handlePresenceSocket(id string) { func handlePresenceSocket(id string) {
aid.Print("(xmpp) connection opened", id) aid.Print("(xmpp) connection opened", id)
@ -10,11 +26,138 @@ func handlePresenceSocket(id string) {
} }
for { for {
_, msg, err := socket.Connection.ReadMessage() _, message, err := socket.Connection.ReadMessage()
if err != nil { if err != nil {
aid.Print("(xmpp) error reading message", err)
break break
} }
aid.Print("(xmpp) message received", string(msg))
parsed := etree.NewDocument()
if err := parsed.ReadFromBytes(message); err != nil {
return
}
aid.Print("(xmpp) message received", string(message))
if handler, ok := socketXmppMessageHandlers[parsed.Root().Tag]; ok {
if err := handler(socket, parsed); err != nil {
aid.Print("(xmpp) connection closed", id, err.Error())
return
}
}
} }
} }
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.WriteTree(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.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.WriteTree(document)
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.WriteTree(document)
return nil
}
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.WriteTree(document)
return true
})
}
}()
}