49 lines
1.3 KiB
Go
49 lines
1.3 KiB
Go
//go:build linux
|
|
|
|
package cli
|
|
|
|
import (
|
|
"bufio"
|
|
"errors"
|
|
"fmt"
|
|
"io"
|
|
"os"
|
|
|
|
"golang.org/x/sys/unix"
|
|
)
|
|
|
|
func readSecretInput(input io.Reader, output io.Writer, prompt string) (value string, err error) {
|
|
file, ok := input.(*os.File)
|
|
if !ok || file == nil {
|
|
return "", errors.New("敏感输入必须来自交互式终端,不接受管道或普通输入流")
|
|
}
|
|
|
|
fd := int(file.Fd())
|
|
original, err := unix.IoctlGetTermios(fd, unix.TCGETS)
|
|
if err != nil {
|
|
return "", errors.New("敏感输入必须来自交互式终端,不接受管道或普通输入流")
|
|
}
|
|
|
|
withoutEcho := *original
|
|
withoutEcho.Lflag &^= unix.ECHO | unix.ECHONL
|
|
if err := unix.IoctlSetTermios(fd, unix.TCSETS, &withoutEcho); err != nil {
|
|
return "", fmt.Errorf("关闭终端回显失败:%w", err)
|
|
}
|
|
defer func() {
|
|
restoreErr := unix.IoctlSetTermios(fd, unix.TCSETS, original)
|
|
if err == nil && restoreErr != nil {
|
|
err = fmt.Errorf("恢复终端状态失败:%w", restoreErr)
|
|
}
|
|
}()
|
|
|
|
if _, err := fmt.Fprint(output, prompt, ": "); err != nil {
|
|
return "", fmt.Errorf("显示敏感输入提示失败:%w", err)
|
|
}
|
|
line, readErr := bufio.NewReader(file).ReadString('\n')
|
|
_, _ = fmt.Fprintln(output)
|
|
if readErr != nil && !errors.Is(readErr, io.EOF) {
|
|
return "", fmt.Errorf("读取敏感输入失败:%w", readErr)
|
|
}
|
|
return parseSecretInput(line)
|
|
}
|