diff --git a/config/.env.dev b/config/.env.dev index 056f3fcb0cf4..93dd0d087ec5 100644 --- a/config/.env.dev +++ b/config/.env.dev @@ -29,4 +29,6 @@ S3_ENDPOINT=http://localhost:10000 S3_EXPORTS_BUCKET=dev-exports S3_IMPORTS_BUCKET=dev-imports -VERIFICATION_ENABLED=false +VERIFICATION_ENABLED=true +DISABLE_REGISTRATION=false +ALLOWED_DOMAINS="plausible.com,example.com" diff --git a/config/.env.test b/config/.env.test index 8fe3862a767b..5f8d41cafed5 100644 --- a/config/.env.test +++ b/config/.env.test @@ -23,3 +23,4 @@ S3_REGION=us-east-1 S3_ENDPOINT=http://localhost:10000 S3_EXPORTS_BUCKET=test-exports S3_IMPORTS_BUCKET=test-imports +ALLOWED_DOMAINS="plausible.com,example.com" diff --git a/config/runtime.exs b/config/runtime.exs index 170f39933d45..5d4786711f5b 100644 --- a/config/runtime.exs +++ b/config/runtime.exs @@ -293,6 +293,8 @@ secure_cookie = license_key = get_var_from_path_or_env(config_dir, "LICENSE_KEY", "") +allowed_domains = get_var_from_path_or_env(config_dir, "ALLOWED_DOMAINS", "") + config :plausible, environment: env, mailer_email: mailer_email, @@ -301,7 +303,8 @@ config :plausible, custom_script_name: custom_script_name, log_failed_login_attempts: log_failed_login_attempts, license_key: license_key, - data_dir: data_dir + data_dir: data_dir, + allowed_domains: allowed_domains config :plausible, :selfhost, enable_email_verification: enable_email_verification, diff --git a/lib/plausible_web/controllers/auth_controller.ex b/lib/plausible_web/controllers/auth_controller.ex index c9eff5765c7b..449e9da22cf4 100644 --- a/lib/plausible_web/controllers/auth_controller.ex +++ b/lib/plausible_web/controllers/auth_controller.ex @@ -59,7 +59,8 @@ defmodule PlausibleWeb.AuthController do end def register(conn, %{"user" => %{"email" => email, "password" => password}}) do - with {:ok, user} <- login_user(conn, email, password) do + with {:domain_allowed, true} <- {:domain_allowed, domain_allowed?(email)}, + {:ok, user} <- login_user(conn, email, password) do conn = set_user_session(conn, user) if user.email_verified do @@ -68,6 +69,26 @@ defmodule PlausibleWeb.AuthController do Auth.EmailVerification.issue_code(user) redirect(conn, to: Routes.auth_path(conn, :activate_form)) end + else + {:domain_allowed, false} -> + render(conn, "login_form.html", + error: "Registration not supported for your email domain.", + layout: {PlausibleWeb.LayoutView, "focus.html"} + ) + + conn -> + conn + end + end + + defp domain_allowed?(email) do + allowed_domains = + Application.get_env(:plausible, :allowed_domains) + |> String.split(",") + + case String.split(email, "@") do + [_, domain] -> domain in allowed_domains or allowed_domains == [""] + _ -> false end end diff --git a/mix.exs b/mix.exs index 19b023a42717..31f05c04e42a 100644 --- a/mix.exs +++ b/mix.exs @@ -83,7 +83,7 @@ defmodule Plausible.MixProject do {:envy, "~> 1.1.1"}, {:eqrcode, "~> 0.1.10"}, {:ex_machina, "~> 2.3", only: [:dev, :test, :ce_dev, :ce_test]}, - {:excoveralls, "~> 0.10", only: :test}, + {:excoveralls, "~> 0.10", only: [:test, :ce_test]}, {:finch, "~> 0.17.0"}, {:floki, "~> 0.35.0"}, {:fun_with_flags, "~> 1.11.0"}, diff --git a/test/plausible_web/controllers/auth_controller_test.exs b/test/plausible_web/controllers/auth_controller_test.exs index 73b5138d3dd3..b4e20d772de3 100644 --- a/test/plausible_web/controllers/auth_controller_test.exs +++ b/test/plausible_web/controllers/auth_controller_test.exs @@ -92,6 +92,48 @@ defmodule PlausibleWeb.AuthControllerTest do assert get_session(conn, :current_user_id) end + + test "domain not allowed", %{conn: conn} do + Repo.insert!( + User.new(%{ + name: "Jane Doe", + email: "user@not.allowed", + password: "very-secret-and-very-long-123", + password_confirmation: "very-secret-and-very-long-123" + }) + ) + + conn = + post(conn, "/register", + user: %{ + email: "user@not.allowed", + password: "very-secret-and-very-long-123" + } + ) + + refute get_session(conn, :current_user_id) + end + + test "email without @", %{conn: conn} do + Repo.insert!( + User.new(%{ + name: "Jane Doe", + email: "usernot.allowed", + password: "very-secret-and-very-long-123", + password_confirmation: "very-secret-and-very-long-123" + }) + ) + + conn = + post(conn, "/register", + user: %{ + email: "usernot.allowed", + password: "very-secret-and-very-long-123" + } + ) + + refute get_session(conn, :current_user_id) + end end describe "GET /register/invitations/:invitation_id" do