package auth import ( "errors" "strings" "testing" ) func TestHashAndVerify(t *testing.T) { const pw = "correct horse battery staple" encoded, err := HashPassword(pw) if err != nil { t.Fatalf("HashPassword: %v", err) } if !strings.HasPrefix(encoded, "$argon2id$") { t.Errorf("hash %q is not an argon2id PHC string", encoded) } ok, err := VerifyPassword(pw, encoded) if err != nil { t.Fatalf("VerifyPassword: %v", err) } if !ok { t.Error("correct password did not verify") } ok, err = VerifyPassword("wrong password", encoded) if err != nil { t.Fatalf("VerifyPassword(wrong): %v", err) } if ok { t.Error("wrong password verified") } } func TestHashIsSalted(t *testing.T) { a, err := HashPassword("same password") if err != nil { t.Fatal(err) } b, err := HashPassword("same password") if err != nil { t.Fatal(err) } if a == b { t.Error("two hashes of the same password are identical; salt is not random") } } func TestVerifyRejectsMalformedHash(t *testing.T) { for _, bad := range []string{ "", "not-a-hash", "$argon2id$v=19$m=65536,t=2,p=4$onlyonefield", "$bcrypt$v=19$m=65536,t=2,p=4$c2FsdA$aGFzaA", } { if _, err := VerifyPassword("x", bad); err == nil { t.Errorf("VerifyPassword(%q) succeeded, want error", bad) } else if !errors.Is(err, ErrInvalidHash) { t.Errorf("VerifyPassword(%q) error = %v, want ErrInvalidHash", bad, err) } } } func TestVerifyRejectsFutureArgonVersion(t *testing.T) { h, err := HashPassword("x") if err != nil { t.Fatal(err) } bumped := strings.Replace(h, "v=19", "v=20", 1) if _, err := VerifyPassword("x", bumped); !errors.Is(err, ErrIncompatibleVersion) { t.Errorf("error = %v, want ErrIncompatibleVersion", err) } }