From 10c103bfbb9c3ca80a7be941b0d18de5ccfc0bbc Mon Sep 17 00:00:00 2001 From: Felix Fontein Date: Thu, 27 Feb 2025 21:14:48 +0100 Subject: [PATCH] Consolidate passphrase reading functionality. Basically readPassphrase was replaced by readSecret in https://github.com/FiloSottile/age/commit/c0e80ef2c985442f957990098ed1cb4b4dd4aa7e so we can just use that and stick to the latest version of cmd/age/tui.go. Signed-off-by: Felix Fontein --- age/encrypted_keys.go | 2 +- age/ssh_parse.go | 2 +- age/tui.go | 45 +++++++------------------------------------ 3 files changed, 9 insertions(+), 40 deletions(-) diff --git a/age/encrypted_keys.go b/age/encrypted_keys.go index 12e7c5264..c7789db90 100644 --- a/age/encrypted_keys.go +++ b/age/encrypted_keys.go @@ -145,7 +145,7 @@ func unwrapIdentities(key string, reader io.Reader) (ParsedIdentities, error) { Passphrase: func() (string, error) { conn, err := gpgagent.NewConn() if err != nil { - passphrase, err := readPassphrase("Enter passphrase for identity " + key + ":") + passphrase, err := readSecret("Enter passphrase for identity " + key + ":") if err != nil { return "", err } diff --git a/age/ssh_parse.go b/age/ssh_parse.go index abc8e260f..467afc278 100644 --- a/age/ssh_parse.go +++ b/age/ssh_parse.go @@ -65,7 +65,7 @@ func parseSSHIdentityFromPrivateKeyFile(keyPath string) (age.Identity, error) { } } passphrasePrompt := func() ([]byte, error) { - pass, err := readPassphrase(fmt.Sprintf("Enter passphrase for %q:", keyPath)) + pass, err := readSecret(fmt.Sprintf("Enter passphrase for %q:", keyPath)) if err != nil { return nil, fmt.Errorf("could not read passphrase for %q: %v", keyPath, err) } diff --git a/age/tui.go b/age/tui.go index c6c15fb9b..e26ef0b8a 100644 --- a/age/tui.go +++ b/age/tui.go @@ -1,5 +1,4 @@ // These functions have been copied from the age project -// https://github.com/FiloSottile/age/blob/v1.0.0/cmd/age/encrypted_keys.go // https://github.com/FiloSottile/age/blob/3d91014ea095e8d70f7c6c4833f89b53a96e0832/cmd/age/tui.go // // Copyright 2021 The age Authors. All rights reserved. @@ -27,43 +26,6 @@ const ( SopsAgePasswordEnv = "SOPS_AGE_PASSWORD" ) -// readPassphrase reads a passphrase from the terminal. It does not read from a -// non-terminal stdin, so it does not check stdinInUse. -func readPassphrase(prompt string) ([]byte, error) { - if testing.Testing() { - password := os.Getenv(SopsAgePasswordEnv) - if password != "" { - return []byte(password), nil - } - } - - var ( - err error - passphrase []byte - ) - - err = withTerminal(func(in, out *os.File) error { - _, err := fmt.Fprintf(out, "%s ", prompt) - if err != nil { - return fmt.Errorf("could not write prompt: %v", err) - } - - // Use CRLF to work around an apparent bug in WSL2's handling of CONOUT$. - // Only when running a Windows binary from WSL2, the cursor would not go - // back to the start of the line with a simple LF. Honestly, it's impressive - // CONIN$ and CONOUT$ even work at all inside WSL2. - defer fmt.Fprintf(out, "\r\n") - - if passphrase, err = term.ReadPassword(int(in.Fd())); err != nil { - return fmt.Errorf("could not read passphrase: %v", err) - } - - return nil - }) - - return passphrase, err -} - func printf(format string, v ...interface{}) { log.Printf("age: "+format, v...) } @@ -133,6 +95,13 @@ func withTerminal(f func(in, out *os.File) error) error { // readSecret reads a value from the terminal with no echo. The prompt is ephemeral. func readSecret(prompt string) (s []byte, err error) { + if testing.Testing() { + password := os.Getenv(SopsAgePasswordEnv) + if password != "" { + return []byte(password), nil + } + } + err = withTerminal(func(in, out *os.File) error { fmt.Fprintf(out, "%s ", prompt) defer clearLine(out)