2022-03-08 10:45:56 +00:00
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
|
|
|
"bufio"
|
|
|
|
"bytes"
|
2023-02-01 23:28:36 +00:00
|
|
|
"fmt"
|
2022-03-08 10:45:56 +00:00
|
|
|
"io"
|
|
|
|
"os"
|
2024-01-21 14:26:00 +00:00
|
|
|
"sync"
|
|
|
|
"sync/atomic"
|
2022-03-08 10:45:56 +00:00
|
|
|
)
|
|
|
|
|
2024-01-21 14:26:00 +00:00
|
|
|
var (
|
|
|
|
inputTTYs = new(sync.Map)
|
|
|
|
askingSecret atomic.Bool
|
|
|
|
)
|
2022-03-08 10:45:56 +00:00
|
|
|
|
2024-01-21 14:26:00 +00:00
|
|
|
func registerInput(in *tty) { inputTTYs.Store(in, in) }
|
|
|
|
func unregiterInput(in *tty) { inputTTYs.Delete(in) }
|
2022-03-08 10:45:56 +00:00
|
|
|
|
2024-01-21 14:26:00 +00:00
|
|
|
func askSecret(prompt string) (s []byte) {
|
|
|
|
err := func() (err error) {
|
|
|
|
askingSecret.Store(true)
|
|
|
|
defer askingSecret.Store(false)
|
2022-03-08 10:45:56 +00:00
|
|
|
|
2024-01-21 14:26:00 +00:00
|
|
|
inputTTYs.Range(func(k, v any) (con bool) { v.(*tty).EchoOff(); return true })
|
|
|
|
defer inputTTYs.Range(func(k, v any) (con bool) { v.(*tty).Restore(); return true })
|
2022-03-08 10:45:56 +00:00
|
|
|
|
2024-01-21 14:26:00 +00:00
|
|
|
var (
|
|
|
|
in io.Reader = stdin
|
|
|
|
out io.Writer = stdout
|
|
|
|
)
|
2022-03-08 10:45:56 +00:00
|
|
|
|
2024-01-21 14:26:00 +00:00
|
|
|
if stdin == nil {
|
|
|
|
in = os.Stdin
|
|
|
|
out = os.Stdout
|
|
|
|
}
|
2022-03-08 10:45:56 +00:00
|
|
|
|
2024-01-21 14:26:00 +00:00
|
|
|
out.Write([]byte(prompt + ": "))
|
|
|
|
|
|
|
|
s, err = bufio.NewReader(in).ReadBytes('\n')
|
|
|
|
if err != nil {
|
|
|
|
return
|
|
|
|
}
|
2022-03-08 10:45:56 +00:00
|
|
|
|
2024-01-21 14:26:00 +00:00
|
|
|
fmt.Println()
|
|
|
|
s = bytes.TrimRight(s, "\r\n")
|
|
|
|
return
|
|
|
|
}()
|
2022-03-08 10:45:56 +00:00
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
fatalf("failed to read from stdin: %v", err)
|
|
|
|
}
|
|
|
|
|
2024-01-21 14:26:00 +00:00
|
|
|
return
|
2022-03-08 10:45:56 +00:00
|
|
|
}
|