From e8d98466b0d29abd3604470af9f10134f3373506 Mon Sep 17 00:00:00 2001 From: Richard van der Hoff <1389908+richvdh@users.noreply.github.com> Date: Wed, 5 Dec 2018 14:38:58 +0100 Subject: [PATCH] Implement .well-known handling (#4262) Sometimes it's useful for synapse to generate its own .well-known file. --- changelog.d/4262.feature | 1 + synapse/app/homeserver.py | 2 + synapse/config/registration.py | 9 +++++ synapse/rest/well_known.py | 70 ++++++++++++++++++++++++++++++++++ tests/rest/test_well_known.py | 58 ++++++++++++++++++++++++++++ 5 files changed, 140 insertions(+) create mode 100644 changelog.d/4262.feature create mode 100644 synapse/rest/well_known.py create mode 100644 tests/rest/test_well_known.py diff --git a/changelog.d/4262.feature b/changelog.d/4262.feature new file mode 100644 index 0000000000..89cfdcab15 --- /dev/null +++ b/changelog.d/4262.feature @@ -0,0 +1 @@ +Support for serving .well-known files diff --git a/synapse/app/homeserver.py b/synapse/app/homeserver.py index 3e4dea2f19..a03a3e4b8a 100755 --- a/synapse/app/homeserver.py +++ b/synapse/app/homeserver.py @@ -60,6 +60,7 @@ from synapse.replication.tcp.resource import ReplicationStreamProtocolFactory from synapse.rest import ClientRestResource from synapse.rest.key.v2 import KeyApiV2Resource from synapse.rest.media.v0.content_repository import ContentRepoResource +from synapse.rest.well_known import WellKnownResource from synapse.server import HomeServer from synapse.storage import DataStore, are_all_users_on_domain from synapse.storage.engines import IncorrectDatabaseSetup, create_engine @@ -195,6 +196,7 @@ class SynapseHomeServer(HomeServer): "/_matrix/client/unstable": client_resource, "/_matrix/client/v2_alpha": client_resource, "/_matrix/client/versions": client_resource, + "/.well-known/matrix/client": WellKnownResource(self), }) if name == "consent": diff --git a/synapse/config/registration.py b/synapse/config/registration.py index 717bbfec61..e365f0c30b 100644 --- a/synapse/config/registration.py +++ b/synapse/config/registration.py @@ -37,6 +37,7 @@ class RegistrationConfig(Config): self.bcrypt_rounds = config.get("bcrypt_rounds", 12) self.trusted_third_party_id_servers = config["trusted_third_party_id_servers"] + self.default_identity_server = config.get("default_identity_server") self.allow_guest_access = config.get("allow_guest_access", False) self.invite_3pid_guest = ( @@ -91,6 +92,14 @@ class RegistrationConfig(Config): # accessible to anonymous users. allow_guest_access: False + # The identity server which we suggest that clients should use when users log + # in on this server. + # + # (By default, no suggestion is made, so it is left up to the client. + # This setting is ignored unless public_baseurl is also set.) + # + # default_identity_server: https://matrix.org + # The list of identity servers trusted to verify third party # identifiers by this server. # diff --git a/synapse/rest/well_known.py b/synapse/rest/well_known.py new file mode 100644 index 0000000000..6e043d6162 --- /dev/null +++ b/synapse/rest/well_known.py @@ -0,0 +1,70 @@ +# -*- coding: utf-8 -*- +# Copyright 2018 New Vector 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. + +import json +import logging + +from twisted.web.resource import Resource + +logger = logging.getLogger(__name__) + + +class WellKnownBuilder(object): + """Utility to construct the well-known response + + Args: + hs (synapse.server.HomeServer): + """ + def __init__(self, hs): + self._config = hs.config + + def get_well_known(self): + # if we don't have a public_base_url, we can't help much here. + if self._config.public_baseurl is None: + return None + + result = { + "m.homeserver": { + "base_url": self._config.public_baseurl, + }, + } + + if self._config.default_identity_server: + result["m.identity_server"] = { + "base_url": self._config.default_identity_server, + } + + return result + + +class WellKnownResource(Resource): + """A Twisted web resource which renders the .well-known file""" + + isLeaf = 1 + + def __init__(self, hs): + Resource.__init__(self) + self._well_known_builder = WellKnownBuilder(hs) + + def render_GET(self, request): + r = self._well_known_builder.get_well_known() + if not r: + request.setResponseCode(404) + request.setHeader(b"Content-Type", b"text/plain") + return b'.well-known not available' + + logger.error("returning: %s", r) + request.setHeader(b"Content-Type", b"application/json") + return json.dumps(r).encode("utf-8") diff --git a/tests/rest/test_well_known.py b/tests/rest/test_well_known.py new file mode 100644 index 0000000000..8d8f03e005 --- /dev/null +++ b/tests/rest/test_well_known.py @@ -0,0 +1,58 @@ +# -*- coding: utf-8 -*- +# Copyright 2018 New Vector +# +# 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 synapse.rest.well_known import WellKnownResource + +from tests import unittest + + +class WellKnownTests(unittest.HomeserverTestCase): + def setUp(self): + super(WellKnownTests, self).setUp() + + # replace the JsonResource with a WellKnownResource + self.resource = WellKnownResource(self.hs) + + def test_well_known(self): + self.hs.config.public_baseurl = "https://tesths" + self.hs.config.default_identity_server = "https://testis" + + request, channel = self.make_request( + "GET", + "/.well-known/matrix/client", + shorthand=False, + ) + self.render(request) + + self.assertEqual(request.code, 200) + self.assertEqual( + channel.json_body, { + "m.homeserver": {"base_url": "https://tesths"}, + "m.identity_server": {"base_url": "https://testis"}, + } + ) + + def test_well_known_no_public_baseurl(self): + self.hs.config.public_baseurl = None + + request, channel = self.make_request( + "GET", + "/.well-known/matrix/client", + shorthand=False, + ) + self.render(request) + + self.assertEqual(request.code, 404)