def create_issuing_service(
    reactor: IReactorTCP,
    acme_url: str,
    account_key_file: str,
    well_known_resource: IResource,
) -> AcmeIssuingService:
    """Create an ACME issuing service, and attach it to a web Resource

    Args:
        reactor: twisted reactor
        acme_url: URL to use to request certificates
        account_key_file: where to store the account key
        well_known_resource: web resource for .well-known.
            we will attach a child resource for "acme-challenge".

    Returns:
        AcmeIssuingService
    """
    responder = HTTP01Responder()

    well_known_resource.putChild(b"acme-challenge", responder.resource)

    store = ErsatzStore()

    return AcmeIssuingService(
        cert_store=store,
        client_creator=(lambda: Client.from_url(
            reactor=reactor,
            url=URL.from_text(acme_url),
            key=load_or_create_client_key(account_key_file),
            alg=RS256,
        )),
        clock=reactor,
        responders=[responder],
    )
Example #2
0
 def test_adaptation(self):
     """
     Test that the Collection class can be adapted to an IResource.
     """
     collection = base.Collection()
     self.assertTrue(ICollection.providedBy(collection))
     self.assertTrue(IResource.providedBy(IResource(collection)))
Example #3
0
 def test_wrapResourceWeb(self):
     if not getTwistedWeb():
         raise SkipTest("This test requires both twisted.web.")
     from twisted.web.resource import IResource, Resource
     root = Resource()
     wrapped = wrapResource(root, [self.checker])
     self.assertTrue(IResource.providedBy(wrapped))
Example #4
0
    def getChild(self, path, request):
        """
        Gets the resource for an element in the collection for this resource.

        If this is a DELETE request addressing an element this collection,
        deletes the child.  If it is a PUT request addressing an element in
        this collection which does not exist yet, creates an element
        accessible at the request path.  Otherwise, attempts to return the
        resource for the appropriate addressed child, by accessing that child
        and attempting to adapt it to ``IResource``.

        If that child could not be found, (unless it is being created, of
        course), returns an error page signaling the missing element.

        The case for updating an element is not covered in this method: since
        updating is an operation on elements that already exist, that is
        handled by the corresponding ElementResource.
        """
        try:
            if request.method == "DELETE" and not request.postpath:
                self._collection.removeByIdentifier(path)
                return Deleted()

            return IResource(self._collection[path])
        except KeyError:
            if request.method == 'PUT' and not request.postpath:
                return self._createElement(request, identifier=path)

            return self._missingElement(request, path)
Example #5
0
def buildResourceTree(resources):

    if IResource.providedBy(resources):
        return resources

    logger.debug("build resorce tree...")
    if isinstance(resources, collections.Mapping):
        res_list = []
        _flatten_url_dict(res_list, resources, "")
    else:
        res_list = list(resources)
    res_list.sort()

    roots = [v for k, v in res_list if not k]
    assert len(roots) <= 1
    logger.debug("resource tree is %r", res_list)

    if roots:
        root, = roots
    else:
        root = _EmptyResource()
    res_list = sorted((k, v) for k, v in res_list if k)

    for fpath, res in res_list:
        logger.debug("path %r, resource %r", fpath, res)
        if fpath.startswith("/"):
            fpath = fpath[1:]
        else:
            raise AssertionError("expected leading '/'")
        _put_subresource(root, fpath.split("/"), res)

    return root
Example #6
0
    def __init__(self, element):
        Resource.__init__(self)

        self._element = element

        for childName in element.children:
            child = getattr(element, childName)
            self.putChild(childName, IResource(child))
Example #7
0
    def render_GET(self, request):
        """
        Create a custom or generic Login/Access to the Application.
        """
        file=FilePath('custom/unauthorized.py')
        if file.exists() and file.isfile() or file.islink():
            # Custom form is provided
            from custom.login import CustomLogin
            root=IResource(CustomLogin())
        else:
            from goliat.auth.login import Login
            from goliat.utils.config import ConfigManager
            root=IResource(Login(
                ConfigManager().get_config('Goliat')['Project']))

        request.setResponseCode(http.UNAUTHORIZED)
        return root.render(request)
