KUnifiedPush Web Push Update
Since the 24.12 KDE Gear release we are shipping the client-side push notification infrastructure for applications such as NeoChat and Tokodon. For 25.08 this is receiving a major update to catch up with the evolving underlying specifications and standards.
Push Notifications
There is an older post describing this in more detail, but as a quick recap the following are the relevant components in a push notification system:
- The end-user application (also “user agent”, “client”): This is the part of the application running on a user’s device and is the thing you generally interact with, e.g. a Mastondon or Matrix client.
- The application server: The server-side part of the application that might want to notify its client about an important event, even if is that is not currently running. E.g. a Mastodon or Matrix server.
- The push server: The server-side part of the push infrastructure. It’s what the application server sends its notification to, and it knows how to forward that to a client device.
- The push distributor: The part of the push infrastructure running on the user’s device. It’s usually a background service with a continuous network connection to the push server and when receiving a notification it launches the corresponding application.
UnifiedPush specifies the interfaces between the application and the push infrastructure parts, and that’s what KDE’s push notification implementation is built upon.
The UnifiedPush specification has evolved since we started this, mainly to achieve compatibility with the Web Push standard (RFC 8030). That’s good as it gives us Web Push’s security features and allows us to use existing Web Push infrastructure. It also simplifies application development as there’s one less standard to worry about.
What this means for our implementation and for applications using our client library is listed below.
KUnifiedPush changes
New UnifedPush D-Bus specification
The new D-Bus interface specified by UnifiedPush mainly aims at making future changes easier in a backward compatible way but doesn’t change things conceptually. This allows us to make this fully transparent to applications, as this only affects the communication between the KUnifiedPush client library and the distributor.
Even better, both the client library and our distributor support both versions of the D-Bus interface, so old clients not using our client library will work with the latest version of our distributor, and so will applications using the latest version of KUnifiedPush when facing an old distributor.
Message encryption
An important addition is a standardized way for doing message encryption (RFC 8291), avoiding that applications had to come up with their own way of doing this, or worse, not using message encryption at all.
The KUnifiedPush client library supports this by generating, persisting and providing the necessary keys as well as by taking care of decrypting incoming messages accordingly.
There’s an example use here.
Implementing message encryption also exposed a small compatibility issue with the ntfy push server in some configurations, a fix for this is awaiting review upstream.
Voluntary Application Server Identification (VAPID) support
VAPID (RFC 8292) provides a mechanism to ensure that only the application server itself is sending push notifications to a client, not somebody else who happens to know the push endpoint.
Most of this happens between the application server and the push server, on the client we only have to do one thing: Pass the VAPID public key from the application server to the distributor.
In KUnifiedPush that’s done with a call to Connector::setVapidPublicKey
, before calling
Connector::registerClient
. As the latter constraint can be somewhat cumbersome to ensure
when the VAPID key first has to be retrieved from the application server, there’s an additional
convenience method, Connector::setVapidPublicKeyRequired
. If VAPID is set to required registering
for push notification is internally delayed until the key is provided, making integration into
existing code usually pretty straightforward.
You’ll find an example use here.
Message urgency
Another feature brought by Web Push is message urgency (RFC 8030 §5.3). The idea here is that a device can reduce the amount of received messages based on their urgency when energy or network resources are limited. So you’d get fewer wakeups when on mobile network with a low battery than when on Wi-Fi and connected to a charger.
This has no impact on the client side. On the distributor side we determine the current urgency threshold and communicate to the push servers in their respective protocols.
For now this is a rather theoretical exercise though, as we yet have to implement device sleeping/wakeup while waiting for push notifications to really make a difference regarding power consumption. Something to discuss at the upcoming Plasma (Mobile) Sprint in Graz.
Mozilla Autopush
Thanks to the alignment with Web Push we can now use Mozilla’s Autopush push server as a backend, both their instance as well as a self-hosted one.
Note though that at least Mozilla’s own instance requires applications to use VAPID, which for example isn’t implemented in Tokodon yet. Additional compatibility considerations are listed here.
Self test
The system settings configuration module for push notifications now has a self-test action, which will send itself a push notification and verify that this was received correctly and sufficiently quickly again.
This isn’t strictly related to the protocol changes, but improved diagnostics help a lot with managing the increased complexity.
Development tooling
Besides the self-test for end user setups we also have a new command line tool for submitting
push notifications for testing during development. Previously this could be done easily with
sending a HTTP POST with curl
, but with message encryption and VAPID signatures this isn’t
really feasible anymore.
For convenience the demo push notification client included in the KUnifiedPush repository now also outputs the corresponding command to send it a notification (which is rather lengthy due to passing all the necessary keys).
Outlook
With all this we should be up-to-date with all the relevant specification changes again, and while at it there also has been a bunch of improvements and robustness fixes in general. The next step is adapting applications to make use of all this.