Files
mcias/internal/validate/validate_test.go
Kyle Isom 0ad9ef1bb4 Fix F-08, F-12, F-13: Implement account lockout, username validation, and password minimum length enforcement
- Added failed login tracking for account lockout enforcement in `db` and `ui` layers; introduced `failed_logins` table to store attempts, window start, and attempt count.
- Updated login checks in `grpcserver/auth.go` and `ui/handlers_auth.go` to reject requests if the account is locked.
- Added immediate failure counter reset on successful login.
- Implemented username length and character set validation (F-12) and minimum password length enforcement (F-13) in shared `validate` package.
- Updated account creation and edit flows in `ui` and `grpcserver` layers to apply validation before hashing/processing.
- Added comprehensive unit tests for lockout, validation, and related edge cases.
- Updated `AUDIT.md` to mark F-08, F-12, and F-13 as fixed.
- Updated `openapi.yaml` to reflect new validation and lockout behaviors.

Security: Prevents brute-force attacks via lockout mechanism and strengthens defenses against weak and invalid input.
2026-03-11 20:59:26 -07:00

73 lines
1.7 KiB
Go

package validate
import (
"strings"
"testing"
)
func TestPasswordValid(t *testing.T) {
valid := []string{
strings.Repeat("a", MinPasswordLen),
strings.Repeat("a", MinPasswordLen+1),
"correct horse battery staple",
"P@ssw0rd!2024XY",
}
for _, p := range valid {
if err := Password(p); err != nil {
t.Errorf("Password(%q) = %v, want nil", p, err)
}
}
}
func TestPasswordTooShort(t *testing.T) {
short := []string{
"",
"short",
strings.Repeat("a", MinPasswordLen-1),
}
for _, p := range short {
if err := Password(p); err == nil {
t.Errorf("Password(%q) = nil, want error", p)
}
}
}
func TestUsernameValid(t *testing.T) {
valid := []string{
"alice",
"Bob123",
"user.name",
"user_name",
"user-name",
"user@domain",
"a",
strings.Repeat("a", MaxUsernameLen),
}
for _, u := range valid {
if err := Username(u); err != nil {
t.Errorf("Username(%q) = %v, want nil", u, err)
}
}
}
func TestUsernameInvalid(t *testing.T) {
invalid := []string{
"", // empty
strings.Repeat("a", MaxUsernameLen+1), // too long
"user name", // space
"user\tname", // tab
"user\nname", // newline
"user\x00name", // null byte
"user<script>", // angle bracket
"user'quote", // single quote
"user\"quote", // double quote
"user/slash", // slash
"user\\backslash", // backslash
}
for _, u := range invalid {
if err := Username(u); err == nil {
t.Errorf("Username(%q) = nil, want error", u)
}
}
}