The encrypted push notification payload previously included a `pm_users`
field for group direct messages.
This commit replaces the `pm_users` field with `recipient_user_ids`.
(new name to migrate from the old "private" keyword)
It's a sorted array of all user IDs participating in a 1:1 or group DM
conversation, including both `user_id` and `sender_id`.
* Previously, `pm_users` was included only for group DMs;
`recipient_user_ids` is present for both 1:1 and group DM conversations.
* The old `pm_users` field was a string containing a comma-separated
list of sorted user IDs. `recipient_user_ids` has a more structured
array format.
Signed-off-by: Prakhar Pratyush <prakhar@zulip.com>
Earlier, while sending notification if `apns_context=None` - we logged:
"APNs: Dropping a notification because nothing configured. Set
ZULIP_SERVICES_URL (or APNS_CERT_FILE)." which is not accurate for E2EE
case.
For the non-E2EE case it is correct because configuring
ZULIP_SERVICES_URL results in transfering the responsbility to
make API call to APNs to the bouncer. Or they can configure
APNS_CERT_FILE if they want to send directly.
In E2EE case, the `send_e2ee_push_notification_apple` is part of
bouncer so configuring `ZULIP_SERVICES_URL` doesn't help. One needs
to configure either `APNS_TOKEN_KEY_FILE` or `APNS_CERT_FILE`.
Message to log is updated accordingly + severity increased from
DEBUG to ERROR.
Signed-off-by: Prakhar Pratyush <prakhar@zulip.com>
If `ANDROID_FCM_CREDENTIALS_PATH` is unset it results in fcm_app=None.
We should log error in this case and return, not doing so will result
in runtime error.
Signed-off-by: Prakhar Pratyush <prakhar@zulip.com>
Earlier, we were constructing the APNs & FCM payloads for legacy &
E2EE push notifications even if the user didn't have such a registered
device to send notifications to.
This commit makes changes to construct:
* apns_payload only if the user has an apple device registered
* fcm_payload only if the user has an android device registered
* payload_to_encrypt only if the user has push device registered
which supports E2EE.
Also, now we perform one db query instead of two to calculate
`apple_devices` and `android_devices` for the legacy case.
Overall, this helps to avoid unnecessary compute.
Signed-off-by: Prakhar Pratyush <prakhar@zulip.com>
Adds a log for the end-to-end latency from when the worker decided
to send push notifications & received a success response from bouncer.
Fixes part of #35368.
Refactoring, no functional change.
This commit refactors `send_e2ee_push_notification_apple`
and `send_e2ee_push_notification_android` to return a
`SentPushNotificationResult` dataclass.
It's a cleaner protocol than passing a mutable data structure
`delete_device_ids` as argument and updating it within
functions.
Fixes part of #35368.
This commit adds an endpoint `/mobile_push/e2ee/test_notification`
to send an end-to-end encrypted test push notification to the user's
selected mobile device or all of their mobile devices.
This commit updates the data that gets encrypted to be
the same on both android and iOS.
The data and its format is almost the same as what we send
as FCM payload to android clients with no E2EE support,
changes are:
For send push notification payload:
* 'realm_id`, 'server', 'sender_email', and 'realm_uri' fields
don't exist in the new payload.
* 'event' field renamed to 'type'
* 'stream' and 'stream_id' fields renamed to 'channel_name'
and 'channel_id' respectively.
* The value of 'recipient_type' will be 'channel' & 'direct'
instead of 'stream' & 'private' respectively.
* 'zulip_message_id' field renamed to 'message_id'
For remove push notification payload:
* 'realm_id`, 'server', and 'realm_uri' fields don't exist
in the new payload.
* 'event' field renamed to 'type'
* 'zulip_message_ids' field renamed to 'message_ids' and it's
value will be a JSON array instead of a string.
In the existing iOS client, we have no code of our own involved
in constructing the notifications in the UI, and instead we
leave it to the iOS SDK to do so.
Since, for clients with E2EE support the data is going to be
interpreted by our own code, not by the iOS SDK - we are free
to keep the same data and format.
Co-authored-by: Tim Abbott <tabbott@zulip.com>
This commit replaces the `PUSH_NOTIFICATION_REDACT_CONTENT` server
setting with `require_e2ee_push_notifications` realm setting.
If `require_e2ee_push_notifications` set to True:
* Older clients: Content redacted
* Updated clients: Encrypted content
If `require_e2ee_push_notifications` set to False:
* Older clients: Content NOT redacted
* Updated clients: Encrypted content
Note: Older clients refers to clients that don't support E2EE.
Fixes part of #35370.
This commit adds a test and updates a few existing tests to
cover more cases related to send push notifications.
* We no longer mock the 'send_push_notifications_legacy' function
while testing 'send_push_notifications' codepath and vice-versa.
This makes the tests more realistic as both functions gets called
in 'handle_push_notification'.
This covers the case when only old clients (which don't support
E2EE) exists for a user. Or only updated clients (which supports
E2EE) exist.
* Adds a test 'test_both_old_and_new_client_coexists' for the case
when a user has both type of clients at an instant i.e. they have
updated a few devices only.
Earlier, we were passing a map `device_id_to_encrypted_data`
and http headers as separate fields to bouncer.
The downside of that approach is it restricts the bouncer to
process only one type of notice i.e. either notification for
a new message or removal of sent notification, because it
used to receive a fixed priority and push_type for all the
entries in the map.
Also, using map restricts the bouncer to receive only one
request per device_id. Server can't send multiple notices
to a device in a single call to bouncer.
Currently, the server isn't modelled in a way to make a
single call to the bouncer with:
* Both send-notification & remove-notification request data.
* Multiple send-notification request data to the same device.
This commit replaces the old protocol of sending data with
a list of objects where each object has the required data
for bouncer to send it to FCM or APNs.
This makes things a lot flexible and opens possibility for
server to batch requests in a different way if we'd like to.
This commit updates 'handle_remove_push_notification' function
to use the new 'send_push_notifications' function.
It leads to encrypt the removal payload before sending it to bouncer.
Fixes part of #35368.
In 'test_e2ee_push_notifications', the `SendPushNotificationTest` class
is already decorated with `@activate_push_notification_service()`,
so individual test methods do not need to repeat it.
This commit adds support to send encrypted push notifications
to devices registered to receive encrypted notifications.
URL: `POST /api/v1/remotes/push/e2ee/notify`
payload: `realm_uuid` and `device_id_to_encrypted_data`
The POST request needs to be authenticated with the server’s
API key.
Note: For Zulip Cloud, a background fact about the push bouncer is
that it runs on the same server and database as the main application;
it’s not a separate service. So, as an optimization we directly call
'send_e2ee_push_notifications' function and skip the HTTP request.