zilencer: Rename registration takeover to registration transfer.

This is the final naming that we want, compared to the naming we merged
in #32399.
Includes renaming the API endpoints, but that should be fine as the
original PR was just merged and this isn't deployed anywhere.
This commit is contained in:
Mateusz Mandera
2025-01-29 12:48:22 +08:00
committed by Tim Abbott
parent a23663e6f9
commit 7390eb2ed0
9 changed files with 57 additions and 57 deletions

View File

@@ -493,11 +493,11 @@ def maybe_enqueue_audit_log_upload(realm: Realm) -> None:
SELF_HOSTING_REGISTRATION_TAKEOVER_CHALLENGE_TOKEN_REDIS_KEY = (
"self_hosting_domain_takeover_challenge_verify"
"self_hosting_domain_transfer_challenge_verify"
)
def prepare_for_registration_takeover_challenge(verification_secret: str) -> str:
def prepare_for_registration_transfer_challenge(verification_secret: str) -> str:
access_token = secrets.token_urlsafe(32)
data_to_store = {"verification_secret": verification_secret, "access_token": access_token}
redis_client.set(

View File

@@ -13,7 +13,7 @@ from typing_extensions import override
from zerver.lib.management import ZulipBaseCommand, check_config
from zerver.lib.remote_server import (
PushBouncerSession,
prepare_for_registration_takeover_challenge,
prepare_for_registration_transfer_challenge,
send_json_to_push_bouncer,
send_server_data_to_push_bouncer,
)
@@ -41,7 +41,7 @@ class Command(ZulipBaseCommand):
help="Automatically rotate your server's zulip_org_key",
)
action.add_argument(
"--registration-takeover",
"--registration-transfer",
action="store_true",
help="Overwrite pre-existing registration for the hostname",
)
@@ -114,8 +114,8 @@ class Command(ZulipBaseCommand):
# enough about what happened.
return
if options["registration_takeover"]:
org_id, org_key = self.do_registration_takeover_flow(hostname)
if options["registration_transfer"]:
org_id, org_key = self.do_registration_transfer_flow(hostname)
# We still want to proceed with a regular request to the registration endpoint,
# as it'll update the registration with new information such as the contact email.
request["zulip_org_id"] = org_id
@@ -154,24 +154,24 @@ class Command(ZulipBaseCommand):
)
print("Mobile Push Notification Service registration successfully updated!")
if options["registration_takeover"]:
if options["registration_transfer"]:
print()
print(
"Make sure to restart the server next by running /home/zulip/deployments/current/scripts/restart-server "
"so that the new credentials are reloaded."
)
def do_registration_takeover_flow(self, hostname: str) -> tuple[str, str]:
def do_registration_transfer_flow(self, hostname: str) -> tuple[str, str]:
params = {"hostname": hostname}
response = self._request_push_notification_bouncer_url(
"/api/v1/remotes/server/register/takeover", params
"/api/v1/remotes/server/register/transfer", params
)
verification_secret = response.json()["verification_secret"]
print(
"Received a verification secret from the service. Preparing to serve it at the verification URL."
)
token_for_push_bouncer = prepare_for_registration_takeover_challenge(verification_secret)
token_for_push_bouncer = prepare_for_registration_transfer_challenge(verification_secret)
print("Sending ACK to the service and awaiting completion of verification...")
response = self._request_push_notification_bouncer_url(

View File

@@ -75,7 +75,7 @@ from zerver.lib.remote_server import (
PushNotificationBouncerServerError,
build_analytics_data,
get_realms_info_for_push_bouncer,
prepare_for_registration_takeover_challenge,
prepare_for_registration_transfer_challenge,
record_push_notifications_recently_working,
redis_client,
send_server_data_to_push_bouncer,
@@ -111,7 +111,7 @@ from zerver.models.scheduled_jobs import NotificationTriggers
from zerver.models.streams import get_stream
from zilencer.auth import (
REMOTE_SERVER_TAKEOVER_TOKEN_VALIDITY_SECONDS,
generate_registration_takeover_verification_secret,
generate_registration_transfer_verification_secret,
)
from zilencer.lib.remote_counts import MissingDataError
from zilencer.models import RemoteZulipServerAuditLog
@@ -5364,7 +5364,7 @@ class PushBouncerSignupTest(ZulipTestCase):
"A server with hostname example.com already exists. "
"If you control the hostname "
"and want to transfer the registration to this server, you can run manage.py register_server "
"with the --registration-takeover flag.",
"with the --registration-transfer flag.",
)
def test_register_contact_email_validation_rules(self) -> None:
@@ -5433,13 +5433,13 @@ class RegistrationTakeoverFlowTest(ZulipTestCase):
server = RemoteZulipServer.objects.get(uuid=self.zulip_org_id)
result = self.client_post(
"/api/v1/remotes/server/register/takeover", {"hostname": self.hostname}
"/api/v1/remotes/server/register/transfer", {"hostname": self.hostname}
)
self.assert_json_success(result)
data = result.json()
verification_secret = data["verification_secret"]
access_token = prepare_for_registration_takeover_challenge(verification_secret)
access_token = prepare_for_registration_transfer_challenge(verification_secret)
# First we query the host's endpoint for serving the verification_secret.
result = self.client_post(f"/api/v1/zulip-services/verify/{access_token}/")
self.assert_json_success(result)
@@ -5469,7 +5469,7 @@ class RegistrationTakeoverFlowTest(ZulipTestCase):
self.assertNotEqual(new_key, self.zulip_org_key)
self.assertEqual(
mock_log.output,
["INFO:zilencer.views:verify_registration_takeover:host:example.com|success"],
["INFO:zilencer.views:verify_registration_transfer:host:example.com|success"],
)
# Verify the registration got updated accordingly.
@@ -5485,7 +5485,7 @@ class RegistrationTakeoverFlowTest(ZulipTestCase):
@override_settings(
RATE_LIMITING=True,
ABSOLUTE_USAGE_LIMITS_BY_ENDPOINT={
"verify_registration_takeover_challenge_ack_endpoint": [(10, 2)]
"verify_registration_transfer_challenge_ack_endpoint": [(10, 2)]
},
)
@responses.activate
@@ -5521,7 +5521,7 @@ class RegistrationTakeoverFlowTest(ZulipTestCase):
self.assertEqual(
mock_log.output,
[
"WARNING:zilencer.views:Rate limit exceeded for verify_registration_takeover_challenge_ack_endpoint"
"WARNING:zilencer.views:Rate limit exceeded for verify_registration_transfer_challenge_ack_endpoint"
],
)
@@ -5548,7 +5548,7 @@ class RegistrationTakeoverFlowTest(ZulipTestCase):
self.assert_json_error(result, "The verification secret is malformed")
with time_machine.travel(time_now, tick=False):
verification_secret = generate_registration_takeover_verification_secret(self.hostname)
verification_secret = generate_registration_transfer_verification_secret(self.hostname)
responses.get(
"https://example.com/api/v1/zulip-services/verify/sometoken/",
json={"verification_secret": verification_secret},
@@ -5568,7 +5568,7 @@ class RegistrationTakeoverFlowTest(ZulipTestCase):
time_machine.travel(time_now, tick=False),
mock.patch("zilencer.auth.REMOTE_SERVER_TAKEOVER_TOKEN_SALT", "foo"),
):
verification_secret = generate_registration_takeover_verification_secret(self.hostname)
verification_secret = generate_registration_transfer_verification_secret(self.hostname)
responses.get(
"https://example.com/api/v1/zulip-services/verify/sometoken/",
json={"verification_secret": verification_secret},
@@ -5582,7 +5582,7 @@ class RegistrationTakeoverFlowTest(ZulipTestCase):
# Make sure a valid verification secret for one hostname does not work for another.
with time_machine.travel(time_now, tick=False):
verification_secret = generate_registration_takeover_verification_secret(
verification_secret = generate_registration_transfer_verification_secret(
"different.example.com"
)
responses.get(
@@ -5616,7 +5616,7 @@ class RegistrationTakeoverFlowTest(ZulipTestCase):
self.assertEqual(
mock_log.output,
[
"INFO:zilencer.views:verify_registration_takeover:host:example.com|secret_not_prepared"
"INFO:zilencer.views:verify_registration_transfer:host:example.com|secret_not_prepared"
],
)
@@ -5633,7 +5633,7 @@ class RegistrationTakeoverFlowTest(ZulipTestCase):
)
self.assert_json_error(result, "Error response received from the host: 403")
self.assertIn(
"verify_registration_takeover:host:example.com|exception:", mock_log.output[0]
"verify_registration_transfer:host:example.com|exception:", mock_log.output[0]
)
# SSLError:
@@ -5649,7 +5649,7 @@ class RegistrationTakeoverFlowTest(ZulipTestCase):
)
self.assert_json_error(result, "SSL error occurred while communicating with the host.")
self.assertIn(
"verify_registration_takeover:host:example.com|exception:", mock_log.output[0]
"verify_registration_transfer:host:example.com|exception:", mock_log.output[0]
)
# ConnectionError:
@@ -5667,7 +5667,7 @@ class RegistrationTakeoverFlowTest(ZulipTestCase):
result, "Connection error occurred while communicating with the host."
)
self.assertIn(
"verify_registration_takeover:host:example.com|exception:", mock_log.output[0]
"verify_registration_transfer:host:example.com|exception:", mock_log.output[0]
)
# Timeout:
@@ -5683,7 +5683,7 @@ class RegistrationTakeoverFlowTest(ZulipTestCase):
)
self.assert_json_error(result, "The request timed out while communicating with the host.")
self.assertIn(
"verify_registration_takeover:host:example.com|exception:", mock_log.output[0]
"verify_registration_transfer:host:example.com|exception:", mock_log.output[0]
)
# Generic RequestException:
@@ -5699,12 +5699,12 @@ class RegistrationTakeoverFlowTest(ZulipTestCase):
)
self.assert_json_error(result, "An error occurred while communicating with the host.")
self.assertIn(
"verify_registration_takeover:host:example.com|exception:", mock_log.output[0]
"verify_registration_transfer:host:example.com|exception:", mock_log.output[0]
)
def test_initiate_flow_for_unregistered_domain(self) -> None:
result = self.client_post(
"/api/v1/remotes/server/register/takeover",
"/api/v1/remotes/server/register/transfer",
{"hostname": "unregistered.example.com"},
)
self.assert_json_error(result, "unregistered.example.com not yet registered")
@@ -5715,7 +5715,7 @@ class RegistrationTakeoverFlowTest(ZulipTestCase):
)
self.assert_json_error(result, "Verification secret not prepared")
valid_access_token = prepare_for_registration_takeover_challenge(verification_secret="foo")
valid_access_token = prepare_for_registration_transfer_challenge(verification_secret="foo")
result = self.client_get(
f"/api/v1/zulip-services/verify/{valid_access_token}/",
)

