x/term: disabling auto-completion around GetPassword()

Triggering the completion during password input might cause some
unintended behavior around handling of TAB, or maybe the auto-completion
functionality would review the secret input. Hence simply
disabling/re-enabling it around the t.readLine call.

Fixes #72736

Change-Id: I64270e8570086247247466afb2536b2581d6af25
Reviewed-on: https://go-review.googlesource.com/c/term/+/607115
Reviewed-by: David Chase <drchase@google.com>
Reviewed-by: Keith Randall <khr@google.com>
Auto-Submit: Sean Liao <sean@liao.dev>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
This commit is contained in:
Dragos Vingarzan
2024-08-20 18:25:39 +02:00
committed by Gopher Robot
parent 04218fdaf7
commit e770dddbf5
2 changed files with 35 additions and 0 deletions

View File

@@ -44,6 +44,8 @@ type Terminal struct {
// bytes, as an index into |line|). If it returns ok=false, the key
// press is processed normally. Otherwise it returns a replacement line
// and the new cursor position.
//
// This will be disabled during ReadPassword.
AutoCompleteCallback func(line string, pos int, key rune) (newLine string, newPos int, ok bool)
// Escape contains a pointer to the escape codes for this terminal.
@@ -692,6 +694,8 @@ func (t *Terminal) Write(buf []byte) (n int, err error) {
// ReadPassword temporarily changes the prompt and reads a password, without
// echo, from the terminal.
//
// The AutoCompleteCallback is disabled during this call.
func (t *Terminal) ReadPassword(prompt string) (line string, err error) {
t.lock.Lock()
defer t.lock.Unlock()
@@ -699,6 +703,11 @@ func (t *Terminal) ReadPassword(prompt string) (line string, err error) {
oldPrompt := t.prompt
t.prompt = []rune(prompt)
t.echo = false
oldAutoCompleteCallback := t.AutoCompleteCallback
t.AutoCompleteCallback = nil
defer func() {
t.AutoCompleteCallback = oldAutoCompleteCallback
}()
line, err = t.readLine()

View File

@@ -396,6 +396,32 @@ func TestReadPasswordLineEnd(t *testing.T) {
}
}
func MockAutoCompleteCallback(line string, pos int, key rune) (newLine string, newPos int, ok bool) {
return "not-good", pos, true
}
func TestReadPasswordDisabledAutoCompleteCallback(t *testing.T) {
input := "testgood\ranother line\r"
expectedPassword := "testgood"
terminal := NewTerminal(
&MockTerminal{
toSend: []byte(input),
bytesPerRead: 1,
},
"prompt")
terminal.AutoCompleteCallback = MockAutoCompleteCallback
password, err := terminal.ReadPassword("Password: ")
if err != nil {
t.Fatalf("failed to read password: %v", err)
}
if password != expectedPassword {
t.Fatalf("failed to read password, got %q", password)
}
if terminal.AutoCompleteCallback == nil {
t.Fatalf("AutoCompleteCallback should not be nil after ReadPassword")
}
}
func TestMakeRawState(t *testing.T) {
fd := int(os.Stdout.Fd())
if !IsTerminal(fd) {