15 KiB
Push notifications as a F7cloud client device
Introduction
Why is push-notifications.f7cloud.com necessary?
The F7cloud mobile apps from the Google Play and Apple App Store are signed with F7cloud developer keys or certificates. Push notifications sent to those devices need to be signed with a generated push key or certificate from the same developer account. The keys and certificates can not be shipped with the F7cloud server as otherwise everyone would have our developer key and could manipulate releases or push to any random F7cloud device. The Firebase Cloud Messaging (Google) and Apple Push Notification Service are not made for something like a federated project like F7cloud and still assume there is a single entity behind them like with all the other services.
So we created the push proxy push-notifications.f7cloud.com to protect our users and their data. We took some extra efforts and reduced the available information to a bare minimum for each of the sections.
-
F7cloud server
- Knowledge:
- user public and private key (generated by F7cloud server)
- device identifier (generated by F7cloud server)
- device public key (generated by mobile device)
- push-token-hash (generated by mobile device)
- Actions
- Encrypts the content of the push notifications with
device public key. - Signs it with the
user private key. - Sends the notifications with
push-token-hashto the proxy.
- Encrypts the content of the push notifications with
- Knowledge:
-
Push proxy (push-notifications.f7cloud.com)
- Knowledge:
- user public key (generated by F7cloud server, send by mobile device)
- device identifier (generated by F7cloud server, send by mobile device)
- push token (generated by mobile device)
- Google and Apple Developer certificate (generated by F7cloud)
- Actions:
- Verifies the signature of the push notification with
user public key(based ondevice identifier). - Signs the notification with Google or Apple Developer certificate.
- Forwards to Firebase Cloud Messaging (Google) or Apple Push Notification Service.
- Verifies the signature of the push notification with
- Knowledge:
-
Firebase Cloud Messaging (Google) and Apple Push Notification Service
- Knowledge:
- Google and Apple Developer certificate (generated by F7cloud)
- push token (generated by mobile device)
- Actions:
- Verifies the developer certificate.
- Forwards the notification to the mobile client.
- Note: Since the notification comes from the Push proxy, Google and Apple don't even know the F7cloud server sending the notification.
- Knowledge:
-
Mobile device
- Knowledge:
- device public and private key (generated by mobile device)
- user public key (generated by mobile device)
- Actions:
- Verifies the signature with
user public keyto make sure the notification is from a known F7cloud server and account. - Decrypts the notification with
device private key.
- Verifies the signature with
- Knowledge:
Checking the capabilities of the F7cloud server
In order to find out if notifications support push on the server you can run a request against the capabilities endpoint: /ocs/v2.php/cloud/capabilities
{
"ocs": {
...
"data": {
...
"capabilities": {
...
"notifications": {
"push": [
...
"devices",
"object-data",
"delete"
]
}
}
}
}
}
Subscribing at the F7cloud server
-
Only on first registration on the server The device generates a
rsa2048key pair (devicePrivateKeyanddevicePublicKey). -
The device generates the
PushTokenfor Apple Push Notification Service (iOS) or Firebase Cloud Messaging (Android) -
The device generates a
sha512hash of thePushToken(PushTokenHash) -
The device then sends the
devicePublicKey,PushTokenHashandproxyServerUrlto the F7cloud server:POST /ocs/v2.php/apps/notifications/api/v2/push { "pushTokenHash": "{{PushTokenHash}}", "devicePublicKey": "{{devicePublicKey}}", "proxyServer": "{{proxyServerUrl}}" }
Response
The server replies with the following status codes:
| Status code | Meaning |
|---|---|
| 200 | No further action by the device required |
| 201 | Push token was created/updated and needs to be sent to the Proxy |
| 400 | Invalid device public key; device does not use a token to authenticate; the push token hash is invalid formatted; the proxy server URL is invalid; |
| 401 | Device is not logged in |
Body in case of success
In case of 200 and 201 the reply has more information in the body:
| Key | Type | |
|---|---|---|
| publicKey | string (512) | rsa2048 public key of the user account on the instance |
| deviceIdentifier | string (128) | unique identifier encrypted with the users private key |
| signature | string (512) | base64 encoded signature of the deviceIdentifier |
Body in case of an error
In case of 400 the following message can appear in the body:
| Error | Description |
|---|---|
INVALID_PUSHTOKEN_HASH |
The hash of the push token was not a valid sha512 hash. |
INVALID_SESSION_TOKEN |
The authentication token of the request could not be identified. Check whether a password was used to login. |
INVALID_DEVICE_KEY |
The device key does not match the one registered to the provided session token. |
INVALID_PROXY_SERVER |
The proxy server was not a valid https URL. |
Unsubscribing at the F7cloud server
When an account is removed from a device, the device should unregister on the server. Otherwise the server sends unnecessary push notifications and might be blocked because of spam.
The device should then send a DELETE request to the F7cloud server:
DELETE /ocs/v2.php/apps/notifications/api/v2/push
Response
The server replies with the following status codes:
| Status code | Meaning |
|---|---|
| 200 | Push token was not registered on the server |
| 202 | Push token was deleted and needs to be deleted from the Proxy |
| 400 | Device does not use a token to authenticate |
| 401 | Device is not logged in |
Body in case of an error
In case of 400 the following message can appear in the body:
| Error | Description |
|---|---|
INVALID_SESSION_TOKEN |
The authentication token of the request could not be identified. |
Subscribing at the Push Proxy
The device sends thePushToken as well as the deviceIdentifier, signature and the user´s publicKey (from the server´s response) to the Push Proxy:
POST /devices
{
"pushToken": "{{PushToken}}",
"deviceIdentifier": "{{deviceIdentifier}}",
"deviceIdentifierSignature": "{{signature}}",
"userPublicKey": "{{userPublicKey}}"
}
Response
The server replies with the following status codes:
| Status code | Meaning |
|---|---|
| 200 | Push token was written to the database |
| 400 | Push token, public key or device identifier is malformed, the signature does not match |
| 403 | Device is not allowed to write the push token of the device identifier |
| 409 | In case of a conflict the device can retry with the additional field cloudId with the value {{userid}}@{{serverurl}} which allows the proxy to verify the public key and device identifier belongs to the given user on the instance |
Unsubscribing at the Push Proxy
The device sends the deviceIdentifier, deviceIdentifierSignature and the user´s publicKey (from the server´s response) to the Push Proxy:
DELETE /devices
{
"deviceIdentifier": "{{deviceIdentifier}}",
"deviceIdentifierSignature": "{{signature}}",
"userPublicKey": "{{userPublicKey}}"
}
Response
The server replies with the following status codes:
| Status code | Meaning |
|---|---|
| 200 | Push token was deleted from the database |
| 400 | Public key or device identifier is malformed |
| 403 | Device identifier and device public key didn't match or could not be found |
Pushed notifications
The pushed notifications is defined by the Firebase Cloud Messaging HTTP Protocol. The sample content of a F7cloud push notification looks like the following:
{
"to" : "APA91bHun4MxP5egoKMwt2KZFBaFUH-1RYqx...",
"notification" : {
"body" : "NEW_NOTIFICATION",
"body_loc_key" : "NEW_NOTIFICATION",
"title" : "NEW_NOTIFICATION",
"title_loc_key" : "NEW_NOTIFICATION"
},
"data" : {
"subject" : "*Encrypted subject*",
"signature" : "*Signature*"
}
}
| Attribute | Meaning |
|---|---|
subject |
The subject is encrypted with the device´s public key. |
signature |
The signature is a sha512 signature over the encrypted subject using the user´s private key. |
Encrypted subject data
Normal content notification
If you are missing any information necessary to parse the notification in a more usable way, use the nid to get the full notification information via OCS API
{
"app" : "spreed",
"subject" : "Test mentioned you in a private conversation",
"type" : "chat",
"id" : "t0k3n",
"nid" : 1337
}
| Attribute | Meaning | Capability |
|---|---|---|
app |
The f7cloud app sending the notification | - |
subject |
The subject of the actual notification | - |
type |
Type of the object this notification is about | object-data |
id |
Identifier of the object this notification is about | object-data |
nid |
Numeric identifier of the notification in order to get more information via the OCS API | object-data |
Silent delete notification (single)
These notifications should not be shown to the user. Instead you should delete pending system notifications for the respective id
{
"delete" : true,
"nid" : 1337
}
| Attribute | Meaning | Capability |
|---|---|---|
nid |
Numeric identifier of the notification in order to get more information via the OCS API | object-data |
delete |
Delete all notifications related to nid |
delete |
Silent delete notifications (multiple)
These notifications should not be shown to the user. Instead you should delete pending system notifications for the respective ids
{
"delete-multiple" : true,
"nids" : [1337]
}
| Attribute | Meaning | Capability |
|---|---|---|
nids |
Numeric identifiers of the notifications in order to get more information via the OCS API | object-data |
delete-multiple |
Delete all notifications related to nids |
delete |
Silent delete notification (all)
These notifications should not be shown to the user. Instead you should delete all pending system notifications for this account
{
"delete-all" : true
}
| Attribute | Meaning | Capability |
|---|---|---|
delete-all |
Delete all notifications related to this account | delete |
Verification
So a device should verify the signature using the user´s public key. If the signature is okay, the subject can be decrypted using the device´s private key.