Merge pull request #5 from PretendoNetwork/modernize

Modernize
This commit is contained in:
Jonathan Barrow
2023-11-01 09:28:42 -04:00
committed by GitHub
103 changed files with 3166 additions and 1937 deletions

16
.gitignore vendored
View File

@@ -1,3 +1,6 @@
# If you prefer the allow list template instead of the deny list, see community template:
# https://github.com/github/gitignore/blob/main/community/Golang/Go.AllowList.gitignore
#
# Binaries for programs and plugins
*.exe
*.exe~
@@ -5,14 +8,21 @@
*.so
*.dylib
# Test binary, build with `go test -c`
# Test binary, built with `go test -c`
*.test
# Output of the go coverage tool, specifically when used with LiteIDE
*.out
# Dependency directories (remove the comment below to include it)
# vendor/
# Go workspace file
go.work
go.work.sum
# custom
build
.vscode
.env
*.key
build
log

60
Makefile Normal file
View File

@@ -0,0 +1,60 @@
# TODO - Assumes a UNIX-like OS
RED := $(shell tput setaf 1)
BLUE := $(shell tput setaf 4)
CYAN := $(shell tput setaf 14)
ORANGE := $(shell tput setaf 202)
YELLOW := $(shell tput setaf 214)
RESET := $(shell tput sgr0)
ifeq ($(shell which go),)
# TODO - Read contents from .git folder instead?
$(error "$(RED)go command not found. Install go to continue $(BLUE)https://go.dev/doc/install$(RESET)")
endif
ifneq ($(wildcard .git),)
# * .git folder exists, build server build string from repo info
ifeq ($(shell which git),)
# TODO - Read contents from .git folder instead?
$(error "$(RED)git command not found. Install git to continue $(ORANGE)https://git-scm.com/downloads$(RESET)")
endif
$(info "$(CYAN)Building server build string from repository info$(RESET)")
# * Build server build string from repo info
BRANCH := $(shell git rev-parse --abbrev-ref HEAD)
REMOTE_ORIGIN := $(shell git config --get remote.origin.url)
# * Handle multiple origin URL formats
HTTPS_PREFIX_CHECK := $(shell echo $(REMOTE_ORIGIN) | head -c 8)
HTTP_PREFIX_CHECK := $(shell echo $(REMOTE_ORIGIN) | head -c 7)
GIT@_PREFIX_CHECK := $(shell echo $(REMOTE_ORIGIN) | head -c 4)
ifeq ($(HTTPS_PREFIX_CHECK), https://)
REMOTE_PATH := $(shell echo $(REMOTE_ORIGIN) | cut -d/ -f4-)
else ifeq ($(HTTP_PREFIX_CHECK), http://)
REMOTE_PATH := $(shell echo $(REMOTE_ORIGIN) | cut -d/ -f4-)
else ifeq ($(GIT@_PREFIX_CHECK), git@)
REMOTE_PATH := $(shell echo $(REMOTE_ORIGIN) | cut -d: -f2-)
else
REMOTE_PATH := $(shell echo $(REMOTE_ORIGIN) | cut -d/ -f2-)
endif
HASH := $(shell git rev-parse --short HEAD)
SERVER_BUILD := $(BRANCH):$(REMOTE_PATH)@$(HASH)
else
# * .git folder not present, assume downloaded from zip file and just use folder name
$(info "$(CYAN)git repository not found. Building server build string from folder name$(RESET)")
SERVER_BUILD := super-mario-maker
endif
# * Final build string
DATE_TIME := $(shell date --iso=seconds)
BUILD_STRING := $(SERVER_BUILD), $(DATE_TIME)
default:
ifeq ($(wildcard .env),)
$(warning "$(YELLOW).env file not found, environment variables may not be populated correctly$(RESET)")
endif
go get -u
go mod tidy
go build -ldflags "-X 'main.serverBuildString=$(BUILD_STRING)'" -o ./build/super-mario-maker

View File

@@ -1,6 +1,65 @@
# Super Mario Maker - Secure
### Pretendo Super Mario Maker secure server
# Super Mario Maker replacement server
Includes both the authentication and secure servers. Works on both WiiU and 3DS
## About
Only handles WiiU at this point. Only has enough implemented to get the Super Mario Maker app booting. Lots of things are not implemented
Does not actually authenticate users atm!
## DataStore (S3)
This server requires an S3 compatible server to store user generated content. The WiiU and 3DS only support TLS versions 1.0 and 1.1 with RSA SSL ciphers, so an S3 server supporting these is required. The server must also support presigned `POST` URLs. This does not leave many options, as nearly all S3 cloud providers no longer support one of these 2 things. Even AWS, the creators of S3 and the provider Nintendo uses, is [dropping support for TLS versions below 1.2 in December 2023](https://aws.amazon.com/blogs/security/tls-1-2-required-for-aws-endpoints/)
For this reason, the recommended setup is using [MinIO](https://min.io/) to self host your S3 server and using [Cloudflare Tunnels](https://developers.cloudflare.com/cloudflare-one/connections/connect-networks/) to act as your reverse proxy. Tunnels support TLS versions 1.0 and 1.1 with the required ciphers, essentially using it as a TLS proxy. This does come at some cost, and you now must manage data storage and security yourself through MinIO, but there are no other options at this time outside of self hosting
## Compiling
### Setup
Install [Go](https://go.dev/doc/install) and [git](https://git-scm.com/downloads), then clone and enter the repository
```bash
$ git clone https://github.com/PretendoNetwork/super-mario-maker
$ cd super-mario-maker
```
### Compiling using `go`
To compile using Go, `go get` the required modules and then `go build` to your desired location. You may also want to tidy the go modules, though this is optional
```bash
$ go get -u
$ go mod tidy
$ go build -o build/super-mario-maker
```
The server is now built to `build/super-mario-maker`
When compiling with only Go, the authentication servers build string is not automatically set. This should not cause any issues with gameplay, but it means that the server build will not be visible in any packet dumps or logs a title may produce
To compile the servers with the authentication server build string, add `-ldflags "-X 'main.serverBuildString=BUILD_STRING_HERE'"` to the build command, or use `make` to compile the server
### Compiling using `make`
Compiling using `make` will read the local `.git` directory to create a dynamic authentication server build string, based on your repositories remote origin and current commit
Install `make` either through your systems package manager or the [official download](https://www.gnu.org/software/make/). We provide a `default` rule which compiles [using `go`](#compiling-using-go)
To build using `go`
```bash
$ make
```
The server is now built to `build/super-mario-maker`
## Configuration
All configuration options are handled via environment variables
`.env` files are supported
| Name | Description | Required |
|-------------------------------------|-----------------------------------------------------------------------|-----------------------------------------------|
| `PN_SMM_POSTGRES_URI` | Fully qualified URI to your Postgres server | Yes |
| `PN_SMM_AUTHENTICATION_SERVER_PORT` | Port for the authentication server | Yes |
| `PN_SMM_SECURE_SERVER_HOST` | Host name for the secure server | Yes |
| `PN_SMM_SECURE_SERVER_PORT` | Port for the secure server | Yes |
| `PN_SMM_KERBEROS_PASSWORD` | Password used as part of the internal server data in Kerberos tickets | No (Default password `password` will be used) |
| `PN_SMM_CONFIG_S3_ENDPOINT` | S3 server endpoint | Yes |
| `PN_SMM_CONFIG_S3_ACCESS_KEY` | S3 access key ID | Yes |
| `PN_SMM_CONFIG_S3_ACCESS_SECRET` | S3 secret | Yes |
| `PN_SMM_CONFIG_S3_BUCKET` | S3 bucket | Yes |
| `PN_SMM_ACCOUNT_GRPC_HOST` | Host name for your account server gRPC service | Yes |
| `PN_SMM_ACCOUNT_GRPC_PORT` | Port for your account server gRPC service | Yes |
| `PN_SMM_ACCOUNT_GRPC_API_KEY` | API key for your account server gRPC service | No (Assumed to be an open gRPC API) |

View File

@@ -1,6 +0,0 @@
package database
func ConnectAll() {
connectMongo()
connectCassandra()
}

View File

@@ -1,122 +0,0 @@
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<text>,
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<bigint>,
played_courses set<bigint>
)`).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)
}
}

View File

@@ -1,24 +0,0 @@
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")
}

View File

@@ -0,0 +1,24 @@
package database
import (
"database/sql"
"os"
"github.com/PretendoNetwork/super-mario-maker-secure/globals"
_ "github.com/lib/pq"
)
var Postgres *sql.DB
func ConnectPostgres() {
var err error
Postgres, err = sql.Open("postgres", os.Getenv("PN_SMM_POSTGRES_URI"))
if err != nil {
globals.Logger.Critical(err.Error())
}
globals.Logger.Success("Connected to Postgres!")
initPostgres()
}

View File

@@ -1,9 +0,0 @@
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)
}
}

View File

@@ -0,0 +1,23 @@
package datastore_db
import (
"github.com/PretendoNetwork/nex-go"
"github.com/PretendoNetwork/super-mario-maker-secure/database"
"github.com/PretendoNetwork/super-mario-maker-secure/globals"
)
func DeleteObjectByDataID(dataID uint64) uint32 {
errCode := IsObjectAvailable(dataID)
if errCode != 0 {
return errCode
}
_, err := database.Postgres.Exec(`UPDATE datastore.objects SET deleted=TRUE WHERE data_id=$1`, dataID)
if err != nil {
globals.Logger.Error(err.Error())
// TODO - Send more specific errors?
return nex.Errors.DataStore.Unknown
}
return 0
}

View File

@@ -0,0 +1,91 @@
package datastore_db
import (
"database/sql"
"time"
"github.com/PretendoNetwork/nex-go"
datastore_types "github.com/PretendoNetwork/nex-protocols-go/datastore/types"
"github.com/PretendoNetwork/super-mario-maker-secure/database"
"github.com/PretendoNetwork/super-mario-maker-secure/globals"
"github.com/lib/pq"
)
func GetObjectInfoByDataID(dataID uint64) (*datastore_types.DataStoreMetaInfo, uint32) {
errCode := IsObjectAvailable(dataID)
if errCode != 0 {
return nil, errCode
}
metaInfo := datastore_types.NewDataStoreMetaInfo()
metaInfo.Permission = datastore_types.NewDataStorePermission()
metaInfo.DelPermission = datastore_types.NewDataStorePermission()
metaInfo.CreatedTime = nex.NewDateTime(0)
metaInfo.UpdatedTime = nex.NewDateTime(0)
metaInfo.ReferredTime = nex.NewDateTime(0)
metaInfo.ExpireTime = nex.NewDateTime(0x9C3f3E0000) // * 9999-12-31T00:00:00.000Z. This is what the real server sends
metaInfo.Ratings = make([]*datastore_types.DataStoreRatingInfoWithSlot, 0)
var createdDate time.Time
var updatedDate time.Time
err := database.Postgres.QueryRow(`SELECT
data_id,
owner,
size,
name,
data_type,
meta_binary,
permission,
permission_recipients,
delete_permission,
delete_permission_recipients,
period,
refer_data_id,
flag,
tags,
creation_date,
update_date
FROM datastore.objects WHERE data_id=$1`, dataID).Scan(
&metaInfo.DataID,
&metaInfo.OwnerID,
&metaInfo.Size,
&metaInfo.Name,
&metaInfo.DataType,
&metaInfo.MetaBinary,
&metaInfo.Permission.Permission,
pq.Array(&metaInfo.Permission.RecipientIDs),
&metaInfo.DelPermission.Permission,
pq.Array(&metaInfo.DelPermission.RecipientIDs),
&metaInfo.Period,
&metaInfo.ReferDataID,
&metaInfo.Flag,
pq.Array(&metaInfo.Tags),
&createdDate,
&updatedDate,
)
if err != nil {
if err == sql.ErrNoRows {
return nil, nex.Errors.DataStore.NotFound
}
globals.Logger.Error(err.Error())
// TODO - Send more specific errors?
return nil, nex.Errors.DataStore.Unknown
}
ratings, errCode := GetObjectRatingsWithSlotByDataID(metaInfo.DataID)
if errCode != 0 {
return nil, errCode
}
metaInfo.Ratings = ratings
metaInfo.CreatedTime.FromTimestamp(createdDate)
metaInfo.UpdatedTime.FromTimestamp(updatedDate)
metaInfo.ReferredTime.FromTimestamp(createdDate) // * This is what the real server does
return metaInfo, 0
}

View File

@@ -0,0 +1,90 @@
package datastore_db
import (
"database/sql"
"time"
"github.com/PretendoNetwork/nex-go"
datastore_types "github.com/PretendoNetwork/nex-protocols-go/datastore/types"
"github.com/PretendoNetwork/super-mario-maker-secure/database"
"github.com/PretendoNetwork/super-mario-maker-secure/globals"
"github.com/lib/pq"
)
func GetObjectInfoByDataIDWithPassword(dataID uint64, password uint64) (*datastore_types.DataStoreMetaInfo, uint32) {
errCode := IsObjectAvailableWithPassword(dataID, password)
if errCode != 0 {
return nil, errCode
}
metaInfo := datastore_types.NewDataStoreMetaInfo()
metaInfo.Permission = datastore_types.NewDataStorePermission()
metaInfo.DelPermission = datastore_types.NewDataStorePermission()
metaInfo.CreatedTime = nex.NewDateTime(0)
metaInfo.UpdatedTime = nex.NewDateTime(0)
metaInfo.ReferredTime = nex.NewDateTime(0)
metaInfo.ExpireTime = nex.NewDateTime(0x9C3f3E0000) // * 9999-12-31T00:00:00.000Z. This is what the real server sends
metaInfo.Ratings = make([]*datastore_types.DataStoreRatingInfoWithSlot, 0)
var createdDate time.Time
var updatedDate time.Time
err := database.Postgres.QueryRow(`SELECT
data_id,
owner,
size,
name,
data_type,
meta_binary,
permission,
permission_recipients,
delete_permission,
delete_permission_recipients,
period,
refer_data_id,
flag,
tags,
creation_date,
update_date
FROM datastore.objects WHERE data_id=$1`, dataID).Scan(
&metaInfo.DataID,
&metaInfo.OwnerID,
&metaInfo.Size,
&metaInfo.Name,
&metaInfo.DataType,
&metaInfo.MetaBinary,
&metaInfo.Permission.Permission,
pq.Array(&metaInfo.Permission.RecipientIDs),
&metaInfo.DelPermission.Permission,
pq.Array(&metaInfo.DelPermission.RecipientIDs),
&metaInfo.Period,
&metaInfo.ReferDataID,
&metaInfo.Flag,
pq.Array(&metaInfo.Tags),
&createdDate,
&updatedDate,
)
if err != nil {
if err == sql.ErrNoRows {
return nil, nex.Errors.DataStore.NotFound
}
globals.Logger.Error(err.Error())
// TODO - Send more specific errors?
return nil, nex.Errors.DataStore.Unknown
}
ratings, errCode := GetObjectRatingsWithSlotByDataIDWithPassword(metaInfo.DataID, password)
if errCode != 0 {
return nil, errCode
}
metaInfo.Ratings = ratings
metaInfo.CreatedTime.FromTimestamp(createdDate)
metaInfo.UpdatedTime.FromTimestamp(updatedDate)
metaInfo.ReferredTime.FromTimestamp(createdDate) // * This is what the real server does
return metaInfo, 0
}

View File

@@ -0,0 +1,101 @@
package datastore_db
import (
"database/sql"
"time"
"github.com/PretendoNetwork/nex-go"
datastore_types "github.com/PretendoNetwork/nex-protocols-go/datastore/types"
"github.com/PretendoNetwork/super-mario-maker-secure/database"
"github.com/PretendoNetwork/super-mario-maker-secure/globals"
"github.com/lib/pq"
)
func GetObjectInfoByPersistenceTargetWithPassword(persistenceTarget *datastore_types.DataStorePersistenceTarget, password uint64) (*datastore_types.DataStoreMetaInfo, uint32) {
metaInfo := datastore_types.NewDataStoreMetaInfo()
metaInfo.Permission = datastore_types.NewDataStorePermission()
metaInfo.DelPermission = datastore_types.NewDataStorePermission()
metaInfo.CreatedTime = nex.NewDateTime(0)
metaInfo.UpdatedTime = nex.NewDateTime(0)
metaInfo.ReferredTime = nex.NewDateTime(0)
metaInfo.ExpireTime = nex.NewDateTime(0x9C3f3E0000) // * 9999-12-31T00:00:00.000Z. This is what the real server sends
metaInfo.Ratings = make([]*datastore_types.DataStoreRatingInfoWithSlot, 0)
var accessPassword uint64
var underReview bool
var createdDate time.Time
var updatedDate time.Time
err := database.Postgres.QueryRow(`SELECT
data_id,
owner,
size,
name,
data_type,
meta_binary,
permission,
permission_recipients,
delete_permission,
delete_permission_recipients,
period,
refer_data_id,
flag,
tags,
creation_date,
update_date,
access_password,
under_review
FROM datastore.objects WHERE owner=$1 AND persistence_slot_id=$2 AND upload_completed=TRUE AND deleted=FALSE`, persistenceTarget.OwnerID, persistenceTarget.PersistenceSlotID).Scan(
&metaInfo.DataID,
&metaInfo.OwnerID,
&metaInfo.Size,
&metaInfo.Name,
&metaInfo.DataType,
&metaInfo.MetaBinary,
&metaInfo.Permission.Permission,
pq.Array(&metaInfo.Permission.RecipientIDs),
&metaInfo.DelPermission.Permission,
pq.Array(&metaInfo.DelPermission.RecipientIDs),
&metaInfo.Period,
&metaInfo.ReferDataID,
&metaInfo.Flag,
pq.Array(&metaInfo.Tags),
&createdDate,
&updatedDate,
&accessPassword,
&underReview,
)
if err != nil {
if err == sql.ErrNoRows {
return nil, nex.Errors.DataStore.NotFound
}
globals.Logger.Error(err.Error())
// TODO - Send more specific errors?
return nil, nex.Errors.DataStore.Unknown
}
if accessPassword != 0 && accessPassword != password {
return nil, nex.Errors.DataStore.InvalidPassword
}
if underReview {
return nil, nex.Errors.DataStore.UnderReviewing
}
ratings, errCode := GetObjectRatingsWithSlotByDataIDWithPassword(metaInfo.DataID, password)
if errCode != 0 {
globals.Logger.Errorf("Failed to get ratings for object %d with password %d", metaInfo.DataID, password)
return nil, errCode
}
metaInfo.Ratings = ratings
metaInfo.CreatedTime.FromTimestamp(createdDate)
metaInfo.UpdatedTime.FromTimestamp(updatedDate)
metaInfo.ReferredTime.FromTimestamp(createdDate) // * This is what the real server does
return metaInfo, 0
}

View File

@@ -0,0 +1,26 @@
package datastore_db
import (
"database/sql"
"github.com/PretendoNetwork/nex-go"
"github.com/PretendoNetwork/super-mario-maker-secure/database"
"github.com/PretendoNetwork/super-mario-maker-secure/globals"
)
func GetObjectOwnerByDataID(dataID uint64) (uint32, uint32) {
var owner uint32
err := database.Postgres.QueryRow(`SELECT owner FROM datastore.objects WHERE data_id=$1`, dataID).Scan(&owner)
if err != nil {
if err == sql.ErrNoRows {
return 0, nex.Errors.DataStore.NotFound
}
globals.Logger.Error(err.Error())
// TODO - Send more specific errors?
return 0, nex.Errors.DataStore.Unknown
}
return owner, 0
}

View File

@@ -0,0 +1,56 @@
package datastore_db
import (
"database/sql"
"github.com/PretendoNetwork/nex-go"
datastore_types "github.com/PretendoNetwork/nex-protocols-go/datastore/types"
"github.com/PretendoNetwork/super-mario-maker-secure/database"
"github.com/PretendoNetwork/super-mario-maker-secure/globals"
)
func GetObjectRatingsWithSlotByDataID(dataID uint64) ([]*datastore_types.DataStoreRatingInfoWithSlot, uint32) {
errCode := IsObjectAvailable(dataID)
if errCode != 0 {
return nil, errCode
}
ratings := make([]*datastore_types.DataStoreRatingInfoWithSlot, 0)
rows, err := database.Postgres.Query(`SELECT slot, total_value, count, initial_value FROM datastore.object_ratings WHERE data_id=$1`, dataID)
if err != nil {
if err == sql.ErrNoRows {
return nil, nex.Errors.DataStore.NotFound
}
globals.Logger.Error(err.Error())
// TODO - Send more specific errors?
return nil, nex.Errors.DataStore.Unknown
}
defer rows.Close()
for rows.Next() {
rating := datastore_types.NewDataStoreRatingInfoWithSlot()
rating.Rating = datastore_types.NewDataStoreRatingInfo()
err := rows.Scan(&rating.Slot, &rating.Rating.TotalValue, &rating.Rating.Count, &rating.Rating.InitialValue)
if err != nil {
globals.Logger.Error(err.Error())
// TODO - Send more specific errors?
return nil, nex.Errors.DataStore.Unknown
}
ratings = append(ratings, rating)
}
if err := rows.Err(); err != nil {
globals.Logger.Error(err.Error())
// TODO - Send more specific errors?
return nil, nex.Errors.DataStore.Unknown
}
return ratings, 0
}

View File

@@ -0,0 +1,56 @@
package datastore_db
import (
"database/sql"
"github.com/PretendoNetwork/nex-go"
datastore_types "github.com/PretendoNetwork/nex-protocols-go/datastore/types"
"github.com/PretendoNetwork/super-mario-maker-secure/database"
"github.com/PretendoNetwork/super-mario-maker-secure/globals"
)
func GetObjectRatingsWithSlotByDataIDWithPassword(dataID uint64, password uint64) ([]*datastore_types.DataStoreRatingInfoWithSlot, uint32) {
errCode := IsObjectAvailableWithPassword(dataID, password)
if errCode != 0 {
return nil, errCode
}
ratings := make([]*datastore_types.DataStoreRatingInfoWithSlot, 0)
rows, err := database.Postgres.Query(`SELECT slot, total_value, count, initial_value FROM datastore.object_ratings WHERE data_id=$1`, dataID)
if err != nil {
if err == sql.ErrNoRows {
return nil, nex.Errors.DataStore.NotFound
}
globals.Logger.Error(err.Error())
// TODO - Send more specific errors?
return nil, nex.Errors.DataStore.Unknown
}
defer rows.Close()
for rows.Next() {
rating := datastore_types.NewDataStoreRatingInfoWithSlot()
rating.Rating = datastore_types.NewDataStoreRatingInfo()
err := rows.Scan(&rating.Slot, &rating.Rating.TotalValue, &rating.Rating.Count, &rating.Rating.InitialValue)
if err != nil {
globals.Logger.Error(err.Error())
// TODO - Send more specific errors?
return nil, nex.Errors.DataStore.Unknown
}
ratings = append(ratings, rating)
}
if err := rows.Err(); err != nil {
globals.Logger.Error(err.Error())
// TODO - Send more specific errors?
return nil, nex.Errors.DataStore.Unknown
}
return ratings, 0
}

View File

@@ -0,0 +1,26 @@
package datastore_db
import (
"database/sql"
"github.com/PretendoNetwork/nex-go"
"github.com/PretendoNetwork/super-mario-maker-secure/database"
"github.com/PretendoNetwork/super-mario-maker-secure/globals"
)
func GetObjectSizeDataID(dataID uint64) (uint32, uint32) {
var size uint32
err := database.Postgres.QueryRow(`SELECT size FROM datastore.objects WHERE data_id=$1`, dataID).Scan(&size)
if err != nil {
if err == sql.ErrNoRows {
return 0, nex.Errors.DataStore.NotFound
}
globals.Logger.Error(err.Error())
// TODO - Send more specific errors?
return 0, nex.Errors.DataStore.Unknown
}
return size, 0
}

View File

@@ -0,0 +1,81 @@
package datastore_db
import (
"time"
"github.com/PretendoNetwork/nex-go"
datastore_types "github.com/PretendoNetwork/nex-protocols-go/datastore/types"
"github.com/PretendoNetwork/super-mario-maker-secure/database"
"github.com/PretendoNetwork/super-mario-maker-secure/globals"
"github.com/lib/pq"
)
func InitializeObjectByPreparePostParam(ownerPID uint32, param *datastore_types.DataStorePreparePostParam) (uint64, uint32) {
now := time.Now()
var dataID uint64
err := database.Postgres.QueryRow(`INSERT INTO datastore.objects (
owner,
size,
name,
data_type,
meta_binary,
permission,
permission_recipients,
delete_permission,
delete_permission_recipients,
flag,
period,
refer_data_id,
tags,
persistence_slot_id,
extra_data,
creation_date,
update_date
) VALUES (
$1,
$2,
$3,
$4,
$5,
$6,
$7,
$8,
$9,
$10,
$11,
$12,
$13,
$14,
$15,
$16,
$17
) RETURNING data_id`,
ownerPID,
param.Size,
param.Name,
param.DataType,
param.MetaBinary,
param.Permission.Permission,
pq.Array(param.Permission.RecipientIDs),
param.DelPermission.Permission,
pq.Array(param.DelPermission.RecipientIDs),
param.Flag,
param.Period,
param.ReferDataID,
pq.Array(param.Tags),
param.PersistenceInitParam.PersistenceSlotID, // TODO - Check param.PersistenceInitParam.DeleteLastObject?
pq.Array(param.ExtraData),
now,
now,
).Scan(&dataID)
if err != nil {
globals.Logger.Error(err.Error())
// TODO - Send more specific errors?
return 0, nex.Errors.DataStore.Unknown
}
return dataID, 0
}

View File

@@ -0,0 +1,56 @@
package datastore_db
import (
"github.com/PretendoNetwork/nex-go"
datastore_types "github.com/PretendoNetwork/nex-protocols-go/datastore/types"
"github.com/PretendoNetwork/super-mario-maker-secure/database"
"github.com/PretendoNetwork/super-mario-maker-secure/globals"
)
func InitializeObjectRatingWithSlot(dataID uint64, param *datastore_types.DataStoreRatingInitParamWithSlot) uint32 {
_, err := database.Postgres.Exec(`INSERT INTO datastore.object_ratings (
data_id,
slot,
flag,
internal_flag,
lock_type,
initial_value,
range_min,
range_max,
period_hour,
period_duration,
total_value
) VALUES (
$1,
$2,
$3,
$4,
$5,
$6,
$7,
$8,
$9,
$10,
$11
)`,
dataID,
param.Slot,
param.Param.Flag,
param.Param.InternalFlag,
param.Param.LockType,
param.Param.InitialValue,
param.Param.RangeMin,
param.Param.RangeMax,
param.Param.PeriodHour,
param.Param.PeriodDuration,
param.Param.InitialValue, // * Start the value off at the initial value
)
if err != nil {
globals.Logger.Error(err.Error())
// TODO - Send more specific errors?
return nex.Errors.DataStore.Unknown
}
return 0
}

View File

@@ -0,0 +1,30 @@
package datastore_db
import (
"database/sql"
"github.com/PretendoNetwork/nex-go"
"github.com/PretendoNetwork/super-mario-maker-secure/database"
"github.com/PretendoNetwork/super-mario-maker-secure/globals"
)
func IsObjectAvailable(dataID uint64) uint32 {
var underReview bool
err := database.Postgres.QueryRow(`SELECT under_review FROM datastore.objects WHERE data_id=$1 AND upload_completed=TRUE AND deleted=FALSE`, dataID).Scan(&underReview)
if err != nil {
if err == sql.ErrNoRows {
return nex.Errors.DataStore.NotFound
}
globals.Logger.Error(err.Error())
// TODO - Send more specific errors?
return nex.Errors.DataStore.Unknown
}
if underReview {
return nex.Errors.DataStore.UnderReviewing
}
return 0
}

View File

@@ -0,0 +1,42 @@
package datastore_db
import (
"database/sql"
"github.com/PretendoNetwork/nex-go"
"github.com/PretendoNetwork/super-mario-maker-secure/database"
"github.com/PretendoNetwork/super-mario-maker-secure/globals"
)
func IsObjectAvailableWithPassword(dataID, password uint64) uint32 {
var underReview bool
var accessPassword uint64
err := database.Postgres.QueryRow(`SELECT
under_review,
access_password
FROM datastore.objects WHERE data_id=$1 AND upload_completed=TRUE AND deleted=FALSE`, dataID).Scan(
&underReview,
&accessPassword,
)
if err != nil {
if err == sql.ErrNoRows {
return nex.Errors.DataStore.NotFound
}
globals.Logger.Error(err.Error())
// TODO - Send more specific errors?
return nex.Errors.DataStore.Unknown
}
if accessPassword != 0 && accessPassword != password {
return nex.Errors.DataStore.InvalidPassword
}
if underReview {
return nex.Errors.DataStore.UnderReviewing
}
return 0
}

View File

@@ -0,0 +1,46 @@
package datastore_db
import (
"database/sql"
"github.com/PretendoNetwork/nex-go"
datastore_types "github.com/PretendoNetwork/nex-protocols-go/datastore/types"
"github.com/PretendoNetwork/super-mario-maker-secure/database"
"github.com/PretendoNetwork/super-mario-maker-secure/globals"
)
func RateObjectWithPassword(dataID uint64, slot uint8, ratingValue int32, accessPassword uint64) (*datastore_types.DataStoreRatingInfo, uint32) {
errCode := IsObjectAvailableWithPassword(dataID, accessPassword)
if errCode != 0 {
return nil, errCode
}
rating := datastore_types.NewDataStoreRatingInfo()
err := database.Postgres.QueryRow(`
UPDATE datastore.object_ratings
SET total_value=total_value+$1, count=count+1
WHERE data_id=$2 AND slot=$3
RETURNING total_value, count, initial_value`, ratingValue, dataID, slot,
).Scan(
&rating.TotalValue,
&rating.Count,
&rating.InitialValue,
)
if err != nil {
// * If no data was returned, that means the slot
// * was out of bounds since the object exists due
// * to the check at the start of the function.
// * This is an invalid argument
if err == sql.ErrNoRows {
return nil, nex.Errors.DataStore.InvalidArgument
}
globals.Logger.Error(err.Error())
// TODO - Send more specific errors?
return nil, nex.Errors.DataStore.Unknown
}
return rating, 0
}

View File

@@ -0,0 +1,47 @@
package datastore_smm_db
import (
"database/sql"
"github.com/PretendoNetwork/nex-go"
"github.com/PretendoNetwork/super-mario-maker-secure/database"
datastore_db "github.com/PretendoNetwork/super-mario-maker-secure/database/datastore"
)
func GetBufferQueuesByDataIDAndSlot(dataID uint64, slot uint32) ([][]byte, uint32) {
errCode := datastore_db.IsObjectAvailable(dataID)
if errCode != 0 {
return nil, errCode
}
bufferQueues := make([][]byte, 0)
rows, err := database.Postgres.Query(`SELECT buffer FROM datastore.buffer_queues WHERE data_id=$1 AND slot=$2 ORDER BY creation_date`, dataID, slot)
// * No rows is allowed
if err != nil && err != sql.ErrNoRows {
// TODO - Send more specific errors?
return nil, nex.Errors.DataStore.Unknown
}
defer rows.Close()
for rows.Next() {
var buffer []byte
err := rows.Scan(&buffer)
if err != nil {
// TODO - Send more specific errors?
return nil, nex.Errors.DataStore.Unknown
}
bufferQueues = append(bufferQueues, buffer)
}
if err := rows.Err(); err != nil {
// TODO - Send more specific errors?
return nil, nex.Errors.DataStore.Unknown
}
return bufferQueues, 0
}

View File

@@ -0,0 +1,60 @@
package datastore_smm_db
import (
"database/sql"
"time"
"github.com/PretendoNetwork/nex-go"
datastore_super_mario_maker_types "github.com/PretendoNetwork/nex-protocols-go/datastore/super-mario-maker/types"
"github.com/PretendoNetwork/super-mario-maker-secure/database"
datastore_db "github.com/PretendoNetwork/super-mario-maker-secure/database/datastore"
"github.com/PretendoNetwork/super-mario-maker-secure/globals"
)
func GetCourseRecordByDataIDAndSlot(dataID uint64, slot uint8) (*datastore_super_mario_maker_types.DataStoreGetCourseRecordResult, uint32) {
errCode := datastore_db.IsObjectAvailable(dataID)
if errCode != 0 {
return nil, errCode
}
courseRecord := datastore_super_mario_maker_types.NewDataStoreGetCourseRecordResult()
courseRecord.DataID = dataID
courseRecord.Slot = slot
courseRecord.CreatedTime = nex.NewDateTime(0)
courseRecord.UpdatedTime = nex.NewDateTime(0)
var createdDate time.Time
var updatedDate time.Time
err := database.Postgres.QueryRow(`SELECT
first_pid,
best_pid,
best_score,
creation_date,
update_date
FROM datastore.course_records WHERE data_id=$1 AND slot=$2`,
dataID,
slot,
).Scan(
&courseRecord.FirstPID,
&courseRecord.BestPID,
&courseRecord.BestScore,
&createdDate,
&updatedDate,
)
if err != nil {
if err == sql.ErrNoRows {
return nil, nex.Errors.DataStore.NotFound
}
globals.Logger.Error(err.Error())
// TODO - Send more specific errors?
return nil, nex.Errors.DataStore.Unknown
}
courseRecord.CreatedTime.FromTimestamp(createdDate)
courseRecord.UpdatedTime.FromTimestamp(updatedDate)
return courseRecord, 0
}

View File

@@ -0,0 +1,76 @@
package datastore_smm_db
import (
"database/sql"
datastore_super_mario_maker_types "github.com/PretendoNetwork/nex-protocols-go/datastore/super-mario-maker/types"
"github.com/PretendoNetwork/super-mario-maker-secure/database"
datastore_db "github.com/PretendoNetwork/super-mario-maker-secure/database/datastore"
"github.com/PretendoNetwork/super-mario-maker-secure/globals"
"github.com/lib/pq"
)
func GetCustomRankingsByDataIDs(applicationID uint32, dataIDs []uint64) []*datastore_super_mario_maker_types.DataStoreCustomRankingResult {
// * Unlike other methods which query for multiple objects,
// * DataStoreSMM::GetCustomRankingByDataID *OMITS* objects
// * from it's response if they could not be found, rather
// * than using a zero-ed object and DataStore::NotFound as
// * the Result. Because of this, all errors are just thrown
// * away here and not sent back to the client
results := make([]*datastore_super_mario_maker_types.DataStoreCustomRankingResult, 0, len(dataIDs))
// * Using UNNEST and WITH ORDINALITY because the input
// * array may contain duplicate DataIDs. These duplicate
// * DataIDs should result in duplicate results, and this
// * was the most efficient way to do this as it doesn't
// * involve processing all rows or manually duplicating
// * rows
rows, err := database.Postgres.Query(`
SELECT
rankings.data_id,
rankings.value
FROM datastore.object_custom_rankings rankings
JOIN UNNEST($1::bigint[])
WITH ORDINALITY AS rows(data_id, ord)
ON rankings.data_id = rows.data_id
AND rankings.application_id = $2
ORDER BY rows.ord`,
pq.Array(dataIDs),
applicationID,
)
// * No rows is allowed
if err != nil && err != sql.ErrNoRows {
globals.Logger.Error(err.Error())
return results
}
defer rows.Close()
for rows.Next() {
var dataID uint64
var value uint32
err := rows.Scan(&dataID, &value)
if err != nil {
globals.Logger.Error(err.Error())
continue
}
objectInfo, errCode := datastore_db.GetObjectInfoByDataID(dataID)
if errCode != 0 {
globals.Logger.Errorf("Got error code %d for object %d", errCode, dataID)
continue
}
result := datastore_super_mario_maker_types.NewDataStoreCustomRankingResult()
// * Order is always 0, for some reason
result.Score = value
result.MetaInfo = objectInfo
results = append(results, result)
}
return results
}

View File

@@ -0,0 +1,116 @@
package datastore_smm_db
import (
"database/sql"
"time"
"github.com/PretendoNetwork/nex-go"
datastore_super_mario_maker_types "github.com/PretendoNetwork/nex-protocols-go/datastore/super-mario-maker/types"
datastore_types "github.com/PretendoNetwork/nex-protocols-go/datastore/types"
"github.com/PretendoNetwork/super-mario-maker-secure/database"
datastore_db "github.com/PretendoNetwork/super-mario-maker-secure/database/datastore"
"github.com/PretendoNetwork/super-mario-maker-secure/globals"
"github.com/lib/pq"
)
func GetRandomCoursesWithLimit(limit int) ([]*datastore_super_mario_maker_types.DataStoreCustomRankingResult, uint32) {
courses := make([]*datastore_super_mario_maker_types.DataStoreCustomRankingResult, 0)
rows, err := database.Postgres.Query(`
SELECT
object.data_id,
object.owner,
object.size,
object.name,
object.data_type,
object.meta_binary,
object.permission,
object.permission_recipients,
object.delete_permission,
object.delete_permission_recipients,
object.period,
object.refer_data_id,
object.flag,
object.tags,
object.creation_date,
object.update_date,
ranking.value
FROM datastore.objects object
JOIN datastore.object_custom_rankings ranking
ON
object.data_id = ranking.data_id AND
object.upload_completed = TRUE AND
object.deleted = FALSE AND
object.under_review = FALSE AND
ranking.application_id = 0
ORDER BY RANDOM()
LIMIT $1
`, limit)
if err != nil {
if err == sql.ErrNoRows {
return nil, nex.Errors.DataStore.NotFound
}
globals.Logger.Error(err.Error())
// TODO - Send more specific errors?
return nil, nex.Errors.DataStore.Unknown
}
defer rows.Close()
for rows.Next() {
course := datastore_super_mario_maker_types.NewDataStoreCustomRankingResult()
course.Order = 0 // * Order is ALWAYS 0
course.MetaInfo = datastore_types.NewDataStoreMetaInfo()
course.MetaInfo.Permission = datastore_types.NewDataStorePermission()
course.MetaInfo.DelPermission = datastore_types.NewDataStorePermission()
course.MetaInfo.CreatedTime = nex.NewDateTime(0)
course.MetaInfo.UpdatedTime = nex.NewDateTime(0)
course.MetaInfo.ReferredTime = nex.NewDateTime(0)
course.MetaInfo.ExpireTime = nex.NewDateTime(0x9C3f3E0000) // * 9999-12-31T00:00:00.000Z. This is what the real server sends
course.MetaInfo.Ratings = make([]*datastore_types.DataStoreRatingInfoWithSlot, 0)
var createdDate time.Time
var updatedDate time.Time
err := rows.Scan(
&course.MetaInfo.DataID,
&course.MetaInfo.OwnerID,
&course.MetaInfo.Size,
&course.MetaInfo.Name,
&course.MetaInfo.DataType,
&course.MetaInfo.MetaBinary,
&course.MetaInfo.Permission.Permission,
pq.Array(&course.MetaInfo.Permission.RecipientIDs),
&course.MetaInfo.DelPermission.Permission,
pq.Array(&course.MetaInfo.DelPermission.RecipientIDs),
&course.MetaInfo.Period,
&course.MetaInfo.ReferDataID,
&course.MetaInfo.Flag,
pq.Array(&course.MetaInfo.Tags),
&createdDate,
&updatedDate,
&course.Score,
)
if err != nil {
globals.Logger.Error(err.Error())
continue
}
ratings, errCode := datastore_db.GetObjectRatingsWithSlotByDataID(course.MetaInfo.DataID)
if errCode != 0 {
return nil, errCode
}
course.MetaInfo.Ratings = ratings
course.MetaInfo.CreatedTime.FromTimestamp(createdDate)
course.MetaInfo.UpdatedTime.FromTimestamp(updatedDate)
course.MetaInfo.ReferredTime.FromTimestamp(createdDate) // * This is what the real server does
courses = append(courses, course)
}
return courses, 0
}

View File

@@ -0,0 +1,54 @@
package datastore_smm_db
import (
"database/sql"
"github.com/PretendoNetwork/nex-go"
"github.com/PretendoNetwork/super-mario-maker-secure/database"
datastore_db "github.com/PretendoNetwork/super-mario-maker-secure/database/datastore"
"github.com/PretendoNetwork/super-mario-maker-secure/globals"
)
func GetUserCourseObjectIDs(ownerPID uint32) ([]uint64, uint32) {
courseObjectIDs := make([]uint64, 0)
// * Course objects seem to have data types > 2 and < 50.
// * Data type 1 seems to be reserved for "maker" objects.
// * Data type 2 seems to be reserved for objects
// * created through "PrepareAttachFile".
// * Data type 50 is reserved for the Event Courses metadata
// * file, and data type 51 is reserved for event courses
rows, err := database.Postgres.Query(`SELECT data_id FROM datastore.objects WHERE owner=$1 AND data_type > 2 AND data_type < 50`, ownerPID)
// * No rows is allowed
if err != nil && err != sql.ErrNoRows {
globals.Logger.Error(err.Error())
return nil, nex.Errors.DataStore.Unknown
}
defer rows.Close()
for rows.Next() {
var dataID uint64
err := rows.Scan(&dataID)
if err != nil {
globals.Logger.Error(err.Error())
continue
}
errCode := datastore_db.IsObjectAvailable(dataID)
if errCode != 0 {
continue
}
courseObjectIDs = append(courseObjectIDs, dataID)
}
if err := rows.Err(); err != nil {
// TODO - Send more specific errors?
return nil, nex.Errors.DataStore.Unknown
}
return courseObjectIDs, 0
}

View File

@@ -0,0 +1,81 @@
package datastore_smm_db
import (
"time"
"github.com/PretendoNetwork/nex-go"
datastore_smm_types "github.com/PretendoNetwork/nex-protocols-go/datastore/super-mario-maker/types"
"github.com/PretendoNetwork/super-mario-maker-secure/database"
"github.com/PretendoNetwork/super-mario-maker-secure/globals"
"github.com/lib/pq"
)
func InitializeObjectByAttachFileParam(ownerPID uint32, param *datastore_smm_types.DataStoreAttachFileParam) (uint64, uint32) {
now := time.Now()
var dataID uint64
err := database.Postgres.QueryRow(`INSERT INTO datastore.objects (
owner,
size,
name,
data_type,
meta_binary,
permission,
permission_recipients,
delete_permission,
delete_permission_recipients,
flag,
period,
refer_data_id,
tags,
persistence_slot_id,
extra_data,
creation_date,
update_date
) VALUES (
$1,
$2,
$3,
$4,
$5,
$6,
$7,
$8,
$9,
$10,
$11,
$12,
$13,
$14,
$15,
$16,
$17
) RETURNING data_id`,
ownerPID,
param.PostParam.Size,
param.PostParam.Name,
param.PostParam.DataType,
param.PostParam.MetaBinary,
param.PostParam.Permission.Permission,
pq.Array(param.PostParam.Permission.RecipientIDs),
param.PostParam.DelPermission.Permission,
pq.Array(param.PostParam.DelPermission.RecipientIDs),
param.PostParam.Flag,
param.PostParam.Period,
param.ReferDataID,
pq.Array(param.PostParam.Tags),
param.PostParam.PersistenceInitParam.PersistenceSlotID, // TODO - Check param.PersistenceInitParam.DeleteLastObject?
pq.Array(param.PostParam.ExtraData),
now,
now,
).Scan(&dataID)
if err != nil {
globals.Logger.Error(err.Error())
// TODO - Send more specific errors?
return 0, nex.Errors.DataStore.Unknown
}
return dataID, 0
}

View File

@@ -0,0 +1,42 @@
package datastore_smm_db
import (
"log"
"time"
"github.com/PretendoNetwork/super-mario-maker-secure/database"
datastore_db "github.com/PretendoNetwork/super-mario-maker-secure/database/datastore"
)
func InsertOrUpdateBufferQueueData(dataID uint64, slot uint32, buffer []byte) uint32 {
errCode := datastore_db.IsObjectAvailable(dataID)
if errCode != 0 {
return errCode
}
now := time.Now()
// * Real server does not allow duplicate
// * buffers to be in a given objects slot,
// * even if the buffers were uploaded by
// * different clients. Instead, it removes
// * the older buffer and adds the newer one.
// * Instead of that, we just update the
// * creation time
_, err := database.Postgres.Exec(`INSERT INTO datastore.buffer_queues (
data_id,
slot,
creation_date,
buffer
) VALUES (
$1,
$2,
$3,
$4
) ON CONFLICT (data_id, slot, buffer) DO UPDATE SET creation_date=$3`, dataID, slot, now, buffer)
if err != nil {
log.Fatal(err)
}
return 0
}

View File

@@ -0,0 +1,57 @@
package datastore_smm_db
import (
"time"
"github.com/PretendoNetwork/nex-go"
"github.com/PretendoNetwork/super-mario-maker-secure/database"
datastore_db "github.com/PretendoNetwork/super-mario-maker-secure/database/datastore"
"github.com/PretendoNetwork/super-mario-maker-secure/globals"
)
func InsertOrUpdateCourseRecord(dataID uint64, slot uint8, pid uint32, score int32) uint32 {
errCode := datastore_db.IsObjectAvailable(dataID)
if errCode != 0 {
globals.Logger.Errorf("Error code %d", errCode)
return errCode
}
now := time.Now()
_, err := database.Postgres.Exec(`INSERT INTO datastore.course_records (
data_id,
slot,
first_pid,
best_pid,
best_score,
creation_date,
update_date
) VALUES (
$1,
$2,
$3,
$4,
$5,
$6,
$7
) ON CONFLICT (data_id, slot) DO UPDATE
SET best_score = CASE WHEN datastore.course_records.best_score > $5 THEN $5 ELSE datastore.course_records.best_score END,
best_pid = CASE WHEN datastore.course_records.best_score > $5 THEN $4 ELSE datastore.course_records.best_pid END,
update_date = CASE WHEN datastore.course_records.best_score > $5 THEN $7 ELSE datastore.course_records.update_date END`,
dataID,
slot,
pid,
pid,
score,
now,
now,
)
if err != nil {
globals.Logger.Error(err.Error())
// TODO - Send more specific errors?
return nex.Errors.DataStore.Unknown
}
return 0
}

View File

@@ -0,0 +1,38 @@
package datastore_smm_db
import (
"github.com/PretendoNetwork/nex-go"
"github.com/PretendoNetwork/super-mario-maker-secure/database"
datastore_db "github.com/PretendoNetwork/super-mario-maker-secure/database/datastore"
"github.com/PretendoNetwork/super-mario-maker-secure/globals"
)
func InsertOrUpdateCustomRanking(dataID uint64, applicationID, score uint32) uint32 {
errCode := datastore_db.IsObjectAvailable(dataID)
if errCode != 0 {
globals.Logger.Errorf("Error code %d", errCode)
return errCode
}
_, err := database.Postgres.Exec(`INSERT INTO datastore.object_custom_rankings (
data_id,
application_id,
value
) VALUES (
$1,
$2,
$3
) ON CONFLICT (data_id, application_id) DO UPDATE SET value=datastore.object_custom_rankings.value+EXCLUDED.value`,
dataID,
applicationID,
score,
)
if err != nil {
globals.Logger.Error(err.Error())
// TODO - Send more specific errors?
return nex.Errors.DataStore.Unknown
}
return 0
}

View File

@@ -0,0 +1,47 @@
package datastore_db
import (
"database/sql"
"github.com/PretendoNetwork/nex-go"
"github.com/PretendoNetwork/super-mario-maker-secure/database"
"github.com/PretendoNetwork/super-mario-maker-secure/globals"
)
func UpdateObjectDataTypeByDataIDWithPassword(dataID uint64, dataType uint16, password uint64) uint32 {
var updatePassword uint64
var underReview bool
err := database.Postgres.QueryRow(`SELECT update_password, under_review FROM datastore.objects WHERE data_id=$1 AND upload_completed=TRUE AND deleted=FALSE`, dataID).Scan(
&updatePassword,
&underReview,
)
if err != nil {
if err == sql.ErrNoRows {
return nex.Errors.DataStore.NotFound
}
globals.Logger.Error(err.Error())
// TODO - Send more specific errors?
return nex.Errors.DataStore.Unknown
}
if updatePassword != 0 && updatePassword != password {
return nex.Errors.DataStore.InvalidPassword
}
if underReview {
return nex.Errors.DataStore.UnderReviewing
}
_, err = database.Postgres.Exec(`UPDATE datastore.objects SET data_type=$1 WHERE data_id=$2`, dataType, dataID)
if err != nil {
globals.Logger.Error(err.Error())
// TODO - Send more specific errors?
return nex.Errors.DataStore.Unknown
}
return 0
}

View File

@@ -0,0 +1,47 @@
package datastore_db
import (
"database/sql"
"github.com/PretendoNetwork/nex-go"
"github.com/PretendoNetwork/super-mario-maker-secure/database"
"github.com/PretendoNetwork/super-mario-maker-secure/globals"
)
func UpdateObjectMetaBinaryByDataIDWithPassword(dataID uint64, metaBinary []byte, password uint64) uint32 {
var updatePassword uint64
var underReview bool
err := database.Postgres.QueryRow(`SELECT update_password, under_review FROM datastore.objects WHERE data_id=$1 AND upload_completed=TRUE AND deleted=FALSE`, dataID).Scan(
&updatePassword,
&underReview,
)
if err != nil {
if err == sql.ErrNoRows {
return nex.Errors.DataStore.NotFound
}
globals.Logger.Error(err.Error())
// TODO - Send more specific errors?
return nex.Errors.DataStore.Unknown
}
if updatePassword != 0 && updatePassword != password {
return nex.Errors.DataStore.InvalidPassword
}
if underReview {
return nex.Errors.DataStore.UnderReviewing
}
_, err = database.Postgres.Exec(`UPDATE datastore.objects SET meta_binary=$1 WHERE data_id=$2`, metaBinary, dataID)
if err != nil {
globals.Logger.Error(err.Error())
// TODO - Send more specific errors?
return nex.Errors.DataStore.Unknown
}
return 0
}

View File

@@ -0,0 +1,47 @@
package datastore_db
import (
"database/sql"
"github.com/PretendoNetwork/nex-go"
"github.com/PretendoNetwork/super-mario-maker-secure/database"
"github.com/PretendoNetwork/super-mario-maker-secure/globals"
)
func UpdateObjectPeriodByDataIDWithPassword(dataID uint64, period uint16, password uint64) uint32 {
var updatePassword uint64
var underReview bool
err := database.Postgres.QueryRow(`SELECT update_password, under_review FROM datastore.objects WHERE data_id=$1 AND upload_completed=TRUE AND deleted=FALSE`, dataID).Scan(
&updatePassword,
&underReview,
)
if err != nil {
if err == sql.ErrNoRows {
return nex.Errors.DataStore.NotFound
}
globals.Logger.Error(err.Error())
// TODO - Send more specific errors?
return nex.Errors.DataStore.Unknown
}
if updatePassword != 0 && updatePassword != password {
return nex.Errors.DataStore.InvalidPassword
}
if underReview {
return nex.Errors.DataStore.UnderReviewing
}
_, err = database.Postgres.Exec(`UPDATE datastore.objects SET period=$1 WHERE data_id=$2`, period, dataID)
if err != nil {
globals.Logger.Error(err.Error())
// TODO - Send more specific errors?
return nex.Errors.DataStore.Unknown
}
return 0
}

View File

@@ -0,0 +1,38 @@
package datastore_db
import (
"database/sql"
"github.com/PretendoNetwork/nex-go"
"github.com/PretendoNetwork/super-mario-maker-secure/database"
"github.com/PretendoNetwork/super-mario-maker-secure/globals"
)
func UpdateObjectUploadCompletedByDataID(dataID uint64, uploadCompleted bool) uint32 {
var underReview bool
err := database.Postgres.QueryRow(`SELECT update_password FROM datastore.objects WHERE data_id=$1 AND deleted=FALSE`, dataID).Scan(&underReview)
if err != nil {
if err == sql.ErrNoRows {
return nex.Errors.DataStore.NotFound
}
globals.Logger.Error(err.Error())
// TODO - Send more specific errors?
return nex.Errors.DataStore.Unknown
}
if underReview {
return nex.Errors.DataStore.UnderReviewing
}
_, err = database.Postgres.Exec(`UPDATE datastore.objects SET upload_completed=$1 WHERE data_id=$2`, uploadCompleted, dataID)
if err != nil {
globals.Logger.Error(err.Error())
// TODO - Send more specific errors?
return nex.Errors.DataStore.Unknown
}
return 0
}

View File

@@ -1,48 +0,0 @@
package database
import (
"encoding/binary"
)
// DataStoreIDGenerator represents a safe, structured, ID for unique NEX DataStore objects
type DataStoreIDGenerator struct {
inUse bool
regionID uint8
nodeID uint8
Value uint32
}
// InUse is used to check if a DataStoreIDGenerator Node is currently generating a number
func (dataStoreIDGenerator *DataStoreIDGenerator) InUse() bool {
return dataStoreIDGenerator.inUse
}
// SetInUse is used to check if a DataStoreIDGenerator Node is currently generating a number
func (dataStoreIDGenerator *DataStoreIDGenerator) SetInUse(inUse bool) {
dataStoreIDGenerator.inUse = inUse
}
// Next is used to get the next value from the DataStoreIDGenerator Node
func (dataStoreIDGenerator *DataStoreIDGenerator) Next() uint64 {
if dataStoreIDGenerator.inUse {
panic("Cannot call DataStoreIDGenerator.Next while in use")
}
dataStoreIDGenerator.Value += 1
data := make([]byte, 8)
data[2] = dataStoreIDGenerator.regionID
data[3] = dataStoreIDGenerator.nodeID
binary.BigEndian.PutUint32(data[4:], dataStoreIDGenerator.Value)
return binary.BigEndian.Uint64(data)
}
func NewDataStoreIDGenerator(regionID, nodeID uint8, value uint32) *DataStoreIDGenerator {
return &DataStoreIDGenerator{
regionID: regionID,
nodeID: nodeID,
Value: value,
}
}

View File

@@ -1,20 +0,0 @@
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
}

View File

@@ -1,57 +0,0 @@
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
}

View File

@@ -1,18 +0,0 @@
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
}

View File

@@ -1,51 +0,0 @@
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
}

View File

@@ -1,26 +0,0 @@
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
}

View File

@@ -1,28 +0,0 @@
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,
}
}

View File

@@ -1,8 +0,0 @@
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
}

View File

@@ -1,25 +0,0 @@
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)
}

View File

@@ -1,10 +0,0 @@
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)
}

View File

@@ -1,9 +0,0 @@
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)
}
}

View File

@@ -1,9 +0,0 @@
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)
}
}

View File

@@ -1,9 +0,0 @@
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)
}
}

View File

@@ -1,9 +0,0 @@
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)
}
}

281
database/init_postgres.go Normal file
View File

@@ -0,0 +1,281 @@
package database
import (
"os"
"time"
"github.com/PretendoNetwork/super-mario-maker-secure/globals"
"github.com/lib/pq"
)
func initPostgres() {
_, err := Postgres.Exec(`CREATE SCHEMA IF NOT EXISTS datastore`)
if err != nil {
globals.Logger.Critical(err.Error())
os.Exit(0)
}
globals.Logger.Success("datastore Postgres schema created")
// * Super Mario Maker has non-standard DataID requirements.
// * DataID 900000 is reserved for the event course metadata
// * file, and official event courses begin at DataID 930010
// * and end at DataID 930050. To prevent a collision
// * eventually, we need to start course IDs AFTER 930050
// *
// * DataIDs are stored and processed as uint64, however
// * Super Mario Maker can not use the full uint64 range.
// * This is because course share codes are generated from the
// * courses DataID. A course share code is an 8 byte hex
// * string, where the upper 2 bytes are the checksum of the
// * lower 6 bytes. The lower 6 bytes are the courses DataID
// *
// * Super Mario Maker is only capable of displaying codes up
// * to 0xFFFFFFFFFFFF, essentially truncating DataIDs down to
// * 48 bit integers instead of 64 bit. I doubt we will ever
// * hit even the 32 bit limit, let alone 48, but this is here
// * just in case
_, err = Postgres.Exec(`CREATE SEQUENCE IF NOT EXISTS datastore.object_data_id_seq
INCREMENT 1
MINVALUE 1
MAXVALUE 281474976710656
START 940000
CACHE 1`, // * Honestly I don't know what CACHE does but I saw it recommended so here it is
)
if err != nil {
globals.Logger.Critical(err.Error())
os.Exit(0)
}
// * "deletion_reason" and "under_review" are specific to SMM.
// * Everything else is stock
_, err = Postgres.Exec(`CREATE TABLE IF NOT EXISTS datastore.objects (
data_id bigint NOT NULL DEFAULT nextval('datastore.object_data_id_seq') PRIMARY KEY,
upload_completed boolean NOT NULL DEFAULT FALSE,
deleted boolean NOT NULL DEFAULT FALSE,
deletion_reason int NOT NULL DEFAULT 0,
under_review boolean NOT NULL DEFAULT FALSE,
owner int,
size int,
name text,
data_type int,
meta_binary bytea,
permission int,
permission_recipients int[],
delete_permission int,
delete_permission_recipients int[],
flag int,
period int,
refer_data_id bigint,
tags text[],
persistence_slot_id int,
extra_data text[],
access_password bigint NOT NULL DEFAULT 0,
update_password bigint NOT NULL DEFAULT 0,
creation_date timestamp,
update_date timestamp
)`)
if err != nil {
globals.Logger.Critical(err.Error())
os.Exit(0)
}
// * Unsure what like half of this is but the client sends it so we saves it
_, err = Postgres.Exec(`CREATE TABLE IF NOT EXISTS datastore.object_ratings (
data_id bigint,
slot smallint,
flag smallint,
internal_flag smallint,
lock_type smallint,
initial_value bigint,
range_min int,
range_max int,
period_hour smallint,
period_duration int,
total_value bigint,
count int NOT NULL DEFAULT 0,
PRIMARY KEY(data_id, slot)
)`)
if err != nil {
globals.Logger.Critical(err.Error())
os.Exit(0)
}
// * Custom rankings are specific to SMM
// TODO - Store the period? What even is the period of custom rankings?
_, err = Postgres.Exec(`CREATE TABLE IF NOT EXISTS datastore.object_custom_rankings (
data_id bigint,
application_id bigint,
value bigint,
PRIMARY KEY(data_id, application_id)
)`)
if err != nil {
globals.Logger.Critical(err.Error())
os.Exit(0)
}
// * BufferQueues are specific to SMM
// * Real server does not allow duplicate buffers in a given slot for an object,
// * even if uploaded by different users. We could change this, but I don't see
// * much point
_, err = Postgres.Exec(`CREATE TABLE IF NOT EXISTS datastore.buffer_queues (
data_id bigint,
slot int,
creation_date timestamp,
buffer bytea,
PRIMARY KEY(data_id, slot, buffer)
)`)
if err != nil {
globals.Logger.Critical(err.Error())
os.Exit(0)
}
// * Course records are specific to SMM
_, err = Postgres.Exec(`CREATE TABLE IF NOT EXISTS datastore.course_records (
data_id bigint,
slot int,
first_pid int,
best_pid int,
best_score int,
creation_date timestamp,
update_date timestamp,
PRIMARY KEY(data_id, slot)
)`)
if err != nil {
globals.Logger.Critical(err.Error())
os.Exit(0)
}
globals.Logger.Success("Postgres tables created")
ensureEventCourseMetaDataFileExists()
}
func ensureEventCourseMetaDataFileExists() {
// * The event course metadata file is REQUIRED for
// * Super Mario Maker to open Course World. This
// * ensures that it exists both in S3 and in the
// * database before booting. It has the reserved
// * DataID 900000
bucket := os.Getenv("PN_SMM_CONFIG_S3_BUCKET")
key := "900000.bin"
objectSizeS3, err := globals.S3ObjectSize(bucket, key)
if err != nil {
globals.Logger.Errorf("Failed to stat event course metadata file. Ensure your S3 credentials are correct and the 900000.bin file is uploaded to your bucket. S3 error: %s", err.Error())
os.Exit(0)
}
globals.Logger.Success("Event course metadata file found. Verifying database")
var exists bool
err = Postgres.QueryRow(`SELECT EXISTS(SELECT 1 FROM datastore.objects WHERE data_id=900000) AS "exists"`).Scan(&exists)
if err != nil {
globals.Logger.Errorf("Error querying for event course metadata object in Postgres: %s", err.Error())
os.Exit(0)
}
now := time.Now()
if !exists {
var dataID uint64
globals.Logger.Info("Event course metadata object not found in Postgres. Creating")
err := Postgres.QueryRow(`INSERT INTO datastore.objects (
data_id,
upload_completed,
owner,
size,
name,
data_type,
meta_binary,
permission,
permission_recipients,
delete_permission,
delete_permission_recipients,
flag,
period,
refer_data_id,
tags,
persistence_slot_id,
extra_data,
creation_date,
update_date
) VALUES (
$1,
$2,
$3,
$4,
$5,
$6,
$7,
$8,
$9,
$10,
$11,
$12,
$13,
$14,
$15,
$16,
$17,
$18,
$19
) RETURNING data_id`,
900000,
true,
2, // * "Quazal Rendez-Vous" special account
objectSizeS3,
"", // * Has no name
50, // * Metadata file has DataType 50. Event courses have DataType 51
[]byte{}, // * No MetaBinary
0, // * Accessible by everyone
pq.Array([]uint32{}),
3, // * THE REAL SERVER HAS THIS SET TO 0, FOR EVERYONE. THAT'S SUPER INSECURE.
pq.Array([]uint32{}),
0,
64306,
0,
pq.Array([]string{}),
0, // * Unsure what the slot ID actually is
pq.Array([]string{}),
now,
now,
).Scan(&dataID)
if err != nil {
globals.Logger.Errorf("Error creating event course metadata object: %s", err.Error())
os.Exit(0)
}
} else {
var objectSizeDB uint32
err := Postgres.QueryRow(`SELECT size FROM datastore.objects WHERE data_id=900000`).Scan(&objectSizeDB)
if err != nil {
globals.Logger.Errorf("Error querying event course metadata object size: %s", err.Error())
os.Exit(0)
}
if objectSizeS3 != uint64(objectSizeDB) {
globals.Logger.Success("Event course metadata object found in Postgres! Updating size")
_, err := Postgres.Exec(`UPDATE datastore.objects SET size=$1, update_date=$2 WHERE data_id=900000`, objectSizeS3, now)
if err != nil {
globals.Logger.Errorf("Error updating event course metadata object size: %s", err.Error())
os.Exit(0)
}
} else {
globals.Logger.Success("Event course metadata object found in Postgres!")
}
globals.Logger.Info("Ensuring event course metadata object has correct delete permission")
_, err = Postgres.Exec(`UPDATE datastore.objects SET delete_permission=3 WHERE data_id=900000`)
if err != nil {
globals.Logger.Errorf("Error updating event course metadata object delete permission: %s", err.Error())
os.Exit(0)
}
}
globals.Logger.Success("Event course metadata object found and is up to date!")
}

View File

@@ -1,56 +0,0 @@
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)
}
}

View File

@@ -1,9 +0,0 @@
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)
}
}

View File

@@ -1,9 +0,0 @@
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)
}
}

View File

@@ -1,9 +0,0 @@
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)
}
}

View File

@@ -1,9 +0,0 @@
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)
}
}

View File

@@ -1,22 +0,0 @@
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)
}
}

View File

@@ -3,12 +3,19 @@ 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"
"github.com/minio/minio-go/v7"
"google.golang.org/grpc"
"google.golang.org/grpc/metadata"
pb "github.com/PretendoNetwork/grpc-go/account"
)
var Logger = plogger.NewLogger()
var NEXServer *nex.Server
var S3Client *s3.Client
var HMACSecret []byte
var DataStoreIDGenerators []*database.DataStoreIDGenerator
var KerberosPassword = "password" // * Default password
var AuthenticationServer *nex.Server
var SecureServer *nex.Server
var MinIOClient *minio.Client
var Presigner *S3Presigner
var GRPCAccountClientConnection *grpc.ClientConn
var GRPCAccountClient pb.AccountClient
var GRPCAccountCommonMetadata metadata.MD

22
globals/password_from_pid.go Executable file
View File

@@ -0,0 +1,22 @@
package globals
import (
"context"
pb "github.com/PretendoNetwork/grpc-go/account"
"github.com/PretendoNetwork/nex-go"
"github.com/PretendoNetwork/nex-protocols-go/globals"
"google.golang.org/grpc/metadata"
)
func PasswordFromPID(pid uint32) (string, uint32) {
ctx := metadata.NewOutgoingContext(context.Background(), GRPCAccountCommonMetadata)
response, err := GRPCAccountClient.GetNEXPassword(ctx, &pb.GetNEXPasswordRequest{Pid: pid})
if err != nil {
globals.Logger.Error(err.Error())
return "", nex.Errors.RendezVous.InvalidUsername
}
return response.Password, 0
}

20
globals/s3_helpers.go Normal file
View File

@@ -0,0 +1,20 @@
package globals
import (
"context"
"github.com/minio/minio-go/v7"
)
func S3StatObject(bucket, key string) (minio.ObjectInfo, error) {
return MinIOClient.StatObject(context.TODO(), bucket, key, minio.StatObjectOptions{})
}
func S3ObjectSize(bucket, key string) (uint64, error) {
info, err := S3StatObject(bucket, key)
if err != nil {
return 0, err
}
return uint64(info.Size), nil
}

46
globals/s3_presigner.go Normal file
View File

@@ -0,0 +1,46 @@
package globals
import (
"context"
"net/url"
"time"
"github.com/minio/minio-go/v7"
)
type S3Presigner struct {
minio *minio.Client
}
func (p *S3Presigner) GetObject(bucket, key string, lifetime time.Duration) (*url.URL, error) {
reqParams := make(url.Values)
return p.minio.PresignedGetObject(context.Background(), bucket, key, lifetime, reqParams)
}
func (p *S3Presigner) PostObject(bucket, key string, lifetime time.Duration) (*url.URL, map[string]string, error) {
policy := minio.NewPostPolicy()
err := policy.SetBucket(bucket)
if err != nil {
return nil, nil, err
}
err = policy.SetKey(key)
if err != nil {
return nil, nil, err
}
err = policy.SetExpires(time.Now().UTC().Add(lifetime).UTC())
if err != nil {
return nil, nil, err
}
return p.minio.PresignedPostPolicy(context.Background(), policy)
}
func NewS3Presigner(minioClient *minio.Client) *S3Presigner {
return &S3Presigner{
minio: minioClient,
}
}

View File

@@ -0,0 +1,40 @@
package globals
import (
"github.com/PretendoNetwork/nex-go"
datastore_types "github.com/PretendoNetwork/nex-protocols-go/datastore/types"
"golang.org/x/exp/slices"
)
func VerifyObjectPermission(ownerPID, accessorPID uint32, permission *datastore_types.DataStorePermission) uint32 {
if permission.Permission > 3 {
return nex.Errors.DataStore.InvalidArgument
}
// * Allow anyone
if permission.Permission == 0 {
return 0
}
// * Allow friends
// TODO - Implement this
if permission.Permission == 1 {
return nex.Errors.DataStore.PermissionDenied
}
// * Allow people in permission.RecipientIDs
if permission.Permission == 2 {
if !slices.Contains(permission.RecipientIDs, accessorPID) {
return nex.Errors.DataStore.PermissionDenied
}
}
// * Allow only the owner
if permission.Permission == 3 {
if ownerPID != accessorPID {
return nex.Errors.DataStore.PermissionDenied
}
}
return 0
}

69
go.mod
View File

@@ -1,48 +1,45 @@
module github.com/PretendoNetwork/super-mario-maker-secure
go 1.19
go 1.21
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/PretendoNetwork/grpc-go v1.0.2
github.com/PretendoNetwork/nex-go v1.0.41
github.com/PretendoNetwork/nex-protocols-common-go v1.0.30
github.com/PretendoNetwork/nex-protocols-go v1.0.58
github.com/PretendoNetwork/plogger-go v1.0.4
github.com/joho/godotenv v1.5.1
go.mongodb.org/mongo-driver v1.11.4
github.com/lib/pq v1.10.9
github.com/minio/minio-go/v7 v7.0.63
golang.org/x/exp v0.0.0-20231006140011-7918f672742d
google.golang.org/grpc v1.59.0
)
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/dustin/go-humanize v1.0.1 // 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/golang/protobuf v1.5.3 // indirect
github.com/google/uuid v1.4.0 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/jwalton/go-supportscolor v1.2.0 // indirect
github.com/klauspost/compress v1.17.2 // indirect
github.com/klauspost/cpuid/v2 v2.2.5 // 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/mattn/go-isatty v0.0.20 // indirect
github.com/minio/md5-simd v1.1.2 // indirect
github.com/minio/sha256-simd v1.0.1 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/rs/xid v1.5.0 // indirect
github.com/sirupsen/logrus v1.9.3 // 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
golang.org/x/crypto v0.14.0 // indirect
golang.org/x/mod v0.13.0 // indirect
golang.org/x/net v0.17.0 // indirect
golang.org/x/sys v0.13.0 // indirect
golang.org/x/term v0.13.0 // indirect
golang.org/x/text v0.13.0 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20231030173426-d783a09b4405 // indirect
google.golang.org/protobuf v1.31.0 // indirect
gopkg.in/ini.v1 v1.67.0 // indirect
)

179
go.sum
View File

@@ -1,125 +1,102 @@
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/PretendoNetwork/grpc-go v1.0.2 h1:9TvKmX7dCOANyoHEra1MMYqS1N/RGav66TRG4SHInvo=
github.com/PretendoNetwork/grpc-go v1.0.2/go.mod h1:XZjEsij9lL7HJBNkH6JPbBIkUSq/1rjflvjGdv+DAj0=
github.com/PretendoNetwork/nex-go v1.0.41 h1:TcBb1Bpe2KAB+AXaGX1K9NVQBRtZJIoy4yCvRde2xbI=
github.com/PretendoNetwork/nex-go v1.0.41/go.mod h1:QwHEa165DeVd0xIuthrgc3j6NWXT8lyPSG6t5kC/Shk=
github.com/PretendoNetwork/nex-protocols-common-go v1.0.30 h1:z2BvyG/3x1lW8sx6Ml83G0Lkj5J9hdb0bjdZuuDCYSE=
github.com/PretendoNetwork/nex-protocols-common-go v1.0.30/go.mod h1:37jNRX6M/s0xA/gc4BccO8k2GLG1lpMZXAtIYRCZCTY=
github.com/PretendoNetwork/nex-protocols-go v1.0.58 h1:W8pZ2LOlJm/mo/UOJjkLWNVHs0jQmkoa8qoI5A1WVyY=
github.com/PretendoNetwork/nex-protocols-go v1.0.58/go.mod h1:136762CMIcAsTZDrt4W7gDE4ppiBuc9zN2QFOHESjS8=
github.com/PretendoNetwork/plogger-go v1.0.4 h1:PF7xHw9eDRHH+RsAP9tmAE7fG0N0p6H4iPwHKnsoXwc=
github.com/PretendoNetwork/plogger-go v1.0.4/go.mod h1:7kD6M4vPq1JL4LTuPg6kuB1OvUBOwQOtAvTaUwMbwvU=
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/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
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/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/uuid v1.4.0 h1:MtMxsa51/r9yyhkyLsVeVt0B+BGQZzpQiTQ4eHZ8bc4=
github.com/google/uuid v1.4.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
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/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
github.com/jwalton/go-supportscolor v1.2.0 h1:g6Ha4u7Vm3LIsQ5wmeBpS4gazu0UP1DRDE8y6bre4H8=
github.com/jwalton/go-supportscolor v1.2.0/go.mod h1:hFVUAZV2cWg+WFFC4v8pT2X/S2qUUBYMioBD9AINXGs=
github.com/klauspost/compress v1.17.2 h1:RlWWUY/Dr4fL8qk9YG7DTZ7PDgME2V4csBXA8L/ixi4=
github.com/klauspost/compress v1.17.2/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE=
github.com/klauspost/cpuid/v2 v2.0.1/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
github.com/klauspost/cpuid/v2 v2.2.5 h1:0E5MSMDEoAulmXNFquVs//DdoomxaoTY1kUhbc/qbZg=
github.com/klauspost/cpuid/v2 v2.2.5/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=
github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw=
github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
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/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/minio/md5-simd v1.1.2 h1:Gdi1DZK69+ZVMoNHRXJyNcxrMA4dSxoYHZSQbirFg34=
github.com/minio/md5-simd v1.1.2/go.mod h1:MzdKDxYpY2BT9XQFocsiZf/NKVtR7nkE4RoEpN+20RM=
github.com/minio/minio-go/v7 v7.0.63 h1:GbZ2oCvaUdgT5640WJOpyDhhDxvknAJU2/T3yurwcbQ=
github.com/minio/minio-go/v7 v7.0.63/go.mod h1:Q6X7Qjb7WMhvG65qKf4gUgA5XaiSox74kR1uAEjxRS4=
github.com/minio/sha256-simd v1.0.1 h1:6kaan5IFmwTNynnKKpDHe6FWHohJOHhCPchzK49dzMM=
github.com/minio/sha256-simd v1.0.1/go.mod h1:Pz6AKMiUdngCLpeTL/RJY1M9rUuPMYujV5xJjtbRSN8=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
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/rs/xid v1.5.0 h1:mKX4bl4iPYJtEIxp6CYiUuLQ/8DYMoz0PUdtGgMFRVc=
github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
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/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
github.com/stretchr/testify v1.7.0/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/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc=
golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4=
golang.org/x/exp v0.0.0-20231006140011-7918f672742d h1:jtJma62tbqLibJ5sFQz8bKtEM8rJBtfilJ2qTU199MI=
golang.org/x/exp v0.0.0-20231006140011-7918f672742d/go.mod h1:ldy0pHrwJyGW56pPQzzkH36rKxoZW1tw7ZJpeKx+hdo=
golang.org/x/mod v0.13.0 h1:I/DsJXRlw/8l/0c24sM9yb0T4z9liZTduXvdAWYiysY=
golang.org/x/mod v0.13.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM=
golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE=
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-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.5.0/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/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE=
golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
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/term v0.13.0 h1:bb+I9cTfFazGW51MZqBVmZy7+JEJMouUHTUSKVQLBek=
golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U=
golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k=
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/genproto/googleapis/rpc v0.0.0-20231030173426-d783a09b4405 h1:AB/lmRny7e2pLhFEYIbl5qkDAUt2h0ZRO4wGPhZf+ik=
google.golang.org/genproto/googleapis/rpc v0.0.0-20231030173426-d783a09b4405/go.mod h1:67X1fPuzjcrkymZzZV1vvkFeTn2Rvc6lYF9MYFGCcwE=
google.golang.org/grpc v1.59.0 h1:Z5Iec2pjwb+LEOqzpB2MR12/eKFhDPhuqW91O+4bwUk=
google.golang.org/grpc v1.59.0/go.mod h1:aUPDwccQo6OTjy7Hct4AfBPD1GptF4fyUjIkQ9YtF98=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8=
google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
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/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA=
gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
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=

129
init.go
View File

@@ -1,13 +1,21 @@
package main
import (
"io/ioutil"
"fmt"
"log"
"runtime"
"os"
"strconv"
"strings"
pb "github.com/PretendoNetwork/grpc-go/account"
"github.com/PretendoNetwork/super-mario-maker-secure/database"
"github.com/PretendoNetwork/super-mario-maker-secure/globals"
"github.com/joho/godotenv"
"github.com/minio/minio-go/v7"
"github.com/minio/minio-go/v7/pkg/credentials"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials/insecure"
"google.golang.org/grpc/metadata"
)
func init() {
@@ -18,26 +26,107 @@ func init() {
log.Fatal("Error loading .env file")
}
globals.HMACSecret, err = ioutil.ReadFile("secret.key")
s3Endpoint := os.Getenv("PN_SMM_CONFIG_S3_ENDPOINT")
s3AccessKey := os.Getenv("PN_SMM_CONFIG_S3_ACCESS_KEY")
s3AccessSecret := os.Getenv("PN_SMM_CONFIG_S3_ACCESS_SECRET")
postgresURI := os.Getenv("PN_SMM_POSTGRES_URI")
kerberosPassword := os.Getenv("PN_SMM_KERBEROS_PASSWORD")
authenticationServerPort := os.Getenv("PN_SMM_AUTHENTICATION_SERVER_PORT")
secureServerHost := os.Getenv("PN_SMM_SECURE_SERVER_HOST")
secureServerPort := os.Getenv("PN_SMM_SECURE_SERVER_PORT")
accountGRPCHost := os.Getenv("PN_SMM_ACCOUNT_GRPC_HOST")
accountGRPCPort := os.Getenv("PN_SMM_ACCOUNT_GRPC_PORT")
accountGRPCAPIKey := os.Getenv("PN_SMM_ACCOUNT_GRPC_API_KEY")
if strings.TrimSpace(postgresURI) == "" {
globals.Logger.Error("PN_SMM_POSTGRES_URI environment variable not set")
os.Exit(0)
}
if strings.TrimSpace(kerberosPassword) == "" {
globals.Logger.Warningf("PN_SMM_KERBEROS_PASSWORD environment variable not set. Using default password: %q", globals.KerberosPassword)
} else {
globals.KerberosPassword = kerberosPassword
}
if strings.TrimSpace(authenticationServerPort) == "" {
globals.Logger.Error("PN_SMM_AUTHENTICATION_SERVER_PORT environment variable not set")
os.Exit(0)
}
if port, err := strconv.Atoi(authenticationServerPort); err != nil {
globals.Logger.Errorf("PN_SMM_AUTHENTICATION_SERVER_PORT is not a valid port. Expected 0-65535, got %s", authenticationServerPort)
os.Exit(0)
} else if port < 0 || port > 65535 {
globals.Logger.Errorf("PN_SMM_AUTHENTICATION_SERVER_PORT is not a valid port. Expected 0-65535, got %s", authenticationServerPort)
os.Exit(0)
}
if strings.TrimSpace(secureServerHost) == "" {
globals.Logger.Error("PN_SMM_SECURE_SERVER_HOST environment variable not set")
os.Exit(0)
}
if strings.TrimSpace(secureServerPort) == "" {
globals.Logger.Error("PN_SMM_SECURE_SERVER_PORT environment variable not set")
os.Exit(0)
}
if port, err := strconv.Atoi(secureServerPort); err != nil {
globals.Logger.Errorf("PN_SMM_SECURE_SERVER_PORT is not a valid port. Expected 0-65535, got %s", secureServerPort)
os.Exit(0)
} else if port < 0 || port > 65535 {
globals.Logger.Errorf("PN_SMM_SECURE_SERVER_PORT is not a valid port. Expected 0-65535, got %s", secureServerPort)
os.Exit(0)
}
if strings.TrimSpace(accountGRPCHost) == "" {
globals.Logger.Error("PN_SMM_ACCOUNT_GRPC_HOST environment variable not set")
os.Exit(0)
}
if strings.TrimSpace(accountGRPCPort) == "" {
globals.Logger.Error("PN_SMM_ACCOUNT_GRPC_PORT environment variable not set")
os.Exit(0)
}
if port, err := strconv.Atoi(accountGRPCPort); err != nil {
globals.Logger.Errorf("PN_SMM_ACCOUNT_GRPC_PORT is not a valid port. Expected 0-65535, got %s", accountGRPCPort)
os.Exit(0)
} else if port < 0 || port > 65535 {
globals.Logger.Errorf("PN_SMM_ACCOUNT_GRPC_PORT is not a valid port. Expected 0-65535, got %s", accountGRPCPort)
os.Exit(0)
}
if strings.TrimSpace(accountGRPCAPIKey) == "" {
globals.Logger.Warning("Insecure gRPC server detected. PN_SMM_ACCOUNT_GRPC_API_KEY environment variable not set")
}
globals.GRPCAccountClientConnection, err = grpc.Dial(fmt.Sprintf("%s:%s", accountGRPCHost, accountGRPCPort), grpc.WithTransportCredentials(insecure.NewCredentials()))
if err != nil {
globals.Logger.Criticalf("Failed to connect to account gRPC server: %v", err)
os.Exit(0)
}
globals.GRPCAccountClient = pb.NewAccountClient(globals.GRPCAccountClientConnection)
globals.GRPCAccountCommonMetadata = metadata.Pairs(
"X-API-Key", accountGRPCAPIKey,
)
staticCredentials := credentials.NewStaticV4(s3AccessKey, s3AccessSecret, "")
minIOClient, err := minio.New(s3Endpoint, &minio.Options{
Creds: staticCredentials,
Secure: true,
})
if err != nil {
panic(err)
}
// Connect to and setup databases
database.ConnectAll()
createDataStoreIDGenerators()
}
func createDataStoreIDGenerators() {
globals.DataStoreIDGenerators = make([]*database.DataStoreIDGenerator, 0)
regionID := 0 // USA
for corenum := 0; corenum < runtime.NumCPU(); corenum++ {
database.CreateDataStoreIDGeneratorRow(corenum)
lastID := database.GetDataStoreIDGeneratorLastID(corenum)
generator := database.NewDataStoreIDGenerator(uint8(regionID), uint8(corenum), lastID)
globals.DataStoreIDGenerators = append(globals.DataStoreIDGenerators, generator)
}
globals.MinIOClient = minIOClient
globals.Presigner = globals.NewS3Presigner(globals.MinIOClient)
// * Connect to and setup databases
database.ConnectPostgres()
}

View File

@@ -9,10 +9,11 @@ import (
var wg sync.WaitGroup
func main() {
wg.Add(1)
wg.Add(2)
// TODO - Add gRPC server
go nex.StartNEXServer()
go nex.StartAuthenticationServer()
go nex.StartSecureServer()
wg.Wait()
}

35
nex/authentication.go Normal file
View File

@@ -0,0 +1,35 @@
package nex
import (
"fmt"
"os"
nex "github.com/PretendoNetwork/nex-go"
"github.com/PretendoNetwork/super-mario-maker-secure/globals"
)
var serverBuildString string
func StartAuthenticationServer() {
globals.AuthenticationServer = nex.NewServer()
globals.AuthenticationServer.SetPRUDPVersion(1)
globals.AuthenticationServer.SetPRUDPProtocolMinorVersion(2)
globals.AuthenticationServer.SetDefaultNEXVersion(nex.NewPatchedNEXVersion(3, 8, 3, "AMAJ"))
globals.AuthenticationServer.SetKerberosPassword(globals.KerberosPassword)
globals.AuthenticationServer.SetAccessKey("9f2b4678")
globals.AuthenticationServer.On("Data", func(packet *nex.PacketV1) {
request := packet.RMCRequest()
fmt.Println("==SMM1 - Auth==")
fmt.Printf("Protocol ID: %d\n", request.ProtocolID())
fmt.Printf("Method ID: %d\n", request.MethodID())
fmt.Println("===============")
})
serverBuildString = "build:3_8_29_3022_0"
registerCommonAuthenticationServerProtocols()
globals.AuthenticationServer.Listen(fmt.Sprintf(":%s", os.Getenv("PN_SMM_AUTHENTICATION_SERVER_PORT")))
}

View File

@@ -1,29 +0,0 @@
package nex_datastore
import (
nex "github.com/PretendoNetwork/nex-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 *datastore.DataStoreChangeMetaParam) {
// STUBBED
// TODO: DO SOMETHING WITH THE DATA
rmcResponse := nex.NewRMCResponse(datastore.ProtocolID, callID)
rmcResponse.SetSuccess(datastore.MethodChangeMeta, 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)
}

View File

@@ -1,29 +0,0 @@
package nex_datastore
import (
nex "github.com/PretendoNetwork/nex-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 *datastore.DataStoreCompletePostParam) {
// TODO: DO SOMETHING WITH THE DATA
rmcResponse := nex.NewRMCResponse(datastore.ProtocolID, callID)
rmcResponse.SetSuccess(datastore.MethodCompletePostObject, 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)
}

View File

@@ -1,104 +0,0 @@
package nex_datastore
import (
"fmt"
"os"
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 GetMeta(err error, client *nex.Client, callID uint32, param *datastore.DataStoreGetMetaParam) {
switch param.DataID {
case 0: // Mii Data
getMetaMiiData(client, callID, param)
case 900000: // Event course news
getMetaEventCourseNewsData(client, callID, param)
default:
fmt.Printf("[Warning] DataStoreProtocol::GetMeta Unsupported dataId: %v\n", param.DataID)
}
}
func getMetaMiiData(client *nex.Client, callID uint32, param *datastore.DataStoreGetMetaParam) {
miiInfo := database.GetUserMiiInfoByPID(param.PersistenceTarget.OwnerID)
pMetaInfo := utility.UserMiiDataToDataStoreMetaInfo(param.PersistenceTarget.OwnerID, miiInfo)
rmcResponseStream := nex.NewStreamOut(globals.NEXServer)
rmcResponseStream.WriteStructure(pMetaInfo)
rmcResponseBody := rmcResponseStream.Bytes()
rmcResponse := nex.NewRMCResponse(datastore.ProtocolID, callID)
rmcResponse.SetSuccess(datastore.MethodGetMeta, 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 getMetaEventCourseNewsData(client *nex.Client, callID uint32, param *datastore.DataStoreGetMetaParam) {
objectSize, _ := utility.S3ObjectSize(os.Getenv("S3_BUCKET_NAME"), "special/900000.bin")
pMetaInfo := datastore.NewDataStoreMetaInfo()
pMetaInfo.DataID = 900000
pMetaInfo.OwnerID = 2
pMetaInfo.Size = uint32(objectSize)
pMetaInfo.Name = ""
pMetaInfo.DataType = 50 // Metdata?
pMetaInfo.MetaBinary = []byte{}
pMetaInfo.Permission = datastore.NewDataStorePermission()
pMetaInfo.Permission.Permission = 0 // idk?
pMetaInfo.Permission.RecipientIds = []uint32{}
pMetaInfo.DelPermission = datastore.NewDataStorePermission()
pMetaInfo.DelPermission.Permission = 0 // idk?
pMetaInfo.DelPermission.RecipientIds = []uint32{}
pMetaInfo.CreatedTime = nex.NewDateTime(135271087238) // Reused from Nintendo
pMetaInfo.UpdatedTime = nex.NewDateTime(135402751254) // Reused from Nintendo
pMetaInfo.Period = 64306 // idk?
pMetaInfo.Status = 0
pMetaInfo.ReferredCnt = 0
pMetaInfo.ReferDataID = 0
pMetaInfo.Flag = 0 // idk?
pMetaInfo.ReferredTime = nex.NewDateTime(135271087238) // Reused from Nintendo
pMetaInfo.ExpireTime = nex.NewDateTime(671075926016) // Reused from Nintendo
pMetaInfo.Tags = []string{} // idk?
pMetaInfo.Ratings = []*datastore.DataStoreRatingInfoWithSlot{}
rmcResponseStream := nex.NewStreamOut(globals.NEXServer)
rmcResponseStream.WriteStructure(pMetaInfo)
rmcResponseBody := rmcResponseStream.Bytes()
rmcResponse := nex.NewRMCResponse(datastore.ProtocolID, callID)
rmcResponse.SetSuccess(datastore.MethodGetMeta, 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)
}

View File

@@ -1,57 +0,0 @@
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)
}

View File

@@ -1,58 +0,0 @@
package nex_datastore
import (
"fmt"
"os"
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 PrepareGetObject(err error, client *nex.Client, callID uint32, dataStorePrepareGetParam *datastore.DataStorePrepareGetParam) {
pReqGetInfo := datastore.NewDataStoreReqGetInfo()
if dataStorePrepareGetParam.DataID == 900000 {
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 = []*datastore.DataStoreKeyValue{}
pReqGetInfo.Size = uint32(objectSize)
pReqGetInfo.RootCA = []byte{}
pReqGetInfo.DataID = 900000
} else {
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 = []*datastore.DataStoreKeyValue{}
pReqGetInfo.Size = courseMetadata.Size
pReqGetInfo.RootCA = []byte{}
pReqGetInfo.DataID = dataStorePrepareGetParam.DataID
}
rmcResponseStream := nex.NewStreamOut(globals.NEXServer)
rmcResponseStream.WriteStructure(pReqGetInfo)
rmcResponseBody := rmcResponseStream.Bytes()
rmcResponse := nex.NewRMCResponse(datastore.ProtocolID, callID)
rmcResponse.SetSuccess(datastore.MethodPrepareGetObject, 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)
}

View File

@@ -1,100 +0,0 @@
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)
}

View File

@@ -1,36 +0,0 @@
package nex_datastore
import (
nex "github.com/PretendoNetwork/nex-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 []*datastore.DataStoreRatingTarget, params []*datastore.DataStoreRateObjectParam, transactional bool, fetchRatings bool) {
// TODO: complete this
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(datastore.ProtocolID, callID)
rmcResponse.SetSuccess(datastore.MethodRateObjects, 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)
}

View File

@@ -3,26 +3,62 @@ 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"
datastore_super_mario_maker_types "github.com/PretendoNetwork/nex-protocols-go/datastore/super-mario-maker/types"
datastore_db "github.com/PretendoNetwork/super-mario-maker-secure/database/datastore"
datastore_smm_db "github.com/PretendoNetwork/super-mario-maker-secure/database/datastore/super-mario-maker"
"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)
func AddToBufferQueues(err error, packet nex.PacketInterface, callID uint32, params []*datastore_super_mario_maker_types.BufferQueueParam, buffers [][]byte) uint32 {
if err != nil {
globals.Logger.Error(err.Error())
return nex.Errors.DataStore.Unknown
}
rmcResponseStream := nex.NewStreamOut(globals.NEXServer)
client := packet.Sender()
rmcResponseStream.WriteListUInt32LE(pResults)
pResults := make([]*nex.Result, 0)
// * The number of params and buffers CAN be allowed
// * to differ, though this doesn't appear to happen
// * in normal gameplay. In these cases, the real
// * server will just loop over smallest list and
// * ignore all other data in the larger list
iterations := min(len(params), len(buffers))
for i := 0; i < iterations; i++ {
param := params[i]
buffer := buffers[i]
if param.Slot == 0 {
objectInfo, errCode := datastore_db.GetObjectInfoByDataID(param.DataID)
if errCode != 0 {
return errCode
}
// * Objects with DataType 1 are "maker" objects. When adding
// * a buffer to slot 0 of a maker object, a course is being
// * added to that users "Starred Courses" list. The buffer
// * is the courses DataID saved as an 8 byte buffer. To
// * prevent people from adding courses to random users
// * "Starred Courses" lists, we have to verify the requesting
// * client owns the maker object
if objectInfo.DataType == 1 && objectInfo.OwnerID != client.PID() {
return nex.Errors.DataStore.PermissionDenied
}
}
errCode := datastore_smm_db.InsertOrUpdateBufferQueueData(param.DataID, param.Slot, buffer)
if errCode != 0 {
return errCode
}
pResults = append(pResults, nex.NewResultSuccess(nex.Errors.Core.Unknown)) // * Seems to ALWAYS be a success?
}
rmcResponseStream := nex.NewStreamOut(globals.SecureServer)
rmcResponseStream.WriteListResult(pResults)
rmcResponseBody := rmcResponseStream.Bytes()
@@ -42,5 +78,7 @@ func AddToBufferQueues(err error, client *nex.Client, callID uint32, params []*d
responsePacket.AddFlag(nex.FlagNeedsAck)
responsePacket.AddFlag(nex.FlagReliable)
globals.NEXServer.Send(responsePacket)
globals.SecureServer.Send(responsePacket)
return 0
}

View File

@@ -1,26 +1,33 @@
package nex_datastore_super_mario_maker
import (
"fmt"
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/globals"
)
func CheckRateCustomRankingCounter(err error, client *nex.Client, callID uint32, applicationID uint32) {
var isBelowThreshold uint8
switch applicationID {
case 0: // unknown
isBelowThreshold = 1
default:
fmt.Printf("[Warning] DataStoreSMMProtocol::CheckRateCustomRankingCounter Unsupported applicationID: %v\n", applicationID)
func CheckRateCustomRankingCounter(err error, packet nex.PacketInterface, callID uint32, applicationID uint32) uint32 {
if err != nil {
globals.Logger.Error(err.Error())
return nex.Errors.DataStore.Unknown
}
rmcResponseStream := nex.NewStreamOut(globals.NEXServer)
client := packet.Sender()
rmcResponseStream.WriteUInt8(isBelowThreshold)
// * No idea what this is. Only seen application ID 0
// * used, and it's always true? Unsure what this checks
isBelowThreshold := false
switch applicationID {
case 0: // * Unknown
isBelowThreshold = true
default:
globals.Logger.Warningf("Unsupported applicationID: %d", applicationID)
}
rmcResponseStream := nex.NewStreamOut(globals.SecureServer)
rmcResponseStream.WriteBool(isBelowThreshold)
rmcResponseBody := rmcResponseStream.Bytes()
@@ -40,5 +47,7 @@ func CheckRateCustomRankingCounter(err error, client *nex.Client, callID uint32,
responsePacket.AddFlag(nex.FlagNeedsAck)
responsePacket.AddFlag(nex.FlagReliable)
globals.NEXServer.Send(responsePacket)
globals.SecureServer.Send(responsePacket)
return 0
}

View File

@@ -3,19 +3,61 @@ package nex_datastore_super_mario_maker
import (
"fmt"
"os"
"time"
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"
datastore_types "github.com/PretendoNetwork/nex-protocols-go/datastore/types"
datastore_db "github.com/PretendoNetwork/super-mario-maker-secure/database/datastore"
"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)
func CompleteAttachFile(err error, packet nex.PacketInterface, callID uint32, param *datastore_types.DataStoreCompletePostParam) uint32 {
if err != nil {
globals.Logger.Error(err.Error())
return nex.Errors.DataStore.Unknown
}
// TODO: complete this
client := packet.Sender()
rmcResponseStream.WriteString(fmt.Sprintf("http://%s.b-cdn.net/image/%d.jpg", os.Getenv("S3_BUCKET_NAME"), dataStoreCompletePostParam.DataID))
// TODO - What is param.IsSuccess? Is this correct?
if !param.IsSuccess {
return nex.Errors.DataStore.InvalidArgument
}
bucket := os.Getenv("PN_SMM_CONFIG_S3_BUCKET")
key := fmt.Sprintf("%d.jpg", param.DataID)
objectSizeS3, err := globals.S3ObjectSize(bucket, key)
if err != nil {
globals.Logger.Error(err.Error())
return nex.Errors.DataStore.NotFound
}
objectSizeDB, errCode := datastore_db.GetObjectSizeDataID(param.DataID)
if errCode != 0 {
return errCode
}
if objectSizeS3 != uint64(objectSizeDB) {
// TODO - Is this a good error?
return nex.Errors.DataStore.Unknown
}
errCode = datastore_db.UpdateObjectUploadCompletedByDataID(param.DataID, true)
if errCode != 0 {
return errCode
}
pURL, err := globals.Presigner.GetObject(bucket, key, time.Minute*15)
if err != nil {
globals.Logger.Error(err.Error())
return nex.Errors.DataStore.OperationNotAllowed
}
rmcResponseStream := nex.NewStreamOut(globals.SecureServer)
rmcResponseStream.WriteString(pURL.String())
rmcResponseBody := rmcResponseStream.Bytes()
@@ -35,5 +77,7 @@ func CompleteAttachFile(err error, client *nex.Client, callID uint32, dataStoreC
responsePacket.AddFlag(nex.FlagNeedsAck)
responsePacket.AddFlag(nex.FlagReliable)
globals.NEXServer.Send(responsePacket)
globals.SecureServer.Send(responsePacket)
return 0
}

View File

@@ -2,25 +2,41 @@ 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"
datastore_types "github.com/PretendoNetwork/nex-protocols-go/datastore/types"
datastore_smm_db "github.com/PretendoNetwork/super-mario-maker-secure/database/datastore/super-mario-maker"
"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))
func CTRPickUpCourseSearchObject(err error, packet nex.PacketInterface, callID uint32, param *datastore_types.DataStoreSearchParam, extraData []string) uint32 {
if err != nil {
globals.Logger.Error(err.Error())
return nex.Errors.DataStore.Unknown
}
rmcResponseStream := nex.NewStreamOut(globals.NEXServer)
client := packet.Sender()
// * This method is only used by the 3DS version
// * of Super Mario Maker and is functionally
// * identical to the WiiU versions
// * DataStoreSMM::RecommendedCourseSearchObject
// * method. The 3DS version LIKELY uses this as
// * a way to filter out courses which use the
// * Mystery Mushroom powerup, since it's not
// * officially supported by the 3DS version. That
// * said, the Mystery Mushroom IS still in the
// * game and can be used somewhat normally, so
// * no filtering is done here to prevent that.
// * I'm not even sure how we would detect that
// TODO - Research extraData
// TODO - Use the offet? Real client never uses it, but might be nice for completeness sake?
pRankingResults, errCode := datastore_smm_db.GetRandomCoursesWithLimit(int(param.ResultRange.Length))
if errCode != 0 {
return errCode
}
rmcResponseStream := nex.NewStreamOut(globals.SecureServer)
rmcResponseStream.WriteListStructure(pRankingResults)
@@ -42,5 +58,7 @@ func CTRPickUpCourseSearchObject(err error, client *nex.Client, callID uint32, d
responsePacket.AddFlag(nex.FlagNeedsAck)
responsePacket.AddFlag(nex.FlagReliable)
globals.NEXServer.Send(responsePacket)
globals.SecureServer.Send(responsePacket)
return 0
}

View File

@@ -2,25 +2,70 @@ 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"
datastore_super_mario_maker_types "github.com/PretendoNetwork/nex-protocols-go/datastore/super-mario-maker/types"
datastore_types "github.com/PretendoNetwork/nex-protocols-go/datastore/types"
datastore_smm_db "github.com/PretendoNetwork/super-mario-maker-secure/database/datastore/super-mario-maker"
"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)
func FollowingsLatestCourseSearchObject(err error, packet nex.PacketInterface, callID uint32, param *datastore_types.DataStoreSearchParam, extraData []string) uint32 {
if err != nil {
globals.Logger.Error(err.Error())
return nex.Errors.DataStore.Unknown
}
for _, pid := range dataStoreSearchParam.OwnerIds {
courseMetadatas := database.GetCourseMetadatasByPID(pid)
client := packet.Sender()
for _, courseMetadata := range courseMetadatas {
pRankingResults = append(pRankingResults, utility.CourseMetadataToDataStoreCustomRankingResult(courseMetadata))
pRankingResults := make([]*datastore_super_mario_maker_types.DataStoreCustomRankingResult, 0)
// * This seems to ONLY be used to get rankings for course objects
// * uploaded by the users in param.OwnerIDs? If param.ResultOption
// * contains the flag 0x20 ("return scores"), then the real server
// * does some kind of check over extraData. It's unknown what this
// * check is, so it's not done here. All other data in param seems
// * to be unused here.
for _, pid := range param.OwnerIDs {
courseObjectIDs, errCode := datastore_smm_db.GetUserCourseObjectIDs(pid)
if errCode != 0 {
return errCode
}
// * This method seems to always use slot 0?
results := datastore_smm_db.GetCustomRankingsByDataIDs(0, courseObjectIDs)
for _, rankingResult := range results {
// * This is kind of backwards.
// * The database pulls this data
// * by default, so it can be done
// * in a single query. So instead
// * of checking if a flag *IS*
// * set, and conditionally *ADDING*
// * the fields, we check if a flag
// * is *NOT* set and conditionally
// * *REMOVE* the field
if param.ResultOption&0x1 == 0 {
rankingResult.MetaInfo.Tags = make([]string, 0)
}
if param.ResultOption&0x2 == 0 {
rankingResult.MetaInfo.Ratings = make([]*datastore_types.DataStoreRatingInfoWithSlot, 0)
}
if param.ResultOption&0x4 == 0 {
rankingResult.MetaInfo.MetaBinary = make([]byte, 0)
}
// TODO - If this flag is set, extraData is checked somehow
if param.ResultOption&0x20 == 0 {
rankingResult.Score = 0
}
pRankingResults = append(pRankingResults, rankingResult)
}
}
rmcResponseStream := nex.NewStreamOut(globals.NEXServer)
rmcResponseStream := nex.NewStreamOut(globals.SecureServer)
rmcResponseStream.WriteListStructure(pRankingResults)
@@ -42,5 +87,7 @@ func FollowingsLatestCourseSearchObject(err error, client *nex.Client, callID ui
responsePacket.AddFlag(nex.FlagNeedsAck)
responsePacket.AddFlag(nex.FlagReliable)
globals.NEXServer.Send(responsePacket)
globals.SecureServer.Send(responsePacket)
return 0
}

View File

@@ -8,26 +8,38 @@ import (
"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
// * Nintendo sets this to 10 by default
// * and users earn more upload slots up
// * to 100.
// * This is a stupid, unfun, mechanic so
// * everyone gets 100 by default. Can be
// * more, but 100 is fine tbh
var MAX_COURSE_UPLOADS uint32 = 100
func GetApplicationConfig(err error, client *nex.Client, callID uint32, applicationID uint32) {
func GetApplicationConfig(err error, packet nex.PacketInterface, callID uint32, applicationID uint32) uint32 {
if err != nil {
globals.Logger.Error(err.Error())
return nex.Errors.DataStore.Unknown
}
client := packet.Sender()
config := make([]uint32, 0)
switch applicationID {
case 0: // Unknown?
config = getApplicationConfig_Unknown0()
case 1: // Official player PIDs
config = getApplicationConfig_OfficialPlayers()
case 2: // Unknown?
case 0: // * Player config?
config = getApplicationConfig_PlayerConfig()
case 1: // * PIDs of the "Official" makers in the "MAKERS" section
config = getApplicationConfig_OfficialMakers()
case 2: // * Unknown
config = getApplicationConfig_Unknown2()
case 10: // Unknown?
case 10: // * Unknown
config = getApplicationConfig_Unknown10()
default:
fmt.Printf("[Warning] DataStoreSMMProtocol::GetApplicationConfig Unsupported applicationID: %v\n", applicationID)
}
rmcResponseStream := nex.NewStreamOut(globals.NEXServer)
rmcResponseStream := nex.NewStreamOut(globals.SecureServer)
rmcResponseStream.WriteListUInt32LE(config)
@@ -49,12 +61,17 @@ func GetApplicationConfig(err error, client *nex.Client, callID uint32, applicat
responsePacket.AddFlag(nex.FlagNeedsAck)
responsePacket.AddFlag(nex.FlagReliable)
globals.NEXServer.Send(responsePacket)
globals.SecureServer.Send(responsePacket)
return 0
}
func getApplicationConfig_Unknown0() []uint32 {
// I have no idea what this is
// Just replaying data sent from the real server
func getApplicationConfig_PlayerConfig() []uint32 {
// * This seems to be per-user configuration
// * settings, based on the fact that the
// * number of max uploads a user can do is
// * sent here. No idea what anything else
// * means
return []uint32{
0x01000000, 0x32000000, 0x96000000, 0x2c010000, 0xf4010000,
0x20030000, 0x14050000, 0xd0070000, 0xb80b0000, 0x88130000,
@@ -67,29 +84,30 @@ func getApplicationConfig_Unknown0() []uint32 {
}
}
func getApplicationConfig_OfficialPlayers() []uint32 {
func getApplicationConfig_OfficialMakers() []uint32 {
// * Used as the PIDs for the "Official" makers in the "MAKERS" section
return []uint32{
0x02000000, // 2 (not a real user PID, this translates to the internal Quazal Rendez-Vous user used by NEX)
0x70cc8269, // 1770179696 (official_player0 on NN, need to make PN versions)
0x50cc8269, // 1770179664 (official_player1 on NN, need to make PN versions)
0x38cc8269, // 1770179640 (official_player2 on NN, need to make PN versions)
0xdbd08269, // 1770180827 (official_player3 on NN, need to make PN versions)
0xa9d08269, // 1770180777 (official_player4 on NN, need to make PN versions)
0x89d08269, // 1770180745 (official_player5 on NN, need to make PN versions)
0x59c48269, // 1770177625 (official_player6 on NN, need to make PN versions)
0x36c48269, // 1770177590 (official_player7 on NN, need to make PN versions)
0x02000000, // * 2 (not a real user PID, this translates to the internal Quazal Rendez-Vous user used by NEX)
0x70cc8269, // * 1770179696 (official_player0 on NN, need to make PN versions)
0x50cc8269, // * 1770179664 (official_player1 on NN, need to make PN versions)
0x38cc8269, // * 1770179640 (official_player2 on NN, need to make PN versions)
0xdbd08269, // * 1770180827 (official_player3 on NN, need to make PN versions)
0xa9d08269, // * 1770180777 (official_player4 on NN, need to make PN versions)
0x89d08269, // * 1770180745 (official_player5 on NN, need to make PN versions)
0x59c48269, // * 1770177625 (official_player6 on NN, need to make PN versions)
0x36c48269, // * 1770177590 (official_player7 on NN, need to make PN versions)
}
}
func getApplicationConfig_Unknown2() []uint32 {
// I have no idea what this is
// Just replaying data sent from the real server
// * I have no idea what this is
// * Just replaying data sent from the real server
return []uint32{0xdf070000, 0x0c000000, 0x16000000, 0x05000000, 0x00000000}
}
func getApplicationConfig_Unknown10() []uint32 {
// I have no idea what this is
// Just replaying data sent from the real server
// Only seen on the 3DS
// * I have no idea what this is
// * Just replaying data sent from the real server
// * Only seen on the 3DS
return []uint32{35, 75, 96, 40, 5, 6}
}

View File

@@ -8,8 +8,15 @@ import (
"github.com/PretendoNetwork/super-mario-maker-secure/globals"
)
func GetApplicationConfigString(err error, client *nex.Client, callID uint32, applicationID uint32) {
// Word blacklists?
func GetApplicationConfigString(err error, packet nex.PacketInterface, callID uint32, applicationID uint32) uint32 {
if err != nil {
globals.Logger.Error(err.Error())
return nex.Errors.DataStore.Unknown
}
client := packet.Sender()
// * Word blacklists?
config := make([]string, 0)
switch applicationID {
@@ -23,7 +30,7 @@ func GetApplicationConfigString(err error, client *nex.Client, callID uint32, ap
fmt.Printf("[Warning] DataStoreSMMProtocol::GetApplicationConfigString Unsupported applicationID: %v\n", applicationID)
}
rmcResponseStream := nex.NewStreamOut(globals.NEXServer)
rmcResponseStream := nex.NewStreamOut(globals.SecureServer)
rmcResponseStream.WriteListString(config)
@@ -45,11 +52,14 @@ func GetApplicationConfigString(err error, client *nex.Client, callID uint32, ap
responsePacket.AddFlag(nex.FlagNeedsAck)
responsePacket.AddFlag(nex.FlagReliable)
globals.NEXServer.Send(responsePacket)
globals.SecureServer.Send(responsePacket)
return 0
}
func getApplicationConfigString_WordBlacklist1() []string {
// Just replaying data sent from Nintendo's servers
// * Just replaying data sent from Nintendo's servers
// * Please no cancel for swears/slurs ;-;
return []string{
"けされ", "消され", "削除され", "リセットされ",
"BANされ", "BANされ", "キミのコース", "君のコース",
@@ -72,14 +82,16 @@ func getApplicationConfigString_WordBlacklist1() []string {
}
func getApplicationConfigString_WordBlacklist2() []string {
// Just replaying data sent from Nintendo's servers
// * Just replaying data sent from Nintendo's servers
// * Please no cancel for swears/slurs ;-;
return []string{
"ゼロから", "0から", "0から", "い  い  ね", "いい", "東日本", "大震",
}
}
func getApplicationConfigString_WordBlacklist3() []string {
// Just replaying data sent from Nintendo's servers
// * Just replaying data sent from Nintendo's servers
// * Please no cancel for swears/slurs ;-;
return []string{
"いいね", "下さい", "ください",
"押して", "おして", "返す",

View File

@@ -1,30 +1,28 @@
package nex_datastore_super_mario_maker
import (
"fmt"
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"
datastore_super_mario_maker_types "github.com/PretendoNetwork/nex-protocols-go/datastore/super-mario-maker/types"
datastore_smm_db "github.com/PretendoNetwork/super-mario-maker-secure/database/datastore/super-mario-maker"
"github.com/PretendoNetwork/super-mario-maker-secure/globals"
)
func GetBufferQueue(err error, client *nex.Client, callID uint32, param *datastore_super_mario_maker.BufferQueueParam) {
// TODO: complete this
rmcResponseStream := nex.NewStreamOut(globals.NEXServer)
var pBufferQueue [][]byte
switch param.Slot {
case 0: // unknown
pBufferQueue = make([][]byte, 0)
case 3: // death data
pBufferQueue = database.GetBufferQueueDeathData(param.DataID)
default:
fmt.Printf("[Warning] DataStoreSMMProtocol::GetBufferQueue Unsupported slot: %v\n", param.Slot)
func GetBufferQueue(err error, packet nex.PacketInterface, callID uint32, param *datastore_super_mario_maker_types.BufferQueueParam) uint32 {
if err != nil {
globals.Logger.Error(err.Error())
return nex.Errors.DataStore.Unknown
}
client := packet.Sender()
pBufferQueue, errCode := datastore_smm_db.GetBufferQueuesByDataIDAndSlot(param.DataID, param.Slot)
if errCode != 0 {
globals.Logger.Errorf("Error code %d for object %d", errCode, param.DataID)
return errCode
}
rmcResponseStream := nex.NewStreamOut(globals.SecureServer)
rmcResponseStream.WriteListQBuffer(pBufferQueue)
rmcResponseBody := rmcResponseStream.Bytes()
@@ -45,5 +43,7 @@ func GetBufferQueue(err error, client *nex.Client, callID uint32, param *datasto
responsePacket.AddFlag(nex.FlagNeedsAck)
responsePacket.AddFlag(nex.FlagReliable)
globals.NEXServer.Send(responsePacket)
globals.SecureServer.Send(responsePacket)
return 0
}

View File

@@ -3,34 +3,32 @@ 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"
datastore_super_mario_maker_types "github.com/PretendoNetwork/nex-protocols-go/datastore/super-mario-maker/types"
datastore_smm_db "github.com/PretendoNetwork/super-mario-maker-secure/database/datastore/super-mario-maker"
"github.com/PretendoNetwork/super-mario-maker-secure/globals"
)
func GetCourseRecord(err error, client *nex.Client, callID uint32, param *datastore_super_mario_maker.DataStoreGetCourseRecordParam) {
worldRecord := database.GetCourseWorldRecord(param.DataID)
func GetCourseRecord(err error, packet nex.PacketInterface, callID uint32, param *datastore_super_mario_maker_types.DataStoreGetCourseRecordParam) uint32 {
if err != nil {
globals.Logger.Error(err.Error())
return nex.Errors.DataStore.Unknown
}
client := packet.Sender()
result, errCode := datastore_smm_db.GetCourseRecordByDataIDAndSlot(param.DataID, param.Slot)
if errCode != 0 {
return errCode
}
rmcResponseStream := nex.NewStreamOut(globals.SecureServer)
rmcResponseStream.WriteStructure(result)
rmcResponseBody := rmcResponseStream.Bytes()
rmcResponse := nex.NewRMCResponse(datastore_super_mario_maker.ProtocolID, callID)
if worldRecord == nil {
rmcResponse.SetError(0x690004)
} else {
result := datastore_super_mario_maker.NewDataStoreGetCourseRecordResult()
result.DataID = param.DataID
result.Slot = param.Slot
result.FirstPID = worldRecord.FirstPID
result.BestPID = worldRecord.BestPID
result.BestScore = worldRecord.Score
result.CreatedTime = worldRecord.CreatedTime
result.UpdatedTime = worldRecord.UpdatedTime
rmcResponseStream := nex.NewStreamOut(globals.NEXServer)
rmcResponseStream.WriteStructure(result)
rmcResponseBody := rmcResponseStream.Bytes()
rmcResponse.SetSuccess(datastore_super_mario_maker.MethodGetCourseRecord, rmcResponseBody)
}
rmcResponse.SetSuccess(datastore_super_mario_maker.MethodGetCourseRecord, rmcResponseBody)
rmcResponseBytes := rmcResponse.Bytes()
@@ -45,5 +43,7 @@ func GetCourseRecord(err error, client *nex.Client, callID uint32, param *datast
responsePacket.AddFlag(nex.FlagNeedsAck)
responsePacket.AddFlag(nex.FlagReliable)
globals.NEXServer.Send(responsePacket)
globals.SecureServer.Send(responsePacket)
return 0
}

View File

@@ -3,37 +3,64 @@ 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"
datastore_super_mario_maker_types "github.com/PretendoNetwork/nex-protocols-go/datastore/super-mario-maker/types"
datastore_types "github.com/PretendoNetwork/nex-protocols-go/datastore/types"
datastore_smm_db "github.com/PretendoNetwork/super-mario-maker-secure/database/datastore/super-mario-maker"
"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)
func GetCustomRankingByDataID(err error, packet nex.PacketInterface, callID uint32, param *datastore_super_mario_maker_types.DataStoreGetCustomRankingByDataIDParam) uint32 {
if err != nil {
globals.Logger.Error(err.Error())
return nex.Errors.DataStore.Unknown
}
rmcResponseStream := nex.NewStreamOut(globals.NEXServer)
client := packet.Sender()
pRankingResult := datastore_smm_db.GetCustomRankingsByDataIDs(param.ApplicationID, param.DataIDList)
pResults := make([]*nex.Result, 0, len(param.DataIDList))
for _, rankingResult := range pRankingResult {
// * This is kind of backwards.
// * The database pulls this data
// * by default, so it can be done
// * in a single query. So instead
// * of checking if a flag *IS*
// * set, and conditionally *ADDING*
// * the fields, we check if a flag
// * is *NOT* set and conditionally
// * *REMOVE* the field
if param.ResultOption&0x1 == 0 {
rankingResult.MetaInfo.Tags = make([]string, 0)
}
if param.ResultOption&0x2 == 0 {
rankingResult.MetaInfo.Ratings = make([]*datastore_types.DataStoreRatingInfoWithSlot, 0)
}
if param.ResultOption&0x4 == 0 {
rankingResult.MetaInfo.MetaBinary = make([]byte, 0)
}
if param.ResultOption&0x20 == 0 {
rankingResult.Score = 0
}
// * Since all errors are thrown away in
// * datastore_smm_db.GetCustomRankingsByDataIDs
// * assume all objects returned were a success
pResults = append(pResults, nex.NewResultSuccess(nex.Errors.Core.Unknown))
}
rmcResponseStream := nex.NewStreamOut(globals.SecureServer)
rmcResponseStream.WriteListStructure(pRankingResult)
rmcResponseStream.WriteListUInt32LE(pResults)
rmcResponseStream.WriteListResult(pResults)
rmcResponseBody := rmcResponseStream.Bytes()
rmcResponse := nex.NewRMCResponse(datastore_super_mario_maker.ProtocolID, callID)
rmcResponse.SetSuccess(datastore_super_mario_maker.MethodGetCustomRankingByDataId, rmcResponseBody)
rmcResponse.SetSuccess(datastore_super_mario_maker.MethodGetCustomRankingByDataID, rmcResponseBody)
rmcResponseBytes := rmcResponse.Bytes()
@@ -48,50 +75,7 @@ func GetCustomRankingByDataId(err error, client *nex.Client, callID uint32, para
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
globals.SecureServer.Send(responsePacket)
return 0
}

View File

@@ -6,18 +6,29 @@ import (
"github.com/PretendoNetwork/super-mario-maker-secure/globals"
)
func GetDeletionReason(err error, client *nex.Client, callID uint32, dataIdLst []uint64) {
// TODO: Complete this
pDeletionReasons := make([]uint32, 0)
for range dataIdLst {
// We don't need the values right now
// stub this
pDeletionReasons = append(pDeletionReasons, 0x690007)
func GetDeletionReason(err error, packet nex.PacketInterface, callID uint32, dataIDLst []uint64) uint32 {
if err != nil {
globals.Logger.Error(err.Error())
return nex.Errors.DataStore.Unknown
}
rmcResponseStream := nex.NewStreamOut(globals.NEXServer)
client := packet.Sender()
// TODO - Complete this
// * It's not actually known what the
// * real "deletion reason" values are.
// * This is stubbed until we figure
// * that out
pDeletionReasons := make([]uint32, 0)
for range dataIDLst {
// * Every course I've checked has had this
// * set to 0, even if the course is not
// * deleted
pDeletionReasons = append(pDeletionReasons, 0)
}
rmcResponseStream := nex.NewStreamOut(globals.SecureServer)
rmcResponseStream.WriteListUInt32LE(pDeletionReasons)
@@ -39,5 +50,7 @@ func GetDeletionReason(err error, client *nex.Client, callID uint32, dataIdLst [
responsePacket.AddFlag(nex.FlagNeedsAck)
responsePacket.AddFlag(nex.FlagReliable)
globals.NEXServer.Send(responsePacket)
globals.SecureServer.Send(responsePacket)
return 0
}

View File

@@ -2,19 +2,140 @@ 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"
datastore_super_mario_maker_types "github.com/PretendoNetwork/nex-protocols-go/datastore/super-mario-maker/types"
datastore_types "github.com/PretendoNetwork/nex-protocols-go/datastore/types"
datastore_db "github.com/PretendoNetwork/super-mario-maker-secure/database/datastore"
datastore_smm_db "github.com/PretendoNetwork/super-mario-maker-secure/database/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
func GetMetasWithCourseRecord(err error, packet nex.PacketInterface, callID uint32, params []*datastore_super_mario_maker_types.DataStoreGetCourseRecordParam, metaParam *datastore_types.DataStoreGetMetaParam) uint32 {
if err != nil {
globals.Logger.Error(err.Error())
return nex.Errors.DataStore.Unknown
}
rmcResponseStream := nex.NewStreamOut(globals.NEXServer)
client := packet.Sender()
rmcResponseStream.WriteUInt32LE(0x00000000) // pMetaInfo List length 0
rmcResponseStream.WriteUInt32LE(0x00000000) // pCourseResults List length 0
rmcResponseStream.WriteUInt32LE(0x00000000) // pResults List length 0
// * The functionality here is largely a guess
// * based on how GetCourseRecord works and
// * based on testing with a custom client.
// * During normal gameplay this method never
// * seems to send any parameters, though if a
// * custom client is used it IS functional
pMetaInfo := make([]*datastore_types.DataStoreMetaInfo, 0, len(params))
pCourseResults := make([]*datastore_super_mario_maker_types.DataStoreGetCourseRecordResult, 0, len(params))
pResults := make([]*nex.Result, 0, len(params))
for _, param := range params {
// * metaParam has a password, but it's always set to 0.
// * It also wouldn't make much sense for the same password
// * to be used for all objects being requested here. So
// * just assume metaParam is ONLY used for the resultOption
// * field?
objectInfo, errCode := datastore_db.GetObjectInfoByDataID(param.DataID)
if errCode != 0 {
// TODO - Maybe this should be broken out into a util function in globals?
objectInfo = datastore_types.NewDataStoreMetaInfo()
objectInfo.DataID = 0
objectInfo.OwnerID = 0
objectInfo.Size = 0
objectInfo.Name = ""
objectInfo.DataType = 0
objectInfo.MetaBinary = []byte{}
objectInfo.Permission = datastore_types.NewDataStorePermission()
objectInfo.Permission.Permission = 0
objectInfo.Permission.RecipientIDs = []uint32{}
objectInfo.DelPermission = datastore_types.NewDataStorePermission()
objectInfo.DelPermission.Permission = 0
objectInfo.DelPermission.RecipientIDs = []uint32{}
objectInfo.CreatedTime = nex.NewDateTime(0)
objectInfo.UpdatedTime = nex.NewDateTime(0)
objectInfo.Period = 0
objectInfo.Status = 0
objectInfo.ReferredCnt = 0
objectInfo.ReferDataID = 0
objectInfo.Flag = 0
objectInfo.ReferredTime = nex.NewDateTime(0)
objectInfo.ExpireTime = nex.NewDateTime(0)
objectInfo.Tags = []string{}
objectInfo.Ratings = []*datastore_types.DataStoreRatingInfoWithSlot{}
} else {
errCode = globals.VerifyObjectPermission(objectInfo.OwnerID, client.PID(), objectInfo.Permission)
if errCode != 0 {
objectInfo = datastore_types.NewDataStoreMetaInfo()
objectInfo.DataID = 0
objectInfo.OwnerID = 0
objectInfo.Size = 0
objectInfo.Name = ""
objectInfo.DataType = 0
objectInfo.MetaBinary = []byte{}
objectInfo.Permission = datastore_types.NewDataStorePermission()
objectInfo.Permission.Permission = 0
objectInfo.Permission.RecipientIDs = []uint32{}
objectInfo.DelPermission = datastore_types.NewDataStorePermission()
objectInfo.DelPermission.Permission = 0
objectInfo.DelPermission.RecipientIDs = []uint32{}
objectInfo.CreatedTime = nex.NewDateTime(0)
objectInfo.UpdatedTime = nex.NewDateTime(0)
objectInfo.Period = 0
objectInfo.Status = 0
objectInfo.ReferredCnt = 0
objectInfo.ReferDataID = 0
objectInfo.Flag = 0
objectInfo.ReferredTime = nex.NewDateTime(0)
objectInfo.ExpireTime = nex.NewDateTime(0)
objectInfo.Tags = []string{}
objectInfo.Ratings = []*datastore_types.DataStoreRatingInfoWithSlot{}
}
// * This is kind of backwards.
// * The database pulls this data
// * by default, so it can be done
// * in a single query. So instead
// * of checking if a flag *IS*
// * set, and conditionally *ADDING*
// * the fields, we check if a flag
// * is *NOT* set and conditionally
// * *REMOVE* the field
if metaParam.ResultOption&0x1 == 0 {
objectInfo.Tags = make([]string, 0)
}
if metaParam.ResultOption&0x2 == 0 {
objectInfo.Ratings = make([]*datastore_types.DataStoreRatingInfoWithSlot, 0)
}
if metaParam.ResultOption&0x4 == 0 {
objectInfo.MetaBinary = make([]byte, 0)
}
}
// * Ignore errors, real server sends empty struct if can't be found
courseRecord, errCode := datastore_smm_db.GetCourseRecordByDataIDAndSlot(param.DataID, param.Slot)
if errCode != 0 || objectInfo.DataID == 0 { // * DataID == 0 means could not be found or accessed
courseRecord = datastore_super_mario_maker_types.NewDataStoreGetCourseRecordResult()
courseRecord.DataID = 0
courseRecord.Slot = 0
courseRecord.FirstPID = 0
courseRecord.BestPID = 0
courseRecord.BestScore = 0
courseRecord.CreatedTime = nex.NewDateTime(0)
courseRecord.UpdatedTime = nex.NewDateTime(0)
}
pMetaInfo = append(pMetaInfo, objectInfo)
pCourseResults = append(pCourseResults, courseRecord)
pResults = append(pResults, nex.NewResultSuccess(nex.Errors.Core.Unknown)) // * Real server ALWAYS returns a success
}
rmcResponseStream := nex.NewStreamOut(globals.SecureServer)
rmcResponseStream.WriteListStructure(pMetaInfo)
rmcResponseStream.WriteListStructure(pCourseResults)
rmcResponseStream.WriteListResult(pResults)
rmcResponseBody := rmcResponseStream.Bytes()
@@ -34,5 +155,7 @@ func GetMetasWithCourseRecord(err error, client *nex.Client, callID uint32, data
responsePacket.AddFlag(nex.FlagNeedsAck)
responsePacket.AddFlag(nex.FlagReliable)
globals.NEXServer.Send(responsePacket)
globals.SecureServer.Send(responsePacket)
return 0
}

View File

@@ -3,33 +3,54 @@ package nex_datastore_super_mario_maker
import (
"fmt"
"os"
"time"
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"
datastore_super_mario_maker_types "github.com/PretendoNetwork/nex-protocols-go/datastore/super-mario-maker/types"
datastore_types "github.com/PretendoNetwork/nex-protocols-go/datastore/types"
datastore_db "github.com/PretendoNetwork/super-mario-maker-secure/database/datastore"
"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)
func GetObjectInfos(err error, packet nex.PacketInterface, callID uint32, dataIDs []uint64) uint32 {
if err != nil {
globals.Logger.Error(err.Error())
return nex.Errors.DataStore.Unknown
}
courseMetadatas := database.GetCourseMetadataByDataIDs(dataIDs)
client := packet.Sender()
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 := make([]*datastore_super_mario_maker_types.DataStoreFileServerObjectInfo, 0)
for _, dataID := range dataIDs {
objectInfo, errCode := datastore_db.GetObjectInfoByDataID(dataID)
if errCode != 0 {
return errCode
}
bucket := os.Getenv("PN_SMM_CONFIG_S3_BUCKET")
key := fmt.Sprintf("%d.bin", objectInfo.DataID)
URL, err := globals.Presigner.GetObject(bucket, key, time.Minute*15)
if err != nil {
globals.Logger.Error(err.Error())
return nex.Errors.DataStore.OperationNotAllowed
}
info := datastore_super_mario_maker_types.NewDataStoreFileServerObjectInfo()
info.DataID = objectInfo.DataID
info.GetInfo = datastore_types.NewDataStoreReqGetInfo()
info.GetInfo.URL = URL.String()
info.GetInfo.RequestHeaders = []*datastore_types.DataStoreKeyValue{}
info.GetInfo.Size = objectInfo.Size
info.GetInfo.RootCACert = []byte{}
info.GetInfo.DataID = objectInfo.DataID
pInfos = append(pInfos, info)
}
rmcResponseStream := nex.NewStreamOut(globals.NEXServer)
rmcResponseStream := nex.NewStreamOut(globals.SecureServer)
rmcResponseStream.WriteListStructure(pInfos)
@@ -51,5 +72,7 @@ func GetObjectInfos(err error, client *nex.Client, callID uint32, dataIDs []uint
responsePacket.AddFlag(nex.FlagNeedsAck)
responsePacket.AddFlag(nex.FlagReliable)
globals.NEXServer.Send(responsePacket)
globals.SecureServer.Send(responsePacket)
return 0
}

View File

@@ -1,71 +1,75 @@
package nex_datastore_super_mario_maker
import (
"crypto/hmac"
"crypto/sha256"
"encoding/hex"
"fmt"
"os"
"strconv"
"time"
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"
datastore_super_mario_maker_types "github.com/PretendoNetwork/nex-protocols-go/datastore/super-mario-maker/types"
datastore_types "github.com/PretendoNetwork/nex-protocols-go/datastore/types"
datastore_db "github.com/PretendoNetwork/super-mario-maker-secure/database/datastore"
datastore_smm_db "github.com/PretendoNetwork/super-mario-maker-secure/database/datastore/super-mario-maker"
"github.com/PretendoNetwork/super-mario-maker-secure/globals"
)
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()))
pid := strconv.Itoa(int(client.PID()))
func PrepareAttachFile(err error, packet nex.PacketInterface, callID uint32, param *datastore_super_mario_maker_types.DataStoreAttachFileParam) uint32 {
if err != nil {
globals.Logger.Error(err.Error())
return nex.Errors.DataStore.Unknown
}
data := pid + bucket + key + date
client := packet.Sender()
hmac := hmac.New(sha256.New, globals.HMACSecret)
hmac.Write([]byte(data))
// * This method seems to be only used at "attach"
// * a file to an existing object. In practice,
// * SMM will use this to upload a courses preview
// * image after uploading the course.
// * param.ReferDataID is the courses object DataID
signature := hex.EncodeToString(hmac.Sum(nil))
dataID, errCode := datastore_smm_db.InitializeObjectByAttachFileParam(client.PID(), param)
if errCode != 0 {
globals.Logger.Errorf("Error code %d on object init", errCode)
return errCode
}
fieldBucket := datastore.NewDataStoreKeyValue()
fieldBucket.Key = "bucket"
fieldBucket.Value = bucket
// TODO - Should this be moved to InitializeObjectByAttachFileParam?
// * This never seems to have any values during normal gameplay,
// * but just in case
for _, ratingInitParamWithSlot := range param.PostParam.RatingInitParams {
errCode = datastore_db.InitializeObjectRatingWithSlot(dataID, ratingInitParamWithSlot)
if errCode != 0 {
globals.Logger.Errorf("Error code %d on rating init", errCode)
return errCode
}
}
fieldKey := datastore.NewDataStoreKeyValue()
fieldKey.Key = "key"
fieldKey.Value = key
// TODO - Check param.ContentType? Always seems to be "image/jpeg" but just in case?
bucket := os.Getenv("PN_SMM_CONFIG_S3_BUCKET")
key := fmt.Sprintf("%d.jpg", dataID)
fieldACL := datastore.NewDataStoreKeyValue()
fieldACL.Key = "acl"
fieldACL.Value = "public-read"
// TODO - Should this also take in the param.ContentType? To add it to the policy?
URL, formData, _ := globals.Presigner.PostObject(bucket, key, time.Minute*15)
fieldContentType := datastore.NewDataStoreKeyValue()
fieldContentType.Key = "content-type"
fieldContentType.Value = "image/jpeg"
pReqPostInfo := datastore_types.NewDataStoreReqPostInfo()
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 = dataStoreAttachFileParam.ReferDataID
pReqPostInfo.URL = os.Getenv("DATASTORE_UPLOAD_URL")
pReqPostInfo.RequestHeaders = []*datastore.DataStoreKeyValue{}
pReqPostInfo.FormFields = []*datastore.DataStoreKeyValue{fieldBucket, fieldKey, fieldACL, fieldContentType, fieldPID, fieldDate, fieldSignature}
pReqPostInfo.DataID = dataID
pReqPostInfo.URL = URL.String()
pReqPostInfo.RequestHeaders = []*datastore_types.DataStoreKeyValue{}
pReqPostInfo.FormFields = make([]*datastore_types.DataStoreKeyValue, 0, len(formData))
pReqPostInfo.RootCACert = []byte{}
for key, value := range formData {
field := datastore_types.NewDataStoreKeyValue()
field.Key = key
field.Value = value
pReqPostInfo.FormFields = append(pReqPostInfo.FormFields, field)
}
rmcResponseStream := nex.NewStreamOut(globals.SecureServer)
rmcResponseStream.WriteStructure(pReqPostInfo)
rmcResponseBody := rmcResponseStream.Bytes()
@@ -86,5 +90,7 @@ func PrepareAttachFile(err error, client *nex.Client, callID uint32, dataStoreAt
responsePacket.AddFlag(nex.FlagNeedsAck)
responsePacket.AddFlag(nex.FlagReliable)
globals.NEXServer.Send(responsePacket)
globals.SecureServer.Send(responsePacket)
return 0
}

View File

@@ -3,92 +3,22 @@ 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"
datastore_super_mario_maker_types "github.com/PretendoNetwork/nex-protocols-go/datastore/super-mario-maker/types"
datastore_smm_db "github.com/PretendoNetwork/super-mario-maker-secure/database/datastore/super-mario-maker"
"github.com/PretendoNetwork/super-mario-maker-secure/globals"
)
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.
This method sends a set number of DataStoreRateCustomRankingParam's in the params list depending
on what action the user does.
- Course upload: 4 params
- DataStoreRateCustomRankingParam.dataId is always the course ID
- DataStoreRateCustomRankingParam.score is always 0
- DataStoreRateCustomRankingParam.period is always 36500
- DataStoreRateCustomRankingParam.applicationId is:
- 0 (seen in other requests relating to Mii data?)
- 2400
- 200000000
- 200002400
- Course clear: 2 params
- DataStoreRateCustomRankingParam.dataId is always the course ID
- DataStoreRateCustomRankingParam.score is always 1
- DataStoreRateCustomRankingParam.period is always 36500
- DataStoreRateCustomRankingParam.applicationId is:
- 200000000
- 200002400
- Course star: 12 params
- DataStoreRateCustomRankingParam.dataId is:
- course ID
- course ID
- course ID
- course ID
- course ID
- course ID
- uploader PID
- uploader PID
- uploader PID
- uploader PID
- uploader PID
- uploader PID
- DataStoreRateCustomRankingParam.score is always 1
- DataStoreRateCustomRankingParam.period is:
- 36500
- 36500
- 1
- 1
- 1
- 1
- 36500
- 36500
- 1
- 1
- 1
- 1
- DataStoreRateCustomRankingParam.applicationId is:
- 0 (seen in other requests relating to Mii data?)
- 2400
- 119700101
- 119702501
- 1497730516
- 1497732916
- 300000000 (seen in other requests relating to Mii data?)
- 300002400
- 419700101
- 419702501
- 1797730516
- 1797732916
It seems like many applicationId's are actually a different ID with 2400 added to it?
Since it always sends a set number of params per action, a quick and dirty way to tell them apart is
to check the param list length. However this should NOT be relied on forever and we NEED to learn more
about applicationId, as it IS used in many other requests
*/
if len(params) == 2 {
// assume "course clear" action
database.IncrementCourseClearCount(params[0].DataID)
func RateCustomRanking(err error, packet nex.PacketInterface, callID uint32, params []*datastore_super_mario_maker_types.DataStoreRateCustomRankingParam) uint32 {
if err != nil {
globals.Logger.Error(err.Error())
return nex.Errors.DataStore.Unknown
}
if len(params) == 12 {
// assume "star course" action
database.IncrementCourseStarCount(params[0].DataID)
client := packet.Sender()
// TODO - Check the period. The real server does check this, just unsure what it means or what the check is
for _, param := range params {
datastore_smm_db.InsertOrUpdateCustomRanking(param.DataID, param.ApplicationID, param.Score)
}
rmcResponse := nex.NewRMCResponse(datastore_super_mario_maker.ProtocolID, callID)
@@ -107,5 +37,7 @@ func RateCustomRanking(err error, client *nex.Client, callID uint32, params []*d
responsePacket.AddFlag(nex.FlagNeedsAck)
responsePacket.AddFlag(nex.FlagReliable)
globals.NEXServer.Send(responsePacket)
globals.SecureServer.Send(responsePacket)
return 0
}

View File

@@ -2,31 +2,47 @@ 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"
datastore_types "github.com/PretendoNetwork/nex-protocols-go/datastore/types"
datastore_smm_db "github.com/PretendoNetwork/super-mario-maker-secure/database/datastore/super-mario-maker"
"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))
}
func RecommendedCourseSearchObject(err error, packet nex.PacketInterface, callID uint32, param *datastore_types.DataStoreSearchParam, extraData []string) uint32 {
if err != nil {
globals.Logger.Error(err.Error())
return nex.Errors.DataStore.Unknown
}
rmcResponseStream := nex.NewStreamOut(globals.NEXServer)
client := packet.Sender()
// * This method is used in 100 Mario and Course World
// *
// * extraData seems to be a set of filters defining a
// * range for a courses success rate
// *
// * Course World (All) ["", "", "", "0", "0"]
// * Course World (Easy) ["1", "0", "34", "0", "0"]
// * Course World (Normal) ["1", "35", "74", "0", "0"]
// * Course World (Expert) ["1", "75", "95", "0", "0"]
// * Course World (Super Expert) ["1", "96", "100", "0", "0"]
// *
// * Indexes 1 and 2 seem to be a min and max for the *failure*
// * rate of the courses. This is not taken into account yet,
// * as the SQL query for this would need to be rather complex.
// * The last 2 values always seem to be 0, and the first seems
// * to always be 1 besides filtering for "All"
// *
// ! All requests are treated as filtering for "All" right now
// TODO - Use these ranges to properly filter by difficulty
// TODO - Use the offet? Real client never uses it, but might be nice for completeness sake?
pRankingResults, errCode := datastore_smm_db.GetRandomCoursesWithLimit(int(param.ResultRange.Length))
if errCode != 0 {
return errCode
}
rmcResponseStream := nex.NewStreamOut(globals.SecureServer)
rmcResponseStream.WriteListStructure(pRankingResults)
@@ -48,5 +64,7 @@ func RecommendedCourseSearchObject(err error, client *nex.Client, callID uint32,
responsePacket.AddFlag(nex.FlagNeedsAck)
responsePacket.AddFlag(nex.FlagReliable)
globals.NEXServer.Send(responsePacket)
globals.SecureServer.Send(responsePacket)
return 0
}

View File

@@ -4,31 +4,43 @@ 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"
datastore_types "github.com/PretendoNetwork/nex-protocols-go/datastore/types"
datastore_smm_db "github.com/PretendoNetwork/super-mario-maker-secure/database/datastore/super-mario-maker"
"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
func SuggestedCourseSearchObject(err error, packet nex.PacketInterface, callID uint32, param *datastore_types.DataStoreSearchParam, extraData []string) uint32 {
if err != nil {
globals.Logger.Error(err.Error())
return nex.Errors.DataStore.Unknown
}
pRankingResults := make([]*datastore_super_mario_maker.DataStoreCustomRankingResult, 0)
client := packet.Sender()
courseMetadatas := database.GetCourseMetadatasByLimit(4) // In PCAPs param.minimalRatingFrequency is 4 but is 0 here?
// * This method is called when a course is completed
// * to show the scrolling courses at the bottom of the
// * screen. extraData[0] is the DataID of the current
// * course. extraData[1] and extraData[2] are usually
// * 2 and 6 respectively. extraData[3] and extraData[4]
// * are always 0? extraData seems to not have any
// * effect on the NUMBER of courses returned but likely
// * does act as a filter of some kind? Maybe it has to
// * do with difficulty? Or ratings?
for _, courseMetadata := range courseMetadatas {
pRankingResults = append(pRankingResults, utility.CourseMetadataToDataStoreCustomRankingResult(courseMetadata))
_, err = strconv.ParseUint(extraData[0], 0, 64)
if err != nil {
globals.Logger.Error(err.Error())
return nex.Errors.DataStore.InvalidArgument
}
rmcResponseStream := nex.NewStreamOut(globals.NEXServer)
// TODO - Use extraData for filtering
pRankingResults, errCode := datastore_smm_db.GetRandomCoursesWithLimit(int(param.ResultRange.Length))
if errCode != 0 {
return errCode
}
rmcResponseStream := nex.NewStreamOut(globals.SecureServer)
rmcResponseStream.WriteListStructure(pRankingResults)
@@ -50,5 +62,7 @@ func SuggestedCourseSearchObject(err error, client *nex.Client, callID uint32, p
responsePacket.AddFlag(nex.FlagNeedsAck)
responsePacket.AddFlag(nex.FlagReliable)
globals.NEXServer.Send(responsePacket)
globals.SecureServer.Send(responsePacket)
return 0
}

View File

@@ -3,12 +3,23 @@ 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"
datastore_super_mario_maker_types "github.com/PretendoNetwork/nex-protocols-go/datastore/super-mario-maker/types"
datastore_smm_db "github.com/PretendoNetwork/super-mario-maker-secure/database/datastore/super-mario-maker"
"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)
func UploadCourseRecord(err error, packet nex.PacketInterface, callID uint32, param *datastore_super_mario_maker_types.DataStoreUploadCourseRecordParam) uint32 {
if err != nil {
globals.Logger.Error(err.Error())
return nex.Errors.DataStore.Unknown
}
client := packet.Sender()
errCode := datastore_smm_db.InsertOrUpdateCourseRecord(param.DataID, param.Slot, client.PID(), param.Score)
if errCode != 0 {
return errCode
}
rmcResponse := nex.NewRMCResponse(datastore_super_mario_maker.ProtocolID, callID)
rmcResponse.SetSuccess(datastore_super_mario_maker.MethodUploadCourseRecord, nil)
@@ -26,5 +37,7 @@ func UploadCourseRecord(err error, client *nex.Client, callID uint32, param *dat
responsePacket.AddFlag(nex.FlagNeedsAck)
responsePacket.AddFlag(nex.FlagReliable)
globals.NEXServer.Send(responsePacket)
globals.SecureServer.Send(responsePacket)
return 0
}

View File

@@ -1,4 +1,4 @@
package main
package nex_message_delivery
import (
nex "github.com/PretendoNetwork/nex-go"
@@ -6,7 +6,16 @@ import (
"github.com/PretendoNetwork/super-mario-maker-secure/globals"
)
func DeliverMessage(err error, client *nex.Client, callID uint32, oUserMessage nex.StructureInterface) {
func DeliverMessage(err error, packet nex.PacketInterface, callID uint32, oUserMessage *nex.DataHolder) uint32 {
if err != nil {
globals.Logger.Error(err.Error())
return nex.Errors.DataStore.Unknown
}
client := packet.Sender()
// TODO - See what this does
rmcResponse := nex.NewRMCResponse(message_delivery.ProtocolID, callID)
rmcResponse.SetSuccess(message_delivery.MethodDeliverMessage, nil)
@@ -23,5 +32,7 @@ func DeliverMessage(err error, client *nex.Client, callID uint32, oUserMessage n
responsePacket.AddFlag(nex.FlagNeedsAck)
responsePacket.AddFlag(nex.FlagReliable)
globals.NEXServer.Send(responsePacket)
globals.SecureServer.Send(responsePacket)
return 0
}

View File

@@ -0,0 +1,30 @@
package nex
import (
"os"
"strconv"
nex "github.com/PretendoNetwork/nex-go"
ticket_granting "github.com/PretendoNetwork/nex-protocols-common-go/ticket-granting"
"github.com/PretendoNetwork/super-mario-maker-secure/globals"
)
func registerCommonAuthenticationServerProtocols() {
ticketGrantingProtocol := ticket_granting.NewCommonTicketGrantingProtocol(globals.AuthenticationServer)
secureStationURL := nex.NewStationURL("")
secureStationURL.SetScheme("prudps")
secureStationURL.SetAddress(os.Getenv("PN_SMM_SECURE_SERVER_HOST"))
port, _ := strconv.ParseUint(os.Getenv("PN_SMM_SECURE_SERVER_PORT"), 10, 32)
secureStationURL.SetPort(uint32(port))
secureStationURL.SetCID(1)
secureStationURL.SetPID(2)
secureStationURL.SetSID(1)
secureStationURL.SetStream(10)
secureStationURL.SetType(2)
ticketGrantingProtocol.SetSecureStationURL(secureStationURL)
ticketGrantingProtocol.SetBuildName(serverBuildString)
globals.AuthenticationServer.SetPasswordFromPIDFunction(globals.PasswordFromPID)
}

View File

@@ -1,15 +0,0 @@
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
}

View File

@@ -0,0 +1,52 @@
package nex
import (
"os"
datastore "github.com/PretendoNetwork/nex-protocols-common-go/datastore"
secureconnection "github.com/PretendoNetwork/nex-protocols-common-go/secure-connection"
datastore_db "github.com/PretendoNetwork/super-mario-maker-secure/database/datastore"
"github.com/PretendoNetwork/super-mario-maker-secure/globals"
nex_datastore_super_mario_maker "github.com/PretendoNetwork/super-mario-maker-secure/nex/datastore/super-mario-maker"
)
func registerCommonSecureProtocols() {
secureconnection.NewCommonSecureConnectionProtocol(globals.SecureServer)
commonDataStoreProtocol := datastore.NewCommonDataStoreProtocol(globals.SecureServer)
commonDataStoreProtocol.SetS3Bucket(os.Getenv("PN_SMM_CONFIG_S3_BUCKET"))
commonDataStoreProtocol.SetMinIOClient(globals.MinIOClient)
commonDataStoreProtocol.GetObjectInfoByDataID(datastore_db.GetObjectInfoByDataID)
commonDataStoreProtocol.UpdateObjectPeriodByDataIDWithPassword(datastore_db.UpdateObjectPeriodByDataIDWithPassword)
commonDataStoreProtocol.UpdateObjectMetaBinaryByDataIDWithPassword(datastore_db.UpdateObjectMetaBinaryByDataIDWithPassword)
commonDataStoreProtocol.UpdateObjectDataTypeByDataIDWithPassword(datastore_db.UpdateObjectDataTypeByDataIDWithPassword)
commonDataStoreProtocol.GetObjectSizeDataID(datastore_db.GetObjectSizeDataID)
commonDataStoreProtocol.UpdateObjectUploadCompletedByDataID(datastore_db.UpdateObjectUploadCompletedByDataID)
commonDataStoreProtocol.GetObjectInfoByPersistenceTargetWithPassword(datastore_db.GetObjectInfoByPersistenceTargetWithPassword)
commonDataStoreProtocol.GetObjectInfoByDataIDWithPassword(datastore_db.GetObjectInfoByDataIDWithPassword)
commonDataStoreProtocol.InitializeObjectByPreparePostParam(datastore_db.InitializeObjectByPreparePostParam)
commonDataStoreProtocol.InitializeObjectRatingWithSlot(datastore_db.InitializeObjectRatingWithSlot)
commonDataStoreProtocol.RateObjectWithPassword(datastore_db.RateObjectWithPassword)
commonDataStoreProtocol.DeleteObjectByDataID(datastore_db.DeleteObjectByDataID)
commonDataStoreProtocol.GetObjectOwnerByDataID(datastore_db.GetObjectOwnerByDataID)
commonDataStoreProtocol.SuperMarioMakerProtocol.GetObjectInfos(nex_datastore_super_mario_maker.GetObjectInfos)
commonDataStoreProtocol.SuperMarioMakerProtocol.RateCustomRanking(nex_datastore_super_mario_maker.RateCustomRanking)
commonDataStoreProtocol.SuperMarioMakerProtocol.GetCustomRankingByDataID(nex_datastore_super_mario_maker.GetCustomRankingByDataID)
commonDataStoreProtocol.SuperMarioMakerProtocol.AddToBufferQueues(nex_datastore_super_mario_maker.AddToBufferQueues)
commonDataStoreProtocol.SuperMarioMakerProtocol.GetBufferQueue(nex_datastore_super_mario_maker.GetBufferQueue)
commonDataStoreProtocol.SuperMarioMakerProtocol.CompleteAttachFile(nex_datastore_super_mario_maker.CompleteAttachFile)
commonDataStoreProtocol.SuperMarioMakerProtocol.PrepareAttachFile(nex_datastore_super_mario_maker.PrepareAttachFile)
commonDataStoreProtocol.SuperMarioMakerProtocol.GetApplicationConfig(nex_datastore_super_mario_maker.GetApplicationConfig)
commonDataStoreProtocol.SuperMarioMakerProtocol.FollowingsLatestCourseSearchObject(nex_datastore_super_mario_maker.FollowingsLatestCourseSearchObject)
commonDataStoreProtocol.SuperMarioMakerProtocol.RecommendedCourseSearchObject(nex_datastore_super_mario_maker.RecommendedCourseSearchObject)
commonDataStoreProtocol.SuperMarioMakerProtocol.SuggestedCourseSearchObject(nex_datastore_super_mario_maker.SuggestedCourseSearchObject)
commonDataStoreProtocol.SuperMarioMakerProtocol.UploadCourseRecord(nex_datastore_super_mario_maker.UploadCourseRecord)
commonDataStoreProtocol.SuperMarioMakerProtocol.GetCourseRecord(nex_datastore_super_mario_maker.GetCourseRecord)
commonDataStoreProtocol.SuperMarioMakerProtocol.GetApplicationConfigString(nex_datastore_super_mario_maker.GetApplicationConfigString)
commonDataStoreProtocol.SuperMarioMakerProtocol.GetDeletionReason(nex_datastore_super_mario_maker.GetDeletionReason)
commonDataStoreProtocol.SuperMarioMakerProtocol.GetMetasWithCourseRecord(nex_datastore_super_mario_maker.GetMetasWithCourseRecord)
commonDataStoreProtocol.SuperMarioMakerProtocol.CheckRateCustomRankingCounter(nex_datastore_super_mario_maker.CheckRateCustomRankingCounter)
commonDataStoreProtocol.SuperMarioMakerProtocol.CTRPickUpCourseSearchObject(nex_datastore_super_mario_maker.CTRPickUpCourseSearchObject)
}

View File

@@ -1,42 +1,13 @@
package nex
import (
"github.com/PretendoNetwork/nex-protocols-go/datastore"
datastore_super_mario_maker "github.com/PretendoNetwork/nex-protocols-go/datastore/super-mario-maker"
message_delivery "github.com/PretendoNetwork/nex-protocols-go/message-delivery"
"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"
nex_message_delivery "github.com/PretendoNetwork/super-mario-maker-secure/nex/message-delivery"
)
func registerNEXProtocols() {
datastoreProtocol := datastore.NewDataStoreProtocol(globals.NEXServer)
messageDeliveryProtocol := message_delivery.NewProtocol(globals.SecureServer)
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)
messageDeliveryProtocol.DeliverMessage(nex_message_delivery.DeliverMessage)
}

View File

@@ -1,5 +0,0 @@
package nex_secure_connection_common
func AddConnection(rvcid uint32, urls []string, ip string, port string) {
// TODO - Stubbed
}

View File

@@ -1,7 +0,0 @@
package nex_secure_connection_common
func DoesConnectionExist(rvcid uint32) bool {
// TODO - Stubbed
return false
}

View File

@@ -1,5 +0,0 @@
package nex_secure_connection_common
func UpdateConnection(rvcid uint32, urls []string, ip string, port string) {
// TODO - Stubbed
}

33
nex/secure.go Normal file
View File

@@ -0,0 +1,33 @@
package nex
import (
"fmt"
"os"
"github.com/PretendoNetwork/nex-go"
"github.com/PretendoNetwork/super-mario-maker-secure/globals"
)
func StartSecureServer() {
globals.SecureServer = nex.NewServer()
globals.SecureServer.SetPRUDPVersion(1)
globals.SecureServer.SetPRUDPProtocolMinorVersion(2)
globals.SecureServer.SetDefaultNEXVersion(nex.NewPatchedNEXVersion(3, 8, 3, "AMAJ"))
globals.SecureServer.SetKerberosPassword(globals.KerberosPassword)
globals.SecureServer.SetAccessKey("9f2b4678")
globals.SecureServer.On("Data", func(packet *nex.PacketV1) {
request := packet.RMCRequest()
fmt.Println("==SMM1 - Secure==")
fmt.Printf("Protocol ID: %d\n", request.ProtocolID())
fmt.Printf("Method ID: %d\n", request.MethodID())
fmt.Println("===============")
})
// * Register the common handlers first so that they can be overridden if needed
registerCommonSecureProtocols()
registerNEXProtocols()
globals.SecureServer.Listen(fmt.Sprintf(":%s", os.Getenv("PN_SMM_SECURE_SERVER_PORT")))
}

View File

@@ -1,37 +0,0 @@
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")
}

Some files were not shown because too many files have changed in this diff Show More