def read_config(self, config, **kwargs): self.enable_registration = bool( strtobool(str(config.get("enable_registration", False)))) if "disable_registration" in config: self.enable_registration = not bool( strtobool(str(config["disable_registration"]))) self.account_validity = AccountValidityConfig( config.get("account_validity") or {}, config) self.registrations_require_3pid = config.get( "registrations_require_3pid", []) self.allowed_local_3pids = config.get("allowed_local_3pids", []) self.enable_3pid_lookup = config.get("enable_3pid_lookup", True) self.registration_shared_secret = config.get( "registration_shared_secret") self.bcrypt_rounds = config.get("bcrypt_rounds", 12) self.trusted_third_party_id_servers = config.get( "trusted_third_party_id_servers", ["matrix.org", "vector.im"]) account_threepid_delegates = config.get( "account_threepid_delegates") or {} self.account_threepid_delegate_email = account_threepid_delegates.get( "email") self.account_threepid_delegate_msisdn = account_threepid_delegates.get( "msisdn") if self.account_threepid_delegate_msisdn and not self.public_baseurl: raise ConfigError( "The configuration option `public_baseurl` is required if " "`account_threepid_delegate.msisdn` is set, such that " "clients know where to submit validation tokens to. Please " "configure `public_baseurl`.") self.default_identity_server = config.get("default_identity_server") self.allow_guest_access = config.get("allow_guest_access", False) if config.get("invite_3pid_guest", False): raise ConfigError("invite_3pid_guest is no longer supported") self.auto_join_rooms = config.get("auto_join_rooms", []) for room_alias in self.auto_join_rooms: if not RoomAlias.is_valid(room_alias): raise ConfigError("Invalid auto_join_rooms entry %s" % (room_alias, )) self.autocreate_auto_join_rooms = config.get( "autocreate_auto_join_rooms", True) self.enable_set_displayname = config.get("enable_set_displayname", True) self.enable_set_avatar_url = config.get("enable_set_avatar_url", True) self.enable_3pid_changes = config.get("enable_3pid_changes", True) self.disable_msisdn_registration = config.get( "disable_msisdn_registration", False) session_lifetime = config.get("session_lifetime") if session_lifetime is not None: session_lifetime = self.parse_duration(session_lifetime) self.session_lifetime = session_lifetime
def read_config(self, config, **kwargs): account_validity_config = config.get("account_validity") or {} self.account_validity_enabled = account_validity_config.get( "enabled", False) self.account_validity_renew_by_email_enabled = ( "renew_at" in account_validity_config) if self.account_validity_enabled: if "period" in account_validity_config: self.account_validity_period = self.parse_duration( account_validity_config["period"]) else: raise ConfigError( "'period' is required when using account validity") if "renew_at" in account_validity_config: self.account_validity_renew_at = self.parse_duration( account_validity_config["renew_at"]) if "renew_email_subject" in account_validity_config: self.account_validity_renew_email_subject = account_validity_config[ "renew_email_subject"] else: self.account_validity_renew_email_subject = "Renew your %(app)s account" self.account_validity_startup_job_max_delta = ( self.account_validity_period * 10.0 / 100.0) if self.account_validity_renew_by_email_enabled: if not self.public_baseurl: raise ConfigError( "Can't send renewal emails without 'public_baseurl'") # Load account validity templates. account_validity_template_dir = account_validity_config.get( "template_dir") account_renewed_template_filename = account_validity_config.get( "account_renewed_html_path", "account_renewed.html") invalid_token_template_filename = account_validity_config.get( "invalid_token_html_path", "invalid_token.html") # Read and store template content ( self.account_validity_account_renewed_template, self.account_validity_account_previously_renewed_template, self.account_validity_invalid_token_template, ) = self.read_templates( [ account_renewed_template_filename, "account_previously_renewed.html", invalid_token_template_filename, ], account_validity_template_dir, )
def __init__(self, config, synapse_config): if config is None: return super().__init__() self.enabled = config.get("enabled", False) self.renew_by_email_enabled = "renew_at" in config if self.enabled: if "period" in config: self.period = self.parse_duration(config["period"]) else: raise ConfigError( "'period' is required when using account validity") if "renew_at" in config: self.renew_at = self.parse_duration(config["renew_at"]) if "renew_email_subject" in config: self.renew_email_subject = config["renew_email_subject"] else: self.renew_email_subject = "Renew your %(app)s account" self.startup_job_max_delta = self.period * 10.0 / 100.0 if self.renew_by_email_enabled: if "public_baseurl" not in synapse_config: raise ConfigError( "Can't send renewal emails without 'public_baseurl'") template_dir = config.get("template_dir") if not template_dir: template_dir = pkg_resources.resource_filename( "synapse", "res/templates") if "account_renewed_html_path" in config: file_path = os.path.join(template_dir, config["account_renewed_html_path"]) self.account_renewed_html_content = self.read_file( file_path, "account_validity.account_renewed_html_path") else: self.account_renewed_html_content = ( "<html><body>Your account has been successfully renewed.</body><html>" ) if "invalid_token_html_path" in config: file_path = os.path.join(template_dir, config["invalid_token_html_path"]) self.invalid_token_html_content = self.read_file( file_path, "account_validity.invalid_token_html_path") else: self.invalid_token_html_content = ( "<html><body>Invalid renewal token.</body><html>")
def read_config(self, config, **kwargs): self.event_cache_size = self.parse_size( config.get("event_cache_size", "10K")) # We *experimentally* support specifying multiple databases via the # `databases` key. This is a map from a label to database config in the # same format as the `database` config option, plus an extra # `data_stores` key to specify which data store goes where. For example: # # databases: # master: # name: psycopg2 # data_stores: ["main"] # args: {} # state: # name: psycopg2 # data_stores: ["state"] # args: {} multi_database_config = config.get("databases") database_config = config.get("database") database_path = config.get("database_path") if multi_database_config and database_config: raise ConfigError( "Can't specify both 'database' and 'databases' in config") if multi_database_config: if database_path: raise ConfigError( "Can't specify 'database_path' with 'databases'") self.databases = [ DatabaseConnectionConfig(name, db_conf) for name, db_conf in multi_database_config.items() ] if database_config: self.databases = [ DatabaseConnectionConfig("master", database_config) ] if database_path: if self.databases and self.databases[0].name != "sqlite3": logger.warning(NON_SQLITE_DATABASE_PATH_WARNING) return database_config = {"name": "sqlite3", "args": {}} self.databases = [ DatabaseConnectionConfig("master", database_config) ] self.set_databasepath(database_path)
def parse_config(config: dict): """Check that the configuration includes the required keys and parse the values expressed as durations.""" if "period" not in config: raise ConfigError( "'period' is required when using email account validity") if "renew_at" not in config: raise ConfigError( "'renew_at' is required when using email account validity") config["period"] = Config.parse_duration(config.get("period") or 0) config["renew_at"] = Config.parse_duration(config.get("renew_at") or 0) return config
def read_config(self, config): acme_config = config.get("acme", None) if acme_config is None: acme_config = {} self.acme_enabled = acme_config.get("enabled", False) # hyperlink complains on py2 if this is not a Unicode self.acme_url = six.text_type( acme_config.get("url", u"https://acme-v01.api.letsencrypt.org/directory")) self.acme_port = acme_config.get("port", 80) self.acme_bind_addresses = acme_config.get("bind_addresses", ['::', '0.0.0.0']) self.acme_reprovision_threshold = acme_config.get( "reprovision_threshold", 30) self.acme_domain = acme_config.get("domain", config.get("server_name")) self.tls_certificate_file = self.abspath( config.get("tls_certificate_path")) self.tls_private_key_file = self.abspath( config.get("tls_private_key_path")) if self.has_tls_listener(): if not self.tls_certificate_file: raise ConfigError( "tls_certificate_path must be specified if TLS-enabled listeners are " "configured.") if not self.tls_private_key_file: raise ConfigError( "tls_private_key_path must be specified if TLS-enabled listeners are " "configured.") self._original_tls_fingerprints = config.get("tls_fingerprints", []) if self._original_tls_fingerprints is None: self._original_tls_fingerprints = [] self.tls_fingerprints = list(self._original_tls_fingerprints) # This config option applies to non-federation HTTP clients # (e.g. for talking to recaptcha, identity servers, and such) # It should never be used in production, and is intended for # use only when running tests. self.use_insecure_ssl_client_just_for_testing_do_not_use = config.get( "use_insecure_ssl_client_just_for_testing_do_not_use") self.tls_certificate = None self.tls_private_key = None
def read_config(self, config, **kwargs): self.enable_registration = bool( strtobool(str(config.get("enable_registration", False)))) if "disable_registration" in config: self.enable_registration = not bool( strtobool(str(config["disable_registration"]))) self.account_validity = AccountValidityConfig( config.get("account_validity", {}), config) self.registrations_require_3pid = config.get( "registrations_require_3pid", []) self.allowed_local_3pids = config.get("allowed_local_3pids", []) self.enable_3pid_lookup = config.get("enable_3pid_lookup", True) self.registration_shared_secret = config.get( "registration_shared_secret") self.bcrypt_rounds = config.get("bcrypt_rounds", 12) self.trusted_third_party_id_servers = config.get( "trusted_third_party_id_servers", ["matrix.org", "vector.im"]) account_threepid_delegates = config.get( "account_threepid_delegates") or {} self.account_threepid_delegate_email = account_threepid_delegates.get( "email") self.account_threepid_delegate_msisdn = account_threepid_delegates.get( "msisdn") self.default_identity_server = config.get("default_identity_server") self.allow_guest_access = config.get("allow_guest_access", False) if config.get("invite_3pid_guest", False): raise ConfigError("invite_3pid_guest is no longer supported") self.auto_join_rooms = config.get("auto_join_rooms", []) for room_alias in self.auto_join_rooms: if not RoomAlias.is_valid(room_alias): raise ConfigError("Invalid auto_join_rooms entry %s" % (room_alias, )) self.autocreate_auto_join_rooms = config.get( "autocreate_auto_join_rooms", True) self.disable_msisdn_registration = config.get( "disable_msisdn_registration", False) session_lifetime = config.get("session_lifetime") if session_lifetime is not None: session_lifetime = self.parse_duration(session_lifetime) self.session_lifetime = session_lifetime
def is_disk_cert_valid(self, allow_self_signed=True): """ Is the certificate we have on disk valid, and if so, for how long? Args: allow_self_signed (bool): Should we allow the certificate we read to be self signed? Returns: int: Days remaining of certificate validity. None: No certificate exists. """ if not os.path.exists(self.tls_certificate_file): return None try: with open(self.tls_certificate_file, "rb") as f: cert_pem = f.read() except Exception as e: raise ConfigError( "Failed to read existing certificate file %s: %s" % (self.tls_certificate_file, e) ) try: tls_certificate = crypto.load_certificate(crypto.FILETYPE_PEM, cert_pem) except Exception as e: raise ConfigError( "Failed to parse existing certificate file %s: %s" % (self.tls_certificate_file, e) ) if not allow_self_signed: if tls_certificate.get_subject() == tls_certificate.get_issuer(): raise ValueError( "TLS Certificate is self signed, and this is not permitted" ) # YYYYMMDDhhmmssZ -- in UTC expiry_data = tls_certificate.get_notAfter() if expiry_data is None: raise ValueError( "TLS Certificate has no expiry date, and this is not permitted" ) expires_on = datetime.strptime(expiry_data.decode("ascii"), "%Y%m%d%H%M%SZ") now = datetime.utcnow() days_remaining = (expires_on - now).days return days_remaining
def load_module(provider: dict, config_path: Iterable[str]) -> Tuple[Type, Any]: """Loads a synapse module with its config Args: provider: a dict with keys 'module' (the module name) and 'config' (the config dict). config_path: the path within the config file. This will be used as a basis for any error message. Returns Tuple of (provider class, parsed config object) """ modulename = provider.get("module") if not isinstance(modulename, str): raise ConfigError("expected a string", path=itertools.chain(config_path, ("module", ))) # We need to import the module, and then pick the class out of # that, so we split based on the last dot. module_name, clz = modulename.rsplit(".", 1) module = importlib.import_module(module_name) provider_class = getattr(module, clz) # Load the module config. If None, pass an empty dictionary instead module_config = provider.get("config") or {} if hasattr(provider_class, "parse_config"): try: provider_config = provider_class.parse_config(module_config) except jsonschema.ValidationError as e: raise json_error_to_config_error( e, itertools.chain(config_path, ("config", ))) except ConfigError as e: raise _wrap_config_error( "Failed to parse config for module %r" % (modulename, ), prefix=itertools.chain(config_path, ("config", )), e=e, ) except Exception as e: raise ConfigError( "Failed to parse config for module %r" % (modulename, ), path=itertools.chain(config_path, ("config", )), ) from e else: provider_config = module_config return provider_class, provider_config
def setup_structured_logging( log_config: dict, ) -> dict: """ Convert a legacy structured logging configuration (from Synapse < v1.23.0) to one compatible with the new standard library handlers. """ if "drains" not in log_config: raise ConfigError("The logging configuration requires a list of drains.") new_config = { "version": 1, "formatters": { "json": {"class": "synapse.logging.JsonFormatter"}, "tersejson": {"class": "synapse.logging.TerseJsonFormatter"}, }, "handlers": {}, "loggers": log_config.get("loggers", DEFAULT_LOGGERS), "root": {"handlers": []}, } for handler_name, handler in parse_drain_configs(log_config["drains"]): new_config["handlers"][handler_name] = handler # Add each handler to the root logger. new_config["root"]["handlers"].append(handler_name) return new_config
def _get_prejoin_state_types(self, config: JsonDict) -> Iterable[str]: """Get the event types to include in the prejoin state Parses the config and returns an iterable of the event types to be included. """ room_prejoin_state_config = config.get("room_prejoin_state") or {} # backwards-compatibility support for room_invite_state_types if "room_invite_state_types" in config: # if both "room_invite_state_types" and "room_prejoin_state" are set, then # we don't really know what to do. if room_prejoin_state_config: raise ConfigError( "Can't specify both 'room_invite_state_types' and 'room_prejoin_state' " "in config" ) logger.warning(_ROOM_INVITE_STATE_TYPES_WARNING) yield from config["room_invite_state_types"] return if not room_prejoin_state_config.get("disable_default_event_types"): yield from _DEFAULT_PREJOIN_STATE_TYPES yield from room_prejoin_state_config.get("additional_event_types", [])
def validate_config(json_schema: JsonDict, config: Any, config_path: Iterable[str]) -> None: """Validates a config setting against a JsonSchema definition This can be used to validate a section of the config file against a schema definition. If the validation fails, a ConfigError is raised with a textual description of the problem. Args: json_schema: the schema to validate against config: the configuration value to be validated config_path: the path within the config file. This will be used as a basis for the error message. """ try: jsonschema.validate(config, json_schema) except jsonschema.ValidationError as e: # copy `config_path` before modifying it. path = list(config_path) for p in list(e.path): if isinstance(p, int): path.append("<item %i>" % p) else: path.append(str(p)) raise ConfigError("Unable to parse configuration: %s at %s" % (e.message, ".".join(path)))
def read_config(self, config): self.enable_registration = bool( strtobool(str(config["enable_registration"]))) if "disable_registration" in config: self.enable_registration = not bool( strtobool(str(config["disable_registration"]))) self.registrations_require_3pid = config.get( "registrations_require_3pid", []) self.allowed_local_3pids = config.get("allowed_local_3pids", []) self.registration_shared_secret = config.get( "registration_shared_secret") self.bcrypt_rounds = config.get("bcrypt_rounds", 12) self.trusted_third_party_id_servers = config[ "trusted_third_party_id_servers"] self.allow_guest_access = config.get("allow_guest_access", False) self.invite_3pid_guest = (self.allow_guest_access and config.get("invite_3pid_guest", False)) self.auto_join_rooms = config.get("auto_join_rooms", []) for room_alias in self.auto_join_rooms: if not RoomAlias.is_valid(room_alias): raise ConfigError('Invalid auto_join_rooms entry %s' % (room_alias, )) self.autocreate_auto_join_rooms = config.get( "autocreate_auto_join_rooms", True)
def read_arguments(self, args): """ Cases for the cli input: - If no databases are configured and no database_path is set, raise. - No databases and only database_path available ==> sqlite3 db. - If there are multiple databases and a database_path raise an error. - If the database set in the config file is sqlite then overwrite with the command line argument. """ if args.database_path is None: if not self.databases: raise ConfigError("No database config provided") return if len(self.databases) == 0: database_config = {"name": "sqlite3", "args": {}} self.databases = [ DatabaseConnectionConfig("master", database_config) ] self.set_databasepath(args.database_path) return if self.get_single_database().name == "sqlite3": self.set_databasepath(args.database_path) else: logger.warning(NON_SQLITE_DATABASE_PATH_WARNING)
def _require_keys(config, required): missing = [key for key in required if key not in config] if missing: raise ConfigError( "LDAP enabled but missing required config values: {}".format( ", ".join(missing) ) )
def __init__(self, config: dict, api: ModuleApi): store = EmailAccountValidityStore(config, api) EmailAccountValidityBase.__init__(self, config, api, store) DirectServeJsonResource.__init__(self) if not api.public_baseurl: raise ConfigError( "Can't send renewal emails without 'public_baseurl'")
def load_appservices(cls, hostname, config_files): """Returns a list of Application Services from the config files.""" if not isinstance(config_files, list): logger.warning("Expected %s to be a list of AS config files.", config_files) return [] # Dicts of value -> filename seen_as_tokens = {} seen_ids = {} appservices = [] for config_file in config_files: try: with open(config_file, 'r') as f: appservice = ApplicationServiceStore._load_appservice( hostname, yaml.load(f), config_file) if appservice.id in seen_ids: raise ConfigError( "Cannot reuse ID across application services: " "%s (files: %s, %s)" % ( appservice.id, config_file, seen_ids[appservice.id], )) seen_ids[appservice.id] = config_file if appservice.token in seen_as_tokens: raise ConfigError( "Cannot reuse as_token across application services: " "%s (files: %s, %s)" % ( appservice.token, config_file, seen_as_tokens[appservice.token], )) seen_as_tokens[appservice.token] = config_file logger.info("Loaded application service: %s", appservice) appservices.append(appservice) except Exception as e: logger.error("Failed to load appservice from '%s'", config_file) logger.exception(e) raise return appservices
def read_config(self, config: dict, **kwargs): self.loaded_modules: List[Tuple[Any, Dict]] = [] configured_modules = config.get("modules") or [] for i, module in enumerate(configured_modules): config_path = ("modules", "<item %i>" % i) if not isinstance(module, dict): raise ConfigError("expected a mapping", config_path) self.loaded_modules.append(load_module(module, config_path))
def _wrap_config_error(msg: str, prefix: Iterable[str], e: ConfigError) -> "ConfigError": """Wrap a relative ConfigError with a new path This is useful when we have a ConfigError with a relative path due to a problem parsing part of the config, and we now need to set it in context. """ path = prefix if e.path: path = itertools.chain(prefix, e.path) e1 = ConfigError(msg, path) # ideally we would set the 'cause' of the new exception to the original exception; # however now that we have merged the path into our own, the stringification of # e will be incorrect, so instead we create a new exception with just the "msg" # part. e1.__cause__ = Exception(e.msg) e1.__cause__.__cause__ = e.__cause__ return e1
def __init__(self, config, synapse_config): self.enabled = config.get("enabled", False) self.renew_by_email_enabled = ("renew_at" in config) if self.enabled: if "period" in config: self.period = self.parse_duration(config["period"]) else: raise ConfigError( "'period' is required when using account validity") if "renew_at" in config: self.renew_at = self.parse_duration(config["renew_at"]) if "renew_email_subject" in config: self.renew_email_subject = config["renew_email_subject"] else: self.renew_email_subject = "Renew your %(app)s account" if self.renew_by_email_enabled and "public_baseurl" not in synapse_config: raise ConfigError( "Can't send renewal emails without 'public_baseurl'")
def read_config(self, config): self.replication_url = config["replication_url"] self.server_name = config["server_name"] self.use_insecure_ssl_client_just_for_testing_do_not_use = config.get( "use_insecure_ssl_client_just_for_testing_do_not_use", False) self.user_agent_suffix = None self.start_pushers = True self.listeners = config["listeners"] self.soft_file_limit = config.get("soft_file_limit") self.daemonize = config.get("daemonize") self.pid_file = self.abspath(config.get("pid_file")) self.public_baseurl = config["public_baseurl"] thresholds = config.get("gc_thresholds", None) if thresholds is not None: try: assert len(thresholds) == 3 self.gc_thresholds = ( int(thresholds[0]), int(thresholds[1]), int(thresholds[2]), ) except: raise ConfigError( "Value of `gc_threshold` must be a list of three integers if set" ) else: self.gc_thresholds = None # some things used by the auth handler but not actually used in the # pusher codebase self.bcrypt_rounds = None self.ldap_enabled = None self.ldap_server = None self.ldap_port = None self.ldap_tls = None self.ldap_search_base = None self.ldap_search_property = None self.ldap_email_property = None self.ldap_full_name_property = None # We would otherwise try to use the registration shared secret as the # macaroon shared secret if there was no macaroon_shared_secret, but # that means pulling in RegistrationConfig too. We don't need to be # backwards compaitible in the pusher codebase so just make people set # macaroon_shared_secret. We set this to None to prevent it referencing # an undefined key. self.registration_shared_secret = None
def __init__(self, name: str, db_config: dict): if db_config["name"] not in ("sqlite3", "psycopg2"): raise ConfigError("Unsupported database type %r" % (db_config["name"],)) if db_config["name"] == "sqlite3": db_config.setdefault("args", {}).update( {"cp_min": 1, "cp_max": 1, "check_same_thread": False} ) data_stores = db_config.get("data_stores") if data_stores is None: data_stores = ["main", "state"] self.name = name self.config = db_config self.data_stores = data_stores
def __init__(self, config: Any, api: ModuleApi, populate_users: bool = True): self._store = EmailAccountValidityStore(config, api) self._api = api super().__init__(config, self._api, self._store) run_in_background(self._store.create_and_populate_table, populate_users) self._api.looping_background_call_async(self._send_renewal_emails, 30 * 60 * 1000) if not api.public_baseurl: raise ConfigError( "Can't send renewal emails without 'public_baseurl'")
def __init__(self, hs): # If we're not configured to use it, raise if we somehow got here. if not hs.config.can_load_media_repo: raise ConfigError("Synapse is not configured to use a media repo.") super().__init__() media_repo = hs.get_media_repository() self.putChild(b"upload", UploadResource(hs, media_repo)) self.putChild(b"download", DownloadResource(hs, media_repo)) self.putChild( b"thumbnail", ThumbnailResource(hs, media_repo, media_repo.media_storage) ) if hs.config.url_preview_enabled: self.putChild( b"preview_url", PreviewUrlResource(hs, media_repo, media_repo.media_storage), ) self.putChild(b"config", MediaConfigResource(hs))
def set_databasepath(self, database_path): if database_path is None: return if database_path != ":memory:": database_path = self.abspath(database_path) # We only support setting a database path if we have a single sqlite3 # database. if len(self.databases) != 1: raise ConfigError("Cannot specify 'database_path' with multiple databases") database = self.get_single_database() if database.config["name"] != "sqlite3": # We don't raise here as we haven't done so before for this case. logger.warn("Ignoring 'database_path' for non-sqlite3 database") return database.config["args"]["database"] = database_path
def load_module(provider): """ Loads a synapse module with its config Take a dict with keys 'module' (the module name) and 'config' (the config dict). Returns Tuple of (provider class, parsed config object) """ # We need to import the module, and then pick the class out of # that, so we split based on the last dot. module, clz = provider["module"].rsplit(".", 1) module = importlib.import_module(module) provider_class = getattr(module, clz) try: provider_config = provider_class.parse_config(provider["config"]) except Exception as e: raise ConfigError("Failed to parse config for %r: %r" % (provider["module"], e)) return provider_class, provider_config
def json_error_to_config_error(e: jsonschema.ValidationError, config_path: Iterable[str]) -> ConfigError: """Converts a json validation error to a user-readable ConfigError Args: e: the exception to be converted config_path: the path within the config file. This will be used as a basis for the error message. Returns: a ConfigError """ # copy `config_path` before modifying it. path = list(config_path) for p in list(e.path): if isinstance(p, int): path.append("<item %i>" % p) else: path.append(str(p)) return ConfigError(e.message, path)
def generate_config_section( self, tls_certificate_path: Optional[str], tls_private_key_path: Optional[str], **kwargs: Any, ) -> str: """If the TLS paths are not specified the default will be certs in the config directory""" if bool(tls_certificate_path) != bool(tls_private_key_path): raise ConfigError( "Please specify both a cert path and a key path or neither.") if tls_certificate_path and tls_private_key_path: return f"""\ tls_certificate_path: {tls_certificate_path} tls_private_key_path: {tls_private_key_path} """ else: return ""
def __init__(self, name: str, db_config: dict): db_engine = db_config.get("name", "sqlite3") if db_engine not in ("sqlite3", "psycopg2"): raise ConfigError("Unsupported database type %r" % (db_engine,)) if db_engine == "sqlite3": db_config.setdefault("args", {}).update( {"cp_min": 1, "cp_max": 1, "check_same_thread": False} ) data_stores = db_config.get("data_stores") if data_stores is None: data_stores = ["main", "state"] self.name = name self.config = db_config # The `data_stores` config is actually talking about `databases` (we # changed the name). self.databases = data_stores
def read_config(self, config): self.enable_registration = bool( strtobool(str(config.get("enable_registration", False)))) if "disable_registration" in config: self.enable_registration = not bool( strtobool(str(config["disable_registration"]))) self.account_validity = AccountValidityConfig( config.get("account_validity", {}), config, ) self.registrations_require_3pid = config.get( "registrations_require_3pid", []) self.allowed_local_3pids = config.get("allowed_local_3pids", []) self.enable_3pid_lookup = config.get("enable_3pid_lookup", True) self.registration_shared_secret = config.get( "registration_shared_secret") self.bcrypt_rounds = config.get("bcrypt_rounds", 12) self.trusted_third_party_id_servers = config.get( "trusted_third_party_id_servers", ["matrix.org", "vector.im"], ) self.default_identity_server = config.get("default_identity_server") self.allow_guest_access = config.get("allow_guest_access", False) self.invite_3pid_guest = (self.allow_guest_access and config.get("invite_3pid_guest", False)) self.auto_join_rooms = config.get("auto_join_rooms", []) for room_alias in self.auto_join_rooms: if not RoomAlias.is_valid(room_alias): raise ConfigError('Invalid auto_join_rooms entry %s' % (room_alias, )) self.autocreate_auto_join_rooms = config.get( "autocreate_auto_join_rooms", True) self.disable_msisdn_registration = (config.get( "disable_msisdn_registration", False))