package main import ( "bufio" "bytes" "fmt" "io" "os" "sync" "sync/atomic" ) var ( inputTTYs = new(sync.Map) askingSecret atomic.Bool ) func registerInput(in *tty) { inputTTYs.Store(in, in) } func unregiterInput(in *tty) { inputTTYs.Delete(in) } func askSecret(prompt string) (s []byte) { err := func() (err error) { askingSecret.Store(true) defer askingSecret.Store(false) 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 }) var ( in io.Reader = stdin out io.Writer = stdout ) if stdin == nil { in = os.Stdin out = os.Stdout } out.Write([]byte(prompt + ": ")) s, err = bufio.NewReader(in).ReadBytes('\n') if err != nil { return } fmt.Println() s = bytes.TrimRight(s, "\r\n") return }() if err != nil { fatalf("failed to read from stdin: %v", err) } return }