diff --git a/synapse/events/spamcheck.py b/synapse/events/spamcheck.py index 87d66a9703..107c2e1f35 100644 --- a/synapse/events/spamcheck.py +++ b/synapse/events/spamcheck.py @@ -46,14 +46,19 @@ class SpamChecker(object): return self.spam_checker.check_event_for_spam(event) - def user_may_invite(self, inviter_userid, invitee_userid, room_id, new_room): + def user_may_invite(self, inviter_userid, invitee_userid, third_party_invite, + room_id, new_room): """Checks if a given user may send an invite If this method returns false, the invite will be rejected. Args: inviter_userid (str) - invitee_userid (str) + invitee_userid (str|None): The user ID of the invitee. Is None + if this is a third party invite and the 3PID is not bound to a + user ID. + invitee_userid (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 part of a room creation, if so the invitee would have been @@ -66,7 +71,7 @@ class SpamChecker(object): return True return self.spam_checker.user_may_invite( - inviter_userid, invitee_userid, room_id, new_room, + inviter_userid, invitee_userid, third_party_invite, room_id, new_room, ) def user_may_create_room(self, userid, invite_list, third_party_invite_list, diff --git a/synapse/handlers/federation.py b/synapse/handlers/federation.py index 1f799a04c1..c106fab0dc 100644 --- a/synapse/handlers/federation.py +++ b/synapse/handlers/federation.py @@ -1346,7 +1346,8 @@ class FederationHandler(BaseHandler): raise SynapseError(403, "This server does not accept room invites") if not self.spam_checker.user_may_invite( - event.sender, event.state_key, event.room_id, new_room=False, + event.sender, event.state_key, None, + room_id=event.room_id, new_room=False, ): raise SynapseError( 403, "This user is not permitted to send invites to this server/user" diff --git a/synapse/handlers/room.py b/synapse/handlers/room.py index a710b51c3d..6f5666e624 100644 --- a/synapse/handlers/room.py +++ b/synapse/handlers/room.py @@ -661,6 +661,7 @@ class RoomCreationHandler(BaseHandler): id_server, requester, txn_id=None, + new_room=True, ) result = {"room_id": room_id} diff --git a/synapse/handlers/room_member.py b/synapse/handlers/room_member.py index 645f615d74..ee7a390b1c 100644 --- a/synapse/handlers/room_member.py +++ b/synapse/handlers/room_member.py @@ -425,7 +425,9 @@ class RoomMemberHandler(object): block_invite = True if not self.spam_checker.user_may_invite( - requester.user.to_string(), target.to_string(), room_id, + requester.user.to_string(), target.to_string(), + third_party_invite=None, + room_id=room_id, new_room=new_room, ): logger.info("Blocking invite due to spam checker") @@ -728,7 +730,8 @@ class RoomMemberHandler(object): address, id_server, requester, - txn_id + txn_id, + new_room=False, ): if self.config.block_non_admin_invites: is_requester_admin = yield self.auth.is_server_admin( @@ -744,6 +747,20 @@ class RoomMemberHandler(object): id_server, medium, address ) + if not self.spam_checker.user_may_invite( + requester.user.to_string(), invitee, + third_party_invite={ + "medium": medium, + "address": address, + }, + room_id=room_id, + new_room=new_room, + ): + logger.info("Blocking invite due to spam checker") + raise SynapseError( + 403, "Invites have been disabled on this server", + ) + if invitee: yield self.update_membership( requester, diff --git a/synapse/rest/client/v1/room.py b/synapse/rest/client/v1/room.py index 48da4d557f..17a1503cdb 100644 --- a/synapse/rest/client/v1/room.py +++ b/synapse/rest/client/v1/room.py @@ -666,7 +666,8 @@ class RoomMembershipRestServlet(ClientV1RestServlet): content["address"], content["id_server"], requester, - txn_id + txn_id, + new_room=False, ) defer.returnValue((200, {})) return diff --git a/synapse/rulecheck/domain_rule_checker.py b/synapse/rulecheck/domain_rule_checker.py index 48ab62faac..b379bbc5b4 100644 --- a/synapse/rulecheck/domain_rule_checker.py +++ b/synapse/rulecheck/domain_rule_checker.py @@ -74,13 +74,19 @@ class DomainRuleChecker(object): """ return False - def user_may_invite(self, inviter_userid, invitee_userid, room_id, - new_room): + def user_may_invite(self, inviter_userid, invitee_userid, third_party_invite, + room_id, new_room): """Implements synapse.events.SpamChecker.user_may_invite """ if self.can_only_invite_during_room_creation and not new_room: return False + if not self.can_invite_by_third_party_id and third_party_invite: + return False + + if third_party_invite and not invitee_userid: + return True + inviter_domain = self._get_domain_from_id(inviter_userid) invitee_domain = self._get_domain_from_id(invitee_userid) diff --git a/tests/rulecheck/test_domainrulecheck.py b/tests/rulecheck/test_domainrulecheck.py index a887249b59..9c9f080f97 100644 --- a/tests/rulecheck/test_domainrulecheck.py +++ b/tests/rulecheck/test_domainrulecheck.py @@ -35,13 +35,15 @@ class DomainRuleCheckerTestCase(unittest.TestCase): } check = DomainRuleChecker(config) self.assertTrue( - check.user_may_invite("test:source_one", "test:target_one", "room", False) + check.user_may_invite( + "test:source_one", "test:target_one", None, "room", False, + ) ) self.assertTrue( - check.user_may_invite("test:source_one", "test:target_two", "room", False) + check.user_may_invite("test:source_one", "test:target_two", None, "room", False) ) self.assertTrue( - check.user_may_invite("test:source_two", "test:target_two", "room", False) + check.user_may_invite("test:source_two", "test:target_two", None, "room", False) ) def test_disallowed(self): @@ -55,16 +57,16 @@ class DomainRuleCheckerTestCase(unittest.TestCase): } check = DomainRuleChecker(config) self.assertFalse( - check.user_may_invite("test:source_one", "test:target_three", "room", False) + check.user_may_invite("test:source_one", "test:target_three", None, "room", False) ) self.assertFalse( - check.user_may_invite("test:source_two", "test:target_three", "room", False) + check.user_may_invite("test:source_two", "test:target_three", None, "room", False) ) self.assertFalse( - check.user_may_invite("test:source_two", "test:target_one", "room", False) + check.user_may_invite("test:source_two", "test:target_one", None, "room", False) ) self.assertFalse( - check.user_may_invite("test:source_four", "test:target_one", "room", False) + check.user_may_invite("test:source_four", "test:target_one", None, "room", False) ) def test_default_allow(self): @@ -77,7 +79,7 @@ class DomainRuleCheckerTestCase(unittest.TestCase): } check = DomainRuleChecker(config) self.assertTrue( - check.user_may_invite("test:source_three", "test:target_one", "room", False) + check.user_may_invite("test:source_three", "test:target_one", None, "room", False) ) def test_default_deny(self): @@ -90,7 +92,7 @@ class DomainRuleCheckerTestCase(unittest.TestCase): } check = DomainRuleChecker(config) self.assertFalse( - check.user_may_invite("test:source_three", "test:target_one", "room", False) + check.user_may_invite("test:source_three", "test:target_one", None, "room", False) ) def test_config_parse(self):