[DINSIC] Block internal users from inviting external users to a public room (#5061)
Co-Authored-By: babolivier <contact@brendanabolivier.com>pull/5178/head
parent
7d71975e6a
commit
e6218e4880
|
|
@ -47,7 +47,7 @@ class SpamChecker(object):
|
|||
return self.spam_checker.check_event_for_spam(event)
|
||||
|
||||
def user_may_invite(self, inviter_userid, invitee_userid, third_party_invite,
|
||||
room_id, new_room):
|
||||
room_id, new_room, published_room):
|
||||
"""Checks if a given user may send an invite
|
||||
|
||||
If this method returns false, the invite will be rejected.
|
||||
|
|
@ -60,9 +60,12 @@ class SpamChecker(object):
|
|||
third_party_invite (dict|None): If a third party invite then is a
|
||||
dict containing the medium and address of the invitee.
|
||||
room_id (str)
|
||||
new_room (bool): Wether the user is being invited to the room as
|
||||
new_room (bool): Whether the user is being invited to the room as
|
||||
part of a room creation, if so the invitee would have been
|
||||
included in the call to `user_may_create_room`.
|
||||
published_room (bool): Whether the room the user is being invited
|
||||
to has been published in the local homeserver's public room
|
||||
directory.
|
||||
|
||||
Returns:
|
||||
bool: True if the user may send an invite, otherwise False
|
||||
|
|
@ -72,6 +75,7 @@ class SpamChecker(object):
|
|||
|
||||
return self.spam_checker.user_may_invite(
|
||||
inviter_userid, invitee_userid, third_party_invite, room_id, new_room,
|
||||
published_room,
|
||||
)
|
||||
|
||||
def user_may_create_room(self, userid, invite_list, third_party_invite_list,
|
||||
|
|
|
|||
|
|
@ -1340,9 +1340,12 @@ class FederationHandler(BaseHandler):
|
|||
if self.hs.config.block_non_admin_invites:
|
||||
raise SynapseError(403, "This server does not accept room invites")
|
||||
|
||||
is_published = yield self.store.is_room_published(event.room_id)
|
||||
|
||||
if not self.spam_checker.user_may_invite(
|
||||
event.sender, event.state_key, None,
|
||||
room_id=event.room_id, new_room=False,
|
||||
published_room=is_published,
|
||||
):
|
||||
raise SynapseError(
|
||||
403, "This user is not permitted to send invites to this server/user"
|
||||
|
|
|
|||
|
|
@ -426,11 +426,14 @@ class RoomMemberHandler(object):
|
|||
)
|
||||
block_invite = True
|
||||
|
||||
is_published = yield self.store.is_room_published(room_id)
|
||||
|
||||
if not self.spam_checker.user_may_invite(
|
||||
requester.user.to_string(), target.to_string(),
|
||||
third_party_invite=None,
|
||||
room_id=room_id,
|
||||
new_room=new_room,
|
||||
published_room=is_published,
|
||||
):
|
||||
logger.info("Blocking invite due to spam checker")
|
||||
block_invite = True
|
||||
|
|
@ -758,6 +761,8 @@ class RoomMemberHandler(object):
|
|||
id_server, medium, address
|
||||
)
|
||||
|
||||
is_published = yield self.store.is_room_published(room_id)
|
||||
|
||||
if not self.spam_checker.user_may_invite(
|
||||
requester.user.to_string(), invitee,
|
||||
third_party_invite={
|
||||
|
|
@ -766,6 +771,7 @@ class RoomMemberHandler(object):
|
|||
},
|
||||
room_id=room_id,
|
||||
new_room=new_room,
|
||||
published_room=is_published,
|
||||
):
|
||||
logger.info("Blocking invite due to spam checker")
|
||||
raise SynapseError(
|
||||
|
|
|
|||
|
|
@ -46,6 +46,10 @@ class DomainRuleChecker(object):
|
|||
# domain mapping rules above.
|
||||
can_only_invite_during_room_creation: false
|
||||
|
||||
# Prevent local users from inviting users from certain domains to
|
||||
# rooms published in the room directory.
|
||||
domains_prevented_from_being_invited_to_published_rooms: []
|
||||
|
||||
# Allow third party invites
|
||||
can_invite_by_third_party_id: true
|
||||
|
||||
|
|
@ -68,6 +72,9 @@ class DomainRuleChecker(object):
|
|||
self.can_invite_by_third_party_id = config.get(
|
||||
"can_invite_by_third_party_id", True,
|
||||
)
|
||||
self.domains_prevented_from_being_invited_to_published_rooms = config.get(
|
||||
"domains_prevented_from_being_invited_to_published_rooms", [],
|
||||
)
|
||||
|
||||
def check_event_for_spam(self, event):
|
||||
"""Implements synapse.events.SpamChecker.check_event_for_spam
|
||||
|
|
@ -75,7 +82,7 @@ class DomainRuleChecker(object):
|
|||
return False
|
||||
|
||||
def user_may_invite(self, inviter_userid, invitee_userid, third_party_invite,
|
||||
room_id, new_room):
|
||||
room_id, new_room, published_room=False):
|
||||
"""Implements synapse.events.SpamChecker.user_may_invite
|
||||
"""
|
||||
if self.can_only_invite_during_room_creation and not new_room:
|
||||
|
|
@ -95,6 +102,12 @@ class DomainRuleChecker(object):
|
|||
if inviter_domain not in self.domain_mapping:
|
||||
return self.default
|
||||
|
||||
if (
|
||||
published_room and
|
||||
invitee_domain in self.domains_prevented_from_being_invited_to_published_rooms
|
||||
):
|
||||
return False
|
||||
|
||||
return invitee_domain in self.domain_mapping[inviter_domain]
|
||||
|
||||
def user_may_create_room(self, userid, invite_list, third_party_invite_list,
|
||||
|
|
|
|||
|
|
@ -171,6 +171,24 @@ class RoomWorkerStore(SQLBaseStore):
|
|||
desc="is_room_blocked",
|
||||
)
|
||||
|
||||
@defer.inlineCallbacks
|
||||
def is_room_published(self, room_id):
|
||||
"""Check whether a room has been published in the local public room
|
||||
directory.
|
||||
|
||||
Args:
|
||||
room_id (str)
|
||||
Returns:
|
||||
bool: Whether the room is currently published in the room directory
|
||||
"""
|
||||
# Get room information
|
||||
room_info = yield self.get_room(room_id)
|
||||
if not room_info:
|
||||
defer.returnValue(False)
|
||||
|
||||
# Check the is_public value
|
||||
defer.returnValue(room_info.get("is_public", False))
|
||||
|
||||
@cachedInlineCallbacks(max_entries=10000)
|
||||
def get_ratelimit_for_user(self, user_id):
|
||||
"""Check if there are any overrides for ratelimiting for the given
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@ class DomainRuleCheckerTestCase(unittest.TestCase):
|
|||
"source_one": ["target_one", "target_two"],
|
||||
"source_two": ["target_two"],
|
||||
},
|
||||
"domains_prevented_from_being_invited_to_published_rooms": ["target_two"]
|
||||
}
|
||||
check = DomainRuleChecker(config)
|
||||
self.assertTrue(
|
||||
|
|
@ -50,6 +51,20 @@ class DomainRuleCheckerTestCase(unittest.TestCase):
|
|||
)
|
||||
)
|
||||
|
||||
# User can invite internal user to a published room
|
||||
self.assertTrue(
|
||||
check.user_may_invite(
|
||||
"test:source_one", "test1:target_one", None, "room", False, True,
|
||||
)
|
||||
)
|
||||
|
||||
# User can invite external user to a non-published room
|
||||
self.assertTrue(
|
||||
check.user_may_invite(
|
||||
"test:source_one", "test:target_two", None, "room", False, False,
|
||||
)
|
||||
)
|
||||
|
||||
def test_disallowed(self):
|
||||
config = {
|
||||
"default": True,
|
||||
|
|
@ -81,6 +96,13 @@ class DomainRuleCheckerTestCase(unittest.TestCase):
|
|||
)
|
||||
)
|
||||
|
||||
# User cannot invite external user to a published room
|
||||
self.assertTrue(
|
||||
check.user_may_invite(
|
||||
"test:source_one", "test:target_two", None, "room", False, True,
|
||||
)
|
||||
)
|
||||
|
||||
def test_default_allow(self):
|
||||
config = {
|
||||
"default": True,
|
||||
|
|
|
|||
Loading…
Reference in New Issue