Example #8
0
        def process(r):
            if IResource.providedBy(r):
                return request.render(getChildForRequest(r, request))

            if IRenderable.providedBy(r):
                return flattenString(request, r).addCallback(process)

            return r
Example #9
0
    def render_GET(self, request):
        """
        Create a custom or generic Login/Access to the Application.
        """
        file = FilePath('custom/unauthorized.py')
        if file.exists() and file.isfile() or file.islink():
            # Custom form is provided
            from custom.login import CustomLogin
            root = IResource(CustomLogin())
        else:
            from goliat.auth.login import Login
            from goliat.utils.config import ConfigManager
            root = IResource(
                Login(ConfigManager().get_config('Goliat')['Project']))

        request.setResponseCode(http.UNAUTHORIZED)
        return root.render(request)
Example #10
0
        def process(r):
            if IResource.providedBy(r):
                request.render(getChildForRequest(r, request))
                return _StandInResource

            if IRenderable.providedBy(r):
                return flattenString(request, r).addCallback(process)

            return r
Example #11
0
 def getChild(self, path, request):
     """override Resource"""
     # TODO: Either add a cache here or throw out the cache in BlockResource which this is defeating, depending on a performance comparison
     path = path.decode('utf-8')  # TODO centralize this 'urls are utf-8'
     if path in self.__cap_table:
         return IResource(self.__resource_factory(self.__cap_table[path]))
     else:
         # old-style-class super call
         return Resource.getChild(self, path, request)
Example #12
0
def static_resource(hierarchy):
    root = Resource()
    for k, v in hierarchy.iteritems():
        if IResource.providedBy(v):
            root.putChild(k, v)
        elif isinstance(v, dict):
            root.putChild(k, static_resource(v))
        else:
            raise NotImplementedError(v)
    return root
Example #13
0
def _flatten_url_dict(acc, d, prefix):
    if IResource.providedBy(d) or isinstance(d, basestring):
        acc.append((prefix, d))
    else:
        for k, v in dict(d).items():
            if k is None:
                pp = prefix
            else:
                pp = "%s/%s" % (prefix, k)
            _flatten_url_dict(acc, v, pp)
Example #14
0
def static_resource(hierarchy):
    root = Resource()
    for k, v in hierarchy.iteritems():
        if IResource.providedBy(v):
            root.putChild(k, v)
        elif isinstance(v, dict):
            root.putChild(k, static_resource(v))
        else:
            raise NotImplementedError(v)
    return root
Example #15
0
 def getChild(self, name, request):
     player = request.getSession()
     if name == 'play' and request.postpath and request.postpath[0]:
         game = IGameRoom(request.postpath[0])
         request.getSession().join(game)
         return IResource(game)
     elif name == 'register' and set(['name', 'password']).issubset(
             request.args):
         name = request.args['name'].pop()
         password = request.args['password'].pop()
         return RegisterResource(name, password)
     return self
Example #16
0
        def process(r):
            if IResource.providedBy(r):
                return request.render(getChildForRequest(r, request))

            if IRenderable.providedBy(r):
                return flattenString(request, r).addCallback(process)

            if isinstance(r, unicode):
                r = r.encode('utf-8')

            if r is not None:
                request.write(r)

            request.finish()
Example #17
0
        def process(r):
            if IResource.providedBy(r):
                return request.render(getChildForRequest(r, request))

            if IRenderable.providedBy(r):
                return flattenString(request, r).addCallback(process)

            if isinstance(r, unicode):
                r = r.encode('utf-8')

            if r is not None:
                request.write(r)

            request.finish()
