mirror of
https://github.com/zulip/zulip.git
synced 2025-11-15 11:22:04 +00:00
push_notifs: Support APNs token auth, as well as cert auth.
This will make it possible to send notifications to multiple distinct app IDs over the same connection.
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -18,6 +18,7 @@
|
|||||||
|
|
||||||
## Config files for the dev environment
|
## Config files for the dev environment
|
||||||
/zproject/apns-dev.pem
|
/zproject/apns-dev.pem
|
||||||
|
/zproject/apns-dev-key.p8
|
||||||
/zproject/dev-secrets.conf
|
/zproject/dev-secrets.conf
|
||||||
/tools/conf.ini
|
/tools/conf.ini
|
||||||
/tools/custom_provision
|
/tools/custom_provision
|
||||||
|
|||||||
@@ -213,13 +213,23 @@ push notifications through the new app is quite straightforward:
|
|||||||
[FCM push notifications](https://firebase.google.com/docs/cloud-messaging)
|
[FCM push notifications](https://firebase.google.com/docs/cloud-messaging)
|
||||||
key in the Google Developer console and set `android_gcm_api_key` in
|
key in the Google Developer console and set `android_gcm_api_key` in
|
||||||
`/etc/zulip/zulip-secrets.conf` to that key.
|
`/etc/zulip/zulip-secrets.conf` to that key.
|
||||||
- Register for a
|
|
||||||
[mobile push notification certificate][apple-docs]
|
- In Apple's developer console, register a [token][apple-doc-token] or
|
||||||
from Apple's developer console. Set `APNS_SANDBOX=False` and
|
[certificate][apple-doc-cert] for sending push notifications.
|
||||||
`APNS_CERT_FILE` to be the path of your APNS certificate file in
|
Then in `/etc/zulip/settings.py`, set `APNS_SANDBOX=False`, and:
|
||||||
`/etc/zulip/settings.py`.
|
|
||||||
|
- If using APNs [certificate-based authentication][apple-doc-cert],
|
||||||
|
set `APNS_CERT_FILE` to the path of your APNs certificate file.
|
||||||
|
|
||||||
|
- If using APNs [token-based authentication][apple-doc-token],
|
||||||
|
set `APNS_TOKEN_KEY_FILE` to the path of your APNs token key file,
|
||||||
|
`APNS_TOKEN_KEY_ID` to the corresponding 10-character key ID, and
|
||||||
|
`APNS_TEAM_ID` to your 10-character Apple team ID.
|
||||||
|
|
||||||
- Set the `APNS_TOPIC` setting to the ID for
|
- Set the `APNS_TOPIC` setting to the ID for
|
||||||
your app (for the official Zulip apps, it's `org.zulip.Zulip`).
|
your app (for the official Zulip apps, it's `org.zulip.Zulip`).
|
||||||
|
|
||||||
- Restart the Zulip server.
|
- Restart the Zulip server.
|
||||||
|
|
||||||
[apple-docs]: https://developer.apple.com/library/content/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/APNSOverview.html
|
[apple-doc-cert]: https://developer.apple.com/documentation/usernotifications/setting_up_a_remote_notification_server/establishing_a_certificate-based_connection_to_apns
|
||||||
|
[apple-doc-token]: https://developer.apple.com/documentation/usernotifications/setting_up_a_remote_notification_server/establishing_a_token-based_connection_to_apns
|
||||||
|
|||||||
@@ -145,13 +145,17 @@ class APNsContext:
|
|||||||
loop: asyncio.AbstractEventLoop
|
loop: asyncio.AbstractEventLoop
|
||||||
|
|
||||||
|
|
||||||
|
def apns_enabled() -> bool:
|
||||||
|
return settings.APNS_TOKEN_KEY_FILE is not None or settings.APNS_CERT_FILE is not None
|
||||||
|
|
||||||
|
|
||||||
@lru_cache(maxsize=None)
|
@lru_cache(maxsize=None)
|
||||||
def get_apns_context() -> Optional[APNsContext]:
|
def get_apns_context() -> Optional[APNsContext]:
|
||||||
# We lazily do this import as part of optimizing Zulip's base
|
# We lazily do this import as part of optimizing Zulip's base
|
||||||
# import time.
|
# import time.
|
||||||
import aioapns
|
import aioapns
|
||||||
|
|
||||||
if settings.APNS_CERT_FILE is None: # nocoverage
|
if not apns_enabled(): # nocoverage
|
||||||
return None
|
return None
|
||||||
|
|
||||||
# NB if called concurrently, this will make excess connections.
|
# NB if called concurrently, this will make excess connections.
|
||||||
@@ -171,6 +175,9 @@ def get_apns_context() -> Optional[APNsContext]:
|
|||||||
async def make_apns() -> aioapns.APNs:
|
async def make_apns() -> aioapns.APNs:
|
||||||
return aioapns.APNs(
|
return aioapns.APNs(
|
||||||
client_cert=settings.APNS_CERT_FILE,
|
client_cert=settings.APNS_CERT_FILE,
|
||||||
|
key=settings.APNS_TOKEN_KEY_FILE,
|
||||||
|
key_id=settings.APNS_TOKEN_KEY_ID,
|
||||||
|
team_id=settings.APNS_TEAM_ID,
|
||||||
topic=settings.APNS_TOPIC,
|
topic=settings.APNS_TOPIC,
|
||||||
max_connection_attempts=APNS_MAX_RETRIES,
|
max_connection_attempts=APNS_MAX_RETRIES,
|
||||||
use_sandbox=settings.APNS_SANDBOX,
|
use_sandbox=settings.APNS_SANDBOX,
|
||||||
@@ -181,10 +188,6 @@ def get_apns_context() -> Optional[APNsContext]:
|
|||||||
return APNsContext(apns=apns, loop=loop)
|
return APNsContext(apns=apns, loop=loop)
|
||||||
|
|
||||||
|
|
||||||
def apns_enabled() -> bool:
|
|
||||||
return settings.APNS_CERT_FILE is not None
|
|
||||||
|
|
||||||
|
|
||||||
def modernize_apns_payload(data: Mapping[str, Any]) -> Mapping[str, Any]:
|
def modernize_apns_payload(data: Mapping[str, Any]) -> Mapping[str, Any]:
|
||||||
"""Take a payload in an unknown Zulip version's format, and return in current format."""
|
"""Take a payload in an unknown Zulip version's format, and return in current format."""
|
||||||
# TODO this isn't super robust as is -- if a buggy remote server
|
# TODO this isn't super robust as is -- if a buggy remote server
|
||||||
|
|||||||
@@ -401,6 +401,9 @@ POST_MIGRATION_CACHE_FLUSHING = False
|
|||||||
# rebuilding the mobile app with a different push notifications
|
# rebuilding the mobile app with a different push notifications
|
||||||
# server.
|
# server.
|
||||||
APNS_CERT_FILE: Optional[str] = None
|
APNS_CERT_FILE: Optional[str] = None
|
||||||
|
APNS_TOKEN_KEY_FILE: Optional[str] = None
|
||||||
|
APNS_TOKEN_KEY_ID = get_secret("apns_token_key_id", development_only=True)
|
||||||
|
APNS_TEAM_ID = get_secret("apns_team_id", development_only=True)
|
||||||
APNS_SANDBOX = True
|
APNS_SANDBOX = True
|
||||||
APNS_TOPIC = "org.zulip.Zulip"
|
APNS_TOPIC = "org.zulip.Zulip"
|
||||||
# ZULIP_IOS_APP_ID is obsolete
|
# ZULIP_IOS_APP_ID is obsolete
|
||||||
|
|||||||
@@ -100,11 +100,14 @@ USING_PGROONGA = True
|
|||||||
# Flush cache after migration.
|
# Flush cache after migration.
|
||||||
POST_MIGRATION_CACHE_FLUSHING = True
|
POST_MIGRATION_CACHE_FLUSHING = True
|
||||||
|
|
||||||
# If a sandbox APNs cert is provided, use it.
|
# If a sandbox APNs key or cert is provided, use it.
|
||||||
# To create such a cert, see instructions at:
|
# To create such a key or cert, see instructions at:
|
||||||
# https://github.com/zulip/zulip-mobile/blob/main/docs/howto/push-notifications.md#ios
|
# https://github.com/zulip/zulip-mobile/blob/main/docs/howto/push-notifications.md#ios
|
||||||
|
_candidate_apns_token_key_file = "zproject/apns-dev-key.p8"
|
||||||
_candidate_apns_cert_file = "zproject/apns-dev.pem"
|
_candidate_apns_cert_file = "zproject/apns-dev.pem"
|
||||||
if os.path.isfile(_candidate_apns_cert_file):
|
if os.path.isfile(_candidate_apns_token_key_file):
|
||||||
|
APNS_TOKEN_KEY_FILE = _candidate_apns_token_key_file
|
||||||
|
elif os.path.isfile(_candidate_apns_cert_file):
|
||||||
APNS_CERT_FILE = _candidate_apns_cert_file
|
APNS_CERT_FILE = _candidate_apns_cert_file
|
||||||
|
|
||||||
# Don't require anything about password strength in development
|
# Don't require anything about password strength in development
|
||||||
|
|||||||
@@ -156,7 +156,8 @@ INLINE_URL_EMBED_PREVIEW = False
|
|||||||
HOME_NOT_LOGGED_IN = "/login/"
|
HOME_NOT_LOGGED_IN = "/login/"
|
||||||
LOGIN_URL = "/accounts/login/"
|
LOGIN_URL = "/accounts/login/"
|
||||||
|
|
||||||
# If dev_settings.py found a cert file to use here, ignore it.
|
# If dev_settings.py found a key or cert file to use here, ignore it.
|
||||||
|
APNS_TOKEN_KEY_FILE: Optional[str] = None
|
||||||
APNS_CERT_FILE: Optional[str] = None
|
APNS_CERT_FILE: Optional[str] = None
|
||||||
|
|
||||||
# By default will not send emails when login occurs.
|
# By default will not send emails when login occurs.
|
||||||
|
|||||||
Reference in New Issue
Block a user