Merge pull request #4772 from jbweston/jbweston/server-version-api

Add 'server_version' endpoint to admin API
pull/4815/head
Erik Johnston 2019-03-05 16:31:00 +00:00 committed by GitHub
commit 16c8b4ecbd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 85 additions and 2 deletions

View File

@ -69,3 +69,6 @@ Serban Constantin <serban.constantin at gmail dot com>
Jason Robinson <jasonr at matrix.org> Jason Robinson <jasonr at matrix.org>
* Minor fixes * Minor fixes
Joseph Weston <joseph at weston.cloud>
+ Add admin API for querying HS version

1
changelog.d/4772.feature Normal file
View File

@ -0,0 +1 @@
Add an endpoint to the admin API for querying the server version. Contributed by Joseph Weston.

View File

@ -0,0 +1,22 @@
Version API
===========
This API returns the running Synapse version and the Python version
on which Synapse is being run. This is useful when a Synapse instance
is behind a proxy that does not forward the 'Server' header (which also
contains Synapse version information).
The api is::
GET /_matrix/client/r0/admin/server_version
including an ``access_token`` of a server admin.
It returns a JSON body like the following:
.. code:: json
{
"server_version": "0.99.2rc1 (b=develop, abcdef123)",
"python_version": "3.6.8"
}

View File

@ -17,12 +17,14 @@
import hashlib import hashlib
import hmac import hmac
import logging import logging
import platform
from six import text_type from six import text_type
from six.moves import http_client from six.moves import http_client
from twisted.internet import defer from twisted.internet import defer
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.servlet import ( from synapse.http.servlet import (
@ -32,6 +34,7 @@ from synapse.http.servlet import (
parse_string, parse_string,
) )
from synapse.types import UserID, create_requester from synapse.types import UserID, create_requester
from synapse.util.versionstring import get_version_string
from .base import ClientV1RestServlet, client_path_patterns from .base import ClientV1RestServlet, client_path_patterns
@ -66,6 +69,25 @@ class UsersRestServlet(ClientV1RestServlet):
defer.returnValue((200, ret)) defer.returnValue((200, ret))
class VersionServlet(ClientV1RestServlet):
PATTERNS = client_path_patterns("/admin/server_version")
@defer.inlineCallbacks
def on_GET(self, request):
requester = yield self.auth.get_user_by_req(request)
is_admin = yield self.auth.is_server_admin(requester.user)
if not is_admin:
raise AuthError(403, "You are not a server admin")
ret = {
'server_version': get_version_string(synapse),
'python_version': platform.python_version(),
}
defer.returnValue((200, ret))
class UserRegisterServlet(ClientV1RestServlet): class UserRegisterServlet(ClientV1RestServlet):
""" """
Attributes: Attributes:
@ -763,3 +785,4 @@ def register_servlets(hs, http_server):
QuarantineMediaInRoom(hs).register(http_server) QuarantineMediaInRoom(hs).register(http_server)
ListMediaInRoom(hs).register(http_server) ListMediaInRoom(hs).register(http_server)
UserRegisterServlet(hs).register(http_server) UserRegisterServlet(hs).register(http_server)
VersionServlet(hs).register(http_server)

View File

@ -20,14 +20,48 @@ import json
from mock import Mock from mock import Mock
from synapse.api.constants import UserTypes from synapse.api.constants import UserTypes
from synapse.rest.client.v1.admin import register_servlets from synapse.rest.client.v1 import admin, login
from tests import unittest from tests import unittest
class VersionTestCase(unittest.HomeserverTestCase):
servlets = [
admin.register_servlets,
login.register_servlets,
]
url = '/_matrix/client/r0/admin/server_version'
def test_version_string(self):
self.register_user("admin", "pass", admin=True)
self.admin_token = self.login("admin", "pass")
request, channel = self.make_request("GET", self.url,
access_token=self.admin_token)
self.render(request)
self.assertEqual(200, int(channel.result["code"]),
msg=channel.result["body"])
self.assertEqual({'server_version', 'python_version'},
set(channel.json_body.keys()))
def test_inaccessible_to_non_admins(self):
self.register_user("unprivileged-user", "pass", admin=False)
user_token = self.login("unprivileged-user", "pass")
request, channel = self.make_request("GET", self.url,
access_token=user_token)
self.render(request)
self.assertEqual(403, int(channel.result['code']),
msg=channel.result['body'])
class UserRegisterTestCase(unittest.HomeserverTestCase): class UserRegisterTestCase(unittest.HomeserverTestCase):
servlets = [register_servlets] servlets = [admin.register_servlets]
def make_homeserver(self, reactor, clock): def make_homeserver(self, reactor, clock):