예제 #1
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)

        if tls and config.no_tls:
            return

        resources = {}
        for res in listener_config["resources"]:
            for name in res["names"]:
                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)
            resources[path] = AdditionalResource(self, handler.handle_request)

        if WEB_CLIENT_PREFIX in resources:
            root_resource = RootRedirect(WEB_CLIENT_PREFIX)
        else:
            root_resource = NoResource()

        root_resource = create_resource_tree(resources, root_resource)

        if tls:
            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,
            )

        else:
            listen_tcp(
                bind_addresses, port,
                SynapseSite(
                    "synapse.access.http.%s" % (site_tag, ),
                    site_tag,
                    listener_config,
                    root_resource,
                    self.version_string,
                ))
        logger.info("Synapse now listening on port %d", port)
예제 #2
0
    def _configure_named_resource(self, name, compress=False):
        """Build a resource map for a named resource

        Args:
            name (str): named resource: one of "client", "federation", etc
            compress (bool): whether to enable gzip compression for this
                resource

        Returns:
            dict[str, Resource]: map from path to HTTP resource
        """
        resources = {}
        if name == "client":
            client_resource = ClientRestResource(self)
            if compress:
                client_resource = gz_wrap(client_resource)

            resources.update({
                "/_matrix/client/api/v1":
                client_resource,
                "/_matrix/client/r0":
                client_resource,
                "/_matrix/client/unstable":
                client_resource,
                "/_matrix/client/v2_alpha":
                client_resource,
                "/_matrix/client/versions":
                client_resource,
                "/.well-known/matrix/client":
                WellKnownResource(self),
                "/_synapse/admin":
                AdminRestResource(self),
                "/_synapse/client/pick_username":
                pick_username_resource(self),
                "/_synapse/client/pick_idp":
                PickIdpResource(self),
            })

            if self.get_config().oidc_enabled:
                from synapse.rest.oidc import OIDCResource

                resources["/_synapse/oidc"] = OIDCResource(self)

            if self.get_config().saml2_enabled:
                from synapse.rest.saml2 import SAML2Resource

                resources["/_matrix/saml2"] = SAML2Resource(self)

            if self.get_config(
            ).threepid_behaviour_email == ThreepidBehaviour.LOCAL:
                from synapse.rest.synapse.client.password_reset import (
                    PasswordResetSubmitTokenResource, )

                resources[
                    "/_synapse/client/password_reset/email/submit_token"] = PasswordResetSubmitTokenResource(
                        self)

        if name == "consent":
            from synapse.rest.consent.consent_resource import ConsentResource

            consent_resource = ConsentResource(self)
            if compress:
                consent_resource = gz_wrap(consent_resource)
            resources.update({"/_matrix/consent": consent_resource})

        if name == "federation":
            resources.update({FEDERATION_PREFIX: TransportLayerServer(self)})

        if name == "openid":
            resources.update({
                FEDERATION_PREFIX:
                TransportLayerServer(self, servlet_groups=["openid"])
            })

        if name in ["static", "client"]:
            resources.update({
                STATIC_PREFIX:
                StaticResource(
                    os.path.join(os.path.dirname(synapse.__file__), "static"))
            })

        if name in ["media", "federation", "client"]:
            if self.get_config().enable_media_repo:
                media_repo = self.get_media_repository_resource()
                resources.update({
                    MEDIA_PREFIX: media_repo,
                    LEGACY_MEDIA_PREFIX: media_repo
                })
            elif name == "media":
                raise ConfigError(
                    "'media' resource conflicts with enable_media_repo=False")

        if name in ["keys", "federation"]:
            resources[SERVER_KEY_V2_PREFIX] = KeyApiV2Resource(self)

        if name == "webclient":
            webclient_loc = self.get_config().web_client_location

            if webclient_loc is None:
                logger.warning(
                    "Not enabling webclient resource, as web_client_location is unset."
                )
            elif webclient_loc.startswith(
                    "http://") or webclient_loc.startswith("https://"):
                resources[WEB_CLIENT_PREFIX] = RootRedirect(webclient_loc)
            else:
                logger.warning(
                    "Running webclient on the same domain is not recommended: "
                    "https://github.com/matrix-org/synapse#security-note - "
                    "after you move webclient to different host you can set "
                    "web_client_location to its full URL to enable redirection."
                )
                # GZip is disabled here due to
                # https://twistedmatrix.com/trac/ticket/7678
                resources[WEB_CLIENT_PREFIX] = File(webclient_loc)

        if name == "metrics" and self.get_config().enable_metrics:
            resources[METRICS_PREFIX] = MetricsResource(RegistryProxy)

        if name == "replication":
            resources[REPLICATION_PREFIX] = ReplicationRestResource(self)

        return resources
