Add ReadPasswordBytes for crypto use cases

Returns []byte so callers can zeroize the buffer after use.
Refactors internals to share readRaw between both variants.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-03-28 11:32:36 -07:00
parent b886f9d222
commit 818c0c2e14
2 changed files with 24 additions and 3 deletions

View File

@@ -12,11 +12,25 @@ import (
// from the terminal with echo disabled. It prints a newline after the
// input is complete so the cursor advances normally.
func ReadPassword(prompt string) (string, error) {
fmt.Fprint(os.Stderr, prompt)
b, err := term.ReadPassword(int(os.Stdin.Fd())) //nolint:gosec // fd fits in int
fmt.Fprintln(os.Stderr)
b, err := readRaw(prompt)
if err != nil {
return "", err
}
return string(b), nil
}
// ReadPasswordBytes is like ReadPassword but returns a []byte so the
// caller can zeroize the buffer after use.
func ReadPasswordBytes(prompt string) ([]byte, error) {
return readRaw(prompt)
}
func readRaw(prompt string) ([]byte, error) {
fmt.Fprint(os.Stderr, prompt)
b, err := term.ReadPassword(int(os.Stdin.Fd())) //nolint:gosec // fd fits in int
fmt.Fprintln(os.Stderr)
if err != nil {
return nil, err
}
return b, nil
}

View File

@@ -12,3 +12,10 @@ func TestReadPasswordNotATTY(t *testing.T) {
t.Fatal("expected error when stdin is not a terminal")
}
}
func TestReadPasswordBytesNotATTY(t *testing.T) {
_, err := ReadPasswordBytes("Password: ")
if err == nil {
t.Fatal("expected error when stdin is not a terminal")
}
}