File: password_supported.go

package info (click to toggle)
golang-github-containers-common 0.64.1%2Bds1-2
  • links: PTS, VCS
  • area: main
  • in suites: experimental
  • size: 5,932 kB
  • sloc: makefile: 132; sh: 111
file content (56 lines) | stat: -rw-r--r-- 1,307 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
//go:build linux || darwin || freebsd || netbsd

package password

import (
	"errors"
	"os"
	"os/signal"
	"syscall"

	terminal "golang.org/x/term"
)

var ErrInterrupt = errors.New("interrupted")

// Read reads a password from the terminal without echo.
func Read(fd int) ([]byte, error) {
	// Store and restore the terminal status on interruptions to
	// avoid that the terminal remains in the password state
	// This is necessary as for https://github.com/golang/go/issues/31180

	oldState, err := terminal.GetState(fd)
	if err != nil {
		return make([]byte, 0), err
	}

	type Buffer struct {
		Buffer []byte
		Error  error
	}
	errorChannel := make(chan Buffer, 1)

	// SIGINT and SIGTERM restore the terminal, otherwise the no-echo mode would remain intact
	interruptChannel := make(chan os.Signal, 1)
	signal.Notify(interruptChannel, syscall.SIGINT, syscall.SIGTERM)
	defer func() {
		signal.Stop(interruptChannel)
		close(interruptChannel)
	}()
	go func() {
		for range interruptChannel {
			if oldState != nil {
				_ = terminal.Restore(fd, oldState)
			}
			errorChannel <- Buffer{Buffer: make([]byte, 0), Error: ErrInterrupt}
		}
	}()

	go func() {
		buf, err := terminal.ReadPassword(fd)
		errorChannel <- Buffer{Buffer: buf, Error: err}
	}()

	buf := <-errorChannel
	return buf.Buffer, buf.Error
}