mirror of
https://github.com/zulip/zulip.git
synced 2025-11-05 06:23:38 +00:00
models: Rework Attachment.is_*_public to be a cache.
Previously, Attachment.is_realm_public and its cousin, Attachment.is_web_public, were properties that began as False and transitioned to True only when a message containing a link to the attachment was sent to the appropriate class of stream, or such a link was added as part of editing a message. This pattern meant that neither field was updated in situations where the access permissions for a message changed: * Moving the message to a different stream. * Changing the permissions for a stream containing links to the message. This correctness issue has limited security impact, because uploaded files are secured both by a random URL and by these access checks. To fix this, we reformulate these fields as a cache, with code paths that change the permissions affecting an attachment responsible for setting these values to the `None` (uncached) state. We prefer setting this `None` state over computing the correct permissions, because the correct post-edit permissions are a function of all messages containing the attachment, and we don't want to be responsible for fetching all of those messages in the edit code paths.
This commit is contained in:
@@ -221,6 +221,7 @@ from zerver.lib.utils import generate_api_key, log_statsd_event
|
||||
from zerver.lib.validator import check_widget_content
|
||||
from zerver.lib.widget import do_widget_post_save_actions, is_widget_message
|
||||
from zerver.models import (
|
||||
ArchivedAttachment,
|
||||
Attachment,
|
||||
Client,
|
||||
CustomProfileField,
|
||||
@@ -5195,6 +5196,17 @@ def do_change_stream_permission(
|
||||
|
||||
event_time = timezone_now()
|
||||
if old_invite_only_value != stream.invite_only:
|
||||
# Reset the Attachment.is_realm_public cache for all
|
||||
# messages in the stream whose permissions were changed.
|
||||
Attachment.objects.filter(messages__recipient_id=stream.recipient_id).update(
|
||||
is_realm_public=None
|
||||
)
|
||||
# We need to do the same for ArchivedAttachment to avoid
|
||||
# bugs if deleted attachments are later restored.
|
||||
ArchivedAttachment.objects.filter(messages__recipient_id=stream.recipient_id).update(
|
||||
is_realm_public=None
|
||||
)
|
||||
|
||||
RealmAuditLog.objects.create(
|
||||
realm=stream.realm,
|
||||
acting_user=acting_user,
|
||||
@@ -5227,6 +5239,17 @@ def do_change_stream_permission(
|
||||
)
|
||||
|
||||
if old_is_web_public_value != stream.is_web_public:
|
||||
# Reset the Attachment.is_realm_public cache for all
|
||||
# messages in the stream whose permissions were changed.
|
||||
Attachment.objects.filter(messages__recipient_id=stream.recipient_id).update(
|
||||
is_web_public=None
|
||||
)
|
||||
# We need to do the same for ArchivedAttachment to avoid
|
||||
# bugs if deleted attachments are later restored.
|
||||
ArchivedAttachment.objects.filter(messages__recipient_id=stream.recipient_id).update(
|
||||
is_web_public=None
|
||||
)
|
||||
|
||||
RealmAuditLog.objects.create(
|
||||
realm=stream.realm,
|
||||
acting_user=acting_user,
|
||||
@@ -7046,6 +7069,24 @@ def do_update_message(
|
||||
delete_event_notify_user_ids = [sub.user_profile_id for sub in subs_losing_access]
|
||||
send_event(user_profile.realm, delete_event, delete_event_notify_user_ids)
|
||||
|
||||
# Reset the Attachment.is_*_public caches for all messages
|
||||
# moved to another stream with different access permissions.
|
||||
if new_stream.invite_only != stream_being_edited.invite_only:
|
||||
Attachment.objects.filter(messages__in=changed_message_ids).update(
|
||||
is_realm_public=None,
|
||||
)
|
||||
ArchivedAttachment.objects.filter(messages__in=changed_message_ids).update(
|
||||
is_realm_public=None,
|
||||
)
|
||||
|
||||
if new_stream.is_web_public != stream_being_edited.is_web_public:
|
||||
Attachment.objects.filter(messages__in=changed_message_ids).update(
|
||||
is_web_public=None,
|
||||
)
|
||||
ArchivedAttachment.objects.filter(messages__in=changed_message_ids).update(
|
||||
is_web_public=None,
|
||||
)
|
||||
|
||||
# This does message.save(update_fields=[...])
|
||||
save_message_for_edit_use_case(message=target_message)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user