Skip to content

nefarius/vicius

Repository files navigation

Nefarius™ vīcĭus updater agent

Build status Documentation GitHub Release Discord Mastodon Follow

Nefarius' nŏvīcĭus universal software updater agent for Windows.

About

vīcĭus is a self-contained C++20 executable acting as a software update agent for Microsoft Windows. It can be deployed alongside your product and will take care of periodically checking for newer versions online and notifying the user of pending updates. Its goal is to require the least amount of configuration to get it up and running while providing enough flexibility to be customized for various environments, if desired. It doesn't require any prerequisites being present on the target system and should be able to run on any recent Windows version.

Motivation

Dealing with software update mechanics has been a steady companion for almost 10 years by now, so it's about time to learn from all the mistakes, hardships and shortcomings the various products used have put me through all this time 😅 If you want something done right, you gotta do it yourself 💪

Features

  • No backend application server required
    All you need on the server-side to get going is a web host supporting delivering static JSON files and you're done. GitHub Pages would be a sufficient free hosting solution where you can upload to and deliver the updater configuration from. Take a look at the example server implementation if you wish to write your own backend service.
  • Self-contained
    No need to worry if .NET or other runtimes are present on the target machines, everything it needs is delivered in a single Win32 executable.
  • (Almost) zero configuration
    The bare minimum configuration can be provided by simply compiling in the server URL by adjusting the CustomizeMe.h header file. This does not mean you need to maintain one build for every product you wanna support; you will get multi-tenancy out of the box by simply naming the resulting executable after the following scheme: manufacturer_product_Updater.exe, e.g. nefarius_HidHide_Updater.exe will build the server path as https://example.org/api/nefarius/HidHide/updates.json (or however it is defined in CustomizeMe.h) automatically!
  • Sane defaults
    We hate wasting time writing configuration files as much as the next person; most configuration options are either optional or have sane default fallback values you can depend on.
  • Self-updater
    Sometimes just the updater process needs an update (e.g. security patches), not the entire product it is watching over. It can update itself if the server-provided instance version is higher than the locally running one.
  • Self-healing
    If run in autostart when the user logs on, it can make sure that scheduled tasks and other supportive components are configured and working properly.
  • Low resource consumption
    The updater process is only invoked on demand (at user logon and once per day via Task Scheduler) and doesn't keep running in the background.
  • Respects your time
    Busy fragging in a game? We won't bother you with any popup windows until you're ready.
  • Powerful template engine included
    Sometimes finding the local resource of interest to check the product version can be more challenging than just having a static, boring file path. You can use inja templates to build your own path resolving logic, all while never having to leave your JSON strings!
  • Expressive modern changelog support
    Update summaries a.k.a. changelogs don't have to be boring slabs of text; Markdown is fully supported! The included fonts are also capable of rendering Fork Awesome icons and system-provided emojis! 🎉 🥳 🍕

Prerequisites

  • Windows 7 or later (x86, x86_64, ARM64)
    • Note: currently anything below Windows 10 is untested and low priority
  • An NTFS formatted volume
  • An Internet connection
  • Your software updates need to be packaged in one of the following ways:

Documentation

Head over to the extended documentation for examples and detailed explanations.

Downloads

You can get unsigned build snapshots here. Consider these Nightly-releases.

Signed stable releases will be provided on the repository releases page. Keep in mind though that those releases are built to use my own update infrastructure so in 99% of the cases you probably don't want to use them, at least not without a configuration file!

Screenshots

nefarius_HidHide_Updater_z4YFTJStbr.png

nefarius_HidHide_Updater_GDFudys8mB.png

nefarius_HidHide_Updater_T7lQFBKqRw.png

Updater_mc9y7o4qcL.png

Updater_EMJNlbXitT.png

How to build

Set up Visual Studio 2022 or newer with the C++ Desktop Development workload.

To get binary compression to work upx has to be installed. You can do so via e.g.:

winget install upx

Multi-tenant build example

You do not have to touch the checked out sources if you wish to customize your build.

Assuming a manufacturer name Valkirie and product name HandheldCompanion, create the following folder structure and file .\include\Valkirie\HandheldCompanion\ViciusPostCustomizeMe.h and override the server url in there like so:

#undef NV_API_URL_TEMPLATE
#define NV_API_URL_TEMPLATE     "https://raw.githubusercontent.com/Valkirie/HandheldCompanion/main/Valkirie_HandheldCompanion_Updates.json"

Now you can build from the command line pointing the compiler to the directory of your header(s) like so:

msbuild .\src\vīcĭus.vcxproj /p:Configuration=Release /p:CustomIncludes="${PWD}\include\Valkirie\HandheldCompanion\" /p:UpdaterName=Valkirie_HandheldCompanion_Updater

This will produce the binary Valkirie_HandheldCompanion_Updater.exe with the server URL of your custom header file baked into it!

You're of course free to put the custom header files anywhere on your system (like your own private repository), they do not need to be put under the project root directory.

TODOs

For more details check the issue tracker.

Non-exhaustive list of things open or in-progress...

Must-haves

  • Add silent update option
    • Docs
    • Types
    • Implementation (see #15)
  • Add message box dialog if the user launches the updater with no args
    • Standard text if we are up to date
    • Inform if Betas are available

Nice-to-haves

  • Localization
  • Add Authenticode signature checks (see #7)
    • Crypto primitives
    • Model types
    • Business logic
  • Design Beta-Release support
    • WizardPage::MultipleVersionsOverview
  • Make app icon customizable
  • Add "Light" theme
  • Support closing and restarting applications before and after the main update
  • Support running prerequisites installation before main update
  • Support running the update as Administrator
  • Implement machine-wide registration Currently only the user executing the updater will run registrations, which is sufficient for most cases
  • Postpone update dialog popping up if the product is currently in use
  • Allow using a HTTP proxy address via configuration
  • Add SAL annotations

Done

Expand me!
  • Make UI DPI-aware
  • Finalize UI design
    • WizardPage::Start
    • WizardPage::SingleVersionSummary
    • WizardPage::DownloadAndInstall
  • Finalize local updater config JSON format
  • Add retry-logic (e.g. retry failed downloads etc.)
  • Add some fallback code if the temp directory isn't available
  • Handle all known error-cases
    • Server response errors
    • Release download errors
    • Setup launch errors
  • Documentation
    • About page
    • JSON Schemas
    • Specify supported Command Line Arguments
    • Exit Codes
    • Emergency Feature
    • Server Discovery
    • Logging
    • Common Errors
    • Local Configuration
    • Remote Configuration
  • Allow setting the download directory
  • Implement "postpone" choice behaviour
  • Implement Task Scheduler
    • Registration
    • Removal
  • Finalize REST API design
  • Add info dialog before self-updating UAC dialog comes up
  • Add self-updater logic
    • Tests
    • Fix issues launching from write-protected directory like Program Files
  • Implement Product Version detection
    • RegistryValue
    • FileVersion
    • FileSize
    • FileChecksum
    • CustomExpression
  • Add some logging
  • Tidy up and improve includes
    • Optimize build times
    • Use pre-compiled headers?
  • Support environment variables or custom placeholders in path strings and alike

Sources & 3rd party credits

This tool benefits from these awesome projects ❤ (appearance in no special order):

Dependencies

Literature & references

DPI-awareness