@ -5,24 +5,44 @@
package password
import (
"bytes"
"crypto/rand"
"math/big"
"strings"
"sync"
"code.gitea.io/gitea/modules/context"
"code.gitea.io/gitea/modules/setting"
)
// complexity contains information about a particular kind of password complexity
type complexity struct {
ValidChars string
TrNameOne string
}
var (
matchComplexityOnce sync . Once
validChars string
requiredChars [ ] string
requiredList [ ] complexity
charComplexities = map [ string ] string {
"lower" : ` abcdefghijklmnopqrstuvwxyz ` ,
"upper" : ` ABCDEFGHIJKLMNOPQRSTUVWXYZ ` ,
"digit" : ` 0123456789 ` ,
"spec" : ` !"#$%&'()*+,-./:;<=>?@[\]^_ { |}~ ` + "`" ,
charComplexities = map [ string ] complexity {
"lower" : {
` abcdefghijklmnopqrstuvwxyz ` ,
"form.password_lowercase_one" ,
} ,
"upper" : {
` ABCDEFGHIJKLMNOPQRSTUVWXYZ ` ,
"form.password_uppercase_one" ,
} ,
"digit" : {
` 0123456789 ` ,
"form.password_digit_one" ,
} ,
"spec" : {
` !"#$%&'()*+,-./:;<=>?@[\]^_ { |}~ ` + "`" ,
"form.password_special_one" ,
} ,
}
)
@ -36,22 +56,22 @@ func NewComplexity() {
func setupComplexity ( values [ ] string ) {
if len ( values ) != 1 || values [ 0 ] != "off" {
for _ , val := range values {
if chars , ok := charComplexities [ val ] ; ok {
validChars += chars
requiredChars = append ( requiredChars , chars )
if complex , ok := charComplexities [ val ] ; ok {
validChars += complex . ValidC hars
requiredList = append ( requiredList , complex )
}
}
if len ( requiredChars ) == 0 {
if len ( requiredList ) == 0 {
// No valid character classes found; use all classes as default
for _ , chars := range charComplexities {
validChars += chars
requiredChars = append ( requiredChars , chars )
for _ , complex := range charComplexities {
validChars += complex . ValidC hars
requiredList = append ( requiredList , complex )
}
}
}
if validChars == "" {
// No complexities to check; provide a sensible default for password generation
validChars = charComplexities [ "lower" ] + charComplexities [ "upper" ] + charComplexities [ "digit" ]
validChars = charComplexities [ "lower" ] . ValidChars + charComplexities [ "upper" ] . ValidChars + charComplexities [ "digit" ] . ValidChars
}
}
@ -59,8 +79,8 @@ func setupComplexity(values []string) {
func IsComplexEnough ( pwd string ) bool {
NewComplexity ( )
if len ( validChars ) > 0 {
for _ , req := range requiredChars {
if ! strings . ContainsAny ( req , pwd ) {
for _ , req := range requiredList {
if ! strings . ContainsAny ( req . ValidChars , pwd ) {
return false
}
}
@ -86,3 +106,17 @@ func Generate(n int) (string, error) {
}
}
}
// BuildComplexityError builds the error message when password complexity checks fail
func BuildComplexityError ( ctx * context . Context ) string {
var buffer bytes . Buffer
buffer . WriteString ( ctx . Tr ( "form.password_complexity" ) )
buffer . WriteString ( "<ul>" )
for _ , c := range requiredList {
buffer . WriteString ( "<li>" )
buffer . WriteString ( ctx . Tr ( c . TrNameOne ) )
buffer . WriteString ( "</li>" )
}
buffer . WriteString ( "</ul>" )
return buffer . String ( )
}