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  }