Scert/backend/internal/cli/secret_input_linux.go
xuans 0788b6e41d 完成Linux敏感输入安全整改
拒绝通过命令行参数和管道传入SMTP敏感值,改用Linux交互式终端隐藏输入,并增加伪终端回显关闭、状态恢复和首尾空格保留测试。
2026-10-05 13:06:34 +08:00

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)
}