144 lines
5.1 KiB
PowerShell
144 lines
5.1 KiB
PowerShell
param(
|
|
[string]$OutputDir = (Join-Path $PSScriptRoot '..\src-tauri\bundled\proxifyre'),
|
|
[ValidateSet('x64', 'x86', 'ARM64')]
|
|
[string[]]$Architectures = @('x64'),
|
|
[switch]$SkipVcRuntime
|
|
)
|
|
|
|
$ErrorActionPreference = 'Stop'
|
|
Set-StrictMode -Version Latest
|
|
$ProgressPreference = 'SilentlyContinue'
|
|
|
|
function Invoke-JsonApi([string]$Uri) {
|
|
Invoke-RestMethod -Uri $Uri -Headers @{
|
|
'User-Agent' = 'proxywarden-bundle-updater'
|
|
'Accept' = 'application/vnd.github+json'
|
|
} -TimeoutSec 60 -MaximumRedirection 10
|
|
}
|
|
|
|
function Invoke-FileDownload([string]$Uri, [string]$Path) {
|
|
$partialPath = "$Path.part"
|
|
Remove-Item -LiteralPath $partialPath -Force -ErrorAction SilentlyContinue
|
|
|
|
try {
|
|
Invoke-WebRequest -UseBasicParsing -Uri $Uri -OutFile $partialPath -Headers @{
|
|
'User-Agent' = 'proxywarden-bundle-updater'
|
|
'Accept' = 'application/octet-stream,*/*'
|
|
} -TimeoutSec 240 -MaximumRedirection 10
|
|
} catch {
|
|
Remove-Item -LiteralPath $partialPath -Force -ErrorAction SilentlyContinue
|
|
throw
|
|
}
|
|
|
|
$item = Get-Item -LiteralPath $partialPath
|
|
if ($item.Length -le 0) {
|
|
Remove-Item -LiteralPath $partialPath -Force -ErrorAction SilentlyContinue
|
|
throw "Downloaded file is empty: $Uri"
|
|
}
|
|
|
|
Move-Item -LiteralPath $partialPath -Destination $Path -Force
|
|
}
|
|
|
|
function Select-ReleaseAsset($Release, [string]$Pattern, [string]$Label) {
|
|
$asset = $Release.assets | Where-Object { $_.name -match $Pattern } | Select-Object -First 1
|
|
if ($null -eq $asset) {
|
|
throw "No asset found for $Label using pattern $Pattern"
|
|
}
|
|
|
|
$asset
|
|
}
|
|
|
|
function Save-Asset([string]$Id, [string]$Name, [string]$Url, [string]$ExpectedDigest = '') {
|
|
$path = Join-Path $OutputDir $Name
|
|
if (Test-Path -LiteralPath $path) {
|
|
$existing = Get-Item -LiteralPath $path
|
|
if ($existing.Length -gt 0) {
|
|
$existingHash = (Get-FileHash -LiteralPath $path -Algorithm SHA256).Hash.ToLowerInvariant()
|
|
$expectedHash = ''
|
|
if (-not [string]::IsNullOrWhiteSpace($ExpectedDigest) -and $ExpectedDigest -match '^sha256:(.+)$') {
|
|
$expectedHash = $Matches[1].ToLowerInvariant()
|
|
}
|
|
|
|
if ([string]::IsNullOrWhiteSpace($expectedHash) -or $existingHash -eq $expectedHash) {
|
|
Write-Host "Using existing $Name"
|
|
return [PSCustomObject]@{
|
|
id = $Id
|
|
name = $Name
|
|
sha256 = $existingHash
|
|
size = $existing.Length
|
|
sourceUrl = $Url
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
Write-Host "Downloading $Name"
|
|
Invoke-FileDownload $Url $path
|
|
|
|
$hash = (Get-FileHash -LiteralPath $path -Algorithm SHA256).Hash.ToLowerInvariant()
|
|
if (-not [string]::IsNullOrWhiteSpace($ExpectedDigest) -and $ExpectedDigest -match '^sha256:(.+)$') {
|
|
$expected = $Matches[1].ToLowerInvariant()
|
|
if ($hash -ne $expected) {
|
|
throw "SHA256 mismatch for $Name. Expected $expected, got $hash."
|
|
}
|
|
}
|
|
|
|
[PSCustomObject]@{
|
|
id = $Id
|
|
name = $Name
|
|
sha256 = $hash
|
|
size = (Get-Item -LiteralPath $path).Length
|
|
sourceUrl = $Url
|
|
}
|
|
}
|
|
|
|
$resolvedOutputDir = [System.IO.Path]::GetFullPath($OutputDir)
|
|
New-Item -ItemType Directory -Force -Path $resolvedOutputDir | Out-Null
|
|
$OutputDir = $resolvedOutputDir
|
|
|
|
$selectedArchitectures = $Architectures |
|
|
ForEach-Object {
|
|
if ($_ -eq 'ARM64') { 'ARM64' } elseif ($_ -eq 'x86') { 'x86' } else { 'x64' }
|
|
} |
|
|
Select-Object -Unique
|
|
|
|
$proxifyreRelease = Invoke-JsonApi 'https://api.github.com/repos/wiresock/proxifyre/releases/latest'
|
|
$ndisapiRelease = Invoke-JsonApi 'https://api.github.com/repos/wiresock/ndisapi/releases/latest'
|
|
|
|
$files = New-Object System.Collections.Generic.List[object]
|
|
|
|
foreach ($arch in $selectedArchitectures) {
|
|
$proxifyreAsset = Select-ReleaseAsset $proxifyreRelease "ProxiFyre-.*-$arch-signed\.zip$" "ProxiFyre $arch"
|
|
$files.Add((Save-Asset "proxifyre-$($arch.ToLowerInvariant())" $proxifyreAsset.name $proxifyreAsset.browser_download_url $proxifyreAsset.digest))
|
|
|
|
$ndisAsset = Select-ReleaseAsset $ndisapiRelease "Windows\.Packet\.Filter\..*\.$arch\.msi$" "Windows Packet Filter $arch"
|
|
$files.Add((Save-Asset "packet-filter-$($arch.ToLowerInvariant())" $ndisAsset.name $ndisAsset.browser_download_url $ndisAsset.digest))
|
|
}
|
|
|
|
if (-not $SkipVcRuntime) {
|
|
if ($selectedArchitectures | Where-Object { $_ -ne 'x86' }) {
|
|
$files.Add((Save-Asset 'vc-runtime-x64' 'vc_redist.x64.exe' 'https://aka.ms/vc14/vc_redist.x64.exe'))
|
|
}
|
|
if ($selectedArchitectures -contains 'x86') {
|
|
$files.Add((Save-Asset 'vc-runtime-x86' 'vc_redist.x86.exe' 'https://aka.ms/vc14/vc_redist.x86.exe'))
|
|
}
|
|
}
|
|
|
|
$manifest = [PSCustomObject]@{
|
|
generatedAt = (Get-Date).ToUniversalTime().ToString('o')
|
|
architectures = @($selectedArchitectures)
|
|
proxifyreRelease = $proxifyreRelease.tag_name
|
|
windowsPacketFilterRelease = $ndisapiRelease.tag_name
|
|
files = $files
|
|
}
|
|
|
|
$manifestPath = Join-Path $OutputDir 'manifest.json'
|
|
$manifest | ConvertTo-Json -Depth 5 | Set-Content -LiteralPath $manifestPath -Encoding UTF8
|
|
|
|
$keepNames = @($files | ForEach-Object { $_.name }) + 'manifest.json'
|
|
Get-ChildItem -LiteralPath $OutputDir -File |
|
|
Where-Object { $keepNames -notcontains $_.Name } |
|
|
ForEach-Object { Remove-Item -LiteralPath $_.FullName -Force }
|
|
|
|
Write-Host "Bundle updated: $OutputDir"
|