Move admin API to a new prefix

This commit is contained in:
Richard van der Hoff 2019-05-01 15:18:58 +01:00
parent 579b637b6c
commit 8e9ca83537
12 changed files with 76 additions and 36 deletions

View File

@ -13,7 +13,7 @@ This API extends the validity of an account by as much time as configured in the
The API is:: The API is::
POST /_matrix/client/unstable/admin/account_validity/validity POST /_synapse/admin/v1/account_validity/validity
with the following body: with the following body:

View File

@ -8,7 +8,7 @@ being deleted.
The API is: The API is:
``` ```
POST /_matrix/client/r0/admin/delete_group/<group_id> POST /_synapse/admin/v1/delete_group/<group_id>
``` ```
including an `access_token` of a server admin. including an `access_token` of a server admin.

View File

@ -4,7 +4,7 @@ This API gets a list of known media in a room.
The API is: The API is:
``` ```
GET /_matrix/client/r0/admin/room/<room_id>/media GET /_synapse/admin/v1/room/<room_id>/media
``` ```
including an `access_token` of a server admin. including an `access_token` of a server admin.

View File

@ -10,7 +10,7 @@ paginate further back in the room from the point being purged from.
The API is: The API is:
``POST /_matrix/client/r0/admin/purge_history/<room_id>[/<event_id>]`` ``POST /_synapse/admin/v1/purge_history/<room_id>[/<event_id>]``
including an ``access_token`` of a server admin. including an ``access_token`` of a server admin.
@ -49,7 +49,7 @@ Purge status query
It is possible to poll for updates on recent purges with a second API; It is possible to poll for updates on recent purges with a second API;
``GET /_matrix/client/r0/admin/purge_history_status/<purge_id>`` ``GET /_synapse/admin/v1/purge_history_status/<purge_id>``
(again, with a suitable ``access_token``). This API returns a JSON body like (again, with a suitable ``access_token``). This API returns a JSON body like
the following: the following:

View File

@ -6,7 +6,7 @@ media.
The API is:: The API is::
POST /_matrix/client/r0/admin/purge_media_cache?before_ts=<unix_timestamp_in_ms>&access_token=<access_token> POST /_synapse/admin/v1/purge_media_cache?before_ts=<unix_timestamp_in_ms>&access_token=<access_token>
{} {}

View File

@ -12,7 +12,7 @@ is not enabled.
To fetch the nonce, you need to request one from the API:: To fetch the nonce, you need to request one from the API::
> GET /_matrix/client/r0/admin/register > GET /_synapse/admin/v1/register
< {"nonce": "thisisanonce"} < {"nonce": "thisisanonce"}
@ -22,7 +22,7 @@ body containing the nonce, username, password, whether they are an admin
As an example:: As an example::
> POST /_matrix/client/r0/admin/register > POST /_synapse/admin/v1/register
> { > {
"nonce": "thisisanonce", "nonce": "thisisanonce",
"username": "pepper_roni", "username": "pepper_roni",

View File

@ -5,7 +5,7 @@ This API returns information about a specific user account.
The api is:: The api is::
GET /_matrix/client/r0/admin/whois/<user_id> GET /_synapse/admin/v1/whois/<user_id>
including an ``access_token`` of a server admin. including an ``access_token`` of a server admin.
@ -50,7 +50,7 @@ references to it).
The api is:: The api is::
POST /_matrix/client/r0/admin/deactivate/<user_id> POST /_synapse/admin/v1/deactivate/<user_id>
with a body of: with a body of:
@ -73,7 +73,7 @@ Changes the password of another user.
The api is:: The api is::
POST /_matrix/client/r0/admin/reset_password/<user_id> POST /_synapse/admin/v1/reset_password/<user_id>
with a body of: with a body of:

View File

@ -8,7 +8,7 @@ contains Synapse version information).
The api is:: The api is::
GET /_matrix/client/r0/admin/server_version GET /_synapse/admin/v1/server_version
including an ``access_token`` of a server admin. including an ``access_token`` of a server admin.

View File

