diff --git a/synapse/api/auth.py b/synapse/api/auth.py
index b5536e8565..3038df4ab8 100644
--- a/synapse/api/auth.py
+++ b/synapse/api/auth.py
@@ -24,6 +24,7 @@ from synapse.api.constants import EventTypes, Membership, JoinRules
from synapse.api.errors import AuthError, Codes, SynapseError, EventSizeError
from synapse.types import Requester, RoomID, UserID, EventID
from synapse.util.logutils import log_function
+from synapse.util.logcontext import preserve_context_over_fn
from unpaddedbase64 import decode_base64
import logging
@@ -433,31 +434,46 @@ class Auth(object):
if event.user_id != invite_event.user_id:
return False
- try:
- public_key = invite_event.content["public_key"]
- if signed["mxid"] != event.state_key:
- return False
- if signed["token"] != token:
- return False
- for server, signature_block in signed["signatures"].items():
- for key_name, encoded_signature in signature_block.items():
- if not key_name.startswith("ed25519:"):
- return False
- verify_key = decode_verify_key_bytes(
- key_name,
- decode_base64(public_key)
- )
- verify_signed_json(signed, server, verify_key)
- # We got the public key from the invite, so we know that the
- # correct server signed the signed bundle.
- # The caller is responsible for checking that the signing
- # server has not revoked that public key.
- return True
+ if signed["mxid"] != event.state_key:
return False
- except (KeyError, SignatureVerifyException,):
+ if signed["token"] != token:
return False
+ for public_key_object in self.get_public_keys(invite_event):
+ public_key = public_key_object["public_key"]
+ try:
+ for server, signature_block in signed["signatures"].items():
+ for key_name, encoded_signature in signature_block.items():
+ if not key_name.startswith("ed25519:"):
+ continue
+ verify_key = decode_verify_key_bytes(
+ key_name,
+ decode_base64(public_key)
+ )
+ verify_signed_json(signed, server, verify_key)
+
+ # We got the public key from the invite, so we know that the
+ # correct server signed the signed bundle.
+ # The caller is responsible for checking that the signing
+ # server has not revoked that public key.
+ return True
+ except (KeyError, SignatureVerifyException,):
+ continue
+ return False
+
+ def get_public_keys(self, invite_event):
+ public_keys = []
+ if "public_key" in invite_event.content:
+ o = {
+ "public_key": invite_event.content["public_key"],
+ }
+ if "key_validity_url" in invite_event.content:
+ o["key_validity_url"] = invite_event.content["key_validity_url"]
+ public_keys.append(o)
+ public_keys.extend(invite_event.content.get("public_keys", []))
+ return public_keys
+
def _get_power_level_event(self, auth_events):
key = (EventTypes.PowerLevels, "", )
return auth_events.get(key)
@@ -518,7 +534,7 @@ class Auth(object):
)
access_token = request.args["access_token"][0]
- user_info = yield self._get_user_by_access_token(access_token)
+ user_info = yield self.get_user_by_access_token(access_token)
user = user_info["user"]
token_id = user_info["token_id"]
is_guest = user_info["is_guest"]
@@ -529,7 +545,8 @@ class Auth(object):
default=[""]
)[0]
if user and access_token and ip_addr:
- self.store.insert_client_ip(
+ preserve_context_over_fn(
+ self.store.insert_client_ip,
user=user,
access_token=access_token,
ip=ip_addr,
@@ -574,11 +591,11 @@ class Auth(object):
raise AuthError(
403,
"Application service has not registered this user"
- )
+ )
defer.returnValue(user_id)
@defer.inlineCallbacks
- def _get_user_by_access_token(self, token):
+ def get_user_by_access_token(self, token):
""" Get a registered user's ID.
Args:
@@ -696,6 +713,7 @@ class Auth(object):
def _look_up_user_by_access_token(self, token):
ret = yield self.store.get_user_by_access_token(token)
if not ret:
+ logger.warn("Unrecognised access token - not in store: %s" % (token,))
raise AuthError(
self.TOKEN_NOT_FOUND_HTTP_STATUS, "Unrecognised access token.",
errcode=Codes.UNKNOWN_TOKEN
@@ -713,6 +731,7 @@ class Auth(object):
token = request.args["access_token"][0]
service = yield self.store.get_app_service_by_token(token)
if not service:
+ logger.warn("Unrecognised appservice access token: %s" % (token,))
raise AuthError(
self.TOKEN_NOT_FOUND_HTTP_STATUS,
"Unrecognised access token.",
diff --git a/synapse/api/constants.py b/synapse/api/constants.py
index 84cbe710b3..8cf4d6169c 100644
--- a/synapse/api/constants.py
+++ b/synapse/api/constants.py
@@ -32,7 +32,6 @@ class PresenceState(object):
OFFLINE = u"offline"
UNAVAILABLE = u"unavailable"
ONLINE = u"online"
- FREE_FOR_CHAT = u"free_for_chat"
class JoinRules(object):
diff --git a/synapse/api/filtering.py b/synapse/api/filtering.py
index c7f021d1ff..cd699ef27f 100644
--- a/synapse/api/filtering.py
+++ b/synapse/api/filtering.py
@@ -15,6 +15,8 @@
from synapse.api.errors import SynapseError
from synapse.types import UserID, RoomID
+import ujson as json
+
class Filtering(object):
@@ -28,14 +30,14 @@ class Filtering(object):
return result
def add_user_filter(self, user_localpart, user_filter):
- self._check_valid_filter(user_filter)
+ self.check_valid_filter(user_filter)
return self.store.add_user_filter(user_localpart, user_filter)
# TODO(paul): surely we should probably add a delete_user_filter or
# replace_user_filter at some point? There's no REST API specified for
# them however
- def _check_valid_filter(self, user_filter_json):
+ def check_valid_filter(self, user_filter_json):
"""Check if the provided filter is valid.
This inspects all definitions contained within the filter.
@@ -129,52 +131,58 @@ class Filtering(object):
class FilterCollection(object):
def __init__(self, filter_json):
- self.filter_json = filter_json
+ self._filter_json = filter_json
- room_filter_json = self.filter_json.get("room", {})
+ room_filter_json = self._filter_json.get("room", {})
- self.room_filter = Filter({
+ self._room_filter = Filter({
k: v for k, v in room_filter_json.items()
if k in ("rooms", "not_rooms")
})
- self.room_timeline_filter = Filter(room_filter_json.get("timeline", {}))
- self.room_state_filter = Filter(room_filter_json.get("state", {}))
- self.room_ephemeral_filter = Filter(room_filter_json.get("ephemeral", {}))
- self.room_account_data = Filter(room_filter_json.get("account_data", {}))
- self.presence_filter = Filter(self.filter_json.get("presence", {}))
- self.account_data = Filter(self.filter_json.get("account_data", {}))
+ self._room_timeline_filter = Filter(room_filter_json.get("timeline", {}))
+ self._room_state_filter = Filter(room_filter_json.get("state", {}))
+ self._room_ephemeral_filter = Filter(room_filter_json.get("ephemeral", {}))
+ self._room_account_data = Filter(room_filter_json.get("account_data", {}))
+ self._presence_filter = Filter(filter_json.get("presence", {}))
+ self._account_data = Filter(filter_json.get("account_data", {}))
- self.include_leave = self.filter_json.get("room", {}).get(
+ self.include_leave = filter_json.get("room", {}).get(
"include_leave", False
)
+ def __repr__(self):
+ return "<FilterCollection %s>" % (json.dumps(self._filter_json),)
+
+ def get_filter_json(self):
+ return self._filter_json
+
def timeline_limit(self):
- return self.room_timeline_filter.limit()
+ return self._room_timeline_filter.limit()
def presence_limit(self):
- return self.presence_filter.limit()
+ return self._presence_filter.limit()
def ephemeral_limit(self):
- return self.room_ephemeral_filter.limit()
+ return self._room_ephemeral_filter.limit()
def filter_presence(self, events):
- return self.presence_filter.filter(events)
+ return self._presence_filter.filter(events)
def filter_account_data(self, events):
- return self.account_data.filter(events)
+ return self._account_data.filter(events)
def filter_room_state(self, events):
- return self.room_state_filter.filter(self.room_filter.filter(events))
+ return self._room_state_filter.filter(self._room_filter.filter(events))
def filter_room_timeline(self, events):
- return self.room_timeline_filter.filter(self.room_filter.filter(events))
+ return self._room_timeline_filter.filter(self._room_filter.filter(events))
def filter_room_ephemeral(self, events):
- return self.room_ephemeral_filter.filter(self.room_filter.filter(events))
+ return self._room_ephemeral_filter.filter(self._room_filter.filter(events))
def filter_room_account_data(self, events):
- return self.room_account_data.filter(self.room_filter.filter(events))
+ return self._room_account_data.filter(self._room_filter.filter(events))
class Filter(object):
@@ -187,18 +195,19 @@ class Filter(object):
Returns:
bool: True if the event matches
"""
- if isinstance(event, dict):
- return self.check_fields(
- event.get("room_id", None),
- event.get("sender", None),
- event.get("type", None),
- )
- else:
- return self.check_fields(
- getattr(event, "room_id", None),
- getattr(event, "sender", None),
- event.type,
- )
+ sender = event.get("sender", None)
+ if not sender:
+ # Presence events have their 'sender' in content.user_id
+ content = event.get("content")
+ # account_data has been allowed to have non-dict content, so check type first
+ if isinstance(content, dict):
+ sender = content.get("user_id")
+
+ return self.check_fields(
+ event.get("room_id", None),
+ sender,
+ event.get("type", None),
+ )
def check_fields(self, room_id, sender, event_type):
"""Checks whether the filter matches the given event fields.
@@ -258,3 +267,6 @@ def _matches_wildcard(actual_value, filter_value):
return actual_value.startswith(type_prefix)
else:
return actual_value == filter_value
+
+
+DEFAULT_FILTER_COLLECTION = FilterCollection({})
diff --git a/synapse/api/urls.py b/synapse/api/urls.py
index 19824f9a02..0fd9b7f244 100644
--- a/synapse/api/urls.py
+++ b/synapse/api/urls.py
@@ -23,5 +23,6 @@ WEB_CLIENT_PREFIX = "/_matrix/client"
CONTENT_REPO_PREFIX = "/_matrix/content"
SERVER_KEY_PREFIX = "/_matrix/key/v1"
SERVER_KEY_V2_PREFIX = "/_matrix/key/v2"
-MEDIA_PREFIX = "/_matrix/media/v1"
+MEDIA_PREFIX = "/_matrix/media/r0"
+LEGACY_MEDIA_PREFIX = "/_matrix/media/v1"
APP_SERVICE_PREFIX = "/_matrix/appservice/v1"
|