diff --git a/lib/algora_web/live/onboarding/dev.ex b/lib/algora_web/live/onboarding/dev.ex index 10d217c01..3da5ec06c 100644 --- a/lib/algora_web/live/onboarding/dev.ex +++ b/lib/algora_web/live/onboarding/dev.ex @@ -187,21 +187,29 @@ defmodule AlgoraWeb.Onboarding.DevLive do @impl true def handle_event("send_signup_code", %{"user" => %{"email" => email}}, socket) do - {secret, code} = AlgoraWeb.UserAuth.generate_totp() + rate_limit_key = socket.assigns.ip_address - changeset = User.signup_changeset(%User{}, %{}) + case Algora.RateLimit.hit("send_otp:#{rate_limit_key}", to_timeout(minute: 1), 3) do + {:allow, _} -> + {secret, code} = AlgoraWeb.UserAuth.generate_totp() - case Algora.Accounts.deliver_totp_signup_email(email, code) do - {:ok, _id} -> - {:noreply, - socket - |> LocalStore.assign_cached(:secret, secret) - |> LocalStore.assign_cached(:email, email) - |> assign(:signup_form, to_form(changeset))} + changeset = User.signup_changeset(%User{}, %{}) + + case Algora.Accounts.deliver_totp_signup_email(email, code) do + {:ok, _id} -> + {:noreply, + socket + |> LocalStore.assign_cached(:secret, secret) + |> LocalStore.assign_cached(:email, email) + |> assign(:signup_form, to_form(changeset))} + + {:error, reason} -> + Logger.error("Failed to send signup code to #{email}: #{inspect(reason)}") + {:noreply, put_flash(socket, :error, "We had trouble sending mail to #{email}. Please try again")} + end - {:error, reason} -> - Logger.error("Failed to send signup code to #{email}: #{inspect(reason)}") - {:noreply, put_flash(socket, :error, "We had trouble sending mail to #{email}. Please try again")} + {:deny, _} -> + {:noreply, put_flash(socket, :error, "Too many requests. Please try again later.")} end end diff --git a/lib/algora_web/live/org/dashboard_live.ex b/lib/algora_web/live/org/dashboard_live.ex index 7c4ee4f00..a33962751 100644 --- a/lib/algora_web/live/org/dashboard_live.ex +++ b/lib/algora_web/live/org/dashboard_live.ex @@ -792,21 +792,29 @@ defmodule AlgoraWeb.Org.DashboardLive do @impl true def handle_event("send_login_code", %{"user" => %{"email" => email}}, socket) do - {secret, code} = AlgoraWeb.UserAuth.generate_totp() + rate_limit_key = socket.assigns.ip_address - changeset = User.login_changeset(%User{}, %{}) + case Algora.RateLimit.hit("send_otp:#{rate_limit_key}", to_timeout(minute: 1), 3) do + {:allow, _} -> + {secret, code} = AlgoraWeb.UserAuth.generate_totp() - case Accounts.deliver_totp_signup_email(email, code) do - {:ok, _id} -> - {:noreply, - socket - |> assign(:secret, secret) - |> assign(:email, email) - |> assign_login_form(changeset)} + changeset = User.login_changeset(%User{}, %{}) + + case Accounts.deliver_totp_signup_email(email, code) do + {:ok, _id} -> + {:noreply, + socket + |> assign(:secret, secret) + |> assign(:email, email) + |> assign_login_form(changeset)} + + {:error, reason} -> + Logger.error("Failed to send login code to #{email}: #{inspect(reason)}") + {:noreply, put_flash(socket, :error, "We had trouble sending mail to #{email}. Please try again")} + end - {:error, reason} -> - Logger.error("Failed to send login code to #{email}: #{inspect(reason)}") - {:noreply, put_flash(socket, :error, "We had trouble sending mail to #{email}. Please try again")} + {:deny, _} -> + {:noreply, put_flash(socket, :error, "Too many requests. Please try again later.")} end end diff --git a/lib/algora_web/live/sign_in_live.ex b/lib/algora_web/live/sign_in_live.ex index ab71480d4..9315f7a81 100644 --- a/lib/algora_web/live/sign_in_live.ex +++ b/lib/algora_web/live/sign_in_live.ex @@ -263,21 +263,29 @@ defmodule AlgoraWeb.SignInLive do @impl true def handle_event("send_login_code", %{"user" => %{"email" => email}}, socket) do - {secret, code} = AlgoraWeb.UserAuth.generate_totp() + rate_limit_key = socket.assigns.ip_address - changeset = User.login_changeset(%User{}, %{}) + case Algora.RateLimit.hit("send_otp:#{rate_limit_key}", to_timeout(minute: 1), 3) do + {:allow, _} -> + {secret, code} = AlgoraWeb.UserAuth.generate_totp() - case Accounts.deliver_totp_signup_email(email, code) do - {:ok, _id} -> - {:noreply, - socket - |> LocalStore.assign_cached(:secret, secret) - |> LocalStore.assign_cached(:email, email) - |> assign_form(changeset)} - - {:error, reason} -> - Logger.error("Failed to send login code to #{email}: #{inspect(reason)}") - {:noreply, put_flash(socket, :error, "We had trouble sending mail to #{email}. Please try again")} + changeset = User.login_changeset(%User{}, %{}) + + case Accounts.deliver_totp_signup_email(email, code) do + {:ok, _id} -> + {:noreply, + socket + |> LocalStore.assign_cached(:secret, secret) + |> LocalStore.assign_cached(:email, email) + |> assign_form(changeset)} + + {:error, reason} -> + Logger.error("Failed to send login code to #{email}: #{inspect(reason)}") + {:noreply, put_flash(socket, :error, "We had trouble sending mail to #{email}. Please try again")} + end + + {:deny, _} -> + {:noreply, put_flash(socket, :error, "Too many requests. Please try again later.")} end end