actions: Modify check_message for handling wildcard_mention_policy setting.

This commit adds enforcement for sending messages containing wildcard
mentions according to wildcard_mention_policy.
This commit is contained in:
sahil839
2020-09-11 19:41:06 +05:30
committed by Tim Abbott
parent 25f32d461e
commit d0f5537fb2
5 changed files with 151 additions and 2 deletions

View File

@@ -105,6 +105,12 @@
{{> dropdown_options_widget option_values=invite_to_stream_policy_values}} {{> dropdown_options_widget option_values=invite_to_stream_policy_values}}
</select> </select>
</div> </div>
<div class="input-group">
<label for="realm_wildcard_mention_policy" class="dropdown-title">{{t "Who can use @all/@everyone mentions in large streams" }}</label>
<select name="realm_wildcard_mention_policy" id="id_realm_wildcard_mention_policy" class="prop-element" data-setting-widget-type="number">
{{> dropdown_options_widget option_values=wildcard_mention_policy_values}}
</select>
</div>
</div> </div>
</div> </div>

View File

@@ -103,6 +103,7 @@ from zerver.lib.message import (
truncate_body, truncate_body,
truncate_topic, truncate_topic,
update_first_visible_message_id, update_first_visible_message_id,
wildcard_mention_allowed,
) )
from zerver.lib.pysa import mark_sanitized from zerver.lib.pysa import mark_sanitized
from zerver.lib.queue import queue_json_publish from zerver.lib.queue import queue_json_publish
@@ -2416,7 +2417,12 @@ def check_message(sender: UserProfile, client: Client, addressee: Addressee,
message_dict = {'message': message, 'stream': stream, 'local_id': local_id, message_dict = {'message': message, 'stream': stream, 'local_id': local_id,
'sender_queue_id': sender_queue_id, 'realm': realm, 'sender_queue_id': sender_queue_id, 'realm': realm,
'widget_content': widget_content} 'widget_content': widget_content}
return build_message_send_dict(message_dict, email_gateway) message_send_dict = build_message_send_dict(message_dict, email_gateway)
if stream is not None and message_send_dict['message'].mentions_wildcard:
if not wildcard_mention_allowed(sender, stream):
raise JsonableError(_("You do not have permission to use wildcard mentions in this stream."))
return message_send_dict
def _internal_prep_message(realm: Realm, def _internal_prep_message(realm: Realm,
sender: UserProfile, sender: UserProfile,

View File

@@ -28,7 +28,10 @@ from zerver.lib.display_recipient import (
from zerver.lib.markdown import MentionData, markdown_convert, topic_links from zerver.lib.markdown import MentionData, markdown_convert, topic_links
from zerver.lib.markdown import version as markdown_version from zerver.lib.markdown import version as markdown_version
from zerver.lib.request import JsonableError from zerver.lib.request import JsonableError
from zerver.lib.stream_subscription import get_stream_subscriptions_for_user from zerver.lib.stream_subscription import (
get_stream_subscriptions_for_user,
num_subscribers_for_stream_id,
)
from zerver.lib.timestamp import datetime_to_timestamp from zerver.lib.timestamp import datetime_to_timestamp
from zerver.lib.topic import DB_TOPIC_NAME, MESSAGE__TOPIC, TOPIC_LINKS, TOPIC_NAME from zerver.lib.topic import DB_TOPIC_NAME, MESSAGE__TOPIC, TOPIC_LINKS, TOPIC_NAME
from zerver.lib.topic_mutes import build_topic_mute_checker, topic_is_muted from zerver.lib.topic_mutes import build_topic_mute_checker, topic_is_muted
@@ -1234,3 +1237,34 @@ def get_recent_private_conversations(user_profile: UserProfile) -> Dict[int, Dic
rec['user_ids'].sort() rec['user_ids'].sort()
return recipient_map return recipient_map
def wildcard_mention_allowed(sender: UserProfile, stream: Stream) -> bool:
realm = sender.realm
# If there are fewer than Realm.WILDCARD_MENTION_THRESHOLD, we
# allow sending. In the future, we may want to make this behavior
# a default, and also just allow explicitly setting whether this
# applies to a stream as an override.
if num_subscribers_for_stream_id(stream.id) <= Realm.WILDCARD_MENTION_THRESHOLD:
return True
if realm.wildcard_mention_policy == Realm.WILDCARD_MENTION_POLICY_NOBODY:
return False
if realm.wildcard_mention_policy == Realm.WILDCARD_MENTION_POLICY_EVERYONE:
return True
if realm.wildcard_mention_policy == Realm.WILDCARD_MENTION_POLICY_ADMINS:
return sender.is_realm_admin
if realm.wildcard_mention_policy == Realm.WILDCARD_MENTION_POLICY_STREAM_ADMINS:
# TODO: Change this when we implement stream administrators
return sender.is_realm_admin
if realm.wildcard_mention_policy == Realm.WILDCARD_MENTION_POLICY_FULL_MEMBERS:
return sender.is_realm_admin or (not sender.is_new_member and not sender.is_guest)
if realm.wildcard_mention_policy == Realm.WILDCARD_MENTION_POLICY_MEMBERS:
return not sender.is_guest
raise AssertionError("Invalid wildcard mention policy")

View File

@@ -178,6 +178,7 @@ class Realm(models.Model):
AUTHENTICATION_FLAGS = ['Google', 'Email', 'GitHub', 'LDAP', 'Dev', AUTHENTICATION_FLAGS = ['Google', 'Email', 'GitHub', 'LDAP', 'Dev',
'RemoteUser', 'AzureAD', 'SAML', 'GitLab', 'Apple'] 'RemoteUser', 'AzureAD', 'SAML', 'GitLab', 'Apple']
SUBDOMAIN_FOR_ROOT_DOMAIN = '' SUBDOMAIN_FOR_ROOT_DOMAIN = ''
WILDCARD_MENTION_THRESHOLD = 15
id: int = models.AutoField(auto_created=True, primary_key=True, verbose_name='ID') id: int = models.AutoField(auto_created=True, primary_key=True, verbose_name='ID')

View File

@@ -1325,6 +1325,108 @@ class StreamMessagesTest(ZulipTestCase):
self.assertEqual(user_message.message.content, content) self.assertEqual(user_message.message.content, content)
self.assertTrue(user_message.flags.mentioned) self.assertTrue(user_message.flags.mentioned)
def send_and_verify_wildcard_mention_message(self,
sender_name: str,
test_fails: bool=False,
sub_count: int=16) -> None:
sender = self.example_user(sender_name)
content = "@**all** test wildcard mention"
with mock.patch(
"zerver.lib.message.num_subscribers_for_stream_id", return_value=sub_count
):
if not test_fails:
msg_id = self.send_stream_message(sender, "test_stream", content)
result = self.api_get(sender, '/json/messages/' + str(msg_id))
self.assert_json_success(result)
else:
with self.assertRaisesRegex(JsonableError,
"You do not have permission to use wildcard mentions in this stream."):
self.send_stream_message(sender, "test_stream", content)
def test_wildcard_mention_restrictions(self) -> None:
cordelia = self.example_user("cordelia")
iago = self.example_user("iago")
polonius = self.example_user("polonius")
realm = cordelia.realm
stream_name = "test_stream"
self.subscribe(cordelia, stream_name)
self.subscribe(iago, stream_name)
self.subscribe(polonius, stream_name)
do_set_realm_property(
realm, "wildcard_mention_policy", Realm.WILDCARD_MENTION_POLICY_EVERYONE
)
self.send_and_verify_wildcard_mention_message("polonius")
do_set_realm_property(
realm, "wildcard_mention_policy", Realm.WILDCARD_MENTION_POLICY_MEMBERS
)
self.send_and_verify_wildcard_mention_message("polonius", test_fails=True)
# There is no restriction on small streams.
self.send_and_verify_wildcard_mention_message("polonius", sub_count=10)
self.send_and_verify_wildcard_mention_message("cordelia")
do_set_realm_property(
realm,
"wildcard_mention_policy",
Realm.WILDCARD_MENTION_POLICY_FULL_MEMBERS
)
do_set_realm_property(realm, "waiting_period_threshold", 10)
iago.date_joined = timezone_now()
iago.save()
cordelia.date_joined = timezone_now()
cordelia.save()
self.send_and_verify_wildcard_mention_message("cordelia", test_fails=True)
self.send_and_verify_wildcard_mention_message("cordelia", sub_count=10)
# Administrators can use wildcard mentions even if they are new.
self.send_and_verify_wildcard_mention_message("iago")
cordelia.date_joined = timezone_now() - datetime.timedelta(days=11)
cordelia.save()
self.send_and_verify_wildcard_mention_message("cordelia")
do_set_realm_property(
realm,
"wildcard_mention_policy",
Realm.WILDCARD_MENTION_POLICY_STREAM_ADMINS
)
# TODO: Change this when we implement stream administrators
self.send_and_verify_wildcard_mention_message("cordelia", test_fails=True)
# There is no restriction on small streams.
self.send_and_verify_wildcard_mention_message("cordelia", sub_count=10)
self.send_and_verify_wildcard_mention_message("iago")
cordelia.date_joined = timezone_now()
cordelia.save()
do_set_realm_property(
realm, "wildcard_mention_policy", Realm.WILDCARD_MENTION_POLICY_ADMINS
)
self.send_and_verify_wildcard_mention_message("cordelia", test_fails=True)
# There is no restriction on small streams.
self.send_and_verify_wildcard_mention_message("cordelia", sub_count=10)
self.send_and_verify_wildcard_mention_message("iago")
do_set_realm_property(
realm, "wildcard_mention_policy", Realm.WILDCARD_MENTION_POLICY_NOBODY
)
self.send_and_verify_wildcard_mention_message("iago", test_fails=True)
self.send_and_verify_wildcard_mention_message("iago", sub_count=10)
def test_invalid_wildcard_mention_policy(self) -> None:
cordelia = self.example_user("cordelia")
self.login_user(cordelia)
self.subscribe(cordelia, "test_stream")
do_set_realm_property(cordelia.realm, "wildcard_mention_policy", 10)
content = "@**all** test wildcard mention"
with mock.patch(
"zerver.lib.message.num_subscribers_for_stream_id", return_value=16
):
with self.assertRaisesRegex(AssertionError, "Invalid wildcard mention policy"):
self.send_stream_message(cordelia, "test_stream", content)
def test_stream_message_mirroring(self) -> None: def test_stream_message_mirroring(self) -> None:
user = self.mit_user('starnine') user = self.mit_user('starnine')
self.subscribe(user, 'Verona') self.subscribe(user, 'Verona')