lockbox

password manager
Log | Files | Refs | README | LICENSE

commit 46b3081dec779154e1e7e384a5d2817c8cf10166
parent e38ad9499b99a03affe1dba77f911e84d8d0a7ca
Author: Sean Enck <sean@ttypty.com>
Date:   Sat, 16 Jul 2022 09:41:02 -0400

restructure utils.go

Diffstat:
Ainternal/colors.go | 40++++++++++++++++++++++++++++++++++++++++
Ainternal/inputs.go | 121+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ainternal/store.go | 51+++++++++++++++++++++++++++++++++++++++++++++++++++
Minternal/utils.go | 192-------------------------------------------------------------------------------
4 files changed, 212 insertions(+), 192 deletions(-)

diff --git a/internal/colors.go b/internal/colors.go @@ -0,0 +1,40 @@ +package internal + +import ( + "errors" +) + +type ( + // Color are terminal colors for dumb terminal coloring. + Color int +) + +const ( + termBeginRed = "\033[1;31m" + termEndRed = "\033[0m" + // ColorRed will get red terminal coloring. + ColorRed = iota +) + +// GetColor will retrieve start/end terminal coloration indicators. +func GetColor(color Color) (string, string, error) { + if color != ColorRed { + return "", "", errors.New("bad color") + } + interactive, err := IsInteractive() + if err != nil { + return "", "", err + } + colors := interactive + if colors { + isColored, err := isYesNoEnv(false, "LOCKBOX_NOCOLOR") + if err != nil { + return "", "", err + } + colors = !isColored + } + if colors { + return termBeginRed, termEndRed, nil + } + return "", "", nil +} diff --git a/internal/inputs.go b/internal/inputs.go @@ -0,0 +1,121 @@ +package internal + +import ( + "bufio" + "bytes" + "fmt" + "os" + "strings" + "syscall" +) + +func isYesNoEnv(defaultValue bool, env string) (bool, error) { + value := strings.ToLower(strings.TrimSpace(os.Getenv(env))) + if len(value) == 0 { + return defaultValue, nil + } + switch value { + case "no": + return false, nil + case "yes": + return true, nil + } + return false, fmt.Errorf("invalid yes/no env value for %s", env) +} + +// IsInteractive indicates if running as a user UI experience. +func IsInteractive() (bool, error) { + return isYesNoEnv(true, "LOCKBOX_INTERACTIVE") +} + +func termEcho(on bool) { + // Common settings and variables for both stty calls. + attrs := syscall.ProcAttr{ + Dir: "", + Env: []string{}, + Files: []uintptr{os.Stdin.Fd(), os.Stdout.Fd(), os.Stderr.Fd()}, + Sys: nil} + var ws syscall.WaitStatus + cmd := "echo" + if !on { + cmd = "-echo" + } + + // Enable/disable echoing. + pid, err := syscall.ForkExec( + "/bin/stty", + []string{"stty", cmd}, + &attrs) + if err != nil { + panic(err) + } + + // Wait for the stty process to complete. + _, err = syscall.Wait4(pid, &ws, 0, nil) + if err != nil { + panic(err) + } +} + +// ConfirmInputsMatch will get 2 inputs and confirm they are the same. +func ConfirmInputsMatch(object string) (string, error) { + termEcho(false) + defer func() { + termEcho(true) + }() + fmt.Printf("please enter %s: ", object) + first, err := Stdin(true) + if err != nil { + return "", err + } + fmt.Printf("\nplease re-enter %s: ", object) + second, err := Stdin(true) + if err != nil { + return "", err + } + if first != second { + return "", fmt.Errorf("%s(s) do NOT match", object) + } + return first, nil +} + +// Stdin will retrieve stdin data. +func Stdin(one bool) (string, error) { + b, err := getStdin(one) + if err != nil { + return "", err + } + return strings.TrimSpace(string(b)), nil +} + +// IsInputFromPipe will indicate if connected to stdin pipe. +func IsInputFromPipe() bool { + fileInfo, _ := os.Stdin.Stat() + return fileInfo.Mode()&os.ModeCharDevice == 0 +} + +// ConfirmYesNoPrompt will ask a yes/no question. +func ConfirmYesNoPrompt(prompt string) (bool, error) { + fmt.Printf("%s? (y/N) ", prompt) + resp, err := Stdin(true) + if err != nil { + return false, err + } + return resp == "Y" || resp == "y", nil +} + +func getStdin(one bool) ([]byte, error) { + scanner := bufio.NewScanner(os.Stdin) + var b bytes.Buffer + for scanner.Scan() { + b.WriteString(scanner.Text()) + b.WriteString("\n") + if one { + break + } + } + if err := scanner.Err(); err != nil { + return nil, err + } + return b.Bytes(), nil +} diff --git a/internal/store.go b/internal/store.go @@ -0,0 +1,51 @@ +package internal + +import ( + "errors" + "io/fs" + "os" + "path/filepath" + "sort" + "strings" +) + +const ( + // Extension is the lockbox file extension. + Extension = ".lb" +) + +// GetStore gets the lockbox directory. +func GetStore() string { + return os.Getenv("LOCKBOX_STORE") +} + +// List will get all lockbox files in a directory store. +func List(store string, display bool) ([]string, error) { + var results []string + if !PathExists(store) { + return nil, errors.New("store does not exists") + } + err := filepath.Walk(store, func(path string, info fs.FileInfo, err error) error { + if err != nil { + return err + } + if strings.HasSuffix(path, Extension) { + usePath := path + if display { + usePath = strings.TrimPrefix(usePath, store) + usePath = strings.TrimPrefix(usePath, "/") + usePath = strings.TrimSuffix(usePath, Extension) + } + results = append(results, usePath) + } + return nil + }) + + if err != nil { + return nil, err + } + if display { + sort.Strings(results) + } + return results, nil +} diff --git a/internal/utils.go b/internal/utils.go @@ -1,176 +1,10 @@ package internal import ( - "bufio" - "bytes" - "errors" "fmt" - "io/fs" "os" - "path/filepath" - "sort" - "strings" - "syscall" ) -type ( - // Color are terminal colors for dumb terminal coloring. - Color int -) - -const ( - // Extension is the lockbox file extension. - Extension = ".lb" - termBeginRed = "\033[1;31m" - termEndRed = "\033[0m" - // ColorRed will get red terminal coloring. - ColorRed = iota -) - -func isYesNoEnv(defaultValue bool, env string) (bool, error) { - value := strings.ToLower(strings.TrimSpace(os.Getenv(env))) - if len(value) == 0 { - return defaultValue, nil - } - switch value { - case "no": - return false, nil - case "yes": - return true, nil - } - return false, fmt.Errorf("invalid yes/no env value for %s", env) -} - -// IsInteractive indicates if running as a user UI experience. -func IsInteractive() (bool, error) { - return isYesNoEnv(true, "LOCKBOX_INTERACTIVE") -} - -// GetColor will retrieve start/end terminal coloration indicators. -func GetColor(color Color) (string, string, error) { - if color != ColorRed { - return "", "", errors.New("bad color") - } - interactive, err := IsInteractive() - if err != nil { - return "", "", err - } - colors := interactive - if colors { - isColored, err := isYesNoEnv(false, "LOCKBOX_NOCOLOR") - if err != nil { - return "", "", err - } - colors = !isColored - } - if colors { - return termBeginRed, termEndRed, nil - } - return "", "", nil -} - -// GetStore gets the lockbox directory. -func GetStore() string { - return os.Getenv("LOCKBOX_STORE") -} - -// List will get all lockbox files in a directory store. -func List(store string, display bool) ([]string, error) { - var results []string - if !PathExists(store) { - return nil, errors.New("store does not exists") - } - err := filepath.Walk(store, func(path string, info fs.FileInfo, err error) error { - if err != nil { - return err - } - if strings.HasSuffix(path, Extension) { - usePath := path - if display { - usePath = strings.TrimPrefix(usePath, store) - usePath = strings.TrimPrefix(usePath, "/") - usePath = strings.TrimSuffix(usePath, Extension) - } - results = append(results, usePath) - } - return nil - }) - - if err != nil { - return nil, err - } - if display { - sort.Strings(results) - } - return results, nil -} - -func termEcho(on bool) { - // Common settings and variables for both stty calls. - attrs := syscall.ProcAttr{ - Dir: "", - Env: []string{}, - Files: []uintptr{os.Stdin.Fd(), os.Stdout.Fd(), os.Stderr.Fd()}, - Sys: nil} - var ws syscall.WaitStatus - cmd := "echo" - if !on { - cmd = "-echo" - } - - // Enable/disable echoing. - pid, err := syscall.ForkExec( - "/bin/stty", - []string{"stty", cmd}, - &attrs) - if err != nil { - panic(err) - } - - // Wait for the stty process to complete. - _, err = syscall.Wait4(pid, &ws, 0, nil) - if err != nil { - panic(err) - } -} - -// ConfirmInputsMatch will get 2 inputs and confirm they are the same. -func ConfirmInputsMatch(object string) (string, error) { - termEcho(false) - defer func() { - termEcho(true) - }() - fmt.Printf("please enter %s: ", object) - first, err := Stdin(true) - if err != nil { - return "", err - } - fmt.Printf("\nplease re-enter %s: ", object) - second, err := Stdin(true) - if err != nil { - return "", err - } - if first != second { - return "", fmt.Errorf("%s(s) do NOT match", object) - } - return first, nil -} - -// Stdin will retrieve stdin data. -func Stdin(one bool) (string, error) { - b, err := getStdin(one) - if err != nil { - return "", err - } - return strings.TrimSpace(string(b)), nil -} - -// IsInputFromPipe will indicate if connected to stdin pipe. -func IsInputFromPipe() bool { - fileInfo, _ := os.Stdin.Stat() - return fileInfo.Mode()&os.ModeCharDevice == 0 -} - // LogError will log an error to stderr. func LogError(message string, err error) { msg := message @@ -195,29 +29,3 @@ func PathExists(path string) bool { } return true } - -// ConfirmYesNoPrompt will ask a yes/no question. -func ConfirmYesNoPrompt(prompt string) (bool, error) { - fmt.Printf("%s? (y/N) ", prompt) - resp, err := Stdin(true) - if err != nil { - return false, err - } - return resp == "Y" || resp == "y", nil -} - -func getStdin(one bool) ([]byte, error) { - scanner := bufio.NewScanner(os.Stdin) - var b bytes.Buffer - for scanner.Scan() { - b.WriteString(scanner.Text()) - b.WriteString("\n") - if one { - break - } - } - if err := scanner.Err(); err != nil { - return nil, err - } - return b.Bytes(), nil -}