[CmdletBinding()] param( [Parameter(Mandatory=$true)][string]$ManifestUrl, [switch]$Apply ) $ErrorActionPreference = "Stop" $Root = Resolve-Path (Join-Path $PSScriptRoot "..") $tmp = Join-Path $Root ".jackailocal\updates" New-Item -ItemType Directory -Force -Path $tmp | Out-Null $manifestPath = Join-Path $tmp "update-manifest.json" $sigPath = Join-Path $tmp "update-manifest.json.sig" $pubKeyPath = Join-Path $Root "config\update-public-key.xml" if (!(Test-Path $pubKeyPath)) { throw "Public key for update verification not found at: $pubKeyPath" } # Download manifest and signature Invoke-WebRequest -Uri $ManifestUrl -OutFile $manifestPath Invoke-WebRequest -Uri "$ManifestUrl.sig" -OutFile $sigPath # Verify Signature & (Join-Path $PSScriptRoot "Verify-SignedManifest.ps1") -ManifestPath $manifestPath -SignaturePath $sigPath -PublicKeyXmlPath $pubKeyPath $manifest = Get-Content $manifestPath -Raw | ConvertFrom-Json if ($manifest.product -ne "JackAILocal") { throw "Wrong product." } $rootPath = [System.IO.Path]::GetFullPath($Root) foreach ($file in $manifest.files) { # Avoid Path Traversal Vulnerability $dest = [System.IO.Path]::GetFullPath((Join-Path $rootPath $file.path)) if (-not $dest.StartsWith($rootPath, [System.StringComparison]::OrdinalIgnoreCase)) { throw "Security error: Path traversal detected in file path: $($file.path)" } $download = Join-Path $tmp ([IO.Path]::GetFileName($file.path)) Invoke-WebRequest -Uri $file.url -OutFile $download $h = (Get-FileHash -Algorithm SHA256 $download).Hash.ToLowerInvariant() if ($h -ne $file.sha256.ToLowerInvariant()) { throw "Checksum failed: $($file.path)" } if ($Apply) { New-Item -ItemType Directory -Force -Path (Split-Path $dest) | Out-Null Copy-Item $download $dest -Force } } if (-not $Apply) { Write-Host "Dry-run update verified. Use -Apply to install." }