Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

remote_server: Add management command for deactivation. #20775

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
10 changes: 5 additions & 5 deletions docs/production/mobile-push-notifications.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,12 +36,12 @@ You can enable this for your Zulip server as follows:

```bash
# As root:
su zulip -c '/home/zulip/deployments/current/manage.py register_server'
su zulip -c '/home/zulip/deployments/current/manage.py mobile_push_service --register'
# Or as the zulip user, you can skip the `su zulip -c`:
/home/zulip/deployments/current/manage.py register_server
/home/zulip/deployments/current/manage.py mobile_push_service --register

# docker-zulip users can run this inside the container with `docker exec`:
docker exec -it -u zulip <container_name> /home/zulip/deployments/current/manage.py register_server
docker exec -it -u zulip <container_name> /home/zulip/deployments/current/manage.py mobile_push_service --register
```

This command will print the registration data it would send to the
Expand Down Expand Up @@ -80,11 +80,11 @@ Your server's registration includes the server's hostname and contact
email address (from `EXTERNAL_HOST` and `ZULIP_ADMINISTRATOR` in
`/etc/zulip/settings.py`, aka the `--hostname` and `--email` options
in the installer). You can update your server's registration data by
running `manage.py register_server` again.
running `manage.py mobile_push_service --register` again.

If you'd like to rotate your server's API key for this service
(`zulip_org_key`), you need to use
`manage.py register_server --rotate-key` option; it will automatically
`manage.py mobile_push_service --rotate-key` option; it will automatically
generate a new `zulip_org_key` and store that new key in
`/etc/zulip/zulip-secrets.conf`.

Expand Down
2 changes: 1 addition & 1 deletion zerver/decorator.py
Original file line number Diff line number Diff line change
Expand Up @@ -218,7 +218,7 @@ def __init__(self, role: str) -> None:

@staticmethod
def msg_format() -> str:
return "Zulip server auth failure: {role} is not registered -- did you run `manage.py register_server`?"
return "Zulip server auth failure: {role} is not registered -- did you run `manage.py mobile_push_service --register`?"


class InvalidZulipServerKeyError(InvalidZulipServerError):
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import base64
import subprocess
from argparse import ArgumentParser
from typing import Any, Dict
from typing import Any, Dict, Optional

import requests
from django.conf import settings
Expand All @@ -21,6 +22,16 @@ class Command(ZulipBaseCommand):
help = """Register a remote Zulip server for push notifications."""

def add_arguments(self, parser: ArgumentParser) -> None:
parser.add_argument(
"--register",
action="store_true",
help="Register your server for the Mobile Push Notification Service.",
)
parser.add_argument(
"--deactivate",
action="store_true",
help="Deactivate your server's Mobile Push Notification Service registration.",
)
parser.add_argument(
"--agree_to_terms_of_service",
action="store_true",
Expand Down Expand Up @@ -55,18 +66,51 @@ def handle(self, *args: Any, **options: Any) -> None:
"in /etc/zulip/settings.py (remove the '#')"
)

if options["register"]:
self._handle_register_subcommand(*args, **options)
elif options["rotate_key"]:
self._handle_rotate_key_subcommand(*args, **options)
elif options["deactivate"]:
self._handle_deactivate_subcommand(*args, **options)

def _handle_rotate_key_subcommand(self, *args: Any, **options: Any) -> None:
request = {
"zulip_org_id": settings.ZULIP_ORG_ID,
"zulip_org_key": settings.ZULIP_ORG_KEY,
"hostname": settings.EXTERNAL_HOST,
"contact_email": settings.ZULIP_ADMINISTRATOR,
"new_org_key": get_random_string(64),
}
if options["rotate_key"]:
request["new_org_key"] = get_random_string(64)
self._log_params(request)

response = self._request_push_notification_bouncer_url(
"/api/v1/remotes/server/register", request
)

assert response.json()["result"] == "success"
print(f"Success! Updating {SECRETS_FILENAME} with the new key...")
subprocess.check_call(
[
"crudini",
"--set",
SECRETS_FILENAME,
"secrets",
"zulip_org_key",
request["new_org_key"],
]
)
print("Mobile Push Notification Service registration successfully updated!")

