A couple of months ago I started playing with Matrix, a federated communication/chat system. Rather than make an account on a public homeserver I installed Synapse on my own server. I installed the Riot app on my iPhone and connected directly to my server. (Synapse is the server and Riot is the client produced by the Matrix team.)
Everything worked well. A bit too well: I was getting push notifications in iOS when I received new messages. Push notifications are very handy but it was confusing. I knew that new messages were arriving at my self-hosted homeserver but there is no way that my server would be allowed to fire notifications into Apple’s push notification service.
It’s a big problem for any kind of federated network such as Matrix, GNU social or XMPP. The entire point is that you can have an account on any server while still participating in the network. If you want to support an iOS client it can’t get realtime notifications directly from the chosen server. Push notifications can only be sent from servers run by the app developer.
You can solve this by playing pass-the-parcel: your homeserver generates an event and sends it to the app developer’s server, who passes it on to Apple, who commands your iPhone to vibrate. This solves the problem nicely apart from some privacy issues which I’ll get to shortly.
But this creates a new problem. Imagine you want to write your own Matrix app for iOS, a free and open source one that you write in your free time. Your users will insist on having push notifications because it’s the 21st century. This requires you to run a push notification server. Even if you’re willing to do this it costs real money on an ongoing basis and it may be the only significant cost you have. You can’t just make it an in-app purchase because the App Store Review Guidelines explicitly forbid taking payments to enable Push Notifications.
If you want to recoup your costs you either have to charge for your app, which will reduce the take-up of the network you presumably want to support, or take a punt and hope nice users give you donations. (This doesn’t often work.)
What we really need is some benevolent company who will release a free iOS app and subsidise the cost of notifications for everybody while focusing on making money some other way. It sounds crazy but that seems to be exactly what Riot is doing.
The above diagram is straight from the Matrix specification. They’ve built mitigation for the push notification problem right into the design.
I have Riot installed on my iPhone and iPad. When I log on to the Riot web interface it shows that the installed apps have registered themselves as “Notification Targets” on my server.
This means when I need to receive a notification my homeserver will make an HTTP POST to that URL with a JSON message describing the content of the notification. The Matrix/Riot servers will take over from there and forward it to Apple.
So that Apple knows where to send it the message contains a pushkey. This comes from the iOS device itself. The app registers for push notifications and obtains an APNS Device Token. MatrixKit then takes this token and uploads it to the homeserver when it creates the HTTP pusher.
So that explains how my push notifications magically work. It’s pretty awesome. The only downside is a small loss of privacy. One of the nice things about federated networks is that you can take total control of your data security. Communications are decentralised, accessible only on the peers that need them. Supporting iOS notifications chips away at that ideal situation, exposing at the very least some metadata to various third parties. I point the blame for that squarely at Apple’s iron grip.
The good news is that it’s easy to limit the amount of information transmitted in the notifications. While the public channels include text snippets when I’m mentioned, if I’m in an encrypted chat it simply says Message from <username>. Apple and Riot may know that I’m talking to a particular person at a particular time (more specifically, that they are talking to me) but not what was said. This is roughly the same privacy you have when you use Signal for iOS. Solution: turn on encryption. According to Matrix’s blog post this will be the default for private rooms in the future.
It’s an interesting situation. On one hand I’m happy to see Riot break the impasse of federated notifications. On the other hand it only solves the problem for Matrix, and relying on the benevolence of a company to keep a technical solution operating doesn’t fill me with confidence. It’s not ideal but at the end of the day it’s considerably better than what you get using Facebook messenger or Slack so at this point I’m happy with the trade-off!