def validate_recipient_user_profiles( user_profiles: Sequence[UserProfile], sender: UserProfile, allow_deactivated: bool = False) -> Sequence[UserProfile]: recipient_profiles_map: Dict[int, UserProfile] = {} # We exempt cross-realm bots from the check that all the recipients # are in the same realm. realms = set() if not is_cross_realm_bot_email(sender.email): realms.add(sender.realm_id) for user_profile in user_profiles: if (not user_profile.is_active and not user_profile.is_mirror_dummy and not allow_deactivated) or user_profile.realm.deactivated: raise ValidationError( _("'{email}' is no longer using Zulip.").format( email=user_profile.email)) recipient_profiles_map[user_profile.id] = user_profile if not is_cross_realm_bot_email(user_profile.email): realms.add(user_profile.realm_id) if len(realms) > 1: raise ValidationError( _("You can't send private messages outside of your organization.")) return list(recipient_profiles_map.values())
def test_is_cross_realm_bot_email(self) -> None: self.assertTrue(is_cross_realm_bot_email("*****@*****.**")) self.assertTrue(is_cross_realm_bot_email("*****@*****.**")) self.assertFalse(is_cross_realm_bot_email("*****@*****.**")) with self.settings(CROSS_REALM_BOT_EMAILS={"*****@*****.**"}): self.assertTrue(is_cross_realm_bot_email("*****@*****.**")) self.assertFalse(is_cross_realm_bot_email("*****@*****.**"))
def test_is_cross_realm_bot_email(self) -> None: self.assertTrue(is_cross_realm_bot_email("*****@*****.**")) self.assertTrue(is_cross_realm_bot_email("*****@*****.**")) self.assertFalse(is_cross_realm_bot_email("*****@*****.**")) with self.settings(CROSS_REALM_BOT_EMAILS={"*****@*****.**"}): self.assertTrue(is_cross_realm_bot_email("*****@*****.**")) self.assertFalse(is_cross_realm_bot_email("*****@*****.**"))
def process_email(email: str) -> None: if is_cross_realm_bot_email(email): if verbose: msg = email_reserved_for_system_bots_error(email) else: msg = _("Reserved for system bots.") deactivated = False errors[email] = (msg, deactivated) return existing_user_profile = user_dict.get(email.lower()) if existing_user_profile is None: # HAPPY PATH! Most people invite users that don't exist yet. return if existing_user_profile.is_mirror_dummy: if existing_user_profile.is_active: raise AssertionError("Mirror dummy user is already active!") return """ Email has already been taken by a "normal" user. """ deactivated = not existing_user_profile.is_active if existing_user_profile.is_active: if verbose: msg = _("{email} already has an account").format(email=email) else: msg = _("Already has an account.") else: msg = _("Account has been deactivated.") errors[email] = (msg, deactivated)
def access_stream_for_send_message( sender: UserProfile, stream: Stream, forwarder_user_profile: Optional[UserProfile]) -> None: # Our caller is responsible for making sure that `stream` actually # matches the realm of the sender. # Organization admins can send to any stream, irrespective of the stream_post_policy value. if sender.is_realm_admin or is_cross_realm_bot_email( sender.delivery_email): pass elif sender.is_bot and (sender.bot_owner is not None and sender.bot_owner.is_realm_admin): pass elif stream.stream_post_policy == Stream.STREAM_POST_POLICY_ADMINS: raise JsonableError( _("Only organization administrators can send to this stream.")) elif stream.stream_post_policy != Stream.STREAM_POST_POLICY_EVERYONE and sender.is_guest: raise JsonableError(_("Guests cannot send to this stream.")) elif stream.stream_post_policy == Stream.STREAM_POST_POLICY_RESTRICT_NEW_MEMBERS: if sender.is_bot and (sender.bot_owner is not None and sender.bot_owner.is_new_member): raise JsonableError(_("New members cannot send to this stream.")) elif sender.is_new_member: raise JsonableError(_("New members cannot send to this stream.")) if stream.is_web_public: # Even guest users can write to web-public streams. return if not (stream.invite_only or sender.is_guest): # This is a public stream and sender is not a guest user return if subscribed_to_stream(sender, stream.id): # It is private, but your are subscribed return if sender.is_api_super_user: return if (forwarder_user_profile is not None and forwarder_user_profile.is_api_super_user): return if sender.is_bot and (sender.bot_owner is not None and subscribed_to_stream(sender.bot_owner, stream.id)): # Bots can send to any stream their owner can. return if sender.delivery_email == settings.WELCOME_BOT: # The welcome bot welcomes folks to the stream. return if sender.delivery_email == settings.NOTIFICATION_BOT: return # All other cases are an error. raise JsonableError( _("Not authorized to send to stream '{}'").format(stream.name))
def email_not_system_bot(email: str) -> None: if is_cross_realm_bot_email(email): msg = email_reserved_for_system_bots_error(email) code = msg raise ValidationError( msg, code=code, params=dict(deactivated=False), )
def access_stream_for_send_message( sender: UserProfile, stream: Stream, forwarder_user_profile: Optional[UserProfile] ) -> None: # Our caller is responsible for making sure that `stream` actually # matches the realm of the sender. try: check_stream_access_based_on_stream_post_policy(sender, stream) except JsonableError as e: if sender.is_bot and sender.bot_owner is not None: check_stream_access_based_on_stream_post_policy(sender.bot_owner, stream) else: raise JsonableError(e.msg) # forwarder_user_profile cases should be analyzed first, as incorrect # message forging is cause for denying access regardless of any other factors. if forwarder_user_profile is not None and forwarder_user_profile != sender: if ( forwarder_user_profile.can_forge_sender and forwarder_user_profile.realm_id == sender.realm_id and sender.realm_id == stream.realm_id ): return else: raise JsonableError(_("User not authorized for this query")) if is_cross_realm_bot_email(sender.delivery_email): return if stream.realm_id != sender.realm_id: # Sending to other realm's streams is always disallowed, # with the exception of cross-realm bots. raise JsonableError(_("User not authorized for this query")) if stream.is_web_public: # Even guest users can write to web-public streams. return if not (stream.invite_only or sender.is_guest): # This is a public stream and sender is not a guest user return if subscribed_to_stream(sender, stream.id): # It is private, but your are subscribed return if sender.can_forge_sender: # can_forge_sender allows sending to any stream in the realm. return if sender.is_bot and ( sender.bot_owner is not None and subscribed_to_stream(sender.bot_owner, stream.id) ): # Bots can send to any stream their owner can. return # All other cases are an error. raise JsonableError(_("Not authorized to send to stream '{}'").format(stream.name))
def create_attachment(file_name: str, path_id: str, user_profile: UserProfile, realm: Realm, file_size: int) -> bool: assert (user_profile.realm_id == realm.id) or is_cross_realm_bot_email( user_profile.delivery_email) attachment = Attachment.objects.create( file_name=file_name, path_id=path_id, owner=user_profile, realm=realm, size=file_size, ) from zerver.lib.actions import notify_attachment_update notify_attachment_update(user_profile, "add", attachment.to_dict()) return True
def delete_user_profile_caches(user_profiles: Iterable['UserProfile']) -> None: # Imported here to avoid cyclic dependency. from zerver.lib.users import get_all_api_keys from zerver.models import is_cross_realm_bot_email keys = [] for user_profile in user_profiles: keys.append(user_profile_by_email_cache_key(user_profile.delivery_email)) keys.append(user_profile_by_id_cache_key(user_profile.id)) for api_key in get_all_api_keys(user_profile): keys.append(user_profile_by_api_key_cache_key(api_key)) keys.append(user_profile_cache_key(user_profile.email, user_profile.realm)) if user_profile.is_bot and is_cross_realm_bot_email(user_profile.email): # Handle clearing system bots from their special cache. keys.append(bot_profile_cache_key(user_profile.email)) cache_delete_many(keys)
def check_stream_access_based_on_stream_post_policy(sender: UserProfile, stream: Stream) -> None: if sender.is_realm_admin or is_cross_realm_bot_email( sender.delivery_email): pass elif stream.stream_post_policy == Stream.STREAM_POST_POLICY_ADMINS: raise JsonableError( _("Only organization administrators can send to this stream.")) elif (stream.stream_post_policy == Stream.STREAM_POST_POLICY_MODERATORS and not sender.is_moderator): raise JsonableError( _("Only organization administrators and moderators can send to this stream." )) elif stream.stream_post_policy != Stream.STREAM_POST_POLICY_EVERYONE and sender.is_guest: raise JsonableError(_("Guests cannot send to this stream.")) elif (stream.stream_post_policy == Stream.STREAM_POST_POLICY_RESTRICT_NEW_MEMBERS and sender.is_provisional_member): raise JsonableError(_("New members cannot send to this stream.")) return