Skip to content

Commit 034496e

Browse files
Merge pull request #1312 from grisu48/password
Add restore handler for password input
2 parents 6b56fb0 + 14e74aa commit 034496e

File tree

4 files changed

+64
-2
lines changed

4 files changed

+64
-2
lines changed

pkg/auth/auth.go

Lines changed: 2 additions & 2 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
// ErrNewCredentialsInvalid means that the new user-provided credentials are
@@ -269,7 +269,7 @@ func getUserAndPass(opts *LoginOptions, password, userFromAuthFile string) (user
269269
}
270270
if password == "" {
271271
fmt.Fprint(opts.Stdout, "Password: ")
272-
pass, err := terminal.ReadPassword(int(os.Stdin.Fd()))
272+
pass, err := util.ReadPassword(int(os.Stdin.Fd()))
273273
if err != nil {
274274
return "", "", fmt.Errorf("reading password: %w", err)
275275
}

pkg/util/util.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package util
22

33
import (
44
"bytes"
5+
"errors"
56
"fmt"
67
"os"
78
"os/exec"
@@ -19,6 +20,8 @@ const (
1920
UnknownPackage = "Unknown"
2021
)
2122

23+
var ErrInterrupt = errors.New("interrupted")
24+
2225
// Note: This function is copied from containers/podman libpod/util.go
2326
// Please see https://github.com/containers/common/pull/1460
2427
func queryPackageVersion(cmdArg ...string) string {

pkg/util/util_supported.go

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,15 @@ import (
77
"errors"
88
"fmt"
99
"os"
10+
"os/signal"
1011
"path/filepath"
1112
"sync"
1213
"syscall"
1314

1415
"github.com/containers/storage/pkg/homedir"
1516
"github.com/containers/storage/pkg/unshare"
1617
"github.com/sirupsen/logrus"
18+
terminal "golang.org/x/term"
1719
)
1820

1921
var (
@@ -89,3 +91,45 @@ func GetRuntimeDir() (string, error) {
8991
}
9092
return rootlessRuntimeDir, nil
9193
}
94+
95+
// ReadPassword reads a password from the terminal without echo.
96+
func ReadPassword(fd int) ([]byte, error) {
97+
// Store and restore the terminal status on interruptions to
98+
// avoid that the terminal remains in the password state
99+
// This is necessary as for https://github.com/golang/go/issues/31180
100+
101+
oldState, err := terminal.GetState(fd)
102+
if err != nil {
103+
return make([]byte, 0), err
104+
}
105+
106+
type Buffer struct {
107+
Buffer []byte
108+
Error error
109+
}
110+
errorChannel := make(chan Buffer, 1)
111+
112+
// SIGINT and SIGTERM restore the terminal, otherwise the no-echo mode would remain intact
113+
interruptChannel := make(chan os.Signal, 1)
114+
signal.Notify(interruptChannel, syscall.SIGINT, syscall.SIGTERM)
115+
defer func() {
116+
signal.Stop(interruptChannel)
117+
close(interruptChannel)
118+
}()
119+
go func() {
120+
for range interruptChannel {
121+
if oldState != nil {
122+
_ = terminal.Restore(fd, oldState)
123+
}
124+
errorChannel <- Buffer{Buffer: make([]byte, 0), Error: ErrInterrupt}
125+
}
126+
}()
127+
128+
go func() {
129+
buf, err := terminal.ReadPassword(fd)
130+
errorChannel <- Buffer{Buffer: buf, Error: err}
131+
}()
132+
133+
buf := <-errorChannel
134+
return buf.Buffer, buf.Error
135+
}

pkg/util/util_windows.go

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,24 @@ package util
55

66
import (
77
"errors"
8+
9+
terminal "golang.org/x/term"
810
)
911

1012
// getRuntimeDir returns the runtime directory
1113
func GetRuntimeDir() (string, error) {
1214
return "", errors.New("this function is not implemented for windows")
1315
}
16+
17+
// ReadPassword reads a password from the terminal.
18+
func ReadPassword(fd int) ([]byte, error) {
19+
oldState, err := terminal.GetState(fd)
20+
if err != nil {
21+
return make([]byte, 0), err
22+
}
23+
buf, err := terminal.ReadPassword(fd)
24+
if oldState != nil {
25+
_ = terminal.Restore(fd, oldState)
26+
}
27+
return buf, err
28+
}

0 commit comments

Comments
 (0)