commit c4975578c27f6d00e4147edf81e0cceafeab8c91
parent 38c784898cf1af0597482f9e1ff4aa3f288f7746
Author: Sean Enck <sean@ttypty.com>
Date: Tue, 25 Jul 2023 19:54:45 -0400
move stdin to platform
Diffstat:
4 files changed, 171 insertions(+), 172 deletions(-)
diff --git a/cmd/main.go b/cmd/main.go
@@ -12,7 +12,6 @@ import (
"github.com/enckse/lockbox/internal/app"
"github.com/enckse/lockbox/internal/inputs"
"github.com/enckse/lockbox/internal/platform"
- "github.com/enckse/lockbox/internal/system"
"github.com/enckse/lockbox/internal/totp"
)
@@ -102,7 +101,7 @@ func run() error {
func clearClipboard() error {
idx := 0
- val, err := system.Stdin(false)
+ val, err := platform.Stdin(false)
if err != nil {
return err
}
diff --git a/internal/app/core.go b/internal/app/core.go
@@ -14,7 +14,7 @@ import (
"github.com/enckse/lockbox/internal/backend"
"github.com/enckse/lockbox/internal/inputs"
- "github.com/enckse/lockbox/internal/system"
+ "github.com/enckse/lockbox/internal/platform"
)
const (
@@ -143,7 +143,7 @@ func (a *DefaultCommand) Transaction() *backend.Transaction {
// Confirm will confirm with the user (dying if something abnormal happens)
func (a *DefaultCommand) Confirm(prompt string) bool {
- yesNo, err := system.ConfirmYesNoPrompt(prompt)
+ yesNo, err := platform.ConfirmYesNoPrompt(prompt)
if err != nil {
Die(fmt.Sprintf("failed to read stdin for confirmation: %v", err))
}
@@ -163,12 +163,12 @@ func (a *DefaultCommand) SetArgs(args ...string) {
// IsPipe will indicate if we're receiving pipe input
func (a *DefaultCommand) IsPipe() bool {
- return system.IsInputFromPipe()
+ return platform.IsInputFromPipe()
}
// Input will read user input
func (a *DefaultCommand) Input(pipe, multi bool) ([]byte, error) {
- return system.GetUserInputPassword(pipe, multi)
+ return platform.GetUserInputPassword(pipe, multi)
}
func subCommand(parent, name, args, desc string) string {
diff --git a/internal/platform/stdin.go b/internal/platform/stdin.go
@@ -0,0 +1,166 @@
+// Package platform handles stdin processing
+package platform
+
+import (
+ "bufio"
+ "bytes"
+ "errors"
+ "fmt"
+ "os"
+ "strings"
+ "syscall"
+)
+
+type (
+ stdinReaderFunc func(string) (bool, error)
+)
+
+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)
+ }
+}
+
+// GetUserInputPassword will read the user's input from stdin via multiple means.
+func GetUserInputPassword(piping, multiLine bool) ([]byte, error) {
+ var password string
+ if !multiLine && !piping {
+ input, err := confirmInputsMatch()
+ if err != nil {
+ return nil, err
+ }
+ password = input
+ } else {
+ input, err := Stdin(false)
+ if err != nil {
+ return nil, err
+ }
+ password = input
+ }
+ if password == "" {
+ return nil, errors.New("password can NOT be empty")
+ }
+ return []byte(password), nil
+}
+
+func confirmInputsMatch() (string, error) {
+ termEcho(false)
+ defer func() {
+ termEcho(true)
+ }()
+ fmt.Print("please enter password: ")
+ first, err := Stdin(true)
+ if err != nil {
+ return "", err
+ }
+ fmt.Print("\nplease re-enter password: ")
+ second, err := Stdin(true)
+ if err != nil {
+ return "", err
+ }
+ if first != second {
+ return "", errors.New("passwords do NOT match")
+ }
+ return first, nil
+}
+
+// Stdin will get one (or more) lines of stdin as string.
+func Stdin(one bool) (string, error) {
+ var b []byte
+ var err error
+ if one {
+ b, err = readLine()
+ } else {
+ b, err = readAll()
+ }
+ 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 readAll() ([]byte, error) {
+ return read(false)
+}
+
+func readLine() ([]byte, error) {
+ return read(true)
+}
+
+// ReadFunc will read stdin and execute the given function
+func ReadFunc(reader stdinReaderFunc) error {
+ if reader == nil {
+ return errors.New("invalid reader, nil")
+ }
+ scanner := bufio.NewScanner(os.Stdin)
+ for scanner.Scan() {
+ ok, err := reader(scanner.Text())
+ if err != nil {
+ return err
+ }
+ if !ok {
+ break
+ }
+ }
+ return scanner.Err()
+}
+
+func read(one bool) ([]byte, error) {
+ var b bytes.Buffer
+ err := ReadFunc(func(line string) (bool, error) {
+ if _, err := b.WriteString(line); err != nil {
+ return false, err
+ }
+ if _, err := b.WriteString("\n"); err != nil {
+ return false, err
+ }
+ if one {
+ return false, nil
+ }
+ return true, nil
+ })
+ if err != nil {
+ return nil, err
+ }
+ return b.Bytes(), nil
+}
diff --git a/internal/system/stdin.go b/internal/system/stdin.go
@@ -1,166 +0,0 @@
-// Package system handles stdin processing
-package system
-
-import (
- "bufio"
- "bytes"
- "errors"
- "fmt"
- "os"
- "strings"
- "syscall"
-)
-
-type (
- stdinReaderFunc func(string) (bool, error)
-)
-
-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)
- }
-}
-
-// GetUserInputPassword will read the user's input from stdin via multiple means.
-func GetUserInputPassword(piping, multiLine bool) ([]byte, error) {
- var password string
- if !multiLine && !piping {
- input, err := confirmInputsMatch()
- if err != nil {
- return nil, err
- }
- password = input
- } else {
- input, err := Stdin(false)
- if err != nil {
- return nil, err
- }
- password = input
- }
- if password == "" {
- return nil, errors.New("password can NOT be empty")
- }
- return []byte(password), nil
-}
-
-func confirmInputsMatch() (string, error) {
- termEcho(false)
- defer func() {
- termEcho(true)
- }()
- fmt.Print("please enter password: ")
- first, err := Stdin(true)
- if err != nil {
- return "", err
- }
- fmt.Print("\nplease re-enter password: ")
- second, err := Stdin(true)
- if err != nil {
- return "", err
- }
- if first != second {
- return "", errors.New("passwords do NOT match")
- }
- return first, nil
-}
-
-// Stdin will get one (or more) lines of stdin as string.
-func Stdin(one bool) (string, error) {
- var b []byte
- var err error
- if one {
- b, err = readLine()
- } else {
- b, err = readAll()
- }
- 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 readAll() ([]byte, error) {
- return read(false)
-}
-
-func readLine() ([]byte, error) {
- return read(true)
-}
-
-// ReadFunc will read stdin and execute the given function
-func ReadFunc(reader stdinReaderFunc) error {
- if reader == nil {
- return errors.New("invalid reader, nil")
- }
- scanner := bufio.NewScanner(os.Stdin)
- for scanner.Scan() {
- ok, err := reader(scanner.Text())
- if err != nil {
- return err
- }
- if !ok {
- break
- }
- }
- return scanner.Err()
-}
-
-func read(one bool) ([]byte, error) {
- var b bytes.Buffer
- err := ReadFunc(func(line string) (bool, error) {
- if _, err := b.WriteString(line); err != nil {
- return false, err
- }
- if _, err := b.WriteString("\n"); err != nil {
- return false, err
- }
- if one {
- return false, nil
- }
- return true, nil
- })
- if err != nil {
- return nil, err
- }
- return b.Bytes(), nil
-}