Implement password generation on new entries

This commit is contained in:
2024-03-07 16:04:46 -05:00
parent 22fcad2fed
commit 1e1a26b098
4 changed files with 102 additions and 17 deletions
+22 -11
View File
@@ -35,7 +35,8 @@ func main() {
cli.EntryReaderShortcut(targetLocation, false) cli.EntryReaderShortcut(targetLocation, false)
case "shear": case "shear":
offline.Shear(targetLocation) offline.Shear(targetLocation)
case "gen": // TODO offline.Gen(targetLocation), exit after run case "gen":
cli.AddEntry(targetLocation, true, 1)
case "copy": case "copy":
cli.HelpCopy() cli.HelpCopy()
case "edit": case "edit":
@@ -87,30 +88,40 @@ func main() {
switch args[3] { switch args[3] {
case "password", "-p": case "password", "-p":
if argsCount == 4 { if argsCount == 4 {
cli.AddEntry(targetLocation, true, false) cli.AddEntry(targetLocation, true, 0)
} else { } else {
switch args[4] { switch args[4] {
case "show", "-s": case "show", "-s":
cli.AddEntry(targetLocation, false, false) cli.AddEntry(targetLocation, false, 0)
default: default:
cli.AddEntry(targetLocation, true, false) cli.AddEntry(targetLocation, true, 0)
} }
} }
case "note", "-n": case "note", "-n":
cli.AddEntry(targetLocation, true, true) cli.AddEntry(targetLocation, true, 2)
case "folder", "-f": case "folder", "-f":
offline.AddFolder(targetLocation) offline.AddFolder(targetLocation)
default: default:
cli.HelpAdd() cli.HelpAdd()
} }
case "gen": case "gen":
var field rune if argsCount == 4 {
field = field // TODO temporary to avoid unused variable error switch args[3] {
switch args[3] { case "show", "-s":
case "update", "-u": // TODO offline.GenUpdate(targetLocation), exit after run cli.AddEntry(targetLocation, false, 1)
default: case "update", "-u": // TODO offline.GenUpdate(targetLocation), exit after run
cli.HelpGen() default:
cli.HelpGen()
}
} else if args[3] == "update" || args[3] == "-u" {
switch args[4] {
case "show", "-s":
cli.AddEntry(targetLocation, false, 1)
default:
cli.AddEntry(targetLocation, true, 1)
}
} }
cli.HelpGen()
default: default:
cli.HelpMain() cli.HelpMain()
} }
+12 -3
View File
@@ -7,7 +7,8 @@ import (
) )
// AddEntry creates a new entry at targetLocation by taking user input via CLI prompts // AddEntry creates a new entry at targetLocation by taking user input via CLI prompts
func AddEntry(targetLocation string, hidePassword bool, isNote bool) { // entryType: 0 = standard (password), 1 = auto-generated password, 2 = note
func AddEntry(targetLocation string, hidePassword bool, entryType uint8) {
_, isAccessible := offline.TargetIsFile(targetLocation, false, 0) _, isAccessible := offline.TargetIsFile(targetLocation, false, 0)
if isAccessible { if isAccessible {
fmt.Println(offline.AnsiError + "Target location already exists" + offline.AnsiReset) fmt.Println(offline.AnsiError + "Target location already exists" + offline.AnsiReset)
@@ -16,9 +17,17 @@ func AddEntry(targetLocation string, hidePassword bool, isNote bool) {
var unencryptedEntry []string var unencryptedEntry []string
if !isNote { if entryType < 2 {
username := input("Username:") username := input("Username:")
password := inputHidden("Password:")
// determine whether to generate the password
var password string
if entryType == 0 {
password = inputHidden("Password:")
} else {
password = offline.StringGen(inputInt("Password length:"), inputBinary("Generate a complex (special characters) password?"), 0.2)
}
url := input("URL:") url := input("URL:")
if inputBinary("Add a note to this entry?") { if inputBinary("Add a note to this entry?") {
note := newNote() note := newNote()
+17 -3
View File
@@ -12,9 +12,9 @@ import (
// input prompts the user for input and returns the input as a string // input prompts the user for input and returns the input as a string
func input(prompt string) string { func input(prompt string) string {
fmt.Print("\n" + prompt + " ") fmt.Print("\n" + prompt + " ")
var input string var userInput string
fmt.Scanln(&input) fmt.Scanln(&userInput)
return input return userInput
} }
// inputHidden prompts the user for input and returns the input as a string, hiding the input from the terminal // inputHidden prompts the user for input and returns the input as a string, hiding the input from the terminal
@@ -26,6 +26,20 @@ func inputHidden(prompt string) string {
return password return password
} }
// inputInt prompts the user for input and returns the input as an integer
func inputInt(prompt string) int {
// loop until a valid integer is entered
for {
fmt.Print("\n" + prompt + " ")
var userInput int
_, err := fmt.Scanln(&userInput)
if err == nil {
return userInput
}
}
}
// inputBinary prompts the user with a yes/no question and returns the response as a boolean // inputBinary prompts the user with a yes/no question and returns the response as a boolean
func inputBinary(prompt string) bool { func inputBinary(prompt string) bool {
reader := bufio.NewReader(os.Stdin) reader := bufio.NewReader(os.Stdin)
+51
View File
@@ -1,10 +1,14 @@
package offline package offline
import ( import (
"crypto/rand"
"fmt" "fmt"
"io" "io"
"math"
"math/big"
"os" "os"
"os/exec" "os/exec"
"strings"
) )
// TargetIsFile TargetStatusCheck checks if the targetLocation is a file, directory, or is inaccessible // TargetIsFile TargetStatusCheck checks if the targetLocation is a file, directory, or is inaccessible
@@ -63,3 +67,50 @@ func RemoveTrailingEmptyStrings(slice []string) []string {
} }
return []string{} return []string{}
} }
// StringGen generates a random string of a specified length and complexity
// complexity: minimum percentage of special characters to be returned in the generated string (only impacts complex strings)
func StringGen(length int, complex bool, complexity float64) string {
var extendedCharset string // hold extended character set used for complex strings
var actualSpecialChars int // track the number of special characters in the generated string
var minSpecialChars int // track the minimum number of special characters to accept
charset := "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" // default character set used for all strings
if complex {
minSpecialChars = int(math.Round(float64(length) * complexity)) // determine minimum number of special characters to accept
extendedCharset = "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~"
charset = charset + extendedCharset
} else {
extendedCharset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
}
for {
// generate a random string
result := make([]byte, length)
for i := range result {
val, _ := rand.Int(rand.Reader, big.NewInt(int64(len(charset))))
result[i] = charset[val.Int64()]
}
// return early if the string is not complex
if !complex {
return string(result)
}
// count the number of special characters in the generated string
for _, char := range string(result) {
if strings.ContainsRune(extendedCharset, char) {
actualSpecialChars++
}
}
// return the generated string if it contains enough special characters
if actualSpecialChars >= minSpecialChars {
return string(result)
}
// reset special character counter
fmt.Println("Regenerating string until desired complexity is achieved...")
actualSpecialChars = 0
}
}