package handler import "testing" // bcrypt hash of "test-password" at the minimum cost, so the test stays fast. const testHash = "$2a$04$6h5pthPxQs2muU4eCZjhReZlMvwf7XP9HUKCEubLMQZsR/84fHs0i" func TestVerifyPassword(t *testing.T) { if !VerifyPassword(testHash, "test-password") { t.Error("the right password did not verify") } for _, pw := range []string{"", "test-passwor", "test-password ", "Test-Password", testHash} { if VerifyPassword(testHash, pw) { t.Errorf("password %q verified against a hash of something else", pw) } } } func TestValidatePasswordHash(t *testing.T) { if err := ValidatePasswordHash(testHash); err != nil { t.Errorf("a valid hash was rejected: %v", err) } // htpasswd writes $2y$; the README tells operators to use it, so it has to work. if err := ValidatePasswordHash("$2y$04$6h5pthPxQs2muU4eCZjhReZlMvwf7XP9HUKCEubLMQZsR/84fHs0i"); err != nil { t.Errorf("a $2y$ hash was rejected: %v", err) } // Every one of these is a plausible misconfiguration that must fail at startup. for name, encoded := range map[string]string{ "empty": "", "plaintext": "test-password", "argon2id": "$argon2id$v=19$m=4096,t=1,p=1$dmlkYXJjaGl2ZXRlc3QwMQ$+Y2TzOaB1vDgGkOgclcj+Q0xYIcRBZf5wh616yVaJCQ", "truncated": "$2a$04$6h5pthPxQs2muU4eCZjhRe", "no cost": "$2a$6h5pthPxQs2muU4eCZjhReZlMvwf7XP9HUKCEubLMQZsR/84fHs0i", "bogus cost": "$2a$zz$6h5pthPxQs2muU4eCZjhReZlMvwf7XP9HUKCEubLMQZsR/84fHs0i", // Accepted by bcrypt, but a login against it would take hours. "absurd cost": "$2a$31$6h5pthPxQs2muU4eCZjhReZlMvwf7XP9HUKCEubLMQZsR/84fHs0i", } { if err := ValidatePasswordHash(encoded); err == nil { t.Errorf("%s hash was accepted", name) } if VerifyPassword(encoded, "test-password") { t.Errorf("%s hash verified a password", name) } } } func TestPublicPaths(t *testing.T) { for _, path := range []string{"/login", "/healthz", "/static/style.css"} { if !publicPath(path) { t.Errorf("%s is guarded, so the login page cannot work", path) } } for _, path := range []string{"/", "/library", "/queue", "/settings", "/media/item/x", "/logins"} { if publicPath(path) { t.Errorf("%s is reachable without a session", path) } } }