diff --git a/synapse/api/errors.py b/synapse/api/errors.py
index e46bfdfcb9..9dd8d48386 100644
--- a/synapse/api/errors.py
+++ b/synapse/api/errors.py
@@ -18,12 +18,15 @@
"""Contains exceptions and error codes."""
import logging
+from typing import Dict, List
from six import iteritems
from six.moves import http_client
from canonicaljson import json
+from twisted.web import http
+
logger = logging.getLogger(__name__)
@@ -62,6 +65,9 @@ class Codes(object):
INCOMPATIBLE_ROOM_VERSION = "M_INCOMPATIBLE_ROOM_VERSION"
WRONG_ROOM_KEYS_VERSION = "M_WRONG_ROOM_KEYS_VERSION"
EXPIRED_ACCOUNT = "ORG_MATRIX_EXPIRED_ACCOUNT"
+ INVALID_SIGNATURE = "M_INVALID_SIGNATURE"
+ USER_DEACTIVATED = "M_USER_DEACTIVATED"
+ BAD_ALIAS = "M_BAD_ALIAS"
PASSWORD_TOO_SHORT = "M_PASSWORD_TOO_SHORT"
PASSWORD_NO_DIGIT = "M_PASSWORD_NO_DIGIT"
PASSWORD_NO_UPPERCASE = "M_PASSWORD_NO_UPPERCASE"
@@ -78,12 +84,36 @@ class CodeMessageException(RuntimeError):
code (int): HTTP error code
msg (str): string describing the error
"""
+
def __init__(self, code, msg):
super(CodeMessageException, self).__init__("%d: %s" % (code, msg))
self.code = code
self.msg = msg
+class RedirectException(CodeMessageException):
+ """A pseudo-error indicating that we want to redirect the client to a different
+ location
+
+ Attributes:
+ cookies: a list of set-cookies values to add to the response. For example:
+ b"sessionId=a3fWa; Expires=Wed, 21 Oct 2015 07:28:00 GMT"
+ """
+
+ def __init__(self, location: bytes, http_code: int = http.FOUND):
+ """
+
+ Args:
+ location: the URI to redirect to
+ http_code: the HTTP response code
+ """
+ msg = "Redirect to %s" % (location.decode("utf-8"),)
+ super().__init__(code=http_code, msg=msg)
+ self.location = location
+
+ self.cookies = [] # type: List[bytes]
+
+
class SynapseError(CodeMessageException):
"""A base exception type for matrix errors which have an errcode and error
message (as well as an HTTP status code).
@@ -91,6 +121,7 @@ class SynapseError(CodeMessageException):
Attributes:
errcode (str): Matrix error code e.g 'M_FORBIDDEN'
"""
+
def __init__(self, code, msg, errcode=Codes.UNKNOWN):
"""Constructs a synapse error.
@@ -103,10 +134,7 @@ class SynapseError(CodeMessageException):
self.errcode = errcode
def error_dict(self):
- return cs_error(
- self.msg,
- self.errcode,
- )
+ return cs_error(self.msg, self.errcode)
class ProxiedRequestError(SynapseError):
@@ -115,27 +143,23 @@ class ProxiedRequestError(SynapseError):
Attributes:
errcode (str): Matrix error code e.g 'M_FORBIDDEN'
"""
+
def __init__(self, code, msg, errcode=Codes.UNKNOWN, additional_fields=None):
- super(ProxiedRequestError, self).__init__(
- code, msg, errcode
- )
+ super(ProxiedRequestError, self).__init__(code, msg, errcode)
if additional_fields is None:
- self._additional_fields = {}
+ self._additional_fields = {} # type: Dict
else:
self._additional_fields = dict(additional_fields)
def error_dict(self):
- return cs_error(
- self.msg,
- self.errcode,
- **self._additional_fields
- )
+ return cs_error(self.msg, self.errcode, **self._additional_fields)
class ConsentNotGivenError(SynapseError):
"""The error returned to the client when the user has not consented to the
privacy policy.
"""
+
def __init__(self, msg, consent_uri):
"""Constructs a ConsentNotGivenError
@@ -144,23 +168,28 @@ class ConsentNotGivenError(SynapseError):
consent_url (str): The URL where the user can give their consent
"""
super(ConsentNotGivenError, self).__init__(
- code=http_client.FORBIDDEN,
- msg=msg,
- errcode=Codes.CONSENT_NOT_GIVEN
+ code=http_client.FORBIDDEN, msg=msg, errcode=Codes.CONSENT_NOT_GIVEN
)
self._consent_uri = consent_uri
def error_dict(self):
- return cs_error(
- self.msg,
- self.errcode,
- consent_uri=self._consent_uri
- )
+ return cs_error(self.msg, self.errcode, consent_uri=self._consent_uri)
-class RegistrationError(SynapseError):
- """An error raised when a registration event fails."""
- pass
+class UserDeactivatedError(SynapseError):
+ """The error returned to the client when the user attempted to access an
+ authenticated endpoint, but the account has been deactivated.
+ """
+
+ def __init__(self, msg):
+ """Constructs a UserDeactivatedError
+
+ Args:
+ msg (str): The human-readable error message
+ """
+ super(UserDeactivatedError, self).__init__(
+ code=http_client.FORBIDDEN, msg=msg, errcode=Codes.USER_DEACTIVATED
+ )
class FederationDeniedError(SynapseError):
@@ -198,15 +227,17 @@ class InteractiveAuthIncompleteError(Exception):
result (dict): the server response to the request, which should be
passed back to the client
"""
+
def __init__(self, result):
super(InteractiveAuthIncompleteError, self).__init__(
- "Interactive auth not yet complete",
+ "Interactive auth not yet complete"
)
self.result = result
class UnrecognizedRequestError(SynapseError):
"""An error indicating we don't understand the request you're trying to make"""
+
def __init__(self, *args, **kwargs):
if "errcode" not in kwargs:
kwargs["errcode"] = Codes.UNRECOGNIZED
@@ -215,25 +246,20 @@ class UnrecognizedRequestError(SynapseError):
message = "Unrecognized request"
else:
message = args[0]
- super(UnrecognizedRequestError, self).__init__(
- 400,
- message,
- **kwargs
- )
+ super(UnrecognizedRequestError, self).__init__(400, message, **kwargs)
class NotFoundError(SynapseError):
"""An error indicating we can't find the thing you asked for"""
+
def __init__(self, msg="Not found", errcode=Codes.NOT_FOUND):
- super(NotFoundError, self).__init__(
- 404,
- msg,
- errcode=errcode
- )
+ super(NotFoundError, self).__init__(404, msg, errcode=errcode)
class AuthError(SynapseError):
- """An error raised when there was a problem authorising an event."""
+ """An error raised when there was a problem authorising an event, and at various
+ other poorly-defined times.
+ """
def __init__(self, *args, **kwargs):
if "errcode" not in kwargs:
@@ -241,13 +267,51 @@ class AuthError(SynapseError):
super(AuthError, self).__init__(*args, **kwargs)
+class InvalidClientCredentialsError(SynapseError):
+ """An error raised when there was a problem with the authorisation credentials
+ in a client request.
+
+ https://matrix.org/docs/spec/client_server/r0.5.0#using-access-tokens:
+
+ When credentials are required but missing or invalid, the HTTP call will
+ return with a status of 401 and the error code, M_MISSING_TOKEN or
+ M_UNKNOWN_TOKEN respectively.
+ """
+
+ def __init__(self, msg, errcode):
+ super().__init__(code=401, msg=msg, errcode=errcode)
+
+
+class MissingClientTokenError(InvalidClientCredentialsError):
+ """Raised when we couldn't find the access token in a request"""
+
+ def __init__(self, msg="Missing access token"):
+ super().__init__(msg=msg, errcode="M_MISSING_TOKEN")
+
+
+class InvalidClientTokenError(InvalidClientCredentialsError):
+ """Raised when we didn't understand the access token in a request"""
+
+ def __init__(self, msg="Unrecognised access token", soft_logout=False):
+ super().__init__(msg=msg, errcode="M_UNKNOWN_TOKEN")
+ self._soft_logout = soft_logout
+
+ def error_dict(self):
+ d = super().error_dict()
+ d["soft_logout"] = self._soft_logout
+ return d
+
+
class ResourceLimitError(SynapseError):
"""
Any error raised when there is a problem with resource usage.
For instance, the monthly active user limit for the server has been exceeded
"""
+
def __init__(
- self, code, msg,
+ self,
+ code,
+ msg,
errcode=Codes.RESOURCE_LIMIT_EXCEEDED,
admin_contact=None,
limit_type=None,
@@ -261,7 +325,7 @@ class ResourceLimitError(SynapseError):
self.msg,
self.errcode,
admin_contact=self.admin_contact,
- limit_type=self.limit_type
+ limit_type=self.limit_type,
)
@@ -276,6 +340,7 @@ class EventSizeError(SynapseError):
class EventStreamError(SynapseError):
"""An error raised when there a problem with the event stream."""
+
def __init__(self, *args, **kwargs):
if "errcode" not in kwargs:
kwargs["errcode"] = Codes.BAD_PAGINATION
@@ -284,47 +349,53 @@ class EventStreamError(SynapseError):
class LoginError(SynapseError):
"""An error raised when there was a problem logging in."""
+
pass
class StoreError(SynapseError):
"""An error raised when there was a problem storing some data."""
+
pass
class InvalidCaptchaError(SynapseError):
- def __init__(self, code=400, msg="Invalid captcha.", error_url=None,
- errcode=Codes.CAPTCHA_INVALID):
+ def __init__(
+ self,
+ code=400,
+ msg="Invalid captcha.",
+ error_url=None,
+ errcode=Codes.CAPTCHA_INVALID,
+ ):
super(InvalidCaptchaError, self).__init__(code, msg, errcode)
self.error_url = error_url
def error_dict(self):
- return cs_error(
- self.msg,
- self.errcode,
- error_url=self.error_url,
- )
+ return cs_error(self.msg, self.errcode, error_url=self.error_url)
class LimitExceededError(SynapseError):
"""A client has sent too many requests and is being throttled.
"""
- def __init__(self, code=429, msg="Too Many Requests", retry_after_ms=None,
- errcode=Codes.LIMIT_EXCEEDED):
+
+ def __init__(
+ self,
+ code=429,
+ msg="Too Many Requests",
+ retry_after_ms=None,
+ errcode=Codes.LIMIT_EXCEEDED,
+ ):
super(LimitExceededError, self).__init__(code, msg, errcode)
self.retry_after_ms = retry_after_ms
def error_dict(self):
- return cs_error(
- self.msg,
- self.errcode,
- retry_after_ms=self.retry_after_ms,
- )
+ return cs_error(self.msg, self.errcode, retry_after_ms=self.retry_after_ms)
class RoomKeysVersionError(SynapseError):
"""A client has tried to upload to a non-current version of the room_keys store
"""
+
def __init__(self, current_version):
"""
Args:
@@ -339,11 +410,10 @@ class RoomKeysVersionError(SynapseError):
class UnsupportedRoomVersionError(SynapseError):
"""The client's request to create a room used a room version that the server does
not support."""
- def __init__(self):
+
+ def __init__(self, msg="Homeserver does not support this room version"):
super(UnsupportedRoomVersionError, self).__init__(
- code=400,
- msg="Homeserver does not support this room version",
- errcode=Codes.UNSUPPORTED_ROOM_VERSION,
+ code=400, msg=msg, errcode=Codes.UNSUPPORTED_ROOM_VERSION,
)
@@ -362,22 +432,19 @@ class IncompatibleRoomVersionError(SynapseError):
Unlike UnsupportedRoomVersionError, it is specific to the case of the make_join
failing.
"""
+
def __init__(self, room_version):
super(IncompatibleRoomVersionError, self).__init__(
code=400,
msg="Your homeserver does not support the features required to "
- "join this room",
+ "join this room",
errcode=Codes.INCOMPATIBLE_ROOM_VERSION,
)
self._room_version = room_version
def error_dict(self):
- return cs_error(
- self.msg,
- self.errcode,
- room_version=self._room_version,
- )
+ return cs_error(self.msg, self.errcode, room_version=self._room_version)
class PasswordRefusedError(SynapseError):
@@ -389,11 +456,7 @@ class PasswordRefusedError(SynapseError):
msg="This password doesn't comply with the server's policy",
errcode=Codes.WEAK_PASSWORD,
):
- super(PasswordRefusedError, self).__init__(
- code=400,
- msg=msg,
- errcode=errcode,
- )
+ super(PasswordRefusedError, self).__init__(code=400, msg=msg, errcode=errcode)
class RequestSendFailed(RuntimeError):
@@ -404,11 +467,11 @@ class RequestSendFailed(RuntimeError):
networking (e.g. DNS failures, connection timeouts etc), versus unexpected
errors (like programming errors).
"""
+
def __init__(self, inner_exception, can_retry):
super(RequestSendFailed, self).__init__(
- "Failed to send request: %s: %s" % (
- type(inner_exception).__name__, inner_exception,
- )
+ "Failed to send request: %s: %s"
+ % (type(inner_exception).__name__, inner_exception)
)
self.inner_exception = inner_exception
self.can_retry = can_retry
@@ -432,7 +495,7 @@ def cs_error(msg, code=Codes.UNKNOWN, **kwargs):
class FederationError(RuntimeError):
- """ This class is used to inform remote home servers about erroneous
+ """ This class is used to inform remote homeservers about erroneous
PDUs they sent us.
FATAL: The remote server could not interpret the source event.
@@ -452,7 +515,7 @@ class FederationError(RuntimeError):
self.affected = affected
self.source = source
- msg = "%s %s: %s" % (level, code, reason,)
+ msg = "%s %s: %s" % (level, code, reason)
super(FederationError, self).__init__(msg)
def get_dict(self):
@@ -472,6 +535,7 @@ class HttpResponseException(CodeMessageException):
Attributes:
response (bytes): body of response
"""
+
def __init__(self, code, msg, response):
"""
@@ -510,7 +574,7 @@ class HttpResponseException(CodeMessageException):
if not isinstance(j, dict):
j = {}
- errcode = j.pop('errcode', Codes.UNKNOWN)
- errmsg = j.pop('error', self.msg)
+ errcode = j.pop("errcode", Codes.UNKNOWN)
+ errmsg = j.pop("error", self.msg)
return ProxiedRequestError(self.code, errmsg, errcode, j)
|