diff --git a/docs/admin_api/account_validity.rst b/docs/admin_api/account_validity.rst
index c26353752f..7559de4c57 100644
--- a/docs/admin_api/account_validity.rst
+++ b/docs/admin_api/account_validity.rst
@@ -13,7 +13,7 @@ This API extends the validity of an account by as much time as configured in the
The API is::
- POST /_matrix/client/unstable/admin/account_validity/validity
+ POST /_synapse/admin/v1/account_validity/validity
with the following body:
diff --git a/docs/admin_api/delete_group.md b/docs/admin_api/delete_group.md
index d703d108b0..1710488ea8 100644
--- a/docs/admin_api/delete_group.md
+++ b/docs/admin_api/delete_group.md
@@ -8,7 +8,7 @@ being deleted.
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.
diff --git a/docs/admin_api/media_admin_api.md b/docs/admin_api/media_admin_api.md
index abdbc1ea86..5e9f8e5d84 100644
--- a/docs/admin_api/media_admin_api.md
+++ b/docs/admin_api/media_admin_api.md
@@ -4,7 +4,7 @@ This API gets a list of known media in a room.
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.
diff --git a/docs/admin_api/purge_history_api.rst b/docs/admin_api/purge_history_api.rst
index a5c3dc8149..f7be226fd9 100644
--- a/docs/admin_api/purge_history_api.rst
+++ b/docs/admin_api/purge_history_api.rst
@@ -10,7 +10,7 @@ paginate further back in the room from the point being purged from.
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.
@@ -49,7 +49,7 @@ Purge status query
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
the following:
diff --git a/docs/admin_api/purge_remote_media.rst b/docs/admin_api/purge_remote_media.rst
index 5deb02a3df..dacd5bc8fb 100644
--- a/docs/admin_api/purge_remote_media.rst
+++ b/docs/admin_api/purge_remote_media.rst
@@ -6,7 +6,7 @@ media.
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>
{}
diff --git a/docs/admin_api/register_api.rst b/docs/admin_api/register_api.rst
index 084e74ebf5..3a63109aa0 100644
--- a/docs/admin_api/register_api.rst
+++ b/docs/admin_api/register_api.rst
@@ -12,7 +12,7 @@ is not enabled.
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"}
@@ -22,7 +22,7 @@ body containing the nonce, username, password, whether they are an admin
As an example::
- > POST /_matrix/client/r0/admin/register
+ > POST /_synapse/admin/v1/register
> {
"nonce": "thisisanonce",
"username": "pepper_roni",
diff --git a/docs/admin_api/user_admin_api.rst b/docs/admin_api/user_admin_api.rst
index d17121a188..8aca4f158d 100644
--- a/docs/admin_api/user_admin_api.rst
+++ b/docs/admin_api/user_admin_api.rst
@@ -5,7 +5,7 @@ This API returns information about a specific user account.
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.
@@ -50,7 +50,7 @@ references to it).
The api is::
- POST /_matrix/client/r0/admin/deactivate/<user_id>
+ POST /_synapse/admin/v1/deactivate/<user_id>
with a body of:
@@ -73,7 +73,7 @@ Changes the password of another user.
The api is::
- POST /_matrix/client/r0/admin/reset_password/<user_id>
+ POST /_synapse/admin/v1/reset_password/<user_id>
with a body of:
diff --git a/docs/admin_api/version_api.rst b/docs/admin_api/version_api.rst
index 30a91b5f43..6d66543b96 100644
--- a/docs/admin_api/version_api.rst
+++ b/docs/admin_api/version_api.rst
@@ -8,7 +8,7 @@ contains Synapse version information).
The api is::
- GET /_matrix/client/r0/admin/server_version
+ GET /_synapse/admin/v1/server_version
including an ``access_token`` of a server admin.
diff --git a/synapse/app/homeserver.py b/synapse/app/homeserver.py
index 79be977ea6..3d7db61d14 100755
--- a/synapse/app/homeserver.py
+++ b/synapse/app/homeserver.py
@@ -62,6 +62,7 @@ from synapse.python_dependencies import check_requirements
from synapse.replication.http import REPLICATION_PREFIX, ReplicationRestResource
from synapse.replication.tcp.resource import ReplicationStreamProtocolFactory
from synapse.rest import ClientRestResource
+from synapse.rest.client.v1.admin import AdminRestResource
from synapse.rest.key.v2 import KeyApiV2Resource
from synapse.rest.media.v0.content_repository import ContentRepoResource
from synapse.rest.well_known import WellKnownResource
@@ -180,6 +181,7 @@ class SynapseHomeServer(HomeServer):
"/_matrix/client/v2_alpha": client_resource,
"/_matrix/client/versions": client_resource,
"/.well-known/matrix/client": WellKnownResource(self),
+ "/_synapse/admin": AdminRestResource(self),
})
if self.get_config().saml2_enabled:
diff --git a/synapse/config/server.py b/synapse/config/server.py
index cdf1e4d286..cc232422b9 100644
--- a/synapse/config/server.py
+++ b/synapse/config/server.py
@@ -388,8 +388,8 @@ class ServerConfig(Config):
#
# Valid resource names are:
#
- # client: the client-server API (/_matrix/client). Also implies 'media' and
- # 'static'.
+ # client: the client-server API (/_matrix/client), and the synapse admin
+ # API (/_synapse/admin). Also implies 'media' and 'static'.
#
# consent: user consent forms (/_matrix/consent). See
# docs/consent_tracking.md.
diff --git a/synapse/rest/__init__.py b/synapse/rest/__init__.py
index a66885d349..6bc50f78e1 100644
--- a/synapse/rest/__init__.py
+++ b/synapse/rest/__init__.py
@@ -58,8 +58,14 @@ from synapse.rest.client.v2_alpha import (
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):
JsonResource.__init__(self, hs, canonical_json=False)
self.register_servlets(self, hs)
@@ -82,7 +88,6 @@ class ClientRestResource(JsonResource):
presence.register_servlets(hs, client_resource)
directory.register_servlets(hs, client_resource)
voip.register_servlets(hs, client_resource)
- admin.register_servlets(hs, client_resource)
pusher.register_servlets(hs, client_resource)
push_rule.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)
capabilities.register_servlets(hs, client_resource)
account_validity.register_servlets(hs, client_resource)
+
+ # moving to /_synapse/admin
+ admin.register_servlets(hs, client_resource)
diff --git a/synapse/rest/client/v1/admin.py b/synapse/rest/client/v1/admin.py
index 8efa457d15..d4f83e4ae8 100644
--- a/synapse/rest/client/v1/admin.py
+++ b/synapse/rest/client/v1/admin.py
@@ -18,6 +18,7 @@ import hashlib
import hmac
import logging
import platform
+import re
from six import text_type
from six.moves import http_client
@@ -27,6 +28,7 @@ from twisted.internet import defer
import synapse
from synapse.api.constants import Membership, UserTypes
from synapse.api.errors import AuthError, Codes, NotFoundError, SynapseError
+from synapse.http.server import JsonResource
from synapse.http.servlet import (
RestServlet,
assert_params_in_dict,
@@ -37,13 +39,33 @@ from synapse.http.servlet import (
from synapse.types import UserID, create_requester
from synapse.util.versionstring import get_version_string
-from .base import client_path_patterns
-
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):
- PATTERNS = client_path_patterns("/admin/users/(?P<user_id>[^/]*)")
+ PATTERNS = historical_admin_path_patterns("/users/(?P<user_id>[^/]*)")
def __init__(self, hs):
self.hs = hs
@@ -72,7 +94,7 @@ class UsersRestServlet(RestServlet):
class VersionServlet(RestServlet):
- PATTERNS = client_path_patterns("/admin/server_version")
+ PATTERNS = historical_admin_path_patterns("/server_version")
def __init__(self, hs):
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
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
def __init__(self, hs):
@@ -231,7 +253,7 @@ class UserRegisterServlet(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):
self.hs = hs
@@ -257,7 +279,7 @@ class WhoisRestServlet(RestServlet):
class PurgeMediaCacheRestServlet(RestServlet):
- PATTERNS = client_path_patterns("/admin/purge_media_cache")
+ PATTERNS = historical_admin_path_patterns("/purge_media_cache")
def __init__(self, hs):
self.media_repository = hs.get_media_repository()
@@ -280,8 +302,8 @@ class PurgeMediaCacheRestServlet(RestServlet):
class PurgeHistoryRestServlet(RestServlet):
- PATTERNS = client_path_patterns(
- "/admin/purge_history/(?P<room_id>[^/]*)(/(?P<event_id>[^/]+))?"
+ PATTERNS = historical_admin_path_patterns(
+ "/purge_history/(?P<room_id>[^/]*)(/(?P<event_id>[^/]+))?"
)
def __init__(self, hs):
@@ -377,8 +399,8 @@ class PurgeHistoryRestServlet(RestServlet):
class PurgeHistoryStatusRestServlet(RestServlet):
- PATTERNS = client_path_patterns(
- "/admin/purge_history_status/(?P<purge_id>[^/]+)"
+ PATTERNS = historical_admin_path_patterns(
+ "/purge_history_status/(?P<purge_id>[^/]+)"
)
def __init__(self, hs):
@@ -406,7 +428,7 @@ class PurgeHistoryStatusRestServlet(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):
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
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 = (
"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
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):
self.store = hs.get_datastore()
@@ -597,7 +619,7 @@ class QuarantineMediaInRoom(RestServlet):
class ListMediaInRoom(RestServlet):
"""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):
self.store = hs.get_datastore()
@@ -627,7 +649,7 @@ class ResetPasswordRestServlet(RestServlet):
Returns:
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):
self.store = hs.get_datastore()
@@ -666,7 +688,7 @@ class GetUsersPaginatedRestServlet(RestServlet):
Returns:
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):
self.store = hs.get_datastore()
@@ -749,7 +771,7 @@ class SearchUsersRestServlet(RestServlet):
Returns:
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):
self.store = hs.get_datastore()
@@ -789,7 +811,7 @@ class SearchUsersRestServlet(RestServlet):
class DeleteGroupAdminRestServlet(RestServlet):
"""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):
self.group_server = hs.get_groups_server_handler()
@@ -812,7 +834,7 @@ class DeleteGroupAdminRestServlet(RestServlet):
class AccountValidityRenewServlet(RestServlet):
- PATTERNS = client_path_patterns("/admin/account_validity/validity$")
+ PATTERNS = historical_admin_path_patterns("/account_validity/validity$")
def __init__(self, hs):
"""
@@ -847,6 +869,14 @@ class AccountValidityRenewServlet(RestServlet):
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):
WhoisRestServlet(hs).register(http_server)
PurgeMediaCacheRestServlet(hs).register(http_server)
|