diff --git a/modules/cabana/backend_users_admin.go b/modules/cabana/backend_users_admin.go index bbfa5eda..9b31014f 100644 --- a/modules/cabana/backend_users_admin.go +++ b/modules/cabana/backend_users_admin.go @@ -8,6 +8,7 @@ import ( "strconv" "strings" "time" + "unicode/utf8" "git.golem15.com/golem15/summercms/modules/backpack" "git.golem15.com/golem15/summercms/modules/bouncer" @@ -841,13 +842,24 @@ func submittedPassword(ctx context.Context) string { return plain } +// adminPasswordMinChars is the shortest password the Administrators form +// accepts, in characters (D-11). +const adminPasswordMinChars = 4 + // storePassword hashes a typed password onto user and reports whether one -// was typed. A password over bcrypt's 72-byte limit is a 422 on the field. +// was typed. A password under adminPasswordMinChars characters or over +// bcrypt's 72-byte limit is a 422 on the field. The length is checked here +// because the form's min:4 rule is a string rule, which the model validator +// does not apply. func (c usersAdmin) storePassword(ctx context.Context, user *BackendUser) (bool, error) { plain := submittedPassword(ctx) if plain == "" { return false, nil } + if utf8.RuneCountInString(plain) < adminPasswordMinChars { + message := accountMessage(ctx, c.translator(), "min.string", "password", map[string]string{"min": strconv.Itoa(adminPasswordMinChars)}) + return false, &ValidationError{Details: map[string]any{"password": []string{message}}} + } if len(plain) > passwordMaxBytes { message := accountMessage(ctx, c.translator(), "max.string", "password", map[string]string{"max": strconv.Itoa(passwordMaxBytes)}) return false, &ValidationError{Details: map[string]any{"password": []string{message}}}