mirror of
https://github.com/jcreek/CosmicClash.git
synced 2026-09-11 08:23:45 +00:00
fix: bind reconnects to verified Steam identity
This commit is contained in:
@@ -29,6 +29,7 @@ type JoinAuthorisation struct {
|
||||
MatchID string
|
||||
ServerID string
|
||||
PlayerID string
|
||||
SteamID string
|
||||
Slot int
|
||||
Team int
|
||||
Protocol string
|
||||
@@ -40,6 +41,7 @@ type rankedConnection struct {
|
||||
PlayerID string
|
||||
Slot int
|
||||
Team int
|
||||
SteamID string
|
||||
Generation uint64
|
||||
ConnectedAt time.Time
|
||||
LostAt time.Time
|
||||
@@ -65,13 +67,18 @@ func NewRankedConnections(matchID, serverID, protocol string, players []JoinAuth
|
||||
if _, exists := r.players[auth.PlayerID]; exists {
|
||||
return nil, fmt.Errorf("%w: duplicate player", ErrJoinAuthorisation)
|
||||
}
|
||||
r.players[auth.PlayerID] = rankedConnection{PlayerID: auth.PlayerID, Slot: auth.Slot, Team: auth.Team, Generation: 1}
|
||||
for _, existing := range r.players {
|
||||
if existing.Slot == auth.Slot {
|
||||
return nil, fmt.Errorf("%w: duplicate slot", ErrJoinAuthorisation)
|
||||
}
|
||||
}
|
||||
r.players[auth.PlayerID] = rankedConnection{PlayerID: auth.PlayerID, SteamID: auth.SteamID, Slot: auth.Slot, Team: auth.Team, Generation: 1}
|
||||
}
|
||||
return r, nil
|
||||
}
|
||||
|
||||
func (r *RankedConnections) validate(auth JoinAuthorisation, now time.Time) error {
|
||||
if auth.MatchID != r.MatchID || auth.ServerID != r.ServerID || auth.Protocol != r.Protocol || auth.PlayerID == "" || auth.Slot < 0 || auth.Team < 0 || auth.ExpiresAt.IsZero() {
|
||||
if auth.MatchID != r.MatchID || auth.ServerID != r.ServerID || auth.Protocol != r.Protocol || auth.PlayerID == "" || auth.SteamID == "" || auth.Slot < 0 || auth.Team < 0 || auth.ExpiresAt.IsZero() {
|
||||
return ErrJoinAuthorisation
|
||||
}
|
||||
if !now.IsZero() && !now.Before(auth.ExpiresAt) {
|
||||
@@ -88,7 +95,7 @@ func (r *RankedConnections) Admit(auth JoinAuthorisation, now time.Time) (uint64
|
||||
return 0, err
|
||||
}
|
||||
player, ok := r.players[auth.PlayerID]
|
||||
if !ok || player.Slot != auth.Slot || player.Team != auth.Team {
|
||||
if !ok || player.SteamID != auth.SteamID || player.Slot != auth.Slot || player.Team != auth.Team {
|
||||
return 0, ErrJoinAuthorisation
|
||||
}
|
||||
// Generation in the authorisation identifies the backend-issued assignment
|
||||
|
||||
@@ -9,7 +9,7 @@ import (
|
||||
func testRoster(now time.Time) []JoinAuthorisation {
|
||||
roster := make([]JoinAuthorisation, 6)
|
||||
for i := range roster {
|
||||
roster[i] = JoinAuthorisation{MatchID: "match-1", ServerID: "server-1", Protocol: "v1", PlayerID: string(rune('a' + i)), Slot: i, Team: i % 2, Generation: 1, ExpiresAt: now.Add(time.Hour)}
|
||||
roster[i] = JoinAuthorisation{MatchID: "match-1", ServerID: "server-1", Protocol: "v1", PlayerID: string(rune('a' + i)), SteamID: string(rune('A' + i)), Slot: i, Team: i % 2, Generation: 1, ExpiresAt: now.Add(time.Hour)}
|
||||
}
|
||||
return roster
|
||||
}
|
||||
@@ -52,6 +52,11 @@ func TestRankedReconnectRejectsWrongBindingAndExpiredGrace(t *testing.T) {
|
||||
if _, err := r.Admit(bad, now); !errors.Is(err, ErrJoinAuthorisation) {
|
||||
t.Fatalf("wrong server accepted: %v", err)
|
||||
}
|
||||
wrongIdentity := testRoster(now)[0]
|
||||
wrongIdentity.SteamID = "steam-attacker"
|
||||
if _, err := r.Admit(wrongIdentity, now); !errors.Is(err, ErrJoinAuthorisation) {
|
||||
t.Fatalf("wrong SteamID accepted: %v", err)
|
||||
}
|
||||
if err := r.Disconnect("a", 1, now); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -60,6 +65,15 @@ func TestRankedReconnectRejectsWrongBindingAndExpiredGrace(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestRankedRosterRejectsDuplicateSlots(t *testing.T) {
|
||||
now := time.Unix(1000, 0)
|
||||
roster := testRoster(now)
|
||||
roster[1].Slot = roster[0].Slot
|
||||
if _, err := NewRankedConnections("match-1", "server-1", "v1", roster); !errors.Is(err, ErrJoinAuthorisation) {
|
||||
t.Fatalf("duplicate slot accepted: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRankedAbandonCooldownUsesRollingSevenDayLadder(t *testing.T) {
|
||||
now := time.Unix(1000, 0)
|
||||
r, err := NewRankedConnections("match-1", "server-1", "v1", testRoster(now))
|
||||
|
||||
Reference in New Issue
Block a user