bookworm-boot/encrypt-secrets.ps1

178 lines
6.7 KiB
PowerShell
Raw Normal View History

<#
.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
}
}