fix: 修复授权码认证的 2 个 BLOCKER + 3 个 WARNING

BLOCKER:
- Bookworm-Setup.sh: ${var,,} → tr 兼容 macOS bash 3.2
- Bookworm-Setup.sh: while 循环加 total_attempts<10 防死循环

WARNING:
- install.ps1: 重写 Decrypt-Secrets 为 while 双计数器,
  格式/过期错误不消耗有效次数,清理残留"主密码"文案
- install.ps1 + auto-setup.ps1: 格式示例去掉误导性空格
  (XXXXXXXX → XXXXXXXXXXXXXXXXXXXXXXXX)

其他:
- 新增 .gitignore,排除 secrets.txt 防止明文密钥误提交

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
bookworm 2026-04-06 22:57:47 +08:00
parent b83c508c22
commit 51525d3c1f
4 changed files with 22 additions and 27 deletions

1
.gitignore vendored Normal file
View File

@ -0,0 +1 @@
secrets.txt

View File

@ -292,7 +292,7 @@ parse_authcode() {
echo "EXPIRED" echo "EXPIRED"
return return
fi fi
echo "${token_upper,,}" # bash4+ 转小写 echo "$token_upper" | tr '[:upper:]' '[:lower:]' # 兼容 bash 3.2 (macOS 默认)
} }
# 先尝试缓存 # 先尝试缓存
@ -301,17 +301,19 @@ if load_cached_secrets 2>/dev/null; then
elif [ -f "$SECRETS_ENC" ]; then elif [ -f "$SECRETS_ENC" ]; then
DECRYPTED="" DECRYPTED=""
valid_attempts=0 valid_attempts=0
while [ $valid_attempts -lt 3 ]; do total_attempts=0
while [ $valid_attempts -lt 3 ] && [ $total_attempts -lt 10 ]; do
echo "" echo ""
read -p " 输入授权码 (BW-YYYYMMDD-XXXXXX, 第 $((valid_attempts+1))/3 次): " AUTH_CODE read -p " 输入授权码 (BW-YYYYMMDD-XXXXXX, 第 $((valid_attempts+1))/3 次): " AUTH_CODE
total_attempts=$((total_attempts + 1))
TOKEN=$(parse_authcode "$AUTH_CODE") TOKEN=$(parse_authcode "$AUTH_CODE")
AUTH_CODE="" AUTH_CODE=""
if [ "$TOKEN" = "EXPIRED" ]; then if [ "$TOKEN" = "EXPIRED" ]; then
warn "授权码已过期, 请联系管理员获取新授权码" warn "授权码已过期, 请联系管理员获取新授权码"
continue # 不消耗尝试次数 continue # 不消耗有效次数
elif [ -z "$TOKEN" ]; then elif [ -z "$TOKEN" ]; then
warn "授权码格式错误 (格式: BW-YYYYMMDD-24位字母数字)" warn "授权码格式错误 (格式: BW-YYYYMMDD-XXXXXXXXXXXXXXXXXXXXXXXX)"
continue # 不消耗尝试次数 continue # 不消耗有效次数
fi fi
valid_attempts=$((valid_attempts + 1)) valid_attempts=$((valid_attempts + 1))
DECRYPTED=$(_decrypt_secrets "$TOKEN" "$SECRETS_ENC") || true DECRYPTED=$(_decrypt_secrets "$TOKEN" "$SECRETS_ENC") || true

View File

@ -231,38 +231,33 @@ function Decrypt-Secrets {
} }
$cryptoHelper = Join-Path $ScriptDir "crypto-helper.js" $cryptoHelper = Join-Path $ScriptDir "crypto-helper.js"
$maxRetries = 3 $validAttempts = 0
for ($attempt = 1; $attempt -le $maxRetries; $attempt++) { $totalAttempts = 0
$label = if ($attempt -gt 1) { " 重新输入授权码 (第 $attempt/$maxRetries 次)" } else { " 输入授权码 (格式: BW-YYYYMMDD-...)" } while ($validAttempts -lt 3 -and $totalAttempts -lt 10) {
$totalAttempts++
$label = if ($validAttempts -gt 0) { " 重新输入授权码 (第 $($validAttempts+1)/3 次)" } else { " 输入授权码 (格式: BW-YYYYMMDD-...)" }
$authCodeRaw = Read-Host $label $authCodeRaw = Read-Host $label
$plainPwd = Parse-AuthCode $authCodeRaw $plainPwd = Parse-AuthCode $authCodeRaw
if (-not $plainPwd) { if (-not $plainPwd) {
# 格式错误或已过期: 不计入密码重试, 直接继续 # 格式错误或已过期: 不计入有效重试次数
$attempt--
$maxRetries-- # 最多给 3 次有效尝试
if ($maxRetries -lt 1) { break }
continue continue
} }
$validAttempts++
$prevEAP = $ErrorActionPreference $prevEAP = $ErrorActionPreference
$ErrorActionPreference = "Continue" $ErrorActionPreference = "Continue"
if ($useNode) { if ($useNode) {
# Node.js 解密 (跨平台一致)
$decrypted = & node $cryptoHelper decrypt $plainPwd $SecretsEnc 2>&1 $decrypted = & node $cryptoHelper decrypt $plainPwd $SecretsEnc 2>&1
$decExit = $LASTEXITCODE $decExit = $LASTEXITCODE
} else { } else {
# openssl 回退
$decrypted = $plainPwd | & $opensslCmd enc -aes-256-cbc -d -pbkdf2 -iter 600000 -md sha256 -in $SecretsEnc -pass stdin 2>&1 $decrypted = $plainPwd | & $opensslCmd enc -aes-256-cbc -d -pbkdf2 -iter 600000 -md sha256 -in $SecretsEnc -pass stdin 2>&1
$decExit = $LASTEXITCODE $decExit = $LASTEXITCODE
} }
$ErrorActionPreference = $prevEAP $ErrorActionPreference = $prevEAP
# 清除内存中的 token
$plainPwd = $null $plainPwd = $null
if ($decExit -eq 0 -and $decrypted -and $decrypted -notmatch 'PASSWORD_ERROR|FORMAT_ERROR|bad decrypt') { if ($decExit -eq 0 -and $decrypted -and $decrypted -notmatch 'PASSWORD_ERROR|FORMAT_ERROR|bad decrypt') {
# 解密成功,注入环境变量
$decrypted -split "`n" | ForEach-Object { $decrypted -split "`n" | ForEach-Object {
$line = $_.Trim() $line = $_.Trim()
if ($line -and $line.Contains('=')) { if ($line -and $line.Contains('=')) {
@ -276,18 +271,15 @@ function Decrypt-Secrets {
return return
} }
# 解密失败 $remaining = 3 - $validAttempts
$remaining = $maxRetries - $attempt
if ($remaining -gt 0) { if ($remaining -gt 0) {
Write-Host " [!!] 密码错误,剩余重试: $remaining" -ForegroundColor Red Write-Host " [!!] 授权码无效 (解密失败),剩余重试: $remaining" -ForegroundColor Red
} }
} }
# 3次全部失败
Write-Host "" Write-Host ""
Write-Host " [ABORT] 3 次密码均错误" -ForegroundColor Red Write-Host " [ABORT] 3 次授权码均无效,凭证未解密" -ForegroundColor Red
Write-Host " 请确认主密码是否正确 (区分大小写)" -ForegroundColor Yellow Write-Host " 请确认授权码是否正确,或联系管理员重新生成" -ForegroundColor Yellow
Write-Host " 如忘记密码,请联系管理员重新生成 secrets.enc" -ForegroundColor Yellow
exit 1 exit 1
} }