Eigenverft.Manifested.Sandbox.Shared.GitHubReleases.ps1
|
<#
Eigenverft.Manifested.Sandbox.Shared.GitHubReleases #> function Enable-ManifestedTls12Support { [CmdletBinding()] param() try { $tls12 = [System.Net.SecurityProtocolType]::Tls12 if (([System.Net.ServicePointManager]::SecurityProtocol -band $tls12) -ne $tls12) { [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor $tls12 } } catch { } } function Get-ManifestedGitHubRequestHeaders { [CmdletBinding()] param() return @{ 'User-Agent' = 'Eigenverft.Manifested.Sandbox' 'Accept' = 'application/vnd.github+json' 'X-GitHub-Api-Version' = '2022-11-28' } } function Invoke-ManifestedGitHubJsonRequest { [CmdletBinding()] param( [Parameter(Mandatory = $true)] [string]$Uri ) Enable-ManifestedTls12Support return (Invoke-RestMethod -Uri $Uri -Headers (Get-ManifestedGitHubRequestHeaders) -ErrorAction Stop) } function Invoke-ManifestedGitHubWebRequest { [CmdletBinding()] param( [Parameter(Mandatory = $true)] [string]$Uri ) Enable-ManifestedTls12Support return (Invoke-WebRequest -Uri $Uri -Headers @{ 'User-Agent' = 'Eigenverft.Manifested.Sandbox' } -UseBasicParsing -ErrorAction Stop) } function ConvertTo-ManifestedSha256Digest { [CmdletBinding()] param( [string]$Digest ) if ([string]::IsNullOrWhiteSpace($Digest)) { return $null } $match = [regex]::Match($Digest, 'sha256:([0-9a-fA-F]{64})') if ($match.Success) { return $match.Groups[1].Value.ToLowerInvariant() } if ($Digest -match '^[0-9a-fA-F]{64}$') { return $Digest.ToLowerInvariant() } return $null } function Get-ManifestedGitHubLatestRelease { [CmdletBinding()] param( [Parameter(Mandatory = $true)] [string]$Owner, [Parameter(Mandatory = $true)] [string]$Repository ) $release = Invoke-ManifestedGitHubJsonRequest -Uri ("https://api.github.com/repos/{0}/{1}/releases/latest" -f $Owner, $Repository) $assets = @( foreach ($asset in @($release.assets)) { [pscustomobject]@{ Name = $asset.name BrowserDownloadUrl = $asset.browser_download_url Digest = ConvertTo-ManifestedSha256Digest -Digest $asset.digest ContentType = $asset.content_type Size = $asset.size } } ) return [pscustomobject]@{ Owner = $Owner Repository = $Repository TagName = [string]$release.tag_name Name = [string]$release.name HtmlUrl = [string]$release.html_url Body = [string]$release.body Draft = [bool]$release.draft Prerelease = [bool]$release.prerelease Assets = @($assets) Source = 'GitHubApi' } } function Get-ManifestedGitHubLatestReleaseTag { [CmdletBinding()] param( [Parameter(Mandatory = $true)] [string]$Owner, [Parameter(Mandatory = $true)] [string]$Repository ) $response = Invoke-ManifestedGitHubWebRequest -Uri ("https://github.com/{0}/{1}/releases/latest" -f $Owner, $Repository) $resolvedUri = $null if ($response.BaseResponse -and $response.BaseResponse.ResponseUri) { $resolvedUri = $response.BaseResponse.ResponseUri.AbsoluteUri } if ([string]::IsNullOrWhiteSpace($resolvedUri)) { return $null } $match = [regex]::Match($resolvedUri, '/releases/tag/([^/?#]+)') if (-not $match.Success) { return $null } return [pscustomobject]@{ Owner = $Owner Repository = $Repository TagName = [uri]::UnescapeDataString($match.Groups[1].Value) HtmlUrl = $resolvedUri Source = 'GitHubLatestRedirect' } } function Get-ManifestedGitHubReleaseAsset { [CmdletBinding()] param( [Parameter(Mandatory = $true)] [pscustomobject]$Release, [Parameter(Mandatory = $true)] [string]$AssetName ) return (@($Release.Assets | Where-Object { $_.Name -eq $AssetName }) | Select-Object -First 1) } function New-ManifestedGitHubReleaseAssetUrl { [CmdletBinding()] param( [Parameter(Mandatory = $true)] [string]$Owner, [Parameter(Mandatory = $true)] [string]$Repository, [Parameter(Mandatory = $true)] [string]$TagName, [Parameter(Mandatory = $true)] [string]$AssetName ) return ('https://github.com/{0}/{1}/releases/download/{2}/{3}' -f $Owner, $Repository, $TagName, $AssetName) } function Get-ManifestedSha256FromText { [CmdletBinding()] param( [Parameter(Mandatory = $true)] [string]$Content, [Parameter(Mandatory = $true)] [string]$FileName ) $escapedFileName = [regex]::Escape($FileName) $patterns = @( '(?im)^\s*([0-9a-f]{64})\s+[\*\s]?' + $escapedFileName + '\s*$', '(?im)^\s*' + $escapedFileName + '\s*\|\s*([0-9a-f]{64})\s*$' ) foreach ($pattern in $patterns) { $match = [regex]::Match($Content, $pattern) if ($match.Success) { return $match.Groups[1].Value.ToLowerInvariant() } } return $null } function Get-ManifestedSha256FromHtml { [CmdletBinding()] param( [Parameter(Mandatory = $true)] [string]$Html, [Parameter(Mandatory = $true)] [string]$AssetName ) $pattern = [regex]::Escape($AssetName) + '.{0,1000}?([0-9a-fA-F]{64})' $match = [regex]::Match( $Html, $pattern, [System.Text.RegularExpressions.RegexOptions]::IgnoreCase -bor [System.Text.RegularExpressions.RegexOptions]::Singleline ) if ($match.Success) { return $match.Groups[1].Value.ToLowerInvariant() } return $null } function Get-ManifestedGitHubReleaseAssetChecksum { [CmdletBinding()] param( [pscustomobject]$Release, [Parameter(Mandatory = $true)] [string]$Owner, [Parameter(Mandatory = $true)] [string]$Repository, [Parameter(Mandatory = $true)] [string]$TagName, [Parameter(Mandatory = $true)] [string]$AssetName, [ValidateSet('None', 'ReleaseHtml', 'ChecksumAsset')] [string]$FallbackSource = 'None', [string]$ChecksumAssetName ) if ($Release) { $asset = Get-ManifestedGitHubReleaseAsset -Release $Release -AssetName $AssetName if ($asset -and $asset.Digest) { return [pscustomobject]@{ Sha256 = $asset.Digest Source = 'GitHubAssetDigest' } } } switch ($FallbackSource) { 'ChecksumAsset' { if ([string]::IsNullOrWhiteSpace($ChecksumAssetName)) { throw 'ChecksumAssetName is required when FallbackSource is ChecksumAsset.' } $checksumAsset = $null if ($Release) { $checksumAsset = Get-ManifestedGitHubReleaseAsset -Release $Release -AssetName $ChecksumAssetName } $checksumUrl = if ($checksumAsset) { $checksumAsset.BrowserDownloadUrl } else { New-ManifestedGitHubReleaseAssetUrl -Owner $Owner -Repository $Repository -TagName $TagName -AssetName $ChecksumAssetName } $response = Invoke-ManifestedGitHubWebRequest -Uri $checksumUrl $sha256 = Get-ManifestedSha256FromText -Content $response.Content -FileName $AssetName if ($sha256) { return [pscustomobject]@{ Sha256 = $sha256 Source = 'GitHubChecksumAsset' } } } 'ReleaseHtml' { $response = Invoke-ManifestedGitHubWebRequest -Uri ("https://github.com/{0}/{1}/releases/tag/{2}" -f $Owner, $Repository, $TagName) $sha256 = Get-ManifestedSha256FromHtml -Html $response.Content -AssetName $AssetName if ($sha256) { return [pscustomobject]@{ Sha256 = $sha256 Source = 'GitHubReleaseHtml' } } } } return $null } |