Files
Git-Skill/.cursor/skills/git-init/scripts/verify-gpg-challenge.ps1
T
2026-08-20 23:42:02 +08:00

99 lines
3.6 KiB
PowerShell

# 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.'