diff --git a/server/app/app.py b/server/app/app.py index de88a5b3..b652baf9 100644 --- a/server/app/app.py +++ b/server/app/app.py @@ -207,8 +207,8 @@ class Server: self.app.permanent_session_lifetime = datetime.timedelta(days=50 * 365) # Config - SECRET_KEY = os.environ.get("CXG_SECRET_KEY", default="SparkleAndShine") - self.app.config.update(SECRET_KEY=SECRET_KEY) + secret_key = app_config.server__flask_secret_key + self.app.config.update(SECRET_KEY=secret_key) self.app.register_blueprint(webbp) diff --git a/server/cli/launch.py b/server/cli/launch.py index 0331e736..8461589d 100644 --- a/server/cli/launch.py +++ b/server/cli/launch.py @@ -275,6 +275,7 @@ class CliLaunchServer(Server): """ the CLI runs a local web server, and needs to enable a few more features. """ + def __init__(self, matrix_data_cache_manager, annotations, app_config): super().__init__(matrix_data_cache_manager, annotations, app_config) @@ -394,6 +395,10 @@ def launch( app_config.complete_config(matrix_data_cache_manager, messagefn) + # Use a default secret if one is not provided + if not app_config.server__flask_secret_key: + app_config.server__flask_secret_key = "SparkleAndShine" + except (ConfigurationError, DatasetAccessError) as e: raise click.ClickException(e) diff --git a/server/common/app_config.py b/server/common/app_config.py index 0390d646..70541bdd 100644 --- a/server/common/app_config.py +++ b/server/common/app_config.py @@ -65,28 +65,37 @@ class AppConfig(object): self.server__about_legal_tos = dc["server"]["about_legal_tos"] self.server__about_legal_privacy = dc["server"]["about_legal_privacy"] self.server__force_https = dc["server"]["force_https"] + self.server__flask_secret_key = dc["server"]["flask_secret_key"] + self.multi_dataset__dataroot = dc["multi_dataset"]["dataroot"] self.multi_dataset__index = dc["multi_dataset"]["index"] self.multi_dataset__allowed_matrix_types = dc["multi_dataset"]["allowed_matrix_types"] self.multi_dataset__matrix_cache__max_datasets = dc["multi_dataset"]["matrix_cache"]["max_datasets"] + self.single_dataset__datapath = dc["single_dataset"]["datapath"] self.single_dataset__obs_names = dc["single_dataset"]["obs_names"] self.single_dataset__var_names = dc["single_dataset"]["var_names"] self.single_dataset__about = dc["single_dataset"]["about"] self.single_dataset__title = dc["single_dataset"]["title"] + self.user_annotations__enable = dc["user_annotations"]["enable"] self.user_annotations__type = dc["user_annotations"]["type"] self.user_annotations__local_file_csv__directory = dc["user_annotations"]["local_file_csv"]["directory"] self.user_annotations__local_file_csv__file = dc["user_annotations"]["local_file_csv"]["file"] self.user_annotations__ontology__enable = dc["user_annotations"]["ontology"]["enable"] self.user_annotations__ontology__obo_location = dc["user_annotations"]["ontology"]["obo_location"] + self.presentation__max_categories = dc["presentation"]["max_categories"] + self.embeddings__names = dc["embeddings"]["names"] self.embeddings__enable_reembedding = dc["embeddings"]["enable_reembedding"] + self.diffexp__enable = dc["diffexp"]["enable"] self.diffexp__lfc_cutoff = dc["diffexp"]["lfc_cutoff"] + self.adaptor__cxg_adaptor__tiledb_ctx = dc["adaptor"]["cxg_adaptor"]["tiledb_ctx"] self.adaptor__anndata_adaptor__backed = dc["adaptor"]["anndata_adaptor"]["backed"] + except KeyError as e: raise ConfigurationError(f"Unexpected config: {str(e)}") @@ -184,6 +193,8 @@ class AppConfig(object): self.__check_attr("server__port", (type(None), int)) self.__check_attr("server__scripts", (list, tuple)) self.__check_attr("server__open_browser", bool) + self.__check_attr("server__force_https", bool) + self.__check_attr("server__flask_secret_key", (type(None), str)) if self.server__port: if not is_port_available(self.server__host, self.server__port): @@ -203,6 +214,11 @@ class AppConfig(object): if not self.server__verbose: sys.tracebacklimit = 0 + # secret key: + # first, from CXG_SECRET_KEY environment variable + # second, from config file + self.server__flask_secret_key = environ.get("CXG_SECRET_KEY", self.server__flask_secret_key) + def handle_presentation(self, context): self.__check_attr("presentation__max_categories", int) diff --git a/server/common/default_config.py b/server/common/default_config.py index 4f8ee4d5..682eeb95 100644 --- a/server/common/default_config.py +++ b/server/common/default_config.py @@ -13,6 +13,7 @@ server: about_legal_tos: null about_legal_privacy: null force_https: false + flask_secret_key: null presentation: max_categories: 1000 diff --git a/server/eb/app.py b/server/eb/app.py index 057c6cc3..f83189e0 100644 --- a/server/eb/app.py +++ b/server/eb/app.py @@ -77,6 +77,13 @@ try: matrix_data_cache_manager = MatrixDataCacheManager() app_config.complete_config(matrix_data_cache_manager, logging.info) + + if not app_config.server__flask_secret_key: + logging.critical( + f"flask_secret_key is not provided. Either set in config file, or in CXG_SECRET_KEY environment variable" + ) + sys.exit(1) + user_annotations = app_config.user_annotations server = WSGIServer(matrix_data_cache_manager, user_annotations, app_config)