register_remote_server: Don't allow duplicate hostnames.

This requires a bit of restructuring of the existing code to handle all
the cases correctly.
This commit is contained in:
Mateusz Mandera 2024-01-26 17:06:12 +01:00 committed by Tim Abbott
parent 5e2d620d9f
commit 25f47bd749
2 changed files with 53 additions and 16 deletions

View File

@ -4909,6 +4909,32 @@ class PushBouncerSignupTest(ZulipTestCase):
result, f"Zulip server auth failure: key does not match role {zulip_org_id}"
)
def test_register_duplicate_hostname(self) -> None:
zulip_org_id = str(uuid.uuid4())
zulip_org_key = get_random_string(64)
request = dict(
zulip_org_id=zulip_org_id,
zulip_org_key=zulip_org_key,
hostname="example.com",
contact_email="server-admin@zulip.com",
)
result = self.client_post("/api/v1/remotes/server/register", request)
self.assert_json_success(result)
server = RemoteZulipServer.objects.get(uuid=zulip_org_id)
self.assertEqual(server.hostname, "example.com")
new_zulip_org_id = str(uuid.uuid4())
new_zulip_org_key = get_random_string(64)
request = dict(
zulip_org_id=new_zulip_org_id,
zulip_org_key=new_zulip_org_key,
hostname="example.com",
contact_email="server-admin@zulip.com",
)
result = self.client_post("/api/v1/remotes/server/register", request)
self.assert_json_error(result, "A server with hostname example.com already exists")
class TestUserPushIdentityCompat(ZulipTestCase):
def test_filter_q(self) -> None:

View File

@ -137,29 +137,40 @@ def register_remote_server(
except ValidationError as e:
raise JsonableError(e.message)
with transaction.atomic():
remote_server, created = RemoteZulipServer.objects.get_or_create(
uuid=zulip_org_id,
defaults={
"hostname": hostname,
"contact_email": contact_email,
"api_key": zulip_org_key,
"last_request_datetime": timezone_now(),
},
try:
remote_server = RemoteZulipServer.objects.get(uuid=zulip_org_id)
except RemoteZulipServer.DoesNotExist:
remote_server = None
if remote_server is not None:
if not constant_time_compare(remote_server.api_key, zulip_org_key):
raise InvalidZulipServerKeyError(zulip_org_id)
if remote_server.deactivated:
raise RemoteServerDeactivatedError
if remote_server is None and RemoteZulipServer.objects.filter(hostname=hostname).exists():
raise JsonableError(
_("A server with hostname {hostname} already exists").format(hostname=hostname)
)
if created:
with transaction.atomic():
if remote_server is None:
created = True
remote_server = RemoteZulipServer.objects.create(
uuid=zulip_org_id,
hostname=hostname,
contact_email=contact_email,
api_key=zulip_org_key,
last_request_datetime=timezone_now(),
)
RemoteZulipServerAuditLog.objects.create(
event_type=RemoteZulipServerAuditLog.REMOTE_SERVER_CREATED,
server=remote_server,
event_time=remote_server.last_updated,
)
else:
if not constant_time_compare(remote_server.api_key, zulip_org_key):
raise InvalidZulipServerKeyError(zulip_org_id)
if remote_server.deactivated:
raise RemoteServerDeactivatedError
created = False
remote_server.hostname = hostname
remote_server.contact_email = contact_email
if new_org_key is not None: