CLI: Improve length check in "photoprism passwd" command #3482

Signed-off-by: Michael Mayer <michael@photoprism.app>
This commit is contained in:
Michael Mayer 2023-06-19 17:24:02 +02:00
parent 054a0764c5
commit 87b6d72477
6 changed files with 26 additions and 19 deletions

View file

@ -15,6 +15,7 @@ import (
"github.com/photoprism/photoprism/internal/entity" "github.com/photoprism/photoprism/internal/entity"
"github.com/photoprism/photoprism/pkg/clean" "github.com/photoprism/photoprism/pkg/clean"
"github.com/photoprism/photoprism/pkg/rnd" "github.com/photoprism/photoprism/pkg/rnd"
"github.com/photoprism/photoprism/pkg/txt"
) )
// PasswdCommand configures the command name, flags, and action. // PasswdCommand configures the command name, flags, and action.
@ -67,12 +68,14 @@ func passwdAction(ctx *cli.Context) error {
return fmt.Errorf("user %s has been deleted", clean.LogQuote(id)) return fmt.Errorf("user %s has been deleted", clean.LogQuote(id))
} }
log.Infof("please enter a new password for %s (minimum %d characters)\n", clean.Log(m.Username()), entity.PasswordLength) log.Infof("please enter a new password for %s (%d-%d characters)\n", clean.Log(m.Username()), entity.PasswordLength, txt.ClipPassword)
newPassword := getPassword("New Password: ") newPassword := getPassword("New Password: ")
if len(newPassword) < 6 { if len([]rune(newPassword)) < entity.PasswordLength {
return errors.New("new password is too short, please try again") return fmt.Errorf("password must have at least %d characters", entity.PasswordLength)
} else if len(newPassword) > txt.ClipPassword {
return fmt.Errorf("password must have less than %d characters", txt.ClipPassword)
} }
retypePassword := getPassword("Retype Password: ") retypePassword := getPassword("Retype Password: ")

View file

@ -11,6 +11,7 @@ import (
"github.com/photoprism/photoprism/internal/entity" "github.com/photoprism/photoprism/internal/entity"
"github.com/photoprism/photoprism/internal/form" "github.com/photoprism/photoprism/internal/form"
"github.com/photoprism/photoprism/pkg/clean" "github.com/photoprism/photoprism/pkg/clean"
"github.com/photoprism/photoprism/pkg/txt"
) )
// UsersAddCommand configures the command name, flags, and action. // UsersAddCommand configures the command name, flags, and action.
@ -90,10 +91,12 @@ func usersAddAction(ctx *cli.Context) error {
frm.UserEmail = clean.Email(res) frm.UserEmail = clean.Email(res)
} }
if interactive && len(ctx.String("password")) < entity.PasswordLength { if interactive && len([]rune(ctx.String("password"))) < entity.PasswordLength {
validate := func(input string) error { validate := func(input string) error {
if len(input) < entity.PasswordLength { if len([]rune(input)) < entity.PasswordLength {
return fmt.Errorf("password must have at least %d characters", entity.PasswordLength) return fmt.Errorf("password must have at least %d characters", entity.PasswordLength)
} else if len(input) > txt.ClipPassword {
return fmt.Errorf("password must have less than %d characters", txt.ClipPassword)
} }
return nil return nil
} }

View file

@ -31,7 +31,7 @@ const (
// UsernameLength specifies the minimum length of the username in characters. // UsernameLength specifies the minimum length of the username in characters.
var UsernameLength = 1 var UsernameLength = 1
// PasswordLength specifies the minimum length of the password in characters. // PasswordLength specifies the minimum length of a password in characters (runes, not bytes).
var PasswordLength = 4 var PasswordLength = 4
// UsersPath is the relative path for user assets. // UsersPath is the relative path for user assets.
@ -768,8 +768,10 @@ func (m *User) SetPassword(password string) error {
return fmt.Errorf("only registered users can change their password") return fmt.Errorf("only registered users can change their password")
} }
if len(password) < PasswordLength { if len([]rune(password)) < PasswordLength {
return fmt.Errorf("password must have at least %d characters", PasswordLength) return fmt.Errorf("password must have at least %d characters", PasswordLength)
} else if len(password) > txt.ClipPassword {
return fmt.Errorf("password must have less than %d characters", txt.ClipPassword)
} }
pw := NewPassword(m.UserUID, password, false) pw := NewPassword(m.UserUID, password, false)

View file

@ -7,14 +7,17 @@ import (
"github.com/photoprism/photoprism/internal/form" "github.com/photoprism/photoprism/internal/form"
"github.com/photoprism/photoprism/pkg/clean" "github.com/photoprism/photoprism/pkg/clean"
"github.com/photoprism/photoprism/pkg/txt"
) )
// AddUser creates a new user record and sets the password in a single transaction. // AddUser creates a new user record and sets the password in a single transaction.
func AddUser(frm form.User) error { func AddUser(frm form.User) error {
user := NewUser().SetFormValues(frm) user := NewUser().SetFormValues(frm)
if len(frm.Password) < PasswordLength { if len([]rune(frm.Password)) < PasswordLength {
return fmt.Errorf("password must have at least %d characters", PasswordLength) return fmt.Errorf("password must have at least %d characters", PasswordLength)
} else if len(frm.Password) > txt.ClipPassword {
return fmt.Errorf("password must have less than %d characters", txt.ClipPassword)
} }
if err := user.Validate(); err != nil { if err := user.Validate(); err != nil {

View file

@ -46,12 +46,14 @@ func NewPassword(uid, pw string, allowHash bool) Password {
// SetPassword sets a new password stored as hash. // SetPassword sets a new password stored as hash.
func (m *Password) SetPassword(pw string, allowHash bool) error { func (m *Password) SetPassword(pw string, allowHash bool) error {
// Remove leading and trailing white space.
pw = clean.Password(pw) pw = clean.Password(pw)
if l := len(pw); l > txt.ClipPassword { // Check if password is too short or too long.
return fmt.Errorf("password is too long") if len([]rune(pw)) < 1 {
} else if l < 1 {
return fmt.Errorf("password is too short") return fmt.Errorf("password is too short")
} else if len(pw) > txt.ClipPassword {
return fmt.Errorf("password must have less than %d characters", txt.ClipPassword)
} }
// Check if string already is a bcrypt hash. // Check if string already is a bcrypt hash.

View file

@ -109,13 +109,7 @@ func Attr(s string) string {
return list.ParseAttr(s).String() return list.ParseAttr(s).String()
} }
// Password returns the sanitized password string with trimmed whitespace. // Password returns the password string with all leading and trailing white space removed.
func Password(s string) string { func Password(s string) string {
s = strings.TrimSpace(s) return strings.TrimSpace(s)
if s == "" || reject(s, txt.ClipPassword) {
return ""
}
return s
} }