You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
96 lines
2.6 KiB
96 lines
2.6 KiB
|
2 months ago
|
package mock
|
||
|
|
|
||
|
|
import (
|
||
|
|
"os"
|
||
|
|
"path/filepath"
|
||
|
|
"testing"
|
||
|
|
"time"
|
||
|
|
|
||
|
|
"tera-clone/services/tera-api/internal/security/password"
|
||
|
|
)
|
||
|
|
|
||
|
|
type startupCountingKDF struct {
|
||
|
|
password.PrototypeSHA256
|
||
|
|
hashes int
|
||
|
|
}
|
||
|
|
|
||
|
|
func (k *startupCountingKDF) Hash(value, salt string) (password.Record, error) {
|
||
|
|
k.hashes++
|
||
|
|
return k.PrototypeSHA256.Hash(value, salt)
|
||
|
|
}
|
||
|
|
|
||
|
|
func TestStartupReusesPersistedAuthWithoutBootstrapHashes(t *testing.T) {
|
||
|
|
path := filepath.Join(t.TempDir(), "auth.json")
|
||
|
|
kdf := &startupCountingKDF{}
|
||
|
|
stages := map[string]bool{}
|
||
|
|
options := StoreOptions{AuthPath: path, PasswordKDF: kdf, RemoveLegacyAuthUsers: true,
|
||
|
|
StartupTiming: func(stage string, elapsed time.Duration, err error) {
|
||
|
|
stages[stage] = true
|
||
|
|
if elapsed < 0 || err != nil {
|
||
|
|
t.Errorf("stage %s: elapsed=%v err=%v", stage, elapsed, err)
|
||
|
|
}
|
||
|
|
},
|
||
|
|
}
|
||
|
|
first, err := NewStoreWithOptions(time.Now, options)
|
||
|
|
if err != nil {
|
||
|
|
t.Fatal(err)
|
||
|
|
}
|
||
|
|
if kdf.hashes != 1 {
|
||
|
|
t.Fatalf("factory boot hashes=%d, want 1", kdf.hashes)
|
||
|
|
}
|
||
|
|
first.Close()
|
||
|
|
before, err := os.ReadFile(path)
|
||
|
|
if err != nil {
|
||
|
|
t.Fatal(err)
|
||
|
|
}
|
||
|
|
kdf.hashes = 0
|
||
|
|
second, err := NewStoreWithOptions(time.Now, options)
|
||
|
|
if err != nil {
|
||
|
|
t.Fatal(err)
|
||
|
|
}
|
||
|
|
defer second.Close()
|
||
|
|
if kdf.hashes != 0 {
|
||
|
|
t.Fatalf("restart hashes=%d, want 0", kdf.hashes)
|
||
|
|
}
|
||
|
|
after, err := os.ReadFile(path)
|
||
|
|
if err != nil {
|
||
|
|
t.Fatal(err)
|
||
|
|
}
|
||
|
|
if string(before) != string(after) {
|
||
|
|
t.Fatal("restart changed persisted credentials")
|
||
|
|
}
|
||
|
|
for _, stage := range []string{"auth.load", "auth.persist", "store.total"} {
|
||
|
|
if !stages[stage] {
|
||
|
|
t.Errorf("missing stage %s", stage)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func TestStartupDoesNotRestoreDeletedAccounts(t *testing.T) {
|
||
|
|
path := filepath.Join(t.TempDir(), "auth.json")
|
||
|
|
if err := os.WriteFile(path, []byte(`{"users":{},"address_filters":{"mode":"blacklist","rules":[]}}`), 0600); err != nil {
|
||
|
|
t.Fatal(err)
|
||
|
|
}
|
||
|
|
kdf := &startupCountingKDF{}
|
||
|
|
s, err := NewStoreWithOptions(time.Now, StoreOptions{AuthPath: path, PasswordKDF: kdf, RemoveLegacyAuthUsers: true})
|
||
|
|
if err != nil {
|
||
|
|
t.Fatal(err)
|
||
|
|
}
|
||
|
|
defer s.Close()
|
||
|
|
if kdf.hashes != 0 || len(s.authUsers) != 0 {
|
||
|
|
t.Fatal("persisted empty inventory was bootstrapped")
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func TestStartupReportsInvalidAuthStore(t *testing.T) {
|
||
|
|
path := filepath.Join(t.TempDir(), "auth.json")
|
||
|
|
if err := os.WriteFile(path, []byte(`{invalid`), 0600); err != nil {
|
||
|
|
t.Fatal(err)
|
||
|
|
}
|
||
|
|
failed := map[string]bool{}
|
||
|
|
_, err := NewStoreWithOptions(time.Now, StoreOptions{AuthPath: path, StartupTiming: func(stage string, _ time.Duration, err error) { failed[stage] = err != nil }})
|
||
|
|
if err == nil || !failed["auth.load"] || !failed["store.total"] {
|
||
|
|
t.Fatalf("missing startup failure: %v %v", err, failed)
|
||
|
|
}
|
||
|
|
}
|