github.com/tommi2day/gomodules@v1.13.2-0.20240423190010-b7d55d252a27/pwlib/password_generate.go (about) 1 package pwlib 2 3 import ( 4 "crypto/rand" 5 "fmt" 6 "math/big" 7 8 log "github.com/sirupsen/logrus" 9 ) 10 11 // GenerateRandomString generate a randow string with the given length and out of allowed charset 12 func GenerateRandomString(length int, allowedChars string) string { 13 letters := allowedChars 14 if len(allowedChars) == 0 { 15 letters = charset.AllChars 16 } 17 ret := make([]byte, length) 18 for i := 0; i < length; i++ { 19 num, _ := rand.Int(rand.Reader, big.NewInt(int64(len(letters)))) 20 ret[i] = letters[num.Int64()] 21 } 22 log.Debugf("Password candidate: %s", string(ret)) 23 return string(ret) 24 } 25 26 // GenPassword generates a password with the given complexity 27 func GenPassword(length int, upper int, lower int, numeric int, special int, firstCharCheck bool) (string, error) { 28 log.Debug("GenPassword entered") 29 // allowed chars 30 var ok = false 31 var err error 32 33 var allowedChars = "" 34 // define allowed charset based on parameters 35 if upper > 0 { 36 allowedChars += charset.UpperChar 37 } 38 if lower > 0 { 39 allowedChars += charset.LowerChar 40 } 41 if numeric > 0 { 42 allowedChars += charset.Digits 43 } 44 if special > 0 { 45 allowedChars += charset.SpecialChar 46 } 47 charset.AllChars = allowedChars 48 49 newPassword := "" 50 // skip password check logging when used to generate 51 SilentCheck = true 52 // max 50 tries to generate a valid password 53 for c := 0; c < 50; c++ { 54 newPassword = GenerateRandomString(length, allowedChars) 55 ok = DoPasswordCheck(newPassword, length, upper, lower, numeric, special, firstCharCheck, allowedChars) 56 if ok { 57 break 58 } 59 newPassword = "" 60 log.Debugf("generate retry %d", c) 61 } 62 SilentCheck = false 63 64 if !ok { 65 err = fmt.Errorf("unable to create required Password") 66 } else { 67 log.Debug("Generation succeeded") 68 } 69 return newPassword, err 70 }