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.py10
-rw-r--r--synapse/handlers/account_data.py (renamed from synapse/handlers/private_user_data.py)6
-rw-r--r--synapse/handlers/auth.py37
-rw-r--r--synapse/handlers/message.py12
-rw-r--r--synapse/handlers/room.py3
-rw-r--r--synapse/handlers/search.py55
-rw-r--r--synapse/handlers/sync.py28
7 files changed, 122 insertions, 29 deletions
diff --git a/synapse/handlers/_base.py b/synapse/handlers/_base.py
index 6519f183df..5fd20285d2 100644
--- a/synapse/handlers/_base.py
+++ b/synapse/handlers/_base.py
@@ -92,7 +92,15 @@ class BaseHandler(object):
 
             membership_event = state.get((EventTypes.Member, user_id), None)
             if membership_event:
-                membership = membership_event.membership
+                was_forgotten_at_event = yield self.store.was_forgotten_at(
+                    membership_event.state_key,
+                    membership_event.room_id,
+                    membership_event.event_id
+                )
+                if was_forgotten_at_event:
+                    membership = None
+                else:
+                    membership = membership_event.membership
             else:
                 membership = None
 
diff --git a/synapse/handlers/private_user_data.py b/synapse/handlers/account_data.py
index 1abe45ed7b..1d35d3b7dc 100644
--- a/synapse/handlers/private_user_data.py
+++ b/synapse/handlers/account_data.py
@@ -16,19 +16,19 @@
 from twisted.internet import defer
 
 
-class PrivateUserDataEventSource(object):
+class AccountDataEventSource(object):
     def __init__(self, hs):
         self.store = hs.get_datastore()
 
     def get_current_key(self, direction='f'):
-        return self.store.get_max_private_user_data_stream_id()
+        return self.store.get_max_account_data_stream_id()
 
     @defer.inlineCallbacks
     def get_new_events(self, user, from_key, **kwargs):
         user_id = user.to_string()
         last_stream_id = from_key
 
-        current_stream_id = yield self.store.get_max_private_user_data_stream_id()
+        current_stream_id = yield self.store.get_max_account_data_stream_id()
         tags = yield self.store.get_updated_tags(user_id, last_stream_id)
 
         results = []
diff --git a/synapse/handlers/auth.py b/synapse/handlers/auth.py
index 1b11dbdffd..e64b67cdfd 100644
--- a/synapse/handlers/auth.py
+++ b/synapse/handlers/auth.py
@@ -18,7 +18,7 @@ from twisted.internet import defer
 from ._base import BaseHandler
 from synapse.api.constants import LoginType
 from synapse.types import UserID
-from synapse.api.errors import LoginError, Codes
+from synapse.api.errors import AuthError, LoginError, Codes
 from synapse.util.async import run_on_reactor
 
 from twisted.web.client import PartialDownloadError
@@ -46,6 +46,7 @@ class AuthHandler(BaseHandler):
         }
         self.bcrypt_rounds = hs.config.bcrypt_rounds
         self.sessions = {}
+        self.INVALID_TOKEN_HTTP_STATUS = 401
 
     @defer.inlineCallbacks
     def check_auth(self, flows, clientdict, clientip):
@@ -297,10 +298,11 @@ class AuthHandler(BaseHandler):
         defer.returnValue((user_id, access_token, refresh_token))
 
     @defer.inlineCallbacks
