diff --git a/Makefile b/Makefile index b25c7ee..aad01a3 100644 --- a/Makefile +++ b/Makefile @@ -83,7 +83,7 @@ clean: # @HELP removes built binaries and temporary files clean: bin-clean bin-clean: - rm -rf .go bin + rm -rf .go bin *.exe help: # @HELP prints this message help: diff --git a/apg.go b/apg.go index 057a444..1b33884 100644 --- a/apg.go +++ b/apg.go @@ -1,17 +1,14 @@ package main import ( - "crypto/rand" "flag" "fmt" - "math/big" "os" - "regexp" ) // Constants const DefaultPwLenght int = 20 -const VersionString string = "0.2.3" +const VersionString string = "0.2.4" const PwLowerCharsHuman string = "abcdefghjkmnpqrstuvwxyz" const PwUpperCharsHuman string = "ABCDEFGHJKMNPQRSTUVWXYZ" const PwLowerChars string = "abcdefghijklmnopqrstuvwxyz" @@ -32,6 +29,7 @@ type cliOpts struct { useSpecial bool humanReadable bool excludeChars string + newStyleModes string showHelp bool showVersion bool } @@ -56,6 +54,8 @@ func init() { // String flags flag.StringVar(&config.excludeChars, "E", "", "Exclude list of characters from generated password") + flag.StringVar(&config.newStyleModes, "M", "", + "New style password parameters (higher priority than single parameters)") flag.Parse() if config.showVersion { @@ -66,21 +66,8 @@ func init() { // Main function that generated the passwords and returns them func main() { - pwLength := config.minPassLen - if pwLength < config.minPassLen { - pwLength = config.minPassLen - } - if pwLength > config.maxPassLen { - pwLength = config.maxPassLen - } - if config.useComplex { - config.useUpperCase = true - config.useLowerCase = true - config.useSpecial = true - config.useNumber = true - config.humanReadable = false - } - + parseParams() + pwLength := getPwLengthFromParams() charRange := getCharRange() for i := 1; i <= config.numOfPass; i++ { @@ -92,80 +79,3 @@ func main() { fmt.Println(pwString) } } - -// Provide the range of available characters based on provided parameters -func getCharRange() string { - pwUpperChars := PwUpperChars - pwLowerChars := PwLowerChars - pwNumbers := PwNumbers - pwSpecialChars := PwSpecialChars - if config.humanReadable { - pwUpperChars = PwUpperCharsHuman - pwLowerChars = PwLowerCharsHuman - pwNumbers = PwNumbersHuman - pwSpecialChars = PwSpecialCharsHuman - } - - var charRange string - if config.useLowerCase { - charRange = charRange + pwLowerChars - } - if config.useUpperCase { - charRange = charRange + pwUpperChars - } - if config.useNumber { - charRange = charRange + pwNumbers - } - if config.useSpecial { - charRange = charRange + pwSpecialChars - } - if config.excludeChars != "" { - regExp := regexp.MustCompile("[" + config.excludeChars + "]") - charRange = regExp.ReplaceAllLiteralString(charRange, "") - } - - return charRange -} - -// Generate random characters based on given character range -// and password length -func getRandChar(charRange *string, pwLength int) (string, error) { - if pwLength <= 0 { - err := fmt.Errorf("provided pwLength value is <= 0: %v", pwLength) - return "", err - } - availCharsLength := len(*charRange) - charSlice := []byte(*charRange) - returnString := make([]byte, pwLength) - for i := 0; i < pwLength; i++ { - randNum, err := getRandNum(availCharsLength) - if err != nil { - return "", err - } - returnString[i] = charSlice[randNum] - } - return string(returnString), nil -} - -// Generate a random number with given maximum value -func getRandNum(maxNum int) (int, error) { - if maxNum <= 0 { - err := fmt.Errorf("provided maxNum is <= 0: %v", maxNum) - return 0, err - } - maxNumBigInt := big.NewInt(int64(maxNum)) - if !maxNumBigInt.IsUint64() { - err := fmt.Errorf("big.NewInt() generation returned negative value: %v", maxNumBigInt) - return 0, err - } - randNum64, err := rand.Int(rand.Reader, maxNumBigInt) - if err != nil { - return 0, err - } - randNum := int(randNum64.Int64()) - if randNum < 0 { - err := fmt.Errorf("generated random number does not fit as int64: %v", randNum64) - return 0, err - } - return randNum, nil -} diff --git a/chars.go b/chars.go new file mode 100644 index 0000000..717d29e --- /dev/null +++ b/chars.go @@ -0,0 +1,37 @@ +package main + +import "regexp" + +// Provide the range of available characters based on provided parameters +func getCharRange() string { + pwUpperChars := PwUpperChars + pwLowerChars := PwLowerChars + pwNumbers := PwNumbers + pwSpecialChars := PwSpecialChars + if config.humanReadable { + pwUpperChars = PwUpperCharsHuman + pwLowerChars = PwLowerCharsHuman + pwNumbers = PwNumbersHuman + pwSpecialChars = PwSpecialCharsHuman + } + + var charRange string + if config.useLowerCase { + charRange = charRange + pwLowerChars + } + if config.useUpperCase { + charRange = charRange + pwUpperChars + } + if config.useNumber { + charRange = charRange + pwNumbers + } + if config.useSpecial { + charRange = charRange + pwSpecialChars + } + if config.excludeChars != "" { + regExp := regexp.MustCompile("[" + config.excludeChars + "]") + charRange = regExp.ReplaceAllLiteralString(charRange, "") + } + + return charRange +} diff --git a/params.go b/params.go new file mode 100644 index 0000000..7d213f3 --- /dev/null +++ b/params.go @@ -0,0 +1,87 @@ +package main + +import ( + "fmt" + "os" +) + +// Parse the new style parameters +func parseNewStyleParams() { + for _, curParam := range config.newStyleModes { + switch curParam { + case 'S': + config.useSpecial = true + break + case 's': + config.useSpecial = false + break + case 'N': + config.useNumber = true + break + case 'n': + config.useNumber = false + break + case 'L': + config.useLowerCase = true + break + case 'l': + config.useLowerCase = false + break + case 'U': + config.useUpperCase = true + break + case 'u': + config.useUpperCase = false + break + case 'H': + config.humanReadable = true + break + case 'h': + config.humanReadable = false + break + // APG compatbilitly + case 'C': + config.useUpperCase = true + break + case 'c': + config.useUpperCase = false + break + default: + fmt.Printf("Unknown password style parameter: %q\n", string(curParam)) + os.Exit(1) + } + } +} + +func getPwLengthFromParams() int { + pwLength := config.minPassLen + if pwLength < config.minPassLen { + pwLength = config.minPassLen + } + if pwLength > config.maxPassLen { + pwLength = config.maxPassLen + } + + return pwLength +} + +func parseParams() { + if config.useComplex { + config.useUpperCase = true + config.useLowerCase = true + config.useSpecial = true + config.useNumber = true + config.humanReadable = false + } + if config.newStyleModes != "" { + parseNewStyleParams() + } + + if config.useUpperCase == false && + config.useLowerCase == false && + config.useNumber == false && + config.useSpecial == false { + fmt.Printf("No password mode set. Cannot generate password from empty character set.") + os.Exit(1) + } +} diff --git a/rand.go b/rand.go new file mode 100644 index 0000000..7c12cd7 --- /dev/null +++ b/rand.go @@ -0,0 +1,50 @@ +package main + +import ( + "crypto/rand" + "fmt" + "math/big" +) + +// Generate random characters based on given character range +// and password length +func getRandChar(charRange *string, pwLength int) (string, error) { + if pwLength <= 0 { + err := fmt.Errorf("provided pwLength value is <= 0: %v", pwLength) + return "", err + } + availCharsLength := len(*charRange) + charSlice := []byte(*charRange) + returnString := make([]byte, pwLength) + for i := 0; i < pwLength; i++ { + randNum, err := getRandNum(availCharsLength) + if err != nil { + return "", err + } + returnString[i] = charSlice[randNum] + } + return string(returnString), nil +} + +// Generate a random number with given maximum value +func getRandNum(maxNum int) (int, error) { + if maxNum <= 0 { + err := fmt.Errorf("provided maxNum is <= 0: %v", maxNum) + return 0, err + } + maxNumBigInt := big.NewInt(int64(maxNum)) + if !maxNumBigInt.IsUint64() { + err := fmt.Errorf("big.NewInt() generation returned negative value: %v", maxNumBigInt) + return 0, err + } + randNum64, err := rand.Int(rand.Reader, maxNumBigInt) + if err != nil { + return 0, err + } + randNum := int(randNum64.Int64()) + if randNum < 0 { + err := fmt.Errorf("generated random number does not fit as int64: %v", randNum64) + return 0, err + } + return randNum, nil +}