@@ -0,0 +1,112 @@
|
||||
# Agent-safe: decrypt the local token and feed it to Git Credential Manager.
|
||||
# Never prints the token. Never writes it to a file.
|
||||
|
||||
param(
|
||||
[Parameter(Mandatory = $true)]
|
||||
[string]$RemoteUrl
|
||||
)
|
||||
|
||||
$ErrorActionPreference = 'Stop'
|
||||
. (Join-Path $PSScriptRoot 'common.ps1')
|
||||
|
||||
$gitProfile = Get-GitSkillsProfile
|
||||
if ($null -eq $gitProfile) {
|
||||
Write-StatusLine -Key 'status' -Value 'failed'
|
||||
Write-StatusLine -Key 'reason' -Value 'profile_missing'
|
||||
exit 1
|
||||
}
|
||||
|
||||
$username = ([string]$gitProfile.gitUsername).Trim()
|
||||
if ([string]::IsNullOrWhiteSpace($username)) {
|
||||
Write-StatusLine -Key 'status' -Value 'failed'
|
||||
Write-StatusLine -Key 'reason' -Value 'git_username_missing'
|
||||
exit 1
|
||||
}
|
||||
if ($username -match "[\r\n]") {
|
||||
Write-StatusLine -Key 'status' -Value 'failed'
|
||||
Write-StatusLine -Key 'reason' -Value 'git_username_invalid'
|
||||
exit 1
|
||||
}
|
||||
|
||||
if (-not (Test-Path -LiteralPath $script:TokenPath)) {
|
||||
Write-StatusLine -Key 'status' -Value 'failed'
|
||||
Write-StatusLine -Key 'reason' -Value 'token_missing'
|
||||
exit 1
|
||||
}
|
||||
|
||||
$parsed = Parse-GitRemoteUrl -RemoteUrl $RemoteUrl
|
||||
$hostName = [string]$parsed.CredentialHost
|
||||
if ([string]::IsNullOrWhiteSpace($hostName)) {
|
||||
$hostName = [string]$parsed.Host
|
||||
}
|
||||
if ([string]::IsNullOrWhiteSpace($hostName)) {
|
||||
Write-StatusLine -Key 'status' -Value 'failed'
|
||||
Write-StatusLine -Key 'reason' -Value 'host_parse_failed'
|
||||
exit 1
|
||||
}
|
||||
|
||||
$credProtocol = 'https'
|
||||
if ([string]$parsed.Protocol -eq 'http') {
|
||||
$credProtocol = 'http'
|
||||
}
|
||||
|
||||
$token = $null
|
||||
$payload = $null
|
||||
try {
|
||||
$data = [System.IO.File]::ReadAllBytes($script:TokenPath)
|
||||
$token = Unprotect-SecretBytes -Data $data
|
||||
if ([string]::IsNullOrWhiteSpace($token)) {
|
||||
Write-StatusLine -Key 'status' -Value 'failed'
|
||||
Write-StatusLine -Key 'reason' -Value 'token_invalid'
|
||||
exit 1
|
||||
}
|
||||
|
||||
$payload = @"
|
||||
protocol=$credProtocol
|
||||
host=$hostName
|
||||
username=$username
|
||||
password=$token
|
||||
|
||||
"@
|
||||
|
||||
$psi = New-Object System.Diagnostics.ProcessStartInfo
|
||||
$psi.FileName = 'git'
|
||||
$psi.Arguments = 'credential approve'
|
||||
$psi.UseShellExecute = $false
|
||||
$psi.RedirectStandardInput = $true
|
||||
$psi.RedirectStandardOutput = $true
|
||||
$psi.RedirectStandardError = $true
|
||||
$psi.CreateNoWindow = $true
|
||||
|
||||
$proc = New-Object System.Diagnostics.Process
|
||||
$proc.StartInfo = $psi
|
||||
[void]$proc.Start()
|
||||
foreach ($line in ($payload -split "`r?`n")) {
|
||||
$proc.StandardInput.WriteLine($line)
|
||||
}
|
||||
$proc.StandardInput.Close()
|
||||
$null = $proc.StandardOutput.ReadToEnd()
|
||||
$null = $proc.StandardError.ReadToEnd()
|
||||
$proc.WaitForExit()
|
||||
if ($proc.ExitCode -ne 0) {
|
||||
Write-StatusLine -Key 'status' -Value 'failed'
|
||||
Write-StatusLine -Key 'reason' -Value 'git_credential_approve_failed'
|
||||
exit 1
|
||||
}
|
||||
}
|
||||
catch {
|
||||
Write-StatusLine -Key 'status' -Value 'failed'
|
||||
Write-StatusLine -Key 'reason' -Value 'inject_error'
|
||||
exit 1
|
||||
}
|
||||
finally {
|
||||
$token = $null
|
||||
$payload = $null
|
||||
$data = $null
|
||||
}
|
||||
|
||||
Write-StatusLine -Key 'status' -Value 'injected'
|
||||
Write-StatusLine -Key 'host' -Value $hostName
|
||||
Write-StatusLine -Key 'protocol' -Value $credProtocol
|
||||
Write-StatusLine -Key 'username' -Value $username
|
||||
Write-Output 'token=hidden'
|
||||
Reference in New Issue
Block a user