aboutsummaryrefslogtreecommitdiff
path: root/internal/game/account_registration_regression_test.go
diff options
context:
space:
mode:
Diffstat (limited to 'internal/game/account_registration_regression_test.go')
-rw-r--r--internal/game/account_registration_regression_test.go55
1 files changed, 55 insertions, 0 deletions
diff --git a/internal/game/account_registration_regression_test.go b/internal/game/account_registration_regression_test.go
new file mode 100644
index 0000000..5ecd254
--- /dev/null
+++ b/internal/game/account_registration_regression_test.go
@@ -0,0 +1,55 @@
+package game
+
+// Registration regression: a pending new-account session whose typed name
+// was created in the meantime (by another concurrent registration) must be
+// refused at confirm time, never overwrite the existing account's password
+// or character list.
+
+import (
+ "testing"
+
+ "thehouseoficarus/internal/net"
+ "thehouseoficarus/internal/player"
+)
+
+func TestPendingRegistrationCannotOverwriteExistingAccount(t *testing.T) {
+ h := newHarness(t)
+ h.seedAccount("alice", "pw", false)
+ p := h.seedCharacter("alice", "alice")
+
+ a := &net.Session{Conn: newChanConn(), State: net.StateAccountName}
+ b := &net.Session{Conn: newChanConn(), State: net.StateAccountName}
+ h.g.RunOnOwner(func() {
+ // Both sessions type the same name while it does not exist yet;
+ // both reach the password-confirmation state.
+ h.g.handleAccountName(a, "wait")
+ h.g.handleAccountName(b, "wait")
+ h.g.handleNewPass(a, "firstpassword")
+ h.g.handleNewPass(b, "otherpassword")
+ // Session a wins the creation race...
+ h.g.handleNewAccount(a, "firstpassword")
+ // ...and a character is attached to the account before b confirms.
+ acc, err := h.g.AccountStore.LoadAccount("wait")
+ if err != nil {
+ t.Error(err)
+ return
+ }
+ acc.Characters = []string{p.Name}
+ if err := h.g.AccountStore.SaveAccount(acc); err != nil {
+ t.Error(err)
+ return
+ }
+ // Session b confirms second: this must not clobber the account.
+ h.g.handleNewAccount(b, "otherpassword")
+ })
+ acc, err := h.g.AccountStore.LoadAccount("wait")
+ if err != nil {
+ t.Fatal(err)
+ }
+ if !player.CheckPassword("firstpassword", acc.PasswordHash) {
+ t.Errorf("winner's password was overwritten by the losing registration")
+ }
+ if len(acc.Characters) != 1 {
+ t.Errorf("character list destroyed by the losing registration: %v", acc.Characters)
+ }
+}