@ -62,6 +62,7 @@ from synapse.python_dependencies import check_requirements
from synapse.replication.http import REPLICATION_PREFIX, ReplicationRestResource from synapse.replication.http import REPLICATION_PREFIX, ReplicationRestResource
from synapse.replication.tcp.resource import ReplicationStreamProtocolFactory from synapse.replication.tcp.resource import ReplicationStreamProtocolFactory
from synapse.rest import ClientRestResource from synapse.rest import ClientRestResource
from synapse.rest.client.v1.admin import AdminRestResource
from synapse.rest.key.v2 import KeyApiV2Resource from synapse.rest.key.v2 import KeyApiV2Resource
from synapse.rest.media.v0.content_repository import ContentRepoResource from synapse.rest.media.v0.content_repository import ContentRepoResource
from synapse.rest.well_known import WellKnownResource from synapse.rest.well_known import WellKnownResource
@ -180,6 +181,7 @@ class SynapseHomeServer(HomeServer):
"/_matrix/client/v2_alpha": client_resource, "/_matrix/client/v2_alpha": client_resource,
"/_matrix/client/versions": client_resource, "/_matrix/client/versions": client_resource,
"/.well-known/matrix/client": WellKnownResource(self), "/.well-known/matrix/client": WellKnownResource(self),
"/_synapse/admin": AdminRestResource(self),
}) })
if self.get_config().saml2_enabled: if self.get_config().saml2_enabled:

View File

@ -388,8 +388,8 @@ class ServerConfig(Config):
# #
# Valid resource names are: # Valid resource names are:
# #
# client: the client-server API (/_matrix/client). Also implies 'media' and # client: the client-server API (/_matrix/client), and the synapse admin
# 'static'. # API (/_synapse/admin). Also implies 'media' and 'static'.
# #
# consent: user consent forms (/_matrix/consent). See # consent: user consent forms (/_matrix/consent). See
# docs/consent_tracking.md. # docs/consent_tracking.md.

View File

