summary refs log tree commit diff
path: root/synapse/handlers
diff options
context:
space:
mode:
Diffstat (limited to 'synapse/handlers')
-rw-r--r--synapse/handlers/_base.py6
-rw-r--r--synapse/handlers/auth.py12
-rw-r--r--synapse/handlers/message.py21
-rw-r--r--synapse/handlers/room.py7
-rw-r--r--synapse/handlers/typing.py12
5 files changed, 51 insertions, 7 deletions
diff --git a/synapse/handlers/_base.py b/synapse/handlers/_base.py
index 4981643166..90f96209f8 100644
--- a/synapse/handlers/_base.py
+++ b/synapse/handlers/_base.py
@@ -57,10 +57,16 @@ class BaseHandler(object):
         time_now = self.clock.time()
         user_id = requester.user.to_string()
 
+        # The AS user itself is never rate limited.
         app_service = self.store.get_app_service_by_user_id(user_id)
         if app_service is not None:
             return  # do not ratelimit app service senders
 
+        # Disable rate limiting of users belonging to any AS that is configured
+        # not to be rate limited in its registration file (rate_limited: true|false).
+        if requester.app_service and not requester.app_service.is_rate_limited():
+            return
+
         allowed, time_allowed = self.ratelimiter.send_message(
             user_id, time_now,
             msg_rate_hz=self.hs.config.rc_messages_per_second,
diff --git a/synapse/handlers/auth.py b/synapse/handlers/auth.py
index dc0fe60e1b..3635521230 100644
--- a/synapse/handlers/auth.py
+++ b/synapse/handlers/auth.py
@@ -611,6 +611,18 @@ class AuthHandler(BaseHandler):
 
     @defer.inlineCallbacks
     def add_threepid(self, user_id, medium, address, validated_at):
+        # 'Canonicalise' email addresses down to lower case.
+        # We've now moving towards the Home Server being the entity that
+        # is responsible for validating threepids used for resetting passwords
+        # on accounts, so in future Synapse will gain knowledge of specific
+        # types (mediums) of threepid. For now, we still use the existing
+        # infrastructure, but this is the start of synapse gaining knowledge
+        # of specific types of threepid (and fixes the fact that checking
+        # for the presenc eof an email address during password reset was
+        # case sensitive).
+        if medium == 'email':
+            address = address.lower()
+
         yield self.store.user_add_threepid(
             user_id, medium, address, validated_at,
             self.hs.get_clock().time_msec()
diff --git a/synapse/handlers/message.py b/synapse/handlers/message.py
index 30ea9630f7..abfa8c65a4 100644
--- a/synapse/handlers/message.py
+++ b/synapse/handlers/message.py
@@ -16,7 +16,7 @@
 from twisted.internet import defer
 
 from synapse.api.constants import EventTypes, Membership
-from synapse.api.errors import AuthError, Codes, SynapseError
+from synapse.api.errors import AuthError, Codes, SynapseError, LimitExceededError
 from synapse.crypto.event_signing import add_hashes_and_signatures
 from synapse.events.utils import serialize_event
 from synapse.events.validator import EventValidator
@@ -82,8 +82,8 @@ class MessageHandler(BaseHandler):
             room_token = pagin_config.from_token.room_key
         else:
             pagin_config.from_token = (
-                yield self.hs.get_event_sources().get_current_token(
-                    direction='b'
+                yield self.hs.get_event_sources().get_current_token_for_room(
+                    room_id=room_id
                 )
             )
             room_token = pagin_config.from_token.room_key
@@ -239,6 +239,21 @@ class MessageHandler(BaseHandler):
                 "Tried to send member event through non-member codepath"
             )
 
+        # We check here if we are currently being rate limited, so that we
+        # don't do unnecessary work. We check again just before we actually
+        # send the event.
+        time_now = self.clock.time()
+        allowed, time_allowed = self.ratelimiter.send_message(
+            event.sender, time_now,
+            msg_rate_hz=self.hs.config.rc_messages_per_second,
+            burst_count=self.hs.config.rc_message_burst_count,
+            update=False,
+        )
+        if not allowed:
+            raise LimitExceededError(
+                retry_after_ms=int(1000 * (time_allowed - time_now)),
+            )
+
         user = UserID.from_string(event.sender)
 
         assert self.hs.is_mine(user), "User must be our own: %s" % (user,)
diff --git a/synapse/handlers/room.py b/synapse/handlers/room.py
index a7f533f7be..59e4d1cd15 100644
--- a/synapse/handlers/room.py
+++ b/synapse/handlers/room.py
@@ -475,8 +475,11 @@ class RoomEventSource(object):
 
         defer.returnValue((events, end_key))
 
-    def get_current_key(self, direction='f'):
-        return self.store.get_room_events_max_id(direction)
+    def get_current_key(self):
+        return self.store.get_room_events_max_id()
+
+    def get_current_key_for_room(self, room_id):
+        return self.store.get_room_events_max_id(room_id)
 
     @defer.inlineCallbacks
     def get_pagination_rows(self, user, config, key):
diff --git a/synapse/handlers/typing.py b/synapse/handlers/typing.py
index 08313417b2..27ee715ff0 100644
--- a/synapse/handlers/typing.py
+++ b/synapse/handlers/typing.py
@@ -88,7 +88,7 @@ class TypingHandler(object):
                 continue
 
             until = self._member_typing_until.get(member, None)
-            if not until or until < now:
+            if not until or until <= now:
                 logger.info("Timing out typing for: %s", member.user_id)
                 preserve_fn(self._stopped_typing)(member)
                 continue
@@ -97,12 +97,20 @@ class TypingHandler(object):
             # user.
             if self.hs.is_mine_id(member.user_id):
                 last_fed_poke = self._member_last_federation_poke.get(member, None)
-                if not last_fed_poke or last_fed_poke + FEDERATION_PING_INTERVAL < now:
+                if not last_fed_poke or last_fed_poke + FEDERATION_PING_INTERVAL <= now:
                     preserve_fn(self._push_remote)(
                         member=member,
                         typing=True
                     )
 
+            # Add a paranoia timer to ensure that we always have a timer for
+            # each person typing.
+            self.wheel_timer.insert(
+                now=now,
+                obj=member,
+                then=now + 60 * 1000,
+            )
+
     def is_typing(self, member):
         return member.user_id in self._room_typing.get(member.room_id, [])