github.com/tommi2day/gomodules/pwlib@v0.0.0-20230217211148-82cdbcf0a79d/password_check.go (about) 1 package pwlib 2 3 import ( 4 "fmt" 5 "strings" 6 7 log "github.com/sirupsen/logrus" 8 ) 9 10 // DoPasswordCheck Checks a password to given criteria 11 func DoPasswordCheck(password string, length int, upper int, lower int, numeric int, special int, firstCharCheck bool, allowedChars string) bool { 12 // var ls = true 13 var ucs = true 14 var lcs = true 15 var ncs = true 16 var sps = true 17 // var cs = true 18 var fcs = true 19 var err error 20 21 // allowed chars 22 possible := allowedChars 23 if allowedChars == "" { 24 possible = AllChars 25 } 26 27 // do checks 28 ls, err := checkLength(password, length) 29 if err != nil { 30 log.Debug(err.Error()) 31 } 32 if upper > 0 { 33 r, err := checkClass(password, upper, UpperChar, "uppercase") 34 ucs = r 35 if err != nil { 36 log.Debug(err.Error()) 37 } else { 38 log.Debug("UpperCase check passed") 39 } 40 } 41 if lower > 0 { 42 r, err := checkClass(password, lower, LowerChar, "lowercase") 43 lcs = r 44 if err != nil { 45 log.Debug(err.Error()) 46 } else { 47 log.Debug("LowerCase check passed") 48 } 49 } 50 if numeric > 0 { 51 r, err := checkClass(password, numeric, Digits, "numeric") 52 ncs = r 53 if err != nil { 54 log.Debug(err.Error()) 55 } else { 56 log.Debug("Digits check passed") 57 } 58 } 59 if special > 0 { 60 r, err := checkClass(password, special, SpecialChar, "special") 61 sps = r 62 if err != nil { 63 log.Debug(err.Error()) 64 } else { 65 log.Debug("SpecialChar check passed") 66 } 67 } 68 cs, err := checkChars(password, possible) 69 if err != nil { 70 log.Debug(err.Error()) 71 } else { 72 log.Debug("allowed Char check passed") 73 } 74 if firstCharCheck { 75 r, err := checkFirstChar(password, UpperChar+LowerChar) 76 if err != nil { 77 log.Debug(err.Error()) 78 } else { 79 log.Debug("FirstChar check passed") 80 } 81 fcs = r 82 } 83 84 // final state 85 return ls && ucs && lcs && ncs && sps && cs && fcs 86 } 87 88 func checkClass( 89 password string, 90 should int, 91 chars string, 92 name string, 93 ) (bool, error) { 94 if len(password) == 0 { 95 return false, fmt.Errorf("%s check failed, password empty", name) 96 } 97 cnt := 0 98 for _, char := range strings.Split(chars, "") { 99 cnt += strings.Count(password, char) 100 } 101 if cnt < should { 102 return false, fmt.Errorf("%s check failed, at least %d chars from %s", name, should, chars) 103 } 104 return true, nil 105 } 106 107 func checkChars( 108 password string, 109 chars string, 110 ) (bool, error) { 111 if len(password) == 0 { 112 return false, fmt.Errorf("%s check failed, password empty", "character") 113 } 114 data := []rune(password) 115 for i := 0; i < len(data); i++ { 116 r := data[i] 117 idx := strings.IndexRune(chars, r) 118 if idx == -1 { 119 return false, fmt.Errorf("%s check failed, only %s allowed", "character", chars) 120 } 121 } 122 return true, nil 123 } 124 125 func checkLength(password string, minlen int) (bool, error) { 126 length := len(password) 127 if length < minlen { 128 return false, fmt.Errorf("length check failed, at least %d chars expected, have %d", minlen, length) 129 } 130 return true, nil 131 } 132 133 func checkFirstChar( 134 password string, 135 allowed string, 136 ) (bool, error) { 137 if len(password) == 0 { 138 return false, fmt.Errorf("%s check failed, password empty", "first letter") 139 } 140 firstLetter := []rune(password)[0] 141 idx := strings.IndexRune(allowed, firstLetter) 142 if idx == -1 { 143 return false, fmt.Errorf("%s check failed, only %s allowed", "first letter", allowed) 144 } 145 return true, nil 146 }