feat: v2.3.0 - Phase 4 改为用户直接输入中转站凭证
Win: Show-ApiKeyDialog GUI + Test-ApiKey 验证 Mac: 调用 ~/.claude/change-key.js (统一逻辑) 两者都保留旧授权码流程作为向后兼容 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
58099da6da
commit
f3a58e1c6d
@ -1,6 +1,6 @@
|
||||
#!/bin/bash
|
||||
# ============================================================
|
||||
# Bookworm Smart Assistant - macOS 全自动安装 v2.2.4
|
||||
# Bookworm Smart Assistant - macOS 全自动安装 v2.3.0
|
||||
#
|
||||
# 用法 (任选一种):
|
||||
# 方式1: 下载后运行
|
||||
@ -39,7 +39,7 @@ echo " | _ \\ / _ \\ / _ \\| |/ /\\ \\ /\\ / / _ \\| '__| '\`_ \` _ \\"
|
||||
echo " | |_) | (_) | (_) | < \\ V V / (_) | | | | | | | |"
|
||||
echo " |____/ \\___/ \\___/|_|\\_\\ \\_/\\_/ \\___/|_| |_| |_| |_|"
|
||||
echo ""
|
||||
echo -e " ${BOLD}全自动安装 v2.2.4 — macOS${NC}"
|
||||
echo -e " ${BOLD}全自动安装 v2.3.0 — macOS${NC}"
|
||||
echo -e " ${BLUE}92 Skills | 18 Agents | 34 Hooks${NC}"
|
||||
echo -e "${NC}"
|
||||
|
||||
|
||||
@ -35,7 +35,7 @@ banner() {
|
||||
echo " | |_) | (_) | (_) | < \\ V V / (_) | | | | | | | |"
|
||||
echo " |____/ \\___/ \\___/|_|\\_\\ \\_/\\_/ \\___/|_| |_| |_| |_|"
|
||||
echo ""
|
||||
echo -e " ${BOLD}Portable macOS Setup v2.2.4${NC}"
|
||||
echo -e " ${BOLD}Portable macOS Setup v2.3.0${NC}"
|
||||
echo -e " ${BLUE}92 Skills | 18 Agents | 34 Hooks${NC}"
|
||||
echo -e "${NC}"
|
||||
}
|
||||
@ -321,7 +321,36 @@ parse_authcode() {
|
||||
# 先尝试缓存
|
||||
if load_cached_secrets 2>/dev/null; then
|
||||
: # 缓存加载成功
|
||||
elif [ -f "$SECRETS_ENC" ] || ls "$BOOT_DIR"/secrets-*.enc 2>/dev/null | head -1 | grep -q .; then
|
||||
else
|
||||
# 优先级 3: 调用 change-key.js 让用户直接输入中转站凭证 (v2.3)
|
||||
CHANGE_KEY_JS="$CLAUDE_DIR/change-key.js"
|
||||
if [ -f "$CHANGE_KEY_JS" ] && command -v node &>/dev/null; then
|
||||
echo ""
|
||||
info "配置中转站凭证 (中转站: https://bww.letcareme.com)"
|
||||
for attempt in 1 2 3; do
|
||||
echo ""
|
||||
read -rs -p " 粘贴凭证 (第 $attempt/3 次, 留空跳过): " UCRED
|
||||
echo ""
|
||||
[ -z "$UCRED" ] && { warn "已跳过"; break; }
|
||||
if node "$CHANGE_KEY_JS" "$UCRED" 2>&1; then
|
||||
export ANTHROPIC_API_KEY="$UCRED"
|
||||
export ANTHROPIC_BASE_URL="https://bww.letcareme.com"
|
||||
UCRED=""
|
||||
save_secrets_to_cache
|
||||
success "凭证已写入并缓存"
|
||||
echo ""
|
||||
info "换凭证方式: 重跑安装器 / bash ~/.claude/change-key.sh / Claude Code 里 /change-key"
|
||||
break
|
||||
else
|
||||
UCRED=""
|
||||
[ $attempt -lt 3 ] && warn "验证失败, 剩余 $((3-attempt)) 次" || fail "3 次失败"
|
||||
fi
|
||||
done
|
||||
fi
|
||||
fi
|
||||
|
||||
# 优先级 4: 授权码模式 (向后兼容旧用户)
|
||||
if [ -z "$ANTHROPIC_API_KEY" ] && { [ -f "$SECRETS_ENC" ] || ls "$BOOT_DIR"/secrets-*.enc 2>/dev/null | head -1 | grep -q .; }; then
|
||||
DECRYPTED=""
|
||||
valid_attempts=0
|
||||
total_attempts=0
|
||||
|
||||
147
auto-setup.ps1
147
auto-setup.ps1
@ -16,7 +16,7 @@ param(
|
||||
$ErrorActionPreference = "Stop"
|
||||
|
||||
# ─── 版本号 (每次更新递增, build.ps1 自动读取) ──────
|
||||
$BWVersion = "2.2.4"
|
||||
$BWVersion = "2.3.0"
|
||||
|
||||
# ─── B4: 单实例保护 (防止双击两次导致竞态) ─────────
|
||||
$mutexCreated = $false
|
||||
@ -352,6 +352,105 @@ function Show-AuthCodeDialog($attempt = 1, $maxAttempts = 3) {
|
||||
return $null
|
||||
}
|
||||
|
||||
# ─── 中转站 API Key 输入对话框 + 验证 (v2.3 新增) ──
|
||||
function Show-ApiKeyDialog($attempt = 1, $maxAttempts = 3, $existingKey = "") {
|
||||
$form = New-Object System.Windows.Forms.Form
|
||||
$form.Text = "Bookworm - 中转站 API Key ($attempt/$maxAttempts)"
|
||||
$form.Size = New-Object System.Drawing.Size(520, 280)
|
||||
$form.StartPosition = "CenterScreen"
|
||||
$form.FormBorderStyle = "FixedDialog"
|
||||
$form.MaximizeBox = $false
|
||||
$form.TopMost = $true
|
||||
$form.BackColor = [System.Drawing.Color]::White
|
||||
|
||||
$lblInfo = New-Object System.Windows.Forms.Label
|
||||
$lblInfo.Location = New-Object System.Drawing.Point(20, 15)
|
||||
$lblInfo.Size = New-Object System.Drawing.Size(470, 50)
|
||||
$lblInfo.Text = "请粘贴你的中转站 API Key`n(bww.letcareme.com 注册后在后台获取, sk- 开头)"
|
||||
$lblInfo.Font = New-Object System.Drawing.Font("Segoe UI", 9)
|
||||
$form.Controls.Add($lblInfo)
|
||||
|
||||
$keyBox = New-Object System.Windows.Forms.TextBox
|
||||
$keyBox.Location = New-Object System.Drawing.Point(20, 75)
|
||||
$keyBox.Size = New-Object System.Drawing.Size(470, 30)
|
||||
$keyBox.Font = New-Object System.Drawing.Font("Consolas", 10)
|
||||
$keyBox.Text = $existingKey
|
||||
$keyBox.PasswordChar = '*'
|
||||
$form.Controls.Add($keyBox)
|
||||
|
||||
$chkShow = New-Object System.Windows.Forms.CheckBox
|
||||
$chkShow.Location = New-Object System.Drawing.Point(20, 110)
|
||||
$chkShow.Size = New-Object System.Drawing.Size(150, 25)
|
||||
$chkShow.Text = "显示 Key"
|
||||
$chkShow.Add_CheckedChanged({ if ($chkShow.Checked) { $keyBox.PasswordChar = [char]0 } else { $keyBox.PasswordChar = '*' } })
|
||||
$form.Controls.Add($chkShow)
|
||||
|
||||
$lblHint = New-Object System.Windows.Forms.Label
|
||||
$lblHint.Location = New-Object System.Drawing.Point(20, 140)
|
||||
$lblHint.Size = New-Object System.Drawing.Size(470, 40)
|
||||
$lblHint.Text = "首次使用请先注册并充值:`nhttps://bww.letcareme.com"
|
||||
$lblHint.Font = New-Object System.Drawing.Font("Segoe UI", 8)
|
||||
$lblHint.ForeColor = [System.Drawing.Color]::FromArgb(100, 110, 130)
|
||||
$form.Controls.Add($lblHint)
|
||||
|
||||
$btnOK = New-Object System.Windows.Forms.Button
|
||||
$btnOK.Location = New-Object System.Drawing.Point(280, 195)
|
||||
$btnOK.Size = New-Object System.Drawing.Size(100, 35)
|
||||
$btnOK.Text = "验证并保存"
|
||||
$btnOK.DialogResult = [System.Windows.Forms.DialogResult]::OK
|
||||
$form.AcceptButton = $btnOK
|
||||
$form.Controls.Add($btnOK)
|
||||
|
||||
$btnCancel = New-Object System.Windows.Forms.Button
|
||||
$btnCancel.Location = New-Object System.Drawing.Point(390, 195)
|
||||
$btnCancel.Size = New-Object System.Drawing.Size(100, 35)
|
||||
$btnCancel.Text = "取消"
|
||||
$btnCancel.DialogResult = [System.Windows.Forms.DialogResult]::Cancel
|
||||
$form.CancelButton = $btnCancel
|
||||
$form.Controls.Add($btnCancel)
|
||||
|
||||
$form.Add_Shown({ $keyBox.Focus() })
|
||||
$result = $form.ShowDialog()
|
||||
|
||||
if ($result -eq [System.Windows.Forms.DialogResult]::OK) {
|
||||
return $keyBox.Text.Trim()
|
||||
}
|
||||
return $null
|
||||
}
|
||||
|
||||
# 向中转站发一个最小请求验证 key 是否可用
|
||||
function Test-ApiKey([string]$apiKey, [string]$baseUrl = "https://bww.letcareme.com") {
|
||||
if (-not $apiKey -or $apiKey.Length -lt 10) { return $false }
|
||||
try {
|
||||
$body = '{"model":"claude-sonnet-4-5","max_tokens":1,"messages":[{"role":"user","content":"hi"}]}'
|
||||
$req = [System.Net.WebRequest]::Create("$baseUrl/v1/messages")
|
||||
$req.Method = "POST"
|
||||
$req.ContentType = "application/json"
|
||||
$req.Headers["x-api-key"] = $apiKey
|
||||
$req.Headers["anthropic-version"] = "2023-06-01"
|
||||
$req.Timeout = 10000
|
||||
$bytes = [System.Text.Encoding]::UTF8.GetBytes($body)
|
||||
$req.ContentLength = $bytes.Length
|
||||
$stream = $req.GetRequestStream()
|
||||
$stream.Write($bytes, 0, $bytes.Length)
|
||||
$stream.Close()
|
||||
$resp = $req.GetResponse()
|
||||
$resp.Close()
|
||||
return $true
|
||||
} catch [System.Net.WebException] {
|
||||
# 401/403 = 认证失败, 其他网络错误也返回 false
|
||||
$statusCode = 0
|
||||
try { $statusCode = [int]$_.Exception.Response.StatusCode } catch {}
|
||||
# 如果返回 200/400 说明 key 有效 (400 可能是请求体问题, 但 key 本身通过)
|
||||
if ($statusCode -ge 200 -and $statusCode -lt 500 -and $statusCode -ne 401 -and $statusCode -ne 403) {
|
||||
return $true
|
||||
}
|
||||
return $false
|
||||
} catch {
|
||||
return $false
|
||||
}
|
||||
}
|
||||
|
||||
function Show-GiteaCredentialDialog {
|
||||
$form = New-Object System.Windows.Forms.Form
|
||||
$form.Text = "Bookworm - Gitea 登录"
|
||||
@ -1017,12 +1116,52 @@ if (-not $secretsDecrypted -and (Get-CachedSecrets)) {
|
||||
Log-OK "从 Registry 缓存加载凭证"
|
||||
$secretsDecrypted = $true
|
||||
}
|
||||
# 优先级 3: 解密 (缓存均未命中时)
|
||||
# 优先级 3: 直接输入中转站 API Key (v2.3 新增)
|
||||
if (-not $secretsDecrypted) {
|
||||
Show-MsgBox "欢迎使用 Bookworm Portable!`n`n接下来需要配置你的中转站 API Key。`n`n如果还没有, 请先去 https://bww.letcareme.com 注册并充值获取。" "配置 API Key" "OK" "Information"
|
||||
|
||||
$keyAttempts = 0
|
||||
$maxKeyAttempts = 3
|
||||
while ($keyAttempts -lt $maxKeyAttempts) {
|
||||
$keyAttempts++
|
||||
$apiKey = Show-ApiKeyDialog $keyAttempts $maxKeyAttempts
|
||||
if (-not $apiKey) {
|
||||
Log-Warn "用户取消 API Key 输入"
|
||||
break
|
||||
}
|
||||
# 基础格式校验
|
||||
if ($apiKey.Length -lt 20) {
|
||||
Show-MsgBox "API Key 格式错误 (长度过短)。`n请检查后重试。" "格式错误" "OK" "Warning"
|
||||
continue
|
||||
}
|
||||
Log-Info "正在验证 API Key..."
|
||||
if (Test-ApiKey $apiKey) {
|
||||
# 验证通过, 写入环境变量 + 缓存
|
||||
[System.Environment]::SetEnvironmentVariable("ANTHROPIC_API_KEY", $apiKey, "Process")
|
||||
[System.Environment]::SetEnvironmentVariable("ANTHROPIC_API_KEY", $apiKey, "User")
|
||||
[System.Environment]::SetEnvironmentVariable("ANTHROPIC_BASE_URL", "https://bww.letcareme.com", "Process")
|
||||
[System.Environment]::SetEnvironmentVariable("ANTHROPIC_BASE_URL", "https://bww.letcareme.com", "User")
|
||||
Log-OK "API Key 已验证并写入环境变量 (永久生效)"
|
||||
$secretsDecrypted = $true
|
||||
Save-SecretsToCache
|
||||
Show-MsgBox "API Key 验证成功!`n`n已写入系统环境变量, 任何终端输入 claude 即可启动。`n`n以后想换 Key, 可以:`n1. 双击桌面 '更换Key.bat'`n2. 或 Claude Code 里输入 /change-key`n3. 或重跑安装器" "验证成功" "OK" "Information"
|
||||
break
|
||||
} else {
|
||||
$remaining = $maxKeyAttempts - $keyAttempts
|
||||
if ($remaining -gt 0) {
|
||||
Show-MsgBox "API Key 验证失败 (无法连接或认证错误)。`n剩余重试: $remaining 次`n`n请检查:`n1. Key 是否正确 (sk- 开头)`n2. 中转站是否有余额`n3. 网络和代理是否正常" "验证失败" "OK" "Warning"
|
||||
} else {
|
||||
Show-MsgBox "3 次验证均失败。`n`n请检查 Key 和网络, 或联系管理员。" "验证失败" "OK" "Error"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# 优先级 4: 解密授权码 (向后兼容, 旧用户保留)
|
||||
if (-not $secretsDecrypted) {
|
||||
$cryptoHelper = Join-Path $BootDir "crypto-helper.js"
|
||||
if (-not (Test-Cmd "node") -or -not (Test-Path $cryptoHelper)) {
|
||||
Log-Fail "解密需要 Node.js (Phase 1 应已安装)"
|
||||
Show-MsgBox "解密凭证需要 Node.js,但未检测到。`n请确认 Phase 1 安装成功后重试。" "缺少 Node.js" "OK" "Error"
|
||||
Log-Info "跳过授权码解密"
|
||||
}
|
||||
elseif ((Test-Path $SecretsEnc) -or (Get-ChildItem $BootDir -Filter "secrets-*.enc" -ErrorAction SilentlyContinue)) {
|
||||
# 强制要求授权码 — 不允许跳过 (跳过 = 无法使用)
|
||||
|
||||
Loading…
Reference in New Issue
Block a user