mirror of
https://github.com/WiiLink24/wfc-server.git
synced 2026-03-21 17:44:58 -05:00
GPCM/GPSP: Hide certain profile information
This commit is contained in:
parent
8ea725a6b3
commit
67996c08b9
|
|
@ -405,6 +405,9 @@ func (g *GameSpySession) replyError(err GPError) {
|
|||
msg := err.GetMessage()
|
||||
// logging.Info(g.ModuleName, "Sending error message:", msg)
|
||||
g.Conn.Write([]byte(msg))
|
||||
if err.Fatal {
|
||||
g.Conn.Close()
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
|
|
@ -416,4 +419,7 @@ func (g *GameSpySession) replyError(err GPError) {
|
|||
msg := err.GetMessageTranslate(g.GameName, g.Region, g.Language, g.ConsoleFriendCode, deviceId)
|
||||
// logging.Info(g.ModuleName, "Sending error message:", msg)
|
||||
g.Conn.Write([]byte(msg))
|
||||
if err.Fatal {
|
||||
g.Conn.Close()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -66,9 +66,12 @@ func (g *GameSpySession) getAuthorizedFriendIndex(profileId uint32) int {
|
|||
}
|
||||
|
||||
const (
|
||||
addFriendMessage = "\r\n\r\n|signed|00000000000000000000000000000000"
|
||||
addFriendMessage = "\r\n\r\n|signed|00000000000000000000000000000000"
|
||||
|
||||
// TODO: Check if this is needed for any game, it sends via bm 1
|
||||
authFriendMessage = "I have authorized your request to add me to your list"
|
||||
logOutMessage = "|s|0|ss|Offline|ls||ip|0|p|0|qm|0"
|
||||
|
||||
logOutMessage = "|s|0|ss|Offline|ls||ip|0|p|0|qm|0"
|
||||
)
|
||||
|
||||
func (g *GameSpySession) addFriend(command common.GameSpyCommand) {
|
||||
|
|
@ -136,57 +139,21 @@ func (g *GameSpySession) addFriend(command common.GameSpyCommand) {
|
|||
newSession.AuthFriendList = append(newSession.AuthFriendList, g.User.ProfileId)
|
||||
|
||||
// Send friend auth message
|
||||
g.sendFriendAuthMessage(uint32(newProfileId))
|
||||
newSession.sendFriendAuthMessage(g.User.ProfileId)
|
||||
sendMessageToSessionBuffer("4", newSession.User.ProfileId, g, "")
|
||||
sendMessageToSession("4", g.User.ProfileId, newSession, "")
|
||||
|
||||
g.exchangeFriendStatus(uint32(newProfileId))
|
||||
}
|
||||
|
||||
func (g *GameSpySession) sendFriendAuthMessage(newProfileId uint32) {
|
||||
// Send both messages in one packet
|
||||
message := common.CreateGameSpyMessage(common.GameSpyCommand{
|
||||
Command: "bm",
|
||||
CommandValue: "2",
|
||||
OtherValues: map[string]string{
|
||||
"f": strconv.FormatUint(uint64(newProfileId), 10),
|
||||
"msg": addFriendMessage,
|
||||
},
|
||||
})
|
||||
message += common.CreateGameSpyMessage(common.GameSpyCommand{
|
||||
Command: "bm",
|
||||
CommandValue: "4",
|
||||
OtherValues: map[string]string{
|
||||
"f": strconv.FormatUint(uint64(newProfileId), 10),
|
||||
"msg": "",
|
||||
},
|
||||
})
|
||||
|
||||
g.Conn.Write([]byte(message))
|
||||
}
|
||||
|
||||
func (g *GameSpySession) sendFriendRequests() {
|
||||
mutex.Lock()
|
||||
defer mutex.Unlock()
|
||||
|
||||
// Condense all requests into one packet
|
||||
var message string
|
||||
|
||||
for _, newSession := range sessions {
|
||||
if newSession.isFriendAdded(g.User.ProfileId) {
|
||||
message += common.CreateGameSpyMessage(common.GameSpyCommand{
|
||||
Command: "bm",
|
||||
CommandValue: "2",
|
||||
OtherValues: map[string]string{
|
||||
"f": strconv.FormatUint(uint64(newSession.User.ProfileId), 10),
|
||||
"msg": addFriendMessage,
|
||||
},
|
||||
})
|
||||
sendMessageToSessionBuffer("2", g.User.ProfileId, newSession, addFriendMessage)
|
||||
}
|
||||
}
|
||||
|
||||
if message != "" {
|
||||
g.Conn.Write([]byte(message))
|
||||
}
|
||||
}
|
||||
|
||||
func (g *GameSpySession) removeFriend(command common.GameSpyCommand) {
|
||||
|
|
@ -607,6 +574,17 @@ func sendMessageToSession(msgType string, from uint32, session *GameSpySession,
|
|||
session.Conn.Write([]byte(message))
|
||||
}
|
||||
|
||||
func sendMessageToSessionBuffer(msgType string, from uint32, session *GameSpySession, msg string) {
|
||||
session.WriteBuffer += common.CreateGameSpyMessage(common.GameSpyCommand{
|
||||
Command: "bm",
|
||||
CommandValue: msgType,
|
||||
OtherValues: map[string]string{
|
||||
"f": strconv.FormatUint(uint64(from), 10),
|
||||
"msg": msg,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func sendMessageToProfileId(msgType string, from uint32, to uint32, msg string) bool {
|
||||
if session, ok := sessions[to]; ok && session.LoggedIn {
|
||||
sendMessageToSession(msgType, from, session, msg)
|
||||
|
|
@ -635,7 +613,7 @@ 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)
|
||||
sendMessageToSessionBuffer("100", profileId, g, session.Status)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -266,7 +266,7 @@ func (g *GameSpySession) login(command common.GameSpyCommand) {
|
|||
|
||||
g.Conn.Write([]byte(payload))
|
||||
|
||||
g.sendFriendRequests()
|
||||
// g.sendFriendRequests()
|
||||
}
|
||||
|
||||
func (g *GameSpySession) exLogin(command common.GameSpyCommand) {
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ import (
|
|||
|
||||
type GameSpySession struct {
|
||||
Conn net.Conn
|
||||
WriteBuffer string
|
||||
User database.User
|
||||
ModuleName string
|
||||
LoggedIn bool
|
||||
|
|
@ -211,6 +212,11 @@ func handleRequest(conn net.Conn) {
|
|||
for _, command := range commands {
|
||||
logging.Error(session.ModuleName, "Unknown command:", aurora.Cyan(command.Command))
|
||||
}
|
||||
|
||||
if session.WriteBuffer != "" {
|
||||
conn.Write([]byte(session.WriteBuffer))
|
||||
session.WriteBuffer = ""
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -38,29 +38,60 @@ func (g *GameSpySession) getProfile(command common.GameSpyCommand) {
|
|||
}
|
||||
}
|
||||
|
||||
response := common.CreateGameSpyMessage(common.GameSpyCommand{
|
||||
Command: "pi",
|
||||
CommandValue: "",
|
||||
OtherValues: map[string]string{
|
||||
"profileid": command.OtherValues["profileid"],
|
||||
"nick": user.UniqueNick,
|
||||
"userid": strconv.FormatUint(uint64(user.UserId), 10),
|
||||
"email": user.Email,
|
||||
"sig": common.RandomHexString(32),
|
||||
"uniquenick": user.UniqueNick,
|
||||
"firstname": user.FirstName,
|
||||
"lastname": user.LastName,
|
||||
"pid": "11",
|
||||
"lon": "0.000000",
|
||||
"lat": "0.000000",
|
||||
"loc": locstring,
|
||||
"id": command.OtherValues["id"],
|
||||
},
|
||||
})
|
||||
|
||||
g.Conn.Write([]byte(response))
|
||||
if user.ProfileId == g.User.ProfileId {
|
||||
g.WriteBuffer += common.CreateGameSpyMessage(common.GameSpyCommand{
|
||||
Command: "pi",
|
||||
CommandValue: "",
|
||||
OtherValues: map[string]string{
|
||||
"profileid": command.OtherValues["profileid"],
|
||||
"nick": user.UniqueNick,
|
||||
"userid": strconv.FormatUint(uint64(user.UserId), 10),
|
||||
"email": user.Email,
|
||||
"sig": common.RandomHexString(32),
|
||||
"uniquenick": user.UniqueNick,
|
||||
"firstname": user.FirstName,
|
||||
"lastname": user.LastName,
|
||||
"pid": "11",
|
||||
"lon": "0.000000",
|
||||
"lat": "0.000000",
|
||||
"loc": locstring,
|
||||
"id": command.OtherValues["id"],
|
||||
},
|
||||
})
|
||||
} else {
|
||||
g.WriteBuffer += common.CreateGameSpyMessage(common.GameSpyCommand{
|
||||
Command: "pi",
|
||||
CommandValue: "",
|
||||
OtherValues: map[string]string{
|
||||
"profileid": command.OtherValues["profileid"],
|
||||
"nick": "000000000" + user.GsbrCode[:4] + "0000000",
|
||||
"userid": "0",
|
||||
"email": "000000000" + user.GsbrCode[:4] + "0000000" + "@nds",
|
||||
"sig": common.RandomHexString(32),
|
||||
"uniquenick": "000000000" + user.GsbrCode[:4] + "0000000",
|
||||
"firstname": user.FirstName,
|
||||
"lastname": "000000000" + user.GsbrCode[:4] + "0000000",
|
||||
"pid": "11",
|
||||
"lon": "0.000000",
|
||||
"lat": "0.000000",
|
||||
"loc": locstring,
|
||||
"id": command.OtherValues["id"],
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func (g *GameSpySession) updateProfile(command common.GameSpyCommand) {
|
||||
g.User.UpdateProfile(pool, ctx, command.OtherValues)
|
||||
}
|
||||
|
||||
func VerifyPlayerSearch(profileId uint32, sessionKey int32, gameName string) (string, bool) {
|
||||
mutex.Lock()
|
||||
defer mutex.Unlock()
|
||||
|
||||
if session, ok := sessions[profileId]; ok && session.LoggedIn && session.SessionKey == sessionKey && session.GameName == gameName {
|
||||
return "000000000" + session.User.GsbrCode[:4] + "0000000", true
|
||||
}
|
||||
|
||||
return "", false
|
||||
}
|
||||
|
|
|
|||
12
gpsp/error.go
Normal file
12
gpsp/error.go
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
package gpsp
|
||||
|
||||
import (
|
||||
"net"
|
||||
"wwfc/gpcm"
|
||||
"wwfc/logging"
|
||||
)
|
||||
|
||||
func replyError(moduleName string, conn net.Conn, err gpcm.GPError) {
|
||||
logging.Error(moduleName, "Reply error:", err.ErrorString)
|
||||
conn.Write([]byte(err.GetMessage()))
|
||||
}
|
||||
133
gpsp/main.go
133
gpsp/main.go
|
|
@ -3,18 +3,12 @@ package gpsp
|
|||
import (
|
||||
"bufio"
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
"strconv"
|
||||
"strings"
|
||||
"wwfc/common"
|
||||
"wwfc/database"
|
||||
"wwfc/gpcm"
|
||||
"wwfc/logging"
|
||||
|
||||
"github.com/jackc/pgx/v4/pgxpool"
|
||||
"github.com/logrusorgru/aurora/v3"
|
||||
)
|
||||
|
||||
var (
|
||||
|
|
@ -27,18 +21,6 @@ func StartServer() {
|
|||
// Get config
|
||||
config := common.GetConfig()
|
||||
|
||||
// Start SQL
|
||||
dbString := fmt.Sprintf("postgres://%s:%s@%s/%s", config.Username, config.Password, config.DatabaseAddress, config.DatabaseName)
|
||||
dbConf, err := pgxpool.ParseConfig(dbString)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
pool, err = pgxpool.ConnectConfig(ctx, dbConf)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
address := *config.GameSpyAddress + ":29901"
|
||||
l, err := net.Listen("tcp", address)
|
||||
if err != nil {
|
||||
|
|
@ -66,139 +48,42 @@ func handleRequest(conn net.Conn) {
|
|||
defer conn.Close()
|
||||
|
||||
moduleName := "GPSP"
|
||||
knownProfileId := uint32(0)
|
||||
|
||||
err := conn.(*net.TCPConn).SetKeepAlive(true)
|
||||
if err != nil {
|
||||
logging.Notice(moduleName, "Unable to set keepalive:", err.Error())
|
||||
}
|
||||
|
||||
logging.Info(moduleName, "Connection established from", aurora.BrightCyan(conn.RemoteAddr()))
|
||||
|
||||
// Here we go into the listening loop
|
||||
for {
|
||||
// TODO: Handle split packets
|
||||
buffer := make([]byte, 1024)
|
||||
_, err := bufio.NewReader(conn).Read(buffer)
|
||||
if err != nil {
|
||||
if errors.Is(err, io.EOF) {
|
||||
// Client closed connection, terminate.
|
||||
logging.Info(moduleName, "Client closed connection")
|
||||
return
|
||||
}
|
||||
|
||||
logging.Error(moduleName, "Connection error:", err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
commands, err := common.ParseGameSpyMessage(string(buffer))
|
||||
if err != nil {
|
||||
logging.Error(moduleName, err)
|
||||
logging.Error(moduleName, "Error parsing message:", err.Error())
|
||||
logging.Error(moduleName, "Raw data:", string(buffer))
|
||||
replyError(moduleName, conn, gpcm.ErrParse)
|
||||
return
|
||||
}
|
||||
|
||||
for _, command := range commands {
|
||||
logging.Info(moduleName, "Command:", aurora.Yellow(command.Command))
|
||||
|
||||
switch command.Command {
|
||||
default:
|
||||
logging.Error(moduleName, "Unknown command:", command.Command)
|
||||
|
||||
case "ka":
|
||||
conn.Write([]byte(`\ka\\final\`))
|
||||
break
|
||||
|
||||
case "otherslist":
|
||||
strProfileId, ok := command.OtherValues["profileid"]
|
||||
if !ok {
|
||||
logging.Error(moduleName, "Missing profileid in otherslist")
|
||||
return
|
||||
}
|
||||
|
||||
profileId, err := strconv.ParseUint(strProfileId, 10, 32)
|
||||
if err != nil {
|
||||
logging.Error(moduleName, err)
|
||||
return
|
||||
}
|
||||
|
||||
if knownProfileId == 0 {
|
||||
knownProfileId = uint32(profileId)
|
||||
moduleName = "GPSP:" + strconv.FormatUint(profileId, 10)
|
||||
moduleName += "/" + common.CalcFriendCodeString(uint32(profileId), "RMCJ")
|
||||
} else if uint32(profileId) != knownProfileId {
|
||||
logging.Warn(moduleName, "Mismatched profile ID in otherslist:", aurora.Cyan(strProfileId))
|
||||
}
|
||||
|
||||
logging.Info(moduleName, "Lookup otherslist for", aurora.Cyan(profileId))
|
||||
conn.Write([]byte(handleOthersList(moduleName, uint32(profileId), command)))
|
||||
conn.Write([]byte(handleOthersList(command)))
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func handleOthersList(moduleName string, _ uint32, command common.GameSpyCommand) string {
|
||||
empty := `\otherslist\\final\`
|
||||
|
||||
_, ok := command.OtherValues["sesskey"]
|
||||
if !ok {
|
||||
logging.Error(moduleName, "Missing sesskey in otherslist")
|
||||
return empty
|
||||
}
|
||||
|
||||
numopids, ok := command.OtherValues["numopids"]
|
||||
if !ok {
|
||||
logging.Error(moduleName, "Missing numopids in otherslist")
|
||||
return empty
|
||||
}
|
||||
|
||||
opids, ok := command.OtherValues["opids"]
|
||||
if !ok {
|
||||
logging.Error(moduleName, "Missing opids in otherslist")
|
||||
return empty
|
||||
}
|
||||
|
||||
_, ok = command.OtherValues["gamename"]
|
||||
if !ok {
|
||||
logging.Error(moduleName, "Missing gamename in otherslist")
|
||||
return empty
|
||||
}
|
||||
|
||||
numOpidsValue, err := strconv.Atoi(numopids)
|
||||
if err != nil {
|
||||
logging.Error(moduleName, err)
|
||||
return empty
|
||||
}
|
||||
|
||||
var opidsSplit []string
|
||||
if strings.Contains(opids, "|") {
|
||||
opidsSplit = strings.Split(opids, "|")
|
||||
} else if opids != "" && opids != "0" {
|
||||
opidsSplit = append(opidsSplit, opids)
|
||||
}
|
||||
|
||||
if len(opidsSplit) != numOpidsValue && opids != "0" {
|
||||
logging.Error(moduleName, "Mismatch opids length with numopids:", aurora.Cyan(len(opidsSplit)), "!=", aurora.Cyan(numOpidsValue))
|
||||
return empty
|
||||
}
|
||||
|
||||
payload := `\otherslist\`
|
||||
for _, strOtherId := range opidsSplit {
|
||||
otherId, err := strconv.ParseUint(strOtherId, 10, 32)
|
||||
if err != nil {
|
||||
logging.Error(moduleName, err)
|
||||
continue
|
||||
}
|
||||
|
||||
// TODO: Perhaps this could be condensed into one database query
|
||||
// Also TODO: Check if the players are actually friends
|
||||
user, ok := database.GetProfile(pool, ctx, uint32(otherId))
|
||||
if !ok {
|
||||
logging.Warn(moduleName, "Other ID doesn't exist:", aurora.Cyan(strOtherId))
|
||||
// If the profile doesn't exist then skip adding it
|
||||
continue
|
||||
}
|
||||
|
||||
payload += `\o\` + strconv.FormatUint(uint64(user.ProfileId), 10)
|
||||
payload += `\uniquenick\` + user.UniqueNick
|
||||
}
|
||||
|
||||
payload += `\oldone\\final\`
|
||||
return payload
|
||||
}
|
||||
|
|
|
|||
94
gpsp/otherslist.go
Normal file
94
gpsp/otherslist.go
Normal file
|
|
@ -0,0 +1,94 @@
|
|||
package gpsp
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
"strings"
|
||||
"wwfc/common"
|
||||
"wwfc/gpcm"
|
||||
"wwfc/logging"
|
||||
|
||||
"github.com/logrusorgru/aurora/v3"
|
||||
)
|
||||
|
||||
func handleOthersList(command common.GameSpyCommand) string {
|
||||
moduleName := "GPSP"
|
||||
|
||||
strProfileId, ok := command.OtherValues["profileid"]
|
||||
if !ok {
|
||||
logging.Error(moduleName, "Missing profileid in otherslist")
|
||||
return gpcm.ErrSearch.GetMessage()
|
||||
}
|
||||
|
||||
profileId, err := strconv.ParseUint(strProfileId, 10, 32)
|
||||
if err != nil {
|
||||
logging.Error(moduleName, "Invalid profileid:", strProfileId)
|
||||
return gpcm.ErrSearch.GetMessage()
|
||||
}
|
||||
|
||||
moduleName = "GPSP:" + strconv.FormatUint(profileId, 10)
|
||||
logging.Info(moduleName, "Lookup otherslist for", aurora.Cyan(profileId))
|
||||
|
||||
strSessionKey, ok := command.OtherValues["sesskey"]
|
||||
if !ok {
|
||||
logging.Error(moduleName, "Missing sesskey in otherslist")
|
||||
return gpcm.ErrSearch.GetMessage()
|
||||
}
|
||||
|
||||
sessionKey, err := strconv.ParseInt(strSessionKey, 10, 32)
|
||||
if err != nil {
|
||||
logging.Error(moduleName, "Invalid sesskey:", strSessionKey)
|
||||
return gpcm.ErrSearch.GetMessage()
|
||||
}
|
||||
|
||||
numopids, ok := command.OtherValues["numopids"]
|
||||
if !ok {
|
||||
logging.Error(moduleName, "Missing numopids in otherslist")
|
||||
return gpcm.ErrSearch.GetMessage()
|
||||
}
|
||||
|
||||
opids, ok := command.OtherValues["opids"]
|
||||
if !ok {
|
||||
logging.Error(moduleName, "Missing opids in otherslist")
|
||||
return gpcm.ErrSearch.GetMessage()
|
||||
}
|
||||
|
||||
gameName, ok := command.OtherValues["gamename"]
|
||||
if !ok {
|
||||
logging.Error(moduleName, "Missing gamename in otherslist")
|
||||
return gpcm.ErrSearch.GetMessage()
|
||||
}
|
||||
|
||||
numOpidsValue, err := strconv.Atoi(numopids)
|
||||
if err != nil {
|
||||
logging.Error(moduleName, "Invalid numopids:", numopids)
|
||||
return gpcm.ErrSearch.GetMessage()
|
||||
}
|
||||
|
||||
var opidsSplit []string
|
||||
if strings.Contains(opids, "|") {
|
||||
opidsSplit = strings.Split(opids, "|")
|
||||
} else if opids != "" && opids != "0" {
|
||||
opidsSplit = append(opidsSplit, opids)
|
||||
}
|
||||
|
||||
if len(opidsSplit) != numOpidsValue && opids != "0" {
|
||||
logging.Error(moduleName, "Mismatch opids length with numopids:", aurora.Cyan(len(opidsSplit)), "!=", aurora.Cyan(numOpidsValue))
|
||||
return gpcm.ErrSearch.GetMessage()
|
||||
}
|
||||
|
||||
// Lookup profile ID using GPCM
|
||||
uniqueNick, ok := gpcm.VerifyPlayerSearch(uint32(profileId), int32(sessionKey), gameName)
|
||||
if !ok {
|
||||
logging.Error(moduleName, "otherslist verify failed")
|
||||
return gpcm.ErrSearch.GetMessage()
|
||||
}
|
||||
|
||||
payload := `\otherslist\`
|
||||
for _, strOtherId := range opidsSplit {
|
||||
payload += `\o\` + strOtherId
|
||||
payload += `\uniquenick\` + uniqueNick
|
||||
}
|
||||
|
||||
payload += `\oldone\\final\`
|
||||
return payload
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user