Example #18
0
 def getChild(self, path, request):
     if path == '': path = 'index'
     path = path.replace(".", "_")
     cm = getattr(self, "wchild_" + path, None)
     if cm:
         p = cm(request)
         if isinstance(p, Deferred):
             return util.DeferredResource(p)
         adapter = IResource(p, None)
         if adapter is not None:
             return adapter
     # maybe we want direct support for ModelLoader?
     # cl = getattr(self, "wload_"+path, None) #???
     return Resource.getChild(self, path, request)
Example #19
0
    def _getRealResource(self, resource):
        proxied = False
        for b in resource.__class__.__bases__:
            if b.__name__ == '(Proxy for twisted.web.resource.IResource)':
                proxied = True

        if not proxied:
            return resource

        # find the real resource (or the next proxy)
        for x in vars(resource).values():
            if IResource.providedBy(x):
                return self._getRealResource(x)

        raise Exception("Unable to find real resource")
Example #20
0
    def _getRealResource(self, resource):
        proxied = False
        for b in resource.__class__.__bases__:
            if b.__name__ == '(Proxy for twisted.web.resource.IResource)':
                proxied = True

        if not proxied:
            return resource

        # find the real resource (or the next proxy)
        for x in vars(resource).values():
            if IResource.providedBy(x):
                return self._getRealResource(x)

        raise Exception("Unable to find real resource")
Example #21
0
        def process(r):
            """
            Recursively go through r and any child Resources until something
            returns an IRenderable, then render it and let the result of that
            bubble back up.
            """

            if IResource.providedBy(r):
                request.render(getChildForRequest(r, request))
                return _StandInResource

            if IRenderable.providedBy(r):
                return renderElement(request, r)

            return r
Example #22
0
    def test_service_with_region_internal(self):
        """
        Validate that an external service does not provide an internal service
        resource.
        """
        iapi = make_example_internal_api(self)
        helper = APIMockHelper(self, [iapi])
        core = helper.core

        service_id = None
        for a_service_id in core._uuid_to_api_internal:
            if core._uuid_to_api_internal[a_service_id] == iapi:
                service_id = a_service_id

        resource = core.service_with_region(u"ORD", service_id,
                                            u"http://some/random/prefix")
        self.assertTrue(IResource.providedBy(resource))
Example #23
0
        def process(r: object) -> Any:
            """
            Recursively go through r and any child Resources until something
            returns an IRenderable, then render it and let the result of that
            bubble back up.
            """
            if isinstance(r, Response):
                r = r._applyToRequest(request)

            if IResource.providedBy(r):
                request.render(getChildForRequest(r, request))
                return StandInResource

            if IRenderable.providedBy(r):
                renderElement(request, r)
                return StandInResource

            return r
Example #24
0
        def process(r):
            if IResource.providedBy(r):
                while (request.postpath and
                       request.postpath != request._klein_postpath_):
                    request.prepath.append(request.postpath.pop(0))

                return request.render(getChildForRequest(r, request))

            if IRenderable.providedBy(r):
                return flattenString(request, r).addCallback(process)

            if isinstance(r, unicode):
                r = r.encode('utf-8')

            if r is not None:
                request.write(r)

            request.finish()
Example #25
0
def create_factory(authnz, git_configuration, git_viewer=None):
    if git_viewer is None:
        git_viewer = NoResource()
    elif not IResource.providedBy(git_viewer):
        raise ValueError("git_viewer should implement IResource")

    credentialFactories = [BasicCredentialFactory('Git Repositories')]
    gitportal = Portal(GitHTTPRealm(authnz, git_configuration,
                                    credentialFactories, git_viewer))

    if hasattr(authnz, 'check_password'):
        log.msg("Registering PasswordChecker")
        gitportal.registerChecker(PasswordChecker(authnz.check_password))
    gitportal.registerChecker(AllowAnonymousAccess())

    resource = HTTPAuthSessionWrapper(gitportal, credentialFactories)
    site = Site(resource)

    return site
