- P1: Banner v1.3→v1.5, Hooks 29→34 - P1: 卸载脚本补删 更新Bookworm.lnk - P1: git stash pop 安全检查 - P2: Playwright 检测改用 npm list - P2: 代理端口扫描 500ms async 超时 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
178 lines
6.7 KiB
PowerShell
178 lines
6.7 KiB
PowerShell
<#
|
|
.SYNOPSIS
|
|
Bookworm Portable - 凭证加密工具
|
|
.DESCRIPTION
|
|
将 API Key 和 MCP 凭证加密为 secrets.enc,
|
|
存放于 Gitea/USB 上, 安装时解密为进程级环境变量.
|
|
.USAGE
|
|
# 交互式创建加密凭证文件
|
|
.\encrypt-secrets.ps1
|
|
|
|
# 从现有 .env 文件加密
|
|
.\encrypt-secrets.ps1 -FromFile "C:\path\to\.env"
|
|
|
|
# 解密验证
|
|
.\encrypt-secrets.ps1 -Decrypt
|
|
#>
|
|
|
|
param(
|
|
[string]$FromFile,
|
|
[switch]$Decrypt
|
|
)
|
|
|
|
$ScriptDir = if ($MyInvocation.MyCommand.Path) {
|
|
Split-Path -Parent $MyInvocation.MyCommand.Path
|
|
} else { $PWD.Path }
|
|
$SecretsEnc = Join-Path $ScriptDir "secrets.enc"
|
|
$TempFile = Join-Path $env:TEMP "bw-secrets-$([guid]::NewGuid().ToString('N').Substring(0,8)).tmp"
|
|
|
|
# 检查 openssl
|
|
$opensslCmd = Get-Command openssl -ErrorAction SilentlyContinue
|
|
if (-not $opensslCmd) {
|
|
# 搜索常见 Git 安装路径
|
|
$searchPaths = @(
|
|
"C:\Program Files\Git\usr\bin\openssl.exe",
|
|
"D:\Git\usr\bin\openssl.exe",
|
|
"D:\Git\mingw64\bin\openssl.exe",
|
|
"C:\Program Files\Git\mingw64\bin\openssl.exe",
|
|
"C:\Program Files (x86)\Git\usr\bin\openssl.exe"
|
|
)
|
|
$found = $searchPaths | Where-Object { Test-Path $_ } | Select-Object -First 1
|
|
if ($found) {
|
|
$opensslCmd = $found
|
|
Write-Host "[INFO] 使用 Git 内置 openssl: $found" -ForegroundColor Gray
|
|
}
|
|
else {
|
|
Write-Host "[ERROR] openssl 未找到。请确认 Git for Windows 已安装。" -ForegroundColor Red
|
|
exit 1
|
|
}
|
|
} else {
|
|
$opensslCmd = $opensslCmd.Source
|
|
}
|
|
|
|
# ─── 解密模式 ─────────────────────────────────────────
|
|
if ($Decrypt) {
|
|
if (-not (Test-Path $SecretsEnc)) {
|
|
Write-Host "[ERROR] secrets.enc 不存在" -ForegroundColor Red
|
|
exit 1
|
|
}
|
|
$password = Read-Host "输入主密码" -AsSecureString
|
|
$bstr = [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($password)
|
|
$plainPwd = [System.Runtime.InteropServices.Marshal]::PtrToStringBSTR($bstr)
|
|
|
|
Write-Host "`n=== 解密内容 ===" -ForegroundColor Cyan
|
|
# 通过 stdin 传入密码,避免进程列表泄露
|
|
$plainPwd | & $opensslCmd enc -aes-256-cbc -d -pbkdf2 -iter 600000 -in $SecretsEnc -pass stdin
|
|
Write-Host "`n=== 结束 ===" -ForegroundColor Cyan
|
|
|
|
$plainPwd = $null
|
|
[System.Runtime.InteropServices.Marshal]::ZeroFreeBSTR($bstr)
|
|
exit 0
|
|
}
|
|
|
|
# ─── 加密模式 ─────────────────────────────────────────
|
|
Write-Host ""
|
|
Write-Host " Bookworm Portable - 凭证加密工具" -ForegroundColor Cyan
|
|
Write-Host " =================================" -ForegroundColor Cyan
|
|
Write-Host ""
|
|
|
|
try {
|
|
|
|
if ($FromFile -and (Test-Path $FromFile)) {
|
|
Write-Host "从文件加载: $FromFile" -ForegroundColor Gray
|
|
$invalidLines = Get-Content $FromFile | Where-Object { $_.Trim() -and $_ -notmatch '^[A-Z][A-Z0-9_]+=.+$' }
|
|
if ($invalidLines) {
|
|
Write-Host "[WARN] 以下行格式不正确 (应为 KEY=value):" -ForegroundColor Yellow
|
|
$invalidLines | ForEach-Object { Write-Host " $_" -ForegroundColor Yellow }
|
|
}
|
|
Copy-Item $FromFile $TempFile
|
|
}
|
|
else {
|
|
Write-Host "请输入凭证 (key=value 格式, 每行一个, 空行结束):" -ForegroundColor White
|
|
Write-Host "常见 Key:" -ForegroundColor Gray
|
|
Write-Host " ANTHROPIC_API_KEY=sk-ant-..." -ForegroundColor DarkGray
|
|
Write-Host " ANTHROPIC_BASE_URL=https://your-relay.com/v1" -ForegroundColor DarkGray
|
|
Write-Host " GITHUB_PERSONAL_ACCESS_TOKEN=ghp_..." -ForegroundColor DarkGray
|
|
Write-Host " SLACK_BOT_TOKEN=xoxb-..." -ForegroundColor DarkGray
|
|
Write-Host " ATLASSIAN_API_TOKEN=..." -ForegroundColor DarkGray
|
|
Write-Host " BROWSERBASE_API_KEY=..." -ForegroundColor DarkGray
|
|
Write-Host " BROWSERBASE_PROJECT_ID=..." -ForegroundColor DarkGray
|
|
Write-Host " FIRECRAWL_API_KEY=..." -ForegroundColor DarkGray
|
|
Write-Host ""
|
|
|
|
$lines = @()
|
|
while ($true) {
|
|
$line = Read-Host ">"
|
|
if ([string]::IsNullOrWhiteSpace($line)) { break }
|
|
if ($line -match '^[A-Z][A-Z0-9_]+=.+$') {
|
|
$lines += $line
|
|
$key = $line.Substring(0, $line.IndexOf('='))
|
|
Write-Host " [+] $key" -ForegroundColor Green
|
|
}
|
|
else {
|
|
Write-Host " [!] 格式不正确,应为 KEY=value" -ForegroundColor Yellow
|
|
}
|
|
}
|
|
|
|
if ($lines.Count -eq 0) {
|
|
Write-Host "[!] 未输入任何凭证,退出" -ForegroundColor Yellow
|
|
exit 0
|
|
}
|
|
|
|
$lines -join "`n" | Set-Content $TempFile -NoNewline
|
|
}
|
|
|
|
# 设置密码并加密
|
|
Write-Host ""
|
|
$password1 = Read-Host "设置主密码 (用于解密, 至少 12 位)" -AsSecureString
|
|
$password2 = Read-Host "确认主密码" -AsSecureString
|
|
|
|
$bstr1 = [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($password1)
|
|
$bstr2 = [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($password2)
|
|
$pwd1 = [System.Runtime.InteropServices.Marshal]::PtrToStringBSTR($bstr1)
|
|
$pwd2 = [System.Runtime.InteropServices.Marshal]::PtrToStringBSTR($bstr2)
|
|
|
|
if ($pwd1 -ne $pwd2) {
|
|
Write-Host "[ERROR] 密码不匹配" -ForegroundColor Red
|
|
exit 1
|
|
}
|
|
|
|
if ($pwd1.Length -lt 12) {
|
|
Write-Host "[ERROR] 密码至少 12 位 (推荐 16+ 位混合字符)" -ForegroundColor Red
|
|
exit 1
|
|
}
|
|
|
|
# AES-256-CBC 加密, PBKDF2 600000 迭代 (OWASP 2023), 通过 stdin 传入密码
|
|
$pwd1 | & $opensslCmd enc -aes-256-cbc -pbkdf2 -iter 600000 -salt -in $TempFile -out $SecretsEnc -pass stdin
|
|
|
|
# 安全删除临时文件
|
|
if (Test-Path $TempFile) {
|
|
$bytes = [System.IO.File]::ReadAllBytes($TempFile)
|
|
[Array]::Clear($bytes, 0, $bytes.Length)
|
|
[System.IO.File]::WriteAllBytes($TempFile, $bytes)
|
|
Remove-Item $TempFile -Force
|
|
}
|
|
|
|
# 清除内存
|
|
$pwd1 = $null; $pwd2 = $null
|
|
[System.Runtime.InteropServices.Marshal]::ZeroFreeBSTR($bstr1)
|
|
[System.Runtime.InteropServices.Marshal]::ZeroFreeBSTR($bstr2)
|
|
|
|
$size = (Get-Item $SecretsEnc).Length
|
|
Write-Host ""
|
|
Write-Host " [OK] secrets.enc 已生成 ($size bytes)" -ForegroundColor Green
|
|
Write-Host " 加密: AES-256-CBC + PBKDF2 (600000 迭代)" -ForegroundColor Gray
|
|
Write-Host " 路径: $SecretsEnc" -ForegroundColor Gray
|
|
Write-Host ""
|
|
Write-Host " 重要提醒:" -ForegroundColor Yellow
|
|
Write-Host " - 主密码无法找回,请牢记" -ForegroundColor Yellow
|
|
Write-Host " - 推送到 Gitea bookworm-boot 仓库即可" -ForegroundColor Yellow
|
|
Write-Host " - 验证: .\encrypt-secrets.ps1 -Decrypt" -ForegroundColor Yellow
|
|
|
|
} finally {
|
|
# 确保任何退出路径都清理临时文件
|
|
if (Test-Path $TempFile -ErrorAction SilentlyContinue) {
|
|
Remove-Item $TempFile -Force -ErrorAction SilentlyContinue
|
|
}
|
|
}
|