From 1130a698f693355190e53c31324d6f88da43398f Mon Sep 17 00:00:00 2001 From: Winni Neessen Date: Sat, 27 Mar 2021 17:03:19 +0100 Subject: [PATCH] v0.2.8: De-cluttered the config flags stuff --- apg.go | 46 +++++++++++--- apg_test.go | 56 ++++++++--------- chars.go | 17 +++--- config.go | 122 +++++++++++++++++++++++++++++++++++++ config/config.go | 154 ----------------------------------------------- 5 files changed, 196 insertions(+), 199 deletions(-) create mode 100644 config.go delete mode 100644 config/config.go diff --git a/apg.go b/apg.go index d879695..5b139b5 100644 --- a/apg.go +++ b/apg.go @@ -2,29 +2,59 @@ package main import ( "fmt" - "github.com/wneessen/apg.go/config" "log" + "os" ) +// Constants +const DefaultPwLenght int = 20 +const VersionString string = "0.2.8" + +type Config struct { + minPassLen int + maxPassLen int + numOfPass int + useComplex bool + useLowerCase bool + useUpperCase bool + useNumber bool + useSpecial bool + humanReadable bool + excludeChars string + newStyleModes string + spellPassword bool + ShowHelp bool + showVersion bool + outputMode int +} + // Main function that generated the passwords and returns them func main() { // Log config log.SetFlags(log.Ltime | log.Ldate | log.Lshortfile) - // Create config - conf := config.NewConfig() - conf.ParseParams() - pwLength := conf.GetPwLengthFromParams() - charRange := getCharRange(conf) + // Read and parse flags + var config = parseFlags() + + // Show version and exit + if config.showVersion { + _, _ = os.Stderr.WriteString("Advanced Password Generator Clone (apg.go) v" + VersionString + "\n") + _, _ = os.Stderr.WriteString("(C) 2021 by Winni Neessen\n") + os.Exit(0) + } + + // Set PW length and available characterset + pwLength := getPwLengthFromParams(&config) + charRange := getCharRange(&config) // Generate passwords - for i := 1; i <= conf.NumOfPass; i++ { + for i := 1; i <= config.numOfPass; i++ { pwString, err := getRandChar(&charRange, pwLength) if err != nil { log.Fatalf("getRandChar returned an error: %q\n", err) } - switch conf.OutputMode { + switch config.outputMode { case 1: { spelledPw, err := spellPasswordString(pwString) diff --git a/apg_test.go b/apg_test.go index fe96d66..5e8183f 100644 --- a/apg_test.go +++ b/apg_test.go @@ -1,9 +1,15 @@ package main -import ( - "github.com/wneessen/apg.go/config" - "testing" -) +import "testing" + +var config Config + +// Make sure the flags are initalized +var _ = func() bool { + testing.Init() + config = parseFlags() + return true +}() // Test getRandNum with max 1000 func TestGetRandNum(t *testing.T) { @@ -114,16 +120,14 @@ func TestGetCharRange(t *testing.T) { {"special_only_human", specialHumanBytes, false, false, false, true, true}, } - conf := config.NewConfig() - conf.ParseParams() for _, testCase := range testTable { t.Run(testCase.testName, func(t *testing.T) { - conf.UseLowerCase = testCase.useLowerCase - conf.UseUpperCase = testCase.useUpperCase - conf.UseNumber = testCase.useNumber - conf.UseSpecial = testCase.useSpecial - conf.HumanReadable = testCase.humanReadable - charRange := getCharRange(conf) + config.useLowerCase = testCase.useLowerCase + config.useUpperCase = testCase.useUpperCase + config.useNumber = testCase.useNumber + config.useSpecial = testCase.useSpecial + config.humanReadable = testCase.humanReadable + charRange := getCharRange(&config) for _, curChar := range charRange { searchAllowedBytes := containsByte(testCase.allowedBytes, int(curChar), t) if !searchAllowedBytes { @@ -147,8 +151,6 @@ func TestConvert(t *testing.T) { {"convert_0_to_ZERO", '0', "ZERO", false}, {"convert_/_to_SLASH", '/', "SLASH", false}, } - conf := config.NewConfig() - conf.ParseParams() for _, testCase := range testTable { t.Run(testCase.testName, func(t *testing.T) { @@ -171,12 +173,12 @@ func TestConvert(t *testing.T) { } t.Run("all_chars_must_return_a_conversion_string", func(t *testing.T) { - conf.UseUpperCase = true - conf.UseLowerCase = true - conf.UseNumber = true - conf.UseSpecial = true - conf.HumanReadable = false - charRange := getCharRange(conf) + config.useUpperCase = true + config.useLowerCase = true + config.useNumber = true + config.useSpecial = true + config.humanReadable = false + charRange := getCharRange(&config) for _, curChar := range charRange { _, err := convertCharToName(byte(curChar)) if err != nil { @@ -215,15 +217,13 @@ func BenchmarkGetRandChar(b *testing.B) { // Benchmark: Random char generation func BenchmarkConvertChar(b *testing.B) { - conf := config.NewConfig() - conf.ParseParams() - conf.UseUpperCase = true - conf.UseLowerCase = true - conf.UseNumber = true - conf.UseSpecial = true - conf.HumanReadable = false - charRange := getCharRange(conf) + config.useUpperCase = true + config.useLowerCase = true + config.useNumber = true + config.useSpecial = true + config.humanReadable = false + charRange := getCharRange(&config) for i := 0; i < b.N; i++ { charToConv, _ := getRandChar(&charRange, 1) charBytes := []byte(charToConv) diff --git a/chars.go b/chars.go index 39c64fb..2e05901 100644 --- a/chars.go +++ b/chars.go @@ -1,7 +1,6 @@ package main import ( - "github.com/wneessen/apg.go/config" "regexp" ) @@ -15,12 +14,12 @@ const PwNumbersHuman string = "23456789" const PwNumbers string = "1234567890" // Provide the range of available characters based on provided parameters -func getCharRange(config *config.Config) string { +func getCharRange(config *Config) string { pwUpperChars := PwUpperChars pwLowerChars := PwLowerChars pwNumbers := PwNumbers pwSpecialChars := PwSpecialChars - if config.HumanReadable { + if config.humanReadable { pwUpperChars = PwUpperCharsHuman pwLowerChars = PwLowerCharsHuman pwNumbers = PwNumbersHuman @@ -28,20 +27,20 @@ func getCharRange(config *config.Config) string { } var charRange string - if config.UseLowerCase { + if config.useLowerCase { charRange = charRange + pwLowerChars } - if config.UseUpperCase { + if config.useUpperCase { charRange = charRange + pwUpperChars } - if config.UseNumber { + if config.useNumber { charRange = charRange + pwNumbers } - if config.UseSpecial { + if config.useSpecial { charRange = charRange + pwSpecialChars } - if config.ExcludeChars != "" { - regExp := regexp.MustCompile("[" + regexp.QuoteMeta(config.ExcludeChars) + "]") + if config.excludeChars != "" { + regExp := regexp.MustCompile("[" + regexp.QuoteMeta(config.excludeChars) + "]") charRange = regExp.ReplaceAllLiteralString(charRange, "") } diff --git a/config.go b/config.go new file mode 100644 index 0000000..801a89c --- /dev/null +++ b/config.go @@ -0,0 +1,122 @@ +package main + +import ( + "flag" + "log" +) + +// Parse the CLI flags +func parseFlags() Config { + var config Config + + // Read and set all flags + flag.BoolVar(&config.useLowerCase, "L", true, "Use lower case characters in passwords") + flag.BoolVar(&config.useUpperCase, "U", true, "Use upper case characters in passwords") + flag.BoolVar(&config.useNumber, "N", true, "Use numbers in passwords") + flag.BoolVar(&config.useSpecial, "S", false, "Use special characters in passwords") + flag.BoolVar(&config.useComplex, "C", false, "Generate complex passwords (implies -L -U -N -S, disables -H)") + flag.BoolVar(&config.spellPassword, "l", false, "Spell generated password") + flag.BoolVar(&config.humanReadable, "H", false, "Generate human-readable passwords") + flag.BoolVar(&config.showVersion, "v", false, "Show version") + flag.IntVar(&config.minPassLen, "m", DefaultPwLenght, "Minimum password length") + flag.IntVar(&config.maxPassLen, "x", DefaultPwLenght, "Maxiumum password length") + flag.IntVar(&config.numOfPass, "n", 1, "Number of passwords to generate") + 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() + + // Parse additional parameters + parseParams(&config) + + return config +} + +// Parse the parameters and set the according config flags +func parseParams(config *Config) { + parseNewStyleParams(config) + + // Complex overrides everything + if config.useComplex { + config.useUpperCase = true + config.useLowerCase = true + config.useSpecial = true + config.useNumber = true + config.humanReadable = false + } + + if config.useUpperCase == false && + config.useLowerCase == false && + config.useNumber == false && + config.useSpecial == false { + log.Fatalf("No password mode set. Cannot generate password from empty character set.") + } + + // Set output mode + if config.spellPassword { + config.outputMode = 1 + } +} + +// Get the password length from the given cli flags +func getPwLengthFromParams(config *Config) int { + pwLength := config.minPassLen + if pwLength < config.minPassLen { + pwLength = config.minPassLen + } + if pwLength > config.maxPassLen { + pwLength = config.maxPassLen + } + + return pwLength +} + +// Parse the new style parameters +func parseNewStyleParams(config *Config) { + if config.newStyleModes == "" { + return + } + + 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 + case 'C': + config.useComplex = true + break + case 'c': + config.useComplex = false + break + default: + log.Fatalf("Unknown password style parameter: %q\n", string(curParam)) + } + } +} diff --git a/config/config.go b/config/config.go deleted file mode 100644 index 94e298c..0000000 --- a/config/config.go +++ /dev/null @@ -1,154 +0,0 @@ -package config - -import ( - "flag" - "log" - "os" -) - -// Constants -const DefaultPwLenght int = 20 -const VersionString string = "0.2.7" - -type Config struct { - MinPassLen int - MaxPassLen int - NumOfPass int - UseComplex bool - UseLowerCase bool - UseUpperCase bool - UseNumber bool - UseSpecial bool - HumanReadable bool - ExcludeChars string - NewStyleModes string - SpellPassword bool - ShowHelp bool - showVersion bool - OutputMode int -} - -var config Config - -func init() { - // Bool flags - flag.BoolVar(&config.UseLowerCase, "L", true, "Use lower case characters in passwords") - flag.BoolVar(&config.UseUpperCase, "U", true, "Use upper case characters in passwords") - flag.BoolVar(&config.UseNumber, "N", true, "Use numbers in passwords") - flag.BoolVar(&config.UseSpecial, "S", false, "Use special characters in passwords") - flag.BoolVar(&config.UseComplex, "C", false, "Generate complex passwords (implies -L -U -N -S, disables -H)") - flag.BoolVar(&config.SpellPassword, "l", false, "Spell generated password") - flag.BoolVar(&config.HumanReadable, "H", false, "Generate human-readable passwords") - flag.BoolVar(&config.showVersion, "v", false, "Show version") - - // Int flags - flag.IntVar(&config.MinPassLen, "m", DefaultPwLenght, "Minimum password length") - flag.IntVar(&config.MaxPassLen, "x", DefaultPwLenght, "Maxiumum password length") - flag.IntVar(&config.NumOfPass, "n", 1, "Number of passwords to generate") - - // 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)") -} - -func NewConfig() *Config { - flag.Parse() - - if config.showVersion { - _, _ = os.Stderr.WriteString("Advanced Password Generator Clone (apg.go) v" + VersionString + "\n") - _, _ = os.Stderr.WriteString("(C) 2021 by Winni Neessen\n") - os.Exit(0) - } - - return &config -} - -// Parse the parameters and set the according config flags -func (config *Config) ParseParams() { - config.parseNewStyleParams() - - // Complex overrides everything - if config.UseComplex { - config.UseUpperCase = true - config.UseLowerCase = true - config.UseSpecial = true - config.UseNumber = true - config.HumanReadable = false - } - - if config.UseUpperCase == false && - config.UseLowerCase == false && - config.UseNumber == false && - config.UseSpecial == false { - log.Fatalf("No password mode set. Cannot generate password from empty character set.") - } - - // Set output mode - if config.SpellPassword { - config.OutputMode = 1 - } -} - -// Get the password length from the given cli flags -func (config *Config) GetPwLengthFromParams() int { - pwLength := config.MinPassLen - if pwLength < config.MinPassLen { - pwLength = config.MinPassLen - } - if pwLength > config.MaxPassLen { - pwLength = config.MaxPassLen - } - - return pwLength -} - -// Parse the new style parameters -func (config *Config) parseNewStyleParams() { - if config.NewStyleModes == "" { - return - } - - 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 - case 'C': - config.UseComplex = true - break - case 'c': - config.UseComplex = false - break - default: - log.Fatalf("Unknown password style parameter: %q\n", string(curParam)) - } - } -}