Example #26
0
def create_factory(authnz, git_configuration, git_viewer=None):
    if git_viewer is None:
        git_viewer = NoResource()
    elif not IResource.providedBy(git_viewer):
        raise ValueError("git_viewer should implement IResource")

    credentialFactories = [BasicCredentialFactory('Git Repositories')]
    gitportal = Portal(
        GitHTTPRealm(authnz, git_configuration, credentialFactories,
                     git_viewer))

    if hasattr(authnz, 'check_password'):
        log.msg("Registering PasswordChecker")
        gitportal.registerChecker(PasswordChecker(authnz.check_password))
    gitportal.registerChecker(AllowAnonymousAccess())

    resource = HTTPAuthSessionWrapper(gitportal, credentialFactories)
    site = Site(resource)

    return site
Example #27
0
    def test_service_with_region_internal(self):
        """
        Validate that an external service does not provide an internal service
        resource.
        """
        iapi = make_example_internal_api(self)
        helper = APIMockHelper(self, [iapi])
        core = helper.core

        service_id = None
        for a_service_id in core._uuid_to_api_internal:
            if core._uuid_to_api_internal[a_service_id] == iapi:
                service_id = a_service_id

        resource = core.service_with_region(
            u"ORD",
            service_id,
            u"http://some/random/prefix"
        )
        self.assertTrue(
            IResource.providedBy(resource)
        )
Example #28
0
 def test_wrapResourceWeb(self):
     from twisted.web.resource import IResource, Resource
     root = Resource()
     wrapped = wrapResource(root, [self.checker])
     self.assertTrue(IResource.providedBy(wrapped))
Example #29
0
    def _listener_http(self, config: HomeServerConfig,
                       listener_config: ListenerConfig):
        port = listener_config.port
        bind_addresses = listener_config.bind_addresses
        tls = listener_config.tls
        site_tag = listener_config.http_options.tag
        if site_tag is None:
            site_tag = str(port)

        # We always include a health resource.
        resources = {"/health": HealthResource()}

        for res in listener_config.http_options.resources:
            for name in res.names:
                if name == "openid" and "federation" in res.names:
                    # Skip loading openid resource if federation is defined
                    # since federation resource will include openid
                    continue
                resources.update(
                    self._configure_named_resource(name, res.compress))

        additional_resources = listener_config.http_options.additional_resources
        logger.debug("Configuring additional resources: %r",
                     additional_resources)
        module_api = self.get_module_api()
        for path, resmodule in additional_resources.items():
            handler_cls, config = load_module(
                resmodule,
                ("listeners", site_tag, "additional_resources", "<%s>" %
                 (path, )),
            )
            handler = handler_cls(config, module_api)
            if IResource.providedBy(handler):
                resource = handler
            elif hasattr(handler, "handle_request"):
                resource = AdditionalResource(self, handler.handle_request)
            else:
                raise ConfigError(
                    "additional_resource %s does not implement a known interface"
                    % (resmodule["module"], ))
            resources[path] = resource

        # try to find something useful to redirect '/' to
        if WEB_CLIENT_PREFIX in resources:
            root_resource = RootOptionsRedirectResource(WEB_CLIENT_PREFIX)
        elif STATIC_PREFIX in resources:
            root_resource = RootOptionsRedirectResource(STATIC_PREFIX)
        else:
            root_resource = OptionsResource()

        root_resource = create_resource_tree(resources, root_resource)

        if tls:
            ports = listen_ssl(
                bind_addresses,
                port,
                SynapseSite(
                    "synapse.access.https.%s" % (site_tag, ),
                    site_tag,
                    listener_config,
                    root_resource,
                    self.version_string,
                ),
                self.tls_server_context_factory,
                reactor=self.get_reactor(),
            )
            logger.info("Synapse now listening on TCP port %d (TLS)", port)

        else:
            ports = listen_tcp(
                bind_addresses,
                port,
                SynapseSite(
                    "synapse.access.http.%s" % (site_tag, ),
                    site_tag,
                    listener_config,
                    root_resource,
                    self.version_string,
                ),
                reactor=self.get_reactor(),
            )
            logger.info("Synapse now listening on TCP port %d", port)

        return ports
