confirmation: Tighten logic around the mark_object_used parameter.

This commit is contained in:
Tim Abbott 2022-07-19 12:13:32 -07:00
parent 495671cca0
commit dcc03a453a
5 changed files with 27 additions and 5 deletions

View File

@ -52,6 +52,15 @@ ConfirmationObjT = Union[MultiuseInvite, PreregistrationUser, EmailChangeStatus,
def get_object_from_key(
confirmation_key: str, confirmation_types: List[int], mark_object_used: bool = True
) -> ConfirmationObjT:
"""Access a confirmation object from one of the provided confirmation
types with the provided key.
The mark_object_used parameter determines whether to mark the
confirmation object as used (which generally prevents it from
being used again). It should always be False for MultiuseInvite
objects, since they are intended to be used multiple times.
"""
# Confirmation keys used to be 40 characters
if len(confirmation_key) not in (24, 40):
raise ConfirmationKeyException(ConfirmationKeyException.WRONG_LENGTH)
@ -67,7 +76,12 @@ def get_object_from_key(
obj = confirmation.content_object
assert obj is not None
if mark_object_used and hasattr(obj, "status"):
if mark_object_used:
# MultiuseInvite objects have no status field, since they are
# intended to be used more than once.
assert confirmation.type != Confirmation.MULTIUSE_INVITE
assert hasattr(obj, "status")
obj.status = getattr(settings, "STATUS_USED", 1)
obj.save(update_fields=["status"])
return obj

View File

@ -191,7 +191,7 @@ def maybe_send_to_registration(
from_multiuse_invite = True
try:
confirmation_obj = get_object_from_key(
multiuse_object_key, [Confirmation.MULTIUSE_INVITE]
multiuse_object_key, [Confirmation.MULTIUSE_INVITE], mark_object_used=False
)
except ConfirmationKeyException as exception:
return render_confirmation_key_error(request, exception)

View File

@ -327,11 +327,15 @@ def check_subdomain_available(request: HttpRequest, subdomain: str) -> HttpRespo
def realm_reactivation(request: HttpRequest, confirmation_key: str) -> HttpResponse:
try:
realm = get_object_from_key(confirmation_key, [Confirmation.REALM_REACTIVATION])
realm = get_object_from_key(
confirmation_key, [Confirmation.REALM_REACTIVATION], mark_object_used=False
)
except ConfirmationKeyException:
return render(request, "zerver/realm_reactivation_link_error.html")
assert isinstance(realm, Realm)
do_reactivate_realm(realm)
# TODO: After reactivating the realm, the confirmation link needs to be revoked in some way.
context = {"realm": realm}
return render(request, "zerver/realm_reactivation.html", context)

View File

@ -751,7 +751,9 @@ def accounts_home_from_multiuse_invite(request: HttpRequest, confirmation_key: s
realm = get_realm_from_request(request)
multiuse_object: Optional[MultiuseInvite] = None
try:
confirmation_obj = get_object_from_key(confirmation_key, [Confirmation.MULTIUSE_INVITE])
confirmation_obj = get_object_from_key(
confirmation_key, [Confirmation.MULTIUSE_INVITE], mark_object_used=False
)
assert isinstance(confirmation_obj, MultiuseInvite)
multiuse_object = confirmation_obj
if realm != multiuse_object.realm:

View File

@ -18,7 +18,9 @@ def process_unsubscribe(
unsubscribe_function: Callable[[UserProfile], None],
) -> HttpResponse:
try:
user_profile = get_object_from_key(confirmation_key, [Confirmation.UNSUBSCRIBE])
user_profile = get_object_from_key(
confirmation_key, [Confirmation.UNSUBSCRIBE], mark_object_used=False
)
except ConfirmationKeyException:
return render(request, "zerver/unsubscribe_link_error.html")