mirror of
https://github.com/wneessen/apg-go.git
synced 2024-11-22 13:50:49 +01:00
Added spelling of pws. Ready for v0.2.4
This commit is contained in:
parent
eb221ccc69
commit
8b9269b1b9
4 changed files with 258 additions and 38 deletions
21
apg.go
21
apg.go
|
@ -30,8 +30,10 @@ type cliOpts struct {
|
||||||
humanReadable bool
|
humanReadable bool
|
||||||
excludeChars string
|
excludeChars string
|
||||||
newStyleModes string
|
newStyleModes string
|
||||||
|
spellPassword bool
|
||||||
showHelp bool
|
showHelp bool
|
||||||
showVersion bool
|
showVersion bool
|
||||||
|
outputMode int
|
||||||
}
|
}
|
||||||
|
|
||||||
var config cliOpts
|
var config cliOpts
|
||||||
|
@ -43,7 +45,8 @@ func init() {
|
||||||
flag.BoolVar(&config.useUpperCase, "U", false, "Use upper case characters in passwords")
|
flag.BoolVar(&config.useUpperCase, "U", false, "Use upper case characters in passwords")
|
||||||
flag.BoolVar(&config.useNumber, "N", false, "Use numbers in passwords")
|
flag.BoolVar(&config.useNumber, "N", false, "Use numbers in passwords")
|
||||||
flag.BoolVar(&config.useSpecial, "S", false, "Use special characters in passwords")
|
flag.BoolVar(&config.useSpecial, "S", false, "Use special characters in passwords")
|
||||||
flag.BoolVar(&config.useComplex, "C", true, "Generate complex passwords (implies -L -U -N -S, disables -H)")
|
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.humanReadable, "H", false, "Generate human-readable passwords")
|
||||||
flag.BoolVar(&config.showVersion, "v", false, "Show version")
|
flag.BoolVar(&config.showVersion, "v", false, "Show version")
|
||||||
|
|
||||||
|
@ -76,6 +79,22 @@ func main() {
|
||||||
fmt.Printf("getRandChar returned an error: %q\n", err.Error())
|
fmt.Printf("getRandChar returned an error: %q\n", err.Error())
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
switch config.outputMode {
|
||||||
|
case 1:
|
||||||
|
{
|
||||||
|
spelledPw, err := spellPasswordString(pwString)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("spellPasswordString returned an error: %q\n", err.Error())
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
fmt.Printf("%v (%v)\n", pwString, spelledPw)
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
{
|
||||||
fmt.Println(pwString)
|
fmt.Println(pwString)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
81
apg_test.go
81
apg_test.go
|
@ -207,6 +207,72 @@ func TestGetCharRange(t *testing.T) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Test Conversions
|
||||||
|
func TestConvert(t *testing.T) {
|
||||||
|
t.Run("convert_A_to_Alfa", func(t *testing.T) {
|
||||||
|
charToString, err := convertCharToName('A')
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("Character to string conversion failed: %v", err.Error())
|
||||||
|
}
|
||||||
|
if charToString != "Alfa" {
|
||||||
|
t.Errorf("Converting 'A' to string did not return the correct value of 'Alfa': %q", charToString)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
t.Run("convert_a_to_alfa", func(t *testing.T) {
|
||||||
|
charToString, err := convertCharToName('a')
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("Character to string conversion failed: %v", err.Error())
|
||||||
|
}
|
||||||
|
if charToString != "alfa" {
|
||||||
|
t.Errorf("Converting 'a' to string did not return the correct value of 'alfa': %q", charToString)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
t.Run("convert_0_to_ZERO", func(t *testing.T) {
|
||||||
|
charToString, err := convertCharToName('0')
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("Character to string conversion failed: %v", err.Error())
|
||||||
|
}
|
||||||
|
if charToString != "ZERO" {
|
||||||
|
t.Errorf("Converting '0' to string did not return the correct value of 'ZERO': %q", charToString)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
t.Run("convert_/_to_SLASH", func(t *testing.T) {
|
||||||
|
charToString, err := convertCharToName('/')
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("Character to string conversion failed: %v", err.Error())
|
||||||
|
}
|
||||||
|
if charToString != "SLASH" {
|
||||||
|
t.Errorf("Converting '/' to string did not return the correct value of 'SLASH': %q", charToString)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
t.Run("all_chars_convert_to_string", func(t *testing.T) {
|
||||||
|
config.useUpperCase = true
|
||||||
|
config.useLowerCase = true
|
||||||
|
config.useNumber = true
|
||||||
|
config.useSpecial = true
|
||||||
|
config.humanReadable = false
|
||||||
|
charRange := getCharRange()
|
||||||
|
for _, curChar := range charRange {
|
||||||
|
_, err := convertCharToName(byte(curChar))
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("Character to string conversion failed: %v", err.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
t.Run("spell_Ab!_to_strings", func(t *testing.T) {
|
||||||
|
pwString := "Ab!"
|
||||||
|
spelledString, err := spellPasswordString(pwString)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("password spelling failed: %v", err.Error())
|
||||||
|
}
|
||||||
|
if spelledString != "Alfa/bravo/EXCLAMATION_POINT" {
|
||||||
|
t.Errorf(
|
||||||
|
"Spelling pwString 'Ab!' is expected to provide 'Alfa/bravo/EXCLAMATION_POINT', but returned: %q",
|
||||||
|
spelledString)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
// Forced failures
|
// Forced failures
|
||||||
func TestForceFailures(t *testing.T) {
|
func TestForceFailures(t *testing.T) {
|
||||||
t.Run("too_big_big.NewInt_value", func(t *testing.T) {
|
t.Run("too_big_big.NewInt_value", func(t *testing.T) {
|
||||||
|
@ -241,6 +307,21 @@ 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()
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
charToConv, _ := getRandChar(&charRange, 1)
|
||||||
|
charBytes := []byte(charToConv)
|
||||||
|
_, _ = convertCharToName(charBytes[0])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Contains function to search a given slice for values
|
// Contains function to search a given slice for values
|
||||||
func containsByte(allowedBytes []int, currentChar int) bool {
|
func containsByte(allowedBytes []int, currentChar int) bool {
|
||||||
for _, charInt := range allowedBytes {
|
for _, charInt := range allowedBytes {
|
||||||
|
|
110
convert.go
Normal file
110
convert.go
Normal file
|
@ -0,0 +1,110 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
symbNumNames = map[byte]string{
|
||||||
|
'1': "ONE",
|
||||||
|
'2': "TWO",
|
||||||
|
'3': "THREE",
|
||||||
|
'4': "FOUR",
|
||||||
|
'5': "FIVE",
|
||||||
|
'6': "SIX",
|
||||||
|
'7': "SEVEN",
|
||||||
|
'8': "EIGHT",
|
||||||
|
'9': "NINE",
|
||||||
|
'0': "ZERO",
|
||||||
|
33: "EXCLAMATION_POINT",
|
||||||
|
34: "QUOTATION_MARK",
|
||||||
|
35: "CROSSHATCH",
|
||||||
|
36: "DOLLAR_SIGN",
|
||||||
|
37: "PERCENT_SIGN",
|
||||||
|
38: "AMPERSAND",
|
||||||
|
39: "APOSTROPHE",
|
||||||
|
40: "LEFT_PARENTHESIS",
|
||||||
|
41: "RIGHT_PARENTHESIS",
|
||||||
|
42: "ASTERISK",
|
||||||
|
43: "PLUS_SIGN",
|
||||||
|
44: "COMMA",
|
||||||
|
45: "HYPHEN",
|
||||||
|
46: "PERIOD",
|
||||||
|
47: "SLASH",
|
||||||
|
58: "COLON",
|
||||||
|
59: "SEMICOLON",
|
||||||
|
60: "LESS_THAN",
|
||||||
|
61: "EQUAL_SIGN",
|
||||||
|
62: "GREATER_THAN",
|
||||||
|
63: "QUESTION_MARK",
|
||||||
|
64: "AT_SIGN",
|
||||||
|
91: "LEFT_BRACKET",
|
||||||
|
92: "BACKSLASH",
|
||||||
|
93: "RIGHT_BRACKET",
|
||||||
|
94: "CIRCUMFLEX",
|
||||||
|
95: "UNDERSCORE",
|
||||||
|
96: "GRAVE",
|
||||||
|
123: "LEFT_BRACE",
|
||||||
|
124: "VERTICAL_BAR",
|
||||||
|
125: "RIGHT_BRACE",
|
||||||
|
126: "TILDE",
|
||||||
|
}
|
||||||
|
alphabetNames = map[byte]string{
|
||||||
|
'A': "Alfa",
|
||||||
|
'B': "Bravo",
|
||||||
|
'C': "Charlie",
|
||||||
|
'D': "Delta",
|
||||||
|
'E': "Echo",
|
||||||
|
'F': "Foxtrot",
|
||||||
|
'G': "Golf",
|
||||||
|
'H': "Hotel",
|
||||||
|
'I': "India",
|
||||||
|
'J': "Juliett",
|
||||||
|
'K': "Kilo",
|
||||||
|
'L': "Lima",
|
||||||
|
'M': "Mike",
|
||||||
|
'N': "November",
|
||||||
|
'O': "Oscar",
|
||||||
|
'P': "Papa",
|
||||||
|
'Q': "Quebec",
|
||||||
|
'R': "Romeo",
|
||||||
|
'S': "Sierra",
|
||||||
|
'T': "Tango",
|
||||||
|
'U': "Uniform",
|
||||||
|
'V': "Victor",
|
||||||
|
'W': "Whiskey",
|
||||||
|
'X': "X_ray",
|
||||||
|
'Y': "Yankee",
|
||||||
|
'Z': "Zulu",
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
func spellPasswordString(pwString string) (string, error) {
|
||||||
|
var returnString []string
|
||||||
|
for _, curChar := range pwString {
|
||||||
|
curSpellString, err := convertCharToName(byte(curChar))
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
returnString = append(returnString, curSpellString)
|
||||||
|
}
|
||||||
|
return strings.Join(returnString, "/"), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func convertCharToName(charByte byte) (string, error) {
|
||||||
|
var returnString string
|
||||||
|
if charByte > 64 && charByte < 91 {
|
||||||
|
returnString = alphabetNames[charByte]
|
||||||
|
} else if charByte > 96 && charByte < 123 {
|
||||||
|
returnString = strings.ToLower(alphabetNames[charByte-32])
|
||||||
|
} else {
|
||||||
|
returnString = symbNumNames[charByte]
|
||||||
|
}
|
||||||
|
|
||||||
|
if returnString == "" {
|
||||||
|
err := fmt.Errorf("cannot convert to character to name: %q is an unknown character", charByte)
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return returnString, nil
|
||||||
|
}
|
82
params.go
82
params.go
|
@ -5,8 +5,52 @@ import (
|
||||||
"os"
|
"os"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// 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 {
|
||||||
|
fmt.Printf("No password mode set. Cannot generate password from empty character set.")
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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
|
// Parse the new style parameters
|
||||||
func parseNewStyleParams() {
|
func parseNewStyleParams() {
|
||||||
|
if config.newStyleModes == "" {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
for _, curParam := range config.newStyleModes {
|
for _, curParam := range config.newStyleModes {
|
||||||
switch curParam {
|
switch curParam {
|
||||||
case 'S':
|
case 'S':
|
||||||
|
@ -39,12 +83,11 @@ func parseNewStyleParams() {
|
||||||
case 'h':
|
case 'h':
|
||||||
config.humanReadable = false
|
config.humanReadable = false
|
||||||
break
|
break
|
||||||
// APG compatbilitly
|
|
||||||
case 'C':
|
case 'C':
|
||||||
config.useUpperCase = true
|
config.useComplex = true
|
||||||
break
|
break
|
||||||
case 'c':
|
case 'c':
|
||||||
config.useUpperCase = false
|
config.useComplex = false
|
||||||
break
|
break
|
||||||
default:
|
default:
|
||||||
fmt.Printf("Unknown password style parameter: %q\n", string(curParam))
|
fmt.Printf("Unknown password style parameter: %q\n", string(curParam))
|
||||||
|
@ -52,36 +95,3 @@ func parseNewStyleParams() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
Loading…
Reference in a new issue