1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
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)
}
}
|