Added spelling of pws. Ready for v0.2.4

This commit is contained in:
Winni Neessen 2021-03-21 15:28:23 +01:00
parent eb221ccc69
commit 8b9269b1b9
Signed by: wneessen
GPG key ID: 385AC9889632126E
4 changed files with 258 additions and 38 deletions

21
apg.go
View file

@ -30,8 +30,10 @@ type cliOpts struct {
humanReadable bool
excludeChars string
newStyleModes string
spellPassword bool
showHelp bool
showVersion bool
outputMode int
}
var config cliOpts
@ -43,7 +45,8 @@ func init() {
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.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.showVersion, "v", false, "Show version")
@ -76,6 +79,22 @@ func main() {
fmt.Printf("getRandChar returned an error: %q\n", err.Error())
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)
break
}
}
}
}

View file

@ -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
func TestForceFailures(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
func containsByte(allowedBytes []int, currentChar int) bool {
for _, charInt := range allowedBytes {

110
convert.go Normal file
View 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
}

View file

@ -5,8 +5,52 @@ import (
"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
func parseNewStyleParams() {
if config.newStyleModes == "" {
return
}
for _, curParam := range config.newStyleModes {
switch curParam {
case 'S':
@ -39,12 +83,11 @@ func parseNewStyleParams() {
case 'h':
config.humanReadable = false
break
// APG compatbilitly
case 'C':
config.useUpperCase = true
config.useComplex = true
break
case 'c':
config.useUpperCase = false
config.useComplex = false
break
default:
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)
}
}