From be04408336def1ab135690c62da002f5773c23c5 Mon Sep 17 00:00:00 2001 From: Flashfyre Date: Mon, 18 Mar 2024 19:55:02 -0400 Subject: [PATCH] Update random daily seed logic --- .gitignore | 2 +- api/account-helper.go | 4 +-- api/account.go | 2 +- api/daily.go | 59 ++++++++++++++++++++++++++++++++---------- api/savedata-helper.go | 8 +++--- api/savedata.go | 8 +++--- api/utils.go | 20 -------------- db/account.go | 6 ++--- db/daily.go | 18 +------------ 9 files changed, 62 insertions(+), 65 deletions(-) delete mode 100644 api/utils.go diff --git a/.gitignore b/.gitignore index 9cb6c63..3bf9323 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,4 @@ pokerogue-server.exe userdata/* -key +secret.key diff --git a/api/account-helper.go b/api/account-helper.go index eeaaae6..116d1a8 100644 --- a/api/account-helper.go +++ b/api/account-helper.go @@ -22,7 +22,7 @@ func GetUsernameFromRequest(request *http.Request) (string, error) { return "", fmt.Errorf("invalid token length: got %d, expected 32", len(token)) } - username, err := db.GetUsernameFromToken(token) + username, err := db.FetchUsernameFromToken(token) if err != nil { return "", fmt.Errorf("failed to validate token: %s", err) } @@ -44,7 +44,7 @@ func GetUuidFromRequest(request *http.Request) ([]byte, error) { return nil, fmt.Errorf("invalid token length: got %d, expected 32", len(token)) } - uuid, err := db.GetUuidFromToken(token) + uuid, err := db.FetchUuidFromToken(token) if err != nil { return nil, fmt.Errorf("failed to validate token: %s", err) } diff --git a/api/account.go b/api/account.go index 7872052..e73b1ac 100644 --- a/api/account.go +++ b/api/account.go @@ -144,7 +144,7 @@ func (s *Server) HandleAccountLogin(w http.ResponseWriter, r *http.Request) { return } - key, salt, err := db.GetAccountKeySaltFromUsername(request.Username) + key, salt, err := db.FetchAccountKeySaltFromUsername(request.Username) if err != nil { if err == sql.ErrNoRows { http.Error(w, "account doesn't exist", http.StatusBadRequest) diff --git a/api/daily.go b/api/daily.go index b6f9127..adcb47e 100644 --- a/api/daily.go +++ b/api/daily.go @@ -1,17 +1,26 @@ package api import ( + "crypto/md5" + "crypto/rand" + "encoding/base64" + "encoding/binary" "encoding/json" "fmt" "log" "net/http" + "os" "strconv" + "time" "github.com/Flashfyre/pokerogue-server/db" ) +const secondsPerDay = 60 * 60 * 24 + var ( - dailyRunSeed string + dailyRunSecret []byte + dailyRunSeed string ) func ScheduleDailyRunRefresh() { @@ -21,24 +30,48 @@ func ScheduleDailyRunRefresh() { } func InitDailyRun() { - var err error - dailyRunSeed, err = db.GetDailyRunSeed() + secret, err := os.ReadFile("secret.key") if err != nil { - log.Printf("failed to generated daily run seed: %s", err.Error()) - } + if !os.IsNotExist(err) { + log.Fatalf("failed to read daily seed secret: %s", err) + } - if dailyRunSeed == "" { - dailyRunSeed = RandString(24) - err := db.TryAddDailyRun(dailyRunSeed) + newSecret := make([]byte, 32) + _, err := rand.Read(newSecret) if err != nil { - log.Print(err.Error()) - } else { - log.Printf("Daily Run Seed: %s", dailyRunSeed) + log.Fatalf("failed to generate daily seed secret: %s", err) } + + err = os.WriteFile("secret.key", newSecret, 0400) + if err != nil { + log.Fatalf("failed to write daily seed secret: %s", err) + } + + secret = newSecret + } + + dailyRunSecret = secret + + dailyRunSeed = base64.StdEncoding.EncodeToString(DeriveDailyRunSeed(time.Now().UTC())) + + err = db.TryAddDailyRun(dailyRunSeed) + if err != nil { + log.Print(err.Error()) + } else { + log.Printf("Daily Run Seed: %s", dailyRunSeed) } } -// /daily/seed - get daily run seed +func DeriveDailyRunSeed(seedTime time.Time) []byte { + day := make([]byte, 8) + binary.BigEndian.PutUint64(day, uint64(seedTime.Unix()/secondsPerDay)) + + hashedSeed := md5.Sum(append(day, dailyRunSecret...)) + + return hashedSeed[:] +} + +// /daily/seed - fetch daily run seed func (s *Server) HandleSeed(w http.ResponseWriter, r *http.Request) { w.Write([]byte(dailyRunSeed)) @@ -60,7 +93,7 @@ func (s *Server) HandleRankings(w http.ResponseWriter, r *http.Request) { page = 1 } - rankings, err := db.GetRankings(page) + rankings, err := db.FetchRankings(page) if err != nil { log.Print("failed to retrieve rankings") } diff --git a/api/savedata-helper.go b/api/savedata-helper.go index 182631d..d7f0542 100644 --- a/api/savedata-helper.go +++ b/api/savedata-helper.go @@ -12,7 +12,7 @@ import ( "github.com/klauspost/compress/zstd" ) -func GetSystemSaveData(uuid []byte) (defs.SystemSaveData, error) { +func ReadSystemSaveData(uuid []byte) (defs.SystemSaveData, error) { var system defs.SystemSaveData save, err := os.ReadFile("userdata/" + hex.EncodeToString(uuid) + "/system.pzs") @@ -40,7 +40,7 @@ func GetSystemSaveData(uuid []byte) (defs.SystemSaveData, error) { return system, nil } -func GetSessionSaveData(uuid []byte, slotId int) (defs.SessionSaveData, error) { +func ReadSessionSaveData(uuid []byte, slotId int) (defs.SessionSaveData, error) { var session defs.SessionSaveData fileName := "session" @@ -76,9 +76,9 @@ func GetSessionSaveData(uuid []byte, slotId int) (defs.SessionSaveData, error) { func ValidateSessionCompleted(session defs.SessionSaveData) bool { switch session.GameMode { case 0: - return session.WaveIndex == 200 + return session.BattleType == 2 && session.WaveIndex == 200 case 3: - return session.WaveIndex == 50 + return session.BattleType == 2 && session.WaveIndex == 50 } return false } diff --git a/api/savedata.go b/api/savedata.go index f2bfee7..3b5dff7 100644 --- a/api/savedata.go +++ b/api/savedata.go @@ -29,7 +29,7 @@ func (s *Server) HandleSavedataGet(w http.ResponseWriter, r *http.Request) { switch r.URL.Query().Get("datatype") { case "0": // System - system, err := GetSystemSaveData(uuid) + system, err := ReadSystemSaveData(uuid) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return @@ -54,7 +54,7 @@ func (s *Server) HandleSavedataGet(w http.ResponseWriter, r *http.Request) { return } - session, err := GetSessionSaveData(uuid, slotId) + session, err := ReadSessionSaveData(uuid, slotId) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return @@ -276,12 +276,12 @@ func (s *Server) HandleSavedataClear(w http.ResponseWriter, r *http.Request) { return } - sessionCompleted := session.BattleType == 2 && ValidateSessionCompleted(session) + sessionCompleted := ValidateSessionCompleted(session) newCompletion := false if session.GameMode == 3 { waveCompleted := session.WaveIndex - if session.BattleType != 2 { + if !sessionCompleted { waveCompleted-- } err = db.AddOrUpdateAccountDailyRun(uuid, session.Score, waveCompleted) diff --git a/api/utils.go b/api/utils.go deleted file mode 100644 index e84a84d..0000000 --- a/api/utils.go +++ /dev/null @@ -1,20 +0,0 @@ -package api - -import ( - "crypto/rand" -) - -const randRunes = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890" -const lenRandRunes = len(randRunes) - -func RandString(length int) string { - b := make([]byte, length) - - rand.Read(b) - - for i := range b { - b[i] = randRunes[int(b[i])%lenRandRunes] - } - - return string(b) -} diff --git a/db/account.go b/db/account.go index 60e8807..d39c65a 100644 --- a/db/account.go +++ b/db/account.go @@ -38,7 +38,7 @@ func UpdateAccountLastActivity(uuid []byte) error { return nil } -func GetUsernameFromToken(token []byte) (string, error) { +func FetchUsernameFromToken(token []byte) (string, error) { var username string err := handle.QueryRow("SELECT a.username FROM accounts a JOIN sessions s ON s.uuid = a.uuid WHERE s.token = ? AND s.expire > UTC_TIMESTAMP()", token).Scan(&username) if err != nil { @@ -48,7 +48,7 @@ func GetUsernameFromToken(token []byte) (string, error) { return username, nil } -func GetAccountKeySaltFromUsername(username string) ([]byte, []byte, error) { +func FetchAccountKeySaltFromUsername(username string) ([]byte, []byte, error) { var key, salt []byte err := handle.QueryRow("SELECT hash, salt FROM accounts WHERE username = ?", username).Scan(&key, &salt) if err != nil { @@ -58,7 +58,7 @@ func GetAccountKeySaltFromUsername(username string) ([]byte, []byte, error) { return key, salt, nil } -func GetUuidFromToken(token []byte) ([]byte, error) { +func FetchUuidFromToken(token []byte) ([]byte, error) { var uuid []byte err := handle.QueryRow("SELECT uuid FROM sessions WHERE token = ? AND expire > UTC_TIMESTAMP()", token).Scan(&uuid) if err != nil { diff --git a/db/daily.go b/db/daily.go index 0689d97..237d81c 100644 --- a/db/daily.go +++ b/db/daily.go @@ -1,8 +1,6 @@ package db import ( - "database/sql" - "github.com/Flashfyre/pokerogue-server/defs" ) @@ -15,20 +13,6 @@ func TryAddDailyRun(seed string) error { return nil } -func GetDailyRunSeed() (string, error) { - var seed string - err := handle.QueryRow("SELECT seed FROM dailyRuns WHERE date = UTC_DATE()").Scan(&seed) - if err != nil { - if err == sql.ErrNoRows { - return "", err - } - - return "", err - } - - return seed, nil -} - func AddOrUpdateAccountDailyRun(uuid []byte, score int, wave int) error { _, err := handle.Exec("INSERT INTO accountDailyRuns (uuid, date, score, wave, timestamp) VALUES (?, UTC_DATE(), ?, ?, UTC_TIMESTAMP()) ON DUPLICATE KEY UPDATE score = ?, wave = GREATEST(wave, ?), timestamp = IF(score < ?, UTC_TIMESTAMP(), timestamp)", uuid, score, wave, score, wave, score) if err != nil { @@ -38,7 +22,7 @@ func AddOrUpdateAccountDailyRun(uuid []byte, score int, wave int) error { return nil } -func GetRankings(page int) ([]defs.DailyRanking, error) { +func FetchRankings(page int) ([]defs.DailyRanking, error) { var rankings []defs.DailyRanking offset := (page - 1) * 10