Skip to content

Commit 5788140

Browse files
committed
Add restore handler for password input
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 cac4013 commit 5788140

File tree

3 files changed

+42
-2
lines changed

3 files changed

+42
-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.ReadPassphraseInCLIParsingPhase(int(os.Stdin.Fd()))
273273
if err != nil {
274274
return "", "", fmt.Errorf("reading password: %w", err)
275275
}

pkg/util/util_supported.go

Lines changed: 28 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,29 @@ func GetRuntimeDir() (string, error) {
8991
}
9092
return rootlessRuntimeDir, nil
9193
}
94+
95+
// ReadPassphraseInCLIParsingPhase reads a password from the terminal. On interruption signal, it will restore the terminal and terminate
96+
func ReadPassphraseInCLIParsingPhase(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+
/* Re-emit the interrupt signal, but restore the terminal in-between*/
102+
oldState, _ := terminal.GetState(fd)
103+
interruptChannel := make(chan os.Signal, 1)
104+
signal.Notify(interruptChannel, syscall.SIGINT, syscall.SIGTERM)
105+
defer func() {
106+
signal.Stop(interruptChannel)
107+
close(interruptChannel)
108+
}()
109+
go func() {
110+
for range interruptChannel {
111+
if oldState != nil {
112+
terminal.Restore(fd, oldState)
113+
}
114+
signal.Reset(os.Interrupt)
115+
os.Exit(1)
116+
}
117+
}()
118+
return terminal.ReadPassword(fd)
119+
}

pkg/util/util_windows.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,21 @@ 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+
// ReadPassphraseInCLIParsingPhase reads a password from the terminal.
18+
func ReadPassphraseInCLIParsingPhase(fd int) ([]byte, error) {
19+
oldState, _ := terminal.GetState(fd)
20+
buf, err := terminal.ReadPassword(fd)
21+
if oldState != nil {
22+
terminal.Restore(fd, oldState)
23+
}
24+
return buf, err
25+
}

0 commit comments

Comments
 (0)