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)
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
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
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
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
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)