package util import ( "crypto/sha256" "encoding/hex" "strings" "testing" ) // Здесь был TestSHA224String, который печатал хеш в stdout и ничего не // проверял. Вместе с самой функцией он удалён: формат хранения паролей // предыдущего поколения в v1 недостижим, а тест, не содержащий утверждений, // создавал видимость покрытия. func TestHashPasswordProducesBcrypt(t *testing.T) { hash, err := HashPassword("correct horse battery staple") if err != nil { t.Fatalf("HashPassword: %v", err) } if !IsBcryptHash(hash) { t.Fatalf("HashPassword вернул не bcrypt: %q", hash) } } // Соль обязана делать два хеша одного пароля различными: именно этого не // давал прежний несолёный SHA-224. func TestHashPasswordIsSalted(t *testing.T) { first, err := HashPassword("one password for both") if err != nil { t.Fatalf("HashPassword: %v", err) } second, err := HashPassword("one password for both") if err != nil { t.Fatalf("HashPassword: %v", err) } if first == second { t.Fatal("два хеша одного пароля совпали: соль не применяется") } if !VerifyPassword("one password for both", first) || !VerifyPassword("one password for both", second) { t.Fatal("солёные хеши не проходят проверку") } } func TestHashPasswordRejectsShortPassword(t *testing.T) { if _, err := HashPassword("12345"); err == nil { t.Fatal("слишком короткий пароль принят") } if _, err := HashPassword(" "); err == nil { t.Fatal("пароль из пробелов принят") } } func TestVerifyPasswordAcceptsOnlyCorrectPassword(t *testing.T) { hash, err := HashPassword("s3cret-passphrase") if err != nil { t.Fatalf("HashPassword: %v", err) } if !VerifyPassword("s3cret-passphrase", hash) { t.Error("верный пароль отклонён") } if VerifyPassword("s3cret-passphras", hash) { t.Error("неверный пароль принят") } if VerifyPassword("", hash) { t.Error("пустой пароль принят") } } // Главная регрессия: несолёный SHA-224 из предыдущего поколения больше не // является допустимым форматом хранения. Раньше VerifyPassword сравнивал с ним // напрямую и возвращал признак legacy, то есть вход по такому хешу удавался. func TestVerifyPasswordRejectsLegacySha224Hash(t *testing.T) { password := "sysadmin" sum := sha256.Sum224([]byte(password)) legacyHash := hex.EncodeToString(sum[:]) if VerifyPassword(password, legacyHash) { t.Fatal("вход по несолёному SHA-224 всё ещё возможен") } if IsBcryptHash(legacyHash) { t.Fatal("SHA-224 опознан как bcrypt") } } // Любая строка, не являющаяся bcrypt-хешем, — повреждённое или подменённое // значение в базе, а не «другой формат». func TestVerifyPasswordRejectsNonBcryptStorage(t *testing.T) { for _, stored := range []string{ "", "plaintext-password", "$1$abcdefgh$0123456789abcdef", "$argon2id$v=19$m=65536,t=3,p=4$c29tZXNhbHQ$hash", strings.Repeat("a", 60), } { if VerifyPassword("plaintext-password", stored) { t.Errorf("принят пароль против не-bcrypt значения %q", stored) } } }