View File

@@ -247,7 +247,7 @@ class VerificationSecretNotPreparedError(JsonableError):
@typed_endpoint_without_parameters
def self_hosting_registration_takeover_challenge_verify(
def self_hosting_registration_transfer_challenge_verify(
request: HttpRequest, access_token: str
) -> HttpResponse:
json_data = redis_client.get(

View File

@@ -40,17 +40,17 @@ logger = logging.getLogger(__name__)
ParamT = ParamSpec("ParamT")
REMOTE_SERVER_TAKEOVER_TOKEN_SALT = "remote_server_takeover"
REMOTE_SERVER_TAKEOVER_TOKEN_SALT = "remote_server_transfer"
REMOTE_SERVER_TAKEOVER_TOKEN_VALIDITY_SECONDS = 10
def generate_registration_takeover_verification_secret(hostname: str) -> str:
def generate_registration_transfer_verification_secret(hostname: str) -> str:
signer = TimestampSigner(salt=REMOTE_SERVER_TAKEOVER_TOKEN_SALT)
secret = base64.b16encode(signer.sign(hostname).encode()).decode()
return secret
def validate_registration_takeover_verification_secret(secret: str, hostname: str) -> None:
def validate_registration_transfer_verification_secret(secret: str, hostname: str) -> None:
signer = TimestampSigner(salt=REMOTE_SERVER_TAKEOVER_TOKEN_SALT)
try:
signed_data = base64.b16decode(secret).decode()

View File

@@ -13,10 +13,10 @@ from zilencer.views import (
remote_server_notify_push,
remote_server_post_analytics,
remote_server_send_test_notification,
take_over_remote_server_registration,
transfer_remote_server_registration,
unregister_all_remote_push_devices,
unregister_remote_push_device,
verify_registration_takeover_challenge_ack_endpoint,
verify_registration_transfer_challenge_ack_endpoint,
)
i18n_urlpatterns: Any = []
@@ -30,10 +30,10 @@ push_bouncer_patterns = [
remote_server_path("remotes/push/test_notification", POST=remote_server_send_test_notification),
# Push signup doesn't use the REST API, since there's no auth.
path("remotes/server/register", register_remote_server),
path("remotes/server/register/takeover", take_over_remote_server_registration),
path("remotes/server/register/transfer", transfer_remote_server_registration),
path(
"remotes/server/register/verify_challenge",
verify_registration_takeover_challenge_ack_endpoint,
verify_registration_transfer_challenge_ack_endpoint,
),
remote_server_path("remotes/server/deactivate", POST=deactivate_remote_server),
# For receiving table data used in analytics and billing

View File

@@ -80,8 +80,8 @@ from zerver.models.realms import DisposableEmailError
from zerver.views.push_notifications import validate_token
from zilencer.auth import (
InvalidZulipServerKeyError,
generate_registration_takeover_verification_secret,
validate_registration_takeover_verification_secret,
generate_registration_transfer_verification_secret,
validate_registration_transfer_verification_secret,
)
from zilencer.lib.remote_counts import MissingDataError
from zilencer.models import (
@@ -162,13 +162,13 @@ def validate_hostname_or_raise_error(hostname: str) -> None:
@csrf_exempt
@require_post
@typed_endpoint
def take_over_remote_server_registration(request: HttpRequest, *, hostname: str) -> HttpResponse:
def transfer_remote_server_registration(request: HttpRequest, *, hostname: str) -> HttpResponse:
validate_hostname_or_raise_error(hostname)
if not RemoteZulipServer.objects.filter(hostname=hostname).exists():
raise JsonableError(_("{hostname} not yet registered").format(hostname=hostname))
verification_secret = generate_registration_takeover_verification_secret(hostname)
verification_secret = generate_registration_transfer_verification_secret(hostname)
return json_success(
request,
data={
@@ -263,7 +263,7 @@ def register_remote_server(
_(
"A server with hostname {hostname} already exists. If you control the hostname "
"and want to transfer the registration to this server, you can run manage.py register_server "
"with the --registration-takeover flag."
"with the --registration-transfer flag."
).format(hostname=hostname)
)
@@ -295,11 +295,11 @@ def register_remote_server(
return json_success(request, data={"created": created})
class RegistrationTakeOverVerificationSession(OutgoingSession):
class RegistrationTransferVerificationSession(OutgoingSession):
def __init__(self) -> None:
# The generous timeout and retries here are likely to be unnecessary; a functional Zulip server should
# respond instantly.
super().__init__(role="verify_registration_takeover_challenge", timeout=5, max_retries=3)
super().__init__(role="verify_registration_transfer_challenge", timeout=5, max_retries=3)
class EndpointUsageRateLimitError(JsonableError):
@@ -309,7 +309,7 @@ class EndpointUsageRateLimitError(JsonableError):
@csrf_exempt
@typed_endpoint
def verify_registration_takeover_challenge_ack_endpoint(
def verify_registration_transfer_challenge_ack_endpoint(
request: HttpRequest,
*,
hostname: str,
@@ -334,13 +334,13 @@ def verify_registration_takeover_challenge_ack_endpoint(
# attacker to fill up the bucket here, and issues can be handled adequately by
# manual intervention.
if settings.RATE_LIMITING:
rate_limit_endpoint_absolute("verify_registration_takeover_challenge_ack_endpoint")
rate_limit_endpoint_absolute("verify_registration_transfer_challenge_ack_endpoint")
except RateLimitedError:
# This rate limit being hit means we've either set the limits too low for legitimate use,
# or the endpoint is being spammed. Ideally, we want this endpoint to always be operational
# so this deserves logging a warning.
logger.warning(
"Rate limit exceeded for verify_registration_takeover_challenge_ack_endpoint"
"Rate limit exceeded for verify_registration_transfer_challenge_ack_endpoint"
)
raise EndpointUsageRateLimitError(
_(
@@ -354,7 +354,7 @@ def verify_registration_takeover_challenge_ack_endpoint(
except RemoteZulipServer.DoesNotExist:
raise JsonableError(_("Registration not found for this hostname"))
session = RegistrationTakeOverVerificationSession()
session = RegistrationTransferVerificationSession()
url = urljoin(f"https://{hostname}", f"/api/v1/zulip-services/verify/{access_token}/")
exception_and_error_message: tuple[Exception, str] | None = None
@@ -362,8 +362,8 @@ def verify_registration_takeover_challenge_ack_endpoint(
response = session.get(url)
response.raise_for_status()
except requests.exceptions.HTTPError as e:
if check_takeover_challenge_response_secret_not_prepared(e.response):
logger.info("verify_registration_takeover:host:%s|secret_not_prepared", hostname)
if check_transfer_challenge_response_secret_not_prepared(e.response):
logger.info("verify_registration_transfer:host:%s|secret_not_prepared", hostname)
raise JsonableError(_("The host reported it has no verification secret."))
error_message = _("Error response received from the host: {status_code}").format(
@@ -385,14 +385,14 @@ def verify_registration_takeover_challenge_ack_endpoint(
if exception_and_error_message is not None:
exception, error_message = exception_and_error_message
logger.info("verify_registration_takeover:host:%s|exception:%s", hostname, exception)
logger.info("verify_registration_transfer:host:%s|exception:%s", hostname, exception)
raise JsonableError(error_message)
data = response.json()
verification_secret = data["verification_secret"]
validate_registration_takeover_verification_secret(verification_secret, hostname)
validate_registration_transfer_verification_secret(verification_secret, hostname)
logger.info("verify_registration_takeover:host:%s|success", hostname)
logger.info("verify_registration_transfer:host:%s|success", hostname)
new_secret_key = get_random_string(RemoteZulipServer.API_KEY_LENGTH)
with transaction.atomic(durable=True):
remote_server.api_key = new_secret_key
@@ -410,7 +410,7 @@ def verify_registration_takeover_challenge_ack_endpoint(
)
def check_takeover_challenge_response_secret_not_prepared(response: requests.Response) -> bool:
def check_transfer_challenge_response_secret_not_prepared(response: requests.Response) -> bool:
secret_not_prepared = False
try:
secret_not_prepared = (

View File

@@ -343,7 +343,7 @@ RATE_LIMITING_RULES: dict[str, list[tuple[int, int]]] = {}
# only, so we don't need a nice overriding system for them like we do
# for RATE_LIMITING_RULES.
ABSOLUTE_USAGE_LIMITS_BY_ENDPOINT = {
"verify_registration_takeover_challenge_ack_endpoint": [
"verify_registration_transfer_challenge_ack_endpoint": [
# 30 requests per day
(86400, 30),
],

View File

@@ -102,7 +102,7 @@ from zerver.views.push_notifications import (
self_hosting_auth_json_endpoint,
self_hosting_auth_not_configured,
self_hosting_auth_redirect_endpoint,
self_hosting_registration_takeover_challenge_verify,
self_hosting_registration_transfer_challenge_verify,
send_test_push_notification_api,
)
from zerver.views.reactions import add_reaction, remove_reaction
@@ -872,7 +872,7 @@ urls += [
urls += [
path(
"api/v1/zulip-services/verify/<str:access_token>/",
self_hosting_registration_takeover_challenge_verify,
self_hosting_registration_transfer_challenge_verify,
),
]