From a5e74b4f2cbcc365832da469ac6ec08b5932c65f Mon Sep 17 00:00:00 2001 From: Philipp Date: Mon, 1 Feb 2021 02:09:33 +0100 Subject: [PATCH] Prepare for runtime release config --- config/config.exs | 2 +- config/prod.exs | 12 ++-- config/runtime.exs | 157 ++++++++++++++++++++++++++++++++++++++++++--- config/test.exs | 4 +- 4 files changed, 157 insertions(+), 18 deletions(-) diff --git a/config/config.exs b/config/config.exs index 55e733e8..aa271220 100644 --- a/config/config.exs +++ b/config/config.exs @@ -21,7 +21,7 @@ config :keila, KeilaWeb.Endpoint, config :keila, :ids, separator: "_", alphabet: "abcdefghijkmnopqrstuvwxyz23456789ABCDEFGHJKLMNPQRSTUVWXYZ_", - salt: "FIXME: Make salt configurable", + salt: "bF4QzDjqV", min_len: 8 # Staging configuration for hCaptcha diff --git a/config/prod.exs b/config/prod.exs index 5d90f30b..7272be4a 100644 --- a/config/prod.exs +++ b/config/prod.exs @@ -10,12 +10,16 @@ import Config # which you should run after static files are built and # before starting your production server. config :keila, KeilaWeb.Endpoint, - url: [host: "example.com", port: 80], - cache_static_manifest: "priv/static/cache_manifest.json" + url: [host: "localhost"], + http: [port: 4000], + cache_static_manifest: "priv/static/cache_manifest.json", + server: true # Do not print debug messages in production config :logger, level: :info +config :keila, Keila.Repo, [] + # ## SSL Support # # To get SSL working, you will need to add the `https` key @@ -49,7 +53,3 @@ config :logger, level: :info # force_ssl: [hsts: true] # # Check `Plug.SSL` for all available options in `force_ssl`. - -# Finally import the config/prod.secret.exs which loads secrets -# and configuration from environment variables. -import_config "prod.secret.exs" diff --git a/config/runtime.exs b/config/runtime.exs index 6f2c1af1..3cdda780 100644 --- a/config/runtime.exs +++ b/config/runtime.exs @@ -1,11 +1,154 @@ import Config +require Logger +:ok == Application.ensure_started(:logger) -update_env = fn app, key, update_fn -> - value = update_fn.(Application.get_env(app, key)) - Application.put_env(app, key, value) +exit_from_exception = fn exception, message -> + Logger.error(exception.message) + Logger.error(message) + Logger.flush() + System.halt(1) +end + +maybe_to_int = fn + string when string not in [nil, ""] -> String.to_integer(string) + _ -> nil +end + +put_if_not_empty = fn + enumerable, key, value when value not in [nil, ""] -> put_in(enumerable, [key], value) + enumerable, _, _ -> enumerable end if config_env() == :prod do + # Database + try do + db_url = System.fetch_env!("DB_URL") + config(:keila, Keila.Repo, url: db_url) + rescue + e -> + exit_from_exception.(e, """ + You must provide the DB_URL environment variable in the format: + postgres://user:password/database + """) + end + + # System Mailer + try do + mailer_type = System.get_env("MAILER_TYPE") || "smtp" + + config = + case mailer_type do + "smtp" -> + host = System.fetch_env!("MAILER_SMTP_HOST") + user = System.fetch_env!("MAILER_SMTP_USER") + password = System.fetch_env!("MAILER_SMTP_PASSWORD") + port = System.get_env("MAILER_SMTP_PORT") |> maybe_to_int.() + + [relay: host, username: user, password: password] + |> put_if_not_empty.(:port, port) + end + + config(:keila, Keila.Mailer, config) + rescue + e -> + exit_from_exception.(e, """ + You must configure a mailer for system emails. + + Use the following environment variables: + - MAILER_TYPE (defaults to "smtp") + - MAILER_SMTP_HOST (required) + - MAILER_SMTP_USER (required) + - MAILER_SMTP_PASSWORD (required) + - MAILER_SMTP_PORT (optional, defaults to 587) + """) + end + + # hCaptcha + hcaptcha_site_key = System.get_env("HCAPTCHA_SITE_KEY") + hcaptcha_secret_key = System.get_env("HCAPTCHA_SECRET_KEY") + hcaptcha_url = System.get_env("HCAPTCHA_SECRET_KEY") + + if hcaptcha_site_key not in [nil, ""] and hcaptcha_secret_key not in [nil, ""] do + config = + [secret_key: hcaptcha_secret_key, site_key: hcaptcha_site_key] + |> put_if_not_empty.(:url, hcaptcha_url) + + config :keila, :hcaptcha, config + else + Logger.warn(""" + hCaptcha not configured. + Keila will fall back to using hCaptcha’s staging configuration. + + To configure hCaptcha, use the following environment variables: + + - HCAPTCHA_SITE_KEY + - HCAPTCHA_SECRET_KEY + - HCAPTCHA_URL (defaults to https://hcaptcha.com/siteverify) + """) + end + + # Secret Key Base + try do + secret_key_base = System.fetch_env!("SECRET_KEY_BASE") + + live_view_salt = + :crypto.hash(:sha384, secret_key_base <> "live_view_salt") |> Base.url_encode64() + + config(:keila, KeilaWeb.Endpoint, + secret_key_base: secret_key_base, + live_view: [signing_salt: live_view_salt] + ) + + hashid_salt = :crypto.hash(:sha384, secret_key_base <> "hashid_salt") |> Base.url_encode64() + config(:keila, :ids, salt: hashid_salt) + rescue + e -> + exit_from_exception.(e, """ + You must set SECRET_KEY_BASE. + + This should be a strong secret with a length + of at least 64 characters. + """) + end + + # Endpoint + url_host = System.get_env("URL_HOST") + url_port = System.get_env("URL_PORT") |> maybe_to_int.() + url_schema = System.get_env("URL_SCHEMA") + + url_schema = + cond do + url_schema not in [nil, "empty"] -> url_schema + url_port == 443 -> "https" + true -> "http" + end + + if url_host not in [nil, ""] do + config = + [host: url_host, scheme: url_schema] + |> put_if_not_empty.(:port, url_port) + + config(:keila, KeilaWeb.Endpoint, url: config) + else + Logger.warn(""" + You have not configured the application URL. Defaulting to http://localhost. + + Use the following environment variables: + - URL_HOST + - URL_PORT (defaults to 80) + - URL Schema (defaults to "https" for port 443, otherwise to "http") + """) + end + + port = System.get_env("PORT") |> maybe_to_int.() + + if not is_nil(port) do + config(:keila, KeilaWeb.Endpoint, http: [port: port]) + else + Logger.info(""" + PORT environment variable unset. Running on port 4000. + """) + end end if config_env() == :test do @@ -13,12 +156,6 @@ if config_env() == :test do if db_url do db_url = db_url <> "#{System.get_env("MIX_TEST_PARTITION")}" - update_env.(:keila, Keila.Repo, &Keyword.replace(&1, :url, db_url)) + config(:keila, Keila.Repo, url: db_url) end - - # username: "postgres", - # password: "postgres-keila-dev-pw", - # database: "keila_test#{System.get_env("MIX_TEST_PARTITION")}", - # hostname: "localhost", - # port: 54323, end diff --git a/config/test.exs b/config/test.exs index 425e03d2..b7a9b597 100644 --- a/config/test.exs +++ b/config/test.exs @@ -9,7 +9,9 @@ import Config config :keila, Keila.Repo, url: "ecto://postgres:postgres@localhost:5432/keila_test#{System.get_env("MIX_TEST_PARTITION")}", - pool: Ecto.Adapters.SQL.Sandbox + pool: Ecto.Adapters.SQL.Sandbox, + ownership_timeout: 60_000, + timeout: 60_000 # We don't run a server during test. If one is required, # you can enable the server option below.