diff --git a/synapse/config/captcha.py b/synapse/config/captcha.py
index f0171bb5b2..56c87fa296 100644
--- a/synapse/config/captcha.py
+++ b/synapse/config/captcha.py
@@ -24,7 +24,6 @@ class CaptchaConfig(Config):
self.enable_registration_captcha = config.get(
"enable_registration_captcha", False
)
- self.captcha_bypass_secret = config.get("captcha_bypass_secret")
self.recaptcha_siteverify_api = config.get(
"recaptcha_siteverify_api",
"https://www.recaptcha.net/recaptcha/api/siteverify",
@@ -49,10 +48,6 @@ class CaptchaConfig(Config):
#
#enable_registration_captcha: false
- # A secret key used to bypass the captcha test entirely.
- #
- #captcha_bypass_secret: "YOUR_SECRET_HERE"
-
# The API endpoint to use for verifying m.login.recaptcha responses.
#
#recaptcha_siteverify_api: "https://www.recaptcha.net/recaptcha/api/siteverify"
diff --git a/synapse/config/database.py b/synapse/config/database.py
index b8ab2f86ac..c27fef157b 100644
--- a/synapse/config/database.py
+++ b/synapse/config/database.py
@@ -20,6 +20,11 @@ from synapse.config._base import Config, ConfigError
logger = logging.getLogger(__name__)
+NON_SQLITE_DATABASE_PATH_WARNING = """\
+Ignoring 'database_path' setting: not using a sqlite3 database.
+--------------------------------------------------------------------------------
+"""
+
DEFAULT_CONFIG = """\
## Database ##
@@ -105,6 +110,11 @@ class DatabaseConnectionConfig:
class DatabaseConfig(Config):
section = "database"
+ def __init__(self, *args, **kwargs):
+ super().__init__(*args, **kwargs)
+
+ self.databases = []
+
def read_config(self, config, **kwargs):
self.event_cache_size = self.parse_size(config.get("event_cache_size", "10K"))
@@ -125,12 +135,13 @@ class DatabaseConfig(Config):
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 'datbases' in config")
if multi_database_config:
- if config.get("database_path"):
+ if database_path:
raise ConfigError("Can't specify 'database_path' with 'databases'")
self.databases = [
@@ -138,13 +149,17 @@ class DatabaseConfig(Config):
for name, db_conf in multi_database_config.items()
]
- else:
- if database_config is None:
- database_config = {"name": "sqlite3", "args": {}}
-
+ if database_config:
self.databases = [DatabaseConnectionConfig("master", database_config)]
- self.set_databasepath(config.get("database_path"))
+ 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 generate_config_section(self, data_dir_path, **kwargs):
return DEFAULT_CONFIG % {
@@ -152,27 +167,37 @@ class DatabaseConfig(Config):
}
def read_arguments(self, args):
- self.set_databasepath(args.database_path)
+ """
+ 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.
+ """
- def set_databasepath(self, database_path):
- if database_path is None:
+ if args.database_path is None:
+ if not self.databases:
+ raise ConfigError("No database config provided")
return
- if database_path != ":memory:":
- database_path = self.abspath(database_path)
+ 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)
- # 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")
+ def set_databasepath(self, database_path):
- 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
+ if database_path != ":memory:":
+ database_path = self.abspath(database_path)
- database.config["args"]["database"] = database_path
+ self.databases[0].config["args"]["database"] = database_path
@staticmethod
def add_arguments(parser):
@@ -187,7 +212,7 @@ class DatabaseConfig(Config):
def get_single_database(self) -> DatabaseConnectionConfig:
"""Returns the database if there is only one, useful for e.g. tests
"""
- if len(self.databases) != 1:
+ if not self.databases:
raise Exception("More than one database exists")
return self.databases[0]
diff --git a/synapse/config/password.py b/synapse/config/password.py
index 2a634ac751..9c0ea8c30a 100644
--- a/synapse/config/password.py
+++ b/synapse/config/password.py
@@ -31,6 +31,10 @@ class PasswordConfig(Config):
self.password_localdb_enabled = password_config.get("localdb_enabled", True)
self.password_pepper = password_config.get("pepper", "")
+ # Password policy
+ self.password_policy = password_config.get("policy") or {}
+ self.password_policy_enabled = self.password_policy.get("enabled", False)
+
def generate_config_section(self, config_dir_path, server_name, **kwargs):
return """\
password_config:
@@ -48,4 +52,39 @@ class PasswordConfig(Config):
# DO NOT CHANGE THIS AFTER INITIAL SETUP!
#
#pepper: "EVEN_MORE_SECRET"
+
+ # Define and enforce a password policy. Each parameter is optional.
+ # This is an implementation of MSC2000.
+ #
+ policy:
+ # Whether to enforce the password policy.
+ # Defaults to 'false'.
+ #
+ #enabled: true
+
+ # Minimum accepted length for a password.
+ # Defaults to 0.
+ #
+ #minimum_length: 15
+
+ # Whether a password must contain at least one digit.
+ # Defaults to 'false'.
+ #
+ #require_digit: true
+
+ # Whether a password must contain at least one symbol.
+ # A symbol is any character that's not a number or a letter.
+ # Defaults to 'false'.
+ #
+ #require_symbol: true
+
+ # Whether a password must contain at least one lowercase letter.
+ # Defaults to 'false'.
+ #
+ #require_lowercase: true
+
+ # Whether a password must contain at least one lowercase letter.
+ # Defaults to 'false'.
+ #
+ #require_uppercase: true
"""
diff --git a/synapse/config/registration.py b/synapse/config/registration.py
index 9bb3beedbc..e7ea3a01cb 100644
--- a/synapse/config/registration.py
+++ b/synapse/config/registration.py
@@ -129,6 +129,10 @@ class RegistrationConfig(Config):
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
)
@@ -330,6 +334,29 @@ class RegistrationConfig(Config):
#email: https://example.com # Delegate email sending to example.com
#msisdn: http://localhost:8090 # Delegate SMS sending to this local process
+ # Whether users are allowed to change their displayname after it has
+ # been initially set. Useful when provisioning users based on the
+ # contents of a third-party directory.
+ #
+ # Does not apply to server administrators. Defaults to 'true'
+ #
+ #enable_set_displayname: false
+
+ # Whether users are allowed to change their avatar after it has been
+ # initially set. Useful when provisioning users based on the contents
+ # of a third-party directory.
+ #
+ # Does not apply to server administrators. Defaults to 'true'
+ #
+ #enable_set_avatar_url: false
+
+ # Whether users can change the 3PIDs associated with their accounts
+ # (email address and msisdn).
+ #
+ # Defaults to 'true'
+ #
+ #enable_3pid_changes: false
+
# Users who register on this homeserver will automatically be joined
# to these rooms
#
diff --git a/synapse/config/sso.py b/synapse/config/sso.py
index 95762689bc..ec3dca9efc 100644
--- a/synapse/config/sso.py
+++ b/synapse/config/sso.py
@@ -39,6 +39,17 @@ class SSOConfig(Config):
self.sso_client_whitelist = sso_config.get("client_whitelist") or []
+ # Attempt to also whitelist the server's login fallback, since that fallback sets
+ # the redirect URL to itself (so it can process the login token then return
+ # gracefully to the client). This would make it pointless to ask the user for
+ # confirmation, since the URL the confirmation page would be showing wouldn't be
+ # the client's.
+ # public_baseurl is an optional setting, so we only add the fallback's URL to the
+ # list if it's provided (because we can't figure out what that URL is otherwise).
+ if self.public_baseurl:
+ login_fallback_url = self.public_baseurl + "_matrix/static/client/login"
+ self.sso_client_whitelist.append(login_fallback_url)
+
def generate_config_section(self, **kwargs):
return """\
# Additional settings to use with single-sign on systems such as SAML2 and CAS.
@@ -54,6 +65,10 @@ class SSOConfig(Config):
# phishing attacks from evil.site. To avoid this, include a slash after the
# hostname: "https://my.client/".
#
+ # If public_baseurl is set, then the login fallback page (used by clients
+ # that don't natively support the required login flows) is whitelisted in
+ # addition to any URLs in this list.
+ #
# By default, this list is empty.
#
#client_whitelist:
|