Auth: Reduce bcrypt cost for faster login on small devices #3718

Signed-off-by: Michael Mayer <michael@photoprism.app>
This commit is contained in:
Michael Mayer 2023-09-12 09:36:23 +02:00
parent 311288312e
commit 096b306420
2 changed files with 14 additions and 14 deletions

View file

@ -10,9 +10,9 @@ import (
"github.com/photoprism/photoprism/pkg/txt" "github.com/photoprism/photoprism/pkg/txt"
) )
var ( // DefaultPasswordCost specifies the cost of the BCrypt Password Hash,
PasswordCost = 14 // see https://github.com/photoprism/photoprism/issues/3718.
) var DefaultPasswordCost = 12
// Password represents a password hash. // Password represents a password hash.
type Password struct { type Password struct {
@ -64,8 +64,8 @@ func (m *Password) SetPassword(pw string, allowHash bool) error {
} }
} }
// Generate hash from plain text string. // Generate hash from plain text string using the default password cost.
if bytes, err := bcrypt.GenerateFromPassword([]byte(pw), PasswordCost); err != nil { if bytes, err := bcrypt.GenerateFromPassword([]byte(pw), DefaultPasswordCost); err != nil {
return err return err
} else { } else {
m.Hash = string(bytes) m.Hash = string(bytes)
@ -125,12 +125,12 @@ func (m *Password) Cost() (int, error) {
return bcrypt.Cost([]byte(m.Hash)) return bcrypt.Cost([]byte(m.Hash))
} }
// IsEmpty returns true if the password is not set. // IsEmpty returns true if no password is set.
func (m *Password) IsEmpty() bool { func (m *Password) IsEmpty() bool {
return m.Hash == "" return m.Hash == ""
} }
// String returns the password hash. // String returns the BCrypt Password Hash.
func (m *Password) String() string { func (m *Password) String() string {
return m.Hash return m.Hash
} }

View file

@ -143,15 +143,15 @@ func TestFindPassword(t *testing.T) {
} }
func TestPassword_Cost(t *testing.T) { func TestPassword_Cost(t *testing.T) {
t.Run("Default", func(t *testing.T) { t.Run("DefaultPasswordCost", func(t *testing.T) {
p := NewPassword("urrwaxd19ldtz68x", "photoprism", false) p := NewPassword("urrwaxd19ldtz68x", "photoprism", false)
if cost, err := p.Cost(); err != nil { if cost, err := p.Cost(); err != nil {
t.Fatal(err) t.Fatal(err)
} else { } else {
assert.Equal(t, PasswordCost, cost) assert.Equal(t, DefaultPasswordCost, cost)
} }
}) })
t.Run("14", func(t *testing.T) { t.Run("PasswordCost14", func(t *testing.T) {
p := NewPassword("urrwaxd19ldtz68x", "$2a$14$qCcNjxupSJV1gjhgdYxz8e9l0e0fTZosX0s0qhMK54IkI9YOyWLt2", true) p := NewPassword("urrwaxd19ldtz68x", "$2a$14$qCcNjxupSJV1gjhgdYxz8e9l0e0fTZosX0s0qhMK54IkI9YOyWLt2", true)
if cost, err := p.Cost(); err != nil { if cost, err := p.Cost(); err != nil {
t.Fatal(err) t.Fatal(err)
@ -159,7 +159,7 @@ func TestPassword_Cost(t *testing.T) {
assert.Equal(t, 14, cost) assert.Equal(t, 14, cost)
} }
}) })
t.Run("empty password", func(t *testing.T) { t.Run("EmptyPassword", func(t *testing.T) {
p := NewPassword("urrwaxd19ldtz68x", "", false) p := NewPassword("urrwaxd19ldtz68x", "", false)
_, err := p.Cost() _, err := p.Cost()
assert.Error(t, err) assert.Error(t, err)
@ -167,18 +167,18 @@ func TestPassword_Cost(t *testing.T) {
} }
func TestPassword_String(t *testing.T) { func TestPassword_String(t *testing.T) {
t.Run("return string", func(t *testing.T) { t.Run("BCrypt", func(t *testing.T) {
p := NewPassword("urrwaxd19ldtz68x", "lkjhgtyu", false) p := NewPassword("urrwaxd19ldtz68x", "lkjhgtyu", false)
assert.Len(t, p.String(), 60) assert.Len(t, p.String(), 60)
}) })
} }
func TestPassword_IsEmpty(t *testing.T) { func TestPassword_IsEmpty(t *testing.T) {
t.Run("false", func(t *testing.T) { t.Run("False", func(t *testing.T) {
p := NewPassword("urrwaxd19ldtz68x", "lkjhgtyu", false) p := NewPassword("urrwaxd19ldtz68x", "lkjhgtyu", false)
assert.False(t, p.IsEmpty()) assert.False(t, p.IsEmpty())
}) })
t.Run("true", func(t *testing.T) { t.Run("True", func(t *testing.T) {
p := Password{} p := Password{}
assert.True(t, p.IsEmpty()) assert.True(t, p.IsEmpty())
}) })