Skip to content

Commit

Permalink
Protect against cross-session overwrites
Browse files Browse the repository at this point in the history
  • Loading branch information
Flashfyre committed Apr 21, 2024
1 parent 75cf6f3 commit 6acbb64
Show file tree
Hide file tree
Showing 3 changed files with 85 additions and 9 deletions.
70 changes: 63 additions & 7 deletions api/endpoints.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,13 @@ import (
"github.com/pagefaultgames/pokerogue-server/api/account"
"github.com/pagefaultgames/pokerogue-server/api/daily"
"github.com/pagefaultgames/pokerogue-server/api/savedata"
"github.com/pagefaultgames/pokerogue-server/db"
"github.com/pagefaultgames/pokerogue-server/defs"
)

type Server struct {
Debug bool
Exit *sync.RWMutex
Exit *sync.RWMutex
}

/*
Expand Down Expand Up @@ -174,7 +175,7 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
}

save = system
// /savedata/clear doesn't specify datatype, it is assumed to be 1 (session)
// /savedata/clear doesn't specify datatype, it is assumed to be 1 (session)
} else if datatype == 1 || r.URL.Path == "/savedata/clear" {
var session defs.SessionSaveData
err = json.NewDecoder(r.Body).Decode(&session)
Expand All @@ -187,22 +188,77 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
}
}

var token []byte
token, err = base64.StdEncoding.DecodeString(r.Header.Get("Authorization"))
if err != nil {
httpError(w, r, fmt.Errorf("failed to decode token: %s", err), http.StatusBadRequest)
return
}

switch r.URL.Path {
case "/savedata/get":
err = db.UpdateActiveSession(uuid, token)
if err != nil {
httpError(w, r, fmt.Errorf("failed to update active session: %s", err), http.StatusInternalServerError)
return
}

save, err = savedata.Get(uuid, datatype, slot)
case "/savedata/update":
var token []byte
token, err = base64.StdEncoding.DecodeString(r.Header.Get("Authorization"))
if err != nil {
httpError(w, r, fmt.Errorf("failed to decode token: %s", err), http.StatusBadRequest)
return
}

var active bool
active, err = db.IsActiveSession(token)
if err != nil {
httpError(w, r, fmt.Errorf("failed to check active session: %s", err), http.StatusInternalServerError)
return
}
if !active {
httpError(w, r, fmt.Errorf("session out of date"), http.StatusBadRequest)
return
}

err = savedata.Update(uuid, slot, save)
case "/savedata/delete":
var active bool
active, err = db.IsActiveSession(token)
if err != nil {
httpError(w, r, fmt.Errorf("failed to check active session: %s", err), http.StatusInternalServerError)
return
}
if !active {
httpError(w, r, fmt.Errorf("session out of date"), http.StatusBadRequest)
return
}

err = savedata.Delete(uuid, datatype, slot)
case "/savedata/clear":
s, ok := save.(defs.SessionSaveData)
if !ok {
httpError(w, r, fmt.Errorf("save data is not type SessionSaveData"), http.StatusBadRequest)
var active bool
active, err = db.IsActiveSession(token)
if err != nil {
httpError(w, r, fmt.Errorf("failed to check active session: %s", err), http.StatusInternalServerError)
return
}

// doesn't return a save, but it works
save, err = savedata.Clear(uuid, slot, daily.Seed(), s)
if active {
s, ok := save.(defs.SessionSaveData)
if !ok {
httpError(w, r, fmt.Errorf("save data is not type SessionSaveData"), http.StatusBadRequest)
return
}

// doesn't return a save, but it works
save, err = savedata.Clear(uuid, slot, daily.Seed(), s)
} else {
var response savedata.ClearResponse
response.Error = "session out of date"
save = response
}
}
if err != nil {
httpError(w, r, err, http.StatusInternalServerError)
Expand Down
5 changes: 3 additions & 2 deletions api/savedata/clear.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ import (
)

type ClearResponse struct {
Success bool `json:"success"`
Success bool `json:"success"`
Error string `json:"error"`
}

// /savedata/clear - mark session save data as cleared and delete
Expand All @@ -34,7 +35,7 @@ func Clear(uuid []byte, slot int, seed string, save defs.SessionSaveData) (Clear
if !sessionCompleted {
waveCompleted--
}

err = db.AddOrUpdateAccountDailyRun(uuid, save.Score, waveCompleted)
if err != nil {
log.Printf("failed to add or update daily run record: %s", err)
Expand Down
19 changes: 19 additions & 0 deletions db/account.go
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,25 @@ func FetchAccountKeySaltFromUsername(username string) ([]byte, []byte, error) {
return key, salt, nil
}

func IsActiveSession(token []byte) (bool, error) {
var active int
err := handle.QueryRow("SELECT `active` FROM sessions WHERE token = ?", token).Scan(&active)
if err != nil {
return false, err
}

return active == 1, nil
}

func UpdateActiveSession(uuid []byte, token []byte) error {
_, err := handle.Exec("UPDATE sessions SET `active` = CASE WHEN token = ? THEN 1 ELSE 0 END WHERE uuid = ?", token, uuid)
if err != nil {
return err
}

return nil
}

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)
Expand Down

0 comments on commit 6acbb64

Please sign in to comment.