diff --git a/synapse/__init__.py b/synapse/__init__.py
index 432567a110..f32c28be02 100644
--- a/synapse/__init__.py
+++ b/synapse/__init__.py
@@ -16,4 +16,4 @@
""" This is a reference implementation of a Matrix home server.
"""
-__version__ = "0.18.4"
+__version__ = "0.18.5-rc2"
diff --git a/synapse/api/auth.py b/synapse/api/auth.py
index 69b3392735..ddab210718 100644
--- a/synapse/api/auth.py
+++ b/synapse/api/auth.py
@@ -39,6 +39,9 @@ AuthEventTypes = (
EventTypes.ThirdPartyInvite,
)
+# guests always get this device id.
+GUEST_DEVICE_ID = "guest_device"
+
class Auth(object):
"""
@@ -51,17 +54,6 @@ class Auth(object):
self.store = hs.get_datastore()
self.state = hs.get_state_handler()
self.TOKEN_NOT_FOUND_HTTP_STATUS = 401
- # Docs for these currently lives at
- # github.com/matrix-org/matrix-doc/blob/master/drafts/macaroons_caveats.rst
- # In addition, we have type == delete_pusher which grants access only to
- # delete pushers.
- self._KNOWN_CAVEAT_PREFIXES = set([
- "gen = ",
- "guest = ",
- "type = ",
- "time < ",
- "user_id = ",
- ])
@defer.inlineCallbacks
def check_from_context(self, event, context, do_sig_check=True):
@@ -728,7 +720,8 @@ class Auth(object):
"user": user,
"is_guest": True,
"token_id": None,
- "device_id": None,
+ # all guests get the same device id
+ "device_id": GUEST_DEVICE_ID,
}
elif rights == "delete_pusher":
# We don't store these tokens in the database
@@ -798,27 +791,38 @@ class Auth(object):
Args:
macaroon(pymacaroons.Macaroon): The macaroon to validate
- type_string(str): The kind of token required (e.g. "access", "refresh",
+ type_string(str): The kind of token required (e.g. "access",
"delete_pusher")
verify_expiry(bool): Whether to verify whether the macaroon has expired.
- This should really always be True, but no clients currently implement
- token refresh, so we can't enforce expiry yet.
user_id (str): The user_id required
"""
v = pymacaroons.Verifier()
+
+ # the verifier runs a test for every caveat on the macaroon, to check
+ # that it is met for the current request. Each caveat must match at
+ # least one of the predicates specified by satisfy_exact or
+ # specify_general.
v.satisfy_exact("gen = 1")
v.satisfy_exact("type = " + type_string)
v.satisfy_exact("user_id = %s" % user_id)
v.satisfy_exact("guest = true")
+
+ # verify_expiry should really always be True, but there exist access
+ # tokens in the wild which expire when they should not, so we can't
+ # enforce expiry yet (so we have to allow any caveat starting with
+ # 'time < ' in access tokens).
+ #
+ # On the other hand, short-term login tokens (as used by CAS login, for
+ # example) have an expiry time which we do want to enforce.
+
if verify_expiry:
v.satisfy_general(self._verify_expiry)
else:
v.satisfy_general(lambda c: c.startswith("time < "))
- v.verify(macaroon, self.hs.config.macaroon_secret_key)
+ # access_tokens include a nonce for uniqueness: any value is acceptable
+ v.satisfy_general(lambda c: c.startswith("nonce = "))
- v = pymacaroons.Verifier()
- v.satisfy_general(self._verify_recognizes_caveats)
v.verify(macaroon, self.hs.config.macaroon_secret_key)
def _verify_expiry(self, caveat):
@@ -829,15 +833,6 @@ class Auth(object):
now = self.hs.get_clock().time_msec()
return now < expiry
- def _verify_recognizes_caveats(self, caveat):
- first_space = caveat.find(" ")
- if first_space < 0:
- return False
- second_space = caveat.find(" ", first_space + 1)
- if second_space < 0:
- return False
- return caveat[:second_space + 1] in self._KNOWN_CAVEAT_PREFIXES
-
@defer.inlineCallbacks
def _look_up_user_by_access_token(self, token):
ret = yield self.store.get_user_by_access_token(token)
diff --git a/synapse/config/logger.py b/synapse/config/logger.py
index dc68683fbc..ec72c95436 100644
--- a/synapse/config/logger.py
+++ b/synapse/config/logger.py
@@ -50,6 +50,7 @@ handlers:
console:
class: logging.StreamHandler
formatter: precise
+ filters: [context]
loggers:
synapse:
diff --git a/synapse/config/registration.py b/synapse/config/registration.py
index cc3f879857..87e500c97a 100644
--- a/synapse/config/registration.py
+++ b/synapse/config/registration.py
@@ -32,7 +32,6 @@ class RegistrationConfig(Config):
)
self.registration_shared_secret = config.get("registration_shared_secret")
- self.user_creation_max_duration = int(config["user_creation_max_duration"])
self.bcrypt_rounds = config.get("bcrypt_rounds", 12)
self.trusted_third_party_id_servers = config["trusted_third_party_id_servers"]
@@ -55,11 +54,6 @@ class RegistrationConfig(Config):
# secret, even if registration is otherwise disabled.
registration_shared_secret: "%(registration_shared_secret)s"
- # Sets the expiry for the short term user creation in
- # milliseconds. For instance the bellow duration is two weeks
- # in milliseconds.
- user_creation_max_duration: 1209600000
-
# Set the number of bcrypt rounds used to generate password hash.
# Larger numbers increase the work factor needed to generate the hash.
# The default number of rounds is 12.
diff --git a/synapse/federation/transaction_queue.py b/synapse/federation/transaction_queue.py
index c94c74a67e..51b656d74a 100644
--- a/synapse/federation/transaction_queue.py
+++ b/synapse/federation/transaction_queue.py
@@ -462,6 +462,13 @@ class TransactionQueue(object):
code = e.code
response = e.response
+ if e.code == 429 or 500 <= e.code:
+ logger.info(
+ "TX [%s] {%s} got %d response",
+ destination, txn_id, code
+ )
+ raise e
+
logger.info(
"TX [%s] {%s} got %d response",
destination, txn_id, code
diff --git a/synapse/handlers/auth.py b/synapse/handlers/auth.py
index 51e7616fcc..3b146f09d6 100644
--- a/synapse/handlers/auth.py
+++ b/synapse/handlers/auth.py
@@ -388,12 +388,10 @@ class AuthHandler(BaseHandler):
return self._check_password(user_id, password)
@defer.inlineCallbacks
- def get_login_tuple_for_user_id(self, user_id, device_id=None,
- initial_display_name=None):
+ def get_access_token_for_user_id(self, user_id, device_id=None,
+ initial_display_name=None):
"""
- Gets login tuple for the user with the given user ID.
-
- Creates a new access/refresh token for the user.
+ Creates a new access token for the user with the given user ID.
The user is assumed to have been authenticated by some other
machanism (e.g. CAS), and the user_id converted to the canonical case.
@@ -408,16 +406,13 @@ class AuthHandler(BaseHandler):
initial_display_name (str): display name to associate with the
device if it needs re-registering
Returns:
- A tuple of:
The access token for the user's session.
- The refresh token for the user's session.
Raises:
StoreError if there was a problem storing the token.
LoginError if there was an authentication problem.
"""
logger.info("Logging in user %s on device %s", user_id, device_id)
access_token = yield self.issue_access_token(user_id, device_id)
- refresh_token = yield self.issue_refresh_token(user_id, device_id)
# the device *should* have been registered before we got here; however,
# it's possible we raced against a DELETE operation. The thing we
@@ -428,7 +423,7 @@ class AuthHandler(BaseHandler):
user_id, device_id, initial_display_name
)
- defer.returnValue((access_token, refresh_token))
+ defer.returnValue(access_token)
@defer.inlineCallbacks
def check_user_exists(self, user_id):
@@ -539,35 +534,19 @@ class AuthHandler(BaseHandler):
device_id)
defer.returnValue(access_token)
- @defer.inlineCallbacks
- def issue_refresh_token(self, user_id, device_id=None):
- refresh_token = self.generate_refresh_token(user_id)
- yield self.store.add_refresh_token_to_user(user_id, refresh_token,
- device_id)
- defer.returnValue(refresh_token)
-
- def generate_access_token(self, user_id, extra_caveats=None,
- duration_in_ms=(60 * 60 * 1000)):
+ def generate_access_token(self, user_id, extra_caveats=None):
extra_caveats = extra_caveats or []
macaroon = self._generate_base_macaroon(user_id)
macaroon.add_first_party_caveat("type = access")
- now = self.hs.get_clock().time_msec()
- expiry = now + duration_in_ms
- macaroon.add_first_party_caveat("time < %d" % (expiry,))
+ # Include a nonce, to make sure that each login gets a different
+ # access token.
+ macaroon.add_first_party_caveat("nonce = %s" % (
+ stringutils.random_string_with_symbols(16),
+ ))
for caveat in extra_caveats:
macaroon.add_first_party_caveat(caveat)
return macaroon.serialize()
- def generate_refresh_token(self, user_id):
- m = self._generate_base_macaroon(user_id)
- m.add_first_party_caveat("type = refresh")
- # Important to add a nonce, because otherwise every refresh token for a
- # user will be the same.
- m.add_first_party_caveat("nonce = %s" % (
- stringutils.random_string_with_symbols(16),
- ))
- return m.serialize()
-
def generate_short_term_login_token(self, user_id, duration_in_ms=(2 * 60 * 1000)):
macaroon = self._generate_base_macaroon(user_id)
macaroon.add_first_party_caveat("type = login")
diff --git a/synapse/handlers/register.py b/synapse/handlers/register.py
index 7e119f13b1..886fec8701 100644
--- a/synapse/handlers/register.py
+++ b/synapse/handlers/register.py
@@ -369,7 +369,7 @@ class RegistrationHandler(BaseHandler):
defer.returnValue(data)
@defer.inlineCallbacks
- def get_or_create_user(self, requester, localpart, displayname, duration_in_ms,
+ def get_or_create_user(self, requester, localpart, displayname,
password_hash=None):
"""Creates a new user if the user does not exist,
else revokes all previous access tokens and generates a new one.
@@ -399,8 +399,7 @@ class RegistrationHandler(BaseHandler):
user = UserID(localpart, self.hs.hostname)
user_id = user.to_string()
- token = self.auth_handler().generate_access_token(
- user_id, None, duration_in_ms)
+ token = self.auth_handler().generate_access_token(user_id)
if need_register:
yield self.store.register(
diff --git a/synapse/http/matrixfederationclient.py b/synapse/http/matrixfederationclient.py
index d0556ae347..d5970c05a8 100644
--- a/synapse/http/matrixfederationclient.py
+++ b/synapse/http/matrixfederationclient.py
@@ -33,6 +33,7 @@ from synapse.api.errors import (
from signedjson.sign import sign_json
+import cgi
import simplejson as json
import logging
import random
@@ -292,12 +293,7 @@ class MatrixFederationHttpClient(object):
if 200 <= response.code < 300:
# We need to update the transactions table to say it was sent?
- c_type = response.headers.getRawHeaders("Content-Type")
-
- if "application/json" not in c_type:
- raise RuntimeError(
- "Content-Type not application/json"
- )
+ check_content_type_is_json(response.headers)
body = yield preserve_context_over_fn(readBody, response)
defer.returnValue(json.loads(body))
@@ -342,12 +338,7 @@ class MatrixFederationHttpClient(object):
if 200 <= response.code < 300:
# We need to update the transactions table to say it was sent?
- c_type = response.headers.getRawHeaders("Content-Type")
-
- if "application/json" not in c_type:
- raise RuntimeError(
- "Content-Type not application/json"
- )
+ check_content_type_is_json(response.headers)
body = yield preserve_context_over_fn(readBody, response)
@@ -400,12 +391,7 @@ class MatrixFederationHttpClient(object):
if 200 <= response.code < 300:
# We need to update the transactions table to say it was sent?
- c_type = response.headers.getRawHeaders("Content-Type")
-
- if "application/json" not in c_type:
- raise RuntimeError(
- "Content-Type not application/json"
- )
+ check_content_type_is_json(response.headers)
body = yield preserve_context_over_fn(readBody, response)
@@ -525,3 +511,29 @@ def _flatten_response_never_received(e):
)
else:
return "%s: %s" % (type(e).__name__, e.message,)
+
+
+def check_content_type_is_json(headers):
+ """
+ Check that a set of HTTP headers have a Content-Type header, and that it
+ is application/json.
+
+ Args:
+ headers (twisted.web.http_headers.Headers): headers to check
+
+ Raises:
+ RuntimeError if the
+
+ """
+ c_type = headers.getRawHeaders("Content-Type")
+ if c_type is None:
+ raise RuntimeError(
+ "No Content-Type header"
+ )
+
+ c_type = c_type[0] # only the first header
+ val, options = cgi.parse_header(c_type)
+ if val != "application/json":
+ raise RuntimeError(
+ "Content-Type not application/json: was '%s'" % c_type
+ )
diff --git a/synapse/rest/client/v1/login.py b/synapse/rest/client/v1/login.py
index 345018a8fc..093bc072f4 100644
--- a/synapse/rest/client/v1/login.py
+++ b/synapse/rest/client/v1/login.py
@@ -137,16 +137,13 @@ class LoginRestServlet(ClientV1RestServlet):
password=login_submission["password"],
)
device_id = yield self._register_device(user_id, login_submission)
- access_token, refresh_token = (
- yield auth_handler.get_login_tuple_for_user_id(
- user_id, device_id,
- login_submission.get("initial_device_display_name")
- )
+ access_token = yield auth_handler.get_access_token_for_user_id(
+ user_id, device_id,
+ login_submission.get("initial_device_display_name"),
)
result = {
"user_id": user_id, # may have changed
"access_token": access_token,
- "refresh_token": refresh_token,
"home_server": self.hs.hostname,
"device_id": device_id,
}
@@ -161,16 +158,13 @@ class LoginRestServlet(ClientV1RestServlet):
yield auth_handler.validate_short_term_login_token_and_get_user_id(token)
)
device_id = yield self._register_device(user_id, login_submission)
- access_token, refresh_token = (
- yield auth_handler.get_login_tuple_for_user_id(
- user_id, device_id,
- login_submission.get("initial_device_display_name")
- )
+ access_token = yield auth_handler.get_access_token_for_user_id(
+ user_id, device_id,
+ login_submission.get("initial_device_display_name"),
)
result = {
"user_id": user_id, # may have changed
"access_token": access_token,
- "refresh_token": refresh_token,
"home_server": self.hs.hostname,
"device_id": device_id,
}
@@ -207,16 +201,14 @@ class LoginRestServlet(ClientV1RestServlet):
device_id = yield self._register_device(
registered_user_id, login_submission
)
- access_token, refresh_token = (
- yield auth_handler.get_login_tuple_for_user_id(
- registered_user_id, device_id,
- login_submission.get("initial_device_display_name")
- )
+ access_token = yield auth_handler.get_access_token_for_user_id(
+ registered_user_id, device_id,
+ login_submission.get("initial_device_display_name"),
)
+
result = {
"user_id": registered_user_id,
"access_token": access_token,
- "refresh_token": refresh_token,
"home_server": self.hs.hostname,
}
else:
diff --git a/synapse/rest/client/v1/register.py b/synapse/rest/client/v1/register.py
index b5a76fefac..ecf7e311a9 100644
--- a/synapse/rest/client/v1/register.py
+++ b/synapse/rest/client/v1/register.py
@@ -384,7 +384,6 @@ class CreateUserRestServlet(ClientV1RestServlet):
def __init__(self, hs):
super(CreateUserRestServlet, self).__init__(hs)
self.store = hs.get_datastore()
- self.direct_user_creation_max_duration = hs.config.user_creation_max_duration
self.handlers = hs.get_handlers()
@defer.inlineCallbacks
@@ -418,18 +417,8 @@ class CreateUserRestServlet(ClientV1RestServlet):
if "displayname" not in user_json:
raise SynapseError(400, "Expected 'displayname' key.")
- if "duration_seconds" not in user_json:
- raise SynapseError(400, "Expected 'duration_seconds' key.")
-
localpart = user_json["localpart"].encode("utf-8")
displayname = user_json["displayname"].encode("utf-8")
- duration_seconds = 0
- try:
- duration_seconds = int(user_json["duration_seconds"])
- except ValueError:
- raise SynapseError(400, "Failed to parse 'duration_seconds'")
- if duration_seconds > self.direct_user_creation_max_duration:
- duration_seconds = self.direct_user_creation_max_duration
password_hash = user_json["password_hash"].encode("utf-8") \
if user_json.get("password_hash") else None
@@ -438,7 +427,6 @@ class CreateUserRestServlet(ClientV1RestServlet):
requester=requester,
localpart=localpart,
displayname=displayname,
- duration_in_ms=(duration_seconds * 1000),
password_hash=password_hash
)
diff --git a/synapse/rest/client/v2_alpha/devices.py b/synapse/rest/client/v2_alpha/devices.py
index 3ba0b0fc07..a1feaf3d54 100644
--- a/synapse/rest/client/v2_alpha/devices.py
+++ b/synapse/rest/client/v2_alpha/devices.py
@@ -39,7 +39,7 @@ class DevicesRestServlet(servlet.RestServlet):
@defer.inlineCallbacks
def on_GET(self, request):
- requester = yield self.auth.get_user_by_req(request)
+ requester = yield self.auth.get_user_by_req(request, allow_guest=True)
devices = yield self.device_handler.get_devices_by_user(
requester.user.to_string()
)
@@ -63,7 +63,7 @@ class DeviceRestServlet(servlet.RestServlet):
@defer.inlineCallbacks
def on_GET(self, request, device_id):
- requester = yield self.auth.get_user_by_req(request)
+ requester = yield self.auth.get_user_by_req(request, allow_guest=True)
device = yield self.device_handler.get_device(
requester.user.to_string(),
device_id,
@@ -99,7 +99,7 @@ class DeviceRestServlet(servlet.RestServlet):
@defer.inlineCallbacks
def on_PUT(self, request, device_id):
- requester = yield self.auth.get_user_by_req(request)
+ requester = yield self.auth.get_user_by_req(request, allow_guest=True)
body = servlet.parse_json_object_from_request(request)
yield self.device_handler.update_device(
diff --git a/synapse/rest/client/v2_alpha/keys.py b/synapse/rest/client/v2_alpha/keys.py
index f185f9a774..08b7c99d57 100644
--- a/synapse/rest/client/v2_alpha/keys.py
+++ b/synapse/rest/client/v2_alpha/keys.py
@@ -65,7 +65,7 @@ class KeyUploadServlet(RestServlet):
@defer.inlineCallbacks
def on_POST(self, request, device_id):
- requester = yield self.auth.get_user_by_req(request)
+ requester = yield self.auth.get_user_by_req(request, allow_guest=True)
user_id = requester.user.to_string()
body = parse_json_object_from_request(request)
@@ -150,7 +150,7 @@ class KeyQueryServlet(RestServlet):
@defer.inlineCallbacks
def on_POST(self, request, user_id, device_id):
- yield self.auth.get_user_by_req(request)
+ yield self.auth.get_user_by_req(request, allow_guest=True)
timeout = parse_integer(request, "timeout", 10 * 1000)
body = parse_json_object_from_request(request)
result = yield self.e2e_keys_handler.query_devices(body, timeout)
@@ -158,7 +158,7 @@ class KeyQueryServlet(RestServlet):
@defer.inlineCallbacks
def on_GET(self, request, user_id, device_id):
- requester = yield self.auth.get_user_by_req(request)
+ requester = yield self.auth.get_user_by_req(request, allow_guest=True)
timeout = parse_integer(request, "timeout", 10 * 1000)
auth_user_id = requester.user.to_string()
user_id = user_id if user_id else auth_user_id
@@ -204,7 +204,7 @@ class OneTimeKeyServlet(RestServlet):
@defer.inlineCallbacks
def on_GET(self, request, user_id, device_id, algorithm):
- yield self.auth.get_user_by_req(request)
+ yield self.auth.get_user_by_req(request, allow_guest=True)
timeout = parse_integer(request, "timeout", 10 * 1000)
result = yield self.e2e_keys_handler.claim_one_time_keys(
{"one_time_keys": {user_id: {device_id: algorithm}}},
@@ -214,7 +214,7 @@ class OneTimeKeyServlet(RestServlet):
@defer.inlineCallbacks
def on_POST(self, request, user_id, device_id, algorithm):
- yield self.auth.get_user_by_req(request)
+ yield self.auth.get_user_by_req(request, allow_guest=True)
timeout = parse_integer(request, "timeout", 10 * 1000)
body = parse_json_object_from_request(request)
result = yield self.e2e_keys_handler.claim_one_time_keys(
diff --git a/synapse/rest/client/v2_alpha/register.py b/synapse/rest/client/v2_alpha/register.py
index 6cfb20866b..3e7a285e10 100644
--- a/synapse/rest/client/v2_alpha/register.py
+++ b/synapse/rest/client/v2_alpha/register.py
@@ -15,6 +15,7 @@
from twisted.internet import defer
+import synapse
from synapse.api.auth import get_access_token_from_request, has_access_token
from synapse.api.constants import LoginType
from synapse.api.errors import SynapseError, Codes, UnrecognizedRequestError
@@ -100,12 +101,14 @@ class RegisterRestServlet(RestServlet):
def on_POST(self, request):
yield run_on_reactor()
+ body = parse_json_object_from_request(request)
+
kind = "user"
if "kind" in request.args:
kind = request.args["kind"][0]
if kind == "guest":
- ret = yield self._do_guest_registration()
+ ret = yield self._do_guest_registration(body)
defer.returnValue(ret)
return
elif kind != "user":
@@ -113,8 +116,6 @@ class RegisterRestServlet(RestServlet):
"Do not understand membership kind: %s" % (kind,)
)
- body = parse_json_object_from_request(request)
-
# we do basic sanity checks here because the auth layer will store these
# in sessions. Pull out the username/password provided to us.
desired_password = None
@@ -373,8 +374,7 @@ class RegisterRestServlet(RestServlet):
def _create_registration_details(self, user_id, params):
"""Complete registration of newly-registered user
- Allocates device_id if one was not given; also creates access_token
- and refresh_token.
+ Allocates device_id if one was not given; also creates access_token.
Args:
(str) user_id: full canonical @user:id
@@ -385,8 +385,8 @@ class RegisterRestServlet(RestServlet):
"""
device_id = yield self._register_device(user_id, params)
- access_token, refresh_token = (
- yield self.auth_handler.get_login_tuple_for_user_id(
+ access_token = (
+ yield self.auth_handler.get_access_token_for_user_id(
user_id, device_id=device_id,
initial_display_name=params.get("initial_device_display_name")
)
@@ -396,7 +396,6 @@ class RegisterRestServlet(RestServlet):
"user_id": user_id,
"access_token": access_token,
"home_server": self.hs.hostname,
- "refresh_token": refresh_token,
"device_id": device_id,
})
@@ -421,20 +420,28 @@ class RegisterRestServlet(RestServlet):
)
@defer.inlineCallbacks
- def _do_guest_registration(self):
+ def _do_guest_registration(self, params):
if not self.hs.config.allow_guest_access:
defer.returnValue((403, "Guest access is disabled"))
user_id, _ = yield self.registration_handler.register(
generate_token=False,
make_guest=True
)
+
+ # we don't allow guests to specify their own device_id, because
+ # we have nowhere to store it.
+ device_id = synapse.api.auth.GUEST_DEVICE_ID
+ initial_display_name = params.get("initial_device_display_name")
+ self.device_handler.check_device_registered(
+ user_id, device_id, initial_display_name
+ )
+
access_token = self.auth_handler.generate_access_token(
user_id, ["guest = true"]
)
- # XXX the "guest" caveat is not copied by /tokenrefresh. That's ok
- # so long as we don't return a refresh_token here.
defer.returnValue((200, {
"user_id": user_id,
+ "device_id": device_id,
"access_token": access_token,
"home_server": self.hs.hostname,
}))
diff --git a/synapse/rest/client/v2_alpha/sendtodevice.py b/synapse/rest/client/v2_alpha/sendtodevice.py
index ac660669f3..d607bd2970 100644
--- a/synapse/rest/client/v2_alpha/sendtodevice.py
+++ b/synapse/rest/client/v2_alpha/sendtodevice.py
@@ -50,7 +50,7 @@ class SendToDeviceRestServlet(servlet.RestServlet):
@defer.inlineCallbacks
def _put(self, request, message_type, txn_id):
- requester = yield self.auth.get_user_by_req(request)
+ requester = yield self.auth.get_user_by_req(request, allow_guest=True)
content = parse_json_object_from_request(request)
diff --git a/synapse/rest/client/v2_alpha/tokenrefresh.py b/synapse/rest/client/v2_alpha/tokenrefresh.py
index 0d312c91d4..6e76b9e9c2 100644
--- a/synapse/rest/client/v2_alpha/tokenrefresh.py
+++ b/synapse/rest/client/v2_alpha/tokenrefresh.py
@@ -15,8 +15,8 @@
from twisted.internet import defer
-from synapse.api.errors import AuthError, StoreError, SynapseError
-from synapse.http.servlet import RestServlet, parse_json_object_from_request
+from synapse.api.errors import AuthError
+from synapse.http.servlet import RestServlet
from ._base import client_v2_patterns
@@ -30,30 +30,10 @@ class TokenRefreshRestServlet(RestServlet):
def __init__(self, hs):
super(TokenRefreshRestServlet, self).__init__()
- self.hs = hs
- self.store = hs.get_datastore()
@defer.inlineCallbacks
def on_POST(self, request):
- body = parse_json_object_from_request(request)
- try:
- old_refresh_token = body["refresh_token"]
- auth_handler = self.hs.get_auth_handler()
- refresh_result = yield self.store.exchange_refresh_token(
- old_refresh_token, auth_handler.generate_refresh_token
- )
- (user_id, new_refresh_token, device_id) = refresh_result
- new_access_token = yield auth_handler.issue_access_token(
- user_id, device_id
- )
- defer.returnValue((200, {
- "access_token": new_access_token,
- "refresh_token": new_refresh_token,
- }))
- except KeyError:
- raise SynapseError(400, "Missing required key 'refresh_token'.")
- except StoreError:
- raise AuthError(403, "Did not recognize refresh token")
+ raise AuthError(403, "tokenrefresh is no longer supported.")
def register_servlets(hs, http_server):
diff --git a/synapse/rest/media/v1/preview_url_resource.py b/synapse/rest/media/v1/preview_url_resource.py
index 33f35fb44e..6a5a57102f 100644
--- a/synapse/rest/media/v1/preview_url_resource.py
+++ b/synapse/rest/media/v1/preview_url_resource.py
@@ -543,5 +543,5 @@ def summarize_paragraphs(text_nodes, min_size=200, max_size=500):
# We always add an ellipsis because at the very least
# we chopped mid paragraph.
- description = new_desc.strip() + "…"
+ description = new_desc.strip() + u"…"
return description if description else None
diff --git a/synapse/storage/__init__.py b/synapse/storage/__init__.py
index 9996f195a0..db146ed348 100644
--- a/synapse/storage/__init__.py
+++ b/synapse/storage/__init__.py
@@ -120,7 +120,6 @@ class DataStore(RoomMemberStore, RoomStore,
self._transaction_id_gen = IdGenerator(db_conn, "sent_transactions", "id")
self._state_groups_id_gen = IdGenerator(db_conn, "state_groups", "id")
self._access_tokens_id_gen = IdGenerator(db_conn, "access_tokens", "id")
- self._refresh_tokens_id_gen = IdGenerator(db_conn, "refresh_tokens", "id")
self._event_reports_id_gen = IdGenerator(db_conn, "event_reports", "id")
self._push_rule_id_gen = IdGenerator(db_conn, "push_rules", "id")
self._push_rules_enable_id_gen = IdGenerator(db_conn, "push_rules_enable", "id")
diff --git a/synapse/storage/registration.py b/synapse/storage/registration.py
index e404fa72de..983a8ec52b 100644
--- a/synapse/storage/registration.py
+++ b/synapse/storage/registration.py
@@ -68,31 +68,6 @@ class RegistrationStore(background_updates.BackgroundUpdateStore):
desc="add_access_token_to_user",
)
- @defer.inlineCallbacks
- def add_refresh_token_to_user(self, user_id, token, device_id=None):
- """Adds a refresh token for the given user.
-
- Args:
- user_id (str): The user ID.
- token (str): The new refresh token to add.
- device_id (str): ID of the device to associate with the access
- token
- Raises:
- StoreError if there was a problem adding this.
- """
- next_id = self._refresh_tokens_id_gen.get_next()
-
- yield self._simple_insert(
- "refresh_tokens",
- {
- "id": next_id,
- "user_id": user_id,
- "token": token,
- "device_id": device_id,
- },
- desc="add_refresh_token_to_user",
- )
-
def register(self, user_id, token=None, password_hash=None,
was_guest=False, make_guest=False, appservice_id=None,
create_profile_with_localpart=None, admin=False):
@@ -353,47 +328,6 @@ class RegistrationStore(background_updates.BackgroundUpdateStore):
token
)
- def exchange_refresh_token(self, refresh_token, token_generator):
- """Exchange a refresh token for a new one.
-
- Doing so invalidates the old refresh token - refresh tokens are single
- use.
-
- Args:
- refresh_token (str): The refresh token of a user.
- token_generator (fn: str -> str): Function which, when given a
- user ID, returns a unique refresh token for that user. This
- function must never return the same value twice.
- Returns:
- tuple of (user_id, new_refresh_token, device_id)
- Raises:
- StoreError if no user was found with that refresh token.
- """
- return self.runInteraction(
- "exchange_refresh_token",
- self._exchange_refresh_token,
- refresh_token,
- token_generator
- )
-
- def _exchange_refresh_token(self, txn, old_token, token_generator):
- sql = "SELECT user_id, device_id FROM refresh_tokens WHERE token = ?"
- txn.execute(sql, (old_token,))
- rows = self.cursor_to_dict(txn)
- if not rows:
- raise StoreError(403, "Did not recognize refresh token")
- user_id = rows[0]["user_id"]
- device_id = rows[0]["device_id"]
-
- # TODO(danielwh): Maybe perform a validation on the macaroon that
- # macaroon.user_id == user_id.
-
- new_token = token_generator(user_id)
- sql = "UPDATE refresh_tokens SET token = ? WHERE token = ?"
- txn.execute(sql, (new_token, old_token,))
-
- return user_id, new_token, device_id
-
@defer.inlineCallbacks
def is_server_admin(self, user):
res = yield self._simple_select_one_onecol(
diff --git a/synapse/storage/schema/delta/39/federation_out_position.sql b/synapse/storage/schema/delta/39/federation_out_position.sql
index edbd8e132f..5af814290b 100644
--- a/synapse/storage/schema/delta/39/federation_out_position.sql
+++ b/synapse/storage/schema/delta/39/federation_out_position.sql
@@ -19,4 +19,4 @@
);
INSERT INTO federation_stream_position (type, stream_id) VALUES ('federation', -1);
- INSERT INTO federation_stream_position (type, stream_id) VALUES ('events', -1);
+ INSERT INTO federation_stream_position (type, stream_id) SELECT 'events', coalesce(max(stream_ordering), -1) FROM events;
diff --git a/synapse/util/retryutils.py b/synapse/util/retryutils.py
index 46ef5a8ec7..e2de7fce91 100644
--- a/synapse/util/retryutils.py
+++ b/synapse/util/retryutils.py
@@ -123,7 +123,7 @@ class RetryDestinationLimiter(object):
def __exit__(self, exc_type, exc_val, exc_tb):
valid_err_code = False
if exc_type is not None and issubclass(exc_type, CodeMessageException):
- valid_err_code = 0 <= exc_val.code < 500
+ valid_err_code = exc_val.code != 429 and 0 <= exc_val.code < 500
if exc_type is None or valid_err_code:
# We connected successfully.
|