예제 #3
0
def create_resource_tree(desired_tree, redirect_root_to_web_client=True):
    """Create the resource tree for this Home Server.

    This in unduly complicated because Twisted does not support putting
    child resources more than 1 level deep at a time.

    Args:
        web_client (bool): True to enable the web client.
        redirect_root_to_web_client (bool): True to redirect '/' to the
        location of the web client. This does nothing if web_client is not
        True.
    """
    if redirect_root_to_web_client and WEB_CLIENT_PREFIX in desired_tree:
        root_resource = RootRedirect(WEB_CLIENT_PREFIX)
    else:
        root_resource = Resource()

    # ideally we'd just use getChild and putChild but getChild doesn't work
    # unless you give it a Request object IN ADDITION to the name :/ So
    # instead, we'll store a copy of this mapping so we can actually add
    # extra resources to existing nodes. See self._resource_id for the key.
    resource_mappings = {}
    for full_path, res in desired_tree.items():
        logger.info("Attaching %s to path %s", res, full_path)
        last_resource = root_resource
        for path_seg in full_path.split('/')[1:-1]:
            if path_seg not in last_resource.listNames():
                # resource doesn't exist, so make a "dummy resource"
                child_resource = Resource()
                last_resource.putChild(path_seg, child_resource)
                res_id = _resource_id(last_resource, path_seg)
                resource_mappings[res_id] = child_resource
                last_resource = child_resource
            else:
                # we have an existing Resource, use that instead.
                res_id = _resource_id(last_resource, path_seg)
                last_resource = resource_mappings[res_id]

        # ===========================
        # now attach the actual desired resource
        last_path_seg = full_path.split('/')[-1]

        # if there is already a resource here, thieve its children and
        # replace it
        res_id = _resource_id(last_resource, last_path_seg)
        if res_id in resource_mappings:
            # there is a dummy resource at this path already, which needs
            # to be replaced with the desired resource.
            existing_dummy_resource = resource_mappings[res_id]
            for child_name in existing_dummy_resource.listNames():
                child_res_id = _resource_id(existing_dummy_resource,
                                            child_name)
                child_resource = resource_mappings[child_res_id]
                # steal the children
                res.putChild(child_name, child_resource)

        # finally, insert the desired resource in the right place
        last_resource.putChild(last_path_seg, res)
        res_id = _resource_id(last_resource, last_path_seg)
        resource_mappings[res_id] = res

    return root_resource
예제 #4
0
    def create_resource_tree(self, redirect_root_to_web_client):
        """Create the resource tree for this Home Server.

        This in unduly complicated because Twisted does not support putting
        child resources more than 1 level deep at a time.

        Args:
            web_client (bool): True to enable the web client.
            redirect_root_to_web_client (bool): True to redirect '/' to the
            location of the web client. This does nothing if web_client is not
            True.
        """
        config = self.get_config()
        web_client = config.web_client

        # list containing (path_str, Resource) e.g:
        # [ ("/aaa/bbb/cc", Resource1), ("/aaa/dummy", Resource2) ]
        desired_tree = [
            (CLIENT_PREFIX, self.get_resource_for_client()),
            (CLIENT_V2_ALPHA_PREFIX, self.get_resource_for_client_v2_alpha()),
            (FEDERATION_PREFIX, self.get_resource_for_federation()),
            (CONTENT_REPO_PREFIX, self.get_resource_for_content_repo()),
            (SERVER_KEY_PREFIX, self.get_resource_for_server_key()),
            (SERVER_KEY_V2_PREFIX, self.get_resource_for_server_key_v2()),
            (MEDIA_PREFIX, self.get_resource_for_media_repository()),
            (STATIC_PREFIX, self.get_resource_for_static_content()),
        ]

        if web_client:
            logger.info("Adding the web client.")
            desired_tree.append((WEB_CLIENT_PREFIX,
                                self.get_resource_for_web_client()))

        if web_client and redirect_root_to_web_client:
            self.root_resource = RootRedirect(WEB_CLIENT_PREFIX)
        else:
            self.root_resource = Resource()

        metrics_resource = self.get_resource_for_metrics()
        if config.metrics_port is None and metrics_resource is not None:
            desired_tree.append((METRICS_PREFIX, metrics_resource))

        # ideally we'd just use getChild and putChild but getChild doesn't work
        # unless you give it a Request object IN ADDITION to the name :/ So
        # instead, we'll store a copy of this mapping so we can actually add
        # extra resources to existing nodes. See self._resource_id for the key.
        resource_mappings = {}
        for full_path, res in desired_tree:
            logger.info("Attaching %s to path %s", res, full_path)
            last_resource = self.root_resource
            for path_seg in full_path.split('/')[1:-1]:
                if path_seg not in last_resource.listNames():
                    # resource doesn't exist, so make a "dummy resource"
                    child_resource = Resource()
                    last_resource.putChild(path_seg, child_resource)
                    res_id = self._resource_id(last_resource, path_seg)
                    resource_mappings[res_id] = child_resource
                    last_resource = child_resource
                else:
                    # we have an existing Resource, use that instead.
                    res_id = self._resource_id(last_resource, path_seg)
                    last_resource = resource_mappings[res_id]

            # ===========================
            # now attach the actual desired resource
            last_path_seg = full_path.split('/')[-1]

            # if there is already a resource here, thieve its children and
            # replace it
            res_id = self._resource_id(last_resource, last_path_seg)
            if res_id in resource_mappings:
                # there is a dummy resource at this path already, which needs
                # to be replaced with the desired resource.
                existing_dummy_resource = resource_mappings[res_id]
                for child_name in existing_dummy_resource.listNames():
                    child_res_id = self._resource_id(existing_dummy_resource,
                                                     child_name)
                    child_resource = resource_mappings[child_res_id]
                    # steal the children
                    res.putChild(child_name, child_resource)

            # finally, insert the desired resource in the right place
            last_resource.putChild(last_path_seg, res)
            res_id = self._resource_id(last_resource, last_path_seg)
            resource_mappings[res_id] = res

        return self.root_resource
