mirror of
https://github.com/wneessen/apg-go.git
synced 2024-11-09 15:52:54 +01:00
v0.2.7: Switched global config to it's own package
This commit is contained in:
parent
44104a5487
commit
637ee8359a
5 changed files with 219 additions and 200 deletions
83
apg.go
83
apg.go
|
@ -1,89 +1,30 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"github.com/wneessen/apg.go/config"
|
||||
"log"
|
||||
"os"
|
||||
)
|
||||
|
||||
// Constants
|
||||
const DefaultPwLenght int = 20
|
||||
const VersionString string = "0.2.6"
|
||||
const PwLowerCharsHuman string = "abcdefghjkmnpqrstuvwxyz"
|
||||
const PwUpperCharsHuman string = "ABCDEFGHJKMNPQRSTUVWXYZ"
|
||||
const PwLowerChars string = "abcdefghijklmnopqrstuvwxyz"
|
||||
const PwUpperChars string = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
const PwSpecialCharsHuman string = "\"#%*+-/:;=\\_|~"
|
||||
const PwSpecialChars string = "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~"
|
||||
const PwNumbersHuman string = "23456789"
|
||||
const PwNumbers string = "1234567890"
|
||||
|
||||
type cliOpts 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 cliOpts
|
||||
|
||||
// Read flags
|
||||
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)")
|
||||
|
||||
flag.Parse()
|
||||
if config.showVersion {
|
||||
_, _ = os.Stderr.WriteString("Winni's Advanced Password Generator Clone (apg.go) v" + VersionString + "\n")
|
||||
_, _ = os.Stderr.WriteString("(C) 2021 by Winni Neessen\n")
|
||||
os.Exit(0)
|
||||
}
|
||||
|
||||
log.SetFlags(log.Ltime | log.Ldate | log.Lshortfile)
|
||||
}
|
||||
|
||||
// Main function that generated the passwords and returns them
|
||||
func main() {
|
||||
parseParams()
|
||||
pwLength := getPwLengthFromParams()
|
||||
charRange := getCharRange()
|
||||
// Log config
|
||||
log.SetFlags(log.Ltime | log.Ldate | log.Lshortfile)
|
||||
|
||||
for i := 1; i <= config.numOfPass; i++ {
|
||||
// Create config
|
||||
conf := config.NewConfig()
|
||||
conf.ParseParams()
|
||||
pwLength := conf.GetPwLengthFromParams()
|
||||
charRange := getCharRange(conf)
|
||||
|
||||
// Generate passwords
|
||||
for i := 1; i <= conf.NumOfPass; i++ {
|
||||
pwString, err := getRandChar(&charRange, pwLength)
|
||||
if err != nil {
|
||||
log.Fatalf("getRandChar returned an error: %q\n", err)
|
||||
}
|
||||
|
||||
switch config.outputMode {
|
||||
switch conf.OutputMode {
|
||||
case 1:
|
||||
{
|
||||
spelledPw, err := spellPasswordString(pwString)
|
||||
|
|
58
apg_test.go
58
apg_test.go
|
@ -1,15 +1,10 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"github.com/wneessen/apg.go/config"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// Make sure the flags are initalized
|
||||
var _ = func() bool {
|
||||
testing.Init()
|
||||
return true
|
||||
}()
|
||||
|
||||
// Test getRandNum with max 1000
|
||||
func TestGetRandNum(t *testing.T) {
|
||||
testTable := []struct {
|
||||
|
@ -118,16 +113,19 @@ func TestGetCharRange(t *testing.T) {
|
|||
{"special_only", specialBytes, false, false, false, true, false},
|
||||
{"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) {
|
||||
config.useLowerCase = testCase.useLowerCase
|
||||
config.useUpperCase = testCase.useUpperCase
|
||||
config.useNumber = testCase.useNumber
|
||||
config.useSpecial = testCase.useSpecial
|
||||
config.humanReadable = testCase.humanReadable
|
||||
charRange := getCharRange()
|
||||
conf.UseLowerCase = testCase.useLowerCase
|
||||
conf.UseUpperCase = testCase.useUpperCase
|
||||
conf.UseNumber = testCase.useNumber
|
||||
conf.UseSpecial = testCase.useSpecial
|
||||
conf.HumanReadable = testCase.humanReadable
|
||||
charRange := getCharRange(conf)
|
||||
for _, curChar := range charRange {
|
||||
searchAllowedBytes := containsByte(testCase.allowedBytes, int(curChar))
|
||||
searchAllowedBytes := containsByte(testCase.allowedBytes, int(curChar), t)
|
||||
if !searchAllowedBytes {
|
||||
t.Errorf("Character range returned invalid value: %v", string(curChar))
|
||||
}
|
||||
|
@ -149,6 +147,9 @@ 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) {
|
||||
charToString, err := convertCharToName(testCase.givenVal)
|
||||
|
@ -170,12 +171,12 @@ func TestConvert(t *testing.T) {
|
|||
}
|
||||
|
||||
t.Run("all_chars_must_return_a_conversion_string", func(t *testing.T) {
|
||||
config.useUpperCase = true
|
||||
config.useLowerCase = true
|
||||
config.useNumber = true
|
||||
config.useSpecial = true
|
||||
config.humanReadable = false
|
||||
charRange := getCharRange()
|
||||
conf.UseUpperCase = true
|
||||
conf.UseLowerCase = true
|
||||
conf.UseNumber = true
|
||||
conf.UseSpecial = true
|
||||
conf.HumanReadable = false
|
||||
charRange := getCharRange(conf)
|
||||
for _, curChar := range charRange {
|
||||
_, err := convertCharToName(byte(curChar))
|
||||
if err != nil {
|
||||
|
@ -214,12 +215,15 @@ func BenchmarkGetRandChar(b *testing.B) {
|
|||
|
||||
// Benchmark: Random char generation
|
||||
func BenchmarkConvertChar(b *testing.B) {
|
||||
config.useUpperCase = true
|
||||
config.useLowerCase = true
|
||||
config.useNumber = true
|
||||
config.useSpecial = true
|
||||
config.humanReadable = false
|
||||
charRange := getCharRange()
|
||||
conf := config.NewConfig()
|
||||
conf.ParseParams()
|
||||
|
||||
conf.UseUpperCase = true
|
||||
conf.UseLowerCase = true
|
||||
conf.UseNumber = true
|
||||
conf.UseSpecial = true
|
||||
conf.HumanReadable = false
|
||||
charRange := getCharRange(conf)
|
||||
for i := 0; i < b.N; i++ {
|
||||
charToConv, _ := getRandChar(&charRange, 1)
|
||||
charBytes := []byte(charToConv)
|
||||
|
@ -228,7 +232,9 @@ func BenchmarkConvertChar(b *testing.B) {
|
|||
}
|
||||
|
||||
// Contains function to search a given slice for values
|
||||
func containsByte(allowedBytes []int, currentChar int) bool {
|
||||
func containsByte(allowedBytes []int, currentChar int, t *testing.T) bool {
|
||||
t.Helper()
|
||||
|
||||
for _, charInt := range allowedBytes {
|
||||
if charInt == currentChar {
|
||||
return true
|
||||
|
|
30
chars.go
30
chars.go
|
@ -1,14 +1,26 @@
|
|||
package main
|
||||
|
||||
import "regexp"
|
||||
import (
|
||||
"github.com/wneessen/apg.go/config"
|
||||
"regexp"
|
||||
)
|
||||
|
||||
const PwLowerCharsHuman string = "abcdefghjkmnpqrstuvwxyz"
|
||||
const PwUpperCharsHuman string = "ABCDEFGHJKMNPQRSTUVWXYZ"
|
||||
const PwLowerChars string = "abcdefghijklmnopqrstuvwxyz"
|
||||
const PwUpperChars string = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
const PwSpecialCharsHuman string = "\"#%*+-/:;=\\_|~"
|
||||
const PwSpecialChars string = "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~"
|
||||
const PwNumbersHuman string = "23456789"
|
||||
const PwNumbers string = "1234567890"
|
||||
|
||||
// Provide the range of available characters based on provided parameters
|
||||
func getCharRange() string {
|
||||
func getCharRange(config *config.Config) string {
|
||||
pwUpperChars := PwUpperChars
|
||||
pwLowerChars := PwLowerChars
|
||||
pwNumbers := PwNumbers
|
||||
pwSpecialChars := PwSpecialChars
|
||||
if config.humanReadable {
|
||||
if config.HumanReadable {
|
||||
pwUpperChars = PwUpperCharsHuman
|
||||
pwLowerChars = PwLowerCharsHuman
|
||||
pwNumbers = PwNumbersHuman
|
||||
|
@ -16,20 +28,20 @@ func getCharRange() 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, "")
|
||||
}
|
||||
|
||||
|
|
154
config/config.go
Normal file
154
config/config.go
Normal file
|
@ -0,0 +1,154 @@
|
|||
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))
|
||||
}
|
||||
}
|
||||
}
|
94
params.go
94
params.go
|
@ -1,94 +0,0 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"log"
|
||||
)
|
||||
|
||||
// Parse the parameters and set the according config flags
|
||||
func parseParams() {
|
||||
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 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 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))
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue