mirror of
https://github.com/element-hq/synapse.git
synced 2025-12-15 02:00:21 +00:00
Compare commits
18 Commits
copilot/up
...
modular-de
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
23bc5ee14e | ||
|
|
76b25075b0 | ||
|
|
f69f4e7a97 | ||
|
|
8a2e8eaaec | ||
|
|
b18f54c845 | ||
|
|
cbb926f237 | ||
|
|
f7cb88c3bd | ||
|
|
a6fb79cf36 | ||
|
|
6d2557f1e8 | ||
|
|
cec502a595 | ||
|
|
fe8636b79e | ||
|
|
059369dd04 | ||
|
|
de7ba972be | ||
|
|
35e6e69ea9 | ||
|
|
34b826bef8 | ||
|
|
f014ea9b5c | ||
|
|
b0cf4228d2 | ||
|
|
21c037ac46 |
1
changelog.d/5878.feature
Normal file
1
changelog.d/5878.feature
Normal file
@@ -0,0 +1 @@
|
|||||||
|
Add admin API endpoint for setting whether or not a user is a server administrator.
|
||||||
1
changelog.d/5914.feature
Normal file
1
changelog.d/5914.feature
Normal file
@@ -0,0 +1 @@
|
|||||||
|
Add admin API endpoint for getting whether or not a user is a server administrator.
|
||||||
1
changelog.d/6015.feature
Normal file
1
changelog.d/6015.feature
Normal file
@@ -0,0 +1 @@
|
|||||||
|
Add config option to increase ratelimits for room admins redacting messages.
|
||||||
@@ -84,3 +84,42 @@ with a body of:
|
|||||||
}
|
}
|
||||||
|
|
||||||
including an ``access_token`` of a server admin.
|
including an ``access_token`` of a server admin.
|
||||||
|
|
||||||
|
|
||||||
|
Get whether a user is a server administrator or not
|
||||||
|
===================================================
|
||||||
|
|
||||||
|
|
||||||
|
The api is::
|
||||||
|
|
||||||
|
GET /_synapse/admin/v1/users/<user_id>/admin
|
||||||
|
|
||||||
|
including an ``access_token`` of a server admin.
|
||||||
|
|
||||||
|
A response body like the following is returned:
|
||||||
|
|
||||||
|
.. code:: json
|
||||||
|
|
||||||
|
{
|
||||||
|
"admin": true
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Change whether a user is a server administrator or not
|
||||||
|
======================================================
|
||||||
|
|
||||||
|
Note that you cannot demote yourself.
|
||||||
|
|
||||||
|
The api is::
|
||||||
|
|
||||||
|
PUT /_synapse/admin/v1/users/<user_id>/admin
|
||||||
|
|
||||||
|
with a body of:
|
||||||
|
|
||||||
|
.. code:: json
|
||||||
|
|
||||||
|
{
|
||||||
|
"admin": true
|
||||||
|
}
|
||||||
|
|
||||||
|
including an ``access_token`` of a server admin.
|
||||||
|
|||||||
@@ -510,6 +510,9 @@ log_config: "CONFDIR/SERVERNAME.log.config"
|
|||||||
# - one for login that ratelimits login requests based on the account the
|
# - one for login that ratelimits login requests based on the account the
|
||||||
# client is attempting to log into, based on the amount of failed login
|
# client is attempting to log into, based on the amount of failed login
|
||||||
# attempts for this account.
|
# attempts for this account.
|
||||||
|
# - one for ratelimiting redactions by room admins. If this is not explicitly
|
||||||
|
# set then it uses the same ratelimiting as per rc_message. This is useful
|
||||||
|
# to allow room admins to deal with abuse quickly.
|
||||||
#
|
#
|
||||||
# The defaults are as shown below.
|
# The defaults are as shown below.
|
||||||
#
|
#
|
||||||
@@ -531,6 +534,10 @@ log_config: "CONFDIR/SERVERNAME.log.config"
|
|||||||
# failed_attempts:
|
# failed_attempts:
|
||||||
# per_second: 0.17
|
# per_second: 0.17
|
||||||
# burst_count: 3
|
# burst_count: 3
|
||||||
|
#
|
||||||
|
#rc_admin_redaction:
|
||||||
|
# per_second: 1
|
||||||
|
# burst_count: 50
|
||||||
|
|
||||||
|
|
||||||
# Ratelimiting settings for incoming federation
|
# Ratelimiting settings for incoming federation
|
||||||
|
|||||||
@@ -35,4 +35,4 @@ try:
|
|||||||
except ImportError:
|
except ImportError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
__version__ = "1.3.1"
|
__version__ = "1.3.2-alpha.2+modular"
|
||||||
|
|||||||
@@ -80,6 +80,12 @@ class RatelimitConfig(Config):
|
|||||||
"federation_rr_transactions_per_room_per_second", 50
|
"federation_rr_transactions_per_room_per_second", 50
|
||||||
)
|
)
|
||||||
|
|
||||||
|
rc_admin_redaction = config.get("rc_admin_redaction")
|
||||||
|
if rc_admin_redaction:
|
||||||
|
self.rc_admin_redaction = RateLimitConfig(rc_admin_redaction)
|
||||||
|
else:
|
||||||
|
self.rc_admin_redaction = None
|
||||||
|
|
||||||
def generate_config_section(self, **kwargs):
|
def generate_config_section(self, **kwargs):
|
||||||
return """\
|
return """\
|
||||||
## Ratelimiting ##
|
## Ratelimiting ##
|
||||||
@@ -102,6 +108,9 @@ class RatelimitConfig(Config):
|
|||||||
# - one for login that ratelimits login requests based on the account the
|
# - one for login that ratelimits login requests based on the account the
|
||||||
# client is attempting to log into, based on the amount of failed login
|
# client is attempting to log into, based on the amount of failed login
|
||||||
# attempts for this account.
|
# attempts for this account.
|
||||||
|
# - one for ratelimiting redactions by room admins. If this is not explicitly
|
||||||
|
# set then it uses the same ratelimiting as per rc_message. This is useful
|
||||||
|
# to allow room admins to deal with abuse quickly.
|
||||||
#
|
#
|
||||||
# The defaults are as shown below.
|
# The defaults are as shown below.
|
||||||
#
|
#
|
||||||
@@ -123,6 +132,10 @@ class RatelimitConfig(Config):
|
|||||||
# failed_attempts:
|
# failed_attempts:
|
||||||
# per_second: 0.17
|
# per_second: 0.17
|
||||||
# burst_count: 3
|
# burst_count: 3
|
||||||
|
#
|
||||||
|
#rc_admin_redaction:
|
||||||
|
# per_second: 1
|
||||||
|
# burst_count: 50
|
||||||
|
|
||||||
|
|
||||||
# Ratelimiting settings for incoming federation
|
# Ratelimiting settings for incoming federation
|
||||||
|
|||||||
@@ -45,6 +45,7 @@ class BaseHandler(object):
|
|||||||
self.state_handler = hs.get_state_handler()
|
self.state_handler = hs.get_state_handler()
|
||||||
self.distributor = hs.get_distributor()
|
self.distributor = hs.get_distributor()
|
||||||
self.ratelimiter = hs.get_ratelimiter()
|
self.ratelimiter = hs.get_ratelimiter()
|
||||||
|
self.admin_redaction_ratelimiter = hs.get_admin_redaction_ratelimiter()
|
||||||
self.clock = hs.get_clock()
|
self.clock = hs.get_clock()
|
||||||
self.hs = hs
|
self.hs = hs
|
||||||
|
|
||||||
@@ -53,7 +54,7 @@ class BaseHandler(object):
|
|||||||
self.event_builder_factory = hs.get_event_builder_factory()
|
self.event_builder_factory = hs.get_event_builder_factory()
|
||||||
|
|
||||||
@defer.inlineCallbacks
|
@defer.inlineCallbacks
|
||||||
def ratelimit(self, requester, update=True):
|
def ratelimit(self, requester, update=True, is_admin_redaction=False):
|
||||||
"""Ratelimits requests.
|
"""Ratelimits requests.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
@@ -62,6 +63,9 @@ class BaseHandler(object):
|
|||||||
Set to False when doing multiple checks for one request (e.g.
|
Set to False when doing multiple checks for one request (e.g.
|
||||||
to check up front if we would reject the request), and set to
|
to check up front if we would reject the request), and set to
|
||||||
True for the last call for a given request.
|
True for the last call for a given request.
|
||||||
|
is_admin_redaction (bool): Whether this is a room admin/moderator
|
||||||
|
redacting an event. If so then we may apply different
|
||||||
|
ratelimits depending on config.
|
||||||
|
|
||||||
Raises:
|
Raises:
|
||||||
LimitExceededError if the request should be ratelimited
|
LimitExceededError if the request should be ratelimited
|
||||||
@@ -90,16 +94,33 @@ class BaseHandler(object):
|
|||||||
messages_per_second = override.messages_per_second
|
messages_per_second = override.messages_per_second
|
||||||
burst_count = override.burst_count
|
burst_count = override.burst_count
|
||||||
else:
|
else:
|
||||||
messages_per_second = self.hs.config.rc_message.per_second
|
# We default to different values if this is an admin redaction and
|
||||||
burst_count = self.hs.config.rc_message.burst_count
|
# the config is set
|
||||||
|
if is_admin_redaction and self.hs.config.rc_admin_redaction:
|
||||||
|
messages_per_second = self.hs.config.rc_admin_redaction.per_second
|
||||||
|
burst_count = self.hs.config.rc_admin_redaction.burst_count
|
||||||
|
else:
|
||||||
|
messages_per_second = self.hs.config.rc_message.per_second
|
||||||
|
burst_count = self.hs.config.rc_message.burst_count
|
||||||
|
|
||||||
allowed, time_allowed = self.ratelimiter.can_do_action(
|
if is_admin_redaction and self.hs.config.rc_admin_redaction:
|
||||||
user_id,
|
# If we have separate config for admin redactions we use a separate
|
||||||
time_now,
|
# ratelimiter
|
||||||
rate_hz=messages_per_second,
|
allowed, time_allowed = self.admin_redaction_ratelimiter.can_do_action(
|
||||||
burst_count=burst_count,
|
user_id,
|
||||||
update=update,
|
time_now,
|
||||||
)
|
rate_hz=messages_per_second,
|
||||||
|
burst_count=burst_count,
|
||||||
|
update=update,
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
allowed, time_allowed = self.ratelimiter.can_do_action(
|
||||||
|
user_id,
|
||||||
|
time_now,
|
||||||
|
rate_hz=messages_per_second,
|
||||||
|
burst_count=burst_count,
|
||||||
|
update=update,
|
||||||
|
)
|
||||||
if not allowed:
|
if not allowed:
|
||||||
raise LimitExceededError(
|
raise LimitExceededError(
|
||||||
retry_after_ms=int(1000 * (time_allowed - time_now))
|
retry_after_ms=int(1000 * (time_allowed - time_now))
|
||||||
|
|||||||
@@ -94,6 +94,25 @@ class AdminHandler(BaseHandler):
|
|||||||
|
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
|
def get_user_server_admin(self, user):
|
||||||
|
"""
|
||||||
|
Get the admin bit on a user.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
user_id (UserID): the (necessarily local) user to manipulate
|
||||||
|
"""
|
||||||
|
return self.store.is_server_admin(user)
|
||||||
|
|
||||||
|
def set_user_server_admin(self, user, admin):
|
||||||
|
"""
|
||||||
|
Set the admin bit on a user.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
user_id (UserID): the (necessarily local) user to manipulate
|
||||||
|
admin (bool): whether or not the user should be an admin of this server
|
||||||
|
"""
|
||||||
|
return self.store.set_server_admin(user, admin)
|
||||||
|
|
||||||
@defer.inlineCallbacks
|
@defer.inlineCallbacks
|
||||||
def export_user_data(self, user_id, writer):
|
def export_user_data(self, user_id, writer):
|
||||||
"""Write all data we have on the user to the given writer.
|
"""Write all data we have on the user to the given writer.
|
||||||
|
|||||||
@@ -726,7 +726,27 @@ class EventCreationHandler(object):
|
|||||||
assert not self.config.worker_app
|
assert not self.config.worker_app
|
||||||
|
|
||||||
if ratelimit:
|
if ratelimit:
|
||||||
yield self.base_handler.ratelimit(requester)
|
# We check if this is a room admin redacting an event so that we
|
||||||
|
# can apply different ratelimiting. We do this by simply checking
|
||||||
|
# it's not a self-redaction (to avoid having to look up whether the
|
||||||
|
# user is actually admin or not).
|
||||||
|
is_admin_redaction = False
|
||||||
|
if event.type == EventTypes.Redaction:
|
||||||
|
original_event = yield self.store.get_event(
|
||||||
|
event.redacts,
|
||||||
|
check_redacted=False,
|
||||||
|
get_prev_content=False,
|
||||||
|
allow_rejected=False,
|
||||||
|
allow_none=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
is_admin_redaction = (
|
||||||
|
original_event and event.sender != original_event.sender
|
||||||
|
)
|
||||||
|
|
||||||
|
yield self.base_handler.ratelimit(
|
||||||
|
requester, is_admin_redaction=is_admin_redaction
|
||||||
|
)
|
||||||
|
|
||||||
yield self.base_handler.maybe_kick_guest_users(event, context)
|
yield self.base_handler.maybe_kick_guest_users(event, context)
|
||||||
|
|
||||||
|
|||||||
@@ -335,6 +335,11 @@ BASE_APPEND_UNDERRIDE_RULES = [
|
|||||||
"_id": "_message",
|
"_id": "_message",
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
# default to not notifying for group chats
|
||||||
|
# see https://github.com/vector-im/riot-web/issues/3268
|
||||||
|
# we can't do this on existing servers because we need to
|
||||||
|
# add per-user overrides to preserve their existing behaviour
|
||||||
|
"enabled": False,
|
||||||
"actions": ["notify", {"set_tweak": "highlight", "value": False}],
|
"actions": ["notify", {"set_tweak": "highlight", "value": False}],
|
||||||
},
|
},
|
||||||
# XXX: this is going to fire for events which aren't m.room.messages
|
# XXX: this is going to fire for events which aren't m.room.messages
|
||||||
|
|||||||
@@ -43,6 +43,7 @@ from synapse.rest.admin._base import (
|
|||||||
)
|
)
|
||||||
from synapse.rest.admin.media import register_servlets_for_media_repo
|
from synapse.rest.admin.media import register_servlets_for_media_repo
|
||||||
from synapse.rest.admin.server_notice_servlet import SendServerNoticeServlet
|
from synapse.rest.admin.server_notice_servlet import SendServerNoticeServlet
|
||||||
|
from synapse.rest.admin.users import UserAdminServlet
|
||||||
from synapse.types import UserID, create_requester
|
from synapse.types import UserID, create_requester
|
||||||
from synapse.util.versionstring import get_version_string
|
from synapse.util.versionstring import get_version_string
|
||||||
|
|
||||||
@@ -50,7 +51,7 @@ logger = logging.getLogger(__name__)
|
|||||||
|
|
||||||
|
|
||||||
class UsersRestServlet(RestServlet):
|
class UsersRestServlet(RestServlet):
|
||||||
PATTERNS = historical_admin_path_patterns("/users/(?P<user_id>[^/]*)")
|
PATTERNS = historical_admin_path_patterns("/users/(?P<user_id>[^/]*)$")
|
||||||
|
|
||||||
def __init__(self, hs):
|
def __init__(self, hs):
|
||||||
self.hs = hs
|
self.hs = hs
|
||||||
@@ -740,6 +741,7 @@ def register_servlets(hs, http_server):
|
|||||||
register_servlets_for_client_rest_resource(hs, http_server)
|
register_servlets_for_client_rest_resource(hs, http_server)
|
||||||
SendServerNoticeServlet(hs).register(http_server)
|
SendServerNoticeServlet(hs).register(http_server)
|
||||||
VersionServlet(hs).register(http_server)
|
VersionServlet(hs).register(http_server)
|
||||||
|
UserAdminServlet(hs).register(http_server)
|
||||||
|
|
||||||
|
|
||||||
def register_servlets_for_client_rest_resource(hs, http_server):
|
def register_servlets_for_client_rest_resource(hs, http_server):
|
||||||
|
|||||||
100
synapse/rest/admin/users.py
Normal file
100
synapse/rest/admin/users.py
Normal file
@@ -0,0 +1,100 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# Copyright 2019 The Matrix.org Foundation C.I.C.
|
||||||
|
#
|
||||||
|
# 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.
|
||||||
|
import re
|
||||||
|
|
||||||
|
from twisted.internet import defer
|
||||||
|
|
||||||
|
from synapse.api.errors import SynapseError
|
||||||
|
from synapse.http.servlet import (
|
||||||
|
RestServlet,
|
||||||
|
assert_params_in_dict,
|
||||||
|
parse_json_object_from_request,
|
||||||
|
)
|
||||||
|
from synapse.rest.admin import assert_requester_is_admin, assert_user_is_admin
|
||||||
|
from synapse.types import UserID
|
||||||
|
|
||||||
|
|
||||||
|
class UserAdminServlet(RestServlet):
|
||||||
|
"""
|
||||||
|
Get or set whether or not a user is a server administrator.
|
||||||
|
|
||||||
|
Note that only local users can be server administrators, and that an
|
||||||
|
administrator may not demote themselves.
|
||||||
|
|
||||||
|
Only server administrators can use this API.
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
* Get
|
||||||
|
GET /_synapse/admin/v1/users/@nonadmin:example.com/admin
|
||||||
|
response on success:
|
||||||
|
{
|
||||||
|
"admin": false
|
||||||
|
}
|
||||||
|
* Set
|
||||||
|
PUT /_synapse/admin/v1/users/@reivilibre:librepush.net/admin
|
||||||
|
request body:
|
||||||
|
{
|
||||||
|
"admin": true
|
||||||
|
}
|
||||||
|
response on success:
|
||||||
|
{}
|
||||||
|
"""
|
||||||
|
|
||||||
|
PATTERNS = (re.compile("^/_synapse/admin/v1/users/(?P<user_id>@[^/]*)/admin$"),)
|
||||||
|
|
||||||
|
def __init__(self, hs):
|
||||||
|
self.hs = hs
|
||||||
|
self.auth = hs.get_auth()
|
||||||
|
self.handlers = hs.get_handlers()
|
||||||
|
|
||||||
|
@defer.inlineCallbacks
|
||||||
|
def on_GET(self, request, user_id):
|
||||||
|
yield assert_requester_is_admin(self.auth, request)
|
||||||
|
|
||||||
|
target_user = UserID.from_string(user_id)
|
||||||
|
|
||||||
|
if not self.hs.is_mine(target_user):
|
||||||
|
raise SynapseError(400, "Only local users can be admins of this homeserver")
|
||||||
|
|
||||||
|
is_admin = yield self.handlers.admin_handler.get_user_server_admin(target_user)
|
||||||
|
is_admin = bool(is_admin)
|
||||||
|
|
||||||
|
return (200, {"admin": is_admin})
|
||||||
|
|
||||||
|
@defer.inlineCallbacks
|
||||||
|
def on_PUT(self, request, user_id):
|
||||||
|
requester = yield self.auth.get_user_by_req(request)
|
||||||
|
yield assert_user_is_admin(self.auth, requester.user)
|
||||||
|
auth_user = requester.user
|
||||||
|
|
||||||
|
target_user = UserID.from_string(user_id)
|
||||||
|
|
||||||
|
body = parse_json_object_from_request(request)
|
||||||
|
|
||||||
|
assert_params_in_dict(body, ["admin"])
|
||||||
|
|
||||||
|
if not self.hs.is_mine(target_user):
|
||||||
|
raise SynapseError(400, "Only local users can be admins of this homeserver")
|
||||||
|
|
||||||
|
set_admin_to = bool(body["admin"])
|
||||||
|
|
||||||
|
if target_user == auth_user and not set_admin_to:
|
||||||
|
raise SynapseError(400, "You may not demote yourself.")
|
||||||
|
|
||||||
|
yield self.handlers.admin_handler.set_user_server_admin(
|
||||||
|
target_user, set_admin_to
|
||||||
|
)
|
||||||
|
|
||||||
|
return (200, {})
|
||||||
@@ -221,6 +221,7 @@ class HomeServer(object):
|
|||||||
self.clock = Clock(reactor)
|
self.clock = Clock(reactor)
|
||||||
self.distributor = Distributor()
|
self.distributor = Distributor()
|
||||||
self.ratelimiter = Ratelimiter()
|
self.ratelimiter = Ratelimiter()
|
||||||
|
self.admin_redaction_ratelimiter = Ratelimiter()
|
||||||
self.registration_ratelimiter = Ratelimiter()
|
self.registration_ratelimiter = Ratelimiter()
|
||||||
|
|
||||||
self.datastore = None
|
self.datastore = None
|
||||||
@@ -279,6 +280,9 @@ class HomeServer(object):
|
|||||||
def get_registration_ratelimiter(self):
|
def get_registration_ratelimiter(self):
|
||||||
return self.registration_ratelimiter
|
return self.registration_ratelimiter
|
||||||
|
|
||||||
|
def get_admin_redaction_ratelimiter(self):
|
||||||
|
return self.admin_redaction_ratelimiter
|
||||||
|
|
||||||
def build_federation_client(self):
|
def build_federation_client(self):
|
||||||
return FederationClient(self)
|
return FederationClient(self)
|
||||||
|
|
||||||
|
|||||||
@@ -62,7 +62,7 @@ var show_login = function() {
|
|||||||
$("#sso_flow").show();
|
$("#sso_flow").show();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!matrixLogin.serverAcceptsPassword && !matrixLogin.serverAcceptsCas) {
|
if (!matrixLogin.serverAcceptsPassword && !matrixLogin.serverAcceptsCas && !matrixLogin.serverAcceptsSso) {
|
||||||
$("#no_login_types").show();
|
$("#no_login_types").show();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -272,6 +272,14 @@ class RegistrationWorkerStore(SQLBaseStore):
|
|||||||
|
|
||||||
@defer.inlineCallbacks
|
@defer.inlineCallbacks
|
||||||
def is_server_admin(self, user):
|
def is_server_admin(self, user):
|
||||||
|
"""Determines if a user is an admin of this homeserver.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
user (UserID): user ID of the user to test
|
||||||
|
|
||||||
|
Returns (bool):
|
||||||
|
true iff the user is a server admin, false otherwise.
|
||||||
|
"""
|
||||||
res = yield self._simple_select_one_onecol(
|
res = yield self._simple_select_one_onecol(
|
||||||
table="users",
|
table="users",
|
||||||
keyvalues={"name": user.to_string()},
|
keyvalues={"name": user.to_string()},
|
||||||
@@ -282,6 +290,21 @@ class RegistrationWorkerStore(SQLBaseStore):
|
|||||||
|
|
||||||
return res if res else False
|
return res if res else False
|
||||||
|
|
||||||
|
def set_server_admin(self, user, admin):
|
||||||
|
"""Sets whether a user is an admin of this homeserver.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
user (UserID): user ID of the user to test
|
||||||
|
admin (bool): true iff the user is to be a server admin,
|
||||||
|
false otherwise.
|
||||||
|
"""
|
||||||
|
return self._simple_update_one(
|
||||||
|
table="users",
|
||||||
|
keyvalues={"name": user.to_string()},
|
||||||
|
updatevalues={"admin": 1 if admin else 0},
|
||||||
|
desc="set_server_admin",
|
||||||
|
)
|
||||||
|
|
||||||
def _query_for_auth(self, txn, token):
|
def _query_for_auth(self, txn, token):
|
||||||
sql = (
|
sql = (
|
||||||
"SELECT users.name, users.is_guest, access_tokens.id as token_id,"
|
"SELECT users.name, users.is_guest, access_tokens.id as token_id,"
|
||||||
|
|||||||
@@ -30,6 +30,14 @@ class RedactionsTestCase(HomeserverTestCase):
|
|||||||
sync.register_servlets,
|
sync.register_servlets,
|
||||||
]
|
]
|
||||||
|
|
||||||
|
def make_homeserver(self, reactor, clock):
|
||||||
|
config = self.default_config()
|
||||||
|
|
||||||
|
config["rc_message"] = {"per_second": 0.2, "burst_count": 10}
|
||||||
|
config["rc_admin_redaction"] = {"per_second": 1, "burst_count": 100}
|
||||||
|
|
||||||
|
return self.setup_test_homeserver(config=config)
|
||||||
|
|
||||||
def prepare(self, reactor, clock, hs):
|
def prepare(self, reactor, clock, hs):
|
||||||
# register a couple of users
|
# register a couple of users
|
||||||
self.mod_user_id = self.register_user("user1", "pass")
|
self.mod_user_id = self.register_user("user1", "pass")
|
||||||
@@ -177,3 +185,20 @@ class RedactionsTestCase(HomeserverTestCase):
|
|||||||
self._redact_event(
|
self._redact_event(
|
||||||
self.other_access_token, self.room_id, create_event_id, expect_code=403
|
self.other_access_token, self.room_id, create_event_id, expect_code=403
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def test_redact_event_as_moderator_ratelimit(self):
|
||||||
|
"""Tests that the correct ratelimiting is applied to redactions
|
||||||
|
"""
|
||||||
|
|
||||||
|
message_ids = []
|
||||||
|
# as a regular user, send messages to redact
|
||||||
|
for _ in range(20):
|
||||||
|
b = self.helper.send(room_id=self.room_id, tok=self.other_access_token)
|
||||||
|
message_ids.append(b["event_id"])
|
||||||
|
self.reactor.advance(10) # To get around ratelimits
|
||||||
|
|
||||||
|
# as the moderator, send a bunch of redactions
|
||||||
|
for msg_id in message_ids:
|
||||||
|
# These should all succeed, even though this would be denied by
|
||||||
|
# the standard message ratelimiter
|
||||||
|
self._redact_event(self.mod_access_token, self.room_id, msg_id)
|
||||||
|
|||||||
Reference in New Issue
Block a user