Added AddFriendRequest method

This commit is contained in:
Jonathan Barrow 2021-10-30 00:08:24 -04:00
parent 51f1032c41
commit 5bbf1653ba
4 changed files with 256 additions and 39 deletions

200
add_friend_request.go Normal file
View File

@ -0,0 +1,200 @@
package main
import (
"encoding/base64"
"math/rand"
"time"
nex "github.com/PretendoNetwork/nex-go"
nexproto "github.com/PretendoNetwork/nex-protocols-go"
"go.mongodb.org/mongo-driver/bson"
)
func addFriendRequest(err error, client *nex.Client, callID uint32, pid uint32, unknown2 uint8, message string, unknown4 uint8, unknown5 string, gameKey *nexproto.GameKey, unknown6 *nex.DateTime) {
rand.Seed(time.Now().UnixNano())
nodeID := rand.Intn(len(snowflakeNodes))
snowflakeNode := snowflakeNodes[nodeID]
friendRequestID := uint64(snowflakeNode.Generate().Int64())
currentTimestamp := time.Now()
expireTimestamp := currentTimestamp.Add(time.Hour * 24 * 29)
sentTime := nex.NewDateTime(0)
expireTime := nex.NewDateTime(0)
sentTime.FromTimestamp(currentTimestamp)
expireTime.FromTimestamp(expireTimestamp)
senderPID := client.PID()
recipientPID := pid
recipientUserInforation := getUserInfoByPID(recipientPID)
friendRequest := nexproto.NewFriendRequest()
friendRequest.PrincipalInfo = nexproto.NewPrincipalBasicInfo()
friendRequest.PrincipalInfo.PID = recipientPID
friendRequest.PrincipalInfo.NNID = recipientUserInforation["username"].(string)
friendRequest.PrincipalInfo.Mii = nexproto.NewMiiV2()
friendRequest.PrincipalInfo.Unknown = 2 // replaying from real server
encodedMiiData := recipientUserInforation["mii"].(bson.M)["data"].(string)
decodedMiiData, _ := base64.StdEncoding.DecodeString(encodedMiiData)
friendRequest.PrincipalInfo.Mii.Name = recipientUserInforation["mii"].(bson.M)["name"].(string)
friendRequest.PrincipalInfo.Mii.Unknown1 = 0 // replaying from real server
friendRequest.PrincipalInfo.Mii.Unknown2 = 0 // replaying from real server
friendRequest.PrincipalInfo.Mii.Data = decodedMiiData
friendRequest.PrincipalInfo.Mii.Datetime = nex.NewDateTime(0)
friendRequest.Message = nexproto.NewFriendRequestMessage()
friendRequest.Message.FriendRequestID = friendRequestID
friendRequest.Message.Unknown1 = 0 // replaying from real server
friendRequest.Message.Unknown2 = 1 // replaying from real
friendRequest.Message.Message = message
friendRequest.Message.Unknown3 = 0 // replaying from real server
friendRequest.Message.Unknown4 = "" // replaying from real server
friendRequest.Message.GameKey = gameKey // maybe this is reused?
friendRequest.Message.Unknown5 = unknown6 // maybe this is reused?
friendRequest.Message.ExpiresOn = sentTime // no idea why this is set as the sent time
friendRequest.SentOn = sentTime
// Why does this exist?? Always empty??
friendInfo := nexproto.NewFriendInfo()
friendInfo.NNAInfo = nexproto.NewNNAInfo()
friendInfo.NNAInfo.PrincipalBasicInfo = nexproto.NewPrincipalBasicInfo()
friendInfo.NNAInfo.PrincipalBasicInfo.PID = 0
friendInfo.NNAInfo.PrincipalBasicInfo.NNID = ""
friendInfo.NNAInfo.PrincipalBasicInfo.Mii = nexproto.NewMiiV2()
friendInfo.NNAInfo.PrincipalBasicInfo.Mii.Name = ""
friendInfo.NNAInfo.PrincipalBasicInfo.Mii.Unknown1 = 0
friendInfo.NNAInfo.PrincipalBasicInfo.Mii.Unknown2 = 0
friendInfo.NNAInfo.PrincipalBasicInfo.Mii.Data = []byte{}
friendInfo.NNAInfo.PrincipalBasicInfo.Mii.Datetime = nex.NewDateTime(0)
friendInfo.NNAInfo.PrincipalBasicInfo.Unknown = 0
friendInfo.NNAInfo.Unknown1 = 0
friendInfo.NNAInfo.Unknown2 = 0
friendInfo.Presence = nexproto.NewNintendoPresenceV2()
friendInfo.Presence.ChangedFlags = 0
friendInfo.Presence.Online = false
friendInfo.Presence.GameKey = gameKey // maybe this is reused?
friendInfo.Presence.Unknown1 = 0
friendInfo.Presence.Message = ""
friendInfo.Presence.Unknown2 = 0
friendInfo.Presence.Unknown3 = 0
friendInfo.Presence.GameServerID = 0
friendInfo.Presence.Unknown4 = 0
friendInfo.Presence.PID = 0
friendInfo.Presence.GatheringID = 0
friendInfo.Presence.ApplicationData = []byte{0x00}
friendInfo.Presence.Unknown5 = 0
friendInfo.Presence.Unknown6 = 0
friendInfo.Presence.Unknown7 = 0
friendInfo.Status = nexproto.NewComment()
friendInfo.Status.Unknown = 0
friendInfo.Status.Contents = ""
friendInfo.Status.LastChanged = nex.NewDateTime(0)
friendInfo.BecameFriend = nex.NewDateTime(0)
friendInfo.LastOnline = nex.NewDateTime(0)
friendInfo.Unknown = 0
recipientClient := client.Server().FindClientFromPID(recipientPID)
if recipientClient != nil {
senderUserInforation := getUserInfoByPID(senderPID)
friendRequestNotificationData := nexproto.NewFriendRequest()
friendRequestNotificationData.PrincipalInfo = nexproto.NewPrincipalBasicInfo()
friendRequestNotificationData.PrincipalInfo.PID = senderPID
friendRequestNotificationData.PrincipalInfo.NNID = senderUserInforation["username"].(string)
friendRequestNotificationData.PrincipalInfo.Mii = nexproto.NewMiiV2()
friendRequestNotificationData.PrincipalInfo.Unknown = 2 // replaying from real server
encodedMiiData := senderUserInforation["mii"].(bson.M)["data"].(string)
decodedMiiData, _ := base64.StdEncoding.DecodeString(encodedMiiData)
friendRequestNotificationData.PrincipalInfo.Mii.Name = senderUserInforation["mii"].(bson.M)["name"].(string)
friendRequestNotificationData.PrincipalInfo.Mii.Unknown1 = 0 // replaying from real server
friendRequestNotificationData.PrincipalInfo.Mii.Unknown2 = 0 // replaying from real server
friendRequestNotificationData.PrincipalInfo.Mii.Data = decodedMiiData
friendRequestNotificationData.PrincipalInfo.Mii.Datetime = nex.NewDateTime(0)
friendRequestNotificationData.Message = nexproto.NewFriendRequestMessage()
friendRequestNotificationData.Message.FriendRequestID = friendRequestID
friendRequestNotificationData.Message.Unknown1 = 0 // replaying from real server
friendRequestNotificationData.Message.Unknown2 = 1 // replaying from real
friendRequestNotificationData.Message.Message = message
friendRequestNotificationData.Message.Unknown3 = 0 // replaying from real server
friendRequestNotificationData.Message.Unknown4 = "" // replaying from real server
friendRequestNotificationData.Message.GameKey = gameKey // maybe this is reused?
friendRequestNotificationData.Message.Unknown5 = unknown6 // maybe this is reused?
friendRequestNotificationData.Message.ExpiresOn = sentTime // no idea why this is set as the sent time
friendRequestNotificationData.SentOn = sentTime
sendFriendRequestNotification(recipientClient, friendRequestNotificationData)
}
rmcResponseStream := nex.NewStreamOut(nexServer)
rmcResponseStream.WriteUInt8(0xFF)
rmcResponseBody := rmcResponseStream.Bytes()
// Build response packet
rmcResponse := nex.NewRMCResponse(nexproto.FriendsProtocolID, callID)
rmcResponse.SetSuccess(nexproto.FriendsMethodAddFriendRequest, rmcResponseBody)
rmcResponseBytes := rmcResponse.Bytes()
responsePacket, _ := nex.NewPacketV0(client, nil)
responsePacket.SetVersion(0)
responsePacket.SetSource(0xA1)
responsePacket.SetDestination(0xAF)
responsePacket.SetType(nex.DataPacket)
responsePacket.SetPayload(rmcResponseBytes)
responsePacket.AddFlag(nex.FlagNeedsAck)
responsePacket.AddFlag(nex.FlagReliable)
nexServer.Send(responsePacket)
}
func sendFriendRequestNotification(client *nex.Client, friendRequestNotificationData *nexproto.FriendRequest) {
eventObject := nexproto.NewNintendoNotificationEvent()
eventObject.Type = 27
eventObject.SenderPID = friendRequestNotificationData.PrincipalInfo.PID
eventObject.DataHolder = nex.NewDataHolder()
eventObject.DataHolder.Name = "FriendRequest"
eventObject.DataHolder.Object = friendRequestNotificationData
stream := nex.NewStreamOut(nexServer)
eventObjectBytes := eventObject.Bytes(stream)
rmcRequest := nex.NewRMCRequest()
rmcRequest.SetProtocolID(nexproto.NintendoNotificationsProtocolID)
rmcRequest.SetCallID(3810693103)
rmcRequest.SetMethodID(nexproto.NintendoNotificationsMethodProcessNintendoNotificationEvent2)
rmcRequest.SetParameters(eventObjectBytes)
rmcRequestBytes := rmcRequest.Bytes()
requestPacket, _ := nex.NewPacketV0(client, nil)
requestPacket.SetVersion(0)
requestPacket.SetSource(0xA1)
requestPacket.SetDestination(0xAF)
requestPacket.SetType(nex.DataPacket)
requestPacket.SetPayload(rmcRequestBytes)
requestPacket.AddFlag(nex.FlagNeedsAck)
requestPacket.AddFlag(nex.FlagReliable)
nexServer.Send(requestPacket)
}

