mirror of
https://codeberg.org/shroff/phylum.git
synced 2026-01-03 18:20:53 -06:00
[client] Password strength validation
This commit is contained in:
@@ -12,6 +12,11 @@ storage:
|
||||
|
||||
user:
|
||||
password:
|
||||
length: 12
|
||||
lower: 1
|
||||
upper: 1
|
||||
numeric: 1
|
||||
symbols: 1
|
||||
basedir: /home
|
||||
perimission: 0
|
||||
|
||||
|
||||
@@ -7,4 +7,9 @@ type Config struct {
|
||||
}
|
||||
|
||||
type PasswordConfig struct {
|
||||
Length int `koanf:"length"`
|
||||
Lower int `koanf:"lower"`
|
||||
Upper int `koanf:"upper"`
|
||||
Numeric int `koanf:"numeric"`
|
||||
Symbols int `koanf:"symbols"`
|
||||
}
|
||||
|
||||
59
server/internal/core/user/password.go
Normal file
59
server/internal/core/user/password.go
Normal file
@@ -0,0 +1,59 @@
|
||||
package user
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"strconv"
|
||||
|
||||
"github.com/shroff/phylum/server/internal/core/errors"
|
||||
)
|
||||
|
||||
type charType int
|
||||
|
||||
const (
|
||||
charTypeOther charType = iota
|
||||
charTypeLower
|
||||
charTypeUpper
|
||||
charTypeNumeric
|
||||
charTypeSymbol
|
||||
)
|
||||
|
||||
var charTypes = map[rune]charType{}
|
||||
|
||||
func init() {
|
||||
for _, c := range "abcdefghijklmnopqrstuvwxyz" {
|
||||
charTypes[c] = charTypeLower
|
||||
}
|
||||
for _, c := range "ABCDEFGHIJKLMNOPQRSTUVWXYZ" {
|
||||
charTypes[c] = charTypeUpper
|
||||
}
|
||||
for _, c := range "0123456789" {
|
||||
charTypes[c] = charTypeNumeric
|
||||
}
|
||||
for _, c := range "`~!@#$%^&*()-_=+[]{}\\|;:'\",.<>/?" {
|
||||
charTypes[c] = charTypeSymbol
|
||||
}
|
||||
}
|
||||
|
||||
func checkPasswordStrength(password string) error {
|
||||
if len(password) < Cfg.Password.Length {
|
||||
return errors.NewError(http.StatusBadRequest, "password_invalid", "Must be at least "+strconv.Itoa(Cfg.Password.Length)+" characters long.")
|
||||
}
|
||||
count := map[charType]int{}
|
||||
for _, c := range password {
|
||||
count[charTypes[c]]++
|
||||
}
|
||||
|
||||
if count[charTypeLower] < Cfg.Password.Lower {
|
||||
return errors.NewError(http.StatusBadRequest, "password_invalid", "Must have at least "+strconv.Itoa(Cfg.Password.Lower)+" lower case.")
|
||||
}
|
||||
if count[charTypeUpper] < Cfg.Password.Upper {
|
||||
return errors.NewError(http.StatusBadRequest, "password_invalid", "Must have at least "+strconv.Itoa(Cfg.Password.Upper)+" upper case.")
|
||||
}
|
||||
if count[charTypeNumeric] < Cfg.Password.Numeric {
|
||||
return errors.NewError(http.StatusBadRequest, "password_invalid", "Must have at least "+strconv.Itoa(Cfg.Password.Numeric)+" numeric.")
|
||||
}
|
||||
if count[charTypeSymbol] < Cfg.Password.Symbols {
|
||||
return errors.NewError(http.StatusBadRequest, "password_invalid", "Must have at least "+strconv.Itoa(Cfg.Password.Symbols)+" symbols.")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -22,6 +22,10 @@ func (m manager) UpdateUserName(user User, name string) error {
|
||||
}
|
||||
|
||||
func (m manager) UpdateUserPassword(user User, password string) error {
|
||||
if err := checkPasswordStrength(password); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
const q = "UPDATE users SET password_hash = $2::TEXT, modified = NOW() WHERE id = $1::INT"
|
||||
if hash, err := crypt.Generate(password); err != nil {
|
||||
return err
|
||||
|
||||
Reference in New Issue
Block a user