mirror of
https://github.com/matrix-org/dendrite.git
synced 2025-12-07 15:03:09 -06:00
#1963 issue : Added more requirements for password
Key Features: Password Configuration: The PasswordConfig struct allows customization of the password validation requirements. This can be extended to include more complex policies as needed. YAML Configuration: The PasswordConfig struct could be loaded from a YAML file, enabling dynamic adjustment of the password requirements without code changes. Password Validation: The ValidatePassword function checks the length, presence of uppercase letters, lowercase letters, digits, and special characters based on the provided configuration. Sidecar Feature: A placeholder sidecarLogPasswordValidation function is included, where you could integrate with a logging service to track password validation attempts. Signed-off-by: AllMightLegend srinjoysen123@gmail.com
This commit is contained in:
parent
8c6cf51b8f
commit
18eed12d40
|
|
@ -28,47 +28,97 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
maxUsernameLength = 254 // https://spec.matrix.org/v1.7/appendices/#user-identifiers TODO account for domain
|
minPasswordLength = 8 // Minimum password length
|
||||||
|
maxPasswordLength = 512 // Maximum password length
|
||||||
minPasswordLength = 8 // http://matrix.org/docs/spec/client_server/r0.2.0.html#password-based
|
maxUsernameLength = 254 // Maximum username length
|
||||||
maxPasswordLength = 512 // https://github.com/matrix-org/synapse/blob/v0.20.0/synapse/rest/client/v2_alpha/register.py#L161
|
sessionIDLength = 24 // Session ID length
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
ErrPasswordTooLong = fmt.Errorf("password too long: max %d characters", maxPasswordLength)
|
ErrPasswordTooLong = errors.New("password is too long")
|
||||||
ErrPasswordWeak = fmt.Errorf("password too weak: min %d characters", minPasswordLength)
|
ErrPasswordWeak = errors.New("password does not meet the strength requirements")
|
||||||
ErrUsernameTooLong = fmt.Errorf("username exceeds the maximum length of %d characters", maxUsernameLength)
|
ErrUsernameTooLong = fmt.Errorf("username exceeds the maximum length of %d characters", maxUsernameLength)
|
||||||
ErrUsernameInvalid = errors.New("username can only contain characters a-z, 0-9, or '_+-./='")
|
ErrUsernameInvalid = errors.New("username can only contain characters a-z, 0-9, or '_+-./='")
|
||||||
ErrUsernameUnderscore = errors.New("username cannot start with a '_'")
|
ErrUsernameUnderscore = errors.New("username cannot start with a '_'")
|
||||||
validUsernameRegex = regexp.MustCompile(`^[0-9a-z_\-+=./]+$`)
|
validUsernameRegex = regexp.MustCompile(`^[0-9a-z_\-+=./]+$`)
|
||||||
)
|
)
|
||||||
|
|
||||||
// ValidatePassword returns an error if the password is invalid
|
// PasswordConfig defines the configurable parameters for password validation
|
||||||
func ValidatePassword(password string) error {
|
type PasswordConfig struct {
|
||||||
// https://github.com/matrix-org/synapse/blob/v0.20.0/synapse/rest/client/v2_alpha/register.py#L161
|
MinLength int `yaml:"min_length"`
|
||||||
if len(password) > maxPasswordLength {
|
MaxLength int `yaml:"max_length"`
|
||||||
|
RequireUppercase bool `yaml:"require_uppercase"`
|
||||||
|
RequireLowercase bool `yaml:"require_lowercase"`
|
||||||
|
RequireDigit bool `yaml:"require_digit"`
|
||||||
|
RequireSpecial bool `yaml:"require_special"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Default password config
|
||||||
|
var defaultPasswordConfig = PasswordConfig{
|
||||||
|
MinLength: minPasswordLength,
|
||||||
|
MaxLength: maxPasswordLength,
|
||||||
|
RequireUppercase: true,
|
||||||
|
RequireLowercase: true,
|
||||||
|
RequireDigit: true,
|
||||||
|
RequireSpecial: true,
|
||||||
|
}
|
||||||
|
|
||||||
|
// ValidatePassword returns an error if the password is invalid according to the config
|
||||||
|
func ValidatePassword(password string, config PasswordConfig) error {
|
||||||
|
if len(password) > config.MaxLength {
|
||||||
return ErrPasswordTooLong
|
return ErrPasswordTooLong
|
||||||
} else if len(password) > 0 && len(password) < minPasswordLength {
|
} else if len(password) < config.MinLength {
|
||||||
return ErrPasswordWeak
|
return ErrPasswordWeak
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var hasUppercase, hasLowercase, hasDigit, hasSpecial bool
|
||||||
|
for _, char := range password {
|
||||||
|
switch {
|
||||||
|
case unicode.IsUpper(char):
|
||||||
|
hasUppercase = true
|
||||||
|
case unicode.IsLower(char):
|
||||||
|
hasLowercase = true
|
||||||
|
case unicode.IsDigit(char):
|
||||||
|
hasDigit = true
|
||||||
|
case unicode.IsPunct(char) || unicode.IsSymbol(char):
|
||||||
|
hasSpecial = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if config.RequireUppercase && !hasUppercase {
|
||||||
|
return ErrPasswordWeak
|
||||||
|
}
|
||||||
|
if config.RequireLowercase && !hasLowercase {
|
||||||
|
return ErrPasswordWeak
|
||||||
|
}
|
||||||
|
if config.RequireDigit && !hasDigit {
|
||||||
|
return ErrPasswordWeak
|
||||||
|
}
|
||||||
|
if config.RequireSpecial && !hasSpecial {
|
||||||
|
return ErrPasswordWeak
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sidecar: Log the password validation attempt (placeholder)
|
||||||
|
sidecarLogPasswordValidation(password)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// PasswordResponse returns a util.JSONResponse for a given error, if any.
|
// Sidecar function to log password validation attempts
|
||||||
func PasswordResponse(err error) *util.JSONResponse {
|
func sidecarLogPasswordValidation(password string) {
|
||||||
switch err {
|
// Placeholder for sidecar logging
|
||||||
case ErrPasswordWeak:
|
fmt.Println("Sidecar log: Password validation attempted")
|
||||||
return &util.JSONResponse{
|
}
|
||||||
Code: http.StatusBadRequest,
|
|
||||||
JSON: spec.WeakPassword(ErrPasswordWeak.Error()),
|
func main() {
|
||||||
}
|
// Example usage
|
||||||
case ErrPasswordTooLong:
|
password := "P@ssw0rd"
|
||||||
return &util.JSONResponse{
|
err := ValidatePassword(password, defaultPasswordConfig)
|
||||||
Code: http.StatusBadRequest,
|
if err != nil {
|
||||||
JSON: spec.BadJSON(ErrPasswordTooLong.Error()),
|
fmt.Println("Password validation failed:", err)
|
||||||
}
|
} else {
|
||||||
|
fmt.Println("Password is valid")
|
||||||
}
|
}
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ValidateUsername returns an error if the username is invalid
|
// ValidateUsername returns an error if the username is invalid
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue