summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--synapse/appservice/__init__.py81
-rw-r--r--synapse/handlers/appservice.py31
-rw-r--r--synapse/push/action_generator.py9
-rw-r--r--synapse/push/baserules.py36
-rw-r--r--synapse/rest/media/v1/download_resource.py1
-rw-r--r--synapse/storage/schema/delta/34/push_display_name_rename.sql20
-rw-r--r--tests/appservice/test_appservice.py109
-rw-r--r--tests/handlers/test_appservice.py13
8 files changed, 150 insertions, 150 deletions
diff --git a/synapse/appservice/__init__.py b/synapse/appservice/__init__.py
index f7178ea0d3..b1b91d0a55 100644
--- a/synapse/appservice/__init__.py
+++ b/synapse/appservice/__init__.py
@@ -14,6 +14,8 @@
 # limitations under the License.
 from synapse.api.constants import EventTypes
 
+from twisted.internet import defer
+
 import logging
 import re
 
@@ -138,65 +140,66 @@ class ApplicationService(object):
             return regex_obj["exclusive"]
         return False
 
-    def _matches_user(self, event, member_list):
-        if (hasattr(event, "sender") and
-                self.is_interested_in_user(event.sender)):
-            return True
+    @defer.inlineCallbacks
+    def _matches_user(self, event, store):
+        if not event:
+            defer.returnValue(False)
+
+        if self.is_interested_in_user(event.sender):
+            defer.returnValue(True)
         # also check m.room.member state key
-        if (hasattr(event, "type") and event.type == EventTypes.Member
-                and hasattr(event, "state_key")
-                and self.is_interested_in_user(event.state_key)):
-            return True
+        if (event.type == EventTypes.Member and
+                self.is_interested_in_user(event.state_key)):
+            defer.returnValue(True)
+
+        if not store:
+            defer.returnValue(False)
+
+        member_list = yield store.get_users_in_room(event.room_id)
+
         # check joined member events
         for user_id in member_list:
             if self.is_interested_in_user(user_id):
-                return True
-        return False
+                defer.returnValue(True)
+        defer.returnValue(False)
 
     def _matches_room_id(self, event):
         if hasattr(event, "room_id"):
             return self.is_interested_in_room(event.room_id)
         return False
 
-    def _matches_aliases(self, event, alias_list):
+    @defer.inlineCallbacks
+    def _matches_aliases(self, event, store):
+        if not store or not event:
+            defer.returnValue(False)
+
+        alias_list = yield store.get_aliases_for_room(event.room_id)
         for alias in alias_list:
             if self.is_interested_in_alias(alias):
-                return True
-        return False
+                defer.returnValue(True)
+        defer.returnValue(False)
 
-    def is_interested(self, event, restrict_to=None, aliases_for_event=None,
-                      member_list=None):
+    @defer.inlineCallbacks
+    def is_interested(self, event, store=None):
         """Check if this service is interested in this event.
 
         Args:
             event(Event): The event to check.
-            restrict_to(str): The namespace to restrict regex tests to.
-            aliases_for_event(list): A list of all the known room aliases for
-            this event.
-            member_list(list): A list of all joined user_ids in this room.
+            store(DataStore)
         Returns:
             bool: True if this service would like to know about this event.
         """
