From 7cc0a02a7cc3e44eb870d4f430b5a792e0dda285 Mon Sep 17 00:00:00 2001 From: Adrien Ferrand Date: Tue, 12 Nov 2019 00:00:26 +0100 Subject: [PATCH] Prepare logic --- windows-installer/auto-update.ps1 | 81 +++++++++++++++++++++++++++++++ windows-installer/construct.py | 10 ++-- windows-installer/renew-down.ps1 | 6 --- windows-installer/renew-up.ps1 | 15 ------ windows-installer/tasks-down.ps1 | 8 +++ windows-installer/tasks-up.ps1 | 26 ++++++++++ windows-installer/template.nsi | 10 ++-- 7 files changed, 126 insertions(+), 30 deletions(-) create mode 100644 windows-installer/auto-update.ps1 delete mode 100644 windows-installer/renew-down.ps1 delete mode 100644 windows-installer/renew-up.ps1 create mode 100644 windows-installer/tasks-down.ps1 create mode 100644 windows-installer/tasks-up.ps1 diff --git a/windows-installer/auto-update.ps1 b/windows-installer/auto-update.ps1 new file mode 100644 index 000000000..2ed20fdef --- /dev/null +++ b/windows-installer/auto-update.ps1 @@ -0,0 +1,81 @@ +#Requires -RunAsAdministrator + +Param( + [Parameter(Mandatory=$true)] + [string]$InstallDir +) + +Start-Transcript -Path "C:\Certbot\log\auto-update.log" +trap { + Stop-Transcript +} + +$ErrorActionPreference = 'Stop' + +$installerAuthenticodeCertificateThumbprint = "74B2E146A82F2B71F8EB4B13EBBB6F951757D8C2" + +# Get current local certbot version +try { + $currentVersion = certbot --version + $currentVersion = $currentVersion -replace '^certbot (\d+\.\d+\.\d+).*$', '$1' +} catch { + "An error occured while fetching the current local certbot version:" + $_.Exception + "Assuming Certbot is not up-to-date." + $currentVersion = "0.0.0" +} + +# Get latest remote certbot version +try { + $result = Invoke-RestMethod -Uri https://api.github.com/repos/certbot/certbot/releases/latest + $latestVersion = $result.tag_name -replace '^v(\d+\.\d+\.\d+).*$', '$1' +} catch { + "Could not get the latest remote certbot version. Error was:" + $_.Exception + throw "Aborting auto-upgrade process." +} + +if ([System.Version]"$currentVersion" -ge [System.Version]"$latestVersion") { + "No upgrade is needed, Certbot is already at the latest version ($currentVersion)." +} else { + # Search for the Windows installer asset + $installerUrl = $null + foreach ($asset in $result.assets) { + if ($asset.name -match '^certbot-.*installer-win32\.exe$') { + $installerUrl = $asset.browser_download_url + } + } + + if ($null -eq $installerUrl) { + throw "Could not find the URL for the latest Certbot for Windows installer." + } + + "Starting Certbot auto-upgrade from $currentVersion to $latestVersion ..." + + $installerPath = "$env:TMP/certbot-installer-win32.exe" + try { + # Download the installer + "Downloading the installer ..." + $webClient = New-Object System.Net.WebClient + $webClient.DownloadFile($installerUrl, $installerPath) + + # Check installer has a valid signature from the Certbot release team + $signature = Get-AuthenticodeSignature "C:\Dev\Firefox Installer.exe" + + if ($signature.Status -ne 'Valid') { + throw "Downloaded installer has no or invalid Authenticode signature." + } + + if ($signature.SignerCertificate.Thumbprint -ne $installerAuthenticodeCertificateThumbprint) { + throw "Downloaded installer has not been signed by Certbot development team." + } + + # Install new version of Certbot + "Running the installer ..." + Start-Process -FilePath $installerPath -ArgumentList "/S /D=$InstallDir" + + "Certbot $latestVersion is installed." + } finally { + Remove-Item $installerPath -ErrorAction 'Ignore' + } +} diff --git a/windows-installer/construct.py b/windows-installer/construct.py index 089296439..63dd1f82e 100644 --- a/windows-installer/construct.py +++ b/windows-installer/construct.py @@ -84,8 +84,9 @@ def _copy_assets(build_path, repo_path): shutil.copy(os.path.join(repo_path, 'windows-installer', 'certbot.ico'), build_path) shutil.copy(os.path.join(repo_path, 'windows-installer', 'run.bat'), build_path) shutil.copy(os.path.join(repo_path, 'windows-installer', 'template.nsi'), build_path) - shutil.copy(os.path.join(repo_path, 'windows-installer', 'renew-up.ps1'), build_path) - shutil.copy(os.path.join(repo_path, 'windows-installer', 'renew-down.ps1'), build_path) + shutil.copy(os.path.join(repo_path, 'windows-installer', 'tasks-up.ps1'), build_path) + shutil.copy(os.path.join(repo_path, 'windows-installer', 'tasks-down.ps1'), build_path) + shutil.copy(os.path.join(repo_path, 'windows-installer', 'auto-update.ps1'), build_path) def _generate_pynsist_config(repo_path, build_path): @@ -143,8 +144,9 @@ bitness={python_bitness} [Include] local_wheels=wheels\\*.whl files=run.bat - renew-up.ps1 - renew-down.ps1 + tasks-up.ps1 + tasks-down.ps1 + auto-update.ps1 [Command certbot] entry_point=certbot._internal.main:main diff --git a/windows-installer/renew-down.ps1 b/windows-installer/renew-down.ps1 deleted file mode 100644 index 60dc4d9e6..000000000 --- a/windows-installer/renew-down.ps1 +++ /dev/null @@ -1,6 +0,0 @@ -$taskName = "Certbot Renew Task" - -$exists = Get-ScheduledTask | Where-Object {$_.TaskName -like $taskName} -if ($exists) { - Unregister-ScheduledTask -TaskName $taskName -Confirm:$false -} diff --git a/windows-installer/renew-up.ps1 b/windows-installer/renew-up.ps1 deleted file mode 100644 index c6a5fd9ea..000000000 --- a/windows-installer/renew-up.ps1 +++ /dev/null @@ -1,15 +0,0 @@ -function Get-ScriptDirectory { Split-Path $MyInvocation.ScriptName } -$down = Join-Path (Get-ScriptDirectory) 'renew-down.ps1' -& $down - -$taskName = "Certbot Renew Task" - -$action = New-ScheduledTaskAction -Execute 'Powershell.exe' -Argument '-NoProfile -WindowStyle Hidden -Command "certbot renew"' -$delay = New-TimeSpan -Hours 12 -$triggerAM = New-ScheduledTaskTrigger -Daily -At 12am -RandomDelay $delay -$triggerPM = New-ScheduledTaskTrigger -Daily -At 12pm -RandomDelay $delay -# NB: For now scheduled task is set up under SYSTEM account because Certbot Installer installs Certbot for all users. -# If in the future we allow the Installer to install Certbot for one specific user, the scheduled task will need to -# switch to this user, since Certbot will be available only for him. -$principal = New-ScheduledTaskPrincipal -UserId SYSTEM -LogonType ServiceAccount -RunLevel Highest -Register-ScheduledTask -Action $action -Trigger $triggerAM,$triggerPM -TaskName $taskName -Description "Execute twice a day the 'certbot renew' command, to renew managed certificates if needed." -Principal $principal diff --git a/windows-installer/tasks-down.ps1 b/windows-installer/tasks-down.ps1 new file mode 100644 index 000000000..158abeaba --- /dev/null +++ b/windows-installer/tasks-down.ps1 @@ -0,0 +1,8 @@ +$tasks = "Certbot Renew & Auto-Update Task", "Certbot Renew Task" + +foreach ($task in $tasks) { + $exists = Get-ScheduledTask | Where-Object {$_.TaskName -like $task} + if ($exists) { + Unregister-ScheduledTask -TaskName $task -Confirm:$false + } +} diff --git a/windows-installer/tasks-up.ps1 b/windows-installer/tasks-up.ps1 new file mode 100644 index 000000000..187c097e8 --- /dev/null +++ b/windows-installer/tasks-up.ps1 @@ -0,0 +1,26 @@ +Param( + [Parameter(Mandatory=$true)] + [string]$InstallDir +) + +Function Get-ScriptDirectory { Split-Path $MyInvocation.ScriptName } +$down = Join-Path (Get-ScriptDirectory) 'tasks-down.ps1' +& $down + +$taskName = "Certbot Renew & Auto-Update Task" + +$actionRenew = New-ScheduledTaskAction -Execute 'Powershell.exe' -Argument '-NoProfile -WindowStyle Hidden -Command "certbot renew"' +$actionPreUpgrade = New-ScheduledTaskAction -Execute 'Powershell.exe' -Argument "-NoProfile -WindowStyle Hidden -Command ""Copy-Item '$InstallDir\auto-update.ps1' ""`$env:TMP\auto-update.ps1""""" +$actionUpgrade = New-ScheduledTaskAction -Execute 'Powershell.exe' -Argument "-NoProfile -WindowStyle Hidden -File ""`$env:TMP\auto-update.ps1"" -InstallDir '$InstallDir'" +$actionPostUpgrade = New-ScheduledTaskAction -Execute 'Powershell.exe' -Argument '-NoProfile -WindowStyle Hidden -Command "Remove-Item "$env:TMP\auto-update.ps1" -ErrorAction "Ignore""' + +$delay = New-TimeSpan -Hours 12 +$triggerAM = New-ScheduledTaskTrigger -Daily -At 12am -RandomDelay $delay +$triggerPM = New-ScheduledTaskTrigger -Daily -At 12pm -RandomDelay $delay +# NB: For now scheduled task is set up under Administrators account because Certbot Installer installs Certbot for all users. +# If in the future we allow the Installer to install Certbot for one specific user, the scheduled task will need to +# switch to this user, since Certbot will be available only for him. +$adminSID = New-Object System.Security.Principal.SecurityIdentifier("S-1-5-32-544") +$adminGroupID = $adminSID.Translate([System.Security.Principal.NTAccount]).Value +$principal = New-ScheduledTaskPrincipal -GroupId $adminGroupID -RunLevel Highest +Register-ScheduledTask -Action $actionRenew,$actionPreUpgrade,$actionUpgrade,$actionPostUpgrade -Trigger $triggerAM,$triggerPM -TaskName $taskName -Description "Execute twice a day the 'certbot renew' command, to renew managed certificates if needed." -Principal $principal diff --git a/windows-installer/template.nsi b/windows-installer/template.nsi index 50a03865f..fa7c3a335 100644 --- a/windows-installer/template.nsi +++ b/windows-installer/template.nsi @@ -165,9 +165,9 @@ Section "!${PRODUCT_NAME}" sec_app "NoRepair" 1 ; CERTBOT CUSTOM BEGIN - ; Execute ps script to create the certbot renew task - DetailPrint "Setting up certbot renew scheduled task" - nsExec::ExecToStack 'powershell -inputformat none -ExecutionPolicy RemoteSigned -File "$INSTDIR\renew-up.ps1"' + ; Execute ps script to create the certbot renew & auto-update task + DetailPrint "Setting up certbot renew & auto-update scheduled task" + nsExec::ExecToStack 'powershell -inputformat none -ExecutionPolicy RemoteSigned -File "$INSTDIR\tasks-up.ps1" -InstallDir "$INSTDIR"' ; CERTBOT CUSTOM END ; Check if we need to reboot @@ -180,8 +180,8 @@ SectionEnd Section "Uninstall" ; CERTBOT CUSTOM BEGIN - ; Execute ps script to remove the certbot renew task - nsExec::ExecToStack 'powershell -inputformat none -ExecutionPolicy RemoteSigned -File "$INSTDIR\renew-down.ps1"' + ; Execute ps script to remove the certbot renew & auto-update task + nsExec::ExecToStack 'powershell -inputformat none -ExecutionPolicy RemoteSigned -File "$INSTDIR\tasks-down.ps1"' ; CERTBOT CUSTOM END SetRegView [[ib.py_bitness]]