@ -58,8 +58,14 @@ from synapse.rest.client.v2_alpha import (
class ClientRestResource(JsonResource): class ClientRestResource(JsonResource):
"""A resource for version 1 of the matrix client API.""" """Matrix Client API REST resource.
This gets mounted at various points under /_matrix/client, including:
* /_matrix/client/r0
* /_matrix/client/api/v1
* /_matrix/client/unstable
* etc
"""
def __init__(self, hs): def __init__(self, hs):
JsonResource.__init__(self, hs, canonical_json=False) JsonResource.__init__(self, hs, canonical_json=False)
self.register_servlets(self, hs) self.register_servlets(self, hs)
@ -82,7 +88,6 @@ class ClientRestResource(JsonResource):
presence.register_servlets(hs, client_resource) presence.register_servlets(hs, client_resource)
directory.register_servlets(hs, client_resource) directory.register_servlets(hs, client_resource)
voip.register_servlets(hs, client_resource) voip.register_servlets(hs, client_resource)
admin.register_servlets(hs, client_resource)
pusher.register_servlets(hs, client_resource) pusher.register_servlets(hs, client_resource)
push_rule.register_servlets(hs, client_resource) push_rule.register_servlets(hs, client_resource)
logout.register_servlets(hs, client_resource) logout.register_servlets(hs, client_resource)
@ -111,3 +116,6 @@ class ClientRestResource(JsonResource):
room_upgrade_rest_servlet.register_servlets(hs, client_resource) room_upgrade_rest_servlet.register_servlets(hs, client_resource)
capabilities.register_servlets(hs, client_resource) capabilities.register_servlets(hs, client_resource)
account_validity.register_servlets(hs, client_resource) account_validity.register_servlets(hs, client_resource)
# moving to /_synapse/admin
admin.register_servlets(hs, client_resource)

View File

@ -18,6 +18,7 @@ import hashlib
import hmac import hmac
import logging import logging
import platform import platform
import re
from six import text_type from six import text_type
from six.moves import http_client from six.moves import http_client
@ -27,6 +28,7 @@ from twisted.internet import defer
import synapse import synapse
from synapse.api.constants import Membership, UserTypes from synapse.api.constants import Membership, UserTypes
from synapse.api.errors import AuthError, Codes, NotFoundError, SynapseError from synapse.api.errors import AuthError, Codes, NotFoundError, SynapseError
from synapse.http.server import JsonResource
from synapse.http.servlet import ( from synapse.http.servlet import (
RestServlet, RestServlet,
assert_params_in_dict, assert_params_in_dict,
@ -37,13 +39,33 @@ from synapse.http.servlet import (
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
from .base import client_path_patterns
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
def historical_admin_path_patterns(path_regex):
"""Returns the list of patterns for an admin endpoint, including historical ones
This is a backwards-compatibility hack. Previously, the Admin API was exposed at
various paths under /_matrix/client. This function returns a list of patterns
matching those paths (as well as the new one), so that existing scripts which rely
on the endpoints being available there are not broken.
Note that this should only be used for existing endpoints: new ones should just
register for the /_synapse/admin path.
"""
return list(
re.compile(prefix + path_regex)
for prefix in (
"^/_synapse/admin/v1",
"^/_matrix/client/api/v1/admin",
"^/_matrix/client/unstable/admin",
"^/_matrix/client/r0/admin"
)
)
class UsersRestServlet(RestServlet): class UsersRestServlet(RestServlet):
PATTERNS = client_path_patterns("/admin/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
@ -72,7 +94,7 @@ class UsersRestServlet(RestServlet):
class VersionServlet(RestServlet): class VersionServlet(RestServlet):
PATTERNS = client_path_patterns("/admin/server_version") PATTERNS = historical_admin_path_patterns("/server_version")
def __init__(self, hs): def __init__(self, hs):
self.auth = hs.get_auth() self.auth = hs.get_auth()
@ -100,7 +122,7 @@ class UserRegisterServlet(RestServlet):
nonces (dict[str, int]): The nonces that we will accept. A dict of nonces (dict[str, int]): The nonces that we will accept. A dict of
nonce to the time it was generated, in int seconds. nonce to the time it was generated, in int seconds.
""" """
PATTERNS = client_path_patterns("/admin/register") PATTERNS = historical_admin_path_patterns("/register")
NONCE_TIMEOUT = 60 NONCE_TIMEOUT = 60
def __init__(self, hs): def __init__(self, hs):
@ -231,7 +253,7 @@ class UserRegisterServlet(RestServlet):
class WhoisRestServlet(RestServlet): class WhoisRestServlet(RestServlet):
PATTERNS = client_path_patterns("/admin/whois/(?P<user_id>[^/]*)") PATTERNS = historical_admin_path_patterns("/whois/(?P<user_id>[^/]*)")
def __init__(self, hs): def __init__(self, hs):
self.hs = hs self.hs = hs
@ -257,7 +279,7 @@ class WhoisRestServlet(RestServlet):
class PurgeMediaCacheRestServlet(RestServlet): class PurgeMediaCacheRestServlet(RestServlet):
PATTERNS = client_path_patterns("/admin/purge_media_cache") PATTERNS = historical_admin_path_patterns("/purge_media_cache")
def __init__(self, hs): def __init__(self, hs):
self.media_repository = hs.get_media_repository() self.media_repository = hs.get_media_repository()
@ -280,8 +302,8 @@ class PurgeMediaCacheRestServlet(RestServlet):
class PurgeHistoryRestServlet(RestServlet): class PurgeHistoryRestServlet(RestServlet):
PATTERNS = client_path_patterns( PATTERNS = historical_admin_path_patterns(
"/admin/purge_history/(?P<room_id>[^/]*)(/(?P<event_id>[^/]+))?" "/purge_history/(?P<room_id>[^/]*)(/(?P<event_id>[^/]+))?"
) )
def __init__(self, hs): def __init__(self, hs):
@ -377,8 +399,8 @@ class PurgeHistoryRestServlet(RestServlet):
class PurgeHistoryStatusRestServlet(RestServlet): class PurgeHistoryStatusRestServlet(RestServlet):
PATTERNS = client_path_patterns( PATTERNS = historical_admin_path_patterns(
"/admin/purge_history_status/(?P<purge_id>[^/]+)" "/purge_history_status/(?P<purge_id>[^/]+)"
) )
def __init__(self, hs): def __init__(self, hs):
@ -406,7 +428,7 @@ class PurgeHistoryStatusRestServlet(RestServlet):
class DeactivateAccountRestServlet(RestServlet): class DeactivateAccountRestServlet(RestServlet):
PATTERNS = client_path_patterns("/admin/deactivate/(?P<target_user_id>[^/]*)") PATTERNS = historical_admin_path_patterns("/deactivate/(?P<target_user_id>[^/]*)")
def __init__(self, hs): def __init__(self, hs):
self._deactivate_account_handler = hs.get_deactivate_account_handler() self._deactivate_account_handler = hs.get_deactivate_account_handler()
@ -449,7 +471,7 @@ class ShutdownRoomRestServlet(RestServlet):
to a new room created by `new_room_user_id` and kicked users will be auto to a new room created by `new_room_user_id` and kicked users will be auto
joined to the new room. joined to the new room.
""" """
PATTERNS = client_path_patterns("/admin/shutdown_room/(?P<room_id>[^/]+)") PATTERNS = historical_admin_path_patterns("/shutdown_room/(?P<room_id>[^/]+)")
DEFAULT_MESSAGE = ( DEFAULT_MESSAGE = (
"Sharing illegal content on this server is not permitted and rooms in" "Sharing illegal content on this server is not permitted and rooms in"
@ -574,7 +596,7 @@ class QuarantineMediaInRoom(RestServlet):
"""Quarantines all media in a room so that no one can download it via """Quarantines all media in a room so that no one can download it via
this server. this server.
""" """
PATTERNS = client_path_patterns("/admin/quarantine_media/(?P<room_id>[^/]+)") PATTERNS = historical_admin_path_patterns("/quarantine_media/(?P<room_id>[^/]+)")
def __init__(self, hs): def __init__(self, hs):
self.store = hs.get_datastore() self.store = hs.get_datastore()
@ -597,7 +619,7 @@ class QuarantineMediaInRoom(RestServlet):
class ListMediaInRoom(RestServlet): class ListMediaInRoom(RestServlet):
"""Lists all of the media in a given room. """Lists all of the media in a given room.
""" """
PATTERNS = client_path_patterns("/admin/room/(?P<room_id>[^/]+)/media") PATTERNS = historical_admin_path_patterns("/room/(?P<room_id>[^/]+)/media")
def __init__(self, hs): def __init__(self, hs):
self.store = hs.get_datastore() self.store = hs.get_datastore()
@ -627,7 +649,7 @@ class ResetPasswordRestServlet(RestServlet):
Returns: Returns:
200 OK with empty object if success otherwise an error. 200 OK with empty object if success otherwise an error.
""" """
PATTERNS = client_path_patterns("/admin/reset_password/(?P<target_user_id>[^/]*)") PATTERNS = historical_admin_path_patterns("/reset_password/(?P<target_user_id>[^/]*)")
def __init__(self, hs): def __init__(self, hs):
self.store = hs.get_datastore() self.store = hs.get_datastore()
@ -666,7 +688,7 @@ class GetUsersPaginatedRestServlet(RestServlet):
Returns: Returns:
200 OK with json object {list[dict[str, Any]], count} or empty object. 200 OK with json object {list[dict[str, Any]], count} or empty object.
""" """
PATTERNS = client_path_patterns("/admin/users_paginate/(?P<target_user_id>[^/]*)") PATTERNS = historical_admin_path_patterns("/users_paginate/(?P<target_user_id>[^/]*)")
def __init__(self, hs): def __init__(self, hs):
self.store = hs.get_datastore() self.store = hs.get_datastore()
@ -749,7 +771,7 @@ class SearchUsersRestServlet(RestServlet):
Returns: Returns:
200 OK with json object {list[dict[str, Any]], count} or empty object. 200 OK with json object {list[dict[str, Any]], count} or empty object.
""" """
PATTERNS = client_path_patterns("/admin/search_users/(?P<target_user_id>[^/]*)") PATTERNS = historical_admin_path_patterns("/search_users/(?P<target_user_id>[^/]*)")
def __init__(self, hs): def __init__(self, hs):
self.store = hs.get_datastore() self.store = hs.get_datastore()
@ -789,7 +811,7 @@ class SearchUsersRestServlet(RestServlet):
class DeleteGroupAdminRestServlet(RestServlet): class DeleteGroupAdminRestServlet(RestServlet):
"""Allows deleting of local groups """Allows deleting of local groups
""" """
PATTERNS = client_path_patterns("/admin/delete_group/(?P<group_id>[^/]*)") PATTERNS = historical_admin_path_patterns("/delete_group/(?P<group_id>[^/]*)")
def __init__(self, hs): def __init__(self, hs):
self.group_server = hs.get_groups_server_handler() self.group_server = hs.get_groups_server_handler()
@ -812,7 +834,7 @@ class DeleteGroupAdminRestServlet(RestServlet):
class AccountValidityRenewServlet(RestServlet): class AccountValidityRenewServlet(RestServlet):
PATTERNS = client_path_patterns("/admin/account_validity/validity$") PATTERNS = historical_admin_path_patterns("/account_validity/validity$")
def __init__(self, hs): def __init__(self, hs):
""" """
@ -847,6 +869,14 @@ class AccountValidityRenewServlet(RestServlet):
defer.returnValue((200, res)) defer.returnValue((200, res))
class AdminRestResource(JsonResource):
"""The REST resource which gets mounted at /_synapse/admin"""
def __init__(self, hs):
JsonResource.__init__(self, hs, canonical_json=False)
register_servlets(hs, self)
def register_servlets(hs, http_server): def register_servlets(hs, http_server):
WhoisRestServlet(hs).register(http_server) WhoisRestServlet(hs).register(http_server)
PurgeMediaCacheRestServlet(hs).register(http_server) PurgeMediaCacheRestServlet(hs).register(http_server)