[Feature] Add in-app auto-update for GitHub Release builds#520
Open
NAME0x0 wants to merge 10 commits intounchihugo:masterfrom
Open
[Feature] Add in-app auto-update for GitHub Release builds#520NAME0x0 wants to merge 10 commits intounchihugo:masterfrom
NAME0x0 wants to merge 10 commits intounchihugo:masterfrom
Conversation
…ut leaving the app. Gated behind #if GITHUB_RELEASE so Microsoft Store builds are unaffected. - Add AutoUpdater class for downloading, verifying, and installing .msixbundle updates with HTTPS-only, file size validation, path traversal prevention, and Authenticode signature verification against CN=unchihugo - Add GetGitHubReleaseAssetAsync to UpdateChecker for fetching the latest release asset from the GitHub API - Add download progress UI and install button to HomePage - Add AutoUpdateEnabled toggle to SystemPage (default: on) - Background-download update on startup when available and enabled - Save settings before ForceApplicationShutdown installation - Clean up temp files on app exit - Add localization keys for auto-update UI strings
The release assets are ZIP archives containing the .msixbundle inside a SystemFiles/ subdirectory, not bare .msixbundle files. Also fixes signature verification to use certificate thumbprint instead of subject CN, which is stronger for self-signed certs. - Download .zip asset and extract .msixbundle via ZipArchive - Verify certificate thumbprint (SHA-1 hash) instead of subject CN, since anyone can create a self-signed cert with the same CN - Fix indentation and normalize line endings in UpdateChecker.cs
…icate before update The GitHub Release assets are ZIPs (not bare .msixbundle files), so downloads are now extracted via ZipArchive to get the .msixbundle and .cer. Signature verification uses the publisher CN instead of thumbprint since the signing certificate is regenerated each release with a new thumbprint but the same CN. The .cer is installed to TrustedPeople via elevated certutil before Add-AppxPackage, with a UAC prompt for user consent.
…and actionable errors Addresses PR review blocking issues: Trust model (6 layers, each independent): 1. Source pinning — download URL must match the pinned GitHub repo prefix 2. Authenticode — rejects HashMismatch/NotSigned statuses 3. Publisher identity — signer CN must match expected value 4. Cert cross-verification — .cer thumbprint must match bundle signer thumbprint before installation (breaks circular trust from ZIP) 5. UAC prompt — user must approve certificate installation 6. OS enforcement — Windows rejects publisher mismatches for MSIX updates
Owner
|
Hi @NAME0x0, before I review the code, have you used AI to assist you with coding? |
Author
|
The final pass and review was done by AI to help find gaps in the implementation @unchihugo |
Author
|
Could you please let me know if you find any issue or anything I overlooked @unchihugo . I will get back to fixing it ASAP. |
certutil -addstore failed with E_INVALIDARG when the .cer path contained spaces (e.g. "GitHub Release.cer") due to PowerShell Start-Process splitting comma-separated -ArgumentList values without quoting. Replaced the PowerShell wrapper with direct certutil invocation using UseShellExecute + Verb=runas for UAC. Also catches Win32Exception 1223 (ERROR_CANCELLED) when the user declines the UAC prompt. Found during E2E testing of v2.9.1 -> v2.9.2 update.
Author
|
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
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
GitHub Release users can download and install MSIX updates directly from the app without leaving it. Downloads the release ZIP from GitHub, extracts the
.msixbundleand.cer, verifies the package through a 6-layer trust chain, installs the certificate (with UAC prompt), and runsAdd-AppxPackage. All auto-update code is gated behind#if GITHUB_RELEASEso Microsoft Store builds are completely unaffected.
Motivation
Sideloaded GitHub Release users currently have to manually check for updates, download the ZIP, and run the installer. This adds in-app auto-update so they can update without leaving the app while preserving their settings.
Type of Change
What Changed
AutoUpdater.cs— core download, extract, 6-layer verification, and install logicGetGitHubReleaseAssetAsync()toUpdateChecker.cswith URL origin pinningMainWindow.xaml.csHomePage.xamlSystemPage.xamlDictionary-en-US.xamlUpdateState.cs— runtime update state properties (IsDownloading,DownloadProgress,IsInstalling,UpdateError,DownloadedBundlePath)AutoUpdateEnabledsetting inUserSettings.cs(default: true)Additional Information
How it works
AutoUpdateEnabledis on, the ZIP is downloaded in the background with progress reportingAdd-AppxPackage -ForceApplicationShutdownhandles the rest%APPDATA%\FluentFlyout\settings.xmlare saved before installation and survive the MSIX update automaticallyTrust model (defense in depth)
Each layer is independent — compromising one does not bypass the others:
https://github.com/unchihugo/FluentFlyout/releases/download/HashMismatchandNotSignedCN=49793F74-1457-4B66-A672-4ED3A640FC76.certhumbprint must match the.msixbundle's embedded signer thumbprintAdd-AppxPackagerejects publisher mismatches for updatesWhy CN-based (not thumbprint/public key pinning)?
The signing certificate is fully regenerated each release — different key pair, different thumbprint, same CN. Thumbprint and public key pinning are impossible under this scheme. The cert cross-verification (layer 4) compensates: an attacker who creates a cert with the same CN cannot get it installed because its thumbprint won't match the bundle's embedded Authenticode signer.
Failure handling
Every failure path sets an actionable user-facing error message and leaves the app fully functional. The user can always retry by clicking the update button again.
E2E verification
Tested against real release artifacts:
Add-AppxPackagesucceeded, app updated)Checklist