From eddb4416f7b055eb155abf8f003b6f538026a2a4 Mon Sep 17 00:00:00 2001 From: MikeIsAStar <99037623+MikeIsAStar@users.noreply.github.com> Date: Mon, 9 Sep 2024 23:55:00 -0400 Subject: [PATCH 1/2] SAKE: Validate the scores submitted in file uploads from Mario Kart Wii --- sake/mario_kart_wii.go | 6 +++--- schema.sql | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/sake/mario_kart_wii.go b/sake/mario_kart_wii.go index f7cb607..e7013f7 100644 --- a/sake/mario_kart_wii.go +++ b/sake/mario_kart_wii.go @@ -110,7 +110,7 @@ func handleMarioKartWiiGhostDownloadRequest(moduleName string, responseWriter ht } time, err := strconv.Atoi(timeString) - if err != nil || time <= 0 { + if err != nil || time <= 0 || time >= 360000 /* 6 minutes */ { logging.Error(moduleName, "Invalid time:", aurora.Cyan(timeString)) responseWriter.Header().Set(SakeFileResultHeader, strconv.Itoa(SakeFileResultMissingParameter)) return @@ -167,14 +167,14 @@ func handleMarioKartWiiGhostUploadRequest(moduleName string, responseWriter http return } courseId := common.MarioKartWiiCourseId(courseIdInt) - if courseId < common.MarioCircuit || courseId > 32767 { + if courseId < common.MarioCircuit || isContest == courseId.IsValid() || courseId > 32767 { logging.Error(moduleName, "Invalid course ID:", aurora.Cyan(courseIdString)) responseWriter.Header().Set(SakeFileResultHeader, strconv.Itoa(SakeFileResultMissingParameter)) return } score, err := strconv.Atoi(scoreString) - if err != nil || score <= 0 { + if err != nil || score <= 0 || score >= 360000 /* 6 minutes */ { logging.Error(moduleName, "Invalid score:", aurora.Cyan(scoreString)) responseWriter.Header().Set(SakeFileResultHeader, strconv.Itoa(SakeFileResultMissingParameter)) return diff --git a/schema.sql b/schema.sql index 56870fe..ec36213 100644 --- a/schema.sql +++ b/schema.sql @@ -59,7 +59,7 @@ ALTER TABLE public.users OWNER TO wiilink; CREATE TABLE IF NOT EXISTS public.mario_kart_wii_sake ( regionid smallint NOT NULL CHECK (regionid >= 1 AND regionid <= 7), courseid smallint NOT NULL CHECK (courseid >= 0 AND courseid <= 32767), - score integer NOT NULL CHECK (score > 0), + score integer NOT NULL CHECK (score > 0 AND score < 360000), pid integer NOT NULL CHECK (pid > 0), playerinfo varchar(108) NOT NULL CHECK (LENGTH(playerinfo) = 108), ghost bytea CHECK (ghost IS NULL OR (OCTET_LENGTH(ghost) BETWEEN 148 AND 10240)), From ccbbeebeba9511a8fe9a556bcb6a14ef07d85afc Mon Sep 17 00:00:00 2001 From: MikeIsAStar <99037623+MikeIsAStar@users.noreply.github.com> Date: Tue, 10 Sep 2024 00:00:00 -0400 Subject: [PATCH 2/2] SAKE: Support file download requests for rival ghosts from Mario Kart Wii Helps address issue #43. --- database/mario_kart_wii.go | 18 ++++++++++ sake/storage.go | 69 +++++++++++++++++++++++++++++++++++++- 2 files changed, 86 insertions(+), 1 deletion(-) diff --git a/database/mario_kart_wii.go b/database/mario_kart_wii.go index 9563c5a..9db7667 100644 --- a/database/mario_kart_wii.go +++ b/database/mario_kart_wii.go @@ -21,6 +21,13 @@ const ( "AND courseid = $2 " + "ORDER BY score ASC " + "LIMIT 10" + getGhostDataQuery = "" + + "SELECT id " + + "FROM mario_kart_wii_sake " + + "WHERE courseid = $1 " + + "AND score < $2 " + + "ORDER BY score DESC " + + "LIMIT 1" getStoredGhostDataQuery = "" + "SELECT pid, id " + "FROM mario_kart_wii_sake " + @@ -73,6 +80,17 @@ func GetMarioKartWiiTopTenRankings(pool *pgxpool.Pool, ctx context.Context, regi return topTenRankings, nil } +func GetMarioKartWiiGhostData(pool *pgxpool.Pool, ctx context.Context, courseId common.MarioKartWiiCourseId, time int) (int, error) { + row := pool.QueryRow(ctx, getGhostDataQuery, courseId, time) + + var fileId int + if err := row.Scan(&fileId); err != nil { + return 0, err + } + + return fileId, nil +} + func GetMarioKartWiiStoredGhostData(pool *pgxpool.Pool, ctx context.Context, regionId common.MarioKartWiiLeaderboardRegionId, courseId common.MarioKartWiiCourseId) (int, int, error) { row := pool.QueryRow(ctx, getStoredGhostDataQuery, regionId, courseId) diff --git a/sake/storage.go b/sake/storage.go index f7ddfd6..03d08d4 100644 --- a/sake/storage.go +++ b/sake/storage.go @@ -383,6 +383,73 @@ func searchForRecords(moduleName string, gameInfo common.GameInfo, request Stora }, } + case "mariokartwii/GhostData": + if request.TableID != "GhostData" { + logging.Error(moduleName, "Invalid table name:", aurora.Cyan(request.TableID)) + return &errorResponse + } + + if request.Sort != "time desc" { + logging.Error(moduleName, "Invalid sort string:", aurora.Cyan(request.Sort)) + return &errorResponse + } + + if request.Offset != 0 { + logging.Error(moduleName, "Invalid offset value:", aurora.Cyan(request.Offset)) + return &errorResponse + } + + if request.Max != 1 { + logging.Error(moduleName, "Invalid number of records to return:", aurora.Cyan(request.Max)) + return &errorResponse + } + + if request.Surrounding != 0 { + logging.Error(moduleName, "Invalid number of surrounding records to return:", aurora.Cyan(request.Surrounding)) + return &errorResponse + } + + if request.OwnerIDs != "" { + logging.Error(moduleName, "Invalid owner id array:", aurora.Cyan(request.OwnerIDs)) + return &errorResponse + } + + if request.CacheFlag != 0 { + logging.Error(moduleName, "Invalid cache value:", aurora.Cyan(request.CacheFlag)) + return &errorResponse + } + + match := regexp.MustCompile(`^course = ([1-9]\d?|0) and gameid = 1687 and time < ([1-9][0-9]{0,5})$`).FindStringSubmatch(request.Filter) + if match == nil { + logging.Error(moduleName, "Invalid filter string:", aurora.Cyan(request.Filter)) + return &errorResponse + } + + courseIdInt, _ := strconv.Atoi(match[1]) + courseId := common.MarioKartWiiCourseId(courseIdInt) + if !courseId.IsValid() { + logging.Error(moduleName, "Invalid course ID:", aurora.Cyan(match[1])) + return &errorResponse + } + + time, _ := strconv.Atoi(match[2]) + if time >= 360000 /* 6 minutes */ { + logging.Error(moduleName, "Invalid time:", aurora.Cyan(match[2])) + return &errorResponse + } + + fileId, err := database.GetMarioKartWiiGhostData(pool, ctx, courseId, time) + if err != nil { + logging.Error(moduleName, "Failed to get the ghost data from the database:", err) + return &errorResponse + } + + values = []map[string]StorageValue{ + { + "fileid": intValue(int32(fileId)), + }, + } + case "mariokartwii/StoredGhostData": if request.Sort != "time" { logging.Error(moduleName, "Invalid sort string:", aurora.Cyan(request.Sort)) @@ -423,7 +490,7 @@ func searchForRecords(moduleName string, gameInfo common.GameInfo, request Stora courseIdInt, _ := strconv.Atoi(match[1]) courseId := common.MarioKartWiiCourseId(courseIdInt) if !courseId.IsValid() { - logging.Error(moduleName, "Invalid course ID:", aurora.Cyan(courseIdInt)) + logging.Error(moduleName, "Invalid course ID:", aurora.Cyan(match[1])) return &errorResponse }