Example #30
0
 def test_resource_smoke(self):
     IResource(self.session.get_entry_point_resource(
         wcommon=WebServiceCommon.stub(reactor=the_reactor)))
Example #31
0
 def setUp(self):
     self.collection = self.collectionClass()
     self.resource = IResource(self.collection)
Example #32
0
class _BaseCollectionTest(object):
    """
    A base class for tests of a collection.
    """
    def setUp(self):
        self.collection = self.collectionClass()
        self.resource = IResource(self.collection)


    def addElements(self, elements=None):
        """
        Adds some element to the collection.

        If no elements are specified, create the default elements specified by
        the elementClass and elementArgs class attributes.
        """
        if elements is None:
            elements = [self.elementClass(*a) for a in self.elementArgs]

        for e in elements:
            self.collection.add(e)


    def _makeRequest(self, resource, request):
        """
        Makes a request to a particular resource.
        """
        self.request = request
        self.response = resource.render(request)


    def _decodeResponse(self):
        """
        Tries to decode the body of a response.
        """
        self.responseContent = json.loads(self.response)


    def _checkContentType(self, expectedContentType="application/json"):
        """
        Verifies the content type of a response.

        If the type is ``None``, verifies that the header is not passed. This
        is intended for cases where an empty response body is expected.
        """
        headers = self.request.responseHeaders.getRawHeaders("Content-Type")

        if expectedContentType is None:
            self.assertEqual(headers, None)
        else:
            self.assertEqual(headers, [expectedContentType])


    def _checkBadRequest(self, expectedCode):
        """
        Tests that a failed request has a particular response code, and that
        the response content has an error message and some details in it.
        """
        self.assertEqual(self.request.code, expectedCode)
        self.assertIn("errorMessage", self.responseContent)
        self.assertIn("errorDetails", self.responseContent)


    def _getResource(self, args=None, headers=None, path=()):
        """
        Generalized GET for a particular resource.
        """
        request = _FakeRequest(args=args, requestHeaders=headers)

        resource = self.resource
        for childName in path:
            resource = resource.getChildWithDefault(childName, request)

        self._makeRequest(resource, request)
        self._checkContentType()
        self._decodeResponse()


    def getElements(self, args=None, headers=None):
        """
        Gets a bunch of elements from a collection.
        """
        self._getResource(args, headers)


    def getElement(self, element, args=None, headers=None):
        """
        Gets a particular element from a collection.
        """
        self._getResource(args, headers, [element])


    def getElementChild(self, element, child, args=None, headers=None):
        """
        Gets a child of a particular element from a collection.
        """
        self._getResource(args, headers, [element, child])


    def updateElement(self, name, body, headers=None):
        """
        Update an element.

        For a successful update, the headers should contain a Content-Type.
        """
        request = _FakePUTRequest(body=body, requestHeaders=headers)
        elementResource = self.resource.getChild(name, request)
        self._makeRequest(elementResource, request)


    def deleteElement(self, name):
        """
        Delete an element.
        """
        request = _FakeDELETERequest()
        elementResource = self.resource.getChild(name, request)
        self._makeRequest(elementResource, request)


    def createElement(self, name, body, headers=None, method="PUT"):
        """
        Create a new element.
        """
        if method == "PUT":
            self.updateElement(name, body, headers)
        elif method == "POST":
            request = _FakePOSTRequest(body=body, requestHeaders=headers)
            self._makeRequest(self.resource, request)
