-
Notifications
You must be signed in to change notification settings - Fork 148
/
applications.md
340 lines (250 loc) · 12.9 KB
/
applications.md
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
# Notes for application developers
This document aims to illustrate some of the quirks, peculiarities and other
notable aspects of Sygnal for developers of applications that need to receive
push.
Sygnal has been somewhat flavoured by the development of the Element iOS
and Element Android clients, but nevertheless is intended to be useful for
other iOS and Android applications that have 'typical' requirements, without
need to resort to customising the application types (Pushkins).
(It is possible to extend Sygnal with other application types, but this is
out of scope for this document.)
Once you have read this document, you may also find [the troubleshooting document](./troubleshooting.md)
useful if you are running into trouble whilst deploying Sygnal.
## Definitions
* **APNs**: Apple Push Notification service, a notification service for iOS
applications.
* **FCM**: Firebase Cloud Messaging (previously Google Cloud Messaging), a
notification service primarily for Android applications but also usable for
iOS and Chrome applications.
* **push key**: Also known as registration token (FCM) or device token (APNs),
this ID identifies a device to which notifications can be sent.
* **Pushkin**: A module which adds support to Sygnal for an application type.
Sygnal comes with an APNs pushkin and an FCM pushkin out of the box, but you
may also use custom ones.
## Outlines of flows
An understanding of the flows of push notifications may be useful.
This section will provide an outline.
### Registration flow
0) The client needs to be configured with the address of its Sygnal instance,
and any configuration that FCM or APNs requires for client apps.
1) The client needs to use an FCM or APNs library to acquire a push key, which
identifies the client to the notification service.
2) The client registers a pusher on the user's homeserver, giving the address of
its Sygnal instance, its push key, and perhaps some other parameters.
To register a pusher, it uses [POST /_matrix/client/r0/pushers/set](https://matrix.org/docs/spec/client_server/latest#post-matrix-client-r0-pushers-set).
#### Worth noting
* In general, there is no contract between the operators of the homeserver(s)
and the operators of the Sygnal push gateways.
- Sygnal (push gateway) instances are deployed by the owner of the application.
- Unless the application restricts it, the user is usually free to choose any
homeserver which may be operated by anyone.
* It is not feasible to allow end-users to configure their own Sygnal instance,
because the Sygnal instance needs the appropriate FCM or APNs secrets that
belong to the application.
### Notification flow
1) The user's homeserver receives an event (from federation, another local user,
or even an application service — the source is unimportant).
2) The user's homeserver applies push rules to the event on behalf of the user,
in order to determine whether to send a push notification or not (as well as
a few other tweaks).
- For example, the push rules can decide to exclude certain rooms, or to
notify for mentions on keywords (so the user could, for example, be notified
when anyone mentions 'lunch').
3) If the homeserver decides to send a notification, we continue.
4) The homeserver calls [POST /_matrix/push/v1/notify](https://matrix.org/docs/spec/push_gateway/latest#post-matrix-push-v1-notify)
on the Sygnal instance that the user's client registered.
5) The Sygnal receives this request and rewrites it into a request for the
appropriate notification service (APNs or FCM), which it then sends.
6) Sygnal responds to the homeserver about the push's success and whether or not
the push key was rejected.
#### Worth noting
* When Sygnal only sends data messages (also known as 'silent notifications') to
target devices — the application needs to wake up and trigger its own
notification, perhaps after downloading and decrypting the event.
- Data-only messages are always sent to FCM.
- Data-only messages are sent to APNs when the `event_id_only` format is in
use. In other cases, the app may still need to perform additional processing,
for example if encrypted events would need to be decrypted.
* When encrypted events are present, the homeserver is unable to conclusively
run push rules — in this case, the client will need to run them locally to
decide whether or not a notification should be displayed, a sound needs to be
played and/or the message needs to be highlighted.
* **Consider user privacy**: if you use the `event_id_only` format, then data
sent to the notification service (FCM or APNs) is minimal. If you do not, then
unencrypted messages will have their content sent to the notification service,
which some may prefer to avoid.
## Platform-specific notes
### Apple Push Notification service
By default, the client will receive a message with this structure:
```json
{
"room_id": "!slw48wfj34rtnrf:example.com",
"event_id": "$qTOWWTEL48yPm3uT-gdNhFcoHxfKbZuqRVnnWWSkGBs",
"aps": {
"alert": {
"loc-key": "MSG_FROM_USER_IN_ROOM_WITH_CONTENT",
"loc-args": [
"Major Tom",
"Mission Control",
"I'm floating in a most peculiar way."
]
},
"badge": 3
}
}
```
Please note that fields may be truncated if they are large, so that they fit
within APNs' limit.
Please also note that some fields will be unavailable if you registered a pusher
with `event_id_only` format.
#### iOS applications beware!
When registering your iOS pusher, you have the ability to specify a default
payload that will be sent to APNs. This allows you to set custom flags for APNs.
Of particular interest are `content-available` and `mutable-content` (which you
can set to `1` to enable).
Consult [APNs documentation] for a more in-depth explanation, but:
* `content-available` wakes up your application for up to 30 seconds in which it
can process the message.
* `mutable-content` allows your application to mutate (modify) the notification.
An example `data` dictionary to specify on `POST /_matrix/client/r0/pushers/set`:
```json
{
"url": "https://push-gateway.location.here/_matrix/push/v1/notify",
"format": "event_id_only",
"default_payload": {
"aps": {
"mutable-content": 1,
"content-available": 1,
"alert": {"loc-key": "SINGLE_UNREAD", "loc-args": []}
}
}
}
```
[APNs documentation]: https://developer.apple.com/library/archive/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/CreatingtheNotificationPayload.html
#### VoIP (voice calls and video calls) notifications on iOS
iOS is capable of displaying an on-screen call notification (with answer/deny buttons)
and playing a ringtone.
However, this requires sending a special kind of push notification.
Sygnal is not able to send this type of push notification because a VoIP call may
begin as a result of an encrypted message, so Sygnal has no way to know that a given
message should initiate a VoIP call.
##### Recent iOS (≥ 14.5) versions
As of iOS 14.5, your iOS application can register a Notification Service Extension that,
upon receiving a relevant VoIP notification, calls [`reportNewIncomingVoIPPushPayload`][iOSReportVoIP]
to trigger a VoIP notification display on the device.
[iOSReportVoIP]: https://developer.apple.com/documentation/callkit/cxprovider/3727263-reportnewincomingvoippushpayload
##### Old iOS (< 14.5) versions
For old iOS versions, a workaround is for your iOS application to register a Notification Service Extension
that, upon receiving a relevant VoIP notification, makes an HTTP request to Sygnal's
[`/_matrix/push/v1/notify`](https://spec.matrix.org/latest/push-gateway-api/#post_matrixpushv1notify)
endpoint in order to trigger the correct type of notification.
(There was no interface to do this on-device.)
The Notification Service Extension of *Element iOS*, [available here][ElementNSE],
may be useful for reference.
[ElementNSE]: https://github.com/vector-im/element-ios/blob/034e253fb19092ef16b5262293d5c32db96aec22/RiotNSE/NotificationService.swift
### Firebase Cloud Messaging
The client will receive a message with an FCM `data` payload with this structure:
```json
{
"event_id": "$3957tyerfgewrf384",
"type": "m.room.message",
"sender": "@exampleuser:example.org",
"room_name": "Mission Control",
"room_alias": "#exampleroom:example.org",
"sender_display_name": "Major Tom",
"content": {
"msgtype": "m.text",
"body": "I'm floating in a most peculiar way."
},
"room_id": "!slw48wfj34rtnrf:example.org",
"prio": "high",
"unread": 2,
"missed_calls": 1
}
```
Please note that fields may be truncated if they are large, so that they fit
within FCM's limit.
Please also note that some fields will be unavailable if you registered a pusher
with `event_id_only` format.
### WebPush
#### Setup & configuration
In the sygnal virtualenv, generate the server key pair by running
`vapid --gen --applicationServerKey`. This will generate a `private_key.pem`
(which you'll refer to in the config file with `vapid_private_key`)
and `public_key.pem` file, and also string labeled `Application Server Key`.
You'll copy the Application Server Key to your web application to subscribe
to the push manager:
```js
serviceWorkerRegistration.pushManager.subscribe({
userVisibleOnly: true,
applicationServerKey: "...",
});
```
You also need to set an e-mail address in `vapid_contact_email` in the config file,
where the push gateway operator can reach you in case they need to notify you
about your usage of their API.
Since for webpush, the push gateway endpoint is variable and comes from the browser
through the push data, you may not want to have your sygnal instance connect to any
random addressable server. For this, you can set the `allowed_endpoints` option to
a list of allowed endpoints. Globs are supported. For example, to allow Firefox,
Chrome and Opera (Google) and Edge as a push gateway, you can use this:
```yaml
allowed_endpoints:
- "updates.push.services.mozilla.com"
- "fcm.googleapis.com"
- "*.notify.windows.com"
```
A default time-to-live of 15 minutes is set for webpush, but you can adjust this by setting the `ttl: <number of seconds>` configuration option for the pusher. If notifications can't be delivered by the push gateway aftet this time, they are dropped.
#### Push key and expected push data
In your web application, [the push manager subscribe method](https://developer.mozilla.org/en-US/docs/Web/API/PushManager/subscribe)
will return
[a subscription](https://developer.mozilla.org/en-US/docs/Web/API/PushSubscription)
with an `endpoint` and `keys` property, the latter containing a `p256dh` and `auth`
property. The `p256dh` key is used as the push key, and the push data must contain
`endpoint` and `auth`. You can also set `default_payload` in the push data;
any properties set in it will be present in the push messages you receive,
so it can be used to pass identifiers specific to your client
(like which account the notification is for).
##### events_only
As of the time of writing, all webpush-supporting browsers require you to set
`userVisibleOnly: true` when calling (`pushManager.subscribe`)
[https://developer.mozilla.org/en-US/docs/Web/API/PushManager/subscribe], to
(prevent abusing webpush to track users)[https://goo.gl/yqv4Q4] without their
knowledge. With this (mandatory) flag, the browser will show a "site has been
updated in the background" notification if no notifications are visible after
your service worker processes a `push` event. This can easily happen when sygnal
sends a push message to clear the unread count, which is not specific
to an event. With `events_only: true` in the pusher data, sygnal won't forward
any push message without a event id. This prevents your service worker being
forced to show a notification to push messages that clear the unread count.
##### only_last_per_room
You can opt in to only receive the last notification per room by setting
`only_last_per_room: true` in the push data. Note that if the first notification
can be delivered before the second one is sent, you will still get both;
it only has an effect when notifications are queued up on the gateway.
##### Multiple pushers on one origin
Also note that because you can only have one push subscription per service worker,
and hence per origin, you might create pushers for different accounts with the same
p256dh push key. To prevent the server from removing other pushers with the same
push key for your other users, you should set `append` to `true` when uploading
your pusher.
#### Notification format
The notification as received by your web application will contain the following keys
(assuming non-null values were sent by the homeserver). These are the
same as specified in [the push gateway spec](https://matrix.org/docs/spec/push_gateway/r0.1.0#post-matrix-push-v1-notify),
but the sub-keys of `counts` (`unread` and `missed_calls`) are flattened into
the notification object.
```
room_id
room_name
room_alias
membership
event_id
sender
sender_display_name
user_is_target
type
content
unread
missed_calls
```