-        if aliases_for_event is None:
-            aliases_for_event = []
-        if member_list is None:
-            member_list = []
-
-        if restrict_to and restrict_to not in ApplicationService.NS_LIST:
-            # this is a programming error, so fail early and raise a general
-            # exception
-            raise Exception("Unexpected restrict_to value: %s". restrict_to)
-
-        if not restrict_to:
-            return (self._matches_user(event, member_list)
-                    or self._matches_aliases(event, aliases_for_event)
-                    or self._matches_room_id(event))
-        elif restrict_to == ApplicationService.NS_ALIASES:
-            return self._matches_aliases(event, aliases_for_event)
-        elif restrict_to == ApplicationService.NS_ROOMS:
-            return self._matches_room_id(event)
-        elif restrict_to == ApplicationService.NS_USERS:
-            return self._matches_user(event, member_list)
+        # Do cheap checks first
+        if self._matches_room_id(event):
+            defer.returnValue(True)
+
+        if (yield self._matches_aliases(event, store)):
+            defer.returnValue(True)
+
+        if (yield self._matches_user(event, store)):
+            defer.returnValue(True)
+
+        defer.returnValue(False)
 
     def is_interested_in_user(self, user_id):
         return (
diff --git a/synapse/handlers/appservice.py b/synapse/handlers/appservice.py
index 48feae07b5..79805cdc2e 100644
--- a/synapse/handlers/appservice.py
+++ b/synapse/handlers/appservice.py
@@ -16,7 +16,6 @@
 from twisted.internet import defer
 
 from synapse.api.constants import EventTypes
-from synapse.appservice import ApplicationService
 from synapse.util.metrics import Measure
 
 import logging
@@ -107,11 +106,12 @@ class ApplicationServicesHandler(object):
             association can be found.
         """
         room_alias_str = room_alias.to_string()
-        alias_query_services = yield self._get_services_for_event(
-            event=None,
-            restrict_to=ApplicationService.NS_ALIASES,
-            alias_list=[room_alias_str]
-        )
+        services = yield self.store.get_app_services()
+        alias_query_services = [
+            s for s in services if (
+                s.is_interested_in_alias(room_alias_str)
+            )
+        ]
         for alias_service in alias_query_services:
             is_known_alias = yield self.appservice_api.query_alias(
                 alias_service, room_alias_str
@@ -124,34 +124,19 @@ class ApplicationServicesHandler(object):
                 defer.returnValue(result)
 
     @defer.inlineCallbacks
-    def _get_services_for_event(self, event, restrict_to="", alias_list=None):
+    def _get_services_for_event(self, event):
         """Retrieve a list of application services interested in this event.
 
         Args:
             event(Event): The event to check. Can be None if alias_list is not.
-            restrict_to(str): The namespace to restrict regex tests to.
-            alias_list: A list of aliases to get services for. If None, this
-            list is obtained from the database.
         Returns:
             list<ApplicationService>: A list of services interested in this
             event based on the service regex.
         """
-        member_list = None
-        if hasattr(event, "room_id"):
-            # We need to know the aliases associated with this event.room_id,
-            # if any.
-            if not alias_list:
-                alias_list = yield self.store.get_aliases_for_room(
-                    event.room_id
-                )
-            # We need to know the members associated with this event.room_id,
-            # if any.
-            member_list = yield self.store.get_users_in_room(event.room_id)
-
         services = yield self.store.get_app_services()
         interested_list = [
             s for s in services if (
-                s.is_interested(event, restrict_to, alias_list, member_list)
+                yield s.is_interested(event, self.store)
             )
         ]
         defer.returnValue(interested_list)
diff --git a/synapse/push/action_generator.py b/synapse/push/action_generator.py
index 46e768e35c..b2c94bfaac 100644
--- a/synapse/push/action_generator.py
+++ b/synapse/push/action_generator.py
@@ -38,15 +38,16 @@ class ActionGenerator:
 
     @defer.inlineCallbacks
     def handle_push_actions_for_event(self, event, context):
-        with Measure(self.clock, "handle_push_actions_for_event"):
+        with Measure(self.clock, "evaluator_for_event"):
             bulk_evaluator = yield evaluator_for_event(
                 event, self.hs, self.store, context.current_state
             )
 
+        with Measure(self.clock, "action_for_event_by_user"):
             actions_by_user = yield bulk_evaluator.action_for_event_by_user(
                 event, context.current_state
             )
 
-            context.push_actions = [
-                (uid, actions) for uid, actions in actions_by_user.items()
-            ]
+        context.push_actions = [
+            (uid, actions) for uid, actions in actions_by_user.items()
+        ]
diff --git a/synapse/push/baserules.py b/synapse/push/baserules.py
index 024c14904f..edb00ed206 100644
--- a/synapse/push/baserules.py
+++ b/synapse/push/baserules.py
@@ -217,45 +217,49 @@ BASE_APPEND_OVERRIDE_RULES = [
             'dont_notify'
         ]
     },
-]
-
-
-BASE_APPEND_UNDERRIDE_RULES = [
+    # This was changed from underride to override so it's closer in priority
+    # to the content rules where the user name highlight rule lives. This
+    # way a room rule is lower priority than both but a custom override rule
+    # is higher priority than both.
     {
-        'rule_id': 'global/underride/.m.rule.call',
+        'rule_id': 'global/override/.m.rule.contains_display_name',
         'conditions': [
             {
-                'kind': 'event_match',
-                'key': 'type',
-                'pattern': 'm.call.invite',
-                '_id': '_call',
+                'kind': 'contains_display_name'
             }
         ],
         'actions': [
             'notify',
             {
                 'set_tweak': 'sound',
-                'value': 'ring'
+                'value': 'default'
             }, {
-                'set_tweak': 'highlight',
-                'value': False
+                'set_tweak': 'highlight'
             }
         ]
     },
+]
+
+
+BASE_APPEND_UNDERRIDE_RULES = [
     {
-        'rule_id': 'global/underride/.m.rule.contains_display_name',
+        'rule_id': 'global/underride/.m.rule.call',
         'conditions': [
             {
-                'kind': 'contains_display_name'
+                'kind': 'event_match',
+                'key': 'type',
+                'pattern': 'm.call.invite',
+                '_id': '_call',
             }
         ],
         'actions': [
             'notify',
             {
                 'set_tweak': 'sound',
-                'value': 'default'
+                'value': 'ring'
             }, {
-                'set_tweak': 'highlight'
+                'set_tweak': 'highlight',
+                'value': False
             }
         ]
     },
diff --git a/synapse/rest/media/v1/download_resource.py b/synapse/rest/media/v1/download_resource.py
index 9f69620772..9f0625a822 100644
--- a/synapse/rest/media/v1/download_resource.py
+++ b/synapse/rest/media/v1/download_resource.py
@@ -45,6 +45,7 @@ class DownloadResource(Resource):
     @request_handler()
     @defer.inlineCallbacks
     def _async_render_GET(self, request):
+        request.setHeader("Content-Security-Policy", "sandbox")
         server_name, media_id, name = parse_media_id(request)
         if server_name == self.server_name:
             yield self._respond_local_file(request, media_id, name)
diff --git a/synapse/storage/schema/delta/34/push_display_name_rename.sql b/synapse/storage/schema/delta/34/push_display_name_rename.sql
new file mode 100644
index 0000000000..0d9fe1a99a
--- /dev/null
+++ b/synapse/storage/schema/delta/34/push_display_name_rename.sql
@@ -0,0 +1,20 @@
+/* Copyright 2016 OpenMarket Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+DELETE FROM push_rules WHERE rule_id = 'global/override/.m.rule.contains_display_name';
+UPDATE push_rules SET rule_id = 'global/override/.m.rule.contains_display_name' WHERE rule_id = 'global/underride/.m.rule.contains_display_name';
+
+DELETE FROM push_rules_enable WHERE rule_id = 'global/override/.m.rule.contains_display_name';
+UPDATE push_rules_enable SET rule_id = 'global/override/.m.rule.contains_display_name' WHERE rule_id = 'global/underride/.m.rule.contains_display_name';
diff --git a/tests/appservice/test_appservice.py b/tests/appservice/test_appservice.py
index d6cc1881e9..aa8cc50550 100644
--- a/tests/appservice/test_appservice.py
+++ b/tests/appservice/test_appservice.py
@@ -14,6 +14,8 @@
 # limitations under the License.
 from synapse.appservice import ApplicationService
 
+from twisted.internet import defer
+
 from mock import Mock
 from tests import unittest
 
@@ -42,20 +44,25 @@ class ApplicationServiceTestCase(unittest.TestCase):
             type="m.something", room_id="!foo:bar", sender="@someone:somewhere"
         )
 
+        self.store = Mock()
+
+    @defer.inlineCallbacks
     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))
+        self.assertTrue((yield self.service.is_interested(self.event)))
 
+    @defer.inlineCallbacks
     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))
+        self.assertFalse((yield self.service.is_interested(self.event)))
 
+    @defer.inlineCallbacks
     def test_regex_room_member_is_checked(self):
         self.service.namespaces[ApplicationService.NS_USERS].append(
             _regex("@irc_.*")
@@ -63,30 +70,36 @@ class ApplicationServiceTestCase(unittest.TestCase):
         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))
+        self.assertTrue((yield self.service.is_interested(self.event)))
 
+    @defer.inlineCallbacks
     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))
+        self.assertTrue((yield self.service.is_interested(self.event)))
 
+    @defer.inlineCallbacks
     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))
+        self.assertFalse((yield self.service.is_interested(self.event)))
 
+    @defer.inlineCallbacks
     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"]
-        ))
+        self.store.get_aliases_for_room.return_value = [
+            "#irc_foobar:matrix.org", "#athing:matrix.org"
+        ]
+        self.store.get_users_in_room.return_value = []
+        self.assertTrue((yield self.service.is_interested(
+            self.event, self.store
+        )))
 
     def test_non_exclusive_alias(self):
         self.service.namespaces[ApplicationService.NS_ALIASES].append(
@@ -136,15 +149,20 @@ class ApplicationServiceTestCase(unittest.TestCase):
             "!irc_foobar:matrix.org"
         ))
 
+    @defer.inlineCallbacks
     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"]
-        ))
+        self.store.get_aliases_for_room.return_value = [
+            "#xmpp_foobar:matrix.org", "#athing:matrix.org"
+        ]
+        self.store.get_users_in_room.return_value = []
+        self.assertFalse((yield self.service.is_interested(
+            self.event, self.store
+        )))
 
+    @defer.inlineCallbacks
     def test_regex_multiple_matches(self):
         self.service.namespaces[ApplicationService.NS_ALIASES].append(
             _regex("#irc_.*:matrix.org")
@@ -153,53 +171,13 @@ class ApplicationServiceTestCase(unittest.TestCase):
             _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"]
-        ))
+        self.store.get_aliases_for_room.return_value = ["#irc_barfoo:matrix.org"]
+        self.store.get_users_in_room.return_value = []
+        self.assertTrue((yield self.service.is_interested(
+            self.event, self.store
+        )))
 
+    @defer.inlineCallbacks
     def test_interested_in_self(self):
         # make sure invites get through
         self.service.sender = "@appservice:name"
@@ -211,20 +189,21 @@ class ApplicationServiceTestCase(unittest.TestCase):
             "membership": "invite"
         }
         self.event.state_key = self.service.sender
-        self.assertTrue(self.service.is_interested(self.event))
+        self.assertTrue((yield self.service.is_interested(self.event)))
 
+    @defer.inlineCallbacks
     def test_member_list_match(self):
         self.service.namespaces[ApplicationService.NS_USERS].append(
             _regex("@irc_.*")
         )
-        join_list = [
+        self.store.get_users_in_room.return_value = [
             "@alice:here",
             "@irc_fo:here",  # AS user
             "@bob:here",
         ]
+        self.store.get_aliases_for_room.return_value = []
 
         self.event.sender = "@xmpp_foobar:matrix.org"
-        self.assertTrue(self.service.is_interested(
-            event=self.event,
-            member_list=join_list
-        ))
+        self.assertTrue((yield self.service.is_interested(
+            event=self.event, store=self.store
+        )))
diff --git a/tests/handlers/test_appservice.py b/tests/handlers/test_appservice.py
index 3116951472..9c1e5cc67c 100644
--- a/tests/handlers/test_appservice.py
+++ b/tests/handlers/test_appservice.py
@@ -110,11 +110,11 @@ class AppServiceHandlerTestCase(unittest.TestCase):
 
         room_id = "!alpha:bet"
         servers = ["aperture"]
-        interested_service = self._mkservice(is_interested=True)
+        interested_service = self._mkservice_alias(is_interested_in_alias=True)
         services = [
-            self._mkservice(is_interested=False),
+            self._mkservice_alias(is_interested_in_alias=False),
             interested_service,
-            self._mkservice(is_interested=False)
+            self._mkservice_alias(is_interested_in_alias=False)
         ]
 
         self.mock_store.get_app_services = Mock(return_value=services)
@@ -137,3 +137,10 @@ class AppServiceHandlerTestCase(unittest.TestCase):
         service.token = "mock_service_token"
         service.url = "mock_service_url"
         return service
+
+    def _mkservice_alias(self, is_interested_in_alias):
+        service = Mock()
+        service.is_interested_in_alias = Mock(return_value=is_interested_in_alias)
+        service.token = "mock_service_token"
+        service.url = "mock_service_url"
+        return service