From b7d7d20a38b3ce21485c022c3162857a53d0beb8 Mon Sep 17 00:00:00 2001 From: Erik Johnston Date: Thu, 21 Mar 2019 12:11:40 +0000 Subject: [PATCH 1/6] Correctly handle 3PID invites in create room spam check We also add an option to outright deny third party invites --- synapse/events/spamcheck.py | 9 +++++++-- synapse/handlers/room.py | 5 +++-- synapse/rulecheck/domain_rule_checker.py | 16 ++++++++++++++-- tests/rulecheck/test_domainrulecheck.py | 15 +++++++++++++++ 4 files changed, 39 insertions(+), 6 deletions(-) diff --git a/synapse/events/spamcheck.py b/synapse/events/spamcheck.py index e4fc988cfc..87d66a9703 100644 --- a/synapse/events/spamcheck.py +++ b/synapse/events/spamcheck.py @@ -69,7 +69,8 @@ class SpamChecker(object): inviter_userid, invitee_userid, room_id, new_room, ) - def user_may_create_room(self, userid, invite_list, cloning): + def user_may_create_room(self, userid, invite_list, third_party_invite_list, + cloning): """Checks if a given user may create a room If this method returns false, the creation request will be rejected. @@ -78,6 +79,8 @@ class SpamChecker(object): userid (string): The sender's user ID invite_list (list[str]): List of user IDs that would be invited to the new room. + third_party_invite_list (list[dict]): List of third party invites + for the new room. cloning (bool): Whether the user is cloning an existing room, e.g. upgrading a room. @@ -87,7 +90,9 @@ class SpamChecker(object): if self.spam_checker is None: return True - return self.spam_checker.user_may_create_room(userid, invite_list, cloning) + return self.spam_checker.user_may_create_room( + userid, invite_list, third_party_invite_list, cloning, + ) def user_may_create_room_alias(self, userid, room_alias): """Checks if a given user may create a room alias diff --git a/synapse/handlers/room.py b/synapse/handlers/room.py index 581cff9526..a710b51c3d 100644 --- a/synapse/handlers/room.py +++ b/synapse/handlers/room.py @@ -269,6 +269,7 @@ class RoomCreationHandler(BaseHandler): if not is_requester_admin and not self.spam_checker.user_may_create_room( user_id, invite_list=[], + third_party_invite_list=[], cloning=True, ): raise SynapseError(403, "You are not permitted to create rooms") @@ -492,6 +493,7 @@ class RoomCreationHandler(BaseHandler): yield self.auth.check_auth_blocking(user_id) invite_list = config.get("invite", []) + invite_3pid_list = config.get("invite_3pid", []) if (self._server_notices_mxid is not None and requester.user.to_string() == self._server_notices_mxid): @@ -505,6 +507,7 @@ class RoomCreationHandler(BaseHandler): if not is_requester_admin and not self.spam_checker.user_may_create_room( user_id, invite_list=invite_list, + third_party_invite_list=invite_3pid_list, cloning=False, ): raise SynapseError(403, "You are not permitted to create rooms") @@ -559,8 +562,6 @@ class RoomCreationHandler(BaseHandler): requester, ) - invite_3pid_list = config.get("invite_3pid", []) - visibility = config.get("visibility", None) is_public = visibility == "public" diff --git a/synapse/rulecheck/domain_rule_checker.py b/synapse/rulecheck/domain_rule_checker.py index 410757041b..48ab62faac 100644 --- a/synapse/rulecheck/domain_rule_checker.py +++ b/synapse/rulecheck/domain_rule_checker.py @@ -46,6 +46,9 @@ class DomainRuleChecker(object): # domain mapping rules above. can_only_invite_during_room_creation: false + # Allow third party invites + can_invite_by_third_party_id: true + Don't forget to consider if you can invite users from your own domain. """ @@ -62,6 +65,9 @@ class DomainRuleChecker(object): self.can_only_invite_during_room_creation = config.get( "can_only_invite_during_room_creation", False, ) + self.can_invite_by_third_party_id = config.get( + "can_invite_by_third_party_id", True, + ) def check_event_for_spam(self, event): """Implements synapse.events.SpamChecker.check_event_for_spam @@ -83,14 +89,20 @@ class DomainRuleChecker(object): return invitee_domain in self.domain_mapping[inviter_domain] - def user_may_create_room(self, userid, invite_list, cloning): + def user_may_create_room(self, userid, invite_list, third_party_invite_list, + cloning): """Implements synapse.events.SpamChecker.user_may_create_room """ if cloning: return True - if self.can_only_create_one_to_one_rooms and len(invite_list) != 1: + if not self.can_invite_by_third_party_id and third_party_invite_list: + return False + + number_of_invites = len(invite_list) + len(third_party_invite_list) + + if self.can_only_create_one_to_one_rooms and number_of_invites != 1: return False return True diff --git a/tests/rulecheck/test_domainrulecheck.py b/tests/rulecheck/test_domainrulecheck.py index de89f95e3c..a887249b59 100644 --- a/tests/rulecheck/test_domainrulecheck.py +++ b/tests/rulecheck/test_domainrulecheck.py @@ -131,6 +131,7 @@ class DomainRuleCheckerRoomTestCase(unittest.HomeserverTestCase): "can_only_join_rooms_with_invite": True, "can_only_create_one_to_one_rooms": True, "can_only_invite_during_room_creation": True, + "can_invite_by_third_party_id": False, }) hs = self.setup_test_homeserver(config=config) @@ -159,6 +160,20 @@ class DomainRuleCheckerRoomTestCase(unittest.HomeserverTestCase): }) assert channel.result["code"] == b"403", channel.result + # Test that it correctly counts both normal and third party invites + channel = self._create_room(self.normal_access_token, content={ + "invite": [self.other_user_id], + "invite_3pid": [{"medium": "email", "address": "foo@example.com"}], + }) + assert channel.result["code"] == b"403", channel.result + + # Test that it correctly rejects third party invites + channel = self._create_room(self.normal_access_token, content={ + "invite": [], + "invite_3pid": [{"medium": "email", "address": "foo@example.com"}], + }) + assert channel.result["code"] == b"403", channel.result + def test_normal_user_can_room_with_single_invites(self): channel = self._create_room(self.normal_access_token, content={ "invite": [self.other_user_id], From 164798ec32a30e07bd5972ec216e7848f0928c78 Mon Sep 17 00:00:00 2001 From: Erik Johnston Date: Thu, 21 Mar 2019 12:25:33 +0000 Subject: [PATCH 2/6] Add 3PID invite support to spam checker --- synapse/events/spamcheck.py | 11 ++++++++--- synapse/handlers/federation.py | 3 ++- synapse/handlers/room.py | 1 + synapse/handlers/room_member.py | 21 +++++++++++++++++++-- synapse/rest/client/v1/room.py | 3 ++- synapse/rulecheck/domain_rule_checker.py | 10 ++++++++-- tests/rulecheck/test_domainrulecheck.py | 20 +++++++++++--------- 7 files changed, 51 insertions(+), 18 deletions(-) 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): From f04ee0b351902c42225d71adfc6c88f3f2118b29 Mon Sep 17 00:00:00 2001 From: Erik Johnston Date: Thu, 21 Mar 2019 12:26:07 +0000 Subject: [PATCH 3/6] Run black on tests/rulecheck/ --- tests/rulecheck/test_domainrulecheck.py | 108 ++++++++++++++---------- 1 file changed, 64 insertions(+), 44 deletions(-) diff --git a/tests/rulecheck/test_domainrulecheck.py b/tests/rulecheck/test_domainrulecheck.py index 9c9f080f97..38a14221cd 100644 --- a/tests/rulecheck/test_domainrulecheck.py +++ b/tests/rulecheck/test_domainrulecheck.py @@ -36,14 +36,18 @@ class DomainRuleCheckerTestCase(unittest.TestCase): check = DomainRuleChecker(config) self.assertTrue( check.user_may_invite( - "test:source_one", "test:target_one", None, "room", False, + "test:source_one", "test:target_one", None, "room", False ) ) self.assertTrue( - check.user_may_invite("test:source_one", "test:target_two", None, "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", None, "room", False) + check.user_may_invite( + "test:source_two", "test:target_two", None, "room", False + ) ) def test_disallowed(self): @@ -57,16 +61,24 @@ class DomainRuleCheckerTestCase(unittest.TestCase): } check = DomainRuleChecker(config) self.assertFalse( - check.user_may_invite("test:source_one", "test:target_three", None, "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", None, "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", None, "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", None, "room", False) + check.user_may_invite( + "test:source_four", "test:target_one", None, "room", False + ) ) def test_default_allow(self): @@ -79,7 +91,9 @@ class DomainRuleCheckerTestCase(unittest.TestCase): } check = DomainRuleChecker(config) self.assertTrue( - check.user_may_invite("test:source_three", "test:target_one", None, "room", False) + check.user_may_invite( + "test:source_three", "test:target_one", None, "room", False + ) ) def test_default_deny(self): @@ -92,7 +106,9 @@ class DomainRuleCheckerTestCase(unittest.TestCase): } check = DomainRuleChecker(config) self.assertFalse( - check.user_may_invite("test:source_three", "test:target_one", None, "room", False) + check.user_may_invite( + "test:source_three", "test:target_one", None, "room", False + ) ) def test_config_parse(self): @@ -127,14 +143,17 @@ class DomainRuleCheckerRoomTestCase(unittest.HomeserverTestCase): def make_homeserver(self, reactor, clock): config = self.default_config() - config.spam_checker = (DomainRuleChecker, { - "default": True, - "domain_mapping": {}, - "can_only_join_rooms_with_invite": True, - "can_only_create_one_to_one_rooms": True, - "can_only_invite_during_room_creation": True, - "can_invite_by_third_party_id": False, - }) + config.spam_checker = ( + DomainRuleChecker, + { + "default": True, + "domain_mapping": {}, + "can_only_join_rooms_with_invite": True, + "can_only_create_one_to_one_rooms": True, + "can_only_invite_during_room_creation": True, + "can_invite_by_third_party_id": False, + }, + ) hs = self.setup_test_homeserver(config=config) return hs @@ -157,29 +176,36 @@ class DomainRuleCheckerRoomTestCase(unittest.HomeserverTestCase): assert channel.result["code"] == b"403", channel.result def test_normal_user_cannot_create_room_with_multiple_invites(self): - channel = self._create_room(self.normal_access_token, content={ - "invite": [self.other_user_id, self.admin_user_id], - }) + channel = self._create_room( + self.normal_access_token, + content={"invite": [self.other_user_id, self.admin_user_id]}, + ) assert channel.result["code"] == b"403", channel.result # Test that it correctly counts both normal and third party invites - channel = self._create_room(self.normal_access_token, content={ - "invite": [self.other_user_id], - "invite_3pid": [{"medium": "email", "address": "foo@example.com"}], - }) + channel = self._create_room( + self.normal_access_token, + content={ + "invite": [self.other_user_id], + "invite_3pid": [{"medium": "email", "address": "foo@example.com"}], + }, + ) assert channel.result["code"] == b"403", channel.result # Test that it correctly rejects third party invites - channel = self._create_room(self.normal_access_token, content={ - "invite": [], - "invite_3pid": [{"medium": "email", "address": "foo@example.com"}], - }) + channel = self._create_room( + self.normal_access_token, + content={ + "invite": [], + "invite_3pid": [{"medium": "email", "address": "foo@example.com"}], + }, + ) assert channel.result["code"] == b"403", channel.result def test_normal_user_can_room_with_single_invites(self): - channel = self._create_room(self.normal_access_token, content={ - "invite": [self.other_user_id], - }) + channel = self._create_room( + self.normal_access_token, content={"invite": [self.other_user_id]} + ) assert channel.result["code"] == b"200", channel.result def test_cannot_join_public_room(self): @@ -189,9 +215,7 @@ class DomainRuleCheckerRoomTestCase(unittest.HomeserverTestCase): room_id = channel.json_body["room_id"] self.helper.join( - room_id, self.normal_user_id, - tok=self.normal_access_token, - expect_code=403, + room_id, self.normal_user_id, tok=self.normal_access_token, expect_code=403 ) def test_can_join_invited_room(self): @@ -208,9 +232,7 @@ class DomainRuleCheckerRoomTestCase(unittest.HomeserverTestCase): ) self.helper.join( - room_id, self.normal_user_id, - tok=self.normal_access_token, - expect_code=200, + room_id, self.normal_user_id, tok=self.normal_access_token, expect_code=200 ) def test_cannot_invite(self): @@ -227,9 +249,7 @@ class DomainRuleCheckerRoomTestCase(unittest.HomeserverTestCase): ) self.helper.join( - room_id, self.normal_user_id, - tok=self.normal_access_token, - expect_code=200, + room_id, self.normal_user_id, tok=self.normal_access_token, expect_code=200 ) self.helper.invite( @@ -241,12 +261,12 @@ class DomainRuleCheckerRoomTestCase(unittest.HomeserverTestCase): ) def _create_room(self, token, content={}): - path = "/_matrix/client/r0/createRoom?access_token=%s" % ( - token, - ) + path = "/_matrix/client/r0/createRoom?access_token=%s" % (token,) request, channel = make_request( - self.hs.get_reactor(), "POST", path, + self.hs.get_reactor(), + "POST", + path, content=json.dumps(content).encode("utf8"), ) render(request, self.resource, self.hs.get_reactor()) From 479b7b1effadf8d571f30d111d33bc895409b5d7 Mon Sep 17 00:00:00 2001 From: Erik Johnston Date: Thu, 21 Mar 2019 12:38:25 +0000 Subject: [PATCH 4/6] Add another test --- tests/rulecheck/test_domainrulecheck.py | 42 +++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/tests/rulecheck/test_domainrulecheck.py b/tests/rulecheck/test_domainrulecheck.py index 38a14221cd..803d680cec 100644 --- a/tests/rulecheck/test_domainrulecheck.py +++ b/tests/rulecheck/test_domainrulecheck.py @@ -260,6 +260,48 @@ class DomainRuleCheckerRoomTestCase(unittest.HomeserverTestCase): expect_code=403, ) + def test_cannot_3pid_invite(self): + """Test that unbound 3pid invites get rejected. + """ + channel = self._create_room(self.admin_access_token) + assert channel.result["code"] == b"200", channel.result + + room_id = channel.json_body["room_id"] + + self.helper.invite( + room_id, + src=self.admin_user_id, + targ=self.normal_user_id, + tok=self.admin_access_token, + ) + + self.helper.join( + room_id, self.normal_user_id, + tok=self.normal_access_token, + expect_code=200, + ) + + self.helper.invite( + room_id, + src=self.normal_user_id, + targ=self.other_user_id, + tok=self.normal_access_token, + expect_code=403, + ) + + request, channel = self.make_request( + "POST", + "rooms/%s/invite" % (room_id), + { + "address": "foo@bar.com", + "medium": "email", + "id_server": "localhost" + }, + access_token=self.normal_access_token, + ) + self.render(request) + self.assertEqual(channel.code, 403, channel.result["body"]) + def _create_room(self, token, content={}): path = "/_matrix/client/r0/createRoom?access_token=%s" % (token,) From aefb7a1146e554db6be59fc820ea06c93fcd5e81 Mon Sep 17 00:00:00 2001 From: Erik Johnston Date: Thu, 21 Mar 2019 12:52:22 +0000 Subject: [PATCH 5/6] Update sample config --- docs/sample_config.yaml | 52 ++++++++++++++++++++++++++++++++ synapse/config/user_directory.py | 5 ++- 2 files changed, 54 insertions(+), 3 deletions(-) diff --git a/docs/sample_config.yaml b/docs/sample_config.yaml index 4ada0fba0e..73d02a63fc 100644 --- a/docs/sample_config.yaml +++ b/docs/sample_config.yaml @@ -654,9 +654,27 @@ uploads_path: "DATADIR/uploads" # #disable_msisdn_registration: true +# Derive the user's matrix ID from a type of 3PID used when registering. +# This overrides any matrix ID the user proposes when calling /register +# The 3PID type should be present in registrations_require_3pid to avoid +# users failing to register if they don't specify the right kind of 3pid. +# +#register_mxid_from_3pid: email + # Mandate that users are only allowed to associate certain formats of # 3PIDs with accounts on this server. # +# Use an Identity Server to establish which 3PIDs are allowed to register? +# Overrides allowed_local_3pids below. +# +#check_is_for_allowed_local_3pids: matrix.org +# +# If you are using an IS you can also check whether that IS registers +# pending invites for the given 3PID (and then allow it to sign up on +# the platform): +# +#allow_invited_3pids: False +# #allowed_local_3pids: # - medium: email # pattern: '.*@matrix\.org' @@ -665,6 +683,11 @@ uploads_path: "DATADIR/uploads" # - medium: msisdn # pattern: '\+44' +# If true, stop users from trying to change the 3PIDs associated with +# their accounts. +# +#disable_3pid_changes: False + # If set, allows registration of standard or admin accounts by anyone who # has the shared secret, even if registration is otherwise disabled. # @@ -702,6 +725,30 @@ uploads_path: "DATADIR/uploads" # - matrix.org # - vector.im +# If enabled, user IDs, display names and avatar URLs will be replicated +# to this server whenever they change. +# This is an experimental API currently implemented by sydent to support +# cross-homeserver user directories. +# +#replicate_user_profiles_to: example.com + +# If specified, attempt to replay registrations, profile changes & 3pid +# bindings on the given target homeserver via the AS API. The HS is authed +# via a given AS token. +# +#shadow_server: +# hs_url: https://shadow.example.com +# hs: shadow.example.com +# as_token: 12u394refgbdhivsia + +# If enabled, don't let users set their own display names/avatars +# other than for the very first time (unless they are a server admin). +# Useful when provisioning users based on the contents of a 3rd party +# directory and to avoid ambiguities. +# +#disable_set_displayname: False +#disable_set_avatar_url: False + # Users who register on this homeserver will automatically be joined # to these rooms # @@ -975,6 +1022,11 @@ password_config: #user_directory: # enabled: true # search_all_users: false +# +# # If this is set, user search will be delegated to this ID server instead +# # of synapse performing the search itself. +# # This is an experimental API. +# defer_to_id_server: https://id.example.com # User Consent configuration diff --git a/synapse/config/user_directory.py b/synapse/config/user_directory.py index 7abf40f37d..56eff15ef8 100644 --- a/synapse/config/user_directory.py +++ b/synapse/config/user_directory.py @@ -52,9 +52,8 @@ class UserDirectoryConfig(Config): # on your database to tell it to rebuild the user_directory search indexes. # #user_directory: - # enabled: true - # - # search_all_users: false + # enabled: true + # search_all_users: false # # # If this is set, user search will be delegated to this ID server instead # # of synapse performing the search itself. From f5c944c7f24ebdd6353b64bb8ee339f8a4942a1b Mon Sep 17 00:00:00 2001 From: Erik Johnston Date: Thu, 21 Mar 2019 15:31:31 +0000 Subject: [PATCH 6/6] Fix comments --- synapse/events/spamcheck.py | 4 ++-- synapse/rulecheck/domain_rule_checker.py | 4 +++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/synapse/events/spamcheck.py b/synapse/events/spamcheck.py index 107c2e1f35..92aaa05e79 100644 --- a/synapse/events/spamcheck.py +++ b/synapse/events/spamcheck.py @@ -57,8 +57,8 @@ class SpamChecker(object): 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. + 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 part of a room creation, if so the invitee would have been diff --git a/synapse/rulecheck/domain_rule_checker.py b/synapse/rulecheck/domain_rule_checker.py index b379bbc5b4..bcec465ef4 100644 --- a/synapse/rulecheck/domain_rule_checker.py +++ b/synapse/rulecheck/domain_rule_checker.py @@ -84,7 +84,9 @@ class DomainRuleChecker(object): if not self.can_invite_by_third_party_id and third_party_invite: return False - if third_party_invite and not invitee_userid: + # This is a third party invite (without a bound mxid), so unless we have + # banned all third party invites (above) we allow it. + if not invitee_userid: return True inviter_domain = self._get_domain_from_id(inviter_userid)