def _handle_register_subcommand(self, *args: Any, **options: Any) -> None:
request = {
"zulip_org_id": settings.ZULIP_ORG_ID,
"zulip_org_key": settings.ZULIP_ORG_KEY,
"hostname": settings.EXTERNAL_HOST,
"contact_email": settings.ZULIP_ADMINISTRATOR,
}
self._log_params(request)

if not options["agree_to_terms_of_service"] and not options["rotate_key"]:
if not options["agree_to_terms_of_service"]:
print(
"To register, you must agree to the Zulipchat Terms of Service: "
"https://zulip.com/terms/"
Expand All @@ -82,6 +126,7 @@ def handle(self, *args: Any, **options: Any) -> None:
"/api/v1/remotes/server/register", request
)

assert response.json()["result"] == "success"
if response.json()["created"]:
print(
"You've successfully registered for the Mobile Push Notification Service!\n"
Expand All @@ -92,25 +137,29 @@ def handle(self, *args: Any, **options: Any) -> None:
)
print("- Return to the documentation to learn how to test push notifications")
else:
if options["rotate_key"]:
print(f"Success! Updating {SECRETS_FILENAME} with the new key...")
subprocess.check_call(
[
"crudini",
"--set",
SECRETS_FILENAME,
"secrets",
"zulip_org_key",
request["new_org_key"],
]
)
print("Mobile Push Notification Service registration successfully updated!")

def _request_push_notification_bouncer_url(self, url: str, params: Dict[str, Any]) -> Response:
def _handle_deactivate_subcommand(self, *args: Any, **options: Any) -> None:
credentials = "{}:{}".format(settings.ZULIP_ORG_ID, settings.ZULIP_ORG_KEY)
basic_auth = "Basic " + base64.b64encode(credentials.encode()).decode()

response = self._request_push_notification_bouncer_url(
"/api/v1/remotes/server/deactivate", headers={"authorization": basic_auth}
)

assert response.json()["result"] == "success"
print("Mobile Push Notification Service registration successfully deactivated!")

def _request_push_notification_bouncer_url(
self,
url: str,
params: Optional[Dict[str, Any]] = {},
headers: Optional[Dict[str, Any]] = {},
) -> Response:
registration_url = settings.PUSH_NOTIFICATION_BOUNCER_URL + url
session = PushBouncerSession()
try:
response = session.post(registration_url, params=params)
response = session.post(registration_url, params=params, headers=headers)
except requests.RequestException:
raise CommandError(
"Network error connecting to push notifications service "
Expand Down
6 changes: 3 additions & 3 deletions zerver/tests/test_push_notifications.py
Original file line number Diff line number Diff line change
Expand Up @@ -261,7 +261,7 @@ def test_register_remote_push_user_paramas(self) -> None:
)
self.assert_json_error(
result,
"Zulip server auth failure: invalid_uuid is not registered -- did you run `manage.py register_server`?",
"Zulip server auth failure: invalid_uuid is not registered -- did you run `manage.py mobile_push_service --register`?",
status_code=401,
)
del self.API_KEYS["invalid_uuid"]
Expand All @@ -276,7 +276,7 @@ def test_register_remote_push_user_paramas(self) -> None:
)
self.assert_json_error(
result,
f"Zulip server auth failure: {credentials_uuid} is not registered -- did you run `manage.py register_server`?",
f"Zulip server auth failure: {credentials_uuid} is not registered -- did you run `manage.py mobile_push_service --register`?",
status_code=401,
)

Expand Down Expand Up @@ -2101,7 +2101,7 @@ def test_400_error_invalid_server_key(self) -> None:
self.assertEqual(
str(exc.exception),
"Push notifications bouncer error: "
"Zulip server auth failure: testRole is not registered -- did you run `manage.py register_server`?",
"Zulip server auth failure: testRole is not registered -- did you run `manage.py mobile_push_service --register`?",
)

@responses.activate
Expand Down
2 changes: 1 addition & 1 deletion zilencer/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ def get_remote_server_by_uuid(uuid: str) -> "RemoteZulipServer":
class RemoteZulipServer(models.Model):
"""Each object corresponds to a single remote Zulip server that is
registered for the Mobile Push Notifications Service via
`manage.py register_server`.
`manage.py mobile_push_service --register`.
"""

UUID_LENGTH = 36
Expand Down