Notifications are a must-have feature for messaging apps. They play an intrinsic role because how else will users know when they have received messages.
The significance of notifications is even greater on Status Messenger given its decentralised P2P architecture (as described in our earlier article). For example, if a Status user is offline when messages are sent to that user, the current implementation stores those messages temporarily on a History node for 30 days before deleting them. So if the user does not come online in those 30 days (unlikely but plausible) and if there were no notifications sent about those incoming messages, the user has no way of receiving those messages. This is unlike typical client-server messenger architectures where servers store messages (almost) indefinitely.
While typical client-server implementations of iOS notification allow the server to link the notification sending and receiving clients, Status Messenger implements this in a privacy-friendly manner using decentralized push notification and Waku protocol.
This article dives into the implementation of notifications on the Status iOS app. We begin by contrasting local versus push notifications and describing how push notifications work on Apple devices. We explain the details of how iOS notifications are implemented in the decentralized P2P architecture of Status Messenger and then conclude by discussing security and privacy considerations of this approach.
Until now, Status iOS app users would receive no indication when messages were sent to them. If they happened to be using the app when someone sent them a message they would receive it. If not, such messages would propagate among Relay nodes for a little while, until their Time-to-Live (TTL) expires (which is currently set to 15 seconds), and then get saved temporarily in the History nodes for up to 30 days.
History nodes save messages for users while they’re offline. These nodes can not know the content or recipient of messages and only have access to the message topic. (These concepts are explained at length in our earlier article.)
If the intended recipients did not use their Status iOS app in the next 30 days, their messages (along with others) would be deleted from the History nodes and they would never receive them. This clearly would be a terrible user experience for a messaging app. The assumption is that most users would check their app for messages within a month. Even then, users would understandably want to read their messages in a timely manner.
Notifications: Local vs Push
Notifications can be triggered either locally from within the app/device or they can be "pushed" to the app remotely from associated servers, even when the app is not running. Notifications generated by the Status app itself upon receiving messages are called local notifications. Notifications sent to the Status app from specific push notification servers, separately from the messages themselves, are called push notifications.
Status implements local notifications on both Android and Desktop apps. Local notifications require the application to be always running to receive messages and subsequently trigger notifications. While this is easily achieved on the Desktop, Android app requires a continuously running foreground service specifically to receive messages even when the app is in the background so that it can trigger corresponding notifications.
Status implements push notifications on its iOS app. This is because iOS only allows certain kinds of applications, e.g. VOIP, to keep a connection open when in the background. iOS apps can request execution time when they are in the background but it has a limited set of use cases and generally not responsive enough to implement a push notification system. Furthermore, unlike Android, iOS does not provide a foreground service capability to let us implement local notifications. This effectively forces us to implement push notifications.
Push Notifications on iOS
Apple Push Notification service (APNs) is the technology that enables remote notifications on iOS and macOS devices. APN service sits between the app provider and the user’s devices.
When the user initially launches the app, an encrypted and persistent connection is established between the app and APNs which enables it to receive notifications. The app provider on the other end configures a persistent secure channel from app servers to APNs using Apple-supplied cryptographic certificates.
The app provider sends notification requests to APNs which in turn forwards them to targeted devices. On receipt of a notification, the device forwards it to the appropriate app and manages interactions with the user. These notifications have special privileges which allow them to be received and displayed even when the app is not running or is in the background. Even if the device is powered off, APNs buffers any notifications and resends them later.
All iOS apps that require notifications use APNs.
Status iOS Notifications
Status uses APNs for notifications on iOS. The implementation includes two other important components: Status Push Notification (SPN) servers and Gorush servers. SPN servers are used to manage client registrations/queries for notifications while Gorush is used for the actual delivery of notifications.
Gorush is an open-source push notification microserver written in Go (Golang) using the Gin framework. The rest of this section describes client registration and notification aspects of SPN service. The detailed flows, message formats and protocol details are available in the specification.
A client may register with one or more SPN servers of their choice. A Push Notification Registration (PNR) message is sent on the partitioned topic for the public key of the SPN server.
The PNR message contains information such as the APNs issued device_token, installation_id of the device and access_token that will be required by other clients to send push notifications. It may include allowed_key_list which is a list of access_tokens encrypted with the AES key generated by Diffie-Hellman between the client and specific contacts who are allowed to send notifications. It may also include a blocked_chat_list which is a list of SHA2-256 hashes of chat IDs which will not trigger a notification. It also allows the client to specify if it wants to be notified on mentions with a specific allowed_mentions_chat_list which is a list of SHA2-256 hashes of chat IDs where it wants to receive mentions.
SPN server does the required checks on this message and responds back with success/failure. A client may register with multiple SPN servers to increase availability.
Each user registered with one or more SPN servers will advertise about it periodically. If no filtering is done based on public keys, the access_token will be included in this advertisement. This will be advertised on the contact-code topic by coupling with the normal contact-code advertisement. This allows others to discover push notification details for the user.
A client that wants to send push notifications would need to have the required access_token from the advertisements of corresponding users or from querying a SPN server. This is used to construct a push notification message that is sent to the SPN server.
SPN server validates the access_token and then forwards the notification request to the Gorush server which delivers the actual notification message.
Status Messenger enables sending of notifications by default but the user is expected to opt-in to receiving notifications.
Security & Privacy Considerations
Access token: Spam is relatively easier on our open, permissionless, privacy-centric decentralized P2P messaging platform as described in our earlier article. The access_token is used to add access control to the notification flow so that the protocol can enforce policies such as receiving notifications only from specific contacts. This reduces spam notifications to a certain extent.
One can generate a random chat key, get the access_token for another user and then spam that user with notifications. Use of encrypted access_token in the allowed_key_list mitigates this situation but that implies disclosing the actual chat key (of the client, during registration) to the SPN server beforehand (see Anonymous mode below).
Use of an access_token also increases deniability because SPN server would know who requested the token but not necessarily who sent a push notification. Correlation between the two can however be trivial in some cases.
Privacy: When clients interact with the SPN service, they disclose certain information required for the notification protocol to work, which reduces their privacy to a certain extent.
When registering with a SPN server, a client discloses its chat key and the devices that will receive notifications. A client may also disclose the hash of the chat IDs it is interested in (allowed_mentions_chat_list) and the hash of the chat IDs it wants to filter out (blocked_chat_list).
When querying a SPN server, a client will disclose that it is interested in sending push notifications to another client, but the querying client's chat key is not disclosed.
Anonymous mode: An anonymous mode of operations is available for increased privacy. A client in this mode can register with SPN service using a new notification key that is different from their chat key. The notification key is effectively a secret and should only be disclosed to clients that the user wants to be notified by. A client may share this key directly through contact updates and advertise the access_token on the contact-code topic of this key.
This anonymous mode effectively does not share the chat identity of the sender or the receiver with the server. However, this may result in missed push notifications because the advertisement of the notification key is left to the client without the involvement of SPN server.
Decentralization: Although Status runs the SPN servers today, push notification servers can technically be run by anyone. Gorush servers can also be run by anyone but they will need the Apple-issued certificate to be able to notify Status clients.
Conclusion: In typical client-server implementations of iOS notification, client A registers with app server S by giving its device token and is connected to APNs. When client B sends a message to client A, server S delivers the message to client A and also sends a push notification to client A through APNs.This allows server S to easily link the sending and receiving clients.
Status uses a decentralized P2P architecture for delivering messages across peers over Waku, where there are no servers which can link the message sending and receiving nodes. We achieve the same with notifications using SPN servers.
The benefits are four-fold: 1) A client can choose the SPN server to interact with and can even run one itself 2) SPN servers are architecturally decentralized and therefore can not easily link the notification sender and receiver 3) SPN servers do not have access to the messages corresponding to the notifications, which makes linking harder 4) Querying the SPN server does not disclose the identity of the sender.
This architecture lets us achieve notification capability on iOS while maintaining the highest privacy considerations.
Version 1.7 of Status app brings notification support on iOS. Status Messenger now has the much anticipated notifications across Desktop, Android and iOS apps.
In this article, we differentiated local versus push notifications and described the rationale behind implementing push notifications on our iOS app. We described the key aspects of this implementation highlighting Status Push Notification service and Gorush servers. Finally, we discussed the security and privacy considerations of this approach to justify how Status achieves privacy-friendly notifications on iOS.
So now, Status users on iOS can enjoy the notifications from their Status network and never miss a message again. Ping!
(Thanks to Andrea Piana and Jonathan Zerah for reviewing drafts of this article and providing helpful feedback. Thanks to Alex Howell for the thoughtful illustration.)
Install Status for Android and iOS here