diff --git a/add_to_buffer_queues.go b/add_to_buffer_queues.go deleted file mode 100644 index 33ad55f..0000000 --- a/add_to_buffer_queues.go +++ /dev/null @@ -1,44 +0,0 @@ -package main - -import ( - nex "github.com/PretendoNetwork/nex-go" - nexproto "github.com/PretendoNetwork/nex-protocols-go" -) - -func addToBufferQueues(err error, client *nex.Client, callID uint32, params []*nexproto.BufferQueueParam, buffers [][]byte) { - pResults := make([]uint32, 0) - - for i := 0; i < len(params); i++ { - buffer := buffers[i] - param := params[i] - - insertBufferQueueData(param.DataID, param.Slot, buffer) - incrementCourseFailCount(param.DataID) - - pResults = append(pResults, 0x690001) - } - - rmcResponseStream := nex.NewStreamOut(nexServer) - - rmcResponseStream.WriteListUInt32LE(pResults) - - rmcResponseBody := rmcResponseStream.Bytes() - - rmcResponse := nex.NewRMCResponse(nexproto.DataStoreProtocolID, callID) - rmcResponse.SetSuccess(nexproto.DataStoreSMMMethodAddToBufferQueues, rmcResponseBody) - - rmcResponseBytes := rmcResponse.Bytes() - - responsePacket, _ := nex.NewPacketV1(client, nil) - - responsePacket.SetVersion(1) - responsePacket.SetSource(0xA1) - responsePacket.SetDestination(0xAF) - responsePacket.SetType(nex.DataPacket) - responsePacket.SetPayload(rmcResponseBytes) - - responsePacket.AddFlag(nex.FlagNeedsAck) - responsePacket.AddFlag(nex.FlagReliable) - - nexServer.Send(responsePacket) -} diff --git a/complete_attach_file.go b/complete_attach_file.go deleted file mode 100644 index ed62697..0000000 --- a/complete_attach_file.go +++ /dev/null @@ -1,37 +0,0 @@ -package main - -import ( - "fmt" - "os" - - nex "github.com/PretendoNetwork/nex-go" - nexproto "github.com/PretendoNetwork/nex-protocols-go" -) - -func completeAttachFile(err error, client *nex.Client, callID uint32, dataStoreCompletePostParam *nexproto.DataStoreCompletePostParam) { - rmcResponseStream := nex.NewStreamOut(nexServer) - - // TODO: complete this - - rmcResponseStream.WriteString(fmt.Sprintf("http://%s.b-cdn.net/image/%d.jpg", os.Getenv("S3_BUCKET_NAME"), dataStoreCompletePostParam.DataID)) - - rmcResponseBody := rmcResponseStream.Bytes() - - rmcResponse := nex.NewRMCResponse(nexproto.DataStoreSMMProtocolID, callID) - rmcResponse.SetSuccess(nexproto.DataStoreSMMMethodCompleteAttachFile, rmcResponseBody) - - rmcResponseBytes := rmcResponse.Bytes() - - responsePacket, _ := nex.NewPacketV1(client, nil) - - responsePacket.SetVersion(1) - responsePacket.SetSource(0xA1) - responsePacket.SetDestination(0xAF) - responsePacket.SetType(nex.DataPacket) - responsePacket.SetPayload(rmcResponseBytes) - - responsePacket.AddFlag(nex.FlagNeedsAck) - responsePacket.AddFlag(nex.FlagReliable) - - nexServer.Send(responsePacket) -} diff --git a/connect.go b/connect.go deleted file mode 100644 index 182e540..0000000 --- a/connect.go +++ /dev/null @@ -1,37 +0,0 @@ -package main - -import ( - nex "github.com/PretendoNetwork/nex-go" -) - -func connect(packet *nex.PacketV1) { - payload := packet.Payload() - - stream := nex.NewStreamIn(payload, nexServer) - - _, _ = stream.ReadBuffer() - checkData, _ := stream.ReadBuffer() - - sessionKey := make([]byte, nexServer.KerberosKeySize()) - - kerberos := nex.NewKerberosEncryption(sessionKey) - - checkDataDecrypted := kerberos.Decrypt(checkData) - checkDataStream := nex.NewStreamIn(checkDataDecrypted, nexServer) - - userPID := checkDataStream.ReadUInt32LE() // User PID - packet.Sender().SetPID(userPID) - _ = checkDataStream.ReadUInt32LE() //CID of secure server station url - responseCheck := checkDataStream.ReadUInt32LE() - - responseValueStream := nex.NewStreamOut(nexServer) - responseValueStream.WriteUInt32LE(responseCheck + 1) - - responseValueBufferStream := nex.NewStreamOut(nexServer) - responseValueBufferStream.WriteBuffer(responseValueStream.Bytes()) - - nexServer.AcknowledgePacket(packet, responseValueBufferStream.Bytes()) - - packet.Sender().UpdateRC4Key(sessionKey) - packet.Sender().SetSessionKey(sessionKey) -} diff --git a/ctr_pick_up_course_search_object.go b/ctr_pick_up_course_search_object.go deleted file mode 100644 index 7684a14..0000000 --- a/ctr_pick_up_course_search_object.go +++ /dev/null @@ -1,42 +0,0 @@ -package main - -import ( - nex "github.com/PretendoNetwork/nex-go" - nexproto "github.com/PretendoNetwork/nex-protocols-go" -) - -// This is the same as DataStoreSMM::RecommendedCourseSearchObject -// Not sure why they used a different method here? -func ctrPickUpCourseSearchObject(err error, client *nex.Client, callID uint32, dataStoreSearchParam *nexproto.DataStoreSearchParam, extraData []string) { - pRankingResults := make([]*nexproto.DataStoreCustomRankingResult, 0) - - courseMetadatas := getCourseMetadatasByLimit(100) // In PCAPs param.minimalRatingFrequency is 100 but is 0 here? - - for _, courseMetadata := range courseMetadatas { - pRankingResults = append(pRankingResults, courseMetadataToDataStoreCustomRankingResult(courseMetadata)) - } - - rmcResponseStream := nex.NewStreamOut(nexServer) - - rmcResponseStream.WriteListStructure(pRankingResults) - - rmcResponseBody := rmcResponseStream.Bytes() - - rmcResponse := nex.NewRMCResponse(nexproto.DataStoreSMMProtocolID, callID) - rmcResponse.SetSuccess(nexproto.DataStoreSMMMethodCTRPickUpCourseSearchObject, rmcResponseBody) - - rmcResponseBytes := rmcResponse.Bytes() - - responsePacket, _ := nex.NewPacketV1(client, nil) - - responsePacket.SetVersion(1) - responsePacket.SetSource(0xA1) - responsePacket.SetDestination(0xAF) - responsePacket.SetType(nex.DataPacket) - responsePacket.SetPayload(rmcResponseBytes) - - responsePacket.AddFlag(nex.FlagNeedsAck) - responsePacket.AddFlag(nex.FlagReliable) - - nexServer.Send(responsePacket) -} diff --git a/database.go b/database.go deleted file mode 100644 index cc67b32..0000000 --- a/database.go +++ /dev/null @@ -1,466 +0,0 @@ -package main - -import ( - "context" - "flag" - "fmt" - "log" - "os" - "time" - - "github.com/PretendoNetwork/nex-go" - "github.com/gocql/gocql" - "go.mongodb.org/mongo-driver/bson" - "go.mongodb.org/mongo-driver/mongo" - "go.mongodb.org/mongo-driver/mongo/options" -) - -var cluster *gocql.ClusterConfig -var cassandraClusterSession *gocql.Session - -var mongoClient *mongo.Client -var mongoContext context.Context -var mongoDatabase *mongo.Database -var mongoCollection *mongo.Collection - -func connectMongo() { - mongoClient, _ = mongo.NewClient(options.Client().ApplyURI(os.Getenv("MONGO_URI"))) - mongoContext, _ = context.WithTimeout(context.Background(), 10*time.Second) - _ = mongoClient.Connect(mongoContext) - - mongoDatabase = mongoClient.Database("pretendo") - mongoCollection = mongoDatabase.Collection("pnids") -} - -func connectCassandra() { - // Connect to Cassandra - - var err error - - cluster = gocql.NewCluster("127.0.0.1") - cluster.Timeout = 30 * time.Second - - createKeyspace("pretendo_smm") - - cluster.Keyspace = "pretendo_smm" - - cassandraClusterSession, err = cluster.CreateSession() - - if err != nil { - panic(err) - } - - // Create tables if missing - - if err := cassandraClusterSession.Query(`CREATE TABLE IF NOT EXISTS pretendo_smm.courses ( - data_id bigint PRIMARY KEY, - playable boolean, - owner_pid int, - name text, - size int, - creation_date bigint, - update_date bigint, - world_record_first_pid int, - world_record_pid int, - world_record_creation_date bigint, - world_record_update_date bigint, - world_record int, - meta_binary blob, - flag int, - extra_data list, - data_type smallint, - period smallint - )`).Exec(); err != nil { - fmt.Println("pretendo_smm.courses") - log.Fatal(err) - } - - if err := cassandraClusterSession.Query(`CREATE TABLE IF NOT EXISTS pretendo_smm.ratings ( - data_id bigint PRIMARY KEY, - stars counter, - attempts counter, - failures counter, - completions counter - )`).Exec(); err != nil { - fmt.Println("pretendo_smm.ratings") - log.Fatal(err) - } - - if err := cassandraClusterSession.Query(`CREATE TABLE IF NOT EXISTS pretendo_smm.buffer_queues ( - id uuid PRIMARY KEY, - data_id bigint, - slot int, - buffer blob - )`).Exec(); err != nil { - fmt.Println("pretendo_smm.buffer_queues") - log.Fatal(err) - } - - if err := cassandraClusterSession.Query(`CREATE TABLE IF NOT EXISTS pretendo_smm.generator_last_id ( - node_id int PRIMARY KEY, - last_id int - )`).Exec(); err != nil { - fmt.Println("pretendo_smm.generator_last_id") - log.Fatal(err) - } - - if err := cassandraClusterSession.Query(`CREATE TABLE IF NOT EXISTS pretendo_smm.user_play_info ( - pid int PRIMARY KEY, - starred_courses set, - played_courses set - )`).Exec(); err != nil { - fmt.Println("pretendo_smm.user_play_info") - log.Fatal(err) - } - - fmt.Println("Connected to Cassandra") -} - -// Adapted from gocql common_test.go -func createKeyspace(keyspace string) { - flagRF := flag.Int("rf", 1, "replication factor for pretendo_smm keyspace") - - c := *cluster - c.Keyspace = "system" - c.Timeout = 30 * time.Second - - s, err := c.CreateSession() - - if err != nil { - panic(err) - } - - defer s.Close() - - if err := s.Query(fmt.Sprintf(`CREATE KEYSPACE IF NOT EXISTS %s - WITH replication = { - 'class' : 'SimpleStrategy', - 'replication_factor' : %d - }`, keyspace, *flagRF)).Exec(); err != nil { - log.Fatal(err) - } -} - -//////////////////////////////// -// // -// Cassandra database methods // -// // -//////////////////////////////// - -func createDataStoreIDGeneratorRow(nodeID int) { - if err := cassandraClusterSession.Query(`INSERT INTO pretendo_smm.generator_last_id(node_id, last_id) VALUES (?, ?) IF NOT EXISTS`, nodeID, 0).Exec(); err != nil { - log.Fatal(err) - } -} - -func getDataStoreIDGeneratorLastID(nodeID int) uint32 { - var lastID uint32 - _ = cassandraClusterSession.Query(`SELECT last_id FROM pretendo_smm.generator_last_id WHERE node_id=?`, nodeID).Scan(&lastID) - - return lastID -} - -func setDataStoreIDGeneratorLastID(nodeID int, value uint32) { - if err := cassandraClusterSession.Query(`UPDATE pretendo_smm.generator_last_id SET last_id=? WHERE node_id=?`, value, nodeID).Exec(); err != nil { - log.Fatal(err) - } -} - -func initializeCourseData(courseID uint64, ownerPID uint32, size uint32, name string, flag uint32, extraData []string, dataType uint16, period uint16) { - datetime := nex.NewDateTime(0) - now := datetime.Now() - - if err := cassandraClusterSession.Query(`INSERT INTO pretendo_smm.courses( - data_id, - owner_pid, - size, - name, - flag, - extra_data, - playable, - creation_date, - update_date, - world_record_first_pid, - world_record_pid, - world_record_creation_date, - world_record_update_date, - world_record, - data_type, - period - ) - VALUES ( - ?, - ?, - ?, - ?, - ?, - ?, - false, - ?, - ?, - 0, - 0, - 0, - 0, - 0, - ?, - ? - ) IF NOT EXISTS`, - courseID, ownerPID, size, name, flag, extraData, now, now, dataType, period).Exec(); err != nil { - log.Fatal(err) - } - - if err := cassandraClusterSession.Query(`UPDATE pretendo_smm.ratings SET stars=stars+0, attempts=attempts+0, failures=failures+0, completions=completions+0 WHERE data_id=?`, courseID).Exec(); err != nil { - log.Fatal(err) - } -} - -func updateCourseMetaBinary(courseID uint64, metaBinary []byte) { - if err := cassandraClusterSession.Query(`UPDATE pretendo_smm.courses SET meta_binary=? WHERE data_id=?`, metaBinary, courseID).Exec(); err != nil { - log.Fatal(err) - } -} - -func setCoursePlayable(courseID uint64) { - if err := cassandraClusterSession.Query(`UPDATE pretendo_smm.courses SET playable=true WHERE data_id=?`, courseID).Exec(); err != nil { - log.Fatal(err) - } -} - -func getCourseMetadatasByLimit(limit uint32) []*CourseMetadata { - var sliceMap []map[string]interface{} - var err error - - if sliceMap, err = cassandraClusterSession.Query(`SELECT data_id, owner_pid, size, name, meta_binary, flag, creation_date, update_date, data_type, period FROM pretendo_smm.courses LIMIT ?`, limit).Iter().SliceMap(); err != nil { - log.Fatal(err) - } - - courseMetadatas := make([]*CourseMetadata, 0) - - for _, course := range sliceMap { - dataID := uint64(course["data_id"].(int64)) - - var stars uint32 - var attempts uint32 - var failures uint32 - var completions uint32 - - _ = cassandraClusterSession.Query(`SELECT stars, attempts, failures, completions FROM pretendo_smm.ratings WHERE data_id=?`, dataID).Scan(&stars, &attempts, &failures, &completions) - - courseMetadata := &CourseMetadata{ - DataID: dataID, - OwnerPID: uint32(course["owner_pid"].(int)), - Size: uint32(course["size"].(int)), - CreatedTime: nex.NewDateTime(uint64(course["creation_date"].(int64))), - UpdatedTime: nex.NewDateTime(uint64(course["update_date"].(int64))), - Name: course["name"].(string), - MetaBinary: course["meta_binary"].([]byte), - Stars: stars, - Attempts: attempts, - Failures: failures, - Completions: completions, - Flag: uint32(course["flag"].(int)), - DataType: uint16(course["data_type"].(int16)), - Period: uint16(course["period"].(int16)), - } - - courseMetadatas = append(courseMetadatas, courseMetadata) - } - - return courseMetadatas -} - -func getCourseMetadataByDataID(dataID uint64) *CourseMetadata { - var ownerPID uint32 - var size uint32 - var name string - var metaBinary []byte - var flag uint32 - var createdTime uint64 - var updatedTime uint64 - var dataType uint16 - var period uint16 - - err := cassandraClusterSession.Query(`SELECT owner_pid, size, name, meta_binary, flag, creation_date, update_date, data_type, period FROM pretendo_smm.courses WHERE data_id=?`, dataID).Scan(&ownerPID, &size, &name, &metaBinary, &flag, &createdTime, &updatedTime, &dataType, &period) - - if err != nil { - if err == gocql.ErrNotFound { - return nil - } else { - log.Fatal(err) - } - } - - var stars uint32 - var attempts uint32 - var failures uint32 - var completions uint32 - - _ = cassandraClusterSession.Query(`SELECT stars, attempts, failures, completions FROM pretendo_smm.ratings WHERE data_id=?`, dataID).Scan(&stars, &attempts, &failures, &completions) - - courseMetadata := &CourseMetadata{ - DataID: dataID, - OwnerPID: ownerPID, - Size: size, - CreatedTime: nex.NewDateTime(createdTime), - UpdatedTime: nex.NewDateTime(updatedTime), - Name: name, - MetaBinary: metaBinary, - Stars: stars, - Attempts: attempts, - Failures: failures, - Completions: completions, - Flag: flag, - DataType: dataType, - Period: period, - } - - return courseMetadata -} - -func getCourseMetadataByDataIDs(dataIDs []uint64) []*CourseMetadata { - // TODO: Do this in one query? - courseMetadatas := make([]*CourseMetadata, 0) - - for _, dataID := range dataIDs { - courseMetadata := getCourseMetadataByDataID(dataID) - - if courseMetadata != nil { - courseMetadatas = append(courseMetadatas, courseMetadata) - } - } - - return courseMetadatas -} - -func getCourseMetadatasByPID(pid uint32) []*CourseMetadata { - courseMetadatas := make([]*CourseMetadata, 0) - - // TODO: Fix this query? Seems like a weird way of doing this... - var sliceMap []map[string]interface{} - var err error - - if sliceMap, err = cassandraClusterSession.Query(`SELECT data_id FROM pretendo_smm.courses WHERE owner_pid=? ALLOW FILTERING`, pid).Iter().SliceMap(); err != nil { - log.Fatal(err) - } - - for _, course := range sliceMap { - dataID := uint64(course["data_id"].(int64)) - courseMetadatas = append(courseMetadatas, getCourseMetadataByDataID(dataID)) - } - - return courseMetadatas -} - -func insertBufferQueueData(dataID uint64, slot uint32, buffer []byte) { - if err := cassandraClusterSession.Query(`INSERT INTO pretendo_smm.buffer_queues( id, data_id, slot, buffer ) VALUES ( now(), ?, ?, ? ) IF NOT EXISTS`, dataID, slot, buffer).Exec(); err != nil { - log.Fatal(err) - } -} - -func getBufferQueueDeathData(dataID uint64) [][]byte { - pBufferQueue := make([][]byte, 0) - - var sliceMap []map[string]interface{} - var err error - - if sliceMap, err = cassandraClusterSession.Query(`SELECT buffer FROM pretendo_smm.buffer_queues WHERE data_id=? AND slot=3 ALLOW FILTERING`, dataID).Iter().SliceMap(); err != nil { - log.Fatal(err) - } - - for _, bufferQueue := range sliceMap { - pBufferQueue = append(pBufferQueue, bufferQueue["buffer"].([]byte)) - } - - return pBufferQueue -} - -func getCourseWorldRecord(dataID uint64) *CourseWorldRecord { - var worldRecordFirstPID uint32 - var worldRecordPID uint32 - var worldRecordCreatedTime uint64 - var worldRecordUpdatedTime uint64 - var worldRecord int32 - - _ = cassandraClusterSession.Query(`SELECT world_record_first_pid, world_record_pid, world_record_creation_date, world_record_update_date, world_record FROM pretendo_smm.courses WHERE data_id=?`, dataID).Scan(&worldRecordFirstPID, &worldRecordPID, &worldRecordCreatedTime, &worldRecordUpdatedTime, &worldRecord) - - if worldRecordFirstPID == 0 { - return nil - } - - return &CourseWorldRecord{ - FirstPID: worldRecordFirstPID, - BestPID: worldRecordPID, - CreatedTime: nex.NewDateTime(worldRecordCreatedTime), - UpdatedTime: nex.NewDateTime(worldRecordUpdatedTime), - Score: worldRecord, - } -} - -func updateCourseWorldRecord(courseID uint64, ownerPID uint32, score int32) { - datetime := nex.NewDateTime(0) - now := datetime.Now() - - if getCourseWorldRecord(courseID) == nil { - if err := cassandraClusterSession.Query(`UPDATE pretendo_smm.courses SET world_record_first_pid=?, world_record_creation_date=? WHERE data_id=?`, ownerPID, now, courseID).Exec(); err != nil { - log.Fatal(err) - } - } - - if err := cassandraClusterSession.Query(`UPDATE pretendo_smm.courses SET world_record_pid=?, world_record_update_date=?, world_record=? WHERE data_id=?`, ownerPID, now, score, courseID).Exec(); err != nil { - log.Fatal(err) - } -} - -func incrementCourseClearCount(courseID uint64) { - if err := cassandraClusterSession.Query(`UPDATE pretendo_smm.ratings SET completions=completions+1 WHERE data_id=?`, courseID).Exec(); err != nil { - log.Fatal(err) - } -} - -func incrementCourseStarCount(courseID uint64) { - if err := cassandraClusterSession.Query(`UPDATE pretendo_smm.ratings SET stars=stars+1 WHERE data_id=?`, courseID).Exec(); err != nil { - log.Fatal(err) - } -} - -func incrementCourseFailCount(courseID uint64) { - if err := cassandraClusterSession.Query(`UPDATE pretendo_smm.ratings SET failures=failures+1 WHERE data_id=?`, courseID).Exec(); err != nil { - log.Fatal(err) - } -} - -func incrementCourseAttemptCount(courseID uint64) { - if err := cassandraClusterSession.Query(`UPDATE pretendo_smm.ratings SET attempts=attempts+1 WHERE data_id=?`, courseID).Exec(); err != nil { - log.Fatal(err) - } -} - -func getUserStarredCourses(pid uint32) []*CourseMetadata { - var dataIDs []uint64 - _ = cassandraClusterSession.Query(`SELECT starred_courses FROM pretendo_smm.user_play_info WHERE pid=?`, pid).Scan(&dataIDs) - - return getCourseMetadataByDataIDs(dataIDs) -} - -////////////////////////////// -// // -// MongoDB database methods // -// // -////////////////////////////// - -func getUserMiiInfoByPID(pid uint32) bson.M { - var result bson.M - - err := mongoCollection.FindOne(context.TODO(), bson.D{{Key: "pid", Value: pid}}, options.FindOne()).Decode(&result) - - if err != nil { - if err == mongo.ErrNoDocuments { - return nil - } - - panic(err) - } - - return result["mii"].(bson.M) -} diff --git a/database/connect_all.go b/database/connect_all.go new file mode 100644 index 0000000..15ca8b8 --- /dev/null +++ b/database/connect_all.go @@ -0,0 +1,6 @@ +package database + +func ConnectAll() { + connectMongo() + connectCassandra() +} diff --git a/database/connect_cassandra.go b/database/connect_cassandra.go new file mode 100644 index 0000000..e86c59f --- /dev/null +++ b/database/connect_cassandra.go @@ -0,0 +1,122 @@ +package database + +import ( + "flag" + "fmt" + "log" + "time" + + "github.com/gocql/gocql" +) + +var cluster *gocql.ClusterConfig +var cassandraClusterSession *gocql.Session + +func connectCassandra() { + // Connect to Cassandra + + var err error + + cluster = gocql.NewCluster("127.0.0.1") + cluster.Timeout = 30 * time.Second + + createKeyspace("pretendo_smm") + + cluster.Keyspace = "pretendo_smm" + + cassandraClusterSession, err = cluster.CreateSession() + + if err != nil { + panic(err) + } + + // Create tables if missing + + if err := cassandraClusterSession.Query(`CREATE TABLE IF NOT EXISTS pretendo_smm.courses ( + data_id bigint PRIMARY KEY, + playable boolean, + owner_pid int, + name text, + size int, + creation_date bigint, + update_date bigint, + world_record_first_pid int, + world_record_pid int, + world_record_creation_date bigint, + world_record_update_date bigint, + world_record int, + meta_binary blob, + flag int, + extra_data list, + data_type smallint, + period smallint + )`).Exec(); err != nil { + fmt.Println("pretendo_smm.courses") + log.Fatal(err) + } + + if err := cassandraClusterSession.Query(`CREATE TABLE IF NOT EXISTS pretendo_smm.ratings ( + data_id bigint PRIMARY KEY, + stars counter, + attempts counter, + failures counter, + completions counter + )`).Exec(); err != nil { + fmt.Println("pretendo_smm.ratings") + log.Fatal(err) + } + + if err := cassandraClusterSession.Query(`CREATE TABLE IF NOT EXISTS pretendo_smm.buffer_queues ( + id uuid PRIMARY KEY, + data_id bigint, + slot int, + buffer blob + )`).Exec(); err != nil { + fmt.Println("pretendo_smm.buffer_queues") + log.Fatal(err) + } + + if err := cassandraClusterSession.Query(`CREATE TABLE IF NOT EXISTS pretendo_smm.generator_last_id ( + node_id int PRIMARY KEY, + last_id int + )`).Exec(); err != nil { + fmt.Println("pretendo_smm.generator_last_id") + log.Fatal(err) + } + + if err := cassandraClusterSession.Query(`CREATE TABLE IF NOT EXISTS pretendo_smm.user_play_info ( + pid int PRIMARY KEY, + starred_courses set, + played_courses set + )`).Exec(); err != nil { + fmt.Println("pretendo_smm.user_play_info") + log.Fatal(err) + } + + fmt.Println("Connected to Cassandra") +} + +// Adapted from gocql common_test.go +func createKeyspace(keyspace string) { + flagRF := flag.Int("rf", 1, "replication factor for pretendo_smm keyspace") + + c := *cluster + c.Keyspace = "system" + c.Timeout = 30 * time.Second + + s, err := c.CreateSession() + + if err != nil { + panic(err) + } + + defer s.Close() + + if err := s.Query(fmt.Sprintf(`CREATE KEYSPACE IF NOT EXISTS %s + WITH replication = { + 'class' : 'SimpleStrategy', + 'replication_factor' : %d + }`, keyspace, *flagRF)).Exec(); err != nil { + log.Fatal(err) + } +} diff --git a/database/connect_mongo.go b/database/connect_mongo.go new file mode 100644 index 0000000..70ae1fb --- /dev/null +++ b/database/connect_mongo.go @@ -0,0 +1,24 @@ +package database + +import ( + "context" + "os" + "time" + + "go.mongodb.org/mongo-driver/mongo" + "go.mongodb.org/mongo-driver/mongo/options" +) + +var mongoClient *mongo.Client +var mongoContext context.Context +var mongoDatabase *mongo.Database +var mongoCollection *mongo.Collection + +func connectMongo() { + mongoClient, _ = mongo.NewClient(options.Client().ApplyURI(os.Getenv("MONGO_URI"))) + mongoContext, _ = context.WithTimeout(context.Background(), 10*time.Second) + _ = mongoClient.Connect(mongoContext) + + mongoDatabase = mongoClient.Database("pretendo") + mongoCollection = mongoDatabase.Collection("pnids") +} diff --git a/database/create_datastore_id_generator_row.go b/database/create_datastore_id_generator_row.go new file mode 100644 index 0000000..f9b08f4 --- /dev/null +++ b/database/create_datastore_id_generator_row.go @@ -0,0 +1,9 @@ +package database + +import "log" + +func CreateDataStoreIDGeneratorRow(nodeID int) { + if err := cassandraClusterSession.Query(`INSERT INTO pretendo_smm.generator_last_id(node_id, last_id) VALUES (?, ?) IF NOT EXISTS`, nodeID, 0).Exec(); err != nil { + log.Fatal(err) + } +} diff --git a/datastore_id_generator.go b/database/datastore_id_generator.go similarity index 98% rename from datastore_id_generator.go rename to database/datastore_id_generator.go index 6be5b39..fcc7297 100644 --- a/datastore_id_generator.go +++ b/database/datastore_id_generator.go @@ -1,4 +1,4 @@ -package main +package database import ( "encoding/binary" diff --git a/database/get_buffer_queue_death_data.go b/database/get_buffer_queue_death_data.go new file mode 100644 index 0000000..3cb3eda --- /dev/null +++ b/database/get_buffer_queue_death_data.go @@ -0,0 +1,20 @@ +package database + +import "log" + +func GetBufferQueueDeathData(dataID uint64) [][]byte { + pBufferQueue := make([][]byte, 0) + + var sliceMap []map[string]interface{} + var err error + + if sliceMap, err = cassandraClusterSession.Query(`SELECT buffer FROM pretendo_smm.buffer_queues WHERE data_id=? AND slot=3 ALLOW FILTERING`, dataID).Iter().SliceMap(); err != nil { + log.Fatal(err) + } + + for _, bufferQueue := range sliceMap { + pBufferQueue = append(pBufferQueue, bufferQueue["buffer"].([]byte)) + } + + return pBufferQueue +} diff --git a/database/get_course_metadata_by_data_id.go b/database/get_course_metadata_by_data_id.go new file mode 100644 index 0000000..a052a10 --- /dev/null +++ b/database/get_course_metadata_by_data_id.go @@ -0,0 +1,57 @@ +package database + +import ( + "log" + + "github.com/PretendoNetwork/nex-go" + "github.com/PretendoNetwork/super-mario-maker-secure/types" + "github.com/gocql/gocql" +) + +func GetCourseMetadataByDataID(dataID uint64) *types.CourseMetadata { + var ownerPID uint32 + var size uint32 + var name string + var metaBinary []byte + var flag uint32 + var createdTime uint64 + var updatedTime uint64 + var dataType uint16 + var period uint16 + + err := cassandraClusterSession.Query(`SELECT owner_pid, size, name, meta_binary, flag, creation_date, update_date, data_type, period FROM pretendo_smm.courses WHERE data_id=?`, dataID).Scan(&ownerPID, &size, &name, &metaBinary, &flag, &createdTime, &updatedTime, &dataType, &period) + + if err != nil { + if err == gocql.ErrNotFound { + return nil + } else { + log.Fatal(err) + } + } + + var stars uint32 + var attempts uint32 + var failures uint32 + var completions uint32 + + _ = cassandraClusterSession.Query(`SELECT stars, attempts, failures, completions FROM pretendo_smm.ratings WHERE data_id=?`, dataID).Scan(&stars, &attempts, &failures, &completions) + + courseMetadata := &types.CourseMetadata{ + DataID: dataID, + OwnerPID: ownerPID, + Size: size, + CreatedTime: nex.NewDateTime(createdTime), + UpdatedTime: nex.NewDateTime(updatedTime), + Name: name, + MetaBinary: metaBinary, + Stars: stars, + Attempts: attempts, + Failures: failures, + Completions: completions, + Flag: flag, + DataType: dataType, + Period: period, + } + + return courseMetadata +} diff --git a/database/get_course_metadata_by_data_ids.go b/database/get_course_metadata_by_data_ids.go new file mode 100644 index 0000000..49f2185 --- /dev/null +++ b/database/get_course_metadata_by_data_ids.go @@ -0,0 +1,18 @@ +package database + +import "github.com/PretendoNetwork/super-mario-maker-secure/types" + +func GetCourseMetadataByDataIDs(dataIDs []uint64) []*types.CourseMetadata { + // TODO: Do this in one query? + courseMetadatas := make([]*types.CourseMetadata, 0) + + for _, dataID := range dataIDs { + courseMetadata := GetCourseMetadataByDataID(dataID) + + if courseMetadata != nil { + courseMetadatas = append(courseMetadatas, courseMetadata) + } + } + + return courseMetadatas +} diff --git a/database/get_course_metadatas_by_limit.go b/database/get_course_metadatas_by_limit.go new file mode 100644 index 0000000..3c5d07a --- /dev/null +++ b/database/get_course_metadatas_by_limit.go @@ -0,0 +1,51 @@ +package database + +import ( + "log" + + "github.com/PretendoNetwork/nex-go" + "github.com/PretendoNetwork/super-mario-maker-secure/types" +) + +func GetCourseMetadatasByLimit(limit uint32) []*types.CourseMetadata { + var sliceMap []map[string]interface{} + var err error + + if sliceMap, err = cassandraClusterSession.Query(`SELECT data_id, owner_pid, size, name, meta_binary, flag, creation_date, update_date, data_type, period FROM pretendo_smm.courses LIMIT ?`, limit).Iter().SliceMap(); err != nil { + log.Fatal(err) + } + + courseMetadatas := make([]*types.CourseMetadata, 0) + + for _, course := range sliceMap { + dataID := uint64(course["data_id"].(int64)) + + var stars uint32 + var attempts uint32 + var failures uint32 + var completions uint32 + + _ = cassandraClusterSession.Query(`SELECT stars, attempts, failures, completions FROM pretendo_smm.ratings WHERE data_id=?`, dataID).Scan(&stars, &attempts, &failures, &completions) + + courseMetadata := &types.CourseMetadata{ + DataID: dataID, + OwnerPID: uint32(course["owner_pid"].(int)), + Size: uint32(course["size"].(int)), + CreatedTime: nex.NewDateTime(uint64(course["creation_date"].(int64))), + UpdatedTime: nex.NewDateTime(uint64(course["update_date"].(int64))), + Name: course["name"].(string), + MetaBinary: course["meta_binary"].([]byte), + Stars: stars, + Attempts: attempts, + Failures: failures, + Completions: completions, + Flag: uint32(course["flag"].(int)), + DataType: uint16(course["data_type"].(int16)), + Period: uint16(course["period"].(int16)), + } + + courseMetadatas = append(courseMetadatas, courseMetadata) + } + + return courseMetadatas +} diff --git a/database/get_course_metadatas_by_pid.go b/database/get_course_metadatas_by_pid.go new file mode 100644 index 0000000..bacb4ec --- /dev/null +++ b/database/get_course_metadatas_by_pid.go @@ -0,0 +1,26 @@ +package database + +import ( + "log" + + "github.com/PretendoNetwork/super-mario-maker-secure/types" +) + +func GetCourseMetadatasByPID(pid uint32) []*types.CourseMetadata { + courseMetadatas := make([]*types.CourseMetadata, 0) + + // TODO: Fix this query? Seems like a weird way of doing this... + var sliceMap []map[string]interface{} + var err error + + if sliceMap, err = cassandraClusterSession.Query(`SELECT data_id FROM pretendo_smm.courses WHERE owner_pid=? ALLOW FILTERING`, pid).Iter().SliceMap(); err != nil { + log.Fatal(err) + } + + for _, course := range sliceMap { + dataID := uint64(course["data_id"].(int64)) + courseMetadatas = append(courseMetadatas, GetCourseMetadataByDataID(dataID)) + } + + return courseMetadatas +} diff --git a/database/get_course_world_record.go b/database/get_course_world_record.go new file mode 100644 index 0000000..f95fb39 --- /dev/null +++ b/database/get_course_world_record.go @@ -0,0 +1,28 @@ +package database + +import ( + "github.com/PretendoNetwork/nex-go" + "github.com/PretendoNetwork/super-mario-maker-secure/types" +) + +func GetCourseWorldRecord(dataID uint64) *types.CourseWorldRecord { + var worldRecordFirstPID uint32 + var worldRecordPID uint32 + var worldRecordCreatedTime uint64 + var worldRecordUpdatedTime uint64 + var worldRecord int32 + + _ = cassandraClusterSession.Query(`SELECT world_record_first_pid, world_record_pid, world_record_creation_date, world_record_update_date, world_record FROM pretendo_smm.courses WHERE data_id=?`, dataID).Scan(&worldRecordFirstPID, &worldRecordPID, &worldRecordCreatedTime, &worldRecordUpdatedTime, &worldRecord) + + if worldRecordFirstPID == 0 { + return nil + } + + return &types.CourseWorldRecord{ + FirstPID: worldRecordFirstPID, + BestPID: worldRecordPID, + CreatedTime: nex.NewDateTime(worldRecordCreatedTime), + UpdatedTime: nex.NewDateTime(worldRecordUpdatedTime), + Score: worldRecord, + } +} diff --git a/database/get_datastore_id_generator_last_id.go b/database/get_datastore_id_generator_last_id.go new file mode 100644 index 0000000..413f2bb --- /dev/null +++ b/database/get_datastore_id_generator_last_id.go @@ -0,0 +1,8 @@ +package database + +func GetDataStoreIDGeneratorLastID(nodeID int) uint32 { + var lastID uint32 + _ = cassandraClusterSession.Query(`SELECT last_id FROM pretendo_smm.generator_last_id WHERE node_id=?`, nodeID).Scan(&lastID) + + return lastID +} diff --git a/database/get_user_mii_info_by_pid.go b/database/get_user_mii_info_by_pid.go new file mode 100644 index 0000000..c4d4582 --- /dev/null +++ b/database/get_user_mii_info_by_pid.go @@ -0,0 +1,25 @@ +package database + +import ( + "context" + + "go.mongodb.org/mongo-driver/bson" + "go.mongodb.org/mongo-driver/mongo" + "go.mongodb.org/mongo-driver/mongo/options" +) + +func GetUserMiiInfoByPID(pid uint32) bson.M { + var result bson.M + + err := mongoCollection.FindOne(context.TODO(), bson.D{{Key: "pid", Value: pid}}, options.FindOne()).Decode(&result) + + if err != nil { + if err == mongo.ErrNoDocuments { + return nil + } + + panic(err) + } + + return result["mii"].(bson.M) +} diff --git a/database/get_user_starred_courses.go b/database/get_user_starred_courses.go new file mode 100644 index 0000000..a2a09ca --- /dev/null +++ b/database/get_user_starred_courses.go @@ -0,0 +1,10 @@ +package database + +import "github.com/PretendoNetwork/super-mario-maker-secure/types" + +func GetUserStarredCourses(pid uint32) []*types.CourseMetadata { + var dataIDs []uint64 + _ = cassandraClusterSession.Query(`SELECT starred_courses FROM pretendo_smm.user_play_info WHERE pid=?`, pid).Scan(&dataIDs) + + return GetCourseMetadataByDataIDs(dataIDs) +} diff --git a/database/increment_course_attempt_count.go b/database/increment_course_attempt_count.go new file mode 100644 index 0000000..acd18f7 --- /dev/null +++ b/database/increment_course_attempt_count.go @@ -0,0 +1,9 @@ +package database + +import "log" + +func IncrementCourseAttemptCount(courseID uint64) { + if err := cassandraClusterSession.Query(`UPDATE pretendo_smm.ratings SET attempts=attempts+1 WHERE data_id=?`, courseID).Exec(); err != nil { + log.Fatal(err) + } +} diff --git a/database/increment_course_clear_count.go b/database/increment_course_clear_count.go new file mode 100644 index 0000000..9ed27b9 --- /dev/null +++ b/database/increment_course_clear_count.go @@ -0,0 +1,9 @@ +package database + +import "log" + +func IncrementCourseClearCount(courseID uint64) { + if err := cassandraClusterSession.Query(`UPDATE pretendo_smm.ratings SET completions=completions+1 WHERE data_id=?`, courseID).Exec(); err != nil { + log.Fatal(err) + } +} diff --git a/database/increment_course_fail_count.go b/database/increment_course_fail_count.go new file mode 100644 index 0000000..3d67413 --- /dev/null +++ b/database/increment_course_fail_count.go @@ -0,0 +1,9 @@ +package database + +import "log" + +func IncrementCourseFailCount(courseID uint64) { + if err := cassandraClusterSession.Query(`UPDATE pretendo_smm.ratings SET failures=failures+1 WHERE data_id=?`, courseID).Exec(); err != nil { + log.Fatal(err) + } +} diff --git a/database/increment_course_star_count.go b/database/increment_course_star_count.go new file mode 100644 index 0000000..6214414 --- /dev/null +++ b/database/increment_course_star_count.go @@ -0,0 +1,9 @@ +package database + +import "log" + +func IncrementCourseStarCount(courseID uint64) { + if err := cassandraClusterSession.Query(`UPDATE pretendo_smm.ratings SET stars=stars+1 WHERE data_id=?`, courseID).Exec(); err != nil { + log.Fatal(err) + } +} diff --git a/database/initialize_course_data.go b/database/initialize_course_data.go new file mode 100644 index 0000000..34a2493 --- /dev/null +++ b/database/initialize_course_data.go @@ -0,0 +1,56 @@ +package database + +import ( + "log" + + "github.com/PretendoNetwork/nex-go" +) + +func InitializeCourseData(courseID uint64, ownerPID uint32, size uint32, name string, flag uint32, extraData []string, dataType uint16, period uint16) { + datetime := nex.NewDateTime(0) + now := datetime.Now() + + if err := cassandraClusterSession.Query(`INSERT INTO pretendo_smm.courses( + data_id, + owner_pid, + size, + name, + flag, + extra_data, + playable, + creation_date, + update_date, + world_record_first_pid, + world_record_pid, + world_record_creation_date, + world_record_update_date, + world_record, + data_type, + period + ) + VALUES ( + ?, + ?, + ?, + ?, + ?, + ?, + false, + ?, + ?, + 0, + 0, + 0, + 0, + 0, + ?, + ? + ) IF NOT EXISTS`, + courseID, ownerPID, size, name, flag, extraData, now, now, dataType, period).Exec(); err != nil { + log.Fatal(err) + } + + if err := cassandraClusterSession.Query(`UPDATE pretendo_smm.ratings SET stars=stars+0, attempts=attempts+0, failures=failures+0, completions=completions+0 WHERE data_id=?`, courseID).Exec(); err != nil { + log.Fatal(err) + } +} diff --git a/database/insert_buffer_queue_data.go b/database/insert_buffer_queue_data.go new file mode 100644 index 0000000..2a8b593 --- /dev/null +++ b/database/insert_buffer_queue_data.go @@ -0,0 +1,9 @@ +package database + +import "log" + +func InsertBufferQueueData(dataID uint64, slot uint32, buffer []byte) { + if err := cassandraClusterSession.Query(`INSERT INTO pretendo_smm.buffer_queues( id, data_id, slot, buffer ) VALUES ( now(), ?, ?, ? ) IF NOT EXISTS`, dataID, slot, buffer).Exec(); err != nil { + log.Fatal(err) + } +} diff --git a/database/set_course_playable.go b/database/set_course_playable.go new file mode 100644 index 0000000..fed5b2f --- /dev/null +++ b/database/set_course_playable.go @@ -0,0 +1,9 @@ +package database + +import "log" + +func SetCoursePlayable(courseID uint64) { + if err := cassandraClusterSession.Query(`UPDATE pretendo_smm.courses SET playable=true WHERE data_id=?`, courseID).Exec(); err != nil { + log.Fatal(err) + } +} diff --git a/database/set_datastore_id_generator_last_id.go b/database/set_datastore_id_generator_last_id.go new file mode 100644 index 0000000..0eef04a --- /dev/null +++ b/database/set_datastore_id_generator_last_id.go @@ -0,0 +1,9 @@ +package database + +import "log" + +func SetDataStoreIDGeneratorLastID(nodeID int, value uint32) { + if err := cassandraClusterSession.Query(`UPDATE pretendo_smm.generator_last_id SET last_id=? WHERE node_id=?`, value, nodeID).Exec(); err != nil { + log.Fatal(err) + } +} diff --git a/database/update_course_meta_binary.go b/database/update_course_meta_binary.go new file mode 100644 index 0000000..39a53e5 --- /dev/null +++ b/database/update_course_meta_binary.go @@ -0,0 +1,9 @@ +package database + +import "log" + +func UpdateCourseMetaBinary(courseID uint64, metaBinary []byte) { + if err := cassandraClusterSession.Query(`UPDATE pretendo_smm.courses SET meta_binary=? WHERE data_id=?`, metaBinary, courseID).Exec(); err != nil { + log.Fatal(err) + } +} diff --git a/database/update_course_world_record.go b/database/update_course_world_record.go new file mode 100644 index 0000000..17d1256 --- /dev/null +++ b/database/update_course_world_record.go @@ -0,0 +1,22 @@ +package database + +import ( + "log" + + "github.com/PretendoNetwork/nex-go" +) + +func UpdateCourseWorldRecord(courseID uint64, ownerPID uint32, score int32) { + datetime := nex.NewDateTime(0) + now := datetime.Now() + + if GetCourseWorldRecord(courseID) == nil { + if err := cassandraClusterSession.Query(`UPDATE pretendo_smm.courses SET world_record_first_pid=?, world_record_creation_date=? WHERE data_id=?`, ownerPID, now, courseID).Exec(); err != nil { + log.Fatal(err) + } + } + + if err := cassandraClusterSession.Query(`UPDATE pretendo_smm.courses SET world_record_pid=?, world_record_update_date=?, world_record=? WHERE data_id=?`, ownerPID, now, score, courseID).Exec(); err != nil { + log.Fatal(err) + } +} diff --git a/followings_latest_course_search_object.go b/followings_latest_course_search_object.go deleted file mode 100644 index 93ca545..0000000 --- a/followings_latest_course_search_object.go +++ /dev/null @@ -1,42 +0,0 @@ -package main - -import ( - nex "github.com/PretendoNetwork/nex-go" - nexproto "github.com/PretendoNetwork/nex-protocols-go" -) - -func followingsLatestCourseSearchObject(err error, client *nex.Client, callID uint32, dataStoreSearchParam *nexproto.DataStoreSearchParam, extraData []string) { - pRankingResults := make([]*nexproto.DataStoreCustomRankingResult, 0) - - for _, pid := range dataStoreSearchParam.OwnerIds { - courseMetadatas := getCourseMetadatasByPID(pid) - - for _, courseMetadata := range courseMetadatas { - pRankingResults = append(pRankingResults, courseMetadataToDataStoreCustomRankingResult(courseMetadata)) - } - } - - rmcResponseStream := nex.NewStreamOut(nexServer) - - rmcResponseStream.WriteListStructure(pRankingResults) - - rmcResponseBody := rmcResponseStream.Bytes() - - rmcResponse := nex.NewRMCResponse(nexproto.DataStoreSMMProtocolID, callID) - rmcResponse.SetSuccess(nexproto.DataStoreSMMMethodFollowingsLatestCourseSearchObject, rmcResponseBody) - - rmcResponseBytes := rmcResponse.Bytes() - - responsePacket, _ := nex.NewPacketV1(client, nil) - - responsePacket.SetVersion(1) - responsePacket.SetSource(0xA1) - responsePacket.SetDestination(0xAF) - responsePacket.SetType(nex.DataPacket) - responsePacket.SetPayload(rmcResponseBytes) - - responsePacket.AddFlag(nex.FlagNeedsAck) - responsePacket.AddFlag(nex.FlagReliable) - - nexServer.Send(responsePacket) -} diff --git a/get_custom_ranking_by_data_id.go b/get_custom_ranking_by_data_id.go deleted file mode 100644 index 2c89892..0000000 --- a/get_custom_ranking_by_data_id.go +++ /dev/null @@ -1,94 +0,0 @@ -package main - -import ( - nex "github.com/PretendoNetwork/nex-go" - nexproto "github.com/PretendoNetwork/nex-protocols-go" -) - -func getCustomRankingByDataId(err error, client *nex.Client, callID uint32, param *nexproto.DataStoreGetCustomRankingByDataIdParam) { - var pRankingResult []*nexproto.DataStoreCustomRankingResult - var pResults []uint32 - - switch param.ApplicationId { - case 0: - if len(param.DataIdList) == 0 { // Starred courses - pRankingResult, pResults = getCustomRankingByDataIdStarredCourses(client.PID()) - } else { // Played courses - pRankingResult, pResults = getCustomRankingByDataIdCourseMetadata(param) - } - case 300000000: // Mii data - pRankingResult, pResults = getCustomRankingByDataIdMiiData(param) - default: // Normal metadata - pRankingResult, pResults = getCustomRankingByDataIdCourseMetadata(param) - } - - rmcResponseStream := nex.NewStreamOut(nexServer) - - rmcResponseStream.WriteListStructure(pRankingResult) - rmcResponseStream.WriteListUInt32LE(pResults) - - rmcResponseBody := rmcResponseStream.Bytes() - - rmcResponse := nex.NewRMCResponse(nexproto.DataStoreProtocolID, callID) - rmcResponse.SetSuccess(nexproto.DataStoreSMMMethodGetCustomRankingByDataId, rmcResponseBody) - - rmcResponseBytes := rmcResponse.Bytes() - - responsePacket, _ := nex.NewPacketV1(client, nil) - - responsePacket.SetVersion(1) - 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 getCustomRankingByDataIdStarredCourses(pid uint32) ([]*nexproto.DataStoreCustomRankingResult, []uint32) { - courseMetadatas := getUserStarredCourses(pid) - - pRankingResult := make([]*nexproto.DataStoreCustomRankingResult, 0) - pResults := make([]uint32, 0) - - for _, courseMetadata := range courseMetadatas { - pRankingResult = append(pRankingResult, courseMetadataToDataStoreCustomRankingResult(courseMetadata)) - pResults = append(pResults, 0x690001) - } - - return pRankingResult, pResults -} - -func getCustomRankingByDataIdMiiData(param *nexproto.DataStoreGetCustomRankingByDataIdParam) ([]*nexproto.DataStoreCustomRankingResult, []uint32) { - pRankingResult := make([]*nexproto.DataStoreCustomRankingResult, 0) - pResults := make([]uint32, 0) - - for _, pid := range param.DataIdList { - pid := uint32(pid) - miiInfo := getUserMiiInfoByPID(pid) // This isn't actually a PID when using the official servers! I set it as one to make this easier for me - - if miiInfo != nil { - pRankingResult = append(pRankingResult, userMiiDataToDataStoreCustomRankingResult(pid, miiInfo)) - pResults = append(pResults, 0x690001) - } - } - - return pRankingResult, pResults -} - -func getCustomRankingByDataIdCourseMetadata(param *nexproto.DataStoreGetCustomRankingByDataIdParam) ([]*nexproto.DataStoreCustomRankingResult, []uint32) { - courseMetadatas := getCourseMetadataByDataIDs(param.DataIdList) - - pRankingResult := make([]*nexproto.DataStoreCustomRankingResult, 0) - pResults := make([]uint32, 0) - - for _, courseMetadata := range courseMetadatas { - pRankingResult = append(pRankingResult, courseMetadataToDataStoreCustomRankingResult(courseMetadata)) - pResults = append(pResults, 0x690001) - } - - return pRankingResult, pResults -} diff --git a/get_metas_multiple_param.go b/get_metas_multiple_param.go deleted file mode 100644 index 216575d..0000000 --- a/get_metas_multiple_param.go +++ /dev/null @@ -1,54 +0,0 @@ -package main - -import ( - "fmt" - - nex "github.com/PretendoNetwork/nex-go" - nexproto "github.com/PretendoNetwork/nex-protocols-go" -) - -func getMetasMultipleParam(err error, client *nex.Client, callID uint32, params []*nexproto.DataStoreGetMetaParam) { - pMetaInfo := make([]*nexproto.DataStoreMetaInfo, 0) - pResults := make([]uint32, 0) - - for _, param := range params { - if param.DataID == 0 { - pMetaInfo = append(pMetaInfo, getMetasMultipleParamMiiData(param)) - } else { - fmt.Println("Unknown meta multiple data ID") - } - - pResults = append(pResults, 0x690001) - } - - rmcResponseStream := nex.NewStreamOut(nexServer) - - rmcResponseStream.WriteListStructure(pMetaInfo) - rmcResponseStream.WriteListUInt32LE(pResults) - - rmcResponseBody := rmcResponseStream.Bytes() - - rmcResponse := nex.NewRMCResponse(nexproto.DataStoreSMMProtocolID, callID) - rmcResponse.SetSuccess(nexproto.DataStoreMethodGetMetasMultipleParam, rmcResponseBody) - - rmcResponseBytes := rmcResponse.Bytes() - - responsePacket, _ := nex.NewPacketV1(client, nil) - - responsePacket.SetVersion(1) - 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 getMetasMultipleParamMiiData(param *nexproto.DataStoreGetMetaParam) *nexproto.DataStoreMetaInfo { - miiInfo := getUserMiiInfoByPID(param.PersistenceTarget.OwnerID) - - return userMiiDataToDataStoreMetaInfo(param.PersistenceTarget.OwnerID, miiInfo) -} diff --git a/get_metas_with_course_record.go b/get_metas_with_course_record.go deleted file mode 100644 index 01d4770..0000000 --- a/get_metas_with_course_record.go +++ /dev/null @@ -1,36 +0,0 @@ -package main - -import ( - nex "github.com/PretendoNetwork/nex-go" - nexproto "github.com/PretendoNetwork/nex-protocols-go" -) - -func getMetasWithCourseRecord(err error, client *nex.Client, callID uint32, dataStoreGetCourseRecordParams []*nexproto.DataStoreGetCourseRecordParam, dataStoreGetMetaParam *nexproto.DataStoreGetMetaParam) { - // TODO: complete this - - rmcResponseStream := nex.NewStreamOut(nexServer) - - rmcResponseStream.WriteUInt32LE(0x00000000) // pMetaInfo List length 0 - rmcResponseStream.WriteUInt32LE(0x00000000) // pCourseResults List length 0 - rmcResponseStream.WriteUInt32LE(0x00000000) // pResults List length 0 - - rmcResponseBody := rmcResponseStream.Bytes() - - rmcResponse := nex.NewRMCResponse(nexproto.DataStoreSMMProtocolID, callID) - rmcResponse.SetSuccess(nexproto.DataStoreSMMMethodGetMetasWithCourseRecord, rmcResponseBody) - - rmcResponseBytes := rmcResponse.Bytes() - - responsePacket, _ := nex.NewPacketV1(client, nil) - - responsePacket.SetVersion(1) - responsePacket.SetSource(0xA1) - responsePacket.SetDestination(0xAF) - responsePacket.SetType(nex.DataPacket) - responsePacket.SetPayload(rmcResponseBytes) - - responsePacket.AddFlag(nex.FlagNeedsAck) - responsePacket.AddFlag(nex.FlagReliable) - - nexServer.Send(responsePacket) -} diff --git a/get_object_infos.go b/get_object_infos.go deleted file mode 100644 index e22629e..0000000 --- a/get_object_infos.go +++ /dev/null @@ -1,52 +0,0 @@ -package main - -import ( - "fmt" - "os" - - nex "github.com/PretendoNetwork/nex-go" - nexproto "github.com/PretendoNetwork/nex-protocols-go" -) - -func getObjectInfos(err error, client *nex.Client, callID uint32, dataIDs []uint64) { - pInfos := make([]*nexproto.DataStoreFileServerObjectInfo, 0) - - courseMetadatas := getCourseMetadataByDataIDs(dataIDs) - - for _, courseMetadata := range courseMetadatas { - info := nexproto.NewDataStoreFileServerObjectInfo() - info.DataID = courseMetadata.DataID - info.GetInfo = nexproto.NewDataStoreReqGetInfo() - info.GetInfo.URL = fmt.Sprintf("http://%s.b-cdn.net/course/%d.bin", os.Getenv("S3_BUCKET_NAME"), courseMetadata.DataID) - info.GetInfo.RequestHeaders = []*nexproto.DataStoreKeyValue{} - info.GetInfo.Size = courseMetadata.Size - info.GetInfo.RootCA = []byte{} - info.GetInfo.DataID = courseMetadata.DataID - - pInfos = append(pInfos, info) - } - - rmcResponseStream := nex.NewStreamOut(nexServer) - - rmcResponseStream.WriteListStructure(pInfos) - - rmcResponseBody := rmcResponseStream.Bytes() - - rmcResponse := nex.NewRMCResponse(nexproto.DataStoreProtocolID, callID) - rmcResponse.SetSuccess(nexproto.DataStoreSMMMethodGetObjectInfos, rmcResponseBody) - - rmcResponseBytes := rmcResponse.Bytes() - - responsePacket, _ := nex.NewPacketV1(client, nil) - - responsePacket.SetVersion(1) - responsePacket.SetSource(0xA1) - responsePacket.SetDestination(0xAF) - responsePacket.SetType(nex.DataPacket) - responsePacket.SetPayload(rmcResponseBytes) - - responsePacket.AddFlag(nex.FlagNeedsAck) - responsePacket.AddFlag(nex.FlagReliable) - - nexServer.Send(responsePacket) -} diff --git a/globals/globals.go b/globals/globals.go new file mode 100644 index 0000000..22539b8 --- /dev/null +++ b/globals/globals.go @@ -0,0 +1,14 @@ +package globals + +import ( + "github.com/PretendoNetwork/nex-go" + "github.com/PretendoNetwork/plogger-go" + "github.com/PretendoNetwork/super-mario-maker-secure/database" + "github.com/aws/aws-sdk-go-v2/service/s3" +) + +var Logger = plogger.NewLogger() +var NEXServer *nex.Server +var S3Client *s3.Client +var HMACSecret []byte +var DataStoreIDGenerators []*database.DataStoreIDGenerator diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..f9b2f68 --- /dev/null +++ b/go.mod @@ -0,0 +1,48 @@ +module github.com/PretendoNetwork/super-mario-maker-secure + +go 1.19 + +require ( + github.com/PretendoNetwork/nex-go v1.0.16 + github.com/PretendoNetwork/nex-protocols-common-go v1.0.17 + github.com/PretendoNetwork/nex-protocols-go v1.0.20 + github.com/PretendoNetwork/plogger-go v1.0.2 + github.com/aws/aws-sdk-go-v2/service/s3 v1.31.2 + github.com/gocql/gocql v1.3.2 + github.com/joho/godotenv v1.5.1 + go.mongodb.org/mongo-driver v1.11.4 +) + +require ( + github.com/aws/aws-sdk-go-v2 v1.17.8 // indirect + github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.10 // indirect + github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.32 // indirect + github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.26 // indirect + github.com/aws/aws-sdk-go-v2/internal/v4a v1.0.24 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.9.11 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.1.27 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.26 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.14.1 // indirect + github.com/aws/smithy-go v1.13.5 // indirect + github.com/fatih/color v1.15.0 // indirect + github.com/golang/snappy v0.0.3 // indirect + github.com/hailocab/go-hostpool v0.0.0-20160125115350-e80d13ce29ed // indirect + github.com/jwalton/go-supportscolor v1.1.0 // indirect + github.com/klauspost/compress v1.13.6 // indirect + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.18 // indirect + github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe // indirect + github.com/pkg/errors v0.9.1 // indirect + github.com/superwhiskers/crunch/v3 v3.5.7 // indirect + github.com/xdg-go/pbkdf2 v1.0.0 // indirect + github.com/xdg-go/scram v1.1.1 // indirect + github.com/xdg-go/stringprep v1.0.3 // indirect + github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d // indirect + golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d // indirect + golang.org/x/exp v0.0.0-20230321023759-10a507213a29 // indirect + golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4 // indirect + golang.org/x/sys v0.7.0 // indirect + golang.org/x/term v0.7.0 // indirect + golang.org/x/text v0.4.0 // indirect + gopkg.in/inf.v0 v0.9.1 // indirect +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..1a1a9fc --- /dev/null +++ b/go.sum @@ -0,0 +1,125 @@ +github.com/PretendoNetwork/nex-go v1.0.16 h1:g2lJW8G+WOS6/8qsgQ0+jLlzemjJ60tQtLqloLTjElo= +github.com/PretendoNetwork/nex-go v1.0.16/go.mod h1:Bx2ONeSefnbJyE0IDIwGopxrjRrnszOV/uQv74Cx+m0= +github.com/PretendoNetwork/nex-protocols-common-go v1.0.17 h1:w0n+RJAHANgX/iVnL5qRiyPJeDHcwr8w6DzDeFqxkqk= +github.com/PretendoNetwork/nex-protocols-common-go v1.0.17/go.mod h1:5Y3jRIbvDxasj0CIvd024za+t9LMbD0OZkBwyKICijg= +github.com/PretendoNetwork/nex-protocols-go v1.0.20 h1:vUoYHFvVWWx9Bm9/2JiN1siW03tFxtD4NY9w/WfC878= +github.com/PretendoNetwork/nex-protocols-go v1.0.20/go.mod h1:Bt7hI7hJ+8r6UU5LSs+3xx4xzsvMVeEUkAW8Cg3lGjQ= +github.com/PretendoNetwork/plogger-go v1.0.2 h1:vWKEnEmJJzYwqLxLyiSsAvCrZV6qnnu/a0GQOjIfzY0= +github.com/PretendoNetwork/plogger-go v1.0.2/go.mod h1:7kD6M4vPq1JL4LTuPg6kuB1OvUBOwQOtAvTaUwMbwvU= +github.com/aws/aws-sdk-go-v2 v1.17.8 h1:GMupCNNI7FARX27L7GjCJM8NgivWbRgpjNI/hOQjFS8= +github.com/aws/aws-sdk-go-v2 v1.17.8/go.mod h1:uzbQtefpm44goOPmdKyAlXSNcwlRgF3ePWVW6EtJvvw= +github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.10 h1:dK82zF6kkPeCo8J1e+tGx4JdvDIQzj7ygIoLg8WMuGs= +github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.10/go.mod h1:VeTZetY5KRJLuD/7fkQXMU6Mw7H5m/KP2J5Iy9osMno= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.32 h1:dpbVNUjczQ8Ae3QKHbpHBpfvaVkRdesxpTOe9pTouhU= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.32/go.mod h1:RudqOgadTWdcS3t/erPQo24pcVEoYyqj/kKW5Vya21I= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.26 h1:QH2kOS3Ht7x+u0gHCh06CXL/h6G8LQJFpZfFBYBNboo= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.26/go.mod h1:vq86l7956VgFr0/FWQ2BWnK07QC3WYsepKzy33qqY5U= +github.com/aws/aws-sdk-go-v2/internal/v4a v1.0.24 h1:zsg+5ouVLLbePknVZlUMm1ptwyQLkjjLMWnN+kVs5dA= +github.com/aws/aws-sdk-go-v2/internal/v4a v1.0.24/go.mod h1:+fFaIjycTmpV6hjmPTbyU9Kp5MI/lA+bbibcAtmlhYA= +github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.9.11 h1:y2+VQzC6Zh2ojtV2LoC0MNwHWc6qXv/j2vrQtlftkdA= +github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.9.11/go.mod h1:iV4q2hsqtNECrfmlXyord9u4zyuFEJX9eLgLpSPzWA8= +github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.1.27 h1:qIw7Hg5eJEc1uSxg3hRwAthPAO7NeOd4dPxhaTi0yB0= +github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.1.27/go.mod h1:Zz0kvhcSlu3NX4XJkaGgdjaa+u7a9LYuy8JKxA5v3RM= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.26 h1:uUt4XctZLhl9wBE1L8lobU3bVN8SNUP7T+olb0bWBO4= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.26/go.mod h1:Bd4C/4PkVGubtNe5iMXu5BNnaBi/9t/UsFspPt4ram8= +github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.14.1 h1:lRWp3bNu5wy0X3a8GS42JvZFlv++AKsMdzEnoiVJrkg= +github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.14.1/go.mod h1:VXBHSxdN46bsJrkniN68psSwbyBKsazQfU2yX/iSDso= +github.com/aws/aws-sdk-go-v2/service/s3 v1.31.2 h1:iOZoYePk+EuBI1tC7bxeRjO+JvClcYm2fZYW5WPIOMQ= +github.com/aws/aws-sdk-go-v2/service/s3 v1.31.2/go.mod h1:aSl9/LJltSz1cVusiR/Mu8tvI4Sv/5w/WWrJmmkNii0= +github.com/aws/smithy-go v1.13.5 h1:hgz0X/DX0dGqTYpGALqXJoRKRj5oQ7150i5FdTePzO8= +github.com/aws/smithy-go v1.13.5/go.mod h1:Tg+OJXh4MB2R/uN61Ko2f6hTZwB/ZYGOtib8J3gBHzA= +github.com/bitly/go-hostpool v0.0.0-20171023180738-a3a6125de932 h1:mXoPYz/Ul5HYEDvkta6I8/rnYM5gSdSV2tJ6XbZuEtY= +github.com/bitly/go-hostpool v0.0.0-20171023180738-a3a6125de932/go.mod h1:NOuUCSz6Q9T7+igc/hlvDOUdtWKryOrtFyIVABv/p7k= +github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869 h1:DDGfHa7BWjL4YnC6+E63dPcxHo2sUxDIu8g3QgEJdRY= +github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4= +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/fatih/color v1.15.0 h1:kOqh6YHBtK8aywxGerMG2Eq3H6Qgoqeo13Bk2Mv/nBs= +github.com/fatih/color v1.15.0/go.mod h1:0h5ZqXfHYED7Bhv2ZJamyIOUej9KtShiJESRwBDUSsw= +github.com/gocql/gocql v1.3.2 h1:ox3T+R7VFibHSIGxRkuUi1uIvAv8jBHCWxc+9aFQ/LA= +github.com/gocql/gocql v1.3.2/go.mod h1:3gM2c4D3AnkISwBxGnMMsS8Oy4y2lhbPRsH4xnJrHG8= +github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/golang/snappy v0.0.3 h1:fHPg5GQYlCeLIPB9BZqMVR5nR9A+IM5zcgeTdjMYmLA= +github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg= +github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/hailocab/go-hostpool v0.0.0-20160125115350-e80d13ce29ed h1:5upAirOpQc1Q53c0bnx2ufif5kANL7bfZWcc6VJWJd8= +github.com/hailocab/go-hostpool v0.0.0-20160125115350-e80d13ce29ed/go.mod h1:tMWxXQ9wFIaZeTI9F+hmhFiGpFmhOHzyShyFUhRm0H4= +github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= +github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= +github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= +github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= +github.com/jwalton/go-supportscolor v1.1.0 h1:HsXFJdMPjRUAx8cIW6g30hVSFYaxh9yRQwEWgkAR7lQ= +github.com/jwalton/go-supportscolor v1.1.0/go.mod h1:hFVUAZV2cWg+WFFC4v8pT2X/S2qUUBYMioBD9AINXGs= +github.com/klauspost/compress v1.13.6 h1:P76CopJELS0TiO2mebmnzgWaajssP/EszplttgQxcgc= +github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= +github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.18 h1:DOKFKCQ7FNG2L1rbrmstDN4QVRdS89Nkh85u68Uwp98= +github.com/mattn/go-isatty v0.0.18/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe h1:iruDEfMl2E6fbMZ9s0scYfZQ84/6SPL6zC8ACM2oIL0= +github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +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 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0= +github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/superwhiskers/crunch/v3 v3.5.7 h1:N9RLxaR65C36i26BUIpzPXGy2f6pQ7wisu2bawbKNqg= +github.com/superwhiskers/crunch/v3 v3.5.7/go.mod h1:4ub2EKgF1MAhTjoOCTU4b9uLMsAweHEa89aRrfAypXA= +github.com/tidwall/pretty v1.0.0 h1:HsD+QiTn7sK6flMKIvNmpqz1qrpP3Ps6jOKIKMooyg4= +github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= +github.com/xdg-go/pbkdf2 v1.0.0 h1:Su7DPu48wXMwC3bs7MCNG+z4FhcyEuz5dlvchbq0B0c= +github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI= +github.com/xdg-go/scram v1.1.1 h1:VOMT+81stJgXW3CpHyqHN3AXDYIMsx56mEFrB37Mb/E= +github.com/xdg-go/scram v1.1.1/go.mod h1:RaEWvsqvNKKvBPvcKeFjrG2cJqOkHTiyTpzz23ni57g= +github.com/xdg-go/stringprep v1.0.3 h1:kdwGpVNwPFtjs98xCGkHjQtGKh86rDcRZN17QEMCOIs= +github.com/xdg-go/stringprep v1.0.3/go.mod h1:W3f5j4i+9rC0kuIEJL0ky1VpHXQU3ocBgklLGvcBnW8= +github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d h1:splanxYIlg+5LfHAM6xpdFEAYOk8iySO56hMFq6uLyA= +github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d/go.mod h1:rHwXgn7JulP+udvsHwJoVG1YGAP6VLg4y9I5dyZdqmA= +go.mongodb.org/mongo-driver v1.11.4 h1:4ayjakA013OdpGyL2K3ZqylTac/rMjrJOMZ1EHizXas= +go.mongodb.org/mongo-driver v1.11.4/go.mod h1:PTSz5yu21bkT/wXpkS7WR5f0ddqw5quethTUn9WM+2g= +golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d h1:sK3txAijHtOK88l68nt020reeT1ZdKLIYetKl95FzVY= +golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/exp v0.0.0-20230321023759-10a507213a29 h1:ooxPy7fPvB4kwsA2h+iBNHkAbp/4JxTSwCmvdjEYmug= +golang.org/x/exp v0.0.0-20230321023759-10a507213a29/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc= +golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4 h1:uVc8UZUe6tr40fFVnUP5Oj+veunVezqYl9z7DYw9xzw= +golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.7.0 h1:3jlCCIQZPdOYu1h8BkNvLz8Kgwtae2cagcG/VamtZRU= +golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.7.0 h1:BEvjmm5fURWqcfbSKTdpkDXYBrUS1c0m8agp14W48vQ= +golang.org/x/term v0.7.0/go.mod h1:P32HKFT3hSsZrRxla30E9HqToFYAQPCMs/zFMBUFqPY= +golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.4.0 h1:BrVqGRd7+k1DiOgtnFvAkoQEWQvBc25ouMJM6429SFg= +golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= +gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= +gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/init.go b/init.go index d0308d9..9a6e4b8 100644 --- a/init.go +++ b/init.go @@ -5,12 +5,11 @@ import ( "log" "runtime" + "github.com/PretendoNetwork/super-mario-maker-secure/database" + "github.com/PretendoNetwork/super-mario-maker-secure/globals" "github.com/joho/godotenv" ) -var hmacSecret []byte -var dataStoreIDGenerators []*DataStoreIDGenerator - func init() { var err error @@ -19,27 +18,26 @@ func init() { log.Fatal("Error loading .env file") } - hmacSecret, err = ioutil.ReadFile("secret.key") + globals.HMACSecret, err = ioutil.ReadFile("secret.key") if err != nil { panic(err) } // Connect to and setup databases - connectMongo() - connectCassandra() + database.ConnectAll() createDataStoreIDGenerators() } func createDataStoreIDGenerators() { - dataStoreIDGenerators = make([]*DataStoreIDGenerator, 0) + globals.DataStoreIDGenerators = make([]*database.DataStoreIDGenerator, 0) regionID := 0 // USA for corenum := 0; corenum < runtime.NumCPU(); corenum++ { - createDataStoreIDGeneratorRow(corenum) + database.CreateDataStoreIDGeneratorRow(corenum) - lastID := getDataStoreIDGeneratorLastID(corenum) + lastID := database.GetDataStoreIDGeneratorLastID(corenum) - generator := NewDataStoreIDGenerator(uint8(regionID), uint8(corenum), lastID) - dataStoreIDGenerators = append(dataStoreIDGenerators, generator) + generator := database.NewDataStoreIDGenerator(uint8(regionID), uint8(corenum), lastID) + globals.DataStoreIDGenerators = append(globals.DataStoreIDGenerators, generator) } } diff --git a/log/all.log b/log/all.log new file mode 100644 index 0000000..e69de29 diff --git a/log/critical.log b/log/critical.log new file mode 100644 index 0000000..e69de29 diff --git a/log/error.log b/log/error.log new file mode 100644 index 0000000..e69de29 diff --git a/log/info.log b/log/info.log new file mode 100644 index 0000000..e69de29 diff --git a/log/success.log b/log/success.log new file mode 100644 index 0000000..e69de29 diff --git a/log/warning.log b/log/warning.log new file mode 100644 index 0000000..e69de29 diff --git a/main.go b/main.go index 6386e47..e1b661d 100644 --- a/main.go +++ b/main.go @@ -1,95 +1,18 @@ package main import ( - "fmt" - "os" + "sync" - nex "github.com/PretendoNetwork/nex-go" - nexproto "github.com/PretendoNetwork/nex-protocols-go" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/credentials" - "github.com/aws/aws-sdk-go/aws/session" - "github.com/aws/aws-sdk-go/service/s3" + "github.com/PretendoNetwork/super-mario-maker-secure/nex" ) -var nexServer *nex.Server -var secureServer *nexproto.SecureProtocol -var s3Client *s3.S3 +var wg sync.WaitGroup func main() { - key := os.Getenv("S3_KEY") - secret := os.Getenv("S3_SECRET") + wg.Add(1) - s3Config := &aws.Config{ - Credentials: credentials.NewStaticCredentials(key, secret, ""), - Endpoint: aws.String("http://b-cdn.net"), - Region: aws.String("us-east-1"), - } + // TODO - Add gRPC server + go nex.StartNEXServer() - newSession, _ := session.NewSession(s3Config) - s3Client = s3.New(newSession) - - nexServer = nex.NewServer() - nexServer.SetPrudpVersion(1) - nexServer.SetNexVersion(4) - nexServer.SetKerberosKeySize(32) - nexServer.SetFragmentSize(1300) - nexServer.SetPingTimeout(20) - nexServer.SetAccessKey("9f2b4678") - - nexServer.On("Data", func(packet *nex.PacketV1) { - request := packet.RMCRequest() - - fmt.Println("==SMM1 - Secure==") - fmt.Printf("Protocol ID: %#v\n", request.ProtocolID()) - fmt.Printf("Method ID: %#v\n", request.MethodID()) - fmt.Println("=================") - }) - - nexServer.On("Kick", func(packet *nex.PacketV1) { - fmt.Println("Leaving") - }) - - nexServer.On("Ping", func(packet *nex.PacketV1) { - fmt.Println("Pinged") - }) - - secureServer = nexproto.NewSecureProtocol(nexServer) - dataStoreSmmServer := nexproto.NewDataStoreSMMProtocol(nexServer) - messageDeliveryServer := nexproto.NewMessageDeliveryProtocol(nexServer) - - // Handle PRUDP CONNECT packet (not an RMC method) - nexServer.On("Connect", connect) - - secureServer.Register(register) - - dataStoreSmmServer.GetMeta(getMeta) - dataStoreSmmServer.PreparePostObject(preparePostObject) - dataStoreSmmServer.PrepareGetObject(prepareGetObject) - dataStoreSmmServer.CompletePostObject(completePostObject) - dataStoreSmmServer.GetMetasMultipleParam(getMetasMultipleParam) - dataStoreSmmServer.ChangeMeta(changeMeta) - dataStoreSmmServer.RateObjects(rateObjects) - dataStoreSmmServer.GetObjectInfos(getObjectInfos) - dataStoreSmmServer.RateCustomRanking(rateCustomRanking) - dataStoreSmmServer.GetCustomRankingByDataId(getCustomRankingByDataId) - dataStoreSmmServer.AddToBufferQueues(addToBufferQueues) - dataStoreSmmServer.GetBufferQueue(getBufferQueue) - dataStoreSmmServer.CompleteAttachFile(completeAttachFile) - dataStoreSmmServer.PrepareAttachFile(prepareAttachFile) - dataStoreSmmServer.GetApplicationConfig(getApplicationConfig) - dataStoreSmmServer.FollowingsLatestCourseSearchObject(followingsLatestCourseSearchObject) - dataStoreSmmServer.RecommendedCourseSearchObject(recommendedCourseSearchObject) - dataStoreSmmServer.SuggestedCourseSearchObject(suggestedCourseSearchObject) - dataStoreSmmServer.UploadCourseRecord(uploadCourseRecord) - dataStoreSmmServer.GetCourseRecord(getCourseRecord) - dataStoreSmmServer.GetApplicationConfigString(getApplicationConfigString) - dataStoreSmmServer.GetDeletionReason(getDeletionReason) - dataStoreSmmServer.GetMetasWithCourseRecord(getMetasWithCourseRecord) - dataStoreSmmServer.CheckRateCustomRankingCounter(checkRateCustomRankingCounter) - dataStoreSmmServer.CTRPickUpCourseSearchObject(ctrPickUpCourseSearchObject) - - messageDeliveryServer.DeliverMessage(deliverMessage) - - nexServer.Listen(":60003") + wg.Wait() } diff --git a/change_meta.go b/nex/datastore/change_meta.go similarity index 52% rename from change_meta.go rename to nex/datastore/change_meta.go index 65464df..6439bef 100644 --- a/change_meta.go +++ b/nex/datastore/change_meta.go @@ -1,15 +1,16 @@ -package main +package nex_datastore import ( nex "github.com/PretendoNetwork/nex-go" - nexproto "github.com/PretendoNetwork/nex-protocols-go" + "github.com/PretendoNetwork/nex-protocols-go/datastore" + "github.com/PretendoNetwork/super-mario-maker-secure/globals" ) -func changeMeta(err error, client *nex.Client, callID uint32, dataStoreChangeMetaParam *nexproto.DataStoreChangeMetaParam) { +func ChangeMeta(err error, client *nex.Client, callID uint32, dataStoreChangeMetaParam *datastore.DataStoreChangeMetaParam) { // STUBBED // TODO: DO SOMETHING WITH THE DATA - rmcResponse := nex.NewRMCResponse(nexproto.DataStoreProtocolID, callID) - rmcResponse.SetSuccess(nexproto.DataStoreMethodChangeMeta, nil) + rmcResponse := nex.NewRMCResponse(datastore.ProtocolID, callID) + rmcResponse.SetSuccess(datastore.MethodChangeMeta, nil) rmcResponseBytes := rmcResponse.Bytes() @@ -24,5 +25,5 @@ func changeMeta(err error, client *nex.Client, callID uint32, dataStoreChangeMet responsePacket.AddFlag(nex.FlagNeedsAck) responsePacket.AddFlag(nex.FlagReliable) - nexServer.Send(responsePacket) + globals.NEXServer.Send(responsePacket) } diff --git a/complete_post_object.go b/nex/datastore/complete_post_object.go similarity index 50% rename from complete_post_object.go rename to nex/datastore/complete_post_object.go index f3c14ee..04f2ca4 100644 --- a/complete_post_object.go +++ b/nex/datastore/complete_post_object.go @@ -1,15 +1,16 @@ -package main +package nex_datastore import ( nex "github.com/PretendoNetwork/nex-go" - nexproto "github.com/PretendoNetwork/nex-protocols-go" + "github.com/PretendoNetwork/nex-protocols-go/datastore" + "github.com/PretendoNetwork/super-mario-maker-secure/globals" ) -func completePostObject(err error, client *nex.Client, callID uint32, dataStoreCompletePostParam *nexproto.DataStoreCompletePostParam) { +func CompletePostObject(err error, client *nex.Client, callID uint32, dataStoreCompletePostParam *datastore.DataStoreCompletePostParam) { // TODO: DO SOMETHING WITH THE DATA - rmcResponse := nex.NewRMCResponse(nexproto.DataStoreProtocolID, callID) - rmcResponse.SetSuccess(nexproto.DataStoreMethodCompletePostObject, nil) + rmcResponse := nex.NewRMCResponse(datastore.ProtocolID, callID) + rmcResponse.SetSuccess(datastore.MethodCompletePostObject, nil) rmcResponseBytes := rmcResponse.Bytes() @@ -24,5 +25,5 @@ func completePostObject(err error, client *nex.Client, callID uint32, dataStoreC responsePacket.AddFlag(nex.FlagNeedsAck) responsePacket.AddFlag(nex.FlagReliable) - nexServer.Send(responsePacket) + globals.NEXServer.Send(responsePacket) } diff --git a/get_meta.go b/nex/datastore/get_meta.go similarity index 61% rename from get_meta.go rename to nex/datastore/get_meta.go index a8b0d9c..21ddf59 100644 --- a/get_meta.go +++ b/nex/datastore/get_meta.go @@ -1,14 +1,17 @@ -package main +package nex_datastore import ( "fmt" "os" nex "github.com/PretendoNetwork/nex-go" - nexproto "github.com/PretendoNetwork/nex-protocols-go" + "github.com/PretendoNetwork/nex-protocols-go/datastore" + "github.com/PretendoNetwork/super-mario-maker-secure/database" + "github.com/PretendoNetwork/super-mario-maker-secure/globals" + "github.com/PretendoNetwork/super-mario-maker-secure/utility" ) -func getMeta(err error, client *nex.Client, callID uint32, param *nexproto.DataStoreGetMetaParam) { +func GetMeta(err error, client *nex.Client, callID uint32, param *datastore.DataStoreGetMetaParam) { switch param.DataID { case 0: // Mii Data getMetaMiiData(client, callID, param) @@ -19,18 +22,18 @@ func getMeta(err error, client *nex.Client, callID uint32, param *nexproto.DataS } } -func getMetaMiiData(client *nex.Client, callID uint32, param *nexproto.DataStoreGetMetaParam) { - miiInfo := getUserMiiInfoByPID(param.PersistenceTarget.OwnerID) +func getMetaMiiData(client *nex.Client, callID uint32, param *datastore.DataStoreGetMetaParam) { + miiInfo := database.GetUserMiiInfoByPID(param.PersistenceTarget.OwnerID) - pMetaInfo := userMiiDataToDataStoreMetaInfo(param.PersistenceTarget.OwnerID, miiInfo) + pMetaInfo := utility.UserMiiDataToDataStoreMetaInfo(param.PersistenceTarget.OwnerID, miiInfo) - rmcResponseStream := nex.NewStreamOut(nexServer) + rmcResponseStream := nex.NewStreamOut(globals.NEXServer) rmcResponseStream.WriteStructure(pMetaInfo) rmcResponseBody := rmcResponseStream.Bytes() - rmcResponse := nex.NewRMCResponse(nexproto.DataStoreProtocolID, callID) - rmcResponse.SetSuccess(nexproto.DataStoreMethodGetMeta, rmcResponseBody) + rmcResponse := nex.NewRMCResponse(datastore.ProtocolID, callID) + rmcResponse.SetSuccess(datastore.MethodGetMeta, rmcResponseBody) rmcResponseBytes := rmcResponse.Bytes() @@ -45,23 +48,23 @@ func getMetaMiiData(client *nex.Client, callID uint32, param *nexproto.DataStore responsePacket.AddFlag(nex.FlagNeedsAck) responsePacket.AddFlag(nex.FlagReliable) - nexServer.Send(responsePacket) + globals.NEXServer.Send(responsePacket) } -func getMetaEventCourseNewsData(client *nex.Client, callID uint32, param *nexproto.DataStoreGetMetaParam) { - objectSize, _ := s3ObjectSize(os.Getenv("S3_BUCKET_NAME"), "special/900000.bin") +func getMetaEventCourseNewsData(client *nex.Client, callID uint32, param *datastore.DataStoreGetMetaParam) { + objectSize, _ := utility.S3ObjectSize(os.Getenv("S3_BUCKET_NAME"), "special/900000.bin") - pMetaInfo := nexproto.NewDataStoreMetaInfo() + pMetaInfo := datastore.NewDataStoreMetaInfo() pMetaInfo.DataID = 900000 pMetaInfo.OwnerID = 2 pMetaInfo.Size = uint32(objectSize) pMetaInfo.Name = "" pMetaInfo.DataType = 50 // Metdata? pMetaInfo.MetaBinary = []byte{} - pMetaInfo.Permission = nexproto.NewDataStorePermission() + pMetaInfo.Permission = datastore.NewDataStorePermission() pMetaInfo.Permission.Permission = 0 // idk? pMetaInfo.Permission.RecipientIds = []uint32{} - pMetaInfo.DelPermission = nexproto.NewDataStorePermission() + pMetaInfo.DelPermission = datastore.NewDataStorePermission() pMetaInfo.DelPermission.Permission = 0 // idk? pMetaInfo.DelPermission.RecipientIds = []uint32{} pMetaInfo.CreatedTime = nex.NewDateTime(135271087238) // Reused from Nintendo @@ -74,15 +77,15 @@ func getMetaEventCourseNewsData(client *nex.Client, callID uint32, param *nexpro pMetaInfo.ReferredTime = nex.NewDateTime(135271087238) // Reused from Nintendo pMetaInfo.ExpireTime = nex.NewDateTime(671075926016) // Reused from Nintendo pMetaInfo.Tags = []string{} // idk? - pMetaInfo.Ratings = []*nexproto.DataStoreRatingInfoWithSlot{} + pMetaInfo.Ratings = []*datastore.DataStoreRatingInfoWithSlot{} - rmcResponseStream := nex.NewStreamOut(nexServer) + rmcResponseStream := nex.NewStreamOut(globals.NEXServer) rmcResponseStream.WriteStructure(pMetaInfo) rmcResponseBody := rmcResponseStream.Bytes() - rmcResponse := nex.NewRMCResponse(nexproto.DataStoreProtocolID, callID) - rmcResponse.SetSuccess(nexproto.DataStoreMethodGetMeta, rmcResponseBody) + rmcResponse := nex.NewRMCResponse(datastore.ProtocolID, callID) + rmcResponse.SetSuccess(datastore.MethodGetMeta, rmcResponseBody) rmcResponseBytes := rmcResponse.Bytes() @@ -97,5 +100,5 @@ func getMetaEventCourseNewsData(client *nex.Client, callID uint32, param *nexpro responsePacket.AddFlag(nex.FlagNeedsAck) responsePacket.AddFlag(nex.FlagReliable) - nexServer.Send(responsePacket) + globals.NEXServer.Send(responsePacket) } diff --git a/nex/datastore/get_metas_multiple_param.go b/nex/datastore/get_metas_multiple_param.go new file mode 100644 index 0000000..257a32a --- /dev/null +++ b/nex/datastore/get_metas_multiple_param.go @@ -0,0 +1,57 @@ +package nex_datastore + +import ( + "fmt" + + nex "github.com/PretendoNetwork/nex-go" + "github.com/PretendoNetwork/nex-protocols-go/datastore" + "github.com/PretendoNetwork/super-mario-maker-secure/database" + "github.com/PretendoNetwork/super-mario-maker-secure/globals" + "github.com/PretendoNetwork/super-mario-maker-secure/utility" +) + +func GetMetasMultipleParam(err error, client *nex.Client, callID uint32, params []*datastore.DataStoreGetMetaParam) { + pMetaInfo := make([]*datastore.DataStoreMetaInfo, 0) + pResults := make([]uint32, 0) + + for _, param := range params { + if param.DataID == 0 { + pMetaInfo = append(pMetaInfo, getMetasMultipleParamMiiData(param)) + } else { + fmt.Println("Unknown meta multiple data ID") + } + + pResults = append(pResults, 0x690001) + } + + rmcResponseStream := nex.NewStreamOut(globals.NEXServer) + + rmcResponseStream.WriteListStructure(pMetaInfo) + rmcResponseStream.WriteListUInt32LE(pResults) + + rmcResponseBody := rmcResponseStream.Bytes() + + rmcResponse := nex.NewRMCResponse(datastore.ProtocolID, callID) + rmcResponse.SetSuccess(datastore.MethodGetMetasMultipleParam, rmcResponseBody) + + rmcResponseBytes := rmcResponse.Bytes() + + responsePacket, _ := nex.NewPacketV1(client, nil) + + responsePacket.SetVersion(1) + responsePacket.SetSource(0xA1) + responsePacket.SetDestination(0xAF) + responsePacket.SetType(nex.DataPacket) + responsePacket.SetPayload(rmcResponseBytes) + + responsePacket.AddFlag(nex.FlagNeedsAck) + responsePacket.AddFlag(nex.FlagReliable) + + globals.NEXServer.Send(responsePacket) +} + +func getMetasMultipleParamMiiData(param *datastore.DataStoreGetMetaParam) *datastore.DataStoreMetaInfo { + miiInfo := database.GetUserMiiInfoByPID(param.PersistenceTarget.OwnerID) + + return utility.UserMiiDataToDataStoreMetaInfo(param.PersistenceTarget.OwnerID, miiInfo) +} diff --git a/prepare_get_object.go b/nex/datastore/prepare_get_object.go similarity index 51% rename from prepare_get_object.go rename to nex/datastore/prepare_get_object.go index 17361da..6f114d0 100644 --- a/prepare_get_object.go +++ b/nex/datastore/prepare_get_object.go @@ -1,42 +1,45 @@ -package main +package nex_datastore import ( "fmt" "os" nex "github.com/PretendoNetwork/nex-go" - nexproto "github.com/PretendoNetwork/nex-protocols-go" + "github.com/PretendoNetwork/nex-protocols-go/datastore" + "github.com/PretendoNetwork/super-mario-maker-secure/database" + "github.com/PretendoNetwork/super-mario-maker-secure/globals" + "github.com/PretendoNetwork/super-mario-maker-secure/utility" ) -func prepareGetObject(err error, client *nex.Client, callID uint32, dataStorePrepareGetParam *nexproto.DataStorePrepareGetParam) { - pReqGetInfo := nexproto.NewDataStoreReqGetInfo() +func PrepareGetObject(err error, client *nex.Client, callID uint32, dataStorePrepareGetParam *datastore.DataStorePrepareGetParam) { + pReqGetInfo := datastore.NewDataStoreReqGetInfo() if dataStorePrepareGetParam.DataID == 900000 { - objectSize, _ := s3ObjectSize(os.Getenv("S3_BUCKET_NAME"), "special/900000.bin") + objectSize, _ := utility.S3ObjectSize(os.Getenv("S3_BUCKET_NAME"), "special/900000.bin") pReqGetInfo.URL = fmt.Sprintf("http://%s.b-cdn.net/special/900000.bin", "pds-AMAJ-d1") - pReqGetInfo.RequestHeaders = []*nexproto.DataStoreKeyValue{} + pReqGetInfo.RequestHeaders = []*datastore.DataStoreKeyValue{} pReqGetInfo.Size = uint32(objectSize) pReqGetInfo.RootCA = []byte{} pReqGetInfo.DataID = 900000 } else { - courseMetadata := getCourseMetadataByDataID(dataStorePrepareGetParam.DataID) + courseMetadata := database.GetCourseMetadataByDataID(dataStorePrepareGetParam.DataID) pReqGetInfo.URL = fmt.Sprintf("http://%s.b-cdn.net/course/%d.bin", os.Getenv("S3_BUCKET_NAME"), dataStorePrepareGetParam.DataID) - pReqGetInfo.RequestHeaders = []*nexproto.DataStoreKeyValue{} + pReqGetInfo.RequestHeaders = []*datastore.DataStoreKeyValue{} pReqGetInfo.Size = courseMetadata.Size pReqGetInfo.RootCA = []byte{} pReqGetInfo.DataID = dataStorePrepareGetParam.DataID } - rmcResponseStream := nex.NewStreamOut(nexServer) + rmcResponseStream := nex.NewStreamOut(globals.NEXServer) rmcResponseStream.WriteStructure(pReqGetInfo) rmcResponseBody := rmcResponseStream.Bytes() - rmcResponse := nex.NewRMCResponse(nexproto.DataStoreProtocolID, callID) - rmcResponse.SetSuccess(nexproto.DataStoreMethodPrepareGetObject, rmcResponseBody) + rmcResponse := nex.NewRMCResponse(datastore.ProtocolID, callID) + rmcResponse.SetSuccess(datastore.MethodPrepareGetObject, rmcResponseBody) rmcResponseBytes := rmcResponse.Bytes() @@ -51,5 +54,5 @@ func prepareGetObject(err error, client *nex.Client, callID uint32, dataStorePre responsePacket.AddFlag(nex.FlagNeedsAck) responsePacket.AddFlag(nex.FlagReliable) - nexServer.Send(responsePacket) + globals.NEXServer.Send(responsePacket) } diff --git a/nex/datastore/prepare_post_object.go b/nex/datastore/prepare_post_object.go new file mode 100644 index 0000000..5e8d146 --- /dev/null +++ b/nex/datastore/prepare_post_object.go @@ -0,0 +1,100 @@ +package nex_datastore + +import ( + "crypto/hmac" + "crypto/sha256" + "encoding/hex" + "fmt" + "math/rand" + "os" + "strconv" + "time" + + nex "github.com/PretendoNetwork/nex-go" + "github.com/PretendoNetwork/nex-protocols-go/datastore" + "github.com/PretendoNetwork/super-mario-maker-secure/database" + "github.com/PretendoNetwork/super-mario-maker-secure/globals" +) + +func PreparePostObject(err error, client *nex.Client, callID uint32, param *datastore.DataStorePreparePostParam) { + rand.Seed(time.Now().UnixNano()) + nodeID := rand.Intn(len(globals.DataStoreIDGenerators)) + + dataStoreIDGenerator := globals.DataStoreIDGenerators[nodeID] + + dataID := dataStoreIDGenerator.Next() + database.SetDataStoreIDGeneratorLastID(nodeID, dataStoreIDGenerator.Value) + database.InitializeCourseData(dataID, client.PID(), param.Size, param.Name, param.Flag, param.ExtraData, param.DataType, param.Period) + + if param.DataType != 1 { // 1 is Mii data, assume other values are course meta data + database.UpdateCourseMetaBinary(dataID, param.MetaBinary) + } + + key := fmt.Sprintf("course/%d.bin", dataID) + bucket := os.Getenv("S3_BUCKET_NAME") + date := strconv.Itoa(int(time.Now().Unix())) + pid := strconv.Itoa(int(client.PID())) + + data := pid + bucket + key + date + + hmac := hmac.New(sha256.New, globals.HMACSecret) + hmac.Write([]byte(data)) + + signature := hex.EncodeToString(hmac.Sum(nil)) + + fieldBucket := datastore.NewDataStoreKeyValue() + fieldBucket.Key = "bucket" + fieldBucket.Value = bucket + + fieldKey := datastore.NewDataStoreKeyValue() + fieldKey.Key = "key" + fieldKey.Value = key + + fieldACL := datastore.NewDataStoreKeyValue() + fieldACL.Key = "acl" + fieldACL.Value = "private" + + fieldPID := datastore.NewDataStoreKeyValue() + fieldPID.Key = "pid" + fieldPID.Value = pid + + fieldDate := datastore.NewDataStoreKeyValue() + fieldDate.Key = "date" + fieldDate.Value = date + + fieldSignature := datastore.NewDataStoreKeyValue() + fieldSignature.Key = "signature" + fieldSignature.Value = signature + + rmcResponseStream := nex.NewStreamOut(globals.NEXServer) + + pReqPostInfo := datastore.NewDataStoreReqPostInfo() + + pReqPostInfo.DataID = dataID + pReqPostInfo.URL = os.Getenv("DATASTORE_UPLOAD_URL") + pReqPostInfo.RequestHeaders = []*datastore.DataStoreKeyValue{} + pReqPostInfo.FormFields = []*datastore.DataStoreKeyValue{fieldBucket, fieldKey, fieldACL, fieldPID, fieldDate, fieldSignature} + pReqPostInfo.RootCACert = []byte{} + + rmcResponseStream.WriteStructure(pReqPostInfo) + + rmcResponseBody := rmcResponseStream.Bytes() + + rmcResponse := nex.NewRMCResponse(datastore.ProtocolID, callID) + rmcResponse.SetSuccess(datastore.MethodPreparePostObject, rmcResponseBody) + + rmcResponseBytes := rmcResponse.Bytes() + + responsePacket, _ := nex.NewPacketV1(client, nil) + + responsePacket.SetVersion(1) + responsePacket.SetSource(0xA1) + responsePacket.SetDestination(0xAF) + responsePacket.SetType(nex.DataPacket) + responsePacket.SetPayload(rmcResponseBytes) + + responsePacket.AddFlag(nex.FlagNeedsAck) + responsePacket.AddFlag(nex.FlagReliable) + + globals.NEXServer.Send(responsePacket) +} diff --git a/rate_objects.go b/nex/datastore/rate_objects.go similarity index 52% rename from rate_objects.go rename to nex/datastore/rate_objects.go index 79bd9c0..fa29fa7 100644 --- a/rate_objects.go +++ b/nex/datastore/rate_objects.go @@ -1,22 +1,23 @@ -package main +package nex_datastore import ( nex "github.com/PretendoNetwork/nex-go" - nexproto "github.com/PretendoNetwork/nex-protocols-go" + "github.com/PretendoNetwork/nex-protocols-go/datastore" + "github.com/PretendoNetwork/super-mario-maker-secure/globals" ) -func rateObjects(err error, client *nex.Client, callID uint32, targets []*nexproto.DataStoreRatingTarget, params []*nexproto.DataStoreRateObjectParam, transactional bool, fetchRatings bool) { +func RateObjects(err error, client *nex.Client, callID uint32, targets []*datastore.DataStoreRatingTarget, params []*datastore.DataStoreRateObjectParam, transactional bool, fetchRatings bool) { // TODO: complete this - rmcResponseStream := nex.NewStreamOut(nexServer) + rmcResponseStream := nex.NewStreamOut(globals.NEXServer) rmcResponseStream.WriteUInt32LE(0x00000000) // pRatings List length 0 rmcResponseStream.WriteUInt32LE(0x00000000) // pResults List length 0 rmcResponseBody := rmcResponseStream.Bytes() - rmcResponse := nex.NewRMCResponse(nexproto.DataStoreSMMProtocolID, callID) - rmcResponse.SetSuccess(nexproto.DataStoreMethodRateObjects, rmcResponseBody) + rmcResponse := nex.NewRMCResponse(datastore.ProtocolID, callID) + rmcResponse.SetSuccess(datastore.MethodRateObjects, rmcResponseBody) rmcResponseBytes := rmcResponse.Bytes() @@ -31,5 +32,5 @@ func rateObjects(err error, client *nex.Client, callID uint32, targets []*nexpro responsePacket.AddFlag(nex.FlagNeedsAck) responsePacket.AddFlag(nex.FlagReliable) - nexServer.Send(responsePacket) + globals.NEXServer.Send(responsePacket) } diff --git a/nex/datastore/super-mario-maker/add_to_buffer_queues.go b/nex/datastore/super-mario-maker/add_to_buffer_queues.go new file mode 100644 index 0000000..f9e6e4f --- /dev/null +++ b/nex/datastore/super-mario-maker/add_to_buffer_queues.go @@ -0,0 +1,46 @@ +package nex_datastore_super_mario_maker + +import ( + nex "github.com/PretendoNetwork/nex-go" + datastore_super_mario_maker "github.com/PretendoNetwork/nex-protocols-go/datastore/super-mario-maker" + "github.com/PretendoNetwork/super-mario-maker-secure/database" + "github.com/PretendoNetwork/super-mario-maker-secure/globals" +) + +func AddToBufferQueues(err error, client *nex.Client, callID uint32, params []*datastore_super_mario_maker.BufferQueueParam, buffers [][]byte) { + pResults := make([]uint32, 0) + + for i := 0; i < len(params); i++ { + buffer := buffers[i] + param := params[i] + + database.InsertBufferQueueData(param.DataID, param.Slot, buffer) + database.IncrementCourseFailCount(param.DataID) + + pResults = append(pResults, 0x690001) + } + + rmcResponseStream := nex.NewStreamOut(globals.NEXServer) + + rmcResponseStream.WriteListUInt32LE(pResults) + + rmcResponseBody := rmcResponseStream.Bytes() + + rmcResponse := nex.NewRMCResponse(datastore_super_mario_maker.ProtocolID, callID) + rmcResponse.SetSuccess(datastore_super_mario_maker.MethodAddToBufferQueues, rmcResponseBody) + + rmcResponseBytes := rmcResponse.Bytes() + + responsePacket, _ := nex.NewPacketV1(client, nil) + + responsePacket.SetVersion(1) + responsePacket.SetSource(0xA1) + responsePacket.SetDestination(0xAF) + responsePacket.SetType(nex.DataPacket) + responsePacket.SetPayload(rmcResponseBytes) + + responsePacket.AddFlag(nex.FlagNeedsAck) + responsePacket.AddFlag(nex.FlagReliable) + + globals.NEXServer.Send(responsePacket) +} diff --git a/check_rate_custom_ranking_counter.go b/nex/datastore/super-mario-maker/check_rate_custom_ranking_counter.go similarity index 59% rename from check_rate_custom_ranking_counter.go rename to nex/datastore/super-mario-maker/check_rate_custom_ranking_counter.go index c4046e5..9965228 100644 --- a/check_rate_custom_ranking_counter.go +++ b/nex/datastore/super-mario-maker/check_rate_custom_ranking_counter.go @@ -1,13 +1,14 @@ -package main +package nex_datastore_super_mario_maker import ( "fmt" nex "github.com/PretendoNetwork/nex-go" - nexproto "github.com/PretendoNetwork/nex-protocols-go" + datastore_super_mario_maker "github.com/PretendoNetwork/nex-protocols-go/datastore/super-mario-maker" + "github.com/PretendoNetwork/super-mario-maker-secure/globals" ) -func checkRateCustomRankingCounter(err error, client *nex.Client, callID uint32, applicationID uint32) { +func CheckRateCustomRankingCounter(err error, client *nex.Client, callID uint32, applicationID uint32) { var isBelowThreshold uint8 switch applicationID { @@ -17,14 +18,14 @@ func checkRateCustomRankingCounter(err error, client *nex.Client, callID uint32, fmt.Printf("[Warning] DataStoreSMMProtocol::CheckRateCustomRankingCounter Unsupported applicationID: %v\n", applicationID) } - rmcResponseStream := nex.NewStreamOut(nexServer) + rmcResponseStream := nex.NewStreamOut(globals.NEXServer) rmcResponseStream.WriteUInt8(isBelowThreshold) rmcResponseBody := rmcResponseStream.Bytes() - rmcResponse := nex.NewRMCResponse(nexproto.DataStoreSMMProtocolID, callID) - rmcResponse.SetSuccess(nexproto.DataStoreSMMMethodCheckRateCustomRankingCounter, rmcResponseBody) + rmcResponse := nex.NewRMCResponse(datastore_super_mario_maker.ProtocolID, callID) + rmcResponse.SetSuccess(datastore_super_mario_maker.MethodCheckRateCustomRankingCounter, rmcResponseBody) rmcResponseBytes := rmcResponse.Bytes() @@ -39,5 +40,5 @@ func checkRateCustomRankingCounter(err error, client *nex.Client, callID uint32, responsePacket.AddFlag(nex.FlagNeedsAck) responsePacket.AddFlag(nex.FlagReliable) - nexServer.Send(responsePacket) + globals.NEXServer.Send(responsePacket) } diff --git a/nex/datastore/super-mario-maker/complete_attach_file.go b/nex/datastore/super-mario-maker/complete_attach_file.go new file mode 100644 index 0000000..42c7fcc --- /dev/null +++ b/nex/datastore/super-mario-maker/complete_attach_file.go @@ -0,0 +1,39 @@ +package nex_datastore_super_mario_maker + +import ( + "fmt" + "os" + + nex "github.com/PretendoNetwork/nex-go" + "github.com/PretendoNetwork/nex-protocols-go/datastore" + datastore_super_mario_maker "github.com/PretendoNetwork/nex-protocols-go/datastore/super-mario-maker" + "github.com/PretendoNetwork/super-mario-maker-secure/globals" +) + +func CompleteAttachFile(err error, client *nex.Client, callID uint32, dataStoreCompletePostParam *datastore.DataStoreCompletePostParam) { + rmcResponseStream := nex.NewStreamOut(globals.NEXServer) + + // TODO: complete this + + rmcResponseStream.WriteString(fmt.Sprintf("http://%s.b-cdn.net/image/%d.jpg", os.Getenv("S3_BUCKET_NAME"), dataStoreCompletePostParam.DataID)) + + rmcResponseBody := rmcResponseStream.Bytes() + + rmcResponse := nex.NewRMCResponse(datastore_super_mario_maker.ProtocolID, callID) + rmcResponse.SetSuccess(datastore_super_mario_maker.MethodCompleteAttachFile, rmcResponseBody) + + rmcResponseBytes := rmcResponse.Bytes() + + responsePacket, _ := nex.NewPacketV1(client, nil) + + responsePacket.SetVersion(1) + responsePacket.SetSource(0xA1) + responsePacket.SetDestination(0xAF) + responsePacket.SetType(nex.DataPacket) + responsePacket.SetPayload(rmcResponseBytes) + + responsePacket.AddFlag(nex.FlagNeedsAck) + responsePacket.AddFlag(nex.FlagReliable) + + globals.NEXServer.Send(responsePacket) +} diff --git a/nex/datastore/super-mario-maker/ctr_pick_up_course_search_object.go b/nex/datastore/super-mario-maker/ctr_pick_up_course_search_object.go new file mode 100644 index 0000000..96a60f9 --- /dev/null +++ b/nex/datastore/super-mario-maker/ctr_pick_up_course_search_object.go @@ -0,0 +1,46 @@ +package nex_datastore_super_mario_maker + +import ( + nex "github.com/PretendoNetwork/nex-go" + "github.com/PretendoNetwork/nex-protocols-go/datastore" + datastore_super_mario_maker "github.com/PretendoNetwork/nex-protocols-go/datastore/super-mario-maker" + "github.com/PretendoNetwork/super-mario-maker-secure/database" + "github.com/PretendoNetwork/super-mario-maker-secure/globals" + "github.com/PretendoNetwork/super-mario-maker-secure/utility" +) + +// This is the same as DataStoreSMM::RecommendedCourseSearchObject +// Not sure why they used a different method here? +func CTRPickUpCourseSearchObject(err error, client *nex.Client, callID uint32, dataStoreSearchParam *datastore.DataStoreSearchParam, extraData []string) { + pRankingResults := make([]*datastore_super_mario_maker.DataStoreCustomRankingResult, 0) + + courseMetadatas := database.GetCourseMetadatasByLimit(100) // In PCAPs param.minimalRatingFrequency is 100 but is 0 here? + + for _, courseMetadata := range courseMetadatas { + pRankingResults = append(pRankingResults, utility.CourseMetadataToDataStoreCustomRankingResult(courseMetadata)) + } + + rmcResponseStream := nex.NewStreamOut(globals.NEXServer) + + rmcResponseStream.WriteListStructure(pRankingResults) + + rmcResponseBody := rmcResponseStream.Bytes() + + rmcResponse := nex.NewRMCResponse(datastore_super_mario_maker.ProtocolID, callID) + rmcResponse.SetSuccess(datastore_super_mario_maker.MethodCTRPickUpCourseSearchObject, rmcResponseBody) + + rmcResponseBytes := rmcResponse.Bytes() + + responsePacket, _ := nex.NewPacketV1(client, nil) + + responsePacket.SetVersion(1) + responsePacket.SetSource(0xA1) + responsePacket.SetDestination(0xAF) + responsePacket.SetType(nex.DataPacket) + responsePacket.SetPayload(rmcResponseBytes) + + responsePacket.AddFlag(nex.FlagNeedsAck) + responsePacket.AddFlag(nex.FlagReliable) + + globals.NEXServer.Send(responsePacket) +} diff --git a/nex/datastore/super-mario-maker/followings_latest_course_search_object.go b/nex/datastore/super-mario-maker/followings_latest_course_search_object.go new file mode 100644 index 0000000..59b1d34 --- /dev/null +++ b/nex/datastore/super-mario-maker/followings_latest_course_search_object.go @@ -0,0 +1,46 @@ +package nex_datastore_super_mario_maker + +import ( + nex "github.com/PretendoNetwork/nex-go" + "github.com/PretendoNetwork/nex-protocols-go/datastore" + datastore_super_mario_maker "github.com/PretendoNetwork/nex-protocols-go/datastore/super-mario-maker" + "github.com/PretendoNetwork/super-mario-maker-secure/database" + "github.com/PretendoNetwork/super-mario-maker-secure/globals" + "github.com/PretendoNetwork/super-mario-maker-secure/utility" +) + +func FollowingsLatestCourseSearchObject(err error, client *nex.Client, callID uint32, dataStoreSearchParam *datastore.DataStoreSearchParam, extraData []string) { + pRankingResults := make([]*datastore_super_mario_maker.DataStoreCustomRankingResult, 0) + + for _, pid := range dataStoreSearchParam.OwnerIds { + courseMetadatas := database.GetCourseMetadatasByPID(pid) + + for _, courseMetadata := range courseMetadatas { + pRankingResults = append(pRankingResults, utility.CourseMetadataToDataStoreCustomRankingResult(courseMetadata)) + } + } + + rmcResponseStream := nex.NewStreamOut(globals.NEXServer) + + rmcResponseStream.WriteListStructure(pRankingResults) + + rmcResponseBody := rmcResponseStream.Bytes() + + rmcResponse := nex.NewRMCResponse(datastore_super_mario_maker.ProtocolID, callID) + rmcResponse.SetSuccess(datastore_super_mario_maker.MethodFollowingsLatestCourseSearchObject, rmcResponseBody) + + rmcResponseBytes := rmcResponse.Bytes() + + responsePacket, _ := nex.NewPacketV1(client, nil) + + responsePacket.SetVersion(1) + responsePacket.SetSource(0xA1) + responsePacket.SetDestination(0xAF) + responsePacket.SetType(nex.DataPacket) + responsePacket.SetPayload(rmcResponseBytes) + + responsePacket.AddFlag(nex.FlagNeedsAck) + responsePacket.AddFlag(nex.FlagReliable) + + globals.NEXServer.Send(responsePacket) +} diff --git a/get_application_config.go b/nex/datastore/super-mario-maker/get_application_config.go similarity index 84% rename from get_application_config.go rename to nex/datastore/super-mario-maker/get_application_config.go index 3160e86..f825108 100644 --- a/get_application_config.go +++ b/nex/datastore/super-mario-maker/get_application_config.go @@ -1,15 +1,16 @@ -package main +package nex_datastore_super_mario_maker import ( "fmt" nex "github.com/PretendoNetwork/nex-go" - nexproto "github.com/PretendoNetwork/nex-protocols-go" + datastore_super_mario_maker "github.com/PretendoNetwork/nex-protocols-go/datastore/super-mario-maker" + "github.com/PretendoNetwork/super-mario-maker-secure/globals" ) var MAX_COURSE_UPLOADS uint32 = 0x64 // Nintendo has this set to 100, but we can change it if we want -func getApplicationConfig(err error, client *nex.Client, callID uint32, applicationID uint32) { +func GetApplicationConfig(err error, client *nex.Client, callID uint32, applicationID uint32) { config := make([]uint32, 0) @@ -26,14 +27,14 @@ func getApplicationConfig(err error, client *nex.Client, callID uint32, applicat fmt.Printf("[Warning] DataStoreSMMProtocol::GetApplicationConfig Unsupported applicationID: %v\n", applicationID) } - rmcResponseStream := nex.NewStreamOut(nexServer) + rmcResponseStream := nex.NewStreamOut(globals.NEXServer) rmcResponseStream.WriteListUInt32LE(config) rmcResponseBody := rmcResponseStream.Bytes() - rmcResponse := nex.NewRMCResponse(nexproto.DataStoreSMMProtocolID, callID) - rmcResponse.SetSuccess(nexproto.DataStoreSMMMethodGetApplicationConfig, rmcResponseBody) + rmcResponse := nex.NewRMCResponse(datastore_super_mario_maker.ProtocolID, callID) + rmcResponse.SetSuccess(datastore_super_mario_maker.MethodGetApplicationConfig, rmcResponseBody) rmcResponseBytes := rmcResponse.Bytes() @@ -48,7 +49,7 @@ func getApplicationConfig(err error, client *nex.Client, callID uint32, applicat responsePacket.AddFlag(nex.FlagNeedsAck) responsePacket.AddFlag(nex.FlagReliable) - nexServer.Send(responsePacket) + globals.NEXServer.Send(responsePacket) } func getApplicationConfig_Unknown0() []uint32 { diff --git a/get_application_config_string.go b/nex/datastore/super-mario-maker/get_application_config_string.go similarity index 85% rename from get_application_config_string.go rename to nex/datastore/super-mario-maker/get_application_config_string.go index c02ae04..2cd1e36 100644 --- a/get_application_config_string.go +++ b/nex/datastore/super-mario-maker/get_application_config_string.go @@ -1,13 +1,14 @@ -package main +package nex_datastore_super_mario_maker import ( "fmt" nex "github.com/PretendoNetwork/nex-go" - nexproto "github.com/PretendoNetwork/nex-protocols-go" + datastore_super_mario_maker "github.com/PretendoNetwork/nex-protocols-go/datastore/super-mario-maker" + "github.com/PretendoNetwork/super-mario-maker-secure/globals" ) -func getApplicationConfigString(err error, client *nex.Client, callID uint32, applicationID uint32) { +func GetApplicationConfigString(err error, client *nex.Client, callID uint32, applicationID uint32) { // Word blacklists? config := make([]string, 0) @@ -22,14 +23,14 @@ func getApplicationConfigString(err error, client *nex.Client, callID uint32, ap fmt.Printf("[Warning] DataStoreSMMProtocol::GetApplicationConfigString Unsupported applicationID: %v\n", applicationID) } - rmcResponseStream := nex.NewStreamOut(nexServer) + rmcResponseStream := nex.NewStreamOut(globals.NEXServer) rmcResponseStream.WriteListString(config) rmcResponseBody := rmcResponseStream.Bytes() - rmcResponse := nex.NewRMCResponse(nexproto.DataStoreSMMProtocolID, callID) - rmcResponse.SetSuccess(nexproto.DataStoreSMMMethodGetApplicationConfigString, rmcResponseBody) + rmcResponse := nex.NewRMCResponse(datastore_super_mario_maker.ProtocolID, callID) + rmcResponse.SetSuccess(datastore_super_mario_maker.MethodGetApplicationConfigString, rmcResponseBody) rmcResponseBytes := rmcResponse.Bytes() @@ -44,7 +45,7 @@ func getApplicationConfigString(err error, client *nex.Client, callID uint32, ap responsePacket.AddFlag(nex.FlagNeedsAck) responsePacket.AddFlag(nex.FlagReliable) - nexServer.Send(responsePacket) + globals.NEXServer.Send(responsePacket) } func getApplicationConfigString_WordBlacklist1() []string { diff --git a/get_buffer_queue.go b/nex/datastore/super-mario-maker/get_buffer_queue.go similarity index 52% rename from get_buffer_queue.go rename to nex/datastore/super-mario-maker/get_buffer_queue.go index 29afc65..7f0eef3 100644 --- a/get_buffer_queue.go +++ b/nex/datastore/super-mario-maker/get_buffer_queue.go @@ -1,16 +1,18 @@ -package main +package nex_datastore_super_mario_maker import ( "fmt" nex "github.com/PretendoNetwork/nex-go" - nexproto "github.com/PretendoNetwork/nex-protocols-go" + datastore_super_mario_maker "github.com/PretendoNetwork/nex-protocols-go/datastore/super-mario-maker" + "github.com/PretendoNetwork/super-mario-maker-secure/database" + "github.com/PretendoNetwork/super-mario-maker-secure/globals" ) -func getBufferQueue(err error, client *nex.Client, callID uint32, param *nexproto.BufferQueueParam) { +func GetBufferQueue(err error, client *nex.Client, callID uint32, param *datastore_super_mario_maker.BufferQueueParam) { // TODO: complete this - rmcResponseStream := nex.NewStreamOut(nexServer) + rmcResponseStream := nex.NewStreamOut(globals.NEXServer) var pBufferQueue [][]byte @@ -18,7 +20,7 @@ func getBufferQueue(err error, client *nex.Client, callID uint32, param *nexprot case 0: // unknown pBufferQueue = make([][]byte, 0) case 3: // death data - pBufferQueue = getBufferQueueDeathData(param.DataID) + pBufferQueue = database.GetBufferQueueDeathData(param.DataID) default: fmt.Printf("[Warning] DataStoreSMMProtocol::GetBufferQueue Unsupported slot: %v\n", param.Slot) } @@ -27,8 +29,8 @@ func getBufferQueue(err error, client *nex.Client, callID uint32, param *nexprot rmcResponseBody := rmcResponseStream.Bytes() - rmcResponse := nex.NewRMCResponse(nexproto.DataStoreSMMProtocolID, callID) - rmcResponse.SetSuccess(nexproto.DataStoreSMMMethodGetBufferQueue, rmcResponseBody) + rmcResponse := nex.NewRMCResponse(datastore_super_mario_maker.ProtocolID, callID) + rmcResponse.SetSuccess(datastore_super_mario_maker.MethodGetBufferQueue, rmcResponseBody) rmcResponseBytes := rmcResponse.Bytes() @@ -43,5 +45,5 @@ func getBufferQueue(err error, client *nex.Client, callID uint32, param *nexprot responsePacket.AddFlag(nex.FlagNeedsAck) responsePacket.AddFlag(nex.FlagReliable) - nexServer.Send(responsePacket) + globals.NEXServer.Send(responsePacket) } diff --git a/get_course_record.go b/nex/datastore/super-mario-maker/get_course_record.go similarity index 51% rename from get_course_record.go rename to nex/datastore/super-mario-maker/get_course_record.go index a99fb7d..f03b436 100644 --- a/get_course_record.go +++ b/nex/datastore/super-mario-maker/get_course_record.go @@ -1,19 +1,21 @@ -package main +package nex_datastore_super_mario_maker import ( nex "github.com/PretendoNetwork/nex-go" - nexproto "github.com/PretendoNetwork/nex-protocols-go" + datastore_super_mario_maker "github.com/PretendoNetwork/nex-protocols-go/datastore/super-mario-maker" + "github.com/PretendoNetwork/super-mario-maker-secure/database" + "github.com/PretendoNetwork/super-mario-maker-secure/globals" ) -func getCourseRecord(err error, client *nex.Client, callID uint32, param *nexproto.DataStoreGetCourseRecordParam) { - worldRecord := getCourseWorldRecord(param.DataID) +func GetCourseRecord(err error, client *nex.Client, callID uint32, param *datastore_super_mario_maker.DataStoreGetCourseRecordParam) { + worldRecord := database.GetCourseWorldRecord(param.DataID) - rmcResponse := nex.NewRMCResponse(nexproto.DataStoreSMMProtocolID, callID) + rmcResponse := nex.NewRMCResponse(datastore_super_mario_maker.ProtocolID, callID) if worldRecord == nil { rmcResponse.SetError(0x690004) } else { - result := nexproto.NewDataStoreGetCourseRecordResult() + result := datastore_super_mario_maker.NewDataStoreGetCourseRecordResult() result.DataID = param.DataID result.Slot = param.Slot result.FirstPID = worldRecord.FirstPID @@ -22,12 +24,12 @@ func getCourseRecord(err error, client *nex.Client, callID uint32, param *nexpro result.CreatedTime = worldRecord.CreatedTime result.UpdatedTime = worldRecord.UpdatedTime - rmcResponseStream := nex.NewStreamOut(nexServer) + rmcResponseStream := nex.NewStreamOut(globals.NEXServer) rmcResponseStream.WriteStructure(result) rmcResponseBody := rmcResponseStream.Bytes() - rmcResponse.SetSuccess(nexproto.DataStoreSMMMethodGetCourseRecord, rmcResponseBody) + rmcResponse.SetSuccess(datastore_super_mario_maker.MethodGetCourseRecord, rmcResponseBody) } rmcResponseBytes := rmcResponse.Bytes() @@ -43,5 +45,5 @@ func getCourseRecord(err error, client *nex.Client, callID uint32, param *nexpro responsePacket.AddFlag(nex.FlagNeedsAck) responsePacket.AddFlag(nex.FlagReliable) - nexServer.Send(responsePacket) + globals.NEXServer.Send(responsePacket) } diff --git a/nex/datastore/super-mario-maker/get_custom_ranking_by_data_id.go b/nex/datastore/super-mario-maker/get_custom_ranking_by_data_id.go new file mode 100644 index 0000000..8bffa56 --- /dev/null +++ b/nex/datastore/super-mario-maker/get_custom_ranking_by_data_id.go @@ -0,0 +1,97 @@ +package nex_datastore_super_mario_maker + +import ( + nex "github.com/PretendoNetwork/nex-go" + datastore_super_mario_maker "github.com/PretendoNetwork/nex-protocols-go/datastore/super-mario-maker" + "github.com/PretendoNetwork/super-mario-maker-secure/database" + "github.com/PretendoNetwork/super-mario-maker-secure/globals" + "github.com/PretendoNetwork/super-mario-maker-secure/utility" +) + +func GetCustomRankingByDataId(err error, client *nex.Client, callID uint32, param *datastore_super_mario_maker.DataStoreGetCustomRankingByDataIdParam) { + var pRankingResult []*datastore_super_mario_maker.DataStoreCustomRankingResult + var pResults []uint32 + + switch param.ApplicationId { + case 0: + if len(param.DataIdList) == 0 { // Starred courses + pRankingResult, pResults = getCustomRankingByDataIdStarredCourses(client.PID()) + } else { // Played courses + pRankingResult, pResults = getCustomRankingByDataIdCourseMetadata(param) + } + case 300000000: // Mii data + pRankingResult, pResults = getCustomRankingByDataIdMiiData(param) + default: // Normal metadata + pRankingResult, pResults = getCustomRankingByDataIdCourseMetadata(param) + } + + rmcResponseStream := nex.NewStreamOut(globals.NEXServer) + + rmcResponseStream.WriteListStructure(pRankingResult) + rmcResponseStream.WriteListUInt32LE(pResults) + + rmcResponseBody := rmcResponseStream.Bytes() + + rmcResponse := nex.NewRMCResponse(datastore_super_mario_maker.ProtocolID, callID) + rmcResponse.SetSuccess(datastore_super_mario_maker.MethodGetCustomRankingByDataId, rmcResponseBody) + + rmcResponseBytes := rmcResponse.Bytes() + + responsePacket, _ := nex.NewPacketV1(client, nil) + + responsePacket.SetVersion(1) + responsePacket.SetSource(0xA1) + responsePacket.SetDestination(0xAF) + responsePacket.SetType(nex.DataPacket) + responsePacket.SetPayload(rmcResponseBytes) + + responsePacket.AddFlag(nex.FlagNeedsAck) + responsePacket.AddFlag(nex.FlagReliable) + + globals.NEXServer.Send(responsePacket) +} + +func getCustomRankingByDataIdStarredCourses(pid uint32) ([]*datastore_super_mario_maker.DataStoreCustomRankingResult, []uint32) { + courseMetadatas := database.GetUserStarredCourses(pid) + + pRankingResult := make([]*datastore_super_mario_maker.DataStoreCustomRankingResult, 0) + pResults := make([]uint32, 0) + + for _, courseMetadata := range courseMetadatas { + pRankingResult = append(pRankingResult, utility.CourseMetadataToDataStoreCustomRankingResult(courseMetadata)) + pResults = append(pResults, 0x690001) + } + + return pRankingResult, pResults +} + +func getCustomRankingByDataIdMiiData(param *datastore_super_mario_maker.DataStoreGetCustomRankingByDataIdParam) ([]*datastore_super_mario_maker.DataStoreCustomRankingResult, []uint32) { + pRankingResult := make([]*datastore_super_mario_maker.DataStoreCustomRankingResult, 0) + pResults := make([]uint32, 0) + + for _, pid := range param.DataIdList { + pid := uint32(pid) + miiInfo := database.GetUserMiiInfoByPID(pid) // This isn't actually a PID when using the official servers! I set it as one to make this easier for me + + if miiInfo != nil { + pRankingResult = append(pRankingResult, utility.UserMiiDataToDataStoreCustomRankingResult(pid, miiInfo)) + pResults = append(pResults, 0x690001) + } + } + + return pRankingResult, pResults +} + +func getCustomRankingByDataIdCourseMetadata(param *datastore_super_mario_maker.DataStoreGetCustomRankingByDataIdParam) ([]*datastore_super_mario_maker.DataStoreCustomRankingResult, []uint32) { + courseMetadatas := database.GetCourseMetadataByDataIDs(param.DataIdList) + + pRankingResult := make([]*datastore_super_mario_maker.DataStoreCustomRankingResult, 0) + pResults := make([]uint32, 0) + + for _, courseMetadata := range courseMetadatas { + pRankingResult = append(pRankingResult, utility.CourseMetadataToDataStoreCustomRankingResult(courseMetadata)) + pResults = append(pResults, 0x690001) + } + + return pRankingResult, pResults +} diff --git a/get_deletion_reason.go b/nex/datastore/super-mario-maker/get_deletion_reason.go similarity index 58% rename from get_deletion_reason.go rename to nex/datastore/super-mario-maker/get_deletion_reason.go index 06adfc0..c83559d 100644 --- a/get_deletion_reason.go +++ b/nex/datastore/super-mario-maker/get_deletion_reason.go @@ -1,11 +1,12 @@ -package main +package nex_datastore_super_mario_maker import ( nex "github.com/PretendoNetwork/nex-go" - nexproto "github.com/PretendoNetwork/nex-protocols-go" + datastore_super_mario_maker "github.com/PretendoNetwork/nex-protocols-go/datastore/super-mario-maker" + "github.com/PretendoNetwork/super-mario-maker-secure/globals" ) -func getDeletionReason(err error, client *nex.Client, callID uint32, dataIdLst []uint64) { +func GetDeletionReason(err error, client *nex.Client, callID uint32, dataIdLst []uint64) { // TODO: Complete this pDeletionReasons := make([]uint32, 0) @@ -16,14 +17,14 @@ func getDeletionReason(err error, client *nex.Client, callID uint32, dataIdLst [ pDeletionReasons = append(pDeletionReasons, 0x690007) } - rmcResponseStream := nex.NewStreamOut(nexServer) + rmcResponseStream := nex.NewStreamOut(globals.NEXServer) rmcResponseStream.WriteListUInt32LE(pDeletionReasons) rmcResponseBody := rmcResponseStream.Bytes() - rmcResponse := nex.NewRMCResponse(nexproto.DataStoreSMMProtocolID, callID) - rmcResponse.SetSuccess(nexproto.DataStoreSMMMethodGetDeletionReason, rmcResponseBody) + rmcResponse := nex.NewRMCResponse(datastore_super_mario_maker.ProtocolID, callID) + rmcResponse.SetSuccess(datastore_super_mario_maker.MethodGetDeletionReason, rmcResponseBody) rmcResponseBytes := rmcResponse.Bytes() @@ -38,5 +39,5 @@ func getDeletionReason(err error, client *nex.Client, callID uint32, dataIdLst [ responsePacket.AddFlag(nex.FlagNeedsAck) responsePacket.AddFlag(nex.FlagReliable) - nexServer.Send(responsePacket) + globals.NEXServer.Send(responsePacket) } diff --git a/nex/datastore/super-mario-maker/get_metas_with_course_record.go b/nex/datastore/super-mario-maker/get_metas_with_course_record.go new file mode 100644 index 0000000..a81e948 --- /dev/null +++ b/nex/datastore/super-mario-maker/get_metas_with_course_record.go @@ -0,0 +1,38 @@ +package nex_datastore_super_mario_maker + +import ( + nex "github.com/PretendoNetwork/nex-go" + "github.com/PretendoNetwork/nex-protocols-go/datastore" + datastore_super_mario_maker "github.com/PretendoNetwork/nex-protocols-go/datastore/super-mario-maker" + "github.com/PretendoNetwork/super-mario-maker-secure/globals" +) + +func GetMetasWithCourseRecord(err error, client *nex.Client, callID uint32, dataStoreGetCourseRecordParams []*datastore_super_mario_maker.DataStoreGetCourseRecordParam, dataStoreGetMetaParam *datastore.DataStoreGetMetaParam) { + // TODO: complete this + + rmcResponseStream := nex.NewStreamOut(globals.NEXServer) + + rmcResponseStream.WriteUInt32LE(0x00000000) // pMetaInfo List length 0 + rmcResponseStream.WriteUInt32LE(0x00000000) // pCourseResults List length 0 + rmcResponseStream.WriteUInt32LE(0x00000000) // pResults List length 0 + + rmcResponseBody := rmcResponseStream.Bytes() + + rmcResponse := nex.NewRMCResponse(datastore_super_mario_maker.ProtocolID, callID) + rmcResponse.SetSuccess(datastore_super_mario_maker.MethodGetMetasWithCourseRecord, rmcResponseBody) + + rmcResponseBytes := rmcResponse.Bytes() + + responsePacket, _ := nex.NewPacketV1(client, nil) + + responsePacket.SetVersion(1) + responsePacket.SetSource(0xA1) + responsePacket.SetDestination(0xAF) + responsePacket.SetType(nex.DataPacket) + responsePacket.SetPayload(rmcResponseBytes) + + responsePacket.AddFlag(nex.FlagNeedsAck) + responsePacket.AddFlag(nex.FlagReliable) + + globals.NEXServer.Send(responsePacket) +} diff --git a/nex/datastore/super-mario-maker/get_object_infos.go b/nex/datastore/super-mario-maker/get_object_infos.go new file mode 100644 index 0000000..4399bd4 --- /dev/null +++ b/nex/datastore/super-mario-maker/get_object_infos.go @@ -0,0 +1,55 @@ +package nex_datastore_super_mario_maker + +import ( + "fmt" + "os" + + nex "github.com/PretendoNetwork/nex-go" + "github.com/PretendoNetwork/nex-protocols-go/datastore" + datastore_super_mario_maker "github.com/PretendoNetwork/nex-protocols-go/datastore/super-mario-maker" + "github.com/PretendoNetwork/super-mario-maker-secure/database" + "github.com/PretendoNetwork/super-mario-maker-secure/globals" +) + +func GetObjectInfos(err error, client *nex.Client, callID uint32, dataIDs []uint64) { + pInfos := make([]*datastore_super_mario_maker.DataStoreFileServerObjectInfo, 0) + + courseMetadatas := database.GetCourseMetadataByDataIDs(dataIDs) + + for _, courseMetadata := range courseMetadatas { + info := datastore_super_mario_maker.NewDataStoreFileServerObjectInfo() + info.DataID = courseMetadata.DataID + info.GetInfo = datastore.NewDataStoreReqGetInfo() + info.GetInfo.URL = fmt.Sprintf("http://%s.b-cdn.net/course/%d.bin", os.Getenv("S3_BUCKET_NAME"), courseMetadata.DataID) + info.GetInfo.RequestHeaders = []*datastore.DataStoreKeyValue{} + info.GetInfo.Size = courseMetadata.Size + info.GetInfo.RootCA = []byte{} + info.GetInfo.DataID = courseMetadata.DataID + + pInfos = append(pInfos, info) + } + + rmcResponseStream := nex.NewStreamOut(globals.NEXServer) + + rmcResponseStream.WriteListStructure(pInfos) + + rmcResponseBody := rmcResponseStream.Bytes() + + rmcResponse := nex.NewRMCResponse(datastore_super_mario_maker.ProtocolID, callID) + rmcResponse.SetSuccess(datastore_super_mario_maker.MethodGetObjectInfos, rmcResponseBody) + + rmcResponseBytes := rmcResponse.Bytes() + + responsePacket, _ := nex.NewPacketV1(client, nil) + + responsePacket.SetVersion(1) + responsePacket.SetSource(0xA1) + responsePacket.SetDestination(0xAF) + responsePacket.SetType(nex.DataPacket) + responsePacket.SetPayload(rmcResponseBytes) + + responsePacket.AddFlag(nex.FlagNeedsAck) + responsePacket.AddFlag(nex.FlagReliable) + + globals.NEXServer.Send(responsePacket) +} diff --git a/prepare_attach_file.go b/nex/datastore/super-mario-maker/prepare_attach_file.go similarity index 52% rename from prepare_attach_file.go rename to nex/datastore/super-mario-maker/prepare_attach_file.go index 6ef0d70..1a2666e 100644 --- a/prepare_attach_file.go +++ b/nex/datastore/super-mario-maker/prepare_attach_file.go @@ -1,4 +1,4 @@ -package main +package nex_datastore_super_mario_maker import ( "crypto/hmac" @@ -10,10 +10,12 @@ import ( "time" nex "github.com/PretendoNetwork/nex-go" - nexproto "github.com/PretendoNetwork/nex-protocols-go" + "github.com/PretendoNetwork/nex-protocols-go/datastore" + datastore_super_mario_maker "github.com/PretendoNetwork/nex-protocols-go/datastore/super-mario-maker" + "github.com/PretendoNetwork/super-mario-maker-secure/globals" ) -func prepareAttachFile(err error, client *nex.Client, callID uint32, dataStoreAttachFileParam *nexproto.DataStoreAttachFileParam) { +func PrepareAttachFile(err error, client *nex.Client, callID uint32, dataStoreAttachFileParam *datastore_super_mario_maker.DataStoreAttachFileParam) { key := fmt.Sprintf("image/%d.jpg", dataStoreAttachFileParam.ReferDataID) bucket := os.Getenv("S3_BUCKET_NAME") date := strconv.Itoa(int(time.Now().Unix())) @@ -21,55 +23,55 @@ func prepareAttachFile(err error, client *nex.Client, callID uint32, dataStoreAt data := pid + bucket + key + date - hmac := hmac.New(sha256.New, hmacSecret) + hmac := hmac.New(sha256.New, globals.HMACSecret) hmac.Write([]byte(data)) signature := hex.EncodeToString(hmac.Sum(nil)) - fieldBucket := nexproto.NewDataStoreKeyValue() + fieldBucket := datastore.NewDataStoreKeyValue() fieldBucket.Key = "bucket" fieldBucket.Value = bucket - fieldKey := nexproto.NewDataStoreKeyValue() + fieldKey := datastore.NewDataStoreKeyValue() fieldKey.Key = "key" fieldKey.Value = key - fieldACL := nexproto.NewDataStoreKeyValue() + fieldACL := datastore.NewDataStoreKeyValue() fieldACL.Key = "acl" fieldACL.Value = "public-read" - fieldContentType := nexproto.NewDataStoreKeyValue() + fieldContentType := datastore.NewDataStoreKeyValue() fieldContentType.Key = "content-type" fieldContentType.Value = "image/jpeg" - fieldPID := nexproto.NewDataStoreKeyValue() + fieldPID := datastore.NewDataStoreKeyValue() fieldPID.Key = "pid" fieldPID.Value = pid - fieldDate := nexproto.NewDataStoreKeyValue() + fieldDate := datastore.NewDataStoreKeyValue() fieldDate.Key = "date" fieldDate.Value = date - fieldSignature := nexproto.NewDataStoreKeyValue() + fieldSignature := datastore.NewDataStoreKeyValue() fieldSignature.Key = "signature" fieldSignature.Value = signature - rmcResponseStream := nex.NewStreamOut(nexServer) + rmcResponseStream := nex.NewStreamOut(globals.NEXServer) - pReqPostInfo := nexproto.NewDataStoreReqPostInfo() + pReqPostInfo := datastore.NewDataStoreReqPostInfo() pReqPostInfo.DataID = dataStoreAttachFileParam.ReferDataID pReqPostInfo.URL = os.Getenv("DATASTORE_UPLOAD_URL") - pReqPostInfo.RequestHeaders = []*nexproto.DataStoreKeyValue{} - pReqPostInfo.FormFields = []*nexproto.DataStoreKeyValue{fieldBucket, fieldKey, fieldACL, fieldContentType, fieldPID, fieldDate, fieldSignature} + pReqPostInfo.RequestHeaders = []*datastore.DataStoreKeyValue{} + pReqPostInfo.FormFields = []*datastore.DataStoreKeyValue{fieldBucket, fieldKey, fieldACL, fieldContentType, fieldPID, fieldDate, fieldSignature} pReqPostInfo.RootCACert = []byte{} rmcResponseStream.WriteStructure(pReqPostInfo) rmcResponseBody := rmcResponseStream.Bytes() - rmcResponse := nex.NewRMCResponse(nexproto.DataStoreProtocolID, callID) - rmcResponse.SetSuccess(nexproto.DataStoreSMMMethodPrepareAttachFile, rmcResponseBody) + rmcResponse := nex.NewRMCResponse(datastore_super_mario_maker.ProtocolID, callID) + rmcResponse.SetSuccess(datastore_super_mario_maker.MethodPrepareAttachFile, rmcResponseBody) rmcResponseBytes := rmcResponse.Bytes() @@ -84,5 +86,5 @@ func prepareAttachFile(err error, client *nex.Client, callID uint32, dataStoreAt responsePacket.AddFlag(nex.FlagNeedsAck) responsePacket.AddFlag(nex.FlagReliable) - nexServer.Send(responsePacket) + globals.NEXServer.Send(responsePacket) } diff --git a/rate_custom_ranking.go b/nex/datastore/super-mario-maker/rate_custom_ranking.go similarity index 78% rename from rate_custom_ranking.go rename to nex/datastore/super-mario-maker/rate_custom_ranking.go index c581aac..26c702f 100644 --- a/rate_custom_ranking.go +++ b/nex/datastore/super-mario-maker/rate_custom_ranking.go @@ -1,11 +1,13 @@ -package main +package nex_datastore_super_mario_maker import ( nex "github.com/PretendoNetwork/nex-go" - nexproto "github.com/PretendoNetwork/nex-protocols-go" + datastore_super_mario_maker "github.com/PretendoNetwork/nex-protocols-go/datastore/super-mario-maker" + "github.com/PretendoNetwork/super-mario-maker-secure/database" + "github.com/PretendoNetwork/super-mario-maker-secure/globals" ) -func rateCustomRanking(err error, client *nex.Client, callID uint32, params []*nexproto.DataStoreRateCustomRankingParam) { +func RateCustomRanking(err error, client *nex.Client, callID uint32, params []*datastore_super_mario_maker.DataStoreRateCustomRankingParam) { /* This has to change. We need to figure out what DataStoreRateCustomRankingParam.applicationId means. @@ -81,16 +83,16 @@ func rateCustomRanking(err error, client *nex.Client, callID uint32, params []*n if len(params) == 2 { // assume "course clear" action - incrementCourseClearCount(params[0].DataID) + database.IncrementCourseClearCount(params[0].DataID) } if len(params) == 12 { // assume "star course" action - incrementCourseStarCount(params[0].DataID) + database.IncrementCourseStarCount(params[0].DataID) } - rmcResponse := nex.NewRMCResponse(nexproto.DataStoreSMMProtocolID, callID) - rmcResponse.SetSuccess(nexproto.DataStoreSMMMethodRateCustomRanking, nil) + rmcResponse := nex.NewRMCResponse(datastore_super_mario_maker.ProtocolID, callID) + rmcResponse.SetSuccess(datastore_super_mario_maker.MethodRateCustomRanking, nil) rmcResponseBytes := rmcResponse.Bytes() @@ -105,5 +107,5 @@ func rateCustomRanking(err error, client *nex.Client, callID uint32, params []*n responsePacket.AddFlag(nex.FlagNeedsAck) responsePacket.AddFlag(nex.FlagReliable) - nexServer.Send(responsePacket) + globals.NEXServer.Send(responsePacket) } diff --git a/nex/datastore/super-mario-maker/recommended_course_search_object.go b/nex/datastore/super-mario-maker/recommended_course_search_object.go new file mode 100644 index 0000000..ce06b7b --- /dev/null +++ b/nex/datastore/super-mario-maker/recommended_course_search_object.go @@ -0,0 +1,52 @@ +package nex_datastore_super_mario_maker + +import ( + nex "github.com/PretendoNetwork/nex-go" + "github.com/PretendoNetwork/nex-protocols-go/datastore" + datastore_super_mario_maker "github.com/PretendoNetwork/nex-protocols-go/datastore/super-mario-maker" + "github.com/PretendoNetwork/super-mario-maker-secure/database" + "github.com/PretendoNetwork/super-mario-maker-secure/globals" + "github.com/PretendoNetwork/super-mario-maker-secure/utility" +) + +func RecommendedCourseSearchObject(err error, client *nex.Client, callID uint32, param *datastore.DataStoreSearchParam, extraData []string) { + // TODO: complete this + + pRankingResults := make([]*datastore_super_mario_maker.DataStoreCustomRankingResult, 0) + + // TEMP FOR SHUTTER TO TEST THINGS + if client.PID() == 1049991375 { + courseMetadata := database.GetCourseMetadataByDataID(145) // specific course shutter wants + pRankingResults = append(pRankingResults, utility.CourseMetadataToDataStoreCustomRankingResult(courseMetadata)) + } else { + courseMetadatas := database.GetCourseMetadatasByLimit(100) // In PCAPs param.minimalRatingFrequency is 100 but is 0 here? + + for _, courseMetadata := range courseMetadatas { + pRankingResults = append(pRankingResults, utility.CourseMetadataToDataStoreCustomRankingResult(courseMetadata)) + } + } + + rmcResponseStream := nex.NewStreamOut(globals.NEXServer) + + rmcResponseStream.WriteListStructure(pRankingResults) + + rmcResponseBody := rmcResponseStream.Bytes() + + rmcResponse := nex.NewRMCResponse(datastore_super_mario_maker.ProtocolID, callID) + rmcResponse.SetSuccess(datastore_super_mario_maker.MethodRecommendedCourseSearchObject, rmcResponseBody) + + rmcResponseBytes := rmcResponse.Bytes() + + responsePacket, _ := nex.NewPacketV1(client, nil) + + responsePacket.SetVersion(1) + responsePacket.SetSource(0xA1) + responsePacket.SetDestination(0xAF) + responsePacket.SetType(nex.DataPacket) + responsePacket.SetPayload(rmcResponseBytes) + + responsePacket.AddFlag(nex.FlagNeedsAck) + responsePacket.AddFlag(nex.FlagReliable) + + globals.NEXServer.Send(responsePacket) +} diff --git a/nex/datastore/super-mario-maker/suggested_course_search_object.go b/nex/datastore/super-mario-maker/suggested_course_search_object.go new file mode 100644 index 0000000..130cdb1 --- /dev/null +++ b/nex/datastore/super-mario-maker/suggested_course_search_object.go @@ -0,0 +1,54 @@ +package nex_datastore_super_mario_maker + +import ( + "strconv" + + nex "github.com/PretendoNetwork/nex-go" + "github.com/PretendoNetwork/nex-protocols-go/datastore" + datastore_super_mario_maker "github.com/PretendoNetwork/nex-protocols-go/datastore/super-mario-maker" + "github.com/PretendoNetwork/super-mario-maker-secure/database" + "github.com/PretendoNetwork/super-mario-maker-secure/globals" + "github.com/PretendoNetwork/super-mario-maker-secure/utility" +) + +func SuggestedCourseSearchObject(err error, client *nex.Client, callID uint32, param *datastore.DataStoreSearchParam, extraData []string) { + // TODO: complete this + + courseID, _ := strconv.ParseUint(extraData[0], 0, 64) + + if utility.UserNotOwnCourse(courseID, client.PID()) { + database.IncrementCourseAttemptCount(courseID) // We also know this is when a user attempts a course + } + + pRankingResults := make([]*datastore_super_mario_maker.DataStoreCustomRankingResult, 0) + + courseMetadatas := database.GetCourseMetadatasByLimit(4) // In PCAPs param.minimalRatingFrequency is 4 but is 0 here? + + for _, courseMetadata := range courseMetadatas { + pRankingResults = append(pRankingResults, utility.CourseMetadataToDataStoreCustomRankingResult(courseMetadata)) + } + + rmcResponseStream := nex.NewStreamOut(globals.NEXServer) + + rmcResponseStream.WriteListStructure(pRankingResults) + + rmcResponseBody := rmcResponseStream.Bytes() + + rmcResponse := nex.NewRMCResponse(datastore_super_mario_maker.ProtocolID, callID) + rmcResponse.SetSuccess(datastore_super_mario_maker.MethodSuggestedCourseSearchObject, rmcResponseBody) + + rmcResponseBytes := rmcResponse.Bytes() + + responsePacket, _ := nex.NewPacketV1(client, nil) + + responsePacket.SetVersion(1) + responsePacket.SetSource(0xA1) + responsePacket.SetDestination(0xAF) + responsePacket.SetType(nex.DataPacket) + responsePacket.SetPayload(rmcResponseBytes) + + responsePacket.AddFlag(nex.FlagNeedsAck) + responsePacket.AddFlag(nex.FlagReliable) + + globals.NEXServer.Send(responsePacket) +} diff --git a/nex/datastore/super-mario-maker/upload_course_record.go b/nex/datastore/super-mario-maker/upload_course_record.go new file mode 100644 index 0000000..2726c22 --- /dev/null +++ b/nex/datastore/super-mario-maker/upload_course_record.go @@ -0,0 +1,30 @@ +package nex_datastore_super_mario_maker + +import ( + nex "github.com/PretendoNetwork/nex-go" + datastore_super_mario_maker "github.com/PretendoNetwork/nex-protocols-go/datastore/super-mario-maker" + "github.com/PretendoNetwork/super-mario-maker-secure/database" + "github.com/PretendoNetwork/super-mario-maker-secure/globals" +) + +func UploadCourseRecord(err error, client *nex.Client, callID uint32, param *datastore_super_mario_maker.DataStoreUploadCourseRecordParam) { + database.UpdateCourseWorldRecord(param.DataID, client.PID(), param.Score) + + rmcResponse := nex.NewRMCResponse(datastore_super_mario_maker.ProtocolID, callID) + rmcResponse.SetSuccess(datastore_super_mario_maker.MethodUploadCourseRecord, nil) + + rmcResponseBytes := rmcResponse.Bytes() + + responsePacket, _ := nex.NewPacketV1(client, nil) + + responsePacket.SetVersion(1) + responsePacket.SetSource(0xA1) + responsePacket.SetDestination(0xAF) + responsePacket.SetType(nex.DataPacket) + responsePacket.SetPayload(rmcResponseBytes) + + responsePacket.AddFlag(nex.FlagNeedsAck) + responsePacket.AddFlag(nex.FlagReliable) + + globals.NEXServer.Send(responsePacket) +} diff --git a/deliver_message.go b/nex/message-delivery/deliver_message.go similarity index 55% rename from deliver_message.go rename to nex/message-delivery/deliver_message.go index a4207d1..0be1936 100644 --- a/deliver_message.go +++ b/nex/message-delivery/deliver_message.go @@ -2,12 +2,13 @@ package main import ( nex "github.com/PretendoNetwork/nex-go" - nexproto "github.com/PretendoNetwork/nex-protocols-go" + message_delivery "github.com/PretendoNetwork/nex-protocols-go/message-delivery" + "github.com/PretendoNetwork/super-mario-maker-secure/globals" ) -func deliverMessage(err error, client *nex.Client, callID uint32, oUserMessage nex.StructureInterface) { - rmcResponse := nex.NewRMCResponse(nexproto.MessageDeliveryProtocolID, callID) - rmcResponse.SetSuccess(nexproto.MessageDeliveryMethodDeliverMessage, nil) +func DeliverMessage(err error, client *nex.Client, callID uint32, oUserMessage nex.StructureInterface) { + rmcResponse := nex.NewRMCResponse(message_delivery.ProtocolID, callID) + rmcResponse.SetSuccess(message_delivery.MethodDeliverMessage, nil) rmcResponseBytes := rmcResponse.Bytes() @@ -22,5 +23,5 @@ func deliverMessage(err error, client *nex.Client, callID uint32, oUserMessage n responsePacket.AddFlag(nex.FlagNeedsAck) responsePacket.AddFlag(nex.FlagReliable) - nexServer.Send(responsePacket) + globals.NEXServer.Send(responsePacket) } diff --git a/nex/register_common_protocols.go b/nex/register_common_protocols.go new file mode 100644 index 0000000..7615dfc --- /dev/null +++ b/nex/register_common_protocols.go @@ -0,0 +1,15 @@ +package nex + +import ( + secureconnection "github.com/PretendoNetwork/nex-protocols-common-go/secure-connection" + "github.com/PretendoNetwork/super-mario-maker-secure/globals" + nex_secure_connection_common "github.com/PretendoNetwork/super-mario-maker-secure/nex/secure-connection/common" +) + +func registerCommonProtocols() { + secureConnectionProtocol := secureconnection.NewCommonSecureConnectionProtocol(globals.NEXServer) + + secureConnectionProtocol.AddConnection(nex_secure_connection_common.AddConnection) // * Stubbed + secureConnectionProtocol.UpdateConnection(nex_secure_connection_common.UpdateConnection) // * Stubbed + secureConnectionProtocol.DoesConnectionExist(nex_secure_connection_common.DoesConnectionExist) // * Stubbed +} diff --git a/nex/register_nex_protocols.go b/nex/register_nex_protocols.go new file mode 100644 index 0000000..e7f14c9 --- /dev/null +++ b/nex/register_nex_protocols.go @@ -0,0 +1,42 @@ +package nex + +import ( + "github.com/PretendoNetwork/nex-protocols-go/datastore" + datastore_super_mario_maker "github.com/PretendoNetwork/nex-protocols-go/datastore/super-mario-maker" + "github.com/PretendoNetwork/super-mario-maker-secure/globals" + nex_datastore "github.com/PretendoNetwork/super-mario-maker-secure/nex/datastore" + nex_datastore_super_mario_maker "github.com/PretendoNetwork/super-mario-maker-secure/nex/datastore/super-mario-maker" +) + +func registerNEXProtocols() { + datastoreProtocol := datastore.NewDataStoreProtocol(globals.NEXServer) + + datastoreProtocol.GetMeta(nex_datastore.GetMeta) + datastoreProtocol.PreparePostObject(nex_datastore.PreparePostObject) + datastoreProtocol.PrepareGetObject(nex_datastore.PrepareGetObject) + datastoreProtocol.CompletePostObject(nex_datastore.CompletePostObject) + datastoreProtocol.GetMetasMultipleParam(nex_datastore.GetMetasMultipleParam) + datastoreProtocol.ChangeMeta(nex_datastore.ChangeMeta) + datastoreProtocol.RateObjects(nex_datastore.RateObjects) + + datastoreSMMProtocol := datastore_super_mario_maker.NewDataStoreSuperMarioMakerProtocol(globals.NEXServer) + + datastoreSMMProtocol.GetObjectInfos(nex_datastore_super_mario_maker.GetObjectInfos) + datastoreSMMProtocol.RateCustomRanking(nex_datastore_super_mario_maker.RateCustomRanking) + datastoreSMMProtocol.GetCustomRankingByDataId(nex_datastore_super_mario_maker.GetCustomRankingByDataId) + datastoreSMMProtocol.AddToBufferQueues(nex_datastore_super_mario_maker.AddToBufferQueues) + datastoreSMMProtocol.GetBufferQueue(nex_datastore_super_mario_maker.GetBufferQueue) + datastoreSMMProtocol.CompleteAttachFile(nex_datastore_super_mario_maker.CompleteAttachFile) + datastoreSMMProtocol.PrepareAttachFile(nex_datastore_super_mario_maker.PrepareAttachFile) + datastoreSMMProtocol.GetApplicationConfig(nex_datastore_super_mario_maker.GetApplicationConfig) + datastoreSMMProtocol.FollowingsLatestCourseSearchObject(nex_datastore_super_mario_maker.FollowingsLatestCourseSearchObject) + datastoreSMMProtocol.RecommendedCourseSearchObject(nex_datastore_super_mario_maker.RecommendedCourseSearchObject) + datastoreSMMProtocol.SuggestedCourseSearchObject(nex_datastore_super_mario_maker.SuggestedCourseSearchObject) + datastoreSMMProtocol.UploadCourseRecord(nex_datastore_super_mario_maker.UploadCourseRecord) + datastoreSMMProtocol.GetCourseRecord(nex_datastore_super_mario_maker.GetCourseRecord) + datastoreSMMProtocol.GetApplicationConfigString(nex_datastore_super_mario_maker.GetApplicationConfigString) + datastoreSMMProtocol.GetDeletionReason(nex_datastore_super_mario_maker.GetDeletionReason) + datastoreSMMProtocol.GetMetasWithCourseRecord(nex_datastore_super_mario_maker.GetMetasWithCourseRecord) + datastoreSMMProtocol.CheckRateCustomRankingCounter(nex_datastore_super_mario_maker.CheckRateCustomRankingCounter) + datastoreSMMProtocol.CTRPickUpCourseSearchObject(nex_datastore_super_mario_maker.CTRPickUpCourseSearchObject) +} diff --git a/nex/secure-connection/common/add_connection.go b/nex/secure-connection/common/add_connection.go new file mode 100644 index 0000000..0fec3c4 --- /dev/null +++ b/nex/secure-connection/common/add_connection.go @@ -0,0 +1,5 @@ +package nex_secure_connection_common + +func AddConnection(rvcid uint32, urls []string, ip string, port string) { + // TODO - Stubbed +} diff --git a/nex/secure-connection/common/does_connection_exist.go b/nex/secure-connection/common/does_connection_exist.go new file mode 100644 index 0000000..bc0ba47 --- /dev/null +++ b/nex/secure-connection/common/does_connection_exist.go @@ -0,0 +1,7 @@ +package nex_secure_connection_common + +func DoesConnectionExist(rvcid uint32) bool { + // TODO - Stubbed + + return false +} diff --git a/nex/secure-connection/common/update_connection.go b/nex/secure-connection/common/update_connection.go new file mode 100644 index 0000000..7f7b659 --- /dev/null +++ b/nex/secure-connection/common/update_connection.go @@ -0,0 +1,5 @@ +package nex_secure_connection_common + +func UpdateConnection(rvcid uint32, urls []string, ip string, port string) { + // TODO - Stubbed +} diff --git a/nex/server.go b/nex/server.go new file mode 100644 index 0000000..b17c148 --- /dev/null +++ b/nex/server.go @@ -0,0 +1,37 @@ +package nex + +import ( + "fmt" + "os" + + nex "github.com/PretendoNetwork/nex-go" + "github.com/PretendoNetwork/super-mario-maker-secure/globals" +) + +func StartNEXServer() { + globals.NEXServer = nex.NewServer() + globals.NEXServer.SetPRUDPVersion(1) + globals.NEXServer.SetPRUDPProtocolMinorVersion(2) + globals.NEXServer.SetDefaultNEXVersion(&nex.NEXVersion{ + Major: 3, + Minor: 8, + Patch: 3, + }) + globals.NEXServer.SetKerberosPassword(os.Getenv("KERBEROS_PASSWORD")) + globals.NEXServer.SetAccessKey("9f2b4678") + + globals.NEXServer.On("Data", func(packet *nex.PacketV1) { + request := packet.RMCRequest() + + fmt.Println("==SMM1 - Secure==") + fmt.Printf("Protocol ID: %#v\n", request.ProtocolID()) + fmt.Printf("Method ID: %#v\n", request.MethodID()) + fmt.Println("===============") + }) + + // * Register the common handlers first so that they can be overridden if needed + registerCommonProtocols() + registerNEXProtocols() + + globals.NEXServer.Listen(":60003") +} diff --git a/prepare_post_object.go b/prepare_post_object.go deleted file mode 100644 index 4e0fab5..0000000 --- a/prepare_post_object.go +++ /dev/null @@ -1,98 +0,0 @@ -package main - -import ( - "crypto/hmac" - "crypto/sha256" - "encoding/hex" - "fmt" - "math/rand" - "os" - "strconv" - "time" - - nex "github.com/PretendoNetwork/nex-go" - nexproto "github.com/PretendoNetwork/nex-protocols-go" -) - -func preparePostObject(err error, client *nex.Client, callID uint32, param *nexproto.DataStorePreparePostParam) { - rand.Seed(time.Now().UnixNano()) - nodeID := rand.Intn(len(dataStoreIDGenerators)) - - dataStoreIDGenerator := dataStoreIDGenerators[nodeID] - - dataID := dataStoreIDGenerator.Next() - setDataStoreIDGeneratorLastID(nodeID, dataStoreIDGenerator.Value) - initializeCourseData(dataID, client.PID(), param.Size, param.Name, param.Flag, param.ExtraData, param.DataType, param.Period) - - if param.DataType != 1 { // 1 is Mii data, assume other values are course meta data - updateCourseMetaBinary(dataID, param.MetaBinary) - } - - key := fmt.Sprintf("course/%d.bin", dataID) - bucket := os.Getenv("S3_BUCKET_NAME") - date := strconv.Itoa(int(time.Now().Unix())) - pid := strconv.Itoa(int(client.PID())) - - data := pid + bucket + key + date - - hmac := hmac.New(sha256.New, hmacSecret) - hmac.Write([]byte(data)) - - signature := hex.EncodeToString(hmac.Sum(nil)) - - fieldBucket := nexproto.NewDataStoreKeyValue() - fieldBucket.Key = "bucket" - fieldBucket.Value = bucket - - fieldKey := nexproto.NewDataStoreKeyValue() - fieldKey.Key = "key" - fieldKey.Value = key - - fieldACL := nexproto.NewDataStoreKeyValue() - fieldACL.Key = "acl" - fieldACL.Value = "private" - - fieldPID := nexproto.NewDataStoreKeyValue() - fieldPID.Key = "pid" - fieldPID.Value = pid - - fieldDate := nexproto.NewDataStoreKeyValue() - fieldDate.Key = "date" - fieldDate.Value = date - - fieldSignature := nexproto.NewDataStoreKeyValue() - fieldSignature.Key = "signature" - fieldSignature.Value = signature - - rmcResponseStream := nex.NewStreamOut(nexServer) - - pReqPostInfo := nexproto.NewDataStoreReqPostInfo() - - pReqPostInfo.DataID = dataID - pReqPostInfo.URL = os.Getenv("DATASTORE_UPLOAD_URL") - pReqPostInfo.RequestHeaders = []*nexproto.DataStoreKeyValue{} - pReqPostInfo.FormFields = []*nexproto.DataStoreKeyValue{fieldBucket, fieldKey, fieldACL, fieldPID, fieldDate, fieldSignature} - pReqPostInfo.RootCACert = []byte{} - - rmcResponseStream.WriteStructure(pReqPostInfo) - - rmcResponseBody := rmcResponseStream.Bytes() - - rmcResponse := nex.NewRMCResponse(nexproto.DataStoreProtocolID, callID) - rmcResponse.SetSuccess(nexproto.DataStoreMethodPreparePostObject, rmcResponseBody) - - rmcResponseBytes := rmcResponse.Bytes() - - responsePacket, _ := nex.NewPacketV1(client, nil) - - responsePacket.SetVersion(1) - responsePacket.SetSource(0xA1) - responsePacket.SetDestination(0xAF) - responsePacket.SetType(nex.DataPacket) - responsePacket.SetPayload(rmcResponseBytes) - - responsePacket.AddFlag(nex.FlagNeedsAck) - responsePacket.AddFlag(nex.FlagReliable) - - nexServer.Send(responsePacket) -} diff --git a/recommended_course_search_object.go b/recommended_course_search_object.go deleted file mode 100644 index 465baf0..0000000 --- a/recommended_course_search_object.go +++ /dev/null @@ -1,48 +0,0 @@ -package main - -import ( - nex "github.com/PretendoNetwork/nex-go" - nexproto "github.com/PretendoNetwork/nex-protocols-go" -) - -func recommendedCourseSearchObject(err error, client *nex.Client, callID uint32, param *nexproto.DataStoreSearchParam, extraData []string) { - // TODO: complete this - - pRankingResults := make([]*nexproto.DataStoreCustomRankingResult, 0) - - // TEMP FOR SHUTTER TO TEST THINGS - if client.PID() == 1049991375 { - courseMetadata := getCourseMetadataByDataID(145) // specific course shutter wants - pRankingResults = append(pRankingResults, courseMetadataToDataStoreCustomRankingResult(courseMetadata)) - } else { - courseMetadatas := getCourseMetadatasByLimit(100) // In PCAPs param.minimalRatingFrequency is 100 but is 0 here? - - for _, courseMetadata := range courseMetadatas { - pRankingResults = append(pRankingResults, courseMetadataToDataStoreCustomRankingResult(courseMetadata)) - } - } - - rmcResponseStream := nex.NewStreamOut(nexServer) - - rmcResponseStream.WriteListStructure(pRankingResults) - - rmcResponseBody := rmcResponseStream.Bytes() - - rmcResponse := nex.NewRMCResponse(nexproto.DataStoreSMMProtocolID, callID) - rmcResponse.SetSuccess(nexproto.DataStoreSMMMethodRecommendedCourseSearchObject, rmcResponseBody) - - rmcResponseBytes := rmcResponse.Bytes() - - responsePacket, _ := nex.NewPacketV1(client, nil) - - responsePacket.SetVersion(1) - responsePacket.SetSource(0xA1) - responsePacket.SetDestination(0xAF) - responsePacket.SetType(nex.DataPacket) - responsePacket.SetPayload(rmcResponseBytes) - - responsePacket.AddFlag(nex.FlagNeedsAck) - responsePacket.AddFlag(nex.FlagReliable) - - nexServer.Send(responsePacket) -} diff --git a/register.go b/register.go deleted file mode 100644 index 5eec1f9..0000000 --- a/register.go +++ /dev/null @@ -1,47 +0,0 @@ -package main - -import ( - "strconv" - - nex "github.com/PretendoNetwork/nex-go" - nexproto "github.com/PretendoNetwork/nex-protocols-go" -) - -func register(err error, client *nex.Client, callID uint32, stationUrls []*nex.StationURL) { - localStation := stationUrls[0] - - address := client.Address().IP.String() - port := strconv.Itoa(client.Address().Port) - - localStation.SetAddress(&address) - localStation.SetPort(&port) - - localStationURL := localStation.EncodeToString() - - rmcResponseStream := nex.NewStreamOut(nexServer) - - rmcResponseStream.WriteUInt32LE(0x10001) // Success - rmcResponseStream.WriteUInt32LE(nexServer.ConnectionIDCounter().Increment()) - rmcResponseStream.WriteString(localStationURL) - - rmcResponseBody := rmcResponseStream.Bytes() - - // Build response packet - rmcResponse := nex.NewRMCResponse(nexproto.SecureProtocolID, callID) - rmcResponse.SetSuccess(nexproto.SecureMethodRegisterEx, rmcResponseBody) - - rmcResponseBytes := rmcResponse.Bytes() - - responsePacket, _ := nex.NewPacketV1(client, nil) - - responsePacket.SetVersion(1) - responsePacket.SetSource(0xA1) - responsePacket.SetDestination(0xAF) - responsePacket.SetType(nex.DataPacket) - responsePacket.SetPayload(rmcResponseBytes) - - responsePacket.AddFlag(nex.FlagNeedsAck) - responsePacket.AddFlag(nex.FlagReliable) - - nexServer.Send(responsePacket) -} diff --git a/suggested_course_search_object.go b/suggested_course_search_object.go deleted file mode 100644 index cd3ccd5..0000000 --- a/suggested_course_search_object.go +++ /dev/null @@ -1,50 +0,0 @@ -package main - -import ( - "strconv" - - nex "github.com/PretendoNetwork/nex-go" - nexproto "github.com/PretendoNetwork/nex-protocols-go" -) - -func suggestedCourseSearchObject(err error, client *nex.Client, callID uint32, param *nexproto.DataStoreSearchParam, extraData []string) { - // TODO: complete this - - courseID, _ := strconv.ParseUint(extraData[0], 0, 64) - - if userNotOwnCourse(courseID, client.PID()) { - incrementCourseAttemptCount(courseID) // We also know this is when a user attempts a course - } - - pRankingResults := make([]*nexproto.DataStoreCustomRankingResult, 0) - - courseMetadatas := getCourseMetadatasByLimit(4) // In PCAPs param.minimalRatingFrequency is 4 but is 0 here? - - for _, courseMetadata := range courseMetadatas { - pRankingResults = append(pRankingResults, courseMetadataToDataStoreCustomRankingResult(courseMetadata)) - } - - rmcResponseStream := nex.NewStreamOut(nexServer) - - rmcResponseStream.WriteListStructure(pRankingResults) - - rmcResponseBody := rmcResponseStream.Bytes() - - rmcResponse := nex.NewRMCResponse(nexproto.DataStoreSMMProtocolID, callID) - rmcResponse.SetSuccess(nexproto.DataStoreSMMMethodSuggestedCourseSearchObject, rmcResponseBody) - - rmcResponseBytes := rmcResponse.Bytes() - - responsePacket, _ := nex.NewPacketV1(client, nil) - - responsePacket.SetVersion(1) - responsePacket.SetSource(0xA1) - responsePacket.SetDestination(0xAF) - responsePacket.SetType(nex.DataPacket) - responsePacket.SetPayload(rmcResponseBytes) - - responsePacket.AddFlag(nex.FlagNeedsAck) - responsePacket.AddFlag(nex.FlagReliable) - - nexServer.Send(responsePacket) -} diff --git a/types.go b/types/course_metadata.go similarity index 69% rename from types.go rename to types/course_metadata.go index b09bf5a..ad249b7 100644 --- a/types.go +++ b/types/course_metadata.go @@ -1,4 +1,4 @@ -package main +package types import "github.com/PretendoNetwork/nex-go" @@ -18,11 +18,3 @@ type CourseMetadata struct { DataType uint16 Period uint16 } - -type CourseWorldRecord struct { - FirstPID uint32 - BestPID uint32 - CreatedTime *nex.DateTime - UpdatedTime *nex.DateTime - Score int32 -} diff --git a/types/course_world_record.go b/types/course_world_record.go new file mode 100644 index 0000000..617e795 --- /dev/null +++ b/types/course_world_record.go @@ -0,0 +1,11 @@ +package types + +import "github.com/PretendoNetwork/nex-go" + +type CourseWorldRecord struct { + FirstPID uint32 + BestPID uint32 + CreatedTime *nex.DateTime + UpdatedTime *nex.DateTime + Score int32 +} diff --git a/upload_course_record.go b/upload_course_record.go deleted file mode 100644 index cec2de2..0000000 --- a/upload_course_record.go +++ /dev/null @@ -1,28 +0,0 @@ -package main - -import ( - nex "github.com/PretendoNetwork/nex-go" - nexproto "github.com/PretendoNetwork/nex-protocols-go" -) - -func uploadCourseRecord(err error, client *nex.Client, callID uint32, param *nexproto.DataStoreUploadCourseRecordParam) { - updateCourseWorldRecord(param.DataID, client.PID(), param.Score) - - rmcResponse := nex.NewRMCResponse(nexproto.DataStoreProtocolID, callID) - rmcResponse.SetSuccess(nexproto.DataStoreSMMMethodUploadCourseRecord, nil) - - rmcResponseBytes := rmcResponse.Bytes() - - responsePacket, _ := nex.NewPacketV1(client, nil) - - responsePacket.SetVersion(1) - responsePacket.SetSource(0xA1) - responsePacket.SetDestination(0xAF) - responsePacket.SetType(nex.DataPacket) - responsePacket.SetPayload(rmcResponseBytes) - - responsePacket.AddFlag(nex.FlagNeedsAck) - responsePacket.AddFlag(nex.FlagReliable) - - nexServer.Send(responsePacket) -} diff --git a/utility.go b/utility/utility.go similarity index 58% rename from utility.go rename to utility/utility.go index 6733fff..61ad457 100644 --- a/utility.go +++ b/utility/utility.go @@ -1,28 +1,32 @@ -package main +package utility import ( + "context" "encoding/base64" "time" nex "github.com/PretendoNetwork/nex-go" - nexproto "github.com/PretendoNetwork/nex-protocols-go" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/service/s3" + "github.com/PretendoNetwork/nex-protocols-go/datastore" + datastore_super_mario_maker "github.com/PretendoNetwork/nex-protocols-go/datastore/super-mario-maker" + "github.com/PretendoNetwork/super-mario-maker-secure/database" + "github.com/PretendoNetwork/super-mario-maker-secure/globals" + "github.com/PretendoNetwork/super-mario-maker-secure/types" + "github.com/aws/aws-sdk-go-v2/service/s3" "go.mongodb.org/mongo-driver/bson/primitive" ) -func courseMetadataToDataStoreCustomRankingResult(courseMetadata *CourseMetadata) *nexproto.DataStoreCustomRankingResult { - rankingResult := nexproto.NewDataStoreCustomRankingResult() +func CourseMetadataToDataStoreCustomRankingResult(courseMetadata *types.CourseMetadata) *datastore_super_mario_maker.DataStoreCustomRankingResult { + rankingResult := datastore_super_mario_maker.NewDataStoreCustomRankingResult() rankingResult.Order = 0 // unknown rankingResult.Score = courseMetadata.Stars - rankingResult.MetaInfo = courseMetadataToDataStoreMetaInfo(courseMetadata) + rankingResult.MetaInfo = CourseMetadataToDataStoreMetaInfo(courseMetadata) return rankingResult } -func courseMetadataToDataStoreMetaInfo(courseMetadata *CourseMetadata) *nexproto.DataStoreMetaInfo { - metaInfo := nexproto.NewDataStoreMetaInfo() +func CourseMetadataToDataStoreMetaInfo(courseMetadata *types.CourseMetadata) *datastore.DataStoreMetaInfo { + metaInfo := datastore.NewDataStoreMetaInfo() metaInfo.DataID = courseMetadata.DataID metaInfo.OwnerID = courseMetadata.OwnerPID @@ -30,10 +34,10 @@ func courseMetadataToDataStoreMetaInfo(courseMetadata *CourseMetadata) *nexproto metaInfo.Name = courseMetadata.Name metaInfo.DataType = courseMetadata.DataType metaInfo.MetaBinary = courseMetadata.MetaBinary - metaInfo.Permission = nexproto.NewDataStorePermission() + metaInfo.Permission = datastore.NewDataStorePermission() metaInfo.Permission.Permission = 0 // unknown metaInfo.Permission.RecipientIds = []uint32{} - metaInfo.DelPermission = nexproto.NewDataStorePermission() + metaInfo.DelPermission = datastore.NewDataStorePermission() metaInfo.DelPermission.Permission = 3 // unknown metaInfo.DelPermission.RecipientIds = []uint32{} metaInfo.CreatedTime = courseMetadata.CreatedTime @@ -46,61 +50,61 @@ func courseMetadataToDataStoreMetaInfo(courseMetadata *CourseMetadata) *nexproto metaInfo.ReferredTime = courseMetadata.CreatedTime metaInfo.ExpireTime = nex.NewDateTime(671075926016) // December 31st, year 9999 metaInfo.Tags = []string{""} // unknown - metaInfo.Ratings = []*nexproto.DataStoreRatingInfoWithSlot{ - nexproto.NewDataStoreRatingInfoWithSlot(), // attempts - nexproto.NewDataStoreRatingInfoWithSlot(), // unknown - nexproto.NewDataStoreRatingInfoWithSlot(), // completions - nexproto.NewDataStoreRatingInfoWithSlot(), // failures - nexproto.NewDataStoreRatingInfoWithSlot(), // unknown - nexproto.NewDataStoreRatingInfoWithSlot(), // unknown - nexproto.NewDataStoreRatingInfoWithSlot(), // unknown + metaInfo.Ratings = []*datastore.DataStoreRatingInfoWithSlot{ + datastore.NewDataStoreRatingInfoWithSlot(), // attempts + datastore.NewDataStoreRatingInfoWithSlot(), // unknown + datastore.NewDataStoreRatingInfoWithSlot(), // completions + datastore.NewDataStoreRatingInfoWithSlot(), // failures + datastore.NewDataStoreRatingInfoWithSlot(), // unknown + datastore.NewDataStoreRatingInfoWithSlot(), // unknown + datastore.NewDataStoreRatingInfoWithSlot(), // unknown } // attempts metaInfo.Ratings[0].Slot = 0 - metaInfo.Ratings[0].Rating = nexproto.NewDataStoreRatingInfo() + metaInfo.Ratings[0].Rating = datastore.NewDataStoreRatingInfo() metaInfo.Ratings[0].Rating.TotalValue = int64(courseMetadata.Attempts) metaInfo.Ratings[0].Rating.Count = courseMetadata.Attempts metaInfo.Ratings[0].Rating.InitialValue = 0 // unknown metaInfo.Ratings[1].Slot = 1 - metaInfo.Ratings[1].Rating = nexproto.NewDataStoreRatingInfo() + metaInfo.Ratings[1].Rating = datastore.NewDataStoreRatingInfo() metaInfo.Ratings[1].Rating.TotalValue = 2 metaInfo.Ratings[1].Rating.Count = 2 metaInfo.Ratings[1].Rating.InitialValue = 0 // completions metaInfo.Ratings[2].Slot = 2 - metaInfo.Ratings[2].Rating = nexproto.NewDataStoreRatingInfo() + metaInfo.Ratings[2].Rating = datastore.NewDataStoreRatingInfo() metaInfo.Ratings[2].Rating.TotalValue = int64(courseMetadata.Completions) metaInfo.Ratings[2].Rating.Count = courseMetadata.Completions metaInfo.Ratings[2].Rating.InitialValue = 0 // failures metaInfo.Ratings[3].Slot = 3 - metaInfo.Ratings[3].Rating = nexproto.NewDataStoreRatingInfo() + metaInfo.Ratings[3].Rating = datastore.NewDataStoreRatingInfo() metaInfo.Ratings[3].Rating.TotalValue = int64(courseMetadata.Failures) metaInfo.Ratings[3].Rating.Count = courseMetadata.Failures metaInfo.Ratings[3].Rating.InitialValue = 0 // unknown metaInfo.Ratings[4].Slot = 4 - metaInfo.Ratings[4].Rating = nexproto.NewDataStoreRatingInfo() + metaInfo.Ratings[4].Rating = datastore.NewDataStoreRatingInfo() metaInfo.Ratings[4].Rating.TotalValue = 5 metaInfo.Ratings[4].Rating.Count = 5 metaInfo.Ratings[4].Rating.InitialValue = 0 // unknown metaInfo.Ratings[5].Slot = 5 - metaInfo.Ratings[5].Rating = nexproto.NewDataStoreRatingInfo() + metaInfo.Ratings[5].Rating = datastore.NewDataStoreRatingInfo() metaInfo.Ratings[5].Rating.TotalValue = 6 metaInfo.Ratings[5].Rating.Count = 6 metaInfo.Ratings[5].Rating.InitialValue = 0 // Number of new Miiverse comments metaInfo.Ratings[6].Slot = 6 - metaInfo.Ratings[6].Rating = nexproto.NewDataStoreRatingInfo() + metaInfo.Ratings[6].Rating = datastore.NewDataStoreRatingInfo() metaInfo.Ratings[6].Rating.TotalValue = 0 metaInfo.Ratings[6].Rating.Count = 0 metaInfo.Ratings[6].Rating.InitialValue = 0 @@ -108,21 +112,21 @@ func courseMetadataToDataStoreMetaInfo(courseMetadata *CourseMetadata) *nexproto return metaInfo } -func userMiiDataToDataStoreCustomRankingResult(ownerID uint32, miiInfo primitive.M) *nexproto.DataStoreCustomRankingResult { - rankingResult := nexproto.NewDataStoreCustomRankingResult() +func UserMiiDataToDataStoreCustomRankingResult(ownerID uint32, miiInfo primitive.M) *datastore_super_mario_maker.DataStoreCustomRankingResult { + rankingResult := datastore_super_mario_maker.NewDataStoreCustomRankingResult() rankingResult.Order = 0 rankingResult.Score = 0 - rankingResult.MetaInfo = userMiiDataToDataStoreMetaInfo(ownerID, miiInfo) + rankingResult.MetaInfo = UserMiiDataToDataStoreMetaInfo(ownerID, miiInfo) return rankingResult } -func userMiiDataToDataStoreMetaInfo(ownerID uint32, miiInfo primitive.M) *nexproto.DataStoreMetaInfo { +func UserMiiDataToDataStoreMetaInfo(ownerID uint32, miiInfo primitive.M) *datastore.DataStoreMetaInfo { encodedMiiData := miiInfo["data"].(string) decodedMiiData, _ := base64.StdEncoding.DecodeString(encodedMiiData) - metaBinaryStream := nex.NewStreamOut(nexServer) + metaBinaryStream := nex.NewStreamOut(globals.NEXServer) metaBinaryStream.Grow(140) metaBinaryStream.WriteBytesNext([]byte{ 0x42, 0x50, 0x46, 0x43, // BPFC magic @@ -143,17 +147,17 @@ func userMiiDataToDataStoreMetaInfo(ownerID uint32, miiInfo primitive.M) *nexpro now := uint64(time.Now().Unix()) - metaInfo := nexproto.NewDataStoreMetaInfo() + metaInfo := datastore.NewDataStoreMetaInfo() metaInfo.DataID = uint64(ownerID) // This isn;t actually a user PID in Nintendo's servers, but it makes it much easier for us to do it this way metaInfo.OwnerID = ownerID metaInfo.Size = 0 metaInfo.Name = miiInfo["name"].(string) metaInfo.DataType = 1 // Mii data type? metaInfo.MetaBinary = metaBinaryStream.Bytes() - metaInfo.Permission = nexproto.NewDataStorePermission() + metaInfo.Permission = datastore.NewDataStorePermission() metaInfo.Permission.Permission = 0 // idk? metaInfo.Permission.RecipientIds = []uint32{} - metaInfo.DelPermission = nexproto.NewDataStorePermission() + metaInfo.DelPermission = datastore.NewDataStorePermission() metaInfo.DelPermission.Permission = 3 // idk? metaInfo.DelPermission.RecipientIds = []uint32{} metaInfo.CreatedTime = nex.NewDateTime(now) @@ -166,26 +170,38 @@ func userMiiDataToDataStoreMetaInfo(ownerID uint32, miiInfo primitive.M) *nexpro metaInfo.ReferredTime = nex.NewDateTime(now) metaInfo.ExpireTime = nex.NewDateTime(now) metaInfo.Tags = []string{"49"} // idk? - metaInfo.Ratings = []*nexproto.DataStoreRatingInfoWithSlot{} + metaInfo.Ratings = []*datastore.DataStoreRatingInfoWithSlot{} return metaInfo } -func userNotOwnCourse(courseID uint64, pid uint32) bool { - courseMetadata := getCourseMetadataByDataID(courseID) +func UserNotOwnCourse(courseID uint64, pid uint32) bool { + courseMetadata := database.GetCourseMetadataByDataID(courseID) return courseMetadata.OwnerPID != pid } -func s3ObjectSize(bucket, key string) (uint64, error) { - headObj := s3.HeadObjectInput{ - Bucket: aws.String(bucket), - Key: aws.String(key), +func S3HeadRequest(bucket, key string) (*s3.HeadObjectOutput, error) { + input := &s3.HeadObjectInput{ + Bucket: &bucket, + Key: &key, } - result, err := s3Client.HeadObject(&headObj) + + res, err := globals.S3Client.HeadObject(context.TODO(), input) + + if err != nil { + return nil, err + } + + return res, nil +} + +func S3ObjectSize(bucket, key string) (uint64, error) { + res, err := S3HeadRequest(bucket, key) + if err != nil { return 0, err } - return uint64(aws.Int64Value(result.ContentLength)), nil + return uint64(res.ContentLength), nil }