55package password
66
77import (
8+ "bytes"
89 "crypto/rand"
910 "math/big"
1011 "strings"
1112 "sync"
1213
14+ "code.gitea.io/gitea/modules/context"
1315 "code.gitea.io/gitea/modules/setting"
1416)
1517
18+ // complexity contains information about a particular kind of password complexity
19+ type complexity struct {
20+ ValidChars string
21+ TrNameOne string
22+ }
23+
1624var (
1725 matchComplexityOnce sync.Once
1826 validChars string
19- requiredChars [] string
27+ requiredList [] complexity
2028
21- charComplexities = map [string ]string {
22- "lower" : `abcdefghijklmnopqrstuvwxyz` ,
23- "upper" : `ABCDEFGHIJKLMNOPQRSTUVWXYZ` ,
24- "digit" : `0123456789` ,
25- "spec" : ` !"#$%&'()*+,-./:;<=>?@[\]^_{|}~` + "`" ,
29+ charComplexities = map [string ]complexity {
30+ "lower" : {
31+ `abcdefghijklmnopqrstuvwxyz` ,
32+ "form.password_lowercase_one" ,
33+ },
34+ "upper" : {
35+ `ABCDEFGHIJKLMNOPQRSTUVWXYZ` ,
36+ "form.password_uppercase_one" ,
37+ },
38+ "digit" : {
39+ `0123456789` ,
40+ "form.password_digit_one" ,
41+ },
42+ "spec" : {
43+ ` !"#$%&'()*+,-./:;<=>?@[\]^_{|}~` + "`" ,
44+ "form.password_special_one" ,
45+ },
2646 }
2747)
2848
@@ -36,31 +56,31 @@ func NewComplexity() {
3656func setupComplexity (values []string ) {
3757 if len (values ) != 1 || values [0 ] != "off" {
3858 for _ , val := range values {
39- if chars , ok := charComplexities [val ]; ok {
40- validChars += chars
41- requiredChars = append (requiredChars , chars )
59+ if complex , ok := charComplexities [val ]; ok {
60+ validChars += complex . ValidChars
61+ requiredList = append (requiredList , complex )
4262 }
4363 }
44- if len (requiredChars ) == 0 {
64+ if len (requiredList ) == 0 {
4565 // No valid character classes found; use all classes as default
46- for _ , chars := range charComplexities {
47- validChars += chars
48- requiredChars = append (requiredChars , chars )
66+ for _ , complex := range charComplexities {
67+ validChars += complex . ValidChars
68+ requiredList = append (requiredList , complex )
4969 }
5070 }
5171 }
5272 if validChars == "" {
5373 // No complexities to check; provide a sensible default for password generation
54- validChars = charComplexities ["lower" ] + charComplexities ["upper" ] + charComplexities ["digit" ]
74+ validChars = charComplexities ["lower" ]. ValidChars + charComplexities ["upper" ]. ValidChars + charComplexities ["digit" ]. ValidChars
5575 }
5676}
5777
5878// IsComplexEnough return True if password meets complexity settings
5979func IsComplexEnough (pwd string ) bool {
6080 NewComplexity ()
6181 if len (validChars ) > 0 {
62- for _ , req := range requiredChars {
63- if ! strings .ContainsAny (req , pwd ) {
82+ for _ , req := range requiredList {
83+ if ! strings .ContainsAny (req . ValidChars , pwd ) {
6484 return false
6585 }
6686 }
@@ -86,3 +106,17 @@ func Generate(n int) (string, error) {
86106 }
87107 }
88108}
109+
110+ // BuildComplexityError builds the error message when password complexity checks fail
111+ func BuildComplexityError (ctx * context.Context ) string {
112+ var buffer bytes.Buffer
113+ buffer .WriteString (ctx .Tr ("form.password_complexity" ))
114+ buffer .WriteString ("<ul>" )
115+ for _ , c := range requiredList {
116+ buffer .WriteString ("<li>" )
117+ buffer .WriteString (ctx .Tr (c .TrNameOne ))
118+ buffer .WriteString ("</li>" )
119+ }
120+ buffer .WriteString ("</ul>" )
121+ return buffer .String ()
122+ }
0 commit comments