diff --git a/cli/input/input.go b/cli/input/input.go index 8c713d55e..43c636476 100644 --- a/cli/input/input.go +++ b/cli/input/input.go @@ -49,15 +49,10 @@ func readLine(trm *term.Terminal, prompt string) (string, error) { // ReadPassword reads the user's password with prompt. func ReadPassword(prompt string) (string, error) { trm := Terminal - if trm == nil { - s, err := term.MakeRaw(int(syscall.Stdin)) - if err != nil { - return "", err - } - defer func() { _ = term.Restore(int(syscall.Stdin), s) }() - trm = term.NewTerminal(ReadWriter{os.Stdin, os.Stdout}, prompt) + if trm != nil { + return trm.ReadPassword(prompt) } - return trm.ReadPassword(prompt) + return readSecurePassword(prompt) } // ConfirmTx asks for a confirmation to send the tx. diff --git a/cli/input/readpass_unix.go b/cli/input/readpass_unix.go new file mode 100644 index 000000000..1a0021e44 --- /dev/null +++ b/cli/input/readpass_unix.go @@ -0,0 +1,30 @@ +//go:build !windows +// +build !windows + +package input + +import ( + "fmt" + "os" + + "golang.org/x/term" +) + +// readSecurePassword reads the user's password with prompt directly from /dev/tty. +func readSecurePassword(prompt string) (string, error) { + f, err := os.OpenFile("/dev/tty", os.O_RDWR, 0) + if err != nil { + return "", err + } + defer f.Close() + _, err = f.WriteString(prompt) + if err != nil { + return "", err + } + pass, err := term.ReadPassword(int(f.Fd())) + if err != nil { + return "", fmt.Errorf("failed to read password: %w", err) + } + _, err = f.WriteString("\n") + return string(pass), err +} diff --git a/cli/input/readpass_windows.go b/cli/input/readpass_windows.go new file mode 100644 index 000000000..b9782c310 --- /dev/null +++ b/cli/input/readpass_windows.go @@ -0,0 +1,22 @@ +//go:build windows +// +build windows + +package input + +import ( + "os" + "syscall" + + "golang.org/x/term" +) + +// readSecurePassword reads the user's password with prompt. +func readSecurePassword(prompt string) (string, error) { + s, err := term.MakeRaw(int(syscall.Stdin)) + if err != nil { + return "", err + } + defer func() { _ = term.Restore(int(syscall.Stdin), s) }() + trm := term.NewTerminal(ReadWriter{os.Stdin, os.Stdout}, prompt) + return trm.ReadPassword(prompt) +}