focalboard/server/services/auth/password.go

107 lines
2.7 KiB
Go
Raw Normal View History

2020-10-28 14:35:41 +01:00
package auth
import (
"fmt"
"strings"
"golang.org/x/crypto/bcrypt"
)
const (
PasswordMaximumLength = 64
PasswordSpecialChars = "!\"\\#$%&'()*+,-./:;<=>?@[]^_`|~" //nolint:gosec
2020-10-28 14:35:41 +01:00
PasswordNumbers = "0123456789"
PasswordUpperCaseLetters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
PasswordLowerCaseLetters = "abcdefghijklmnopqrstuvwxyz"
PasswordAllChars = PasswordSpecialChars + PasswordNumbers + PasswordUpperCaseLetters + PasswordLowerCaseLetters
InvalidLowercasePassword = "lowercase"
InvalidMinLengthPassword = "min-length"
InvalidMaxLengthPassword = "max-length"
InvalidNumberPassword = "number"
InvalidUppercasePassword = "uppercase"
InvalidSymbolPassword = "symbol"
)
var PasswordHashStrength = 10
// HashPassword generates a hash using the bcrypt.GenerateFromPassword.
2020-10-28 14:35:41 +01:00
func HashPassword(password string) string {
hash, err := bcrypt.GenerateFromPassword([]byte(password), PasswordHashStrength)
2020-10-28 14:35:41 +01:00
if err != nil {
panic(err)
}
return string(hash)
}
// ComparePassword compares the hash.
2021-03-21 09:28:26 +01:00
func ComparePassword(hash, password string) bool {
2020-10-28 14:35:41 +01:00
if len(password) == 0 || len(hash) == 0 {
return false
}
err := bcrypt.CompareHashAndPassword([]byte(hash), []byte(password))
return err == nil
}
type InvalidPasswordError struct {
FailingCriterias []string
}
func (ipe *InvalidPasswordError) Error() string {
return fmt.Sprintf("invalid password, failing criteria: %s", strings.Join(ipe.FailingCriterias, ", "))
2020-10-28 14:35:41 +01:00
}
type PasswordSettings struct {
MinimumLength int
Lowercase bool
Number bool
Uppercase bool
Symbol bool
}
2020-11-06 16:46:35 +01:00
func IsPasswordValid(password string, settings PasswordSettings) error {
2020-10-28 14:35:41 +01:00
err := &InvalidPasswordError{
FailingCriterias: []string{},
}
2020-11-06 16:46:35 +01:00
if len(password) < settings.MinimumLength {
2020-10-28 14:35:41 +01:00
err.FailingCriterias = append(err.FailingCriterias, InvalidMinLengthPassword)
}
if len(password) > PasswordMaximumLength {
err.FailingCriterias = append(err.FailingCriterias, InvalidMaxLengthPassword)
}
2020-11-06 16:46:35 +01:00
if settings.Lowercase {
2020-10-28 14:35:41 +01:00
if !strings.ContainsAny(password, PasswordLowerCaseLetters) {
err.FailingCriterias = append(err.FailingCriterias, InvalidLowercasePassword)
}
}
2020-11-06 16:46:35 +01:00
if settings.Uppercase {
2020-10-28 14:35:41 +01:00
if !strings.ContainsAny(password, PasswordUpperCaseLetters) {
err.FailingCriterias = append(err.FailingCriterias, InvalidUppercasePassword)
}
}
2020-11-06 16:46:35 +01:00
if settings.Number {
2020-10-28 14:35:41 +01:00
if !strings.ContainsAny(password, PasswordNumbers) {
err.FailingCriterias = append(err.FailingCriterias, InvalidNumberPassword)
}
}
2020-11-06 16:46:35 +01:00
if settings.Symbol {
2020-10-28 14:35:41 +01:00
if !strings.ContainsAny(password, PasswordSpecialChars) {
err.FailingCriterias = append(err.FailingCriterias, InvalidSymbolPassword)
}
}
if len(err.FailingCriterias) > 0 {
return err
}
return nil
}