Example #33
0
def _finish(result, render, request):
    """
    Try to finish rendering the response to a request.

    This implements extra convenience functionality not provided by Twisted
    Web.  Various resources in Tahoe-LAFS made use of this functionality when
    it was provided by Nevow.  Rather than making that application code do the
    more tedious thing itself, we duplicate the functionality here.

    :param result: Something returned by a render method which we can turn
        into a response.

    :param render: The original render method which produced the result.

    :param request: The request being responded to.

    :return: ``None``
    """
    if isinstance(result, Failure):
        if result.check(CancelledError):
            return
        Message.log(
            message_type=u"allmydata:web:common-render:failure",
            message=result.getErrorMessage(),
        )
        _finish(
            _renderHTTP_exception(request, result),
            render,
            request,
        )
    elif IResource.providedBy(result):
        # If result is also using @render_exception then we don't want to
        # double-apply the logic.  This leads to an attempt to double-finish
        # the request.  If it isn't using @render_exception then you should
        # fix it so it is.
        Message.log(
            message_type=u"allmydata:web:common-render:resource",
            resource=fullyQualifiedName(type(result)),
        )
        result.render(request)
    elif isinstance(result, str):
        Message.log(message_type=u"allmydata:web:common-render:unicode", )
        request.write(result.encode("utf-8"))
        request.finish()
    elif isinstance(result, bytes):
        Message.log(message_type=u"allmydata:web:common-render:bytes", )
        request.write(result)
        request.finish()
    elif isinstance(result, DecodedURL):
        Message.log(message_type=u"allmydata:web:common-render:DecodedURL", )
        _finish(redirectTo(result.to_text().encode("utf-8"), request), render,
                request)
    elif result is None:
        Message.log(message_type=u"allmydata:web:common-render:None", )
        request.finish()
    elif result == NOT_DONE_YET:
        Message.log(message_type=u"allmydata:web:common-render:NOT_DONE_YET", )
        pass
    else:
        Message.log(message_type=u"allmydata:web:common-render:unknown", )
        log.err(
            "Request for {!r} handled by {!r} returned unusable {!r}".format(
                request.uri,
                fullyQualifiedName(render),
                result,
            ))
        request.setResponseCode(http.INTERNAL_SERVER_ERROR)
        _finish(b"Internal Server Error", render, request)
Example #34
0
 def __init__(self, server):
     Adapter.__init__(self, server)
     Site.__init__(self, IResource(self))
     reactor.callWhenRunning(self.startListening)
Example #35
0
class _BaseCollectionTest(object):
    """
    A base class for tests of a collection.
    """
    def setUp(self):
        self.collection = self.collectionClass()
        self.resource = IResource(self.collection)

    def addElements(self, elements=None):
        """
        Adds some element to the collection.

        If no elements are specified, create the default elements specified by
        the elementClass and elementArgs class attributes.
        """
        if elements is None:
            elements = [self.elementClass(*a) for a in self.elementArgs]

        for e in elements:
            self.collection.add(e)

    def _makeRequest(self, resource, request):
        """
        Makes a request to a particular resource.
        """
        self.request = request
        self.response = resource.render(request)

    def _decodeResponse(self):
        """
        Tries to decode the body of a response.
        """
        self.responseContent = json.loads(self.response)

    def _checkContentType(self, expectedContentType="application/json"):
        """
        Verifies the content type of a response.

        If the type is ``None``, verifies that the header is not passed. This
        is intended for cases where an empty response body is expected.
        """
        headers = self.request.responseHeaders.getRawHeaders("Content-Type")

        if expectedContentType is None:
            self.assertEqual(headers, None)
        else:
            self.assertEqual(headers, [expectedContentType])

    def _checkBadRequest(self, expectedCode):
        """
        Tests that a failed request has a particular response code, and that
        the response content has an error message and some details in it.
        """
        self.assertEqual(self.request.code, expectedCode)
        self.assertIn("errorMessage", self.responseContent)
        self.assertIn("errorDetails", self.responseContent)

    def _getResource(self, args=None, headers=None, path=()):
        """
        Generalized GET for a particular resource.
        """
        request = _FakeRequest(args=args, requestHeaders=headers)

        resource = self.resource
        for childName in path:
            resource = resource.getChildWithDefault(childName, request)

        self._makeRequest(resource, request)
        self._checkContentType()
        self._decodeResponse()

    def getElements(self, args=None, headers=None):
        """
        Gets a bunch of elements from a collection.
        """
        self._getResource(args, headers)

    def getElement(self, element, args=None, headers=None):
        """
        Gets a particular element from a collection.
        """
        self._getResource(args, headers, [element])

    def getElementChild(self, element, child, args=None, headers=None):
        """
        Gets a child of a particular element from a collection.
        """
        self._getResource(args, headers, [element, child])

    def updateElement(self, name, body, headers=None):
        """
        Update an element.

        For a successful update, the headers should contain a Content-Type.
        """
        request = _FakePUTRequest(body=body, requestHeaders=headers)
        elementResource = self.resource.getChild(name, request)
        self._makeRequest(elementResource, request)

    def deleteElement(self, name):
        """
        Delete an element.
        """
        request = _FakeDELETERequest()
        elementResource = self.resource.getChild(name, request)
        self._makeRequest(elementResource, request)

    def createElement(self, name, body, headers=None, method="PUT"):
        """
        Create a new element.
        """
        if method == "PUT":
            self.updateElement(name, body, headers)
        elif method == "POST":
            request = _FakePOSTRequest(body=body, requestHeaders=headers)
            self._makeRequest(self.resource, request)
