refactor(core): ♻️ 移除 brew 脚本中的 sudo 密码注入并重构代码

移除 Homebrew 升级脚本中硬编码的 sudo 密码处理逻辑,改为依赖用户预先认证(sudo -v),提高安全性并简化 PTY 转发逻辑。同步更新文档说明及 sntp 脚本的类型校验。

- 脚本: 移除 SUDO_PWD 相关变量及自动注入逻辑,升级版本至 v5.3
- 文档: 更新 README 建议使用 sudo -v 刷新凭据,重写交互说明
- 工具: 在 sntp-rename.js 中增加对非字符串名称的防御性校验
This commit is contained in:
2026-05-04 01:50:00 +08:00
parent c3437ae163
commit 3c980ec87a
3 changed files with 54 additions and 69 deletions

View File

@@ -1,6 +1,5 @@
#!/usr/bin/env bash
# Homebrew 智能升级脚本(强制 Cask 更新增强版 v5.2 - 修复 PTY 终端尺寸导致 Ruby 渲染崩溃问题
# ❗❗️❗️️使用前请搜索 SUDO_PWD 并添加自己的 root 密码!!!
# Homebrew 智能升级脚本(强制 Cask 更新增强版 v5.3 - 移除 sudo 密码注入
# ================== 脚本环境设置 ==================
@@ -104,9 +103,6 @@ separator
print_header "Step 4: Executing comprehensive upgrades (Formulae & Casks)"
echo -e "${NC}"
# 使用前请先修改这里的密码!!
SUDO_PWD=""
# 1. 升级命令行工具 (Formulae)
echo -e "\n${CYAN}>>> [1/2] Upgrading CLI Formulae (brew upgrade --formula)...${NC}"
brew upgrade --formula
@@ -121,79 +117,70 @@ export HOMEBREW_COLOR=1
# 强制将 Bash 计算好的真实终端宽度传递给底层,防止 Ruby 绘表时发生 negative argument 崩溃
export COLUMNS="$TERMINAL_WIDTH"
# 使用 Python 原生 PTY 自建极简轮询引擎
# 使用 Python 原生 PTY 自建极简转发引擎。它只转发用户输入,不保存、不注入 sudo 密码。
python3 -c '
import pty, os, sys, select, fcntl, termios, struct
import pty, os, sys, select, fcntl, termios, struct, tty
# 将传入的明文密码转换为底层的原始字节流,并在末尾追加换行符模拟按下回车键
pwd = sys.argv[1].encode() + b"\n"
cmd = sys.argv[2:]
# 在操作系统底层分叉出一个携带完整伪终端(PTY)特性的子进程
cmd = sys.argv[1:]
pid, fd = pty.fork()
if pid == 0:
# --- 逻辑分支:子进程空间 ---
# 使用 execvp 顶替当前进程,正式开始执行 brew cu 命令
os.execvp(cmd[0], cmd)
else:
# --- 逻辑分支:父进程空间 (监控端) ---
# --- 核心修复:物理终端尺寸投影 ---
# 尝试捕获外层真实物理终端的行列尺寸,并硬塞进伪终端的文件描述符中
try:
# 打包一个空的 4 短整型结构体准备接收数据
s = struct.pack("HHHH", 0, 0, 0, 0)
# 通过 ioctl 系统调用,向操作系统的标准输出请求 TIOCGWINSZ (获取窗口大小)
winsize = fcntl.ioctl(sys.stdout.fileno(), termios.TIOCGWINSZ, s)
# 将获取到的真实尺寸,立刻通过 TIOCSWINSZ (设置窗口大小) 写入刚刚生成的伪终端 fd 中
fcntl.ioctl(fd, termios.TIOCSWINSZ, winsize)
except Exception:
# 如果当前环境不是交互式终端(如 crontab 后台运行),捕获异常静默跳过,
# 此时外层 bash 注入的 export COLUMNS="$TERMINAL_WIDTH" 将作为完美兜底
pass
stdin_fd = sys.stdin.fileno()
stdout_fd = sys.stdout.fileno()
forward_stdin = sys.stdin.isatty()
old_stdin_attrs = None
if forward_stdin:
old_stdin_attrs = termios.tcgetattr(stdin_fd)
tty.setraw(stdin_fd)
exit_code = 0
while True:
try:
# 开启 IO 多路复用轮询,设置 0.1 秒的极短超时时间防止物理死锁
rfds, _, _ = select.select([fd], [], [], 0.1)
try:
while True:
try:
watch = [fd]
if forward_stdin:
watch.append(stdin_fd)
rfds, _, _ = select.select(watch, [], [], 0.1)
# 如果伪终端有数据吐出
if fd in rfds:
# 以 8KB 为块,读取原始字节流 (Raw Bytes)
data = os.read(fd, 8192)
# 读到空字节代表通道已被操作系统关闭
if not data:
break
if fd in rfds:
data = os.read(fd, 8192)
if not data:
break
os.write(stdout_fd, data)
# 在纯净字节流中精准狙击 sudo 发出的密码请求信号
if b"assword:" in data or b"Password:" in data:
# 发现目标,将密码字节流强行注入到伪终端标准输入中
os.write(fd, pwd)
if forward_stdin and stdin_fd in rfds:
data = os.read(stdin_fd, 8192)
if data:
os.write(fd, data)
# 将读取到的原汁原味的字节流直接刷入真实屏幕,确保 Emoji 不乱码
os.write(sys.stdout.fileno(), data)
except OSError:
# 捕获对侧进程已死导致的 EIO 错误,安全打破循环
break
# 主动进程心跳侦测:非阻塞探查子进程生死
try:
wpid, wstatus = os.waitpid(pid, os.WNOHANG)
if wpid == pid:
if os.WIFEXITED(wstatus):
exit_code = os.WEXITSTATUS(wstatus)
else:
exit_code = 1
except OSError:
break
except ChildProcessError:
break
# 将真实状态码原样返回给外层的 shell
try:
wpid, wstatus = os.waitpid(pid, os.WNOHANG)
if wpid == pid:
if os.WIFEXITED(wstatus):
exit_code = os.WEXITSTATUS(wstatus)
else:
exit_code = 1
break
except ChildProcessError:
break
finally:
if old_stdin_attrs is not None:
termios.tcsetattr(stdin_fd, termios.TCSADRAIN, old_stdin_attrs)
sys.exit(exit_code)
' "$SUDO_PWD" brew cu -yaq
' brew cu -yaq
separator
printf "\n"
@@ -205,4 +192,4 @@ separator
printf "\n"
echo -e "${GREEN}All operations completed!${NC}"
printf "\n"
printf "\n"