From c4f6f8b5e1913906b21f31f1b8dd675ebc68a6cf Mon Sep 17 00:00:00 2001 From: Anand Date: Sat, 11 Dec 2021 20:45:12 +0530 Subject: [PATCH 01/12] ref issue #9 - moved all argument parsing logic to main.go --- main.go | 86 +++++++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 69 insertions(+), 17 deletions(-) diff --git a/main.go b/main.go index 927f8ff..462efea 100644 --- a/main.go +++ b/main.go @@ -5,7 +5,8 @@ package main import ( "fmt" "strconv" - getopt "github.com/pborman/getopt/v2" + // getopt "github.com/pborman/getopt/v2" + "github.com/akamensky/argparse" "os" ) @@ -17,9 +18,17 @@ type actionFunc func(string) error type actionFunc2 func(string) (error, string) type voidFunc func() error +// Structure to keep the options data +type CmdOption struct { + Short string + Long string + Help string + Default string +} + // Print the program's usage string and exit func printUsage() error { - getopt.Usage() + // getopt.Usage() os.Exit(0) return nil @@ -57,8 +66,8 @@ func generatePassword(length string) (error, string) { return nil, passwd } -// Perform an action by using the command line options map -func performAction(optMap map[string]interface{}, optionMap map[string]interface{}) { +// // Perform an action by using the command line options map +func performAction(optMap map[string]interface{}) { var flag bool @@ -99,6 +108,7 @@ func performAction(optMap map[string]interface{}, optionMap map[string]interface } } + // One of bool or string actions for key, mappedFunc := range boolActionsMap { if *optMap[key].(*bool) { @@ -113,9 +123,7 @@ func performAction(optMap map[string]interface{}, optionMap map[string]interface } for key, mappedFunc := range stringActionsMap { - option := optionMap[key].(Option) - - if *optMap[key].(*string) != option.Path { + if *optMap[key].(*string) != "" { var val = *(optMap[key].(*string)) mappedFunc(val) @@ -129,10 +137,7 @@ func performAction(optMap map[string]interface{}, optionMap map[string]interface } for key, mappedFunc := range stringActions2Map { - option := optionMap[key].(Option) - - if *optMap[key].(*string) != option.Path { - + if *optMap[key].(*string) != "" { var val = *(optMap[key].(*string)) mappedFunc(val) break @@ -141,19 +146,66 @@ func performAction(optMap map[string]interface{}, optionMap map[string]interface } +func initializeCmdLine(parser *argparse.Parser) map[string]interface{} { + var optMap map[string]interface{} + + optMap = make(map[string]interface{}) + + boolOptions := []CmdOption{ + {"e", "encrypt", "Encrypt the current database", ""}, + {"A", "add", "Add a new entry", ""}, + {"p", "path", "Show current database path", ""}, + {"a", "list-all", "List all entries in current database", ""}, + {"s", "show", "Show passwords when listing entries", ""}, + {"c", "copy", "Copy password to clipboard", ""}, + {"v", "version", "Show version information and exit", ""}, + {"h", "help", "Print this help message and exit", ""}, + } + + for _, opt := range boolOptions { + optMap[opt.Long] = parser.Flag(string(opt.Short), opt.Long, &argparse.Options{Help: opt.Help}) + } + + stringOptions := []CmdOption{ + {"I", "init", "Initialize a new database", ""}, + {"d", "decrypt", "Decrypt password database", ""}, + {"C", "clone", "Clone an entry", ""}, + {"R", "remove", "Remove an entry", ""}, + {"U", "use-db", "Set as active database", ""}, + {"f", "find", "Search entries", ""}, + {"E", "edit", "Edit entry by id", ""}, + {"l", "list-entry", "List entry by id", ""}, + {"x", "export", "Export all entries to ", ""}, + {"g", "genpass", "Generate password of given length", "12"}, + } + + for _, opt := range stringOptions { + optMap[opt.Long] = parser.String(opt.Short, opt.Long, &argparse.Options{Help: opt.Help, Default: opt.Default}) + } + + return optMap +} + // Main routine func main() { if len(os.Args) == 1 { os.Args = append(os.Args, "-h") } - optMap, optionMap := initializeCommandLine() - getopt.SetUsage(func() { - usageString(optionMap) - }) + parser := argparse.NewParser("varuh", "Password manager for the command line for Unix like operating systems") + + // optMap, optionMap := initializeCommandLine(parser) - getopt.Parse() + // versionFlag := parser.Flag("v", "version", &argparse.Options{Help: "Show version information and exit"}) + optMap := initializeCmdLine(parser) + + err := parser.Parse(os.Args) + + if err != nil { + fmt.Println(parser.Usage(err)) + } + getOrCreateLocalConfig(APP) - performAction(optMap, optionMap) + performAction(optMap) } From f1ee30c50c03448c3a35b2a346f9441c6a65fe66 Mon Sep 17 00:00:00 2001 From: Anand Date: Sat, 11 Dec 2021 20:45:59 +0530 Subject: [PATCH 02/12] ref issue #9 - removed options.go --- options.go | 161 ----------------------------------------------------- 1 file changed, 161 deletions(-) delete mode 100644 options.go diff --git a/options.go b/options.go deleted file mode 100644 index c27a9a9..0000000 --- a/options.go +++ /dev/null @@ -1,161 +0,0 @@ -// Managing command line options -package main - -import ( - "fmt" - "strings" - - getopt "github.com/pborman/getopt/v2" -) - -// Structure to keep the options data -type Option struct { - Short rune - Long string - Path string - Help string - Type uint8 -} - -// Usage string template -const HELP_STRING = ` -SYNOPSIS - - %s [options] [flags] - -OPTIONS - - EDIT/CREATE ACTIONS: - -%s - - FIND/LIST ACTIONS: - -%s - - MISC ACTIONS: - -%s - - HELP ACTIONS: - -%s - - FLAGS: - -%s - - -AUTHORS - Copyright (C) 2021 %s -` - -// Generate the usage string for the program -func usageString(optMap map[string]interface{}) { - - var editActions []string - var findActions []string - var helpActions []string - var flagActions []string - var miscActions []string - - var maxLen1 int - var maxLen2 int - - var usageTemplate = "%8s --%s %s %s" - - // Find max string length - for _, value := range optMap { - option := value.(Option) - - if len(option.Long) > maxLen1 { - maxLen1 = len(option.Long) - } - if len(option.Path) > maxLen2 { - maxLen2 = len(option.Path) - } - } - - for _, value := range optMap { - option := value.(Option) - - delta := maxLen1 + 5 - len(option.Long) - for i := 0; i < delta; i++ { - option.Long += " " - } - - if len(option.Path) < maxLen2 { - delta := maxLen2 - len(option.Path) - for i := 0; i < delta; i++ { - option.Path += " " - } - } - - switch option.Type { - case 0: - editActions = append(editActions, fmt.Sprintf(usageTemplate, "-"+string(option.Short), option.Long, option.Path, option.Help)) - case 1: - findActions = append(findActions, fmt.Sprintf(usageTemplate, "-"+string(option.Short), option.Long, option.Path, option.Help)) - case 2: - helpActions = append(helpActions, fmt.Sprintf(usageTemplate, "-"+string(option.Short), option.Long, option.Path, option.Help)) - case 3: - flagActions = append(flagActions, fmt.Sprintf(usageTemplate, "-"+string(option.Short), option.Long, option.Path, option.Help)) - case 4: - miscActions = append(miscActions, fmt.Sprintf(usageTemplate, "-"+string(option.Short), option.Long, option.Path, option.Help)) - } - } - - fmt.Println(fmt.Sprintf(HELP_STRING, APP, - strings.Join(editActions, "\n"), - strings.Join(findActions, "\n"), - strings.Join(miscActions, "\n"), - strings.Join(helpActions, "\n"), - strings.Join(flagActions, "\n"), - AUTHOR_EMAIL)) - -} - -// Set up command line options - returns two maps -func initializeCommandLine() (map[string]interface{}, map[string]interface{}) { - var optMap map[string]interface{} - var optionMap map[string]interface{} - - optMap = make(map[string]interface{}) - optionMap = make(map[string]interface{}) - - stringOptions := []Option{ - {'I', "init", "", "Initialize a new database", 0}, - {'d', "decrypt", "", "Decrypt password database", 0}, - {'C', "clone", "", "Clone an entry", 0}, - {'R', "remove", "", "Remove an entry", 0}, - {'U', "use-db", "", "Set as active database", 0}, - {'f', "find", "", "Search entries", 1}, - {'E', "edit", "", "Edit entry by id", 0}, - {'l', "list-entry", "", "List entry by id", 1}, - {'x', "export", "", "Export all entries to ", 1}, - {'g', "genpass", "", "Generate password of given length", 4}, - } - - for _, opt := range stringOptions { - optMap[opt.Long] = getopt.StringLong(opt.Long, opt.Short, opt.Path, opt.Help) - optionMap[opt.Long] = opt - } - - boolOptions := []Option{ - {'e', "encrypt", "", "Encrypt the current database", 0}, - {'A', "add", "", "Add a new entry", 0}, - {'p', "path", "", "Show current database path", 1}, - {'a', "list-all", "", "List all entries in current database", 1}, - {'s', "show", "", "Show passwords when listing entries", 3}, - {'c', "copy", "", "Copy password to clipboard", 3}, - {'v', "version", "", "Show version information and exit", 2}, - {'h', "help", "", "Print this help message and exit", 2}, - } - - for _, opt := range boolOptions { - optMap[opt.Long] = getopt.BoolLong(opt.Long, opt.Short, opt.Help) - optionMap[opt.Long] = opt - } - - return optMap, optionMap -} From bd05925863c9f1f396530a959b4e89dfcf2b6fb3 Mon Sep 17 00:00:00 2001 From: Anand Date: Sun, 12 Dec 2021 13:13:21 +0530 Subject: [PATCH 03/12] ref issue #9 - Updated version number --- main.go | 93 +++++++++++++++++++++++++++++---------------------------- 1 file changed, 48 insertions(+), 45 deletions(-) diff --git a/main.go b/main.go index 462efea..8396fd7 100644 --- a/main.go +++ b/main.go @@ -4,15 +4,18 @@ package main import ( "fmt" - "strconv" - // getopt "github.com/pborman/getopt/v2" - "github.com/akamensky/argparse" + "github.com/pythonhacker/argparse" "os" + "strconv" ) -const VERSION = 0.2 +const VERSION = 0.3 const APP = "varuh" -const AUTHOR_EMAIL = "Anand B Pillai " + +const AUTHOR_INFO = ` +AUTHORS + Copyright (C) 2021 Anand B Pillai +` type actionFunc func(string) error type actionFunc2 func(string) (error, string) @@ -20,9 +23,10 @@ type voidFunc func() error // Structure to keep the options data type CmdOption struct { - Short string - Long string - Help string + Short string + Long string + Help string + Path string Default string } @@ -43,13 +47,13 @@ func printVersionInfo() error { } // Command-line wrapper to generateRandomPassword -func generatePassword(length string) (error, string) { +func genPass(length string) (error, string) { var iLength int var err error var passwd string - + iLength, _ = strconv.Atoi(length) - err, passwd = generateRandomPassword(iLength) + err, passwd = generatePassword(iLength) if err != nil { fmt.Printf("Error generating password - \"%s\"\n", err.Error()) @@ -62,7 +66,7 @@ func generatePassword(length string) (error, string) { copyPasswordToClipboard(passwd) fmt.Println("Password copied to clipboard") } - + return nil, passwd } @@ -93,7 +97,7 @@ func performAction(optMap map[string]interface{}) { stringActions2Map := map[string]actionFunc2{ "decrypt": decryptDatabase, - "genpass": generatePassword, + "genpass": genPass, } flagsActionsMap := map[string]voidFunc{ @@ -108,7 +112,6 @@ func performAction(optMap map[string]interface{}) { } } - // One of bool or string actions for key, mappedFunc := range boolActionsMap { if *optMap[key].(*bool) { @@ -151,38 +154,38 @@ func initializeCmdLine(parser *argparse.Parser) map[string]interface{} { optMap = make(map[string]interface{}) + stringOptions := []CmdOption{ + {"I", "init", "Initialize a new database", "", ""}, + {"d", "decrypt", "Decrypt password database", "", ""}, + {"C", "clone", "Clone an entry with ", "", ""}, + {"R", "remove", "Remove an entry with ", "", ""}, + {"U", "use-db", "Set as active database", "", ""}, + {"f", "find", "Search entries with ", "", ""}, + {"E", "edit", "Edit entry by ", "", ""}, + {"l", "list-entry", "List entry by ", "", ""}, + {"x", "export", "Export all entries to ", "", ""}, + {"g", "genpass", "Generate password of given ", "", ""}, + } + + for _, opt := range stringOptions { + optMap[opt.Long] = parser.String(opt.Short, opt.Long, &argparse.Options{Help: opt.Help, Path: opt.Path}) + } + boolOptions := []CmdOption{ - {"e", "encrypt", "Encrypt the current database", ""}, - {"A", "add", "Add a new entry", ""}, - {"p", "path", "Show current database path", ""}, - {"a", "list-all", "List all entries in current database", ""}, - {"s", "show", "Show passwords when listing entries", ""}, - {"c", "copy", "Copy password to clipboard", ""}, - {"v", "version", "Show version information and exit", ""}, - {"h", "help", "Print this help message and exit", ""}, + {"e", "encrypt", "Encrypt the current database", "", ""}, + {"A", "add", "Add a new entry", "", ""}, + {"p", "path", "Show current database path", "", ""}, + {"a", "list-all", "List all entries in current database", "", ""}, + {"s", "show", "Show passwords when listing entries", "", ""}, + {"c", "copy", "Copy password to clipboard", "", ""}, + {"v", "version", "Show version information and exit", "", ""}, + {"h", "help", "Print this help message and exit", "", ""}, } for _, opt := range boolOptions { optMap[opt.Long] = parser.Flag(string(opt.Short), opt.Long, &argparse.Options{Help: opt.Help}) - } - - stringOptions := []CmdOption{ - {"I", "init", "Initialize a new database", ""}, - {"d", "decrypt", "Decrypt password database", ""}, - {"C", "clone", "Clone an entry", ""}, - {"R", "remove", "Remove an entry", ""}, - {"U", "use-db", "Set as active database", ""}, - {"f", "find", "Search entries", ""}, - {"E", "edit", "Edit entry by id", ""}, - {"l", "list-entry", "List entry by id", ""}, - {"x", "export", "Export all entries to ", ""}, - {"g", "genpass", "Generate password of given length", "12"}, } - for _, opt := range stringOptions { - optMap[opt.Long] = parser.String(opt.Short, opt.Long, &argparse.Options{Help: opt.Help, Default: opt.Default}) - } - return optMap } @@ -192,19 +195,19 @@ func main() { os.Args = append(os.Args, "-h") } - parser := argparse.NewParser("varuh", "Password manager for the command line for Unix like operating systems") - - // optMap, optionMap := initializeCommandLine(parser) + parser := argparse.NewParser("varuh", + "Password manager for the command line for Unix like operating systems", + AUTHOR_INFO, + ) - // versionFlag := parser.Flag("v", "version", &argparse.Options{Help: "Show version information and exit"}) optMap := initializeCmdLine(parser) - + err := parser.Parse(os.Args) if err != nil { fmt.Println(parser.Usage(err)) } - + getOrCreateLocalConfig(APP) performAction(optMap) From ec5b88bcd046927ce01332caa8ee7ba441f399a9 Mon Sep 17 00:00:00 2001 From: Anand Date: Sun, 12 Dec 2021 13:16:46 +0530 Subject: [PATCH 04/12] ref issue #9 - Updated usage on README.md --- README.md | 88 ++++++++++++++++++++++++++----------------------------- 1 file changed, 41 insertions(+), 47 deletions(-) diff --git a/README.md b/README.md index b81d83a..ec77c22 100644 --- a/README.md +++ b/README.md @@ -50,12 +50,15 @@ should work. Then, - $ make - go: downloading github.com/kirsle/configdir v0.0.0-20170128060238-e45d2f54772f - go: downloading github.com/pborman/getopt/v2 v2.1.0 - go: downloading golang.org/x/crypto v0.0.0-20210921155107-089bfa567519 - go: downloading gorm.io/driver/sqlite v1.2.3 - ... + $ make + Building varuh + go: downloading github.com/akamensky/argparse v1.3.1 + go: downloading golang.org/x/crypto v0.0.0-20210921155107-089bfa567519 + go: downloading github.com/atotto/clipboard v0.1.4 + go: downloading github.com/kirsle/configdir v0.0.0-20170128060238-e45d2f54772f + go: downloading github.com/pythonhacker/argparse v1.3.2 + go: downloading gorm.io/driver/sqlite v1.2.3 + ... $ sudo make install Installing varuh...done @@ -66,53 +69,44 @@ The binary will be installed in `/usr/local/bin` folder. Usage ===== - $ varuh -h - - - SYNOPSIS - - varuh [options] [flags] - - OPTIONS - - EDIT/CREATE ACTIONS: - - -A --add Add a new entry - -I --init Initialize a new database - -R --remove Remove an entry - -e --encrypt Encrypt the current database - -d --decrypt Decrypt password database - -C --clone Clone an entry - -U --use-db Set as active database - -E --edit Edit entry by id - - FIND/LIST ACTIONS: - - -f --find Search entries - -l --list-entry List entry by id - -x --export Export all entries to - -p --path Show current database path - -a --list-all List all entries in current database - - MISC ACTIONS: - - -g --genpass Generate password of given length - - HELP ACTIONS: - - -h --help Print this help message and exit - -v --version Show version information and exit - - FLAGS: - - -s --show Show passwords when listing entries - -c --copy Copy password to clipboard + $ ./varuh -h + usage: varuh [-h|--help] [-I|--init ""] [-d|--decrypt ""] + [-C|--clone ""] [-R|--remove ""] [-U|--use-db + ""] [-f|--find ""] [-E|--edit ""] + [-l|--list-entry ""] [-x|--export ""] [-g|--genpass + ""] [-e|--encrypt] [-A|--add] [-p|--path] [-a|--list-all] + [-s|--show] [-c|--copy] [-v|--version] + + Password manager for the command line for Unix like operating + systems + + Options: + + -h --help Print help information + -I --init Initialize a new database + -d --decrypt Decrypt password database + -C --clone Clone an entry with + -R --remove Remove an entry with + -U --use-db Set as active database + -f --find Search entries with + -E --edit Edit entry by + -l --list-entry List entry by + -x --export Export all entries to + -g --genpass Generate password of given + -e --encrypt Encrypt the current database + -A --add Add a new entry + -p --path Show current database path + -a --list-all List all entries in current database + -s --show Show passwords when listing entries + -c --copy Copy password to clipboard + -v --version Show version information and exit AUTHORS Copyright (C) 2021 Anand B Pillai + The command line flags are grouped into `Edit/Create`, `Find/List`, `Misc` and `Help` actions. The first group of actions allows you to work with password databases and perform create/edit as well as encrypt/decrypt actions. The second set of actions allows you to work with an active decrypted database and view/search/list entries. Encryption and Security From 6f4f50f778ee5e8ae1722b2c8ed70e865facee63 Mon Sep 17 00:00:00 2001 From: Anand Date: Sun, 12 Dec 2021 13:17:11 +0530 Subject: [PATCH 05/12] ref issue #9 - Updated go.{mod,sum} --- go.mod | 3 ++- go.sum | 6 ++++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 8ef09b6..f320c0a 100644 --- a/go.mod +++ b/go.mod @@ -3,9 +3,10 @@ module varuh go 1.16 require ( + github.com/akamensky/argparse v1.3.1 github.com/atotto/clipboard v0.1.4 github.com/kirsle/configdir v0.0.0-20170128060238-e45d2f54772f - github.com/pborman/getopt/v2 v2.1.0 + github.com/pythonhacker/argparse v1.3.2 golang.org/x/crypto v0.0.0-20210921155107-089bfa567519 gorm.io/driver/sqlite v1.2.3 gorm.io/gorm v1.22.2 diff --git a/go.sum b/go.sum index 87a562f..b6161ad 100644 --- a/go.sum +++ b/go.sum @@ -1,3 +1,5 @@ +github.com/akamensky/argparse v1.3.1 h1:kP6+OyvR0fuBH6UhbE6yh/nskrDEIQgEA1SUXDPjx4g= +github.com/akamensky/argparse v1.3.1/go.mod h1:S5kwC7IuDcEr5VeXtGPRVZ5o/FdhcMlQz4IZQuw64xA= github.com/atotto/clipboard v0.1.4 h1:EH0zSVneZPSuFR11BlR9YppQTVDbh5+16AmcJi4g1z4= github.com/atotto/clipboard v0.1.4/go.mod h1:ZY9tmq7sm5xIbd9bOK4onWV4S6X0u6GY7Vn0Yu86PYI= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -11,10 +13,10 @@ github.com/kirsle/configdir v0.0.0-20170128060238-e45d2f54772f h1:dKccXx7xA56UNq github.com/kirsle/configdir v0.0.0-20170128060238-e45d2f54772f/go.mod h1:4rEELDSfUAlBSyUjPG0JnaNGjf13JySHFeRdD/3dLP0= github.com/mattn/go-sqlite3 v1.14.9 h1:10HX2Td0ocZpYEjhilsuo6WWtUqttj2Kb0KtD86/KYA= github.com/mattn/go-sqlite3 v1.14.9/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= -github.com/pborman/getopt/v2 v2.1.0 h1:eNfR+r+dWLdWmV8g5OlpyrTYHkhVNxHBdN2cCrJmOEA= -github.com/pborman/getopt/v2 v2.1.0/go.mod h1:4NtW75ny4eBw9fO1bhtNdYTlZKYX5/tBLtsOpwKIKd0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pythonhacker/argparse v1.3.2 h1:JOojnYFHk7oap+MQiFgiPAHlzvhJfqukErLneWaHR/M= +github.com/pythonhacker/argparse v1.3.2/go.mod h1:gdUstTr/g1ojhRwrF9gKFOVLwsNfwarBg8aCQRjtvo8= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= From f69f83ef1c1cde654b6449b7ef9df118fa6c6188 Mon Sep 17 00:00:00 2001 From: Anand Date: Sun, 12 Dec 2021 13:18:20 +0530 Subject: [PATCH 06/12] ref issue #9 - Updated README.md, removed irrelevant lines --- README.md | 3 --- 1 file changed, 3 deletions(-) diff --git a/README.md b/README.md index ec77c22..581965b 100644 --- a/README.md +++ b/README.md @@ -106,9 +106,6 @@ Usage Copyright (C) 2021 Anand B Pillai - -The command line flags are grouped into `Edit/Create`, `Find/List`, `Misc` and `Help` actions. The first group of actions allows you to work with password databases and perform create/edit as well as encrypt/decrypt actions. The second set of actions allows you to work with an active decrypted database and view/search/list entries. - Encryption and Security ======================= From 5c2350bcede4c5293de81884910c059d955171ad Mon Sep 17 00:00:00 2001 From: Anand Date: Sun, 12 Dec 2021 14:00:15 +0530 Subject: [PATCH 07/12] ref issue #13 - generate strong passwords --- crypto.go | 100 ++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 98 insertions(+), 2 deletions(-) diff --git a/crypto.go b/crypto.go index 924031f..2c9ac69 100644 --- a/crypto.go +++ b/crypto.go @@ -13,7 +13,9 @@ import ( "golang.org/x/crypto/pbkdf2" "io" "math/big" + "math/rand" "os" + "time" "unsafe" crand "crypto/rand" @@ -435,10 +437,10 @@ func decryptFileXChachaPoly(encDbPath string, password string) error { } // Generate a random password - for adding listings -func generateRandomPassword(length int) (error, string) { +func generatePassword(length int) (error, string) { var data []byte - const source = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789?)(/%#!?)=" + const source = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789=+_()$#@!~:/%" data = make([]byte, length) @@ -453,3 +455,97 @@ func generateRandomPassword(length int) (error, string) { return nil, string(data) } + +// Generate a "strong" password +// A strong password is defined as, +// A mix of upper and lower case alphabets +// at least one number [0-9] +// at least one upper case alphabet [A-Z] +// at least one punctuation character +// at least length 12 +func generateStrongPassword() (error, string) { + + var data []byte + var length int + + const sourceAlpha = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" + const sourceLargeAlpha = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + const sourceNum = "0123456789" + const sourcePunct = "=+_()$#@!~:/%" + const source = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789=+_()$#@!~:/%" + + // Generate in range 12 - 16 + rand.Seed(time.Now().UnixNano()) + + length = rand.Intn(4) + 12 + + data = make([]byte, length) + + var lengthAlpha int + var i, j, k, l int + + // Alpha chars is at least length 3-5 + lengthAlpha = rand.Intn(2) + 3 + + for i = 0; i < lengthAlpha; i++ { + num, err := crand.Int(crand.Reader, big.NewInt(int64(len(sourceAlpha)))) + if err != nil { + return err, "" + } + + data[i] = sourceAlpha[num.Int64()] + } + + // Add in numbers 1 or 2 + var lengthNum int + + lengthNum = rand.Intn(2) + 1 + + for j = i; j < i+lengthNum; j++ { + num, err := crand.Int(crand.Reader, big.NewInt(int64(len(sourceNum)))) + if err != nil { + return err, "" + } + + data[j] = sourceNum[num.Int64()] + } + + // Add in punctuations 1 or 2 + var lengthPunc int + + lengthPunc = rand.Intn(2) + 1 + + for k = j; k < j+lengthPunc; k++ { + num, err := crand.Int(crand.Reader, big.NewInt(int64(len(sourcePunct)))) + if err != nil { + return err, "" + } + + data[k] = sourcePunct[num.Int64()] + } + + // Fill in the rest + var lengthRem int + + lengthRem = length - k + + if lengthRem > 0 { + for l = k; l < k+lengthRem; l++ { + num, err := crand.Int(crand.Reader, big.NewInt(int64(len(source)))) + if err != nil { + return err, "" + } + + data[l] = source[num.Int64()] + } + } + + // Shuffle a few times + for i = 0; i < 5; i++ { + rand.Shuffle(len(data), func(i, j int) { + data[i], data[j] = data[j], data[i] + }) + } + + return nil, string(data) +} From 023045bfe3a82cff3470622207fc4bf96375de34 Mon Sep 17 00:00:00 2001 From: Anand Date: Sun, 12 Dec 2021 14:00:29 +0530 Subject: [PATCH 08/12] ref issue #13 - use strong passwords in creating entries --- actions.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/actions.go b/actions.go index 73a61bb..e6db91c 100644 --- a/actions.go +++ b/actions.go @@ -239,7 +239,7 @@ func addNewEntry() error { if len(passwd) == 0 { fmt.Printf("\nGenerating password ...") - err, passwd = generateRandomPassword(16) + err, passwd = generateStrongPassword() fmt.Printf("done") } // fmt.Printf("Password => %s\n", passwd) @@ -315,7 +315,7 @@ func editCurrentEntry(idString string) error { if strings.ToLower(passwd) == "y" { fmt.Printf("\nGenerating new password ...") - err, passwd = generateRandomPassword(16) + err, passwd = generateStrongPassword() } // fmt.Printf("Password => %s\n", passwd) From 4a856e718d88c1ddd33cf2fbd66c9078039f2d24 Mon Sep 17 00:00:00 2001 From: Anand Date: Sun, 12 Dec 2021 14:00:42 +0530 Subject: [PATCH 09/12] ref issue #13 - generate strong passwords --- main.go | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/main.go b/main.go index 8396fd7..343073d 100644 --- a/main.go +++ b/main.go @@ -6,7 +6,6 @@ import ( "fmt" "github.com/pythonhacker/argparse" "os" - "strconv" ) const VERSION = 0.3 @@ -20,6 +19,7 @@ AUTHORS type actionFunc func(string) error type actionFunc2 func(string) (error, string) type voidFunc func() error +type voidFunc2 func() (error, string) // Structure to keep the options data type CmdOption struct { @@ -47,13 +47,11 @@ func printVersionInfo() error { } // Command-line wrapper to generateRandomPassword -func genPass(length string) (error, string) { - var iLength int +func genPass() (error, string) { var err error var passwd string - iLength, _ = strconv.Atoi(length) - err, passwd = generatePassword(iLength) + err, passwd = generateStrongPassword() if err != nil { fmt.Printf("Error generating password - \"%s\"\n", err.Error()) @@ -97,6 +95,9 @@ func performAction(optMap map[string]interface{}) { stringActions2Map := map[string]actionFunc2{ "decrypt": decryptDatabase, + } + + flagsActions2Map := map[string]voidFunc2{ "genpass": genPass, } @@ -112,6 +113,15 @@ func performAction(optMap map[string]interface{}) { } } + // Flag 2 actions + for key, mappedFunc := range flagsActions2Map { + if *optMap[key].(*bool) { + mappedFunc() + flag = true + break + } + } + // One of bool or string actions for key, mappedFunc := range boolActionsMap { if *optMap[key].(*bool) { @@ -164,7 +174,6 @@ func initializeCmdLine(parser *argparse.Parser) map[string]interface{} { {"E", "edit", "Edit entry by ", "", ""}, {"l", "list-entry", "List entry by ", "", ""}, {"x", "export", "Export all entries to ", "", ""}, - {"g", "genpass", "Generate password of given ", "", ""}, } for _, opt := range stringOptions { @@ -176,6 +185,7 @@ func initializeCmdLine(parser *argparse.Parser) map[string]interface{} { {"A", "add", "Add a new entry", "", ""}, {"p", "path", "Show current database path", "", ""}, {"a", "list-all", "List all entries in current database", "", ""}, + {"g", "genpass", "Generate a strong password of length from 8 - 12", "", ""}, {"s", "show", "Show passwords when listing entries", "", ""}, {"c", "copy", "Copy password to clipboard", "", ""}, {"v", "version", "Show version information and exit", "", ""}, From 9118a489beaab1f11e1b14e10e829d2d0f208282 Mon Sep 17 00:00:00 2001 From: Anand Date: Sun, 12 Dec 2021 14:04:31 +0530 Subject: [PATCH 10/12] ref issue #9 - Updated README.md with updated usage --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 581965b..056223e 100644 --- a/README.md +++ b/README.md @@ -73,9 +73,9 @@ Usage usage: varuh [-h|--help] [-I|--init ""] [-d|--decrypt ""] [-C|--clone ""] [-R|--remove ""] [-U|--use-db ""] [-f|--find ""] [-E|--edit ""] - [-l|--list-entry ""] [-x|--export ""] [-g|--genpass - ""] [-e|--encrypt] [-A|--add] [-p|--path] [-a|--list-all] - [-s|--show] [-c|--copy] [-v|--version] + [-l|--list-entry ""] [-x|--export ""] [-e|--encrypt] + [-A|--add] [-p|--path] [-a|--list-all] [-g|--genpass] [-s|--show] + [-c|--copy] [-v|--version] Password manager for the command line for Unix like operating systems @@ -92,11 +92,11 @@ Usage -E --edit Edit entry by -l --list-entry List entry by -x --export Export all entries to - -g --genpass Generate password of given -e --encrypt Encrypt the current database -A --add Add a new entry -p --path Show current database path -a --list-all List all entries in current database + -g --genpass Generate a strong password of length from 8 - 12 -s --show Show passwords when listing entries -c --copy Copy password to clipboard -v --version Show version information and exit From 26ed9f52f0cf6e23c0c972e8fb2533320cc00fda Mon Sep 17 00:00:00 2001 From: Anand Date: Sun, 12 Dec 2021 14:05:48 +0530 Subject: [PATCH 11/12] ref issue #9 - Updated help for genpass --- main.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/main.go b/main.go index 343073d..6f90f87 100644 --- a/main.go +++ b/main.go @@ -185,7 +185,7 @@ func initializeCmdLine(parser *argparse.Parser) map[string]interface{} { {"A", "add", "Add a new entry", "", ""}, {"p", "path", "Show current database path", "", ""}, {"a", "list-all", "List all entries in current database", "", ""}, - {"g", "genpass", "Generate a strong password of length from 8 - 12", "", ""}, + {"g", "genpass", "Generate a strong password of length from 12 - 16", "", ""}, {"s", "show", "Show passwords when listing entries", "", ""}, {"c", "copy", "Copy password to clipboard", "", ""}, {"v", "version", "Show version information and exit", "", ""}, From d30e22930b125de438487c4fbff266debe6228d8 Mon Sep 17 00:00:00 2001 From: Anand Date: Sun, 12 Dec 2021 14:05:55 +0530 Subject: [PATCH 12/12] ref issue #9 - Updated help for genpass --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 056223e..db30300 100644 --- a/README.md +++ b/README.md @@ -96,7 +96,7 @@ Usage -A --add Add a new entry -p --path Show current database path -a --list-all List all entries in current database - -g --genpass Generate a strong password of length from 8 - 12 + -g --genpass Generate a strong password of length from 12 - 16 -s --show Show passwords when listing entries -c --copy Copy password to clipboard -v --version Show version information and exit