def parse_config(config: dict) -> JinjaOidcMappingConfig: subject_claim = config.get("subject_claim", "sub") if "localpart_template" not in config: raise ConfigError( "missing key: oidc_config.user_mapping_provider.config.localpart_template" ) try: localpart_template = env.from_string(config["localpart_template"]) except Exception as e: raise ConfigError( "invalid jinja template for oidc_config.user_mapping_provider.config.localpart_template: %r" % (e,) ) display_name_template = None # type: Optional[Template] if "display_name_template" in config: try: display_name_template = env.from_string(config["display_name_template"]) except Exception as e: raise ConfigError( "invalid jinja template for oidc_config.user_mapping_provider.config.display_name_template: %r" % (e,) ) return JinjaOidcMappingConfig( subject_claim=subject_claim, localpart_template=localpart_template, display_name_template=display_name_template, )
def __init__(self, hs: "HomeServer"): super().__init__() self.hs = hs self.store = hs.get_datastores().main self.registration_handler = hs.get_registration_handler() # this is required by the request_handler wrapper self.clock = hs.get_clock() # Consent must be configured to create this resource. default_consent_version = hs.config.consent.user_consent_version consent_template_directory = hs.config.consent.user_consent_template_dir if default_consent_version is None or consent_template_directory is None: raise ConfigError( "Consent resource is enabled but user_consent section is " "missing in config file." ) self._default_consent_version = default_consent_version # TODO: switch to synapse.util.templates.build_jinja_env loader = jinja2.FileSystemLoader(consent_template_directory) self._jinja_env = jinja2.Environment( loader=loader, autoescape=jinja2.select_autoescape(["html", "htm", "xml"]) ) if hs.config.key.form_secret is None: raise ConfigError( "Consent resource is enabled but form_secret is not set in " "config file. It should be set to an arbitrary secret string." ) self._hmac_secret = hs.config.key.form_secret.encode("utf-8")
def read_config(self, config: JsonDict, **kwargs: Any) -> None: self.spam_checkers: List[Tuple[Any, Dict]] = [] spam_checkers = config.get("spam_checker") or [] if isinstance(spam_checkers, dict): # The spam_checker config option used to only support one # spam checker, and thus was simply a dictionary with module # and config keys. Support this old behaviour by checking # to see if the option resolves to a dictionary self.spam_checkers.append( load_module(spam_checkers, ("spam_checker", ))) elif isinstance(spam_checkers, list): for i, spam_checker in enumerate(spam_checkers): config_path = ("spam_checker", "<item %i>" % i) if not isinstance(spam_checker, dict): raise ConfigError("expected a mapping", config_path) self.spam_checkers.append( load_module(spam_checker, config_path)) else: raise ConfigError("spam_checker syntax is incorrect") # If this configuration is being used in any way, warn the admin that it is going # away soon. if self.spam_checkers: logger.warning(LEGACY_SPAM_CHECKER_WARNING)
def parse_config(config_dict: dict) -> PFSPresenceRouterConfig: """Parse a configuration dictionary from the homeserver config, do some validation and return a typed PFSPresenceRouterConfig. Args: config_dict: The configuration dictionary. Returns: A validated config object. """ try: blockchain_sync = int(config_dict.get("blockchain_sync_seconds", "15")) except ValueError: raise ConfigError("`blockchain_sync_seconds` needs to be an integer") try: service_registry_address = to_canonical_address( to_checksum_address(config_dict.get("service_registry_address")) # type: ignore ) except (TypeError, ValueError): raise ConfigError("`service_registry_address` is not a valid address or missing") try: ethereum_rpc = config_dict.get("ethereum_rpc") parsed_ethereum_rpc = urlparse(ethereum_rpc) if not all([parsed_ethereum_rpc.scheme, parsed_ethereum_rpc.netloc]): raise ValueError() except ValueError: raise ConfigError("`ethereum_rpc` is not properly configured") return PFSPresenceRouterConfig( service_registry_address, ethereum_rpc, blockchain_sync # type: ignore )
def __init__(self, hs): """ Args: hs (synapse.server.HomeServer): """ self._server_notices_manager = hs.get_server_notices_manager() self._store = hs.get_datastore() self._users_in_progress = set() self._current_consent_version = hs.config.user_consent_version self._server_notice_content = hs.config.user_consent_server_notice_content self._send_to_guests = hs.config.user_consent_server_notice_to_guests if self._server_notice_content is not None: if not self._server_notices_manager.is_enabled(): raise ConfigError( "user_consent configuration requires server notices, but " "server notices are not enabled." ) if "body" not in self._server_notice_content: raise ConfigError( "user_consent server_notice_consent must contain a 'body' key." ) self._consent_uri_builder = ConsentURIBuilder(hs.config)
def __init__(self, hs): """ Args: hs (synapse.server.HomeServer): homeserver """ Resource.__init__(self) self.hs = hs self.store = hs.get_datastore() self.registration_handler = hs.get_registration_handler() # this is required by the request_handler wrapper self.clock = hs.get_clock() self._default_consent_version = hs.config.user_consent_version if self._default_consent_version is None: raise ConfigError( "Consent resource is enabled but user_consent section is " "missing in config file.", ) consent_template_directory = hs.config.user_consent_template_dir loader = jinja2.FileSystemLoader(consent_template_directory) self._jinja_env = jinja2.Environment( loader=loader, autoescape=jinja2.select_autoescape(['html', 'htm', 'xml']), ) if hs.config.form_secret is None: raise ConfigError( "Consent resource is enabled but form_secret is not set in " "config file. It should be set to an arbitrary secret string.", ) self._hmac_secret = hs.config.form_secret.encode("utf-8")
def __init__(self, hs_config): """ Args: hs_config (synapse.config.homeserver.HomeServerConfig): """ if hs_config.form_secret is None: raise ConfigError("form_secret not set in config") if hs_config.public_baseurl is None: raise ConfigError("public_baseurl not set in config") self._hmac_secret = hs_config.form_secret.encode("utf-8") self._public_baseurl = hs_config.public_baseurl
def parse_config(config: dict) -> JinjaOidcMappingConfig: subject_claim = config.get("subject_claim", "sub") if "localpart_template" not in config: raise ConfigError( "missing key: oidc_config.user_mapping_provider.config.localpart_template" ) try: localpart_template = env.from_string(config["localpart_template"]) except Exception as e: raise ConfigError( "invalid jinja template for oidc_config.user_mapping_provider.config.localpart_template: %r" % (e,) ) display_name_template = None # type: Optional[Template] if "display_name_template" in config: try: display_name_template = env.from_string(config["display_name_template"]) except Exception as e: raise ConfigError( "invalid jinja template for oidc_config.user_mapping_provider.config.display_name_template: %r" % (e,) ) extra_attributes = {} # type Dict[str, Template] if "extra_attributes" in config: extra_attributes_config = config.get("extra_attributes") or {} if not isinstance(extra_attributes_config, dict): raise ConfigError( "oidc_config.user_mapping_provider.config.extra_attributes must be a dict" ) for key, value in extra_attributes_config.items(): try: extra_attributes[key] = env.from_string(value) except Exception as e: raise ConfigError( "invalid jinja template for oidc_config.user_mapping_provider.config.extra_attributes.%s: %r" % (key, e) ) return JinjaOidcMappingConfig( subject_claim=subject_claim, localpart_template=localpart_template, display_name_template=display_name_template, extra_attributes=extra_attributes, )
def read_config(self, config, **kwargs): consent_config = config.get("user_consent") self.terms_template = self.read_template("terms.html") if consent_config is None: return self.user_consent_version = str(consent_config["version"]) self.user_consent_template_dir = self.abspath(consent_config["template_dir"]) if not path.isdir(self.user_consent_template_dir): raise ConfigError( "Could not find template directory '%s'" % (self.user_consent_template_dir,) ) self.user_consent_server_notice_content = consent_config.get( "server_notice_content" ) self.block_events_without_consent_error = consent_config.get( "block_events_error" ) self.user_consent_server_notice_to_guests = bool( consent_config.get("send_server_notice_to_guests", False) ) self.user_consent_at_registration = bool( consent_config.get("require_at_registration", False) ) self.user_consent_policy_name = consent_config.get( "policy_name", "Privacy Policy" )
def init_tracer(hs: "HomeServer"): """Set the whitelists and initialise the JaegerClient tracer""" global opentracing if not hs.config.opentracer_enabled: # We don't have a tracer opentracing = None return if not opentracing or not JaegerConfig: raise ConfigError( "The server has been configured to use opentracing but opentracing is not " "installed.") # Pull out the jaeger config if it was given. Otherwise set it to something sensible. # See https://github.com/jaegertracing/jaeger-client-python/blob/master/jaeger_client/config.py set_homeserver_whitelist(hs.config.opentracer_whitelist) from jaeger_client.metrics.prometheus import PrometheusMetricsFactory config = JaegerConfig( config=hs.config.jaeger_config, service_name=f"{hs.config.server_name} {hs.get_instance_name()}", scope_manager=LogContextScopeManager(hs.config), metrics_factory=PrometheusMetricsFactory(), ) # If we have the rust jaeger reporter available let's use that. if RustReporter: logger.info("Using rust_python_jaeger_reporter library") tracer = config.create_tracer(RustReporter(), config.sampler) opentracing.set_global_tracer(tracer) else: config.initialize_tracer()
def init_tracer(config): """Set the whitelists and initialise the JaegerClient tracer Args: config (HomeserverConfig): The config used by the homeserver """ global opentracing if not config.opentracer_enabled: # We don't have a tracer opentracing = None return if not opentracing or not JaegerConfig: raise ConfigError( "The server has been configured to use opentracing but opentracing is not " "installed.") # Include the worker name name = config.worker_name if config.worker_name else "master" # Pull out the jaeger config if it was given. Otherwise set it to something sensible. # See https://github.com/jaegertracing/jaeger-client-python/blob/master/jaeger_client/config.py set_homeserver_whitelist(config.opentracer_whitelist) JaegerConfig( config=config.jaeger_config, service_name="{} {}".format(config.server_name, name), scope_manager=LogContextScopeManager(config), ).initialize_tracer()
def parse_template_config(option_name: str) -> Optional[Template]: if option_name not in config: return None try: return env.from_string(config[option_name]) except Exception as e: raise ConfigError("invalid jinja template", path=[option_name]) from e
def __init__(self, hs): """ Args: hs (synapse.server.HomeServer): homeserver """ Resource.__init__(self) self.hs = hs self.store = hs.get_datastore() # this is required by the request_handler wrapper self.clock = hs.get_clock() self._default_consent_version = hs.config.user_consent_version if self._default_consent_version is None: raise ConfigError( "Consent resource is enabled but user_consent section is " "missing in config file.", ) # daemonize changes the cwd to /, so make the path absolute now. consent_template_directory = path.abspath( hs.config.user_consent_template_dir, ) if not path.isdir(consent_template_directory): raise ConfigError( "Could not find template directory '%s'" % ( consent_template_directory, ), ) loader = jinja2.FileSystemLoader(consent_template_directory) self._jinja_env = jinja2.Environment( loader=loader, autoescape=jinja2.select_autoescape(['html', 'htm', 'xml']), ) if hs.config.form_secret is None: raise ConfigError( "Consent resource is enabled but form_secret is not set in " "config file. It should be set to an arbitrary secret string.", ) self._hmac_secret = hs.config.form_secret.encode("utf-8")
def parse_config(config: dict) -> JinjaOidcMappingConfig: subject_claim = config.get("subject_claim", "sub") localpart_template = None # type: Optional[Template] if "localpart_template" in config: try: localpart_template = env.from_string(config["localpart_template"]) except Exception as e: raise ConfigError( "invalid jinja template", path=["localpart_template"] ) from e display_name_template = None # type: Optional[Template] if "display_name_template" in config: try: display_name_template = env.from_string(config["display_name_template"]) except Exception as e: raise ConfigError( "invalid jinja template", path=["display_name_template"] ) from e extra_attributes = {} # type Dict[str, Template] if "extra_attributes" in config: extra_attributes_config = config.get("extra_attributes") or {} if not isinstance(extra_attributes_config, dict): raise ConfigError("must be a dict", path=["extra_attributes"]) for key, value in extra_attributes_config.items(): try: extra_attributes[key] = env.from_string(value) except Exception as e: raise ConfigError( "invalid jinja template", path=["extra_attributes", key] ) from e return JinjaOidcMappingConfig( subject_claim=subject_claim, localpart_template=localpart_template, display_name_template=display_name_template, extra_attributes=extra_attributes, )
def read_config(self, config, **kwargs): self.spam_checkers = [] # type: List[Tuple[Any, Dict]] spam_checkers = config.get("spam_checker") or [] if isinstance(spam_checkers, dict): # The spam_checker config option used to only support one # spam checker, and thus was simply a dictionary with module # and config keys. Support this old behaviour by checking # to see if the option resolves to a dictionary self.spam_checkers.append( load_module(spam_checkers, ("spam_checker", ))) elif isinstance(spam_checkers, list): for i, spam_checker in enumerate(spam_checkers): config_path = ("spam_checker", "<item %i>" % i) if not isinstance(spam_checker, dict): raise ConfigError("expected a mapping", config_path) self.spam_checkers.append( load_module(spam_checker, config_path)) else: raise ConfigError("spam_checker syntax is incorrect")
def parse_config(config: dict) -> SamlConfig: """Parse the dict provided by the homeserver's config Args: config: A dictionary containing configuration options for this provider Returns: SamlConfig: A custom config object for this module """ # Parse config options and use defaults where necessary mxid_source_attribute = config.get("mxid_source_attribute", "uid") mapping_type = config.get("mxid_mapping", "hexencode") # Retrieve the associating mapping function try: mxid_mapper = MXID_MAPPER_MAP[mapping_type] except KeyError: raise ConfigError( "saml2_config.user_mapping_provider.config: '%s' is not a valid " "mxid_mapping value" % (mapping_type, )) return SamlConfig(mxid_source_attribute, mxid_mapper)
def init_tracer(config): """Set the whitelists and initialise the JaegerClient tracer Args: config (HomeserverConfig): The config used by the homeserver """ global opentracing if not config.opentracer_enabled: # We don't have a tracer opentracing = None return if not opentracing or not JaegerConfig: raise ConfigError( "The server has been configured to use opentracing but opentracing is not " "installed.") # Include the worker name name = config.worker_name if config.worker_name else "master" set_homeserver_whitelist(config.opentracer_whitelist) jaeger_config = JaegerConfig( config={ "sampler": { "type": "const", "param": 1 }, "logging": True }, service_name="{} {}".format(config.server_name, name), scope_manager=LogContextScopeManager(config), ) jaeger_config.initialize_tracer() # Set up tags to be opentracing's tags global tags tags = opentracing.tags
def _calculate_registration_flows( config: HomeServerConfig, auth_handler: AuthHandler) -> List[List[str]]: """Get a suitable flows list for registration Args: config: server configuration auth_handler: authorization handler Returns: a list of supported flows """ # FIXME: need a better error than "no auth flow found" for scenarios # where we required 3PID for registration but the user didn't give one require_email = "email" in config.registration.registrations_require_3pid require_msisdn = "msisdn" in config.registration.registrations_require_3pid show_msisdn = True show_email = True if config.registration.disable_msisdn_registration: show_msisdn = False require_msisdn = False enabled_auth_types = auth_handler.get_enabled_auth_types() if LoginType.EMAIL_IDENTITY not in enabled_auth_types: show_email = False if require_email: raise ConfigError( "Configuration requires email address at registration, but email " "validation is not configured") if LoginType.MSISDN not in enabled_auth_types: show_msisdn = False if require_msisdn: raise ConfigError( "Configuration requires msisdn at registration, but msisdn " "validation is not configured") flows = [] # only support 3PIDless registration if no 3PIDs are required if not require_email and not require_msisdn: # Add a dummy step here, otherwise if a client completes # recaptcha first we'll assume they were going for this flow # and complete the request, when they could have been trying to # complete one of the flows with email/msisdn auth. flows.append([LoginType.DUMMY]) # only support the email-only flow if we don't require MSISDN 3PIDs if show_email and not require_msisdn: flows.append([LoginType.EMAIL_IDENTITY]) # only support the MSISDN-only flow if we don't require email 3PIDs if show_msisdn and not require_email: flows.append([LoginType.MSISDN]) if show_email and show_msisdn: # always let users provide both MSISDN & email flows.append([LoginType.MSISDN, LoginType.EMAIL_IDENTITY]) # Prepend m.login.terms to all flows if we're requiring consent if config.consent.user_consent_at_registration: for flow in flows: flow.insert(0, LoginType.TERMS) # Prepend recaptcha to all flows if we're requiring captcha if config.captcha.enable_registration_captcha: for flow in flows: flow.insert(0, LoginType.RECAPTCHA) # Prepend registration token to all flows if we're requiring a token if config.registration.registration_requires_token: for flow in flows: flow.insert(0, LoginType.REGISTRATION_TOKEN) return flows
def __init__(self, hs_config: HomeServerConfig): if hs_config.key.form_secret is None: raise ConfigError("form_secret not set in config") self._hmac_secret = hs_config.key.form_secret.encode("utf-8") self._public_baseurl = hs_config.server.public_baseurl