v0.2.8: De-cluttered the config flags stuff

This commit is contained in:
Winni Neessen 2021-03-27 17:03:19 +01:00
parent dd1a6b2b62
commit 1130a698f6
Signed by: wneessen
GPG key ID: 385AC9889632126E
5 changed files with 196 additions and 199 deletions

46
apg.go
View file

@ -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)

View file

@ -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)

View file

@ -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, "")
}

122
config.go Normal file
View file

@ -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))
}
}
}

View file

@ -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))
}
}
}