100 lines
4.4 KiB
PowerShell
100 lines
4.4 KiB
PowerShell
[CmdletBinding()]
|
|
param(
|
|
[Parameter(Mandatory = $true)][string] $Destination,
|
|
[string] $ArchivePath,
|
|
[ValidateSet('x64', 'arm64')][string] $Architecture = 'x64'
|
|
)
|
|
|
|
$ErrorActionPreference = 'Stop'
|
|
Set-StrictMode -Version Latest
|
|
$OutputEncoding = [Console]::OutputEncoding = [System.Text.UTF8Encoding]::new($false)
|
|
|
|
# Reuse the Microsoft 1.22 runtime pair already shipped with Pebrel's predecessor.
|
|
# Only these two redistributables are extracted, never the older application.
|
|
$archiveHash = '9B2413144C0434E29749CCBD5C2B0F93E930DAFD22634DD70D34B763037E0DA4'
|
|
$sourceUrl = 'https://github.com/Kuddev/pebrel/releases/download/v1.5.0/NebulaTerminal-v1.5.0-windows-x64.zip'
|
|
$expected = [ordered]@{
|
|
'conpty.dll' = '375BFB0479B6C53836AB307E3F9FD17BEDBD733F2E9690943D0F12E72FB80777'
|
|
'OpenConsole.exe' = '55B18996761C88C351820E82508E05AB0EC2194AEEAD20724FDFAEEDEC076EF4'
|
|
}
|
|
$entries = @{
|
|
'conpty.dll' = 'runtime\conpty.dll'
|
|
'OpenConsole.exe' = 'runtime\OpenConsole.exe'
|
|
}
|
|
$archiveName = 'pebrel-conpty-source-v1.5.0.zip'
|
|
$machine = 0x8664
|
|
if ($Architecture -eq 'arm64') {
|
|
# Microsoft MIT-licensed redistributables; the NuGet declares build 17763+.
|
|
# Keep the previously shipped x64 runtime unchanged.
|
|
$sourceUrl = 'https://api.nuget.org/v3-flatcontainer/microsoft.windows.console.conpty/1.24.260710001/microsoft.windows.console.conpty.1.24.260710001.nupkg'
|
|
$archiveName = 'pebrel-conpty-source-1.24.260710001.nupkg'
|
|
$archiveHash = '175640566A3B59C4B132070EE96C2C77E5AB7EDD2E92732A5EB3610BBF63D90E'
|
|
$expected = [ordered]@{
|
|
'conpty.dll' = 'DB3D173640B172BAFD42D5B541B638A9AEEC1C7D0E40DD636BF02822A32C912C'
|
|
'OpenConsole.exe' = 'ED7622FD0D3BEDC9AB9F122F5E58EDF0DEF9E7999224F52DD395BA9F54EDBE09'
|
|
}
|
|
$entries = @{
|
|
'conpty.dll' = 'runtimes/win-arm64/native/conpty.dll'
|
|
'OpenConsole.exe' = 'build/native/runtimes/arm64/OpenConsole.exe'
|
|
}
|
|
$machine = 0xAA64
|
|
}
|
|
|
|
function Assert-RuntimeMachine([string] $Path) {
|
|
$bytes = [IO.File]::ReadAllBytes($Path)
|
|
if ($bytes.Length -lt 64 -or $bytes[0] -ne 0x4D -or $bytes[1] -ne 0x5A) {
|
|
throw "Invalid PE runtime: $Path"
|
|
}
|
|
$offset = [BitConverter]::ToInt32($bytes, 0x3C)
|
|
if ($offset -lt 64 -or $offset -gt $bytes.Length - 6 -or
|
|
[BitConverter]::ToUInt32($bytes, $offset) -ne 0x4550 -or
|
|
[BitConverter]::ToUInt16($bytes, $offset + 4) -ne $machine) {
|
|
throw "Runtime PE architecture does not match $Architecture`: $Path"
|
|
}
|
|
}
|
|
|
|
if ([string]::IsNullOrWhiteSpace($ArchivePath)) {
|
|
$ArchivePath = Join-Path ([System.IO.Path]::GetTempPath()) $archiveName
|
|
if (-not (Test-Path -LiteralPath $ArchivePath -PathType Leaf)) {
|
|
Invoke-WebRequest -Uri $sourceUrl -OutFile $ArchivePath -UseBasicParsing -TimeoutSec 120
|
|
}
|
|
}
|
|
if ((Get-FileHash -LiteralPath $ArchivePath -Algorithm SHA256).Hash -ne $archiveHash) {
|
|
throw 'The pinned runtime source archive failed SHA256 verification.'
|
|
}
|
|
|
|
Add-Type -AssemblyName System.IO.Compression.FileSystem
|
|
$archive = [System.IO.Compression.ZipFile]::OpenRead((Resolve-Path $ArchivePath).Path)
|
|
try {
|
|
New-Item -ItemType Directory -Path $Destination -Force | Out-Null
|
|
foreach ($name in $expected.Keys) {
|
|
$target = Join-Path $Destination $name
|
|
if ((Test-Path -LiteralPath $target -PathType Leaf) -and
|
|
(Get-FileHash -LiteralPath $target -Algorithm SHA256).Hash -eq $expected[$name]) {
|
|
Assert-RuntimeMachine $target
|
|
continue
|
|
}
|
|
$entry = $archive.GetEntry($entries[$name])
|
|
if ($null -eq $entry) { throw "Runtime archive is missing $($entries[$name])" }
|
|
$temporary = "$target.$([guid]::NewGuid().ToString('N')).tmp"
|
|
try {
|
|
$inputStream = $entry.Open()
|
|
try {
|
|
$outputStream = [System.IO.File]::Create($temporary)
|
|
try { $inputStream.CopyTo($outputStream) } finally { $outputStream.Dispose() }
|
|
} finally { $inputStream.Dispose() }
|
|
if ((Get-FileHash -LiteralPath $temporary -Algorithm SHA256).Hash -ne $expected[$name]) {
|
|
throw "The pinned $name failed SHA256 verification."
|
|
}
|
|
Assert-RuntimeMachine $temporary
|
|
Move-Item -LiteralPath $temporary -Destination $target -Force
|
|
} finally {
|
|
if (Test-Path -LiteralPath $temporary) { Remove-Item -LiteralPath $temporary }
|
|
}
|
|
}
|
|
} finally { $archive.Dispose() }
|
|
|
|
foreach ($name in $expected.Keys) {
|
|
Write-Output "$name SHA256 $($expected[$name])"
|
|
}
|