def make_homeserver(self, reactor, clock): self.hs = self.setup_test_homeserver() self.service = ApplicationService( id="unique_identifier", token="some_token", hostname="example.com", sender="@asbot:example.com", namespaces={ ApplicationService.NS_USERS: [{ "regex": r"@as_user.*", "exclusive": False }], ApplicationService.NS_ROOMS: [], ApplicationService.NS_ALIASES: [], }, ) self.another_service = ApplicationService( id="another__identifier", token="another_token", hostname="example.com", sender="@as2bot:example.com", namespaces={ ApplicationService.NS_USERS: [{ "regex": r"@as2_user.*", "exclusive": False }], ApplicationService.NS_ROOMS: [], ApplicationService.NS_ALIASES: [], }, ) self.hs.get_datastore().services_cache.append(self.service) self.hs.get_datastore().services_cache.append(self.another_service) return self.hs
async def _do_appservice_login(self, login_submission: JsonDict, appservice: ApplicationService): identifier = login_submission.get("identifier") logger.info("Got appservice login request with identifier: %r", identifier) if not isinstance(identifier, dict): raise SynapseError(400, "Invalid identifier in login submission", Codes.INVALID_PARAM) # this login flow only supports identifiers of type "m.id.user". if identifier.get("type") != "m.id.user": raise SynapseError(400, "Unknown login identifier type", Codes.INVALID_PARAM) user = identifier.get("user") if not isinstance(user, str): raise SynapseError(400, "Invalid user in identifier", Codes.INVALID_PARAM) if user.startswith("@"): qualified_user_id = user else: qualified_user_id = UserID(user, self.hs.hostname).to_string() if not appservice.is_interested_in_user(qualified_user_id): raise LoginError(403, "Invalid access_token", errcode=Codes.FORBIDDEN) return await self._complete_login( qualified_user_id, login_submission, ratelimit=appservice.is_rate_limited())
def setUp(self): self.service = ApplicationService(url="some_url", token="some_token", namespaces={ ApplicationService.NS_USERS: [], ApplicationService.NS_ROOMS: [], ApplicationService.NS_ALIASES: [] }) self.event = Mock(type="m.something", room_id="!foo:bar", sender="@someone:somewhere")
def setUp(self): self.service = ApplicationService( id="unique_identifier", sender="@as:test", url="some_url", token="some_token", hostname="matrix.org", # only used by get_groups_for_user ) self.event = Mock(type="m.something", room_id="!foo:bar", sender="@someone:somewhere") self.store = Mock()
def test_allowed_appservice_ratelimited_via_can_requester_do_action(self): appservice = ApplicationService( None, "example.com", id="foo", rate_limited=True, sender="@as:example.com", ) as_requester = create_requester("@user:example.com", app_service=appservice) limiter = Ratelimiter(clock=None, rate_hz=0.1, burst_count=1) allowed, time_allowed = limiter.can_requester_do_action(as_requester, _time_now_s=0) self.assertTrue(allowed) self.assertEquals(10.0, time_allowed) allowed, time_allowed = limiter.can_requester_do_action(as_requester, _time_now_s=5) self.assertFalse(allowed) self.assertEquals(10.0, time_allowed) allowed, time_allowed = limiter.can_requester_do_action(as_requester, _time_now_s=10) self.assertTrue(allowed) self.assertEquals(20.0, time_allowed)
def test_GET_whoami_appservices(self): user_id = "@as:test" as_token = "i_am_an_app_service" appservice = ApplicationService( as_token, self.hs.config.server.server_name, id="1234", namespaces={"users": [{ "regex": user_id, "exclusive": True }]}, sender=user_id, ) self.hs.get_datastore().services_cache.append(appservice) whoami = self._whoami(as_token) self.assertEqual( whoami, { "user_id": user_id, # Unstable until MSC3069 enters spec "org.matrix.msc3069.is_guest": False, }, ) self.assertFalse(hasattr(whoami, "device_id"))
def test_blocking_mau__appservice_requester_disallowed_when_tracking_ips( self): self.auth_blocking._max_mau_value = 50 self.auth_blocking._limit_usage_by_mau = True self.auth_blocking._track_appservice_user_ips = True self.store.get_monthly_active_count = simple_async_mock(100) self.store.user_last_seen_monthly_active = simple_async_mock() self.store.is_trial_user = simple_async_mock() appservice = ApplicationService( "abcd", self.hs.config.server.server_name, id="1234", namespaces={ "users": [{ "regex": "@_appservice.*:sender", "exclusive": True }] }, sender="@appservice:sender", ) requester = Requester( user="******", access_token_id=None, device_id="FOOBAR", is_guest=False, shadow_banned=False, app_service=appservice, authenticated_entity="@appservice:server", ) self.get_failure(self.auth.check_auth_blocking(requester=requester), ResourceLimitError)
def test_POST_appservice_registration_valid(self): user_id = "@as_user_kermit:test" as_token = "i_am_an_app_service" appservice = ApplicationService( as_token, self.hs.config.server.server_name, id="1234", namespaces={ "users": [{ "regex": r"@as_user.*", "exclusive": True }] }, sender="@as:test", ) self.hs.get_datastore().services_cache.append(appservice) request_data = json.dumps({ "username": "******", "type": APP_SERVICE_REGISTRATION_TYPE }) channel = self.make_request( b"POST", self.url + b"?access_token=i_am_an_app_service", request_data) self.assertEquals(channel.result["code"], b"200", channel.result) det_data = {"user_id": user_id, "home_server": self.hs.hostname} self.assertDictContainsSubset(det_data, channel.json_body)
def setUp(self): self.service = ApplicationService( id="unique_identifier", url="some_url", token="some_token", hostname="matrix.org", # only used by get_groups_for_user namespaces={ ApplicationService.NS_USERS: [], ApplicationService.NS_ROOMS: [], ApplicationService.NS_ALIASES: [] }) self.event = Mock(type="m.something", room_id="!foo:bar", sender="@someone:somewhere") self.store = Mock()
async def validate_appservice_can_control_user_id( self, app_service: ApplicationService, user_id: str): """Validates that the app service is allowed to control the given user. Args: app_service: The app service that controls the user user_id: The author MXID that the app service is controlling Raises: AuthError: If the application service is not allowed to control the user (user namespace regex does not match, wrong homeserver, etc) or if the user has not been registered yet. """ # It's ok if the app service is trying to use the sender from their registration if app_service.sender == user_id: pass # Check to make sure the app service is allowed to control the user elif not app_service.is_interested_in_user(user_id): raise AuthError( 403, "Application service cannot masquerade as this user (%s)." % user_id, ) # Check to make sure the user is already registered on the homeserver elif not (await self.store.get_user_by_id(user_id)): raise AuthError( 403, "Application service has not registered this user (%s)" % user_id)
def test_allowed_appservice_via_can_requester_do_action(self): appservice = ApplicationService( None, "example.com", id="foo", rate_limited=False, sender="@as:example.com", ) as_requester = create_requester("@user:example.com", app_service=appservice) limiter = Ratelimiter( store=self.hs.get_datastore(), clock=None, rate_hz=0.1, burst_count=1 ) allowed, time_allowed = self.get_success_or_raise( limiter.can_do_action(as_requester, _time_now_s=0) ) self.assertTrue(allowed) self.assertEquals(-1, time_allowed) allowed, time_allowed = self.get_success_or_raise( limiter.can_do_action(as_requester, _time_now_s=5) ) self.assertTrue(allowed) self.assertEquals(-1, time_allowed) allowed, time_allowed = self.get_success_or_raise( limiter.can_do_action(as_requester, _time_now_s=10) ) self.assertTrue(allowed) self.assertEquals(-1, time_allowed)
def test_update_and_retrieval_of_service(self): url = "https://matrix.org/appservices/foobar" hs_token = "hstok" user_regex = ["@foobar_.*:matrix.org"] alias_regex = ["#foobar_.*:matrix.org"] room_regex = [] service = ApplicationService(url=url, hs_token=hs_token, token=self.as_token, namespaces={ ApplicationService.NS_USERS: user_regex, ApplicationService.NS_ALIASES: alias_regex, ApplicationService.NS_ROOMS: room_regex }) yield self.store.update_app_service(service) stored_service = yield self.store.get_app_service_by_token( self.as_token) self.assertEquals(stored_service.token, self.as_token) self.assertEquals(stored_service.url, url) self.assertEquals( stored_service.namespaces[ApplicationService.NS_ALIASES], alias_regex) self.assertEquals( stored_service.namespaces[ApplicationService.NS_ROOMS], room_regex) self.assertEquals( stored_service.namespaces[ApplicationService.NS_USERS], user_regex)
def _register_application_service( self, namespaces: Optional[Dict[str, Iterable[Dict]]] = None, ) -> ApplicationService: """ Register a new application service, with the given namespaces of interest. Args: namespaces: A dictionary containing any user, room or alias namespaces that the application service is interested in. Returns: The registered application service. """ # Create an application service appservice = ApplicationService( token=random_string(10), id=random_string(10), sender="@as:example.com", rate_limited=False, namespaces=namespaces, supports_ephemeral=True, ) # Register the application service self._services.append(appservice) return appservice
def make_homeserver(self, reactor: MemoryReactor, clock: Clock) -> HomeServer: config = self.default_config() config["update_user_directory"] = True self.appservice = ApplicationService( token="i_am_an_app_service", id="1234", namespaces={ "users": [{ "regex": r"@as_user.*", "exclusive": True }] }, # Note: this user does not match the regex above, so that tests # can distinguish the sender from the AS user. sender="@as_main:test", ) mock_load_appservices = Mock(return_value=[self.appservice]) with patch( "synapse.storage.databases.main.appservice.load_appservices", mock_load_appservices, ): hs = self.setup_test_homeserver(config=config) return hs
def setUp(self): self.service = ApplicationService( id="unique_identifier", sender="@as:test", url="some_url", token="some_token", ) self.event = Mock( event_id="$abc:xyz", type="m.something", room_id="!foo:bar", sender="@someone:somewhere", ) self.store = Mock() self.store.get_aliases_for_room = simple_async_mock([]) self.store.get_users_in_room = simple_async_mock([])
def prepare(self, reactor: MemoryReactor, clock: Clock, hs: HomeServer): self.api = hs.get_application_service_api() self.service = ApplicationService( id="unique_identifier", sender="@as:test", url=URL, token="unused", hs_token=TOKEN, )
def _parse_services_dict(self, results): # SQL results in the form: # [ # { # 'regex': "something", # 'url': "something", # 'namespace': enum, # 'as_id': 0, # 'token': "something", # 'hs_token': "otherthing", # 'id': 0 # } # ] services = {} for res in results: as_token = res["token"] if as_token is None: continue if as_token not in services: # add the service services[as_token] = { "id": res["id"], "url": res["url"], "token": as_token, "hs_token": res["hs_token"], "sender": res["sender"], "namespaces": { ApplicationService.NS_USERS: [], ApplicationService.NS_ALIASES: [], ApplicationService.NS_ROOMS: [] } } # add the namespace regex if one exists ns_int = res["namespace"] if ns_int is None: continue try: services[as_token]["namespaces"][ ApplicationService.NS_LIST[ns_int]].append( json.loads(res["regex"]) ) except IndexError: logger.error("Bad namespace enum '%s'. %s", ns_int, res) except JSONDecodeError: logger.error("Bad regex object '%s'", res["regex"]) service_list = [] for service in services.values(): service_list.append(ApplicationService( token=service["token"], url=service["url"], namespaces=service["namespaces"], hs_token=service["hs_token"], sender=service["sender"], id=service["id"] )) return service_list
async def delete_appservice_association(self, service: ApplicationService, room_alias: RoomAlias) -> None: if not service.is_interested_in_alias(room_alias.to_string()): raise SynapseError( 400, "This application service has not reserved this kind of alias", errcode=Codes.EXCLUSIVE, ) await self._delete_association(room_alias)
def _populate_cache(self): """Populates the ApplicationServiceCache from the database.""" sql = ("SELECT * FROM application_services LEFT JOIN " "application_services_regex ON application_services.id = " "application_services_regex.as_id") # SQL results in the form: # [ # { # 'regex': "something", # 'url': "something", # 'namespace': enum, # 'as_id': 0, # 'token': "something", # 'hs_token': "otherthing", # 'id': 0 # } # ] services = {} results = yield self._execute_and_decode(sql) for res in results: as_token = res["token"] if as_token not in services: # add the service services[as_token] = { "url": res["url"], "token": as_token, "hs_token": res["hs_token"], "sender": res["sender"], "namespaces": { ApplicationService.NS_USERS: [], ApplicationService.NS_ALIASES: [], ApplicationService.NS_ROOMS: [] } } # add the namespace regex if one exists ns_int = res["namespace"] if ns_int is None: continue try: services[as_token]["namespaces"][ ApplicationService.NS_LIST[ns_int]].append(res["regex"]) except IndexError: logger.error("Bad namespace enum '%s'. %s", ns_int, res) # TODO get last successful txn id f.e. service for service in services.values(): logger.info("Found application service: %s", service) self.cache.services.append( ApplicationService(token=service["token"], url=service["url"], namespaces=service["namespaces"], hs_token=service["hs_token"], sender=service["sender"]))
def setUp(self): self.service = ApplicationService( url="some_url", token="some_token", namespaces={ ApplicationService.NS_USERS: [], ApplicationService.NS_ROOMS: [], ApplicationService.NS_ALIASES: [] } ) self.event = Mock( type="m.something", room_id="!foo:bar", sender="@someone:somewhere" )
def make_homeserver(self, reactor: MemoryReactor, clock: Clock) -> HomeServer: self.appservice = ApplicationService( token="i_am_an_app_service", id="1234", namespaces={"users": [{"regex": r"@as_user.*", "exclusive": True}]}, sender="@as:test", ) mock_load_appservices = Mock(return_value=[self.appservice]) with patch( "synapse.storage.databases.main.appservice.load_appservices", mock_load_appservices, ): hs = super().make_homeserver(reactor, clock) return hs
def setUp(self): self.service = ApplicationService( id="unique_identifier", url="some_url", token="some_token", hostname="matrix.org", # only used by get_groups_for_user namespaces={ ApplicationService.NS_USERS: [], ApplicationService.NS_ROOMS: [], ApplicationService.NS_ALIASES: [] } ) self.event = Mock( type="m.something", room_id="!foo:bar", sender="@someone:somewhere" ) self.store = Mock()
async def _do_appservice_login(self, login_submission: JsonDict, appservice: ApplicationService): logger.info( "Got appservice login request with identifier: %r", login_submission.get("identifier"), ) identifier = convert_client_dict_legacy_fields_to_identifier( login_submission) qualified_user_id = self._get_qualified_user_id(identifier) if not appservice.is_interested_in_user(qualified_user_id): raise LoginError(403, "Invalid access_token", errcode=Codes.FORBIDDEN) return await self._complete_login(qualified_user_id, login_submission)
def _load_appservice(self, as_info): required_string_fields = [ "url", "as_token", "hs_token", "sender_localpart" ] for field in required_string_fields: if not isinstance(as_info.get(field), basestring): raise KeyError("Required string field: '%s'", field) localpart = as_info["sender_localpart"] if urllib.quote(localpart) != localpart: raise ValueError( "sender_localpart needs characters which are not URL encoded." ) user = UserID(localpart, self.hostname) user_id = user.to_string() # namespace checks if not isinstance(as_info.get("namespaces"), dict): raise KeyError("Requires 'namespaces' object.") for ns in ApplicationService.NS_LIST: # specific namespaces are optional if ns in as_info["namespaces"]: # expect a list of dicts with exclusive and regex keys for regex_obj in as_info["namespaces"][ns]: if not isinstance(regex_obj, dict): raise ValueError( "Expected namespace entry in %s to be an object," " but got %s", ns, regex_obj ) if not isinstance(regex_obj.get("regex"), basestring): raise ValueError( "Missing/bad type 'regex' key in %s", regex_obj ) if not isinstance(regex_obj.get("exclusive"), bool): raise ValueError( "Missing/bad type 'exclusive' key in %s", regex_obj ) return ApplicationService( token=as_info["as_token"], url=as_info["url"], namespaces=as_info["namespaces"], hs_token=as_info["hs_token"], sender=user_id, id=as_info["as_token"] # the token is the only unique thing here )
def test_POST_appservice_registration_no_type(self) -> None: as_token = "i_am_an_app_service" appservice = ApplicationService( as_token, id="1234", namespaces={"users": [{"regex": r"@as_user.*", "exclusive": True}]}, sender="@as:test", ) self.hs.get_datastores().main.services_cache.append(appservice) request_data = json.dumps({"username": "******"}) channel = self.make_request( b"POST", self.url + b"?access_token=i_am_an_app_service", request_data ) self.assertEqual(channel.result["code"], b"400", channel.result)
def test_GET_whoami_appservices(self): user_id = "@as:test" as_token = "i_am_an_app_service" appservice = ApplicationService( as_token, self.hs.config.server_name, id="1234", namespaces={"users": [{ "regex": user_id, "exclusive": True }]}, sender=user_id, ) self.hs.get_datastore().services_cache.append(appservice) whoami = self.whoami(as_token) self.assertEqual(whoami, {"user_id": user_id}) self.assertFalse(hasattr(whoami, "device_id"))
async def _is_appservice_interested_in_device_lists_of_user( self, appservice: ApplicationService, user_id: str, ) -> bool: """ Returns whether a given application service is interested in the device list updates of a given user. The application service is interested in the user's device list updates if any of the following are true: * The user is the appservice's sender localpart user. * The user is in the appservice's user namespace. * At least one member of one room that the user is a part of is in the appservice's user namespace. * The appservice is explicitly (via room ID or alias) interested in at least one room that the user is in. Args: appservice: The application service to gauge interest of. user_id: The ID of the user whose device list interest is in question. Returns: True if the application service is interested in the user's device lists, False otherwise. """ # This method checks against both the sender localpart user as well as if the # user is in the appservice's user namespace. if appservice.is_interested_in_user(user_id): return True # Determine whether any of the rooms the user is in justifies sending this # device list update to the application service. room_ids = await self.store.get_rooms_for_user(user_id) for room_id in room_ids: # This method covers checking room members for appservice interest as well as # room ID and alias checks. if await appservice.is_interested_in_room(room_id, self.store): return True return False
def test_as_ignores_mau(self): """Test that application services can still create users when the MAU limit has been reached. This only works when application service user ip tracking is disabled. """ # Create and sync so that the MAU counts get updated token1 = self.create_user("kermit1") self.do_sync_for_user(token1) token2 = self.create_user("kermit2") self.do_sync_for_user(token2) # check we're testing what we think we are: there should be two active users self.assertEqual( self.get_success(self.store.get_monthly_active_count()), 2) # We've created and activated two users, we shouldn't be able to # register new users with self.assertRaises(SynapseError) as cm: self.create_user("kermit3") e = cm.exception self.assertEqual(e.code, 403) self.assertEqual(e.errcode, Codes.RESOURCE_LIMIT_EXCEEDED) # Cheekily add an application service that we use to register a new user # with. as_token = "foobartoken" self.store.services_cache.append( ApplicationService( token=as_token, hostname=self.hs.hostname, id="SomeASID", sender="@as_sender:test", namespaces={"users": [{ "regex": "@as_*", "exclusive": True }]}, )) self.create_user("as_kermit4", token=as_token, appservice=True)
def prepare(self, reactor: MemoryReactor, clock: Clock, hs: HomeServer) -> None: # Mock the ApplicationServiceScheduler's _TransactionController's send method so that # we can track what's going out self.send_mock = simple_async_mock() hs.get_application_service_handler( ).scheduler.txn_ctrl.send = self.send_mock # type: ignore[assignment] # We assign to a method. # Define an application service for the tests self._service_token = "VERYSECRET" self._service = ApplicationService( self._service_token, "as1", "@as.sender:test", namespaces={ "users": [ { "regex": "@_as_.*:test", "exclusive": True }, { "regex": "@as.sender:test", "exclusive": True }, ] }, msc3202_transaction_extensions=True, ) self.hs.get_datastores().main.services_cache = [self._service] # Register some appservice users self._sender_user, self._sender_device = self.register_appservice_user( "as.sender", self._service_token) self._namespaced_user, self._namespaced_device = self.register_appservice_user( "_as_user1", self._service_token) # Register a real user as well. self._real_user = self.register_user("real.user", "meow") self._real_user_token = self.login("real.user", "meow")
def test_deleting_alias_via_directory_appservice(self) -> None: user_id = "@as:test" as_token = "i_am_an_app_service" appservice = ApplicationService( as_token, id="1234", namespaces={"aliases": [{ "regex": "#asns-*", "exclusive": True }]}, sender=user_id, ) self.hs.get_datastores().main.services_cache.append(appservice) # Add an alias for the room, as the appservice alias = RoomAlias(f"asns-{random_string(5)}", self.hs.hostname).to_string() data = {"room_id": self.room_id} request_data = json.dumps(data) channel = self.make_request( "PUT", f"/_matrix/client/r0/directory/room/{alias}", request_data, access_token=as_token, ) self.assertEqual(channel.code, HTTPStatus.OK, channel.result) # Then try to remove the alias, as the appservice channel = self.make_request( "DELETE", f"/_matrix/client/r0/directory/room/{alias}", access_token=as_token, ) self.assertEqual(channel.code, HTTPStatus.OK, channel.result)
def _load_appservice(hostname: str, as_info: JsonDict, config_filename: str) -> ApplicationService: required_string_fields = ["id", "as_token", "hs_token", "sender_localpart"] for field in required_string_fields: if not isinstance(as_info.get(field), str): raise KeyError("Required string field: '%s' (%s)" % (field, config_filename)) # 'url' must either be a string or explicitly null, not missing # to avoid accidentally turning off push for ASes. if not isinstance(as_info.get("url"), str) and as_info.get("url", "") is not None: raise KeyError("Required string field or explicit null: 'url' (%s)" % (config_filename, )) localpart = as_info["sender_localpart"] if urlparse.quote(localpart) != localpart: raise ValueError( "sender_localpart needs characters which are not URL encoded.") user = UserID(localpart, hostname) user_id = user.to_string() # Rate limiting for users of this AS is on by default (excludes sender) rate_limited = as_info.get("rate_limited") if not isinstance(rate_limited, bool): rate_limited = True # namespace checks if not isinstance(as_info.get("namespaces"), dict): raise KeyError("Requires 'namespaces' object.") for ns in ApplicationService.NS_LIST: # specific namespaces are optional if ns in as_info["namespaces"]: # expect a list of dicts with exclusive and regex keys for regex_obj in as_info["namespaces"][ns]: if not isinstance(regex_obj, dict): raise ValueError( "Expected namespace entry in %s to be an object, but got %s", ns, regex_obj, ) if not isinstance(regex_obj.get("regex"), str): raise ValueError("Missing/bad type 'regex' key in %s", regex_obj) if not isinstance(regex_obj.get("exclusive"), bool): raise ValueError("Missing/bad type 'exclusive' key in %s", regex_obj) # protocols check protocols = as_info.get("protocols") if protocols: if not isinstance(protocols, list): raise KeyError("Optional 'protocols' must be a list if present.") for p in protocols: if not isinstance(p, str): raise KeyError("Bad value for 'protocols' item") if as_info["url"] is None: logger.info( "(%s) Explicitly empty 'url' provided. This application service" " will not receive events or queries.", config_filename, ) ip_range_whitelist = None if as_info.get("ip_range_whitelist"): ip_range_whitelist = IPSet(as_info.get("ip_range_whitelist")) supports_ephemeral = as_info.get("de.sorunome.msc2409.push_ephemeral", False) # Opt-in flag for the MSC3202-specific transactional behaviour. # When enabled, appservice transactions contain the following information: # - device One-Time Key counts # - device unused fallback key usage states # - device list changes msc3202_transaction_extensions = as_info.get("org.matrix.msc3202", False) if not isinstance(msc3202_transaction_extensions, bool): raise ValueError( "The `org.matrix.msc3202` option should be true or false if specified." ) return ApplicationService( token=as_info["as_token"], url=as_info["url"], namespaces=as_info["namespaces"], hs_token=as_info["hs_token"], sender=user_id, id=as_info["id"], protocols=protocols, rate_limited=rate_limited, ip_range_whitelist=ip_range_whitelist, supports_ephemeral=supports_ephemeral, msc3202_transaction_extensions=msc3202_transaction_extensions, )
class ApplicationServiceTestCase(unittest.TestCase): def setUp(self): self.service = ApplicationService(id="unique_identifier", url="some_url", token="some_token", namespaces={ ApplicationService.NS_USERS: [], ApplicationService.NS_ROOMS: [], ApplicationService.NS_ALIASES: [] }) self.event = Mock(type="m.something", room_id="!foo:bar", sender="@someone:somewhere") def test_regex_user_id_prefix_match(self): self.service.namespaces[ApplicationService.NS_USERS].append( _regex("@irc_.*")) self.event.sender = "@irc_foobar:matrix.org" self.assertTrue(self.service.is_interested(self.event)) def test_regex_user_id_prefix_no_match(self): self.service.namespaces[ApplicationService.NS_USERS].append( _regex("@irc_.*")) self.event.sender = "@someone_else:matrix.org" self.assertFalse(self.service.is_interested(self.event)) def test_regex_room_member_is_checked(self): self.service.namespaces[ApplicationService.NS_USERS].append( _regex("@irc_.*")) self.event.sender = "@someone_else:matrix.org" self.event.type = "m.room.member" self.event.state_key = "@irc_foobar:matrix.org" self.assertTrue(self.service.is_interested(self.event)) def test_regex_room_id_match(self): self.service.namespaces[ApplicationService.NS_ROOMS].append( _regex("!some_prefix.*some_suffix:matrix.org")) self.event.room_id = "!some_prefixs0m3th1nGsome_suffix:matrix.org" self.assertTrue(self.service.is_interested(self.event)) def test_regex_room_id_no_match(self): self.service.namespaces[ApplicationService.NS_ROOMS].append( _regex("!some_prefix.*some_suffix:matrix.org")) self.event.room_id = "!XqBunHwQIXUiqCaoxq:matrix.org" self.assertFalse(self.service.is_interested(self.event)) def test_regex_alias_match(self): self.service.namespaces[ApplicationService.NS_ALIASES].append( _regex("#irc_.*:matrix.org")) self.assertTrue( self.service.is_interested(self.event, aliases_for_event=[ "#irc_foobar:matrix.org", "#athing:matrix.org" ])) def test_non_exclusive_alias(self): self.service.namespaces[ApplicationService.NS_ALIASES].append( _regex("#irc_.*:matrix.org", exclusive=False)) self.assertFalse( self.service.is_exclusive_alias("#irc_foobar:matrix.org")) def test_non_exclusive_room(self): self.service.namespaces[ApplicationService.NS_ROOMS].append( _regex("!irc_.*:matrix.org", exclusive=False)) self.assertFalse( self.service.is_exclusive_room("!irc_foobar:matrix.org")) def test_non_exclusive_user(self): self.service.namespaces[ApplicationService.NS_USERS].append( _regex("@irc_.*:matrix.org", exclusive=False)) self.assertFalse( self.service.is_exclusive_user("@irc_foobar:matrix.org")) def test_exclusive_alias(self): self.service.namespaces[ApplicationService.NS_ALIASES].append( _regex("#irc_.*:matrix.org", exclusive=True)) self.assertTrue( self.service.is_exclusive_alias("#irc_foobar:matrix.org")) def test_exclusive_user(self): self.service.namespaces[ApplicationService.NS_USERS].append( _regex("@irc_.*:matrix.org", exclusive=True)) self.assertTrue( self.service.is_exclusive_user("@irc_foobar:matrix.org")) def test_exclusive_room(self): self.service.namespaces[ApplicationService.NS_ROOMS].append( _regex("!irc_.*:matrix.org", exclusive=True)) self.assertTrue( self.service.is_exclusive_room("!irc_foobar:matrix.org")) def test_regex_alias_no_match(self): self.service.namespaces[ApplicationService.NS_ALIASES].append( _regex("#irc_.*:matrix.org")) self.assertFalse( self.service.is_interested(self.event, aliases_for_event=[ "#xmpp_foobar:matrix.org", "#athing:matrix.org" ])) def test_regex_multiple_matches(self): self.service.namespaces[ApplicationService.NS_ALIASES].append( _regex("#irc_.*:matrix.org")) self.service.namespaces[ApplicationService.NS_USERS].append( _regex("@irc_.*")) self.event.sender = "@irc_foobar:matrix.org" self.assertTrue( self.service.is_interested( self.event, aliases_for_event=["#irc_barfoo:matrix.org"])) def test_restrict_to_rooms(self): self.service.namespaces[ApplicationService.NS_ROOMS].append( _regex("!flibble_.*:matrix.org")) self.service.namespaces[ApplicationService.NS_USERS].append( _regex("@irc_.*")) self.event.sender = "@irc_foobar:matrix.org" self.event.room_id = "!wibblewoo:matrix.org" self.assertFalse( self.service.is_interested( self.event, restrict_to=ApplicationService.NS_ROOMS)) def test_restrict_to_aliases(self): self.service.namespaces[ApplicationService.NS_ALIASES].append( _regex("#xmpp_.*:matrix.org")) self.service.namespaces[ApplicationService.NS_USERS].append( _regex("@irc_.*")) self.event.sender = "@irc_foobar:matrix.org" self.assertFalse( self.service.is_interested( self.event, restrict_to=ApplicationService.NS_ALIASES, aliases_for_event=["#irc_barfoo:matrix.org"])) def test_restrict_to_senders(self): self.service.namespaces[ApplicationService.NS_ALIASES].append( _regex("#xmpp_.*:matrix.org")) self.service.namespaces[ApplicationService.NS_USERS].append( _regex("@irc_.*")) self.event.sender = "@xmpp_foobar:matrix.org" self.assertFalse( self.service.is_interested( self.event, restrict_to=ApplicationService.NS_USERS, aliases_for_event=["#xmpp_barfoo:matrix.org"])) def test_interested_in_self(self): # make sure invites get through self.service.sender = "@appservice:name" self.service.namespaces[ApplicationService.NS_USERS].append( _regex("@irc_.*")) self.event.type = "m.room.member" self.event.content = {"membership": "invite"} self.event.state_key = self.service.sender self.assertTrue(self.service.is_interested(self.event)) def test_member_list_match(self): self.service.namespaces[ApplicationService.NS_USERS].append( _regex("@irc_.*")) join_list = [ "@alice:here", "@irc_fo:here", # AS user "@bob:here", ] self.event.sender = "@xmpp_foobar:matrix.org" self.assertTrue( self.service.is_interested(event=self.event, member_list=join_list))
class ApplicationServiceTestCase(unittest.TestCase): def setUp(self): self.service = ApplicationService( id="unique_identifier", url="some_url", token="some_token", namespaces={ ApplicationService.NS_USERS: [], ApplicationService.NS_ROOMS: [], ApplicationService.NS_ALIASES: [] } ) self.event = Mock( type="m.something", room_id="!foo:bar", sender="@someone:somewhere" ) def test_regex_user_id_prefix_match(self): self.service.namespaces[ApplicationService.NS_USERS].append( _regex("@irc_.*") ) self.event.sender = "@irc_foobar:matrix.org" self.assertTrue(self.service.is_interested(self.event)) def test_regex_user_id_prefix_no_match(self): self.service.namespaces[ApplicationService.NS_USERS].append( _regex("@irc_.*") ) self.event.sender = "@someone_else:matrix.org" self.assertFalse(self.service.is_interested(self.event)) def test_regex_room_member_is_checked(self): self.service.namespaces[ApplicationService.NS_USERS].append( _regex("@irc_.*") ) self.event.sender = "@someone_else:matrix.org" self.event.type = "m.room.member" self.event.state_key = "@irc_foobar:matrix.org" self.assertTrue(self.service.is_interested(self.event)) def test_regex_room_id_match(self): self.service.namespaces[ApplicationService.NS_ROOMS].append( _regex("!some_prefix.*some_suffix:matrix.org") ) self.event.room_id = "!some_prefixs0m3th1nGsome_suffix:matrix.org" self.assertTrue(self.service.is_interested(self.event)) def test_regex_room_id_no_match(self): self.service.namespaces[ApplicationService.NS_ROOMS].append( _regex("!some_prefix.*some_suffix:matrix.org") ) self.event.room_id = "!XqBunHwQIXUiqCaoxq:matrix.org" self.assertFalse(self.service.is_interested(self.event)) def test_regex_alias_match(self): self.service.namespaces[ApplicationService.NS_ALIASES].append( _regex("#irc_.*:matrix.org") ) self.assertTrue(self.service.is_interested( self.event, aliases_for_event=["#irc_foobar:matrix.org", "#athing:matrix.org"] )) def test_non_exclusive_alias(self): self.service.namespaces[ApplicationService.NS_ALIASES].append( _regex("#irc_.*:matrix.org", exclusive=False) ) self.assertFalse(self.service.is_exclusive_alias( "#irc_foobar:matrix.org" )) def test_non_exclusive_room(self): self.service.namespaces[ApplicationService.NS_ROOMS].append( _regex("!irc_.*:matrix.org", exclusive=False) ) self.assertFalse(self.service.is_exclusive_room( "!irc_foobar:matrix.org" )) def test_non_exclusive_user(self): self.service.namespaces[ApplicationService.NS_USERS].append( _regex("@irc_.*:matrix.org", exclusive=False) ) self.assertFalse(self.service.is_exclusive_user( "@irc_foobar:matrix.org" )) def test_exclusive_alias(self): self.service.namespaces[ApplicationService.NS_ALIASES].append( _regex("#irc_.*:matrix.org", exclusive=True) ) self.assertTrue(self.service.is_exclusive_alias( "#irc_foobar:matrix.org" )) def test_exclusive_user(self): self.service.namespaces[ApplicationService.NS_USERS].append( _regex("@irc_.*:matrix.org", exclusive=True) ) self.assertTrue(self.service.is_exclusive_user( "@irc_foobar:matrix.org" )) def test_exclusive_room(self): self.service.namespaces[ApplicationService.NS_ROOMS].append( _regex("!irc_.*:matrix.org", exclusive=True) ) self.assertTrue(self.service.is_exclusive_room( "!irc_foobar:matrix.org" )) def test_regex_alias_no_match(self): self.service.namespaces[ApplicationService.NS_ALIASES].append( _regex("#irc_.*:matrix.org") ) self.assertFalse(self.service.is_interested( self.event, aliases_for_event=["#xmpp_foobar:matrix.org", "#athing:matrix.org"] )) def test_regex_multiple_matches(self): self.service.namespaces[ApplicationService.NS_ALIASES].append( _regex("#irc_.*:matrix.org") ) self.service.namespaces[ApplicationService.NS_USERS].append( _regex("@irc_.*") ) self.event.sender = "@irc_foobar:matrix.org" self.assertTrue(self.service.is_interested( self.event, aliases_for_event=["#irc_barfoo:matrix.org"] )) def test_restrict_to_rooms(self): self.service.namespaces[ApplicationService.NS_ROOMS].append( _regex("!flibble_.*:matrix.org") ) self.service.namespaces[ApplicationService.NS_USERS].append( _regex("@irc_.*") ) self.event.sender = "@irc_foobar:matrix.org" self.event.room_id = "!wibblewoo:matrix.org" self.assertFalse(self.service.is_interested( self.event, restrict_to=ApplicationService.NS_ROOMS )) def test_restrict_to_aliases(self): self.service.namespaces[ApplicationService.NS_ALIASES].append( _regex("#xmpp_.*:matrix.org") ) self.service.namespaces[ApplicationService.NS_USERS].append( _regex("@irc_.*") ) self.event.sender = "@irc_foobar:matrix.org" self.assertFalse(self.service.is_interested( self.event, restrict_to=ApplicationService.NS_ALIASES, aliases_for_event=["#irc_barfoo:matrix.org"] )) def test_restrict_to_senders(self): self.service.namespaces[ApplicationService.NS_ALIASES].append( _regex("#xmpp_.*:matrix.org") ) self.service.namespaces[ApplicationService.NS_USERS].append( _regex("@irc_.*") ) self.event.sender = "@xmpp_foobar:matrix.org" self.assertFalse(self.service.is_interested( self.event, restrict_to=ApplicationService.NS_USERS, aliases_for_event=["#xmpp_barfoo:matrix.org"] )) def test_interested_in_self(self): # make sure invites get through self.service.sender = "@appservice:name" self.service.namespaces[ApplicationService.NS_USERS].append( _regex("@irc_.*") ) self.event.type = "m.room.member" self.event.content = { "membership": "invite" } self.event.state_key = self.service.sender self.assertTrue(self.service.is_interested(self.event)) def test_member_list_match(self): self.service.namespaces[ApplicationService.NS_USERS].append( _regex("@irc_.*") ) join_list = [ "@alice:here", "@irc_fo:here", # AS user "@bob:here", ] self.event.sender = "@xmpp_foobar:matrix.org" self.assertTrue(self.service.is_interested( event=self.event, member_list=join_list ))