Skip to content
This repository has been archived by the owner on Apr 26, 2024. It is now read-only.

Add --data-dir and --open-private-ports options. #5524

Merged
merged 6 commits into from
Jun 24, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions changelog.d/5523.bugfix
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Fix a regression where homeservers on private IP addresses were incorrectly blacklisted.
1 change: 1 addition & 0 deletions changelog.d/5524.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Add --data-dir and --open-private-ports options.
2 changes: 1 addition & 1 deletion docs/sample_config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,7 @@ listeners:
- names: [client, federation]
compress: false

# example additonal_resources:
# example additional_resources:
#
#additional_resources:
# "/_matrix/my/custom/endpoint":
Expand Down
135 changes: 64 additions & 71 deletions synapse/config/_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -136,11 +136,6 @@ def read_file(cls, file_path, config_name):
with open(file_path) as file_stream:
return file_stream.read()

@staticmethod
def read_config_file(file_path):
with open(file_path) as file_stream:
return yaml.safe_load(file_stream)

def invoke_all(self, name, *args, **kargs):
results = []
for cls in type(self).mro():
Expand All @@ -155,12 +150,12 @@ def generate_config(
server_name,
generate_secrets=False,
report_stats=None,
open_private_ports=False,
):
"""Build a default configuration file

This is used both when the user explicitly asks us to generate a config file
(eg with --generate_config), and before loading the config at runtime (to give
a base which the config files override)
This is used when the user explicitly asks us to generate a config file
(eg with --generate_config).

Args:
config_dir_path (str): The path where the config files are kept. Used to
Expand All @@ -179,23 +174,25 @@ def generate_config(
report_stats (bool|None): Initial setting for the report_stats setting.
If None, report_stats will be left unset.

open_private_ports (bool): True to leave private ports (such as the non-TLS
HTTP listener) open to the internet.

Returns:
str: the yaml config file
"""
default_config = "\n\n".join(
return "\n\n".join(
dedent(conf)
for conf in self.invoke_all(
"default_config",
"generate_config_section",
config_dir_path=config_dir_path,
data_dir_path=data_dir_path,
server_name=server_name,
generate_secrets=generate_secrets,
report_stats=report_stats,
open_private_ports=open_private_ports,
)
)

return default_config

@classmethod
def load_config(cls, description, argv):
"""Parse the commandline and config files
Expand Down Expand Up @@ -240,9 +237,7 @@ def load_config(cls, description, argv):
config_dir_path = os.path.abspath(config_dir_path)
data_dir_path = os.getcwd()

config_dict = obj.read_config_files(
config_files, config_dir_path=config_dir_path, data_dir_path=data_dir_path
)
config_dict = read_config_files(config_files)
obj.parse_config_dict(
config_dict, config_dir_path=config_dir_path, data_dir_path=data_dir_path
)
Expand Down Expand Up @@ -300,6 +295,23 @@ def load_or_generate_config(cls, description, argv):
" config file."
),
)
generate_group.add_argument(
"--data-directory",
metavar="DIRECTORY",
help=(
"Specify where data such as the media store and database file should be"
" stored. Defaults to the current working directory."
),
)
generate_group.add_argument(
"--open-private-ports",
action="store_true",
help=(
"Leave private ports (such as the non-TLS HTTP listener) open to the"
" internet. Do not use this unless you know what you are doing."
),
)

config_args, remaining_args = config_parser.parse_known_args(argv)

config_files = find_config_files(search_paths=config_args.config_path)
Expand Down Expand Up @@ -333,6 +345,12 @@ def load_or_generate_config(cls, description, argv):
if not cls.path_exists(config_path):
print("Generating config file %s" % (config_path,))

if config_args.data_directory:
data_dir_path = config_args.data_directory
else:
data_dir_path = os.getcwd()
data_dir_path = os.path.abspath(data_dir_path)

server_name = config_args.server_name
if not server_name:
raise ConfigError(
Expand All @@ -346,6 +364,7 @@ def load_or_generate_config(cls, description, argv):
server_name=server_name,
report_stats=(config_args.report_stats == "yes"),
generate_secrets=True,
open_private_ports=config_args.open_private_ports,
)

if not cls.path_exists(config_dir_path):
Expand All @@ -354,8 +373,8 @@ def load_or_generate_config(cls, description, argv):
config_file.write("# vim:ft=yaml\n\n")
config_file.write(config_str)

config = yaml.safe_load(config_str)
obj.invoke_all("generate_files", config)
config_dict = yaml.safe_load(config_str)
obj.generate_missing_files(config_dict, config_dir_path)

print(
(
Expand Down Expand Up @@ -385,12 +404,9 @@ def load_or_generate_config(cls, description, argv):
obj.invoke_all("add_arguments", parser)
args = parser.parse_args(remaining_args)

config_dict = obj.read_config_files(
config_files, config_dir_path=config_dir_path, data_dir_path=data_dir_path
)

config_dict = read_config_files(config_files)
if generate_missing_configs:
obj.generate_missing_files(config_dict)
obj.generate_missing_files(config_dict, config_dir_path)
return None

obj.parse_config_dict(
Expand All @@ -400,53 +416,6 @@ def load_or_generate_config(cls, description, argv):

return obj

def read_config_files(self, config_files, config_dir_path, data_dir_path):
"""Read the config files into a dict

Args:
config_files (iterable[str]): A list of the config files to read

config_dir_path (str): The path where the config files are kept. Used to
create filenames for things like the log config and the signing key.

data_dir_path (str): The path where the data files are kept. Used to create
filenames for things like the database and media store.

Returns: dict
"""
# first we read the config files into a dict
specified_config = {}
for config_file in config_files:
yaml_config = self.read_config_file(config_file)
specified_config.update(yaml_config)

# not all of the options have sensible defaults in code, so we now need to
# generate a default config file suitable for the specified server name...
if "server_name" not in specified_config:
raise ConfigError(MISSING_SERVER_NAME)
server_name = specified_config["server_name"]
config_string = self.generate_config(
config_dir_path=config_dir_path,
data_dir_path=data_dir_path,
server_name=server_name,
generate_secrets=False,
)

# ... and read it into a base config dict ...
config = yaml.safe_load(config_string)

# ... and finally, overlay it with the actual configuration.
config.pop("log_config")
config.update(specified_config)

if "report_stats" not in config:
raise ConfigError(
MISSING_REPORT_STATS_CONFIG_INSTRUCTIONS
+ "\n"
+ MISSING_REPORT_STATS_SPIEL
)
return config

def parse_config_dict(self, config_dict, config_dir_path, data_dir_path):
"""Read the information from the config dict into this Config object.

Expand All @@ -466,8 +435,32 @@ def parse_config_dict(self, config_dict, config_dir_path, data_dir_path):
data_dir_path=data_dir_path,
)

