From 4cac6b6ce8fbdcaf6ef640b8c0d80a8afe2c9a37 Mon Sep 17 00:00:00 2001 From: Frederico Santos Date: Sat, 22 Jun 2024 22:28:14 +0100 Subject: [PATCH] Update SaveData to handle session and system out of date overwrites (#43) * chore: Update savedata API to handle session out of date errors * chore: Handle session out of date errors in savedata API * chore: Handle session out of date errors in savedata API * chore: Update savedata API to handle session out of date errors --- api/endpoints.go | 56 ++++++++++++++++++++++++++++++++++++++++++++++++ db/savedata.go | 10 +++++++++ 2 files changed, 66 insertions(+) diff --git a/api/endpoints.go b/api/endpoints.go index 827e8e2..2eccdd9 100644 --- a/api/endpoints.go +++ b/api/endpoints.go @@ -198,6 +198,17 @@ func handleSession(w http.ResponseWriter, r *http.Request) { return } + existingSave, err := savedata.GetSession(uuid, slot) + if err != nil && !errors.Is(err, sql.ErrNoRows) { + httpError(w, r, fmt.Errorf("failed to retrieve session save data: %s", err), http.StatusInternalServerError) + return + } else { + if existingSave.Seed == session.Seed && existingSave.WaveIndex > session.WaveIndex { + httpError(w, r, fmt.Errorf("session out of date: existing wave index is greater"), http.StatusBadRequest) + return + } + } + err = savedata.UpdateSession(uuid, slot, session) if err != nil { httpError(w, r, fmt.Errorf("failed to put session data: %s", err), http.StatusInternalServerError) @@ -306,6 +317,34 @@ func handleUpdateAll(w http.ResponseWriter, r *http.Request) { } } + existingPlaytime, err := db.RetrievePlaytime(uuid) + if err != nil && !errors.Is(err, sql.ErrNoRows) { + httpError(w, r, fmt.Errorf("failed to retrieve playtime: %s", err), http.StatusInternalServerError) + return + } else { + playtime, ok := data.System.GameStats.(map[string]interface{})["playTime"].(float64) + if !ok { + httpError(w, r, fmt.Errorf("no playtime found"), http.StatusBadRequest) + return + } + + if float64(existingPlaytime) > playtime { + httpError(w, r, fmt.Errorf("session out of date: existing playtime is greater"), http.StatusBadRequest) + return + } + } + + existingSave, err := savedata.GetSession(uuid, data.SessionSlotId) + if err != nil && !errors.Is(err, sql.ErrNoRows) { + httpError(w, r, fmt.Errorf("failed to retrieve session save data: %s", err), http.StatusInternalServerError) + return + } else { + if existingSave.Seed == data.Session.Seed && existingSave.WaveIndex > data.Session.WaveIndex { + httpError(w, r, fmt.Errorf("session out of date: existing wave index is greater"), http.StatusBadRequest) + return + } + } + err = savedata.Update(uuid, data.SessionSlotId, data.Session) if err != nil { httpError(w, r, err, http.StatusInternalServerError) @@ -380,6 +419,23 @@ func handleSystem(w http.ResponseWriter, r *http.Request) { return } + existingPlaytime, err := db.RetrievePlaytime(uuid) + if err != nil && !errors.Is(err, sql.ErrNoRows) { + httpError(w, r, fmt.Errorf("failed to retrieve playtime: %s", err), http.StatusInternalServerError) + return + } else { + playtime, ok := system.GameStats.(map[string]interface{})["playTime"].(float64) + if !ok { + httpError(w, r, fmt.Errorf("no playtime found"), http.StatusBadRequest) + return + } + + if float64(existingPlaytime) > playtime { + httpError(w, r, fmt.Errorf("session out of date: existing playtime is greater"), http.StatusBadRequest) + return + } + } + err = savedata.UpdateSystem(uuid, system) if err != nil { httpError(w, r, fmt.Errorf("failed to put system data: %s", err), http.StatusInternalServerError) diff --git a/db/savedata.go b/db/savedata.go index bb792c5..10256a3 100644 --- a/db/savedata.go +++ b/db/savedata.go @@ -142,3 +142,13 @@ func DeleteSessionSaveData(uuid []byte, slot int) error { return nil } + +func RetrievePlaytime(uuid []byte) (int, error) { + var playtime int + err := handle.QueryRow("SELECT playTime FROM accountStats WHERE uuid = ?", uuid).Scan(&playtime) + if err != nil { + return 0, err + } + + return playtime, nil +}