When designing new products, our mantra is “easy to deploy”. This was also the case when we had our first version of SensorFu Beacon Application for Windows ready.
When deploying Beacon Application, there are two files to consider. First you have the executable that is the same for all Beacons and then there is the config that makes the Beacon unique. We use AppVeyor to build the Beacon binaries and the configs are stored in Home. As user downloads Windows Beacon from Home, these two files need to be combined somehow. For our *nix tuned brains the answer to the this problem was obvious. Just append the Beacon config to the end of the binary. This gives you a compact program that loads config from itself and happily starts testing network segregation. We even added “ — service install/uninstall” parameters so that one can exercise CommandlineFu and install Beacon as Windows service.
But we quickly found out that this is not the perfect solution. Firstly, some antivirus software think that executable with string padded on the end is fishy. Secondly, the word on the streets was that Microsoft Installer (MSI) package is the way to go. Our hackery padded binary had served its purpose while doing the initial test runs on Windows but now the MSI way sounded pretty obvious. As said, we build our Windows Beacon releases on AppVeyor and we get plain executable without any configs. One can see the problem here. We can’t create MSI on AppVeyor as we don’t have the Beacon config and we can’t create the MSI in Home as we use Alpine Linux. You can’t create MSI on Linux systems, right? Wrong!
There’s this nifty little toolset called “msitools” that can do exactly that. Especially the “wixl” tool sounded promising as it allows one to use popular WiX MSI configuration format. We started hacking prototype of Home that gives you MSI packages. The idea was that we get the plain executable from Appveyor and use the “wixl” to slap together MSI package when user downloads the Beacon. And it worked! Build time was pretty much instant and you got yourself an unique MSI with selected Beacon config.
As we continued developing the Windows application, we realized that we should probably use the Windows EventLog for logging the Beacon output. You register your application to the EventLog and start logging. Now, WiX format doesn’t directly support this registration but there is extension that does. No problemo, we can just use that? Well no. The “wixl” tool in “msitools” doesn’t support extensions. It also doesn’t support MSI installer UI stuff either. It was time to dive in to the deep end and start looking into the MSI file format.
MSI file format isn’t very well documented but after some GoogleFu we got the basics figured. You have the MSI package and inside of it there are these cabinet (CAB) files. Beacon binary is in one CAB and config in another. MSI installer extracts these CABs to the install location. We also found out that there are Rust crates for manipulating MSI and CAB files. Could we just add our Beacon config to existing MSI package by using these libraries? It turns out that we can! After some research and refactoring we had the build system that would give us perfect MSI packages. The trick was to build MSI on AppVeyor using the real WiX toolset. This way we can use all features that the WiX format supports. To avoid the problem with AppVeyor and Beacon config, we just build the MSI package with empty config. When user downloads the Beacon, we manipulate the MSI by replacing the empty config with the real one. And voilà, we have easy to install Windows Beacon with all the features needed.