View File

@ -53,6 +53,35 @@ func connectCassandra() {
// Create tables if missing
if err := cassandraClusterSession.Query(`CREATE TABLE IF NOT EXISTS pretendo_friends.preferences (
pid int PRIMARY KEY,
show_online boolean,
show_current_game boolean,
block_friend_requests boolean
)`).Exec(); err != nil {
log.Fatal(err)
}
if err := cassandraClusterSession.Query(`CREATE TABLE IF NOT EXISTS pretendo_friends.blocks (
id text PRIMARY KEY,
blocker_pid int,
blocked_pid int,
date bigint
)`).Exec(); err != nil {
log.Fatal(err)
}
if err := cassandraClusterSession.Query(`CREATE TABLE IF NOT EXISTS pretendo_friends.friend_requests (
id bigint PRIMARY KEY,
sender_pid int,
recipient_pid int,
sent_on bigint,
expires_on bigint,
message text
)`).Exec(); err != nil {
log.Fatal(err)
}
if err := cassandraClusterSession.Query(`CREATE TABLE IF NOT EXISTS pretendo_friends.users (
pid int PRIMARY KEY,
nnid text,
@ -71,15 +100,6 @@ func connectCassandra() {
log.Fatal(err)
}
if err := cassandraClusterSession.Query(`CREATE TABLE IF NOT EXISTS pretendo_friends.preferences (
pid int PRIMARY KEY,
show_online boolean,
show_current_game boolean,
block_friend_requests boolean
)`).Exec(); err != nil {
log.Fatal(err)
}
if err := cassandraClusterSession.Query(`CREATE TABLE IF NOT EXISTS pretendo_friends.friendships (
id bigint PRIMARY KEY,
user1_pid int,
@ -89,15 +109,6 @@ func connectCassandra() {
log.Fatal(err)
}
if err := cassandraClusterSession.Query(`CREATE TABLE IF NOT EXISTS pretendo_friends.blocks (
id text PRIMARY KEY,
blocker_pid int,
blocked_pid int,
date bigint
)`).Exec(); err != nil {
log.Fatal(err)
}
if err := cassandraClusterSession.Query(`CREATE TABLE IF NOT EXISTS pretendo_friends.miis (
pid int PRIMARY KEY,
name text,
@ -109,16 +120,6 @@ func connectCassandra() {
log.Fatal(err)
}
if err := cassandraClusterSession.Query(`CREATE TABLE IF NOT EXISTS pretendo_friends.friend_requests (
id bigint PRIMARY KEY,
sender_pid int,
recipient_pid int,
sent_on bigint,
message text
)`).Exec(); err != nil {
log.Fatal(err)
}
if err := cassandraClusterSession.Query(`CREATE TABLE IF NOT EXISTS pretendo_friends.notifications (
id bigint PRIMARY KEY,
sender_pid int,
@ -237,22 +238,19 @@ func getUserBlockList(pid uint32) {}
func getUserNotifications(pid uint32) {}
func updateUserPrincipalPreference(pid uint32, principalPreference *nexproto.PrincipalPreference) {
if err := cassandraClusterSession.Query(`UPDATE pretendo_friends.preferences SET show_online=?, show_current_game=?, block_friend_requests=? WHERE pid=?`, principalPreference.Unknown1, principalPreference.Unknown2, principalPreference.Unknown3, pid).Exec(); err != nil {
if err := cassandraClusterSession.Query(`UPDATE pretendo_friends.preferences SET
show_online=?,
show_current_game=?,
block_friend_requests=?
WHERE pid=?`, principalPreference.ShowOnlinePresence, principalPreference.ShowCurrentTitle, principalPreference.BlockFriendRequests, pid).Exec(); err != nil {
log.Fatal(err)
}
}
func getUserPrincipalPreference(pid uint32) *nexproto.PrincipalPreference {
var showOnline bool
var showCurrentGame bool
var blockFriendRequests bool
_ = cassandraClusterSession.Query(`SELECT show_online, show_current_game, block_friend_requests FROM pretendo_friends.preferences WHERE pid=?`, pid).Scan(&showOnline, &showCurrentGame, &blockFriendRequests)
preference := nexproto.NewPrincipalPreference()
preference.Unknown1 = showOnline
preference.Unknown2 = showCurrentGame
preference.Unknown3 = blockFriendRequests
_ = cassandraClusterSession.Query(`SELECT show_online, show_current_game, block_friend_requests FROM pretendo_friends.preferences WHERE pid=?`, pid).Scan(&preference.ShowOnlinePresence, &preference.ShowCurrentTitle, &preference.BlockFriendRequests)
return preference
}

18
init.go
View File

@ -2,9 +2,12 @@ package main
import (
"crypto/rsa"
"fmt"
"io/ioutil"
"log"
"runtime"
"github.com/bwmarrin/snowflake"
"github.com/joho/godotenv"
)
@ -27,6 +30,7 @@ type nexToken struct {
var rsaPrivateKeyBytes []byte
var rsaPrivateKey *rsa.PrivateKey
var hmacSecret []byte
var snowflakeNodes []*snowflake.Node
func init() {
// Setup RSA private key for token parsing
@ -54,4 +58,18 @@ func init() {
connectMongo()
connectCassandra()
createSnowflakeNodes()
}
func createSnowflakeNodes() {
snowflakeNodes = make([]*snowflake.Node, 0)
for corenum := 0; corenum < runtime.NumCPU(); corenum++ {
node, err := snowflake.NewNode(int64(corenum))
if err != nil {
fmt.Println(err)
return
}
snowflakeNodes = append(snowflakeNodes, node)
}
}

View File

@ -44,9 +44,10 @@ func main() {
// Friends (WiiU) protocol handles
friendsServer.UpdateAndGetAllInformation(updateAndGetAllInformation)
friendsServer.CheckSettingStatus(checkSettingStatus)
friendsServer.AddFriendRequest(addFriendRequest)
friendsServer.UpdatePreference(updatePreferenceWiiU)
friendsServer.GetBasicInfo(getBasicInfo)
friendsServer.CheckSettingStatus(checkSettingStatus)
friendsServer.GetRequestBlockSettings(getRequestBlockSettings)
// Friends (3DS) protocol handles