-    def login_with_cas_user_id(self, user_id):
+    def get_login_tuple_for_user_id(self, user_id):
         """
-        Authenticates the user with the given user ID,
-        intended to have been captured from a CAS response
+        Gets login tuple for the user with the given user ID.
+        The user is assumed to have been authenticated by some other
+        machanism (e.g. CAS)
 
         Args:
             user_id (str): User ID
@@ -393,6 +395,23 @@ class AuthHandler(BaseHandler):
         ))
         return m.serialize()
 
+    def generate_short_term_login_token(self, user_id):
+        macaroon = self._generate_base_macaroon(user_id)
+        macaroon.add_first_party_caveat("type = login")
+        now = self.hs.get_clock().time_msec()
+        expiry = now + (2 * 60 * 1000)
+        macaroon.add_first_party_caveat("time < %d" % (expiry,))
+        return macaroon.serialize()
+
+    def validate_short_term_login_token_and_get_user_id(self, login_token):
+        try:
+            macaroon = pymacaroons.Macaroon.deserialize(login_token)
+            auth_api = self.hs.get_auth()
+            auth_api.validate_macaroon(macaroon, "login", True)
+            return self._get_user_from_macaroon(macaroon)
+        except (pymacaroons.exceptions.MacaroonException, TypeError, ValueError):
+            raise AuthError(401, "Invalid token", errcode=Codes.UNKNOWN_TOKEN)
+
     def _generate_base_macaroon(self, user_id):
         macaroon = pymacaroons.Macaroon(
             location=self.hs.config.server_name,
@@ -402,6 +421,16 @@ class AuthHandler(BaseHandler):
         macaroon.add_first_party_caveat("user_id = %s" % (user_id,))
         return macaroon
 
+    def _get_user_from_macaroon(self, macaroon):
+        user_prefix = "user_id = "
+        for caveat in macaroon.caveats:
+            if caveat.caveat_id.startswith(user_prefix):
+                return caveat.caveat_id[len(user_prefix):]
+        raise AuthError(
+            self.INVALID_TOKEN_HTTP_STATUS, "No user_id found in token",
+            errcode=Codes.UNKNOWN_TOKEN
+        )
+
     @defer.inlineCallbacks
     def set_password(self, user_id, newpassword):
         password_hash = self.hash(newpassword)
diff --git a/synapse/handlers/message.py b/synapse/handlers/message.py
index a92409c6a2..64c57375f7 100644
--- a/synapse/handlers/message.py
+++ b/synapse/handlers/message.py
@@ -436,14 +436,14 @@ class MessageHandler(BaseHandler):
                     for c in current_state.values()
                 ]
 
-                private_user_data = []
+                account_data = []
                 tags = tags_by_room.get(event.room_id)
                 if tags:
-                    private_user_data.append({
+                    account_data.append({
                         "type": "m.tag",
                         "content": {"tags": tags},
                     })
-                d["private_user_data"] = private_user_data
+                d["account_data"] = account_data
             except:
                 logger.exception("Failed to get snapshot")
 
@@ -498,14 +498,14 @@ class MessageHandler(BaseHandler):
                 user_id, room_id, pagin_config, membership, member_event_id, is_guest
             )
 
-        private_user_data = []
+        account_data = []
         tags = yield self.store.get_tags_for_room(user_id, room_id)
         if tags:
-            private_user_data.append({
+            account_data.append({
                 "type": "m.tag",
                 "content": {"tags": tags},
             })
-        result["private_user_data"] = private_user_data
+        result["account_data"] = account_data
 
         defer.returnValue(result)
 
diff --git a/synapse/handlers/room.py b/synapse/handlers/room.py
index 3f04752581..023b4001b8 100644
--- a/synapse/handlers/room.py
+++ b/synapse/handlers/room.py
@@ -743,6 +743,9 @@ class RoomMemberHandler(BaseHandler):
         )
         defer.returnValue((token, public_key, key_validity_url, display_name))
 
+    def forget(self, user, room_id):
+        self.store.forget(user.to_string(), room_id)
+
 
 class RoomListHandler(BaseHandler):
 
diff --git a/synapse/handlers/search.py b/synapse/handlers/search.py
index b7545c111f..50688e51a8 100644
--- a/synapse/handlers/search.py
+++ b/synapse/handlers/search.py
@@ -17,13 +17,14 @@ from twisted.internet import defer
 
 from ._base import BaseHandler
 
-from synapse.api.constants import Membership
+from synapse.api.constants import Membership, EventTypes
 from synapse.api.filtering import Filter
 from synapse.api.errors import SynapseError
 from synapse.events.utils import serialize_event
 
 from unpaddedbase64 import decode_base64, encode_base64
 
+import itertools
 import logging
 
 
@@ -79,6 +80,9 @@ class SearchHandler(BaseHandler):
             # What to order results by (impacts whether pagination can be doen)
             order_by = room_cat.get("order_by", "rank")
 
+            # Return the current state of the rooms?
+            include_state = room_cat.get("include_state", False)
+
             # Include context around each event?
             event_context = room_cat.get(
                 "event_context", None
@@ -96,6 +100,10 @@ class SearchHandler(BaseHandler):
                 after_limit = int(event_context.get(
                     "after_limit", 5
                 ))
+
+                # Return the historic display name and avatar for the senders
+                # of the events?
+                include_profile = bool(event_context.get("include_profile", False))
         except KeyError:
             raise SynapseError(400, "Invalid search query")
 
@@ -269,6 +277,33 @@ class SearchHandler(BaseHandler):
                     "room_key", res["end"]
                 ).to_string()
 
+                if include_profile:
+                    senders = set(
+                        ev.sender
+                        for ev in itertools.chain(
+                            res["events_before"], [event], res["events_after"]
+                        )
+                    )
+
+                    if res["events_after"]:
+                        last_event_id = res["events_after"][-1].event_id
+                    else:
+                        last_event_id = event.event_id
+
+                    state = yield self.store.get_state_for_event(
+                        last_event_id,
+                        types=[(EventTypes.Member, sender) for sender in senders]
+                    )
+
+                    res["profile_info"] = {
+                        s.state_key: {
+                            "displayname": s.content.get("displayname", None),
+                            "avatar_url": s.content.get("avatar_url", None),
+                        }
+                        for s in state.values()
+                        if s.type == EventTypes.Member and s.state_key in senders
+                    }
+
                 contexts[event.event_id] = res
         else:
             contexts = {}
@@ -287,6 +322,18 @@ class SearchHandler(BaseHandler):
                 for e in context["events_after"]
             ]
 
+        state_results = {}
+        if include_state:
+            rooms = set(e.room_id for e in allowed_events)
+            for room_id in rooms:
+                state = yield self.state_handler.get_current_state(room_id)
+                state_results[room_id] = state.values()
+
+            state_results.values()
+
+        # We're now about to serialize the events. We should not make any
+        # blocking calls after this. Otherwise the 'age' will be wrong
+
         results = {
             e.event_id: {
                 "rank": rank_map[e.event_id],
@@ -303,6 +350,12 @@ class SearchHandler(BaseHandler):
             "count": len(results)
         }
 
+        if state_results:
+            rooms_cat_res["state"] = {
+                room_id: [serialize_event(e, time_now) for e in state]
+                for room_id, state in state_results.items()
+            }
+
         if room_groups and "room_id" in group_keys:
             rooms_cat_res.setdefault("groups", {})["room_id"] = room_groups
 
diff --git a/synapse/handlers/sync.py b/synapse/handlers/sync.py
index 6dc9d0fb92..877328b29e 100644
--- a/synapse/handlers/sync.py
+++ b/synapse/handlers/sync.py
@@ -51,7 +51,7 @@ class JoinedSyncResult(collections.namedtuple("JoinedSyncResult", [
     "timeline",          # TimelineBatch
     "state",             # dict[(str, str), FrozenEvent]
     "ephemeral",
-    "private_user_data",
+    "account_data",
 ])):
     __slots__ = []
 
@@ -63,7 +63,7 @@ class JoinedSyncResult(collections.namedtuple("JoinedSyncResult", [
             self.timeline
             or self.state
             or self.ephemeral
-            or self.private_user_data
+            or self.account_data
         )
 
 
@@ -71,7 +71,7 @@ class ArchivedSyncResult(collections.namedtuple("JoinedSyncResult", [
     "room_id",            # str
     "timeline",           # TimelineBatch
     "state",              # dict[(str, str), FrozenEvent]
-    "private_user_data",
+    "account_data",
 ])):
     __slots__ = []
 
@@ -82,7 +82,7 @@ class ArchivedSyncResult(collections.namedtuple("JoinedSyncResult", [
         return bool(
             self.timeline
             or self.state
-            or self.private_user_data
+            or self.account_data
         )
 
 
@@ -261,20 +261,20 @@ class SyncHandler(BaseHandler):
             timeline=batch,
             state=current_state,
             ephemeral=ephemeral_by_room.get(room_id, []),
-            private_user_data=self.private_user_data_for_room(
+            account_data=self.account_data_for_room(
                 room_id, tags_by_room
             ),
         ))
 
-    def private_user_data_for_room(self, room_id, tags_by_room):
-        private_user_data = []
+    def account_data_for_room(self, room_id, tags_by_room):
+        account_data = []
         tags = tags_by_room.get(room_id)
         if tags is not None:
-            private_user_data.append({
+            account_data.append({
                 "type": "m.tag",
                 "content": {"tags": tags},
             })
-        return private_user_data
+        return account_data
 
     @defer.inlineCallbacks
     def ephemeral_by_room(self, sync_config, now_token, since_token=None):
@@ -357,7 +357,7 @@ class SyncHandler(BaseHandler):
             room_id=room_id,
             timeline=batch,
             state=leave_state,
-            private_user_data=self.private_user_data_for_room(
+            account_data=self.account_data_for_room(
                 room_id, tags_by_room
             ),
         ))
@@ -412,7 +412,7 @@ class SyncHandler(BaseHandler):
 
         tags_by_room = yield self.store.get_updated_tags(
             sync_config.user.to_string(),
-            since_token.private_user_data_key,
+            since_token.account_data_key,
         )
 
         joined = []
@@ -468,7 +468,7 @@ class SyncHandler(BaseHandler):
                     ),
                     state=state,
                     ephemeral=ephemeral_by_room.get(room_id, []),
-                    private_user_data=self.private_user_data_for_room(
+                    account_data=self.account_data_for_room(
                         room_id, tags_by_room
                     ),
                 )
@@ -605,7 +605,7 @@ class SyncHandler(BaseHandler):
             timeline=batch,
             state=state,
             ephemeral=ephemeral_by_room.get(room_id, []),
-            private_user_data=self.private_user_data_for_room(
+            account_data=self.account_data_for_room(
                 room_id, tags_by_room
             ),
         )
@@ -653,7 +653,7 @@ class SyncHandler(BaseHandler):
             room_id=leave_event.room_id,
             timeline=batch,
             state=state_events_delta,
-            private_user_data=self.private_user_data_for_room(
+            account_data=self.account_data_for_room(
                 leave_event.room_id, tags_by_room
             ),
         )