github.com/Azareal/Gosora@v0.0.0-20210729070923-553e66b59003/common/weak_passwords.go (about) 1 package common 2 3 import ( 4 "errors" 5 "strconv" 6 "strings" 7 "unicode" 8 ) 9 10 var weakPassStrings []string 11 var weakPassLit = make(map[string]struct{}) 12 var ErrWeakPasswordNone = errors.New("You didn't put in a password.") 13 var ErrWeakPasswordShort = errors.New("Your password needs to be at-least eight characters long") 14 var ErrWeakPasswordNameInPass = errors.New("You can't use your name in your password.") 15 var ErrWeakPasswordEmailInPass = errors.New("You can't use your email in your password.") 16 var ErrWeakPasswordCommon = errors.New("You may not use a password that is in common use") 17 var ErrWeakPasswordNoNumbers = errors.New("You don't have any numbers in your password") 18 var ErrWeakPasswordNoUpper = errors.New("You don't have any uppercase characters in your password") 19 var ErrWeakPasswordNoLower = errors.New("You don't have any lowercase characters in your password") 20 var ErrWeakPasswordUniqueChars = errors.New("You don't have enough unique characters in your password") 21 var ErrWeakPasswordContains error 22 23 type weakpassHolder struct { 24 Contains []string `json:"contains"` 25 Literal []string `json:"literal"` 26 } 27 28 func InitWeakPasswords() error { 29 var weakpass weakpassHolder 30 e := unmarshalJsonFile("./config/weakpass_default.json", &weakpass) 31 if e != nil { 32 return e 33 } 34 35 wcon := make(map[string]struct{}) 36 for _, item := range weakpass.Contains { 37 wcon[item] = struct{}{} 38 } 39 for _, item := range weakpass.Literal { 40 weakPassLit[item] = struct{}{} 41 } 42 43 weakpass = weakpassHolder{} 44 e = unmarshalJsonFileIgnore404("./config/weakpass.json", &weakpass) 45 if e != nil { 46 return e 47 } 48 49 for _, item := range weakpass.Contains { 50 wcon[item] = struct{}{} 51 } 52 for _, item := range weakpass.Literal { 53 weakPassLit[item] = struct{}{} 54 } 55 weakPassStrings = make([]string, len(wcon)) 56 var i int 57 for pattern, _ := range wcon { 58 weakPassStrings[i] = pattern 59 i++ 60 } 61 62 s := "You may not have " 63 for i, passBit := range weakPassStrings { 64 if i > 0 { 65 if i == len(weakPassStrings)-1 { 66 s += " or " 67 } else { 68 s += ", " 69 } 70 } 71 s += "'" + passBit + "'" 72 } 73 ErrWeakPasswordContains = errors.New(s + " in your password") 74 75 return nil 76 } 77 78 func WeakPassword(password, username, email string) error { 79 lowPassword := strings.ToLower(password) 80 switch { 81 case password == "": 82 return ErrWeakPasswordNone 83 case len(password) < 8: 84 return ErrWeakPasswordShort 85 case len(username) > 3 && strings.Contains(lowPassword, strings.ToLower(username)): 86 return ErrWeakPasswordNameInPass 87 case len(email) > 2 && strings.Contains(lowPassword, strings.ToLower(email)): 88 return ErrWeakPasswordEmailInPass 89 } 90 if len(lowPassword) > 30 { 91 return nil 92 } 93 94 litPass := lowPassword 95 for i := 0; i < 10; i++ { 96 litPass = strings.TrimSuffix(litPass, strconv.Itoa(i)) 97 } 98 _, ok := weakPassLit[litPass] 99 if ok { 100 return ErrWeakPasswordCommon 101 } 102 for _, passBit := range weakPassStrings { 103 if strings.Contains(lowPassword, passBit) { 104 return ErrWeakPasswordContains 105 } 106 } 107 108 charMap := make(map[rune]int) 109 var numbers, symbols, upper, lower int 110 for _, char := range password { 111 charItem, ok := charMap[char] 112 if ok { 113 charItem++ 114 } else { 115 charItem = 1 116 } 117 charMap[char] = charItem 118 119 if unicode.IsLetter(char) { 120 if unicode.IsUpper(char) { 121 upper++ 122 } else { 123 lower++ 124 } 125 } else if unicode.IsNumber(char) { 126 numbers++ 127 } else { 128 symbols++ 129 } 130 } 131 132 if upper == 0 { 133 return ErrWeakPasswordNoUpper 134 } 135 if lower == 0 { 136 return ErrWeakPasswordNoLower 137 } 138 if len(password) < 18 { 139 if numbers == 0 { 140 return ErrWeakPasswordNoNumbers 141 } 142 if (len(password) / 2) > len(charMap) { 143 return ErrWeakPasswordUniqueChars 144 } 145 } else if (len(password) / 3) > len(charMap) { 146 // Be a little lenient on the number of unique characters for long passwords 147 return ErrWeakPasswordUniqueChars 148 } 149 return nil 150 }