@@ -0,0 +1,98 @@
|
||||
# Generate a Gitea GPG key-verification signature (official UI challenge).
|
||||
# Token comes from /user/settings/keys -> Verify. Never commit the token.
|
||||
# Matches Gitea template: echo "TOKEN" | gpg -a --default-key KEYID --detach-sig
|
||||
# (trailing newline included - unlike SSH verification).
|
||||
|
||||
param(
|
||||
[Parameter(Mandatory = $true)]
|
||||
[string]$Token,
|
||||
[Parameter(Mandatory = $true)]
|
||||
[string]$KeyId,
|
||||
[string]$GpgPath
|
||||
)
|
||||
|
||||
$ErrorActionPreference = 'Stop'
|
||||
. (Join-Path $PSScriptRoot 'common.ps1')
|
||||
|
||||
function Resolve-GpgPath {
|
||||
param([string]$Preferred)
|
||||
if ($Preferred -and (Test-Path -LiteralPath $Preferred)) { return $Preferred }
|
||||
$cmd = Get-Command gpg -ErrorAction SilentlyContinue
|
||||
if ($cmd) { return $cmd.Source }
|
||||
$candidates = @(
|
||||
(Join-Path $env:ProgramFiles 'Git\usr\bin\gpg.exe'),
|
||||
(Join-Path ${env:ProgramFiles(x86)} 'GnuPG\bin\gpg.exe'),
|
||||
(Join-Path $env:ProgramFiles 'GnuPG\bin\gpg.exe')
|
||||
)
|
||||
foreach ($p in $candidates) {
|
||||
if ($p -and (Test-Path -LiteralPath $p)) { return $p }
|
||||
}
|
||||
return $null
|
||||
}
|
||||
|
||||
$gpg = Resolve-GpgPath -Preferred $GpgPath
|
||||
if ($null -eq $gpg) {
|
||||
Write-StatusLine -Key 'status' -Value 'failed'
|
||||
Write-StatusLine -Key 'reason' -Value 'gpg_missing'
|
||||
exit 1
|
||||
}
|
||||
|
||||
$token = $Token.Trim()
|
||||
$keyId = $KeyId.Trim()
|
||||
if ([string]::IsNullOrWhiteSpace($token) -or [string]::IsNullOrWhiteSpace($keyId)) {
|
||||
Write-StatusLine -Key 'status' -Value 'failed'
|
||||
Write-StatusLine -Key 'reason' -Value 'token_or_key_empty'
|
||||
exit 1
|
||||
}
|
||||
|
||||
$bash = Join-Path $env:ProgramFiles 'Git\bin\bash.exe'
|
||||
$sigText = $null
|
||||
# gpg prints "using ... as default secret key" to stderr; do not treat as terminating error.
|
||||
$prevEap = $ErrorActionPreference
|
||||
$ErrorActionPreference = 'Continue'
|
||||
try {
|
||||
if (Test-Path -LiteralPath $bash) {
|
||||
# Unix echo "TOKEN" includes a single trailing LF - matches Gitea UI help.
|
||||
$sigText = Invoke-GitSkillsNativeWithInput -FilePath $bash -ArgumentList @('-lc', "gpg -a --default-key '$keyId' --detach-sig") -InputText ($token + "`n") | Out-String
|
||||
} else {
|
||||
$tmp = [System.IO.Path]::GetTempFileName()
|
||||
try {
|
||||
# UTF-8 token + LF, no BOM
|
||||
$bytes = [System.Text.Encoding]::UTF8.GetBytes($token + "`n")
|
||||
[System.IO.File]::WriteAllBytes($tmp, $bytes)
|
||||
$null = Invoke-GitSkillsNative -FilePath $gpg -ArgumentList @('-a', '--default-key', $keyId, '--detach-sig', $tmp)
|
||||
$asc = $tmp + '.asc'
|
||||
if (Test-Path -LiteralPath $asc) {
|
||||
$sigText = Get-Content -LiteralPath $asc -Raw -Encoding UTF8
|
||||
Remove-Item -LiteralPath $asc -Force -ErrorAction SilentlyContinue
|
||||
}
|
||||
}
|
||||
finally {
|
||||
Remove-Item -LiteralPath $tmp -Force -ErrorAction SilentlyContinue
|
||||
}
|
||||
}
|
||||
}
|
||||
finally {
|
||||
$ErrorActionPreference = $prevEap
|
||||
}
|
||||
|
||||
if ($sigText -notmatch 'BEGIN PGP SIGNATURE') {
|
||||
Write-StatusLine -Key 'status' -Value 'failed'
|
||||
Write-StatusLine -Key 'reason' -Value 'sign_failed'
|
||||
Write-StatusLine -Key 'gpg' -Value $gpg
|
||||
exit 1
|
||||
}
|
||||
|
||||
Write-StatusLine -Key 'status' -Value 'ok'
|
||||
Write-StatusLine -Key 'key_id' -Value $keyId
|
||||
Write-StatusLine -Key 'gpg' -Value $gpg
|
||||
Write-Output '-----BEGIN_SIGNATURE_BODY-----'
|
||||
# Print only the armored block lines for easy copy
|
||||
$capture = $false
|
||||
foreach ($line in ($sigText -split "`r?`n")) {
|
||||
if ($line -match 'BEGIN PGP SIGNATURE') { $capture = $true }
|
||||
if ($capture) { Write-Output $line }
|
||||
if ($line -match 'END PGP SIGNATURE') { break }
|
||||
}
|
||||
Write-Output '-----END_SIGNATURE_BODY-----'
|
||||
Write-Output 'Paste the block between BEGIN/END PGP SIGNATURE into Gitea Verify, then click verify.'
|
||||
Reference in New Issue
Block a user