diff --git a/synapse/api/auth.py b/synapse/api/auth.py
index d8190f92ab..75388643ee 100644
--- a/synapse/api/auth.py
+++ b/synapse/api/auth.py
@@ -58,7 +58,7 @@ class _InvalidMacaroonException(Exception):
pass
-class Auth(object):
+class Auth:
"""
FIXME: This class contains a mix of functions for authenticating users
of our client-server API and authenticating events added to room graphs.
@@ -213,6 +213,7 @@ class Auth(object):
user = user_info["user"]
token_id = user_info["token_id"]
is_guest = user_info["is_guest"]
+ shadow_banned = user_info["shadow_banned"]
# Deny the request if the user account has expired.
if self._account_validity.enabled and not allow_expired:
@@ -252,7 +253,12 @@ class Auth(object):
opentracing.set_tag("device_id", device_id)
return synapse.types.create_requester(
- user, token_id, is_guest, device_id, app_service=app_service
+ user,
+ token_id,
+ is_guest,
+ shadow_banned,
+ device_id,
+ app_service=app_service,
)
except KeyError:
raise MissingClientTokenError()
@@ -297,6 +303,7 @@ class Auth(object):
dict that includes:
`user` (UserID)
`is_guest` (bool)
+ `shadow_banned` (bool)
`token_id` (int|None): access token id. May be None if guest
`device_id` (str|None): device corresponding to access token
Raises:
@@ -356,6 +363,7 @@ class Auth(object):
ret = {
"user": user,
"is_guest": True,
+ "shadow_banned": False,
"token_id": None,
# all guests get the same device id
"device_id": GUEST_DEVICE_ID,
@@ -365,6 +373,7 @@ class Auth(object):
ret = {
"user": user,
"is_guest": False,
+ "shadow_banned": False,
"token_id": None,
"device_id": None,
}
@@ -488,6 +497,7 @@ class Auth(object):
"user": UserID.from_string(ret.get("name")),
"token_id": ret.get("token_id", None),
"is_guest": False,
+ "shadow_banned": ret.get("shadow_banned"),
"device_id": ret.get("device_id"),
"valid_until_ms": ret.get("valid_until_ms"),
}
diff --git a/synapse/api/auth_blocking.py b/synapse/api/auth_blocking.py
index 49093bf181..d8fafd7cb8 100644
--- a/synapse/api/auth_blocking.py
+++ b/synapse/api/auth_blocking.py
@@ -22,7 +22,7 @@ from synapse.config.server import is_threepid_reserved
logger = logging.getLogger(__name__)
-class AuthBlocking(object):
+class AuthBlocking:
def __init__(self, hs):
self.store = hs.get_datastore()
diff --git a/synapse/api/constants.py b/synapse/api/constants.py
index 6a6d32c302..46013cde15 100644
--- a/synapse/api/constants.py
+++ b/synapse/api/constants.py
@@ -28,7 +28,7 @@ MAX_ALIAS_LENGTH = 255
MAX_USERID_LENGTH = 255
-class Membership(object):
+class Membership:
"""Represents the membership states of a user in a room."""
@@ -40,7 +40,7 @@ class Membership(object):
LIST = (INVITE, JOIN, KNOCK, LEAVE, BAN)
-class PresenceState(object):
+class PresenceState:
"""Represents the presence state of a user."""
OFFLINE = "offline"
@@ -48,14 +48,14 @@ class PresenceState(object):
ONLINE = "online"
-class JoinRules(object):
+class JoinRules:
PUBLIC = "public"
KNOCK = "knock"
INVITE = "invite"
PRIVATE = "private"
-class LoginType(object):
+class LoginType:
PASSWORD = "m.login.password"
EMAIL_IDENTITY = "m.login.email.identity"
MSISDN = "m.login.msisdn"
@@ -65,7 +65,7 @@ class LoginType(object):
DUMMY = "m.login.dummy"
-class EventTypes(object):
+class EventTypes:
Member = "m.room.member"
Create = "m.room.create"
Tombstone = "m.room.tombstone"
@@ -96,17 +96,17 @@ class EventTypes(object):
Presence = "m.presence"
-class RejectedReason(object):
+class RejectedReason:
AUTH_ERROR = "auth_error"
-class RoomCreationPreset(object):
+class RoomCreationPreset:
PRIVATE_CHAT = "private_chat"
PUBLIC_CHAT = "public_chat"
TRUSTED_PRIVATE_CHAT = "trusted_private_chat"
-class ThirdPartyEntityKind(object):
+class ThirdPartyEntityKind:
USER = "user"
LOCATION = "location"
@@ -115,7 +115,7 @@ ServerNoticeMsgType = "m.server_notice"
ServerNoticeLimitReached = "m.server_notice.usage_limit_reached"
-class UserTypes(object):
+class UserTypes:
"""Allows for user type specific behaviour. With the benefit of hindsight
'admin' and 'guest' users should also be UserTypes. Normal users are type None
"""
@@ -125,7 +125,7 @@ class UserTypes(object):
ALL_USER_TYPES = (SUPPORT, BOT)
-class RelationTypes(object):
+class RelationTypes:
"""The types of relations known to this server.
"""
@@ -134,14 +134,14 @@ class RelationTypes(object):
REFERENCE = "m.reference"
-class LimitBlockingTypes(object):
+class LimitBlockingTypes:
"""Reasons that a server may be blocked"""
MONTHLY_ACTIVE_USER = "monthly_active_user"
HS_DISABLED = "hs_disabled"
-class EventContentFields(object):
+class EventContentFields:
"""Fields found in events' content, regardless of type."""
# Labels for the event, cf https://github.com/matrix-org/matrix-doc/pull/2326
@@ -152,6 +152,6 @@ class EventContentFields(object):
SELF_DESTRUCT_AFTER = "org.matrix.self_destruct_after"
-class RoomEncryptionAlgorithms(object):
+class RoomEncryptionAlgorithms:
MEGOLM_V1_AES_SHA2 = "m.megolm.v1.aes-sha2"
DEFAULT = MEGOLM_V1_AES_SHA2
diff --git a/synapse/api/errors.py b/synapse/api/errors.py
index 6e40630ab6..94a9e58eae 100644
--- a/synapse/api/errors.py
+++ b/synapse/api/errors.py
@@ -21,17 +21,17 @@ import typing
from http import HTTPStatus
from typing import Dict, List, Optional, Union
-from canonicaljson import json
-
from twisted.web import http
+from synapse.util import json_decoder
+
if typing.TYPE_CHECKING:
from synapse.types import JsonDict
logger = logging.getLogger(__name__)
-class Codes(object):
+class Codes:
UNRECOGNIZED = "M_UNRECOGNIZED"
UNAUTHORIZED = "M_UNAUTHORIZED"
FORBIDDEN = "M_FORBIDDEN"
@@ -593,7 +593,7 @@ class HttpResponseException(CodeMessageException):
# try to parse the body as json, to get better errcode/msg, but
# default to M_UNKNOWN with the HTTP status as the error text
try:
- j = json.loads(self.response.decode("utf-8"))
+ j = json_decoder.decode(self.response.decode("utf-8"))
except ValueError:
j = {}
@@ -604,3 +604,11 @@ class HttpResponseException(CodeMessageException):
errmsg = j.pop("error", self.msg)
return ProxiedRequestError(self.code, errmsg, errcode, j)
+
+
+class ShadowBanError(Exception):
+ """
+ Raised when a shadow-banned user attempts to perform an action.
+
+ This should be caught and a proper "fake" success response sent to the user.
+ """
diff --git a/synapse/api/filtering.py b/synapse/api/filtering.py
index 7393d6cb74..2a2c9e6f13 100644
--- a/synapse/api/filtering.py
+++ b/synapse/api/filtering.py
@@ -23,7 +23,7 @@ from jsonschema import FormatChecker
from synapse.api.constants import EventContentFields
from synapse.api.errors import SynapseError
-from synapse.storage.presence import UserPresenceState
+from synapse.api.presence import UserPresenceState
from synapse.types import RoomID, UserID
FILTER_SCHEMA = {
@@ -130,7 +130,7 @@ def matrix_user_id_validator(user_id_str):
return UserID.from_string(user_id_str)
-class Filtering(object):
+class Filtering:
def __init__(self, hs):
super(Filtering, self).__init__()
self.store = hs.get_datastore()
@@ -168,7 +168,7 @@ class Filtering(object):
raise SynapseError(400, str(e))
-class FilterCollection(object):
+class FilterCollection:
def __init__(self, filter_json):
self._filter_json = filter_json
@@ -249,7 +249,7 @@ class FilterCollection(object):
)
-class Filter(object):
+class Filter:
def __init__(self, filter_json):
self.filter_json = filter_json
diff --git a/synapse/api/presence.py b/synapse/api/presence.py
new file mode 100644
index 0000000000..18a462f0ee
--- /dev/null
+++ b/synapse/api/presence.py
@@ -0,0 +1,69 @@
+# -*- coding: utf-8 -*-
+# Copyright 2014-2016 OpenMarket Ltd
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+from collections import namedtuple
+
+from synapse.api.constants import PresenceState
+
+
+class UserPresenceState(
+ namedtuple(
+ "UserPresenceState",
+ (
+ "user_id",
+ "state",
+ "last_active_ts",
+ "last_federation_update_ts",
+ "last_user_sync_ts",
+ "status_msg",
+ "currently_active",
+ ),
+ )
+):
+ """Represents the current presence state of the user.
+
+ user_id (str)
+ last_active (int): Time in msec that the user last interacted with server.
+ last_federation_update (int): Time in msec since either a) we sent a presence
+ update to other servers or b) we received a presence update, depending
+ on if is a local user or not.
+ last_user_sync (int): Time in msec that the user last *completed* a sync
+ (or event stream).
+ status_msg (str): User set status message.
+ """
+
+ def as_dict(self):
+ return dict(self._asdict())
+
+ @staticmethod
+ def from_dict(d):
+ return UserPresenceState(**d)
+
+ def copy_and_replace(self, **kwargs):
+ return self._replace(**kwargs)
+
+ @classmethod
+ def default(cls, user_id):
+ """Returns a default presence state.
+ """
+ return cls(
+ user_id=user_id,
+ state=PresenceState.OFFLINE,
+ last_active_ts=0,
+ last_federation_update_ts=0,
+ last_user_sync_ts=0,
+ status_msg=None,
+ currently_active=False,
+ )
diff --git a/synapse/api/ratelimiting.py b/synapse/api/ratelimiting.py
index e62ae50ac2..5d9d5a228f 100644
--- a/synapse/api/ratelimiting.py
+++ b/synapse/api/ratelimiting.py
@@ -21,7 +21,7 @@ from synapse.types import Requester
from synapse.util import Clock
-class Ratelimiter(object):
+class Ratelimiter:
"""
Ratelimit actions marked by arbitrary keys.
diff --git a/synapse/api/room_versions.py b/synapse/api/room_versions.py
index d7baf2bc39..f3ecbf36b6 100644
--- a/synapse/api/room_versions.py
+++ b/synapse/api/room_versions.py
@@ -18,7 +18,7 @@ from typing import Dict
import attr
-class EventFormatVersions(object):
+class EventFormatVersions:
"""This is an internal enum for tracking the version of the event format,
independently from the room version.
"""
@@ -35,20 +35,20 @@ KNOWN_EVENT_FORMAT_VERSIONS = {
}
-class StateResolutionVersions(object):
+class StateResolutionVersions:
"""Enum to identify the state resolution algorithms"""
V1 = 1 # room v1 state res
V2 = 2 # MSC1442 state res: room v2 and later
-class RoomDisposition(object):
+class RoomDisposition:
STABLE = "stable"
UNSTABLE = "unstable"
@attr.s(slots=True, frozen=True)
-class RoomVersion(object):
+class RoomVersion:
"""An object which describes the unique attributes of a room version."""
identifier = attr.ib() # str; the identifier for this version
@@ -69,7 +69,7 @@ class RoomVersion(object):
limit_notifications_power_levels = attr.ib(type=bool)
-class RoomVersions(object):
+class RoomVersions:
V1 = RoomVersion(
"1",
RoomDisposition.STABLE,
diff --git a/synapse/api/urls.py b/synapse/api/urls.py
index bd03ebca5a..bbfccf955e 100644
--- a/synapse/api/urls.py
+++ b/synapse/api/urls.py
@@ -33,7 +33,7 @@ MEDIA_PREFIX = "/_matrix/media/r0"
LEGACY_MEDIA_PREFIX = "/_matrix/media/v1"
-class ConsentURIBuilder(object):
+class ConsentURIBuilder:
def __init__(self, hs_config):
"""
Args:
|