Configuring Prosody for iOS and Chatsecure Push

I’m one of those people who run their own XMPP server because I like my privacy. In my case I use Prosody and by default it communicates directly with the client apps such as ‘Conversations’ or ‘Pix-Art Messenger’ on Android. Unfortunately, iOS is much less cooperative and in the name of power saving, cuts the connection to clients a few minutes after they have gone to the background. Sending messages to these clients then requires the use of Apple’s push service to wake up the client app, e.g. the Chatsecure app, so it can pull the message from the server. So how is that done in practice?

In practice, the makers of Chatsecure have put their own push server infrastructure in place. When an XMPP server signals that it supports push (more about that in a minute), the Chatsecure client talks to the Chatsecure push server which in turn talks to the Apple push service to gets some sort of token. The client then forwards this token to the XMPP server, i.e. Prosody. When a message arrives for a Chatsecure client that can’t be directly delivered because the TCP connection is broken, Prosody uses the XMPP server to server (s2s) protocol on TCP port 5269 to send a push message to the Chatsecure push server and identifies the device with the token it has previously received from the client. The Chatsecure push server then contacts the Apple push service which in turn contacts the client device and the Chatsecure App.

It sounds complicated and even worse, the approach totally breaks federation because it puts two centralized push services in place. Not nice at all but if you want to support iOS devices there is no other possibility.  So now’s the question how to configure this in practice as by default, the Prosody XMPP server does not use anti-federated push. There isn’t a lot of information out there but I found out that adding the following lines in my prosody.config file makes XEP-0357 compatible push come alive:

modules_enabled = {

[...]

 -- For iOS push notification...
 "cloud_notify"; -- Support for XEP-0357 Push Notifications
 "mam";
}


-- For iOS push notification...
-- mod_cloud_notify settings
push_notification_with_body = false;
push_notification_with_sender = true;

You might have noticed that I’ve set ‘notification with body‘ to false as at least the content of a message should go to the device directly, even if it is encrypted.

And for group messaging the following modules need to be enabled below the group messaging configuration:

---Set up a MUC (multi-user chat) room server 
Component "conference.xxxxxx.net" "muc"

modules_enabled = {
  "muc_mam";
  "muc_cloud_notify";
}

No special configuration is necessary to configure particular push servers as the token given by the client to the server when it wants the push service to be activated for it contains all necessary information.

And here’s command that filters push messaging debug messages out of the log file so you can see if things are working as they should:

tail -n 5000 -f /var/log/prosody/prosody.log | grep -E "push|notify|pubsub"

If things are working, you will see log entries such as the ones below if you’ve set the log level to ‘debug’:

[...]

c2s1abe518 debug Invoking cloud handle_notify_request() for smacks queued stanza
xxxx.net:cloud_notify debug Sending important push notification for mi@xxxx.net to pubsub.chatsecure.org (yyyy)
s2sout1e2e428 debug Sending[s2sout]: <iq to='pubsub.chatsecure.org' id='xxx...xxx' type='set' from='xxxx.net'>

s2sin1ab91c8 debug Received[s2sin]: <iq type='result' id='xxx...xxx' to='xxxx.net' from='pubsub.chatsecure.org'>
s2sin1ab91c8 debug Received[s2sin]: <iq type='result' id='0123' to='xxxx.net' from='pubsub.chatsecure.org'>
s2sin1ab91c8 debug Received[s2sin]: <iq type='result' id='xxx...xxx' to='xxxx.net' from='pubsub.chatsecure.org'>

c2s1abe518 debug Attempting to enable push notifications
c2s1abe518 info Push notifications enabled for mi@xxxx.net/chatsecure123 (pubsub.chatsecure.org<yyyy)

[...]

In the meantime I have 4 iOS devices on my server making use of this very un-federated push notification service. 3 of them work quite o.k. but I do notice that occasionally, a push notification is sent and an indication of an incoming message is shown on the device but the message itself has not been retrieved. Not o.k. but at least it only happens very rarely.

The behavior of the fourth iOS device is very strange, however, as it does not want to activate push at all. Chatsecure indicates that the server does not offer the push service extension and that’s that. I have no idea what the problem might be as the other three work with exactly the same configuration. Hints to fix this would be greatly appreciated!

Oh, and there is one more thing to be aware of: The Conversations app, if bought in the Play store, will also use push messaging if the server supports it. Not sure if there is an option in the app to disable it. The free version in the F-droid store fortunately doesn’t and also doesn’t seem to have an option to enable it. Good!