def generate_missing_files(self, config_dict):
self.invoke_all("generate_files", config_dict)
def generate_missing_files(self, config_dict, config_dir_path):
self.invoke_all("generate_files", config_dict, config_dir_path)


def read_config_files(config_files):
"""Read the config files into a dict

Args:
config_files (iterable[str]): A list of the config files to read

Returns: dict
"""
specified_config = {}
for config_file in config_files:
with open(config_file) as file_stream:
yaml_config = yaml.safe_load(file_stream)
specified_config.update(yaml_config)

if "server_name" not in specified_config:
raise ConfigError(MISSING_SERVER_NAME)

if "report_stats" not in specified_config:
raise ConfigError(
MISSING_REPORT_STATS_CONFIG_INSTRUCTIONS + "\n" + MISSING_REPORT_STATS_SPIEL
)
return specified_config


def find_config_files(search_paths):
Expand Down
2 changes: 1 addition & 1 deletion synapse/config/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ def read_config(self, config, **kwargs):
],
)

def default_config(cls, **kwargs):
def generate_config_section(cls, **kwargs):
return """\
## API Configuration ##

Expand Down
2 changes: 1 addition & 1 deletion synapse/config/appservice.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ def read_config(self, config, **kwargs):
self.notify_appservices = config.get("notify_appservices", True)
self.track_appservice_user_ips = config.get("track_appservice_user_ips", False)

def default_config(cls, **kwargs):
def generate_config_section(cls, **kwargs):
return """\
# A list of application service config files to use
#
Expand Down
2 changes: 1 addition & 1 deletion synapse/config/captcha.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ def read_config(self, config, **kwargs):
"https://www.recaptcha.net/recaptcha/api/siteverify",
)

def default_config(self, **kwargs):
def generate_config_section(self, **kwargs):
return """\
## Captcha ##
# See docs/CAPTCHA_SETUP for full details of configuring this.
Expand Down
2 changes: 1 addition & 1 deletion synapse/config/cas.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ def read_config(self, config, **kwargs):
self.cas_service_url = None
self.cas_required_attributes = {}

def default_config(self, config_dir_path, server_name, **kwargs):
def generate_config_section(self, config_dir_path, server_name, **kwargs):
return """
# Enable CAS for registration and login.
#
Expand Down
2 changes: 1 addition & 1 deletion synapse/config/consent_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -111,5 +111,5 @@ def read_config(self, config, **kwargs):
"policy_name", "Privacy Policy"
)

