realm_reactivation: Use redirect-to-POST trick.

Uses the approach done for email change confirmations in #34980 to avoid
triggering a reactivation via just a GET request. Instead, the GET
should return a page which will trigger the browser to then POST the key
to the endpoint.
This commit is contained in:
Mateusz Mandera
2025-07-17 02:30:18 +08:00
committed by Tim Abbott
parent 5b00cb6753
commit 4210ccc5db
4 changed files with 38 additions and 6 deletions

View File

@@ -273,7 +273,7 @@ _properties = {
"join", validity_in_days=settings.INVITATION_LINK_VALIDITY_DAYS
),
Confirmation.REALM_CREATION: ConfirmationType("get_prereg_key_and_redirect"),
Confirmation.REALM_REACTIVATION: ConfirmationType("realm_reactivation"),
Confirmation.REALM_REACTIVATION: ConfirmationType("realm_reactivation_get"),
}
if settings.ZILENCER_ENABLED:
_properties[Confirmation.REMOTE_SERVER_BILLING_LEGACY_LOGIN] = ConfirmationType(

View File

@@ -514,7 +514,11 @@ class RealmTest(ZulipTestCase):
obj = RealmReactivationStatus.objects.create(realm=realm)
confirmation_url = create_confirmation_link(obj, Confirmation.REALM_REACTIVATION)
key = confirmation_url.split("/")[-1]
response = self.client_get(confirmation_url)
self.assert_in_success_response(["redirect-to-post-form"], response)
response = self.client_post("/reactivate/", {"key": key})
self.assert_in_success_response(
["Your organization has been successfully reactivated"], response
)
@@ -527,6 +531,8 @@ class RealmTest(ZulipTestCase):
)
response = self.client_get(confirmation_url)
self.assertEqual(response.status_code, 404)
response = self.client_post("/reactivate/", {"key": key})
self.assertEqual(response.status_code, 404)
def test_realm_reactivation_confirmation_object(self) -> None:
realm = get_realm("zulip")
@@ -650,7 +656,12 @@ class RealmTest(ZulipTestCase):
self.assertIn("Dear former administrators", mail.outbox[0].body)
admins = realm.get_human_admin_users()
confirmation_url = self.get_confirmation_url_from_outbox(admins[0].delivery_email)
key = confirmation_url.split("/")[-1]
response = self.client_get(confirmation_url)
self.assert_in_success_response(["redirect-to-post-form"], response)
response = self.client_post("/reactivate/", {"key": key})
self.assert_in_success_response(
["Your organization has been successfully reactivated"], response
)

View File

@@ -6,6 +6,7 @@ from django.core.exceptions import ValidationError
from django.db import transaction
from django.http import HttpRequest, HttpResponse
from django.shortcuts import render
from django.urls import reverse
from django.utils.translation import gettext as _
from django.views.decorators.http import require_safe
from pydantic import Json, NonNegativeInt, StringConstraints
@@ -28,7 +29,7 @@ from zerver.actions.realm_settings import (
parse_and_set_setting_value_if_required,
validate_authentication_methods_dict_from_api,
)
from zerver.decorator import require_realm_admin, require_realm_owner
from zerver.decorator import require_post, require_realm_admin, require_realm_owner
from zerver.forms import check_subdomain_available as check_subdomain
from zerver.lib.demo_organizations import check_demo_organization_has_set_email
from zerver.lib.exceptions import JsonableError, OrganizationOwnerRequiredError
@@ -576,11 +577,29 @@ def check_subdomain_available(request: HttpRequest, subdomain: str) -> HttpRespo
return json_success(request, data={"msg": e.message})
def realm_reactivation(request: HttpRequest, confirmation_key: str) -> HttpResponse:
def realm_reactivation_get(request: HttpRequest, confirmation_key: str) -> HttpResponse:
try:
obj = get_object_from_key(
confirmation_key, [Confirmation.REALM_REACTIVATION], mark_object_used=True
get_object_from_key(
confirmation_key, [Confirmation.REALM_REACTIVATION], mark_object_used=False
)
except ConfirmationKeyError: # nocoverage
return render(request, "zerver/realm_reactivation_link_error.html", status=404)
return render(
request,
"confirmation/redirect_to_post.html",
context={
"target_url": reverse("realm_reactivation"),
"key": confirmation_key,
},
)
@require_post
@typed_endpoint
def realm_reactivation(request: HttpRequest, *, key: str) -> HttpResponse:
try:
obj = get_object_from_key(key, [Confirmation.REALM_REACTIVATION], mark_object_used=True)
except ConfirmationKeyError:
return render(request, "zerver/realm_reactivation_link_error.html", status=404)

View File

@@ -124,6 +124,7 @@ from zerver.views.realm import (
check_subdomain_available,
deactivate_realm,
realm_reactivation,
realm_reactivation_get,
update_realm,
update_realm_user_settings_defaults,
)
@@ -698,7 +699,8 @@ i18n_urls = [
path("new/", create_realm),
path("new/<creation_key>", create_realm, name="create_realm"),
# Realm reactivation
path("reactivate/<confirmation_key>", realm_reactivation, name="realm_reactivation"),
path("reactivate/", realm_reactivation, name="realm_reactivation"),
path("reactivate/<confirmation_key>", realm_reactivation_get, name="realm_reactivation_get"),
# Login/registration
path("register/", accounts_home, name="register"),
path("login/", login_page, {"template_name": "zerver/login.html"}, name="login_page"),