GPCM: Friend status improvements

This commit is contained in:
mkwcat 2023-10-31 07:37:22 -04:00
parent b645caf448
commit 6df0f76855
No known key found for this signature in database
GPG Key ID: 7A505679CE9E7AA9
2 changed files with 122 additions and 83 deletions

View File

@ -19,32 +19,23 @@ func (g *GameSpySession) isFriendAdded(profileId uint32) bool {
return false
}
func sendMessageToSession(msgType string, from uint32, session *GameSpySession, msg string) {
message := common.CreateGameSpyMessage(common.GameSpyCommand{
Command: "bm",
CommandValue: msgType,
OtherValues: map[string]string{
"f": strconv.FormatUint(uint64(from), 10),
"msg": msg,
},
})
session.Conn.Write([]byte(message))
}
func sendMessageToProfileId(msgType string, from uint32, to uint32, msg string) bool {
if session, ok := sessions[to]; ok && session.LoggedIn {
sendMessageToSession(msgType, from, session, msg)
return true
}
logging.Info("GPCM", "Destination", aurora.Cyan(to), "from", aurora.Cyan(from), "is not online")
return false
}
func (g *GameSpySession) addFriend(pool *pgxpool.Pool, ctx context.Context, command common.GameSpyCommand) {
strNewProfileId := command.OtherValues["newprofileid"]
newProfileId, err := strconv.ParseUint(strNewProfileId, 10, 32)
if err != nil {
g.replyError(1536)
return
}
// Required for a friend auth
if g.User.LastName == "" {
logging.Error(g.ModuleName, "Add friend without last name")
g.replyError(1537)
return
}
if newProfileId == uint64(g.User.ProfileId) {
logging.Error(g.ModuleName, "Attempt to add self as friend")
g.replyError(1538)
return
}
@ -69,36 +60,11 @@ func (g *GameSpySession) removeFriend(pool *pgxpool.Pool, ctx context.Context, c
// TODO
}
func (g *GameSpySession) bestieMessage(pool *pgxpool.Pool, ctx context.Context, command common.GameSpyCommand) {
if command.CommandValue != "1" {
logging.Notice(g.ModuleName, "Received unknown bestie message type:", aurora.Cyan(command.CommandValue))
return
}
strToProfileId := command.OtherValues["t"]
toProfileId, err := strconv.ParseUint(strToProfileId, 10, 32)
if err != nil {
g.replyError(2304)
return
}
mutex.Lock()
defer mutex.Unlock()
if toSession, ok := sessions[uint32(toProfileId)]; ok && toSession.LoggedIn {
// TODO: Check if mutual friends
// TODO SECURITY: Sanitize message (there's a stack overflow exploit in DWC here)
sendMessageToSession("1", g.User.ProfileId, toSession, command.OtherValues["msg"])
return
}
g.replyError(2307)
}
func (g *GameSpySession) authAddFriend(pool *pgxpool.Pool, ctx context.Context, command common.GameSpyCommand) {
strFromProfileId := command.OtherValues["fromprofileid"]
fromProfileId, err := strconv.ParseUint(strFromProfileId, 10, 32)
if err != nil {
logging.Error(g.ModuleName, "Invalid profile ID string:", aurora.Cyan(strFromProfileId))
g.replyError(1793)
return
}
@ -107,11 +73,8 @@ func (g *GameSpySession) authAddFriend(pool *pgxpool.Pool, ctx context.Context,
defer mutex.Unlock()
sendMessageToProfileId("4", g.User.ProfileId, uint32(fromProfileId), "")
// Send status as well
if session, ok := sessions[uint32(fromProfileId)]; ok && session.LoggedIn && g.Status != "" {
// TODO: Check if on friend list
session.Conn.Write([]byte(g.Status))
}
// Exchange statuses now
g.exchangeFriendStatus(uint32(fromProfileId))
}
func (g *GameSpySession) setStatus(pool *pgxpool.Pool, ctx context.Context, command common.GameSpyCommand) {
@ -121,24 +84,12 @@ func (g *GameSpySession) setStatus(pool *pgxpool.Pool, ctx context.Context, comm
if !ok {
logging.Notice(g.ModuleName, "Missing statstring")
statstring = ""
} else {
if statstring == "" {
logging.Notice(g.ModuleName, "statstring: (empty)")
} else {
logging.Notice(g.ModuleName, "statstring:", aurora.Cyan(statstring))
}
}
locstring, ok := command.OtherValues["locstring"]
if !ok {
logging.Notice(g.ModuleName, "Missing locstring")
locstring = ""
} else {
if locstring == "" {
logging.Notice(g.ModuleName, "locstring: (empty)")
} else {
logging.Notice(g.ModuleName, "locstring:", aurora.Cyan(locstring))
}
}
// Get the IP address for the status msg
@ -155,29 +106,113 @@ func (g *GameSpySession) setStatus(pool *pgxpool.Pool, ctx context.Context, comm
// TODO: Check if this handles negative numbers correctly
ip := strconv.FormatInt(int64(int32(rawIP)), 10)
friendStatus := common.CreateGameSpyMessage(common.GameSpyCommand{
Command: "bm",
CommandValue: "100",
OtherValues: map[string]string{
"f": strconv.FormatUint(uint64(g.User.ProfileId), 10),
"msg": "|s|" + status + "|ss|" + statstring + "|ls|" + locstring + "|ip|" + ip + "|p|0|qm|0",
},
})
statusMsg := "|s|" + status + "|ss|" + statstring + "|ls|" + locstring + "|ip|" + ip + "|p|0|qm|0"
logging.Notice(g.ModuleName, "New status:", aurora.BrightMagenta(statusMsg))
mutex.Lock()
g.LocString = locstring
g.Status = friendStatus
g.Status = statusMsg
for _, storedPid := range g.FriendList {
if session, ok := sessions[uint32(storedPid)]; ok && session.LoggedIn {
if !session.isFriendAdded(g.User.ProfileId) {
continue
}
// TODO: Check if on friend list
session.Conn.Write([]byte(friendStatus))
}
g.sendFriendStatus(storedPid)
}
mutex.Unlock()
}
func (g *GameSpySession) bestieMessage(pool *pgxpool.Pool, ctx context.Context, command common.GameSpyCommand) {
if command.CommandValue != "1" {
logging.Notice(g.ModuleName, "Received unknown bestie message type:", aurora.Cyan(command.CommandValue))
return
}
strToProfileId := command.OtherValues["t"]
toProfileId, err := strconv.ParseUint(strToProfileId, 10, 32)
if err != nil {
logging.Error(g.ModuleName, "Invalid profile ID string:", aurora.Cyan(strToProfileId))
g.replyError(2304)
return
}
if !g.isFriendAdded(uint32(toProfileId)) {
logging.Error(g.ModuleName, "Destination", aurora.Cyan(toProfileId), "not even on own friend list")
g.replyError(2305)
return
}
mutex.Lock()
defer mutex.Unlock()
if toSession, ok := sessions[uint32(toProfileId)]; ok && toSession.LoggedIn {
if !toSession.isFriendAdded(g.User.ProfileId) {
logging.Error(g.ModuleName, "Destination", aurora.Cyan(toProfileId), "is not friends with sender")
}
// TODO SECURITY: Sanitize message (there's a stack overflow exploit in DWC here)
sendMessageToSession("1", g.User.ProfileId, toSession, command.OtherValues["msg"])
return
}
logging.Error(g.ModuleName, "Destination", aurora.Cyan(toProfileId), "is not online")
g.replyError(2307)
}
func sendMessageToSession(msgType string, from uint32, session *GameSpySession, msg string) {
message := common.CreateGameSpyMessage(common.GameSpyCommand{
Command: "bm",
CommandValue: msgType,
OtherValues: map[string]string{
"f": strconv.FormatUint(uint64(from), 10),
"msg": msg,
},
})
session.Conn.Write([]byte(message))
}
func sendMessageToProfileId(msgType string, from uint32, to uint32, msg string) bool {
if session, ok := sessions[to]; ok && session.LoggedIn {
sendMessageToSession(msgType, from, session, msg)
return true
}
logging.Info("GPCM", "Destination", aurora.Cyan(to), "from", aurora.Cyan(from), "is not online")
return false
}
func (g *GameSpySession) sendFriendStatus(profileId uint32) {
if g.isFriendAdded(profileId) {
if session, ok := sessions[profileId]; ok && session.LoggedIn && session.isFriendAdded(g.User.ProfileId) {
sendMessageToSession("100", g.User.ProfileId, session, g.Status)
}
}
}
func (g *GameSpySession) exchangeFriendStatus(profileId uint32) {
if g.isFriendAdded(profileId) {
if session, ok := sessions[profileId]; ok && session.LoggedIn && session.isFriendAdded(g.User.ProfileId) {
sendMessageToSession("100", g.User.ProfileId, session, g.Status)
sendMessageToSession("100", profileId, g, session.Status)
}
}
}
func (g *GameSpySession) sendLogoutStatus() {
// Get the IP address for the status msg
var rawIP int
for i, s := range strings.Split(strings.Split(g.Conn.RemoteAddr().String(), ":")[0], ".") {
val, err := strconv.Atoi(s)
if err != nil {
panic(err)
}
rawIP |= val << (24 - i*8)
}
// TODO: Check if this handles negative numbers correctly
ip := strconv.FormatInt(int64(int32(rawIP)), 10)
mutex.Lock()
for _, storedPid := range g.FriendList {
sendMessageToProfileId("100", g.User.ProfileId, storedPid, "|s|0|ss|Offline|ls||ip|"+ip+"|p|0|qm|0")
}
mutex.Unlock()
}

View File

@ -73,6 +73,10 @@ func StartServer() {
}
func (g *GameSpySession) closeSession() {
if g.LoggedIn {
g.sendLogoutStatus()
}
mutex.Lock()
defer mutex.Unlock()