diff options
Diffstat (limited to 'vendor/github.com/bgentry/speakeasy/speakeasy_unix.go')
-rw-r--r-- | vendor/github.com/bgentry/speakeasy/speakeasy_unix.go | 93 |
1 files changed, 93 insertions, 0 deletions
diff --git a/vendor/github.com/bgentry/speakeasy/speakeasy_unix.go b/vendor/github.com/bgentry/speakeasy/speakeasy_unix.go new file mode 100644 index 0000000..d99fda1 --- /dev/null +++ b/vendor/github.com/bgentry/speakeasy/speakeasy_unix.go | |||
@@ -0,0 +1,93 @@ | |||
1 | // based on https://code.google.com/p/gopass | ||
2 | // Author: johnsiilver@gmail.com (John Doak) | ||
3 | // | ||
4 | // Original code is based on code by RogerV in the golang-nuts thread: | ||
5 | // https://groups.google.com/group/golang-nuts/browse_thread/thread/40cc41e9d9fc9247 | ||
6 | |||
7 | // +build darwin dragonfly freebsd linux netbsd openbsd solaris | ||
8 | |||
9 | package speakeasy | ||
10 | |||
11 | import ( | ||
12 | "fmt" | ||
13 | "os" | ||
14 | "os/signal" | ||
15 | "strings" | ||
16 | "syscall" | ||
17 | ) | ||
18 | |||
19 | const sttyArg0 = "/bin/stty" | ||
20 | |||
21 | var ( | ||
22 | sttyArgvEOff = []string{"stty", "-echo"} | ||
23 | sttyArgvEOn = []string{"stty", "echo"} | ||
24 | ) | ||
25 | |||
26 | // getPassword gets input hidden from the terminal from a user. This is | ||
27 | // accomplished by turning off terminal echo, reading input from the user and | ||
28 | // finally turning on terminal echo. | ||
29 | func getPassword() (password string, err error) { | ||
30 | sig := make(chan os.Signal, 10) | ||
31 | brk := make(chan bool) | ||
32 | |||
33 | // File descriptors for stdin, stdout, and stderr. | ||
34 | fd := []uintptr{os.Stdin.Fd(), os.Stdout.Fd(), os.Stderr.Fd()} | ||
35 | |||
36 | // Setup notifications of termination signals to channel sig, create a process to | ||
37 | // watch for these signals so we can turn back on echo if need be. | ||
38 | signal.Notify(sig, syscall.SIGHUP, syscall.SIGINT, syscall.SIGKILL, syscall.SIGQUIT, | ||
39 | syscall.SIGTERM) | ||
40 | go catchSignal(fd, sig, brk) | ||
41 | |||
42 | // Turn off the terminal echo. | ||
43 | pid, err := echoOff(fd) | ||
44 | if err != nil { | ||
45 | return "", err | ||
46 | } | ||
47 | |||
48 | // Turn on the terminal echo and stop listening for signals. | ||
49 | defer signal.Stop(sig) | ||
50 | defer close(brk) | ||
51 | defer echoOn(fd) | ||
52 | |||
53 | syscall.Wait4(pid, nil, 0, nil) | ||
54 | |||
55 | line, err := readline() | ||
56 | if err == nil { | ||
57 | password = strings.TrimSpace(line) | ||
58 | } else { | ||
59 | err = fmt.Errorf("failed during password entry: %s", err) | ||
60 | } | ||
61 | |||
62 | return password, err | ||
63 | } | ||
64 | |||
65 | // echoOff turns off the terminal echo. | ||
66 | func echoOff(fd []uintptr) (int, error) { | ||
67 | pid, err := syscall.ForkExec(sttyArg0, sttyArgvEOff, &syscall.ProcAttr{Dir: "", Files: fd}) | ||
68 | if err != nil { | ||
69 | return 0, fmt.Errorf("failed turning off console echo for password entry:\n\t%s", err) | ||
70 | } | ||
71 | return pid, nil | ||
72 | } | ||
73 | |||
74 | // echoOn turns back on the terminal echo. | ||
75 | func echoOn(fd []uintptr) { | ||
76 | // Turn on the terminal echo. | ||
77 | pid, e := syscall.ForkExec(sttyArg0, sttyArgvEOn, &syscall.ProcAttr{Dir: "", Files: fd}) | ||
78 | if e == nil { | ||
79 | syscall.Wait4(pid, nil, 0, nil) | ||
80 | } | ||
81 | } | ||
82 | |||
83 | // catchSignal tries to catch SIGKILL, SIGQUIT and SIGINT so that we can turn | ||
84 | // terminal echo back on before the program ends. Otherwise the user is left | ||
85 | // with echo off on their terminal. | ||
86 | func catchSignal(fd []uintptr, sig chan os.Signal, brk chan bool) { | ||
87 | select { | ||
88 | case <-sig: | ||
89 | echoOn(fd) | ||
90 | os.Exit(-1) | ||
91 | case <-brk: | ||
92 | } | ||
93 | } | ||