예제 #5
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)
            resources[path] = AdditionalResource(self, handler.handle_request)

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

        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
예제 #6
0
    def _listener_http(self, config, listener_config):
        port = listener_config["port"]
        bind_address = listener_config.get("bind_address", "")
        tls = listener_config.get("tls", False)
        site_tag = listener_config.get("tag", port)

        if tls and config.no_tls:
            return

        resources = {}
        for res in listener_config["resources"]:
            for name in res["names"]:
                if name == "client":
                    client_resource = ClientRestResource(self)
                    if res["compress"]:
                        client_resource = gz_wrap(client_resource)

                    resources.update({
                        "/_matrix/client/api/v1":
                        client_resource,
                        "/_matrix/client/r0":
                        client_resource,
                        "/_matrix/client/unstable":
                        client_resource,
                        "/_matrix/client/v2_alpha":
                        client_resource,
                        "/_matrix/client/versions":
                        client_resource,
                    })

                if name == "federation":
                    resources.update({
                        FEDERATION_PREFIX:
                        TransportLayerServer(self),
                    })

                if name in ["static", "client"]:
                    resources.update({
                        STATIC_PREFIX:
                        File(
                            os.path.join(os.path.dirname(synapse.__file__),
                                         "static")),
                    })

                if name in ["media", "federation", "client"]:
                    media_repo = MediaRepositoryResource(self)
                    resources.update({
                        MEDIA_PREFIX:
                        media_repo,
                        LEGACY_MEDIA_PREFIX:
                        media_repo,
                        CONTENT_REPO_PREFIX:
                        ContentRepoResource(self, self.config.uploads_path,
                                            self.auth, self.content_addr),
                    })

                if name in ["keys", "federation"]:
                    resources.update({
                        SERVER_KEY_PREFIX:
                        LocalKey(self),
                        SERVER_KEY_V2_PREFIX:
                        KeyApiV2Resource(self),
                    })

                if name == "webclient":
                    resources[
                        WEB_CLIENT_PREFIX] = build_resource_for_web_client(
                            self)

                if name == "metrics" and self.get_config().enable_metrics:
                    resources[METRICS_PREFIX] = MetricsResource(self)

                if name == "replication":
                    resources[REPLICATION_PREFIX] = ReplicationResource(self)

        if WEB_CLIENT_PREFIX in resources:
            root_resource = RootRedirect(WEB_CLIENT_PREFIX)
        else:
            root_resource = Resource()

        root_resource = create_resource_tree(resources, root_resource)
        if tls:
            reactor.listenSSL(port,
                              SynapseSite(
                                  "synapse.access.https.%s" % (site_tag, ),
                                  site_tag,
                                  listener_config,
                                  root_resource,
                              ),
                              self.tls_server_context_factory,
                              interface=bind_address)
        else:
            reactor.listenTCP(port,
                              SynapseSite(
                                  "synapse.access.http.%s" % (site_tag, ),
                                  site_tag,
                                  listener_config,
                                  root_resource,
                              ),
                              interface=bind_address)
        logger.info("Synapse now listening on port %d", port)