diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile index e7b95066b..9d7457811 100644 --- a/.devcontainer/Dockerfile +++ b/.devcontainer/Dockerfile @@ -16,6 +16,7 @@ RUN echo "APT::Install-Recommends 0;" >> /etc/apt/apt.conf.d/01norecommends \ wget \ net-tools \ wireguard \ + inotify-tools \ ca-certificates \ build-essential \ python python-pip \ @@ -79,9 +80,7 @@ ENV HOME=/home/$USERNAME \ ASDF_DATA_DIR="/opt/asdf-data" RUN echo '\n. /opt/asdf/asdf.sh' >> ~/.bashrc \ - && echo '\n. /opt/asdf/completions/asdf.bash' >> ~/.bashrc \ - && echo '\nexport LC_ALL="C.UTF-8"' >> ~/.bashrc \ - && echo '\nexport TZ="UTC"' >> ~/.bashrc + && echo '\n. /opt/asdf/completions/asdf.bash' >> ~/.bashrc SHELL ["/bin/bash", "-ic"] @@ -97,11 +96,15 @@ RUN asdf install erlang # No order to asdf, so elixir error without Erlang RUN asdf install +RUN mix local.hex --force +RUN mix local.rebar --force + VOLUME ["${ASDF_DATA_DIR}"] # Pre-commit install with deps RUN pip install setuptools wheel RUN pip install pre-commit -RUN echo 'export PATH="$HOME/.local/bin:$PATH"' >> ~/.bashrc + +ENV PATH=${HOME}/.local/bin:/opt/asdf-data/shims:/opt/asdf/bin:${PATH} CMD ["/bin/bash"] diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index f18cea521..5f8d39c8b 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -13,12 +13,13 @@ // Add the IDs of extensions you want installed when the container is created. "extensions": [ - "jakebecker.elixir-ls" + "jakebecker.elixir-ls", + "phoenixframework.phoenix" ], // Use 'forwardPorts' to make a list of ports inside the container available locally. // This can be used to network with other containers or with the host. - "forwardPorts": [4000, 4001, 4002, 5432], + "forwardPorts": [4000, 5432], // Use 'postCreateCommand' to run commands after the container is created. // "postCreateCommand": "mix deps.get" diff --git a/.env.sample b/.env.sample new file mode 100644 index 000000000..25c651564 --- /dev/null +++ b/.env.sample @@ -0,0 +1,12 @@ +MIX_ENV=dev +# This is a sample .env file. Update and add variables in here as needed, and +# rename to `.env` + +# Set the EXTERNAL_URL if it's not localhost:4000 +# EXTERNAL_URL=https:///local.dev + +LOCAL_AUTH_ENABLED=true + +# Set PROXY_FORWARDED to true if you're running this behind a proxy or using +# GitHub codespaces +PROXY_FORWARDED=true diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 840b55453..e2d9b5a0a 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -65,6 +65,19 @@ We use [pre-commit](https://pre-commit.com) to catch any static analysis issues before code is committed. Install with Homebrew: `brew install pre-commit` or pip: `pip install pre-commit`. +### The ENV file + +In order to save local environment variables in your development environment, +you can use a `.env` file in the project root directory to store any commonly +used settings. + +.env.sample will give you an example of what this file may look like. + +Run the following command to 'source' the environment variables from .env on +`mix start` + +`env $(cat .env | grep -v \# | xargs) mix start` + ## Bootstrapping Assuming you've completed the steps above, you should be able to get everything @@ -96,8 +109,26 @@ mix start ``` At this point you should be able to sign in to -[http://localhost:4000](http://localhost:4000) with email `factory@factory` and -password `factory`. +[http://localhost:4000](http://localhost:4000) with email `firezone@localhost` and +password `firezone1234`. + +## Running this inside a Devcontainer + +You can run this using Github Codespaces or your own devcontainer using Docker. + +On GitHub Codespaces, follow the instructions above but start the server with +PROXY_FORWARDED enabled and pass in your Codespace external url: + +`PROXY_FORWARDED=true EXTERNAL_URL=[your_devcontainer_url] MIX_ENV=dev mix start` + +or using the `.env` file + +`env $(cat .env | grep -v \# | xargs) mix start` + +On Github Codespaces you can find your EXTERNAL_URL by issuing the following +command in the terminal: + +`echo "https://${CODESPACE_NAME}-4000.githubpreview.dev"` # Reporting Bugs We appreciate any and all bug reports. diff --git a/apps/fz_http/lib/fz_http_web/endpoint.ex b/apps/fz_http/lib/fz_http_web/endpoint.ex index 1188b90ff..577347739 100644 --- a/apps/fz_http/lib/fz_http_web/endpoint.ex +++ b/apps/fz_http/lib/fz_http_web/endpoint.ex @@ -2,6 +2,10 @@ defmodule FzHttpWeb.Endpoint do use Phoenix.Endpoint, otp_app: :fz_http alias FzHttpWeb.Session + if Application.get_env(:fz_http, FzHttpWeb.Endpoint, :proxy_forwarded) do + plug Plug.RewriteOn, [:x_forwarded_host, :x_forwarded_port, :x_forwarded_proto] + end + if Application.get_env(:fz_http, :sql_sandbox) do plug Phoenix.Ecto.SQL.Sandbox end @@ -36,7 +40,15 @@ defmodule FzHttpWeb.Endpoint do # Code reloading can be explicitly enabled under the # :code_reloader configuration of your endpoint. if code_reloading? do - socket "/phoenix/live_reload/socket", Phoenix.LiveReloader.Socket + socket "/phoenix/live_reload/socket", Phoenix.LiveReloader.Socket, + websocket: [ + connect_info: [ + session: {Session, :options, []} + ], + # XXX: csrf token should prevent CSWH but double check + check_origin: false + ] + plug Phoenix.LiveReloader plug Phoenix.CodeReloader plug Phoenix.Ecto.CheckRepoStatus, otp_app: :fz_http diff --git a/config/config.exs b/config/config.exs index d224f7d86..9b093c94f 100644 --- a/config/config.exs +++ b/config/config.exs @@ -104,7 +104,8 @@ external_url = "http://localhost:4000" config :fz_http, FzHttpWeb.Endpoint, url: [host: host, port: port, scheme: scheme, path: path], render_errors: [view: FzHttpWeb.ErrorView, accepts: ~w(html json)], - pubsub_server: FzHttp.PubSub + pubsub_server: FzHttp.PubSub, + proxy_forwarded: false # Configures Elixir's Logger config :logger, :console, diff --git a/config/dev.exs b/config/dev.exs index ba4ac7797..f2c394576 100644 --- a/config/dev.exs +++ b/config/dev.exs @@ -1,7 +1,5 @@ import Config -alias FzCommon.ConfigHelpers - # Configure your database if url = System.get_env("DATABASE_URL") do config :fz_http, FzHttp.Repo, diff --git a/config/releases.exs b/config/releases.exs deleted file mode 100644 index 63700aee9..000000000 --- a/config/releases.exs +++ /dev/null @@ -1,220 +0,0 @@ -# In this file, we load production configuration and secrets -# from environment variables. You can also hardcode secrets, -# although such is generally not recommended and you have to -# remember to add this file to your .gitignore. -import Config -alias FzCommon.{CLI, FzInteger, FzString} - -# For releases, require that all these are set -database_name = System.fetch_env!("DATABASE_NAME") -database_user = System.fetch_env!("DATABASE_USER") -database_host = System.fetch_env!("DATABASE_HOST") -database_port = String.to_integer(System.fetch_env!("DATABASE_PORT")) -database_pool = String.to_integer(System.fetch_env!("DATABASE_POOL")) -database_ssl = FzString.to_boolean(System.fetch_env!("DATABASE_SSL")) -database_ssl_opts = Jason.decode!(System.fetch_env!("DATABASE_SSL_OPTS")) -database_parameters = Jason.decode!(System.fetch_env!("DATABASE_PARAMETERS")) -phoenix_port = String.to_integer(System.fetch_env!("PHOENIX_PORT")) -admin_email = System.fetch_env!("ADMIN_EMAIL") -default_admin_password = System.fetch_env!("DEFAULT_ADMIN_PASSWORD") -wireguard_interface_name = System.fetch_env!("WIREGUARD_INTERFACE_NAME") -wireguard_port = String.to_integer(System.fetch_env!("WIREGUARD_PORT")) -nft_path = System.fetch_env!("NFT_PATH") -wg_path = System.fetch_env!("WG_PATH") -egress_interface = System.fetch_env!("EGRESS_INTERFACE") -wireguard_public_key = System.fetch_env!("WIREGUARD_PUBLIC_KEY") -wireguard_psk_dir = System.fetch_env!("WIREGUARD_PSK_DIR") -wireguard_dns = System.fetch_env!("WIREGUARD_DNS") -wireguard_allowed_ips = System.fetch_env!("WIREGUARD_ALLOWED_IPS") -wireguard_persistent_keepalive = System.fetch_env!("WIREGUARD_PERSISTENT_KEEPALIVE") -wireguard_ipv4_enabled = FzString.to_boolean(System.fetch_env!("WIREGUARD_IPV4_ENABLED")) -wireguard_ipv4_network = System.fetch_env!("WIREGUARD_IPV4_NETWORK") -wireguard_ipv4_address = System.fetch_env!("WIREGUARD_IPV4_ADDRESS") -wireguard_ipv6_enabled = FzString.to_boolean(System.fetch_env!("WIREGUARD_IPV6_ENABLED")) -wireguard_ipv6_network = System.fetch_env!("WIREGUARD_IPV6_NETWORK") -wireguard_ipv6_address = System.fetch_env!("WIREGUARD_IPV6_ADDRESS") -wireguard_mtu = System.fetch_env!("WIREGUARD_MTU") -wireguard_endpoint = System.fetch_env!("WIREGUARD_ENDPOINT") -telemetry_enabled = FzString.to_boolean(System.fetch_env!("TELEMETRY_ENABLED")) -telemetry_id = System.fetch_env!("TELEMETRY_ID") -guardian_secret_key = System.fetch_env!("GUARDIAN_SECRET_KEY") -external_url = System.fetch_env!("EXTERNAL_URL") - -allow_unprivileged_device_management = - FzString.to_boolean(System.fetch_env!("ALLOW_UNPRIVILEGED_DEVICE_MANAGEMENT")) - -# Local auth -local_auth_enabled = FzString.to_boolean(System.fetch_env!("LOCAL_AUTH_ENABLED")) - -# Okta auth -okta_auth_enabled = FzString.to_boolean(System.fetch_env!("OKTA_AUTH_ENABLED")) -okta_client_id = System.get_env("OKTA_CLIENT_ID") -okta_client_secret = System.get_env("OKTA_CLIENT_SECRET") -okta_site = System.get_env("OKTA_SITE") - -# Google auth -google_auth_enabled = FzString.to_boolean(System.fetch_env!("GOOGLE_AUTH_ENABLED")) -google_client_id = System.get_env("GOOGLE_CLIENT_ID") -google_client_secret = System.get_env("GOOGLE_CLIENT_SECRET") -google_redirect_uri = System.get_env("GOOGLE_REDIRECT_URI") - -max_devices_per_user = - System.fetch_env!("MAX_DEVICES_PER_USER") - |> String.to_integer() - |> FzInteger.clamp(0, 100) - -telemetry_module = - if telemetry_enabled do - FzCommon.Telemetry - else - FzCommon.MockTelemetry - end - -connectivity_checks_enabled = - FzString.to_boolean(System.fetch_env!("CONNECTIVITY_CHECKS_ENABLED")) && - System.get_env("CI") != "true" - -connectivity_checks_interval = - System.fetch_env!("CONNECTIVITY_CHECKS_INTERVAL") - |> String.to_integer() - |> FzInteger.clamp(60, 86_400) - -# secrets -encryption_key = System.fetch_env!("DATABASE_ENCRYPTION_KEY") -secret_key_base = System.fetch_env!("SECRET_KEY_BASE") -live_view_signing_salt = System.fetch_env!("LIVE_VIEW_SIGNING_SALT") -cookie_signing_salt = System.fetch_env!("COOKIE_SIGNING_SALT") - -# Password is not needed if using bundled PostgreSQL, so use nil if it's not set. -database_password = System.get_env("DATABASE_PASSWORD") - -# XXX: Using to_atom here because this is trusted input and to_existing_atom -# won't work because we won't know the keys ahead of time. -ssl_opts = Keyword.new(database_ssl_opts, fn {k, v} -> {String.to_atom(k), v} end) -parameters = Keyword.new(database_parameters, fn {k, v} -> {String.to_atom(k), v} end) - -# Database configuration -connect_opts = [ - database: database_name, - username: database_user, - hostname: database_host, - port: database_port, - pool_size: database_pool, - ssl: database_ssl, - ssl_opts: ssl_opts, - parameters: parameters, - queue_target: 500 -] - -if database_password do - config(:fz_http, FzHttp.Repo, connect_opts ++ [password: database_password]) -else - config(:fz_http, FzHttp.Repo, connect_opts) -end - -config :fz_http, FzHttp.Vault, - ciphers: [ - default: { - Cloak.Ciphers.AES.GCM, - # In AES.GCM, it is important to specify 12-byte IV length for - # interoperability with other encryption software. See this GitHub - # issue for more details: - # https://github.com/danielberkompas/cloak/issues/93 - # - # In Cloak 2.0, this will be the default iv length for AES.GCM. - tag: "AES.GCM.V1", key: Base.decode64!(encryption_key), iv_length: 12 - } - ] - -%{host: host, path: path, port: port, scheme: scheme} = URI.parse(external_url) - -config :fz_http, FzHttpWeb.Endpoint, - http: [ip: {127, 0, 0, 1}, port: phoenix_port], - url: [host: host, scheme: scheme, port: port, path: path], - check_origin: ["//127.0.0.1", "//localhost", "//#{host}"], - server: true, - secret_key_base: secret_key_base, - live_view: [ - signing_salt: live_view_signing_salt - ] - -config :fz_wall, - nft_path: nft_path, - egress_interface: egress_interface, - wireguard_interface_name: wireguard_interface_name, - cli: FzWall.CLI.Live - -config :fz_vpn, - wireguard_psk_dir: wireguard_psk_dir, - wireguard_public_key: wireguard_public_key, - wireguard_interface_name: wireguard_interface_name, - wireguard_port: wireguard_port, - cli: FzVpn.CLI.Live - -# Guardian configuration -config :fz_http, FzHttpWeb.Authentication, - issuer: "fz_http", - secret_key: guardian_secret_key - -config :fz_http, - allow_unprivileged_device_management: allow_unprivileged_device_management, - max_devices_per_user: max_devices_per_user, - local_auth_enabled: local_auth_enabled, - okta_auth_enabled: okta_auth_enabled, - google_auth_enabled: google_auth_enabled, - wireguard_dns: wireguard_dns, - wireguard_allowed_ips: wireguard_allowed_ips, - wireguard_persistent_keepalive: wireguard_persistent_keepalive, - wireguard_ipv4_enabled: wireguard_ipv4_enabled, - wireguard_ipv4_network: wireguard_ipv4_network, - wireguard_ipv4_address: wireguard_ipv4_address, - wireguard_ipv6_enabled: wireguard_ipv6_enabled, - wireguard_ipv6_network: wireguard_ipv6_network, - wireguard_ipv6_address: wireguard_ipv6_address, - wireguard_mtu: wireguard_mtu, - wireguard_endpoint: wireguard_endpoint, - telemetry_module: telemetry_module, - telemetry_id: telemetry_id, - connectivity_checks_enabled: connectivity_checks_enabled, - connectivity_checks_interval: connectivity_checks_interval, - admin_email: admin_email, - default_admin_password: default_admin_password - -# Configure strategies -identity_strategy = - {:identity, - {Ueberauth.Strategy.Identity, - [ - callback_methods: ["POST"], - callback_url: "#{external_url}/auth/identity/callback", - uid_field: :email - ]}} - -okta_strategy = {:okta, {Ueberauth.Strategy.Okta, []}} -google_strategy = {:google, {Ueberauth.Strategy.Google, []}} - -providers = - [ - {local_auth_enabled, identity_strategy}, - {google_auth_enabled, google_strategy}, - {okta_auth_enabled, okta_strategy} - ] - |> Enum.filter(fn {key, _val} -> key end) - |> Enum.map(fn {_key, val} -> val end) - -config :ueberauth, Ueberauth, providers: providers - -# Configure OAuth portion of enabled strategies -if okta_auth_enabled do - config :ueberauth, Ueberauth.Strategy.Okta.OAuth, - client_id: okta_client_id, - client_secret: okta_client_secret, - site: okta_site -end - -if google_auth_enabled do - config :ueberauth, Ueberauth.Strategy.Google.OAuth, - client_id: google_client_id, - client_secret: google_client_secret, - redirect_uri: google_redirect_uri -end diff --git a/config/runtime.exs b/config/runtime.exs new file mode 100644 index 000000000..677f20af4 --- /dev/null +++ b/config/runtime.exs @@ -0,0 +1,241 @@ +# In this file, we load configuration and secrets +# from environment variables. You can also hardcode secrets, +# although such is generally not recommended and you have to +# remember to add this file to your .gitignore. + +import Config +alias FzCommon.{CLI, FzInteger, FzString} + +# Optional config across all envs + +# Defaults to localhost:4000. +external_url = System.get_env("EXTERNAL_URL") || "http://localhost:4000" + +if config_env() == :prod do + # Errors if not set in production + System.fetch_env!("EXTERNAL_URL") +end + +# Enable Forwarded headers, e.g 'X-FORWARDED-HOST' +proxy_forwarded = FzString.to_boolean(System.get_env("PROXY_FORWARDED") || "false") + +%{host: host, path: path, port: port, scheme: scheme} = URI.parse(external_url) + +config :fz_http, FzHttpWeb.Endpoint, + url: [host: host, scheme: scheme, port: port, path: path], + check_origin: ["//127.0.0.1", "//localhost", "//#{host}"], + proxy_forwarded: proxy_forwarded + +# Formerly releases.exs - Only evaluated in production +if config_env() == :prod do + # For releases, require that all these are set + database_name = System.fetch_env!("DATABASE_NAME") + database_user = System.fetch_env!("DATABASE_USER") + database_host = System.fetch_env!("DATABASE_HOST") + database_port = String.to_integer(System.fetch_env!("DATABASE_PORT")) + database_pool = String.to_integer(System.fetch_env!("DATABASE_POOL")) + database_ssl = FzString.to_boolean(System.fetch_env!("DATABASE_SSL")) + database_ssl_opts = Jason.decode!(System.fetch_env!("DATABASE_SSL_OPTS")) + database_parameters = Jason.decode!(System.fetch_env!("DATABASE_PARAMETERS")) + phoenix_port = String.to_integer(System.fetch_env!("PHOENIX_PORT")) + admin_email = System.fetch_env!("ADMIN_EMAIL") + default_admin_password = System.fetch_env!("DEFAULT_ADMIN_PASSWORD") + wireguard_interface_name = System.fetch_env!("WIREGUARD_INTERFACE_NAME") + wireguard_port = String.to_integer(System.fetch_env!("WIREGUARD_PORT")) + nft_path = System.fetch_env!("NFT_PATH") + wg_path = System.fetch_env!("WG_PATH") + egress_interface = System.fetch_env!("EGRESS_INTERFACE") + wireguard_public_key = System.fetch_env!("WIREGUARD_PUBLIC_KEY") + wireguard_psk_dir = System.fetch_env!("WIREGUARD_PSK_DIR") + wireguard_dns = System.fetch_env!("WIREGUARD_DNS") + wireguard_allowed_ips = System.fetch_env!("WIREGUARD_ALLOWED_IPS") + wireguard_persistent_keepalive = System.fetch_env!("WIREGUARD_PERSISTENT_KEEPALIVE") + wireguard_ipv4_enabled = FzString.to_boolean(System.fetch_env!("WIREGUARD_IPV4_ENABLED")) + wireguard_ipv4_network = System.fetch_env!("WIREGUARD_IPV4_NETWORK") + wireguard_ipv4_address = System.fetch_env!("WIREGUARD_IPV4_ADDRESS") + wireguard_ipv6_enabled = FzString.to_boolean(System.fetch_env!("WIREGUARD_IPV6_ENABLED")) + wireguard_ipv6_network = System.fetch_env!("WIREGUARD_IPV6_NETWORK") + wireguard_ipv6_address = System.fetch_env!("WIREGUARD_IPV6_ADDRESS") + wireguard_mtu = System.fetch_env!("WIREGUARD_MTU") + wireguard_endpoint = System.fetch_env!("WIREGUARD_ENDPOINT") + telemetry_enabled = FzString.to_boolean(System.fetch_env!("TELEMETRY_ENABLED")) + telemetry_id = System.fetch_env!("TELEMETRY_ID") + guardian_secret_key = System.fetch_env!("GUARDIAN_SECRET_KEY") + + allow_unprivileged_device_management = + FzString.to_boolean(System.fetch_env!("ALLOW_UNPRIVILEGED_DEVICE_MANAGEMENT")) + + # Local auth + local_auth_enabled = FzString.to_boolean(System.fetch_env!("LOCAL_AUTH_ENABLED")) + + # Okta auth + okta_auth_enabled = FzString.to_boolean(System.fetch_env!("OKTA_AUTH_ENABLED")) + okta_client_id = System.get_env("OKTA_CLIENT_ID") + okta_client_secret = System.get_env("OKTA_CLIENT_SECRET") + okta_site = System.get_env("OKTA_SITE") + + # Google auth + google_auth_enabled = FzString.to_boolean(System.fetch_env!("GOOGLE_AUTH_ENABLED")) + google_client_id = System.get_env("GOOGLE_CLIENT_ID") + google_client_secret = System.get_env("GOOGLE_CLIENT_SECRET") + google_redirect_uri = System.get_env("GOOGLE_REDIRECT_URI") + + max_devices_per_user = + System.fetch_env!("MAX_DEVICES_PER_USER") + |> String.to_integer() + |> FzInteger.clamp(0, 100) + + telemetry_module = + if telemetry_enabled do + FzCommon.Telemetry + else + FzCommon.MockTelemetry + end + + connectivity_checks_enabled = + FzString.to_boolean(System.fetch_env!("CONNECTIVITY_CHECKS_ENABLED")) && + System.get_env("CI") != "true" + + connectivity_checks_interval = + System.fetch_env!("CONNECTIVITY_CHECKS_INTERVAL") + |> String.to_integer() + |> FzInteger.clamp(60, 86_400) + + # secrets + encryption_key = System.fetch_env!("DATABASE_ENCRYPTION_KEY") + secret_key_base = System.fetch_env!("SECRET_KEY_BASE") + live_view_signing_salt = System.fetch_env!("LIVE_VIEW_SIGNING_SALT") + cookie_signing_salt = System.fetch_env!("COOKIE_SIGNING_SALT") + + # Password is not needed if using bundled PostgreSQL, so use nil if it's not set. + database_password = System.get_env("DATABASE_PASSWORD") + + # XXX: Using to_atom here because this is trusted input and to_existing_atom + # won't work because we won't know the keys ahead of time. + ssl_opts = Keyword.new(database_ssl_opts, fn {k, v} -> {String.to_atom(k), v} end) + parameters = Keyword.new(database_parameters, fn {k, v} -> {String.to_atom(k), v} end) + + # Database configuration + connect_opts = [ + database: database_name, + username: database_user, + hostname: database_host, + port: database_port, + pool_size: database_pool, + ssl: database_ssl, + ssl_opts: ssl_opts, + parameters: parameters, + queue_target: 500 + ] + + if database_password do + config(:fz_http, FzHttp.Repo, connect_opts ++ [password: database_password]) + else + config(:fz_http, FzHttp.Repo, connect_opts) + end + + config :fz_http, FzHttp.Vault, + ciphers: [ + default: { + Cloak.Ciphers.AES.GCM, + # In AES.GCM, it is important to specify 12-byte IV length for + # interoperability with other encryption software. See this GitHub + # issue for more details: + # https://github.com/danielberkompas/cloak/issues/93 + # + # In Cloak 2.0, this will be the default iv length for AES.GCM. + tag: "AES.GCM.V1", key: Base.decode64!(encryption_key), iv_length: 12 + } + ] + + config :fz_http, FzHttpWeb.Endpoint, + http: [ip: {127, 0, 0, 1}, port: phoenix_port], + server: true, + secret_key_base: secret_key_base, + live_view: [ + signing_salt: live_view_signing_salt + ] + + config :fz_wall, + nft_path: nft_path, + egress_interface: egress_interface, + wireguard_interface_name: wireguard_interface_name, + cli: FzWall.CLI.Live + + config :fz_vpn, + wireguard_psk_dir: wireguard_psk_dir, + wireguard_public_key: wireguard_public_key, + wireguard_interface_name: wireguard_interface_name, + wireguard_port: wireguard_port, + cli: FzVpn.CLI.Live + + # Guardian configuration + config :fz_http, FzHttpWeb.Authentication, + issuer: "fz_http", + secret_key: guardian_secret_key + + config :fz_http, + wg_path: wg_path, + cookie_signing_salt: cookie_signing_salt, + allow_unprivileged_device_management: allow_unprivileged_device_management, + max_devices_per_user: max_devices_per_user, + local_auth_enabled: local_auth_enabled, + okta_auth_enabled: okta_auth_enabled, + google_auth_enabled: google_auth_enabled, + wireguard_dns: wireguard_dns, + wireguard_allowed_ips: wireguard_allowed_ips, + wireguard_persistent_keepalive: wireguard_persistent_keepalive, + wireguard_ipv4_enabled: wireguard_ipv4_enabled, + wireguard_ipv4_network: wireguard_ipv4_network, + wireguard_ipv4_address: wireguard_ipv4_address, + wireguard_ipv6_enabled: wireguard_ipv6_enabled, + wireguard_ipv6_network: wireguard_ipv6_network, + wireguard_ipv6_address: wireguard_ipv6_address, + wireguard_mtu: wireguard_mtu, + wireguard_endpoint: wireguard_endpoint, + telemetry_module: telemetry_module, + telemetry_id: telemetry_id, + connectivity_checks_enabled: connectivity_checks_enabled, + connectivity_checks_interval: connectivity_checks_interval, + admin_email: admin_email, + default_admin_password: default_admin_password + + # Configure strategies + identity_strategy = + {:identity, + {Ueberauth.Strategy.Identity, + [ + callback_methods: ["POST"], + callback_url: "#{external_url}/auth/identity/callback", + uid_field: :email + ]}} + + okta_strategy = {:okta, {Ueberauth.Strategy.Okta, []}} + google_strategy = {:google, {Ueberauth.Strategy.Google, []}} + + providers = + [ + {local_auth_enabled, identity_strategy}, + {google_auth_enabled, google_strategy}, + {okta_auth_enabled, okta_strategy} + ] + |> Enum.filter(fn {key, _val} -> key end) + |> Enum.map(fn {_key, val} -> val end) + + config :ueberauth, Ueberauth, providers: providers + + # Configure OAuth portion of enabled strategies + if okta_auth_enabled do + config :ueberauth, Ueberauth.Strategy.Okta.OAuth, + client_id: okta_client_id, + client_secret: okta_client_secret, + site: okta_site + end + + if google_auth_enabled do + config :ueberauth, Ueberauth.Strategy.Google.OAuth, + client_id: google_client_id, + client_secret: google_client_secret, + redirect_uri: google_redirect_uri + end +end