Discreet Log #15: Cwtch Comes to MacOS

03 Sep 2021

Welcome to Discreet Log! A fortnightly technical development blog to provide an in-depth look into the research, projects and tools that we work on at Open Privacy. For our fifteenth post Dan Ballard talks about the work it took to port Cwtch to MacOS and the work still to do

Open Privacy just released Cwtch Beta 1.2 and one of the biggest new features was an full new MacOS port.

Cwtch on MacOS

The first step was to get access to MacOS. It may not be that surprising that as a team of Open Source enthusiasts and freedom liking folk, the Open Privacy staff had no Macs between all of us. So step 1 ended up being signing up for an online MacOS VPS, which unlike Linux, and even to a less extent Windows, are very uncommon, niche, and as we found out, still a little buggy. However, as imperfect as the MacOS VPS space is, it did enable us to rapidly and, in the short term, cheaply execute this port.

libCwtch

As a precursor to porting the Cwtch Flutter UI, we had to first port our Cwtch library libCwtch-go, all written in Go, to compile on MacOS as a shared library. This turned out to be very straight forward as all the tooling supported it and was just a matter of adding a new build target in the Makefile of libcwtch-go:

macos: libCwtch.dylib 

libCwtch.dylib: lib.go 
	./switch-ffi.sh
	go build -buildmode c-shared -o libCwtch.dylib

UI

Building Cwtch on MacOS

For the UI we had to install XCode (App store) and Flutter which was mostly straight forward. Then

flutter config --enable-macos-desktop

However, doing a flutter build macos took a bit more work. flutter doctor revealed an error of: “install cocaopods with sudo gem install cocoapods” which was needed as a further prerequisite to building. I attempted that only to have it fail on an FFI module complaining of missing Ruby headers. As far as could be determined, the latest version of cocaopods in gem (1.10.x) doesn’t work on MacOS BigSur (as far as I know, the latest version of MacOS) which was a little surprising. Google confirmed I was not the only one seeing this, but suggested forcing a version of 1.9.x which did still work on BigSur. This successfully installed a version of cocaopods which also worked with Flutter (I had tried 1.8 before and that was too old for Flutter).

gem install cocaopods -v 1.9.3

With that installed flutter build macos was happy to run once we used cocaopods to generate some podfiles in the macos directory.

Making Cwtch Run on MacOS

Once compiled, Cwtch failed to run having a series of predictable startup errors around loading libCwtch.dylib and finding tor.

One of the first changes we made was disabling Mac Sandbox mode. There were a few reasons to disable the sandbox. The first was this was an experimental version MacOS port prototype, we didn’t need everything in the first effort. More deeply, as demonstrated in the Windows porting and packaging work modern sandboxes make it neigh impossible to exec sub-processes, in our case a requirement for setting up and running a custom configured tor instance. One day this requirement might go away, but until then we will likely be faces with tradeoffs the operating systems’ security model and our own.

It was pretty straight forward to expand lib/cwtch/ffi.dart to load the MacOS libCwtch.dylib.

The next step to running Cwtch on MacOS was getting tor to bundle with it and run. Unlike Linux and Android for which we build our own using tools from Briar (tor reproducer) or Windows where Tor Project ship a stand alone binary, we had less options for MacOS. Taking a lead from OnionShare and their build tools (get-tor-osx.py) we downloaded the Tor Browser and extracted the version of tor bundled with it.

With this all in place, we could get Cwtch to run on MacOS!

Packaging for MacOS

As previously mentioned we had disabled sandbox mode so this ruled out, at least for now, packaging for the Apple App Store, which is what the Flutter build tools and instructions are all geared towards. Not knowing what was the common standard for MacOS I asked my twitter and it was suggested I package the app as a .dmg. For those not in the know, as I was a week ago, a .dmg is a Mac disk image, which a little additional scripting for Finder, the Mac file browser. In conventional use, it has the App in one folder, and the scripting off-centres the folder with just the app name with a zoomed in icon, and places down a link to the Applications folder and the user just has to drag the app folder (an App Bundle another Mac standard) into Applications and the app is ‘installed’. Fancier Finder scripts in these images also script in a background image with an arrow from the App folder to Applications to make the intention crystal clear.

After some further doc and guide reading it seemed the quickest and best way to build a .dmg for Cwtch was using create-dmg. I installed it via brew and then wrote a simple script to create our first .dmg.

macos/package-release.sh

#!/bin/sh
# Run from SRCROOT

cp libCwtch.dylib build/macos/Build/Products/Release/Cwtch.app/Contents/Frameworks/
cp -r /Applications/Tor\ Browser.app/Contents/MacOS/Tor build/macos/Build/Products/Release/Cwtch.app/Contents/MacOS/

rm Cwtch.dmg
rm -r macos_dmg
mkdir macos_dmg
cp -r "build/macos/Build/Products/Release/Cwtch.app" macos_dmg/

create-dmg \
	--volname "Cwtch" \
	--volicon "macos/cwtch.icns" \
	--window-pos 200 120 \
	--window-size 800 400 \
	--icon-size 100 \
	--icon "Cwtch.app" 200 190 \
	--hide-extension "Cwtch.app" \
	--app-drop-link 600 185 \
	"Cwtch.dmg" \
	macos_dmg

This script extracts the app bundle from Flutter’s build directory (build/macos/Build/Products/Release/Cwtch.app) after adding libCwtch.dylib and tor, and then invokes create-dmg to build Cwtch.dmg. We also had to do a little other work around icon generation, as MacOS uses its own .icns format, and we automated this in macos/make-icns.sh.

With this all done we were able to release a MacOS build of Cwtch with our new 1.2 release, downloadable at cwtch.im!

The Future of Cwtch on MacOS

There’s still more work to be done, currently the builds are entirely manual with no automation. Tying the builds into Drone CI will be a separate project, but it means no nightly Cwtch builds for the next while. Additionally, as some users noted, we aren’t signing our builds so large warnings popup on first run. Finally, how we can enable Sandbox mode and package in a more modern Mac format is an open question that will take some time and research.

The MacOS port seems to have been a popular addition with new community members and Cwtch users showing up using it, and a few people already volunteering to help with parts of maintaining it moving forward. As always, and as outlined above however, there is still plenty of work to be done on just this port alone, so if you like our work and want to see it continue and even potentially speed up, please consider donating, every little bit helps!

What is Discreet Log?

Discreet Log is a fortnightly technical development blog to give a more in-depth look at the research, projects and tools that we work on at Open Privacy.

More Discreet Log

Donate to Open Privacy



Open Privacy is an incorporated non-profit society in British Columbia, Canada. Donations are not tax deductible. You can Donate Once via Bitcoin, Monero, Zcash, and Paypal, or you can Donate Monthly via Patreon or Paypal. Please contact us to arrange a donation by other methods.