summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--synapse/appservice/__init__.py21
-rw-r--r--synapse/handlers/appservice.py44
2 files changed, 44 insertions, 21 deletions
diff --git a/synapse/appservice/__init__.py b/synapse/appservice/__init__.py
index d9ca856c8b..46d46a5a48 100644
--- a/synapse/appservice/__init__.py
+++ b/synapse/appservice/__init__.py
@@ -75,27 +75,23 @@ class ApplicationService(object):
 
     def _matches_user(self, event):
         if (hasattr(event, "sender") and
-                self._matches_regex(
-                event.sender, ApplicationService.NS_USERS)):
+                self.is_interested_in_user(event.sender)):
             return True
         # also check m.room.member state key
         if (hasattr(event, "type") and event.type == EventTypes.Member
                 and hasattr(event, "state_key")
-                and self._matches_regex(
-                event.state_key, ApplicationService.NS_USERS)):
+                and self.is_interested_in_user(event.state_key)):
             return True
         return False
 
     def _matches_room_id(self, event):
         if hasattr(event, "room_id"):
-            return self._matches_regex(
-                event.room_id, ApplicationService.NS_ROOMS
-            )
+            return self.is_interested_in_room(event.room_id)
         return False
 
     def _matches_aliases(self, event, alias_list):
         for alias in alias_list:
-            if self._matches_regex(alias, ApplicationService.NS_ALIASES):
+            if self.is_interested_in_alias(alias):
                 return True
         return False
 
@@ -128,5 +124,14 @@ class ApplicationService(object):
         elif restrict_to == ApplicationService.NS_USERS:
             return self._matches_user(event)
 
+    def is_interested_in_user(self, user_id):
+        return self._matches_regex(user_id, ApplicationService.NS_USERS)
+
+    def is_interested_in_alias(self, alias):
+        return self._matches_regex(alias, ApplicationService.NS_ALIASES)
+
+    def is_interested_in_room(self, room_id):
+        return self._matches_regex(room_id, ApplicationService.NS_ROOMS)
+
     def __str__(self):
         return "ApplicationService: %s" % (self.__dict__,)
diff --git a/synapse/handlers/appservice.py b/synapse/handlers/appservice.py
index ef94215133..8d0cdd528c 100644
--- a/synapse/handlers/appservice.py
+++ b/synapse/handlers/appservice.py
@@ -15,6 +15,7 @@
 
 from twisted.internet import defer
 
+from synapse.api.constants import EventTypes
 from synapse.api.errors import Codes, StoreError, SynapseError
 from synapse.appservice import ApplicationService
 from synapse.appservice.api import ApplicationServiceApi
@@ -78,32 +79,31 @@ class ApplicationServicesHandler(object):
             return  # no services need notifying
 
         # Do we know this user exists? If not, poke the user query API for
-        # all services which match that user regex.
-        unknown_user = yield self._is_unknown_user(event.sender)
-        if unknown_user:
-            yield self.query_user_exists(event)
+        # all services which match that user regex. This needs to block as these
+        # user queries need to be made BEFORE pushing the event.
+        yield self._check_user_exists(event.sender)
+        if event.type == EventTypes.Member:
+            yield self._check_user_exists(event.state_key)
 
         # Fork off pushes to these services - XXX First cut, best effort
         for service in services:
             self.appservice_api.push(service, event)
 
     @defer.inlineCallbacks
-    def query_user_exists(self, event):
-        """Check if an application services knows this event.sender exists.
+    def query_user_exists(self, user_id):
+        """Check if any application service knows this user_id exists.
 
         Args:
-            event: An event sent by the user to query
+            user_id(str): The user to query if they exist on any AS.
         Returns:
-            True if this user exists.
+            True if this user exists on at least one application service.
         """
-        # TODO Would be nice for this to accept a user ID instead of an event.
-        user_query_services = yield self._get_services_for_event(
-            event=event,
-            restrict_to=ApplicationService.NS_USERS
+        user_query_services = yield self._get_services_for_user(
+            user_id=user_id
         )
         for user_service in user_query_services:
             is_known_user = yield self.appservice_api.query_user(
-                user_service, event.sender
+                user_service, user_id
             )
             if is_known_user:
                 defer.returnValue(True)
@@ -162,6 +162,16 @@ class ApplicationServicesHandler(object):
         defer.returnValue(interested_list)
 
     @defer.inlineCallbacks
+    def _get_services_for_user(self, user_id):
+        services = yield self.store.get_app_services()
+        interested_list = [
+            s for s in services if (
+                s.is_interested_in_user(user_id)
+            )
+        ]
+        defer.returnValue(interested_list)
+
+    @defer.inlineCallbacks
     def _is_unknown_user(self, user_id):
         user = UserID.from_string(user_id)
         if not self.hs.is_mine(user):
@@ -173,5 +183,13 @@ class ApplicationServicesHandler(object):
         user_info = yield self.store.get_user_by_id(user_id)
         defer.returnValue(len(user_info) == 0)
 
+    @defer.inlineCallbacks
+    def _check_user_exists(self, user_id):
+        unknown_user = yield self._is_unknown_user(user_id)
+        if unknown_user:
+            exists = yield self.query_user_exists(user_id)
+            defer.returnValue(exists)
+        defer.returnValue(True)
+
     def _generate_hs_token(self):
         return stringutils.random_string(24)