Example #36
0
 def test_wrapResourceWeb(self):
     from twisted.web.resource import IResource, Resource
     root = Resource()
     wrapped = wrapResource(root, [self.checker])
     self.assertTrue(IResource.providedBy(wrapped))
Example #37
0
 def setUp(self):
     self.collection = self.collectionClass()
     self.resource = IResource(self.collection)
Example #38
0
    def _listener_http(self, config, listener_config):
        port = listener_config["port"]
        bind_addresses = listener_config["bind_addresses"]
        tls = listener_config.get("tls", False)
        site_tag = listener_config.get("tag", port)

        resources = {}
        for res in listener_config["resources"]:
            for name in res["names"]:
                if name == "openid" and "federation" in res["names"]:
                    # Skip loading openid resource if federation is defined
                    # since federation resource will include openid
                    continue
                resources.update(
                    self._configure_named_resource(name, res.get("compress", False))
                )

        additional_resources = listener_config.get("additional_resources", {})
        logger.debug("Configuring additional resources: %r", additional_resources)
        module_api = ModuleApi(self, self.get_auth_handler())
        for path, resmodule in additional_resources.items():
            handler_cls, config = load_module(resmodule)
            handler = handler_cls(config, module_api)
            if IResource.providedBy(handler):
                resource = handler
            elif hasattr(handler, "handle_request"):
                resource = AdditionalResource(self, handler.handle_request)
            else:
                raise ConfigError(
                    "additional_resource %s does not implement a known interface"
                    % (resmodule["module"],)
                )
            resources[path] = resource

        # try to find something useful to redirect '/' to
        if WEB_CLIENT_PREFIX in resources:
            root_resource = RootOptionsRedirectResource(WEB_CLIENT_PREFIX)
        elif STATIC_PREFIX in resources:
            root_resource = RootOptionsRedirectResource(STATIC_PREFIX)
        else:
            root_resource = OptionsResource()

        root_resource = create_resource_tree(resources, root_resource)

        if tls:
            ports = listen_ssl(
                bind_addresses,
                port,
                SynapseSite(
                    "synapse.access.https.%s" % (site_tag,),
                    site_tag,
                    listener_config,
                    root_resource,
                    self.version_string,
                ),
                self.tls_server_context_factory,
                reactor=self.get_reactor(),
            )
            logger.info("Synapse now listening on TCP port %d (TLS)", port)

        else:
            ports = listen_tcp(
                bind_addresses,
                port,
                SynapseSite(
                    "synapse.access.http.%s" % (site_tag,),
                    site_tag,
                    listener_config,
                    root_resource,
                    self.version_string,
                ),
                reactor=self.get_reactor(),
            )
            logger.info("Synapse now listening on TCP port %d", port)

        return ports