def default_config(self, **kwargs):
def generate_config_section(self, **kwargs):
return DEFAULT_CONFIG
2 changes: 1 addition & 1 deletion synapse/config/database.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ def read_config(self, config, **kwargs):

self.set_databasepath(config.get("database_path"))

def default_config(self, data_dir_path, **kwargs):
def generate_config_section(self, data_dir_path, **kwargs):
database_path = os.path.join(data_dir_path, "homeserver.db")
return (
"""\
Expand Down
2 changes: 1 addition & 1 deletion synapse/config/emailconfig.py
Original file line number Diff line number Diff line change
Expand Up @@ -214,7 +214,7 @@ def read_config(self, config, **kwargs):
if not os.path.isfile(p):
raise ConfigError("Unable to find email template file %s" % (p,))

def default_config(self, config_dir_path, server_name, **kwargs):
def generate_config_section(self, config_dir_path, server_name, **kwargs):
return """
# Enable sending emails for password resets, notification events or
# account expiry notices
Expand Down
2 changes: 1 addition & 1 deletion synapse/config/groups.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ def read_config(self, config, **kwargs):
self.enable_group_creation = config.get("enable_group_creation", False)
self.group_creation_prefix = config.get("group_creation_prefix", "")

def default_config(self, **kwargs):
def generate_config_section(self, **kwargs):
return """\
# Uncomment to allow non-server-admin users to create groups on this server
#
Expand Down
2 changes: 1 addition & 1 deletion synapse/config/jwt_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ def read_config(self, config, **kwargs):
self.jwt_secret = None
self.jwt_algorithm = None

def default_config(self, **kwargs):
def generate_config_section(self, **kwargs):
return """\
# The JWT needs to contain a globally unique "sub" (subject) claim.
#
Expand Down
24 changes: 18 additions & 6 deletions synapse/config/key.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,13 +65,18 @@ class TrustedKeyServer(object):


class KeyConfig(Config):
def read_config(self, config, **kwargs):
def read_config(self, config, config_dir_path, **kwargs):
# the signing key can be specified inline or in a separate file
if "signing_key" in config:
self.signing_key = read_signing_keys([config["signing_key"]])
else:
self.signing_key_path = config["signing_key_path"]
self.signing_key = self.read_signing_key(self.signing_key_path)
signing_key_path = config.get("signing_key_path")
if signing_key_path is None:
signing_key_path = os.path.join(
config_dir_path, config["server_name"] + ".signing.key"
)

self.signing_key = self.read_signing_key(signing_key_path)

self.old_signing_keys = self.read_old_signing_keys(
config.get("old_signing_keys", {})
Expand Down Expand Up @@ -117,7 +122,7 @@ def read_config(self, config, **kwargs):
# falsification of values
self.form_secret = config.get("form_secret", None)

def default_config(
def generate_config_section(
self, config_dir_path, server_name, generate_secrets=False, **kwargs
):
base_key_name = os.path.join(config_dir_path, server_name)
Expand Down Expand Up @@ -237,8 +242,15 @@ def read_old_signing_keys(self, old_signing_keys):
)
return keys

def generate_files(self, config):
signing_key_path = config["signing_key_path"]
def generate_files(self, config, config_dir_path):
if "signing_key" in config:
return

signing_key_path = config.get("signing_key_path")
if signing_key_path is None:
signing_key_path = os.path.join(
config_dir_path, config["server_name"] + ".signing.key"
)

if not self.path_exists(signing_key_path):
print("Generating signing key file %s" % (signing_key_path,))
Expand Down
4 changes: 2 additions & 2 deletions synapse/config/logger.py
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ def read_config(self, config, **kwargs):
self.log_config = self.abspath(config.get("log_config"))
self.log_file = self.abspath(config.get("log_file"))

def default_config(self, config_dir_path, server_name, **kwargs):
def generate_config_section(self, config_dir_path, server_name, **kwargs):
log_config = os.path.join(config_dir_path, server_name + ".log.config")
return (
"""\
Expand Down Expand Up @@ -133,7 +133,7 @@ def add_arguments(cls, parser):
help="Do not redirect stdout/stderr to the log",
)

def generate_files(self, config):
def generate_files(self, config, config_dir_path):
log_config = config.get("log_config")
if log_config and not os.path.exists(log_config):
log_file = self.abspath("homeserver.log")
Expand Down
2 changes: 1 addition & 1 deletion synapse/config/metrics.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ def read_config(self, config, **kwargs):
"sentry.dsn field is required when sentry integration is enabled"
)

def default_config(self, report_stats=None, **kwargs):
def generate_config_section(self, report_stats=None, **kwargs):
res = """\
## Metrics ###

Expand Down
Loading