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  }