Skip to content

Commit 1637e40

Browse files
committed
Add workaround for no password echo
This commit restores the terminal state in case the program is interrupted while being in password read mode. This ensures the terminal remains usable, also if the password input is being cancelled. Signed-off-by: Felix Niederwanger <[email protected]>
1 parent 17f7e40 commit 1637e40

File tree

2 files changed

+38
-4
lines changed

2 files changed

+38
-4
lines changed

pkg/auth/auth.go

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,13 @@ import (
1010
"path/filepath"
1111
"strings"
1212

13+
"github.com/containers/common/pkg/util"
1314
"github.com/containers/image/v5/docker"
1415
"github.com/containers/image/v5/docker/reference"
1516
"github.com/containers/image/v5/pkg/docker/config"
1617
"github.com/containers/image/v5/pkg/sysregistriesv2"
1718
"github.com/containers/image/v5/types"
1819
"github.com/sirupsen/logrus"
19-
terminal "golang.org/x/term"
2020
)
2121

2222
// GetDefaultAuthFile returns env value REGISTRY_AUTH_FILE as default
@@ -244,11 +244,10 @@ func getUserAndPass(opts *LoginOptions, password, userFromAuthFile string) (user
244244
}
245245
if password == "" {
246246
fmt.Fprint(opts.Stdout, "Password: ")
247-
pass, err := terminal.ReadPassword(int(os.Stdin.Fd()))
247+
password, err = util.ReadPassword()
248248
if err != nil {
249249
return "", "", fmt.Errorf("reading password: %w", err)
250250
}
251-
password = string(pass)
252251
fmt.Fprintln(opts.Stdout)
253252
}
254253
return strings.TrimSpace(username), password, err

pkg/util/util.go

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,13 @@
11
package util
22

3-
import "regexp"
3+
import (
4+
"fmt"
5+
"os"
6+
"os/signal"
7+
"regexp"
8+
9+
terminal "golang.org/x/term"
10+
)
411

512
// StringInSlice determines if a string is in a string slice, returns bool
613
func StringInSlice(s string, sl []string) bool {
@@ -22,3 +29,31 @@ func StringMatchRegexSlice(s string, re []string) bool {
2229
}
2330
return false
2431
}
32+
33+
// ReadPassword reads a password from the terminal and restores the terminal state on interruption
34+
func ReadPassword() (string, error) {
35+
var err error
36+
var password []byte
37+
// Store and restore the terminal status on interruptions to
38+
// avoid that the terminal remains in the password state
39+
// This is necessary as a workaround for https://github.com/golang/go/issues/31180
40+
stdin := int(os.Stdin.Fd())
41+
oldState, err := terminal.GetState(stdin)
42+
if err != nil {
43+
oldState = nil
44+
}
45+
sigch := make(chan os.Signal, 1)
46+
defer close(sigch)
47+
signal.Notify(sigch, os.Interrupt)
48+
go func() {
49+
for range sigch {
50+
if oldState != nil {
51+
terminal.Restore(stdin, oldState)
52+
}
53+
err = fmt.Errorf("interrupted")
54+
}
55+
}()
56+
password, err = terminal.ReadPassword(stdin)
57+
signal.Reset(os.Interrupt)
58+
return string(password), err
59+
}

0 commit comments

Comments
 (0)