Esempio n. 1
0
    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
Esempio n. 2
0
    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,
        )
Esempio n. 3
0
    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>")
Esempio n. 4
0
    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
Esempio n. 6
0
    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
Esempio n. 7
0
    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
Esempio n. 8
0
    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
Esempio n. 9
0
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
Esempio n. 10
0
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
Esempio n. 11
0
    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", [])
Esempio n. 12
0
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)))
Esempio n. 13
0
    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)
Esempio n. 14
0
    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)
Esempio n. 15
0
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)
            )
        )
Esempio n. 16
0
    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'")
Esempio n. 17
0
    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
Esempio n. 18
0
    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))
Esempio n. 19
0
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
Esempio n. 20
0
    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'")
Esempio n. 21
0
    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
Esempio n. 22
0
    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'")
Esempio n. 24
0
    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))
Esempio n. 25
0
    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
Esempio n. 26
0
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
Esempio n. 27
0
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)
Esempio n. 28
0
    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 ""
Esempio n. 29
0
    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
Esempio n. 30
0
    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))