Last active
April 25, 2024 08:56
-
-
Save mavaddat/29bea8cbc54d14b5ca04aef6af0cfeca to your computer and use it in GitHub Desktop.
Setting Python REQUESTS_CA_BUNDLE for Windows using all the available certificates on the machine. Answer to this Stackoverflow question: https://stackoverflow.com/questions/51925384/unable-to-get-local-issuer-certificate-when-using-requests-in-python
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#Requires -Version 6.0 | |
# Allocate a temporary directory for receiving the certificates | |
$tmpCertsDir = New-Item -Path "$env:TEMP" -Name "Certs$(Get-Date -Format FileDateTimeUniversal)" -ItemType Directory -Force | |
# Collect the certs from the local machine | |
$certs = Get-ChildItem -Path Cert:\ -Recurse | Where-Object -FilterScript { $_.Thumbprint } | |
# This will contain the paths to the resulting PEM files | |
$pemPaths = [string[]]::new($certs.Count) | |
$certs | ForEach-Object -Process { | |
$curCert = $_.FriendlyName | |
$i = $certs.IndexOf($_) | |
if ([string]::IsNullOrEmpty($curCert)) { | |
$curCert = $_.Subject | |
} | |
if ([string]::IsNullOrEmpty($curCert)) { | |
$curCert = $_.Thumbprint | |
} | |
Write-Progress -Activity 'Copying certificates' -Status "Copying $curCert" -PercentComplete (100 * $i / $certs.Count) | |
$outCert = Join-Path -Path $tmpCertsDir -ChildPath "$($_.Thumbprint).crt" | |
$pemPaths[$i] = Join-Path -Path $export.Directory.FullName -ChildPath "$($export.BaseName).pem" | |
if (-not (Test-Path -Path $outCert -PathType Leaf)) { | |
$export = $_ | Export-Certificate -Type CERT -FilePath $outCert -Force | |
openssl x509 -inform DER -in $export.FullName -out ($pemPaths[$i]) -text | |
} | |
} -End { | |
Remove-Item -Path $tmpCertsDir\*.crt -Force | |
Write-Progress -Activity 'Copying certificates' -Status 'Done' -Completed | |
} | |
<# if you already have certifi installed, you can use | |
$RequestsCaBundle = python -c 'import certifi; print(certifi.where())' # "$Env:LOCALAPPDATA\Packages\PythonSoftwareFoundation.Python.3.11_qbz5n2kfra8p0\LocalCache\local-packages\Python311\site-packages\certifi\cacert.pem" | |
#> | |
<# Apparently, we aren't allowed to write into the site-packages directory, so this does not work | |
$RequestsCaBundle = Join-Path -Path (python -c "import sys; [print(p) for p in sys.path if p.endswith(r'Lib\site-packages')]" | Sort-Object -Unique) -ChildPath "cacerts.pem" | |
#> | |
$RequestsCaBundle = "$env:USERPROFILE\cacerts.pem" # Not sure if this is the best location for cacerts on Windows | |
$rcaTmp = New-TemporaryFile | |
for ($i = 0; $i -lt $pemPaths.Count; $i++) { | |
Write-Progress -Activity 'Concatenating certificates' -Status "Concatenating $curCert" -PercentComplete (100 * $i / $pemPaths.Count) | |
$pemPaths[$i] | Get-Content | Add-Content -Path $rcaTmp -Force | |
} | |
Remove-Item -Path $tmpCertsDir -Recurse -Force | |
try { | |
Move-Item -Path $rcaTmp -Destination $RequestsCaBundle -Force -ErrorAction Stop | |
} | |
catch [System.UnauthorizedAccessException] { | |
if (-not(Test-Path -Path $RequestsCaBundle -PathType Leaf) -and $rcaTmp.Length -gt 0) { | |
$errOut = New-TemporaryFile | |
# Move $rcaTmp to $RequestsCaBundle using RunAs verb | |
Start-Process -FilePath pwsh -ArgumentList @('NonInteractive', 'NoProfile', 'NoLogo', "-Command `"try { Move-Item -Path '$rcaTmp' -Destination '$RequestsCaBundle' -Force *>&1 }catch{`$_} ) | Export-Clixml -Path $errOut -Force`"") -Verb RunAs | |
if ($errOut.Length -gt 0) { | |
Import-Clixml -Path $errOut | Write-Error | |
} | |
Remove-Item -Path $errOut | |
} | |
} | |
if (Test-Path -Path $RequestsCaBundle -PathType Leaf) { | |
$env:REQUESTS_CA_BUNDLE = "$RequestsCaBundle" | |
try { | |
[System.Environment]::SetEnvironmentVariable('REQUESTS_CA_BUNDLE',$RequestsCaBundle,[System.EnvironmentVariableTarget]::Machine) | |
} | |
catch [System.Management.Automation.MethodInvocationException] { | |
$errOut = New-TemporaryFile | |
# Set the REQUESTS_CA_BUNDLE environment variable at the machine scope using RunAs verb | |
Start-Process -FilePath pwsh -ArgumentList @('NonInteractive', 'NoProfile', 'NoLogo', "-Command `"try { [System.Environment]::SetEnvironmentVariable('REQUESTS_CA_BUNDLE',$RequestsCaBundle,[System.EnvironmentVariableTarget]::Machine) *>&1 }catch{`$_} ) | Export-Clixml -Path $errOut -Force`"") -Verb RunAs | |
if ($errOut.Length -gt 0) { | |
Import-Clixml -Path $errOut | Write-Error | |
} | |
Remove-Item -Path $errOut | |
} | |
} | |
else { | |
Write-Warning "Unable to write to '$RequestsCaBundle'; Check permissions and try again." | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment