add install-silent.ps1 + updated agent.exe with security fixes

- install-silent.ps1: non-interactive deployment for remote agent setup
- agent.exe: rebuilt with path traversal defense, size checks, pending TTL
This commit is contained in:
dongsheng123132
2026-03-23 20:34:50 +08:00
parent 17688fe3f9
commit 76d7e85b50
2 changed files with 278 additions and 0 deletions

278
website/install-silent.ps1 Normal file
View File

@@ -0,0 +1,278 @@
# ============================================================
# U-Claw Silent Installer (Windows PowerShell)
# Non-interactive version for remote exec deployment
#
# Usage:
# install-silent.ps1 -Model deepseek-chat -ApiKey sk-xxx
# install-silent.ps1 -Model deepseek-chat -ApiKey sk-xxx -BaseUrl https://api.deepseek.com/v1
# install-silent.ps1 -Model ollama -NoKey
# install-silent.ps1 -SkipConfig # install only, configure later
# ============================================================
param(
[string]$Model = "deepseek-chat",
[string]$ApiKey = "",
[string]$BaseUrl = "",
[switch]$NoKey,
[switch]$SkipConfig,
[switch]$Force
)
Set-ExecutionPolicy Bypass -Scope Process -Force -ErrorAction SilentlyContinue
try {
$null = cmd /c chcp 65001
[Console]::OutputEncoding = [System.Text.Encoding]::UTF8
$OutputEncoding = [System.Text.Encoding]::UTF8
} catch {}
$ErrorActionPreference = "Stop"
# ---- Constants ----
$UCLAW_DIR = "$env:USERPROFILE\.uclaw"
$RUNTIME_DIR = "$UCLAW_DIR\runtime"
$CORE_DIR = "$UCLAW_DIR\core"
$DATA_DIR = "$UCLAW_DIR\data"
$CONFIG_PATH = "$DATA_DIR\.openclaw\openclaw.json"
$NODE_VERSION = "v22.16.0"
$NODE_MIRROR = "https://npmmirror.com/mirrors/node"
# ---- Known model presets ----
$presets = @{
"deepseek-chat" = @{ baseUrl="https://api.deepseek.com/v1"; provider="custom" }
"moonshot-v1-auto" = @{ baseUrl="https://api.moonshot.cn/v1"; provider="custom" }
"qwen-plus" = @{ baseUrl="https://dashscope.aliyuncs.com/compatible-mode/v1"; provider="custom" }
"glm-4-plus" = @{ baseUrl="https://open.bigmodel.cn/api/paas/v4"; provider="custom" }
"abab6.5s-chat" = @{ baseUrl="https://api.minimax.chat/v1"; provider="custom" }
"claude-sonnet-4-20250514" = @{ baseUrl=""; provider="anthropic" }
"gpt-4o" = @{ baseUrl=""; provider="openai" }
"ollama" = @{ baseUrl="http://127.0.0.1:11434/v1"; provider="custom"; model="llama3.2" }
}
function Log($msg) { Write-Host "[uclaw-silent] $msg" }
function LogOK($msg) { Write-Host "[uclaw-silent] OK: $msg" -ForegroundColor Green }
function LogFail($msg) { Write-Host "[uclaw-silent] FAIL: $msg" -ForegroundColor Red }
# ============================================================
# Check existing install
# ============================================================
if ((Test-Path "$CORE_DIR\node_modules\openclaw") -and -not $Force) {
LogOK "Already installed at $UCLAW_DIR. Use -Force to overwrite."
exit 0
}
# Create directories
foreach ($d in @($RUNTIME_DIR, $CORE_DIR, "$DATA_DIR\.openclaw", "$DATA_DIR\memory", "$DATA_DIR\backups")) {
New-Item -ItemType Directory -Force -Path $d | Out-Null
}
# ============================================================
# Step 1: Node.js
# ============================================================
Log "Installing Node.js $NODE_VERSION ..."
$ARCH = $env:PROCESSOR_ARCHITECTURE
if ($ARCH -eq "AMD64" -or $ARCH -eq "x86_64") { $PLATFORM = "win-x64" }
elseif ($ARCH -eq "ARM64") { $PLATFORM = "win-arm64" }
else { LogFail "Unsupported arch: $ARCH"; exit 1 }
$NODE_INSTALL_DIR = "$RUNTIME_DIR\node-$PLATFORM"
$INSTALL_NODE = ""
$NPM_CLI = ""
# Check system Node.js
$sysNode = Get-Command node -ErrorAction SilentlyContinue
if ($sysNode) {
$sysVer = & node --version 2>$null
$major = [int]($sysVer -replace 'v','').Split('.')[0]
if ($major -ge 20) {
LogOK "System Node.js $sysVer"
$INSTALL_NODE = "node"
}
}
if (-not $INSTALL_NODE) {
if (Test-Path "$NODE_INSTALL_DIR\node.exe") {
LogOK "Node.js already downloaded"
$INSTALL_NODE = "$NODE_INSTALL_DIR\node.exe"
} else {
$zipName = "node-$NODE_VERSION-$PLATFORM.zip"
$url = "$NODE_MIRROR/$NODE_VERSION/$zipName"
$tempZip = "$env:TEMP\$zipName"
$tempExtract = "$env:TEMP\node-extract-uclaw"
Log "Downloading $url ..."
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
$ProgressPreference = 'SilentlyContinue'
try {
Invoke-WebRequest -Uri $url -OutFile $tempZip -UseBasicParsing
} catch {
try { & curl.exe -sL $url -o $tempZip } catch { LogFail "Node.js download failed"; exit 1 }
}
if (Test-Path $tempExtract) { Remove-Item -Recurse -Force $tempExtract }
Expand-Archive -Path $tempZip -DestinationPath $tempExtract -Force
$extractedDir = Get-ChildItem $tempExtract | Select-Object -First 1
New-Item -ItemType Directory -Force -Path $NODE_INSTALL_DIR | Out-Null
Copy-Item -Recurse -Force "$($extractedDir.FullName)\*" $NODE_INSTALL_DIR
Remove-Item -Force $tempZip -ErrorAction SilentlyContinue
Remove-Item -Recurse -Force $tempExtract -ErrorAction SilentlyContinue
if (Test-Path "$NODE_INSTALL_DIR\node.exe") {
LogOK "Node.js installed"
$INSTALL_NODE = "$NODE_INSTALL_DIR\node.exe"
} else {
LogFail "Node.js install failed"; exit 1
}
}
$env:PATH = "$NODE_INSTALL_DIR;$env:PATH"
}
# ============================================================
# Step 2: OpenClaw bundle
# ============================================================
Log "Installing OpenClaw ..."
if (Test-Path "$CORE_DIR\node_modules\openclaw\openclaw.mjs") {
LogOK "OpenClaw already installed"
} else {
$BUNDLE_URL = "https://github.com/dongsheng123132/u-claw/releases/download/v1.0.0-bundle/openclaw-bundle.zip"
$BUNDLE_MIRRORS = @(
"https://ghfast.top/$BUNDLE_URL",
"https://gh-proxy.com/$BUNDLE_URL",
"https://mirror.ghproxy.com/$BUNDLE_URL",
$BUNDLE_URL
)
$bundleZip = "$env:TEMP\openclaw-bundle.zip"
$downloaded = $false
foreach ($mirrorUrl in $BUNDLE_MIRRORS) {
Log "Trying: $mirrorUrl"
try {
$ProgressPreference = 'SilentlyContinue'
Invoke-WebRequest -Uri $mirrorUrl -OutFile $bundleZip -UseBasicParsing -TimeoutSec 60
if ((Get-Item $bundleZip).Length -gt 1MB) { $downloaded = $true; break }
} catch {}
}
if (-not $downloaded) {
try {
& curl.exe -sL "https://ghfast.top/$BUNDLE_URL" -o $bundleZip
if ((Get-Item $bundleZip).Length -gt 1MB) { $downloaded = $true }
} catch {}
}
if (-not $downloaded) { LogFail "OpenClaw download failed"; exit 1 }
$tempExtract = "$env:TEMP\openclaw-bundle-extract"
if (Test-Path $tempExtract) { Remove-Item -Recurse -Force $tempExtract }
Expand-Archive -Path $bundleZip -DestinationPath $tempExtract -Force
New-Item -ItemType Directory -Force -Path $CORE_DIR | Out-Null
Copy-Item -Recurse -Force "$tempExtract\*" $CORE_DIR
Remove-Item -Force $bundleZip -ErrorAction SilentlyContinue
Remove-Item -Recurse -Force $tempExtract -ErrorAction SilentlyContinue
if (Test-Path "$CORE_DIR\node_modules\openclaw\openclaw.mjs") {
LogOK "OpenClaw installed"
} else {
LogFail "OpenClaw install failed"; exit 1
}
}
# ============================================================
# Step 3: Config
# ============================================================
if ($SkipConfig) {
Log "Skipping config (-SkipConfig)"
} else {
Log "Configuring model: $Model ..."
# Resolve model preset
$resolvedModel = $Model
$resolvedBaseUrl = $BaseUrl
$resolvedProvider = "custom"
if ($presets.ContainsKey($Model)) {
$p = $presets[$Model]
if ($p.model) { $resolvedModel = $p.model }
if (-not $resolvedBaseUrl -and $p.baseUrl) { $resolvedBaseUrl = $p.baseUrl }
$resolvedProvider = $p.provider
}
if ($resolvedProvider -eq "custom" -and $resolvedBaseUrl) {
$configJson = @"
{
"gateway": {
"mode": "local",
"auth": { "token": "uclaw" }
},
"agent": {
"model": "$resolvedModel",
"apiKey": "$ApiKey",
"baseUrl": "$resolvedBaseUrl"
}
}
"@
} else {
$configJson = @"
{
"gateway": {
"mode": "local",
"auth": { "token": "uclaw" }
},
"agent": {
"model": "$resolvedModel",
"apiKey": "$ApiKey",
"provider": "$resolvedProvider"
}
}
"@
}
[IO.File]::WriteAllText($CONFIG_PATH, $configJson, (New-Object System.Text.UTF8Encoding $false))
LogOK "Config saved: model=$resolvedModel"
}
# ============================================================
# Step 4: Generate start script
# ============================================================
Log "Generating start.bat ..."
$startBat = @'
@echo off
setlocal EnableDelayedExpansion
chcp 65001 >nul 2>&1
title U-Claw
set "DIR=%~dp0"
set "NODE_BIN=%DIR%runtime\node-win-x64\node.exe"
if not exist "%NODE_BIN%" set "NODE_BIN=node"
set "OPENCLAW_MJS=%DIR%core\node_modules\openclaw\openclaw.mjs"
set "OPENCLAW_HOME=%DIR%data"
set "OPENCLAW_STATE_DIR=%DIR%data\.openclaw"
set "OPENCLAW_CONFIG_PATH=%DIR%data\.openclaw\openclaw.json"
set PORT=18789
:check_port
netstat -an | findstr ":%PORT% " | findstr "LISTENING" >nul 2>&1
if %errorlevel%==0 (
set /a PORT+=1
if !PORT! gtr 18799 (echo No available port & pause & exit /b 1)
goto :check_port
)
cd /d "%DIR%core"
start /B "" cmd /c "timeout /t 3 /nobreak >nul && start http://127.0.0.1:!PORT!/#token=uclaw"
"%NODE_BIN%" "%OPENCLAW_MJS%" gateway run --allow-unconfigured --force --port !PORT!
pause
'@
$startBat | Out-File -Encoding ascii "$UCLAW_DIR\start.bat"
LogOK "start.bat generated"
# ============================================================
# Done
# ============================================================
Log ""
LogOK "Installation complete!"
Log " Location: $UCLAW_DIR"
Log " Start: $UCLAW_DIR\start.bat"