lockbox

password manager
Log | Files | Refs | README | LICENSE

commit 200df5997f9787dea06a7f7bf10c4a52fd4d5d64
parent e5f566f2db5589da1d18d29a331f006e9ed8e031
Author: Sean Enck <sean@ttypty.com>
Date:   Sat, 16 Jul 2022 11:01:11 -0400

renaming files

Diffstat:
Rinternal/hooks/hooks.go -> internal/hooks/execute.go | 0
Ainternal/inputs/env.go | 30++++++++++++++++++++++++++++++
Ainternal/inputs/env_test.go | 70++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Dinternal/inputs/inputs.go | 130-------------------------------------------------------------------------------
Ainternal/inputs/stdin.go | 107+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ainternal/misc/errors.go | 21+++++++++++++++++++++
Ainternal/misc/os.go | 15+++++++++++++++
Dinternal/misc/utils.go | 31-------------------------------
8 files changed, 243 insertions(+), 161 deletions(-)

diff --git a/internal/hooks/hooks.go b/internal/hooks/execute.go diff --git a/internal/inputs/env.go b/internal/inputs/env.go @@ -0,0 +1,30 @@ +package inputs + +import ( + "fmt" + "os" + "strings" +) + +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) +} + +func IsNoColorEnabled() (bool, error) { + return isYesNoEnv(false, "LOCKBOX_NOCOLOR") +} + +// IsInteractive indicates if running as a user UI experience. +func IsInteractive() (bool, error) { + return isYesNoEnv(true, "LOCKBOX_INTERACTIVE") +} diff --git a/internal/inputs/env_test.go b/internal/inputs/env_test.go @@ -0,0 +1,70 @@ +package inputs + +import ( + "os" + "testing" +) + +func TestColorSetting(t *testing.T) { + os.Setenv("LOCKBOX_NOCOLOR", "yes") + c, err := IsNoColorEnabled() + if err != nil { + t.Errorf("invalid error: %v", err) + } + if !c { + t.Error("invalid setting") + } + os.Setenv("LOCKBOX_NOCOLOR", "") + c, err = IsNoColorEnabled() + if err != nil { + t.Errorf("invalid error: %v", err) + } + if c { + t.Error("invalid setting") + } + os.Setenv("LOCKBOX_NOCOLOR", "no") + c, err = IsNoColorEnabled() + if err != nil { + t.Errorf("invalid error: %v", err) + } + if c { + t.Error("invalid setting") + } + os.Setenv("LOCKBOX_NOCOLOR", "lkaj;f") + _, err = IsNoColorEnabled() + if err == nil || err.Error() != "invalid yes/no env value for LOCKBOX_NOCOLOR" { + t.Errorf("unexpected error: %v", err) + } +} + +func TestInteractiveSetting(t *testing.T) { + os.Setenv("LOCKBOX_INTERACTIVE", "yes") + c, err := IsInteractive() + if err != nil { + t.Errorf("invalid error: %v", err) + } + if !c { + t.Error("invalid setting") + } + os.Setenv("LOCKBOX_INTERACTIVE", "no") + c, err = IsInteractive() + if err != nil { + t.Errorf("invalid error: %v", err) + } + if c { + t.Error("invalid setting") + } + os.Setenv("LOCKBOX_INTERACTIVE", "") + c, err = IsInteractive() + if err != nil { + t.Errorf("invalid error: %v", err) + } + if !c { + t.Error("invalid setting") + } + os.Setenv("LOCKBOX_INTERACTIVE", "yaojia") + _, err = IsInteractive() + if err == nil || err.Error() != "invalid yes/no env value for LOCKBOX_INTERACTIVE" { + t.Errorf("unexpected error: %v", err) + } +} diff --git a/internal/inputs/inputs.go b/internal/inputs/inputs.go @@ -1,130 +0,0 @@ -package inputs - -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) -} - -func IsColorEnabled() (bool, error) { - return isYesNoEnv(false, "LOCKBOX_NOCOLOR") -} - -// 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 -} - -// RawStdin will get raw stdin data. -func RawStdin() ([]byte, error) { - return getStdin(false) -} - -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/inputs/stdin.go b/internal/inputs/stdin.go @@ -0,0 +1,107 @@ +package inputs + +import ( + "bufio" + "bytes" + "fmt" + "os" + "strings" + "syscall" +) + +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 +} + +// RawStdin will get raw stdin data. +func RawStdin() ([]byte, error) { + return getStdin(false) +} + +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/misc/errors.go b/internal/misc/errors.go @@ -0,0 +1,21 @@ +package misc + +import ( + "fmt" + "os" +) + +// LogError will log an error to stderr. +func LogError(message string, err error) { + msg := message + if err != nil { + msg = fmt.Sprintf("%s (%v)", msg, err) + } + fmt.Fprintln(os.Stderr, msg) +} + +// Die will print messages and exit. +func Die(message string, err error) { + LogError(message, err) + os.Exit(1) +} diff --git a/internal/misc/os.go b/internal/misc/os.go @@ -0,0 +1,15 @@ +package misc + +import ( + "os" +) + +// PathExists indicates if a path exists. +func PathExists(path string) bool { + if _, err := os.Stat(path); err != nil { + if os.IsNotExist(err) { + return false + } + } + return true +} diff --git a/internal/misc/utils.go b/internal/misc/utils.go @@ -1,31 +0,0 @@ -package misc - -import ( - "fmt" - "os" -) - -// LogError will log an error to stderr. -func LogError(message string, err error) { - msg := message - if err != nil { - msg = fmt.Sprintf("%s (%v)", msg, err) - } - fmt.Fprintln(os.Stderr, msg) -} - -// Die will print messages and exit. -func Die(message string, err error) { - LogError(message, err) - os.Exit(1) -} - -// PathExists indicates if a path exists. -func PathExists(path string) bool { - if _, err := os.Stat(path); err != nil { - if os.IsNotExist(err) { - return false - } - } - return true -}