mirror of
https://github.com/plausible/analytics.git
synced 2024-11-23 11:12:15 +03:00
Add HCaptcha support (#304)
* Add HCaptcha support * Actually verify password reset requests * Fix password request when captcha not configured * Add configuration for prod release
This commit is contained in:
parent
4aa4dfdcaf
commit
9feda6a3d3
@ -184,6 +184,10 @@ config :plausible, :custom_domain_server,
|
||||
config :plausible, PlausibleWeb.Firewall,
|
||||
blocklist: System.get_env("IP_BLOCKLIST", "") |> String.split(",") |> Enum.map(&String.trim/1)
|
||||
|
||||
config :plausible, :hcaptcha,
|
||||
sitekey: System.get_env("HCAPTCHA_SITEKEY"),
|
||||
secret: System.get_env("HCAPTCHA_SECRET")
|
||||
|
||||
config :geolix,
|
||||
databases: [
|
||||
%{
|
||||
|
@ -53,6 +53,9 @@ custom_domain_server_user = System.get_env("CUSTOM_DOMAIN_SERVER_USER")
|
||||
custom_domain_server_password = System.get_env("CUSTOM_DOMAIN_SERVER_PASSWORD")
|
||||
geolite2_country_db = System.get_env("GEOLITE2_COUNTRY_DB")
|
||||
disable_auth = String.to_existing_atom(System.get_env("DISABLE_AUTH", "false"))
|
||||
hcaptcha_sitekey = System.get_env("HCAPTCHA_SITEKEY")
|
||||
hcaptcha_secret = System.get_env("HCAPTCHA_SECRET")
|
||||
|
||||
|
||||
config :plausible,
|
||||
admin_user: admin_user,
|
||||
@ -187,6 +190,10 @@ config :plausible, Oban,
|
||||
queues: if(cron_enabled, do: base_queues ++ extra_queues, else: base_queues),
|
||||
crontab: if(cron_enabled, do: base_cron ++ extra_cron, else: base_cron)
|
||||
|
||||
config :plausible, :hcaptcha,
|
||||
sitekey: hcaptcha_sitekey,
|
||||
secret: hcaptcha_secret
|
||||
|
||||
config :ref_inspector,
|
||||
init: {Plausible.Release, :configure_ref_inspector}
|
||||
|
||||
|
@ -54,4 +54,5 @@ config :geolix,
|
||||
]
|
||||
|
||||
config :plausible,
|
||||
session_timeout: 0
|
||||
session_timeout: 0,
|
||||
environment: System.get_env("ENVIRONMENT", "test")
|
||||
|
27
lib/plausible_web/captcha.ex
Normal file
27
lib/plausible_web/captcha.ex
Normal file
@ -0,0 +1,27 @@
|
||||
defmodule PlausibleWeb.Captcha do
|
||||
@verify_endpoint "https://hcaptcha.com/siteverify"
|
||||
|
||||
def enabled? do
|
||||
!!sitekey()
|
||||
end
|
||||
|
||||
def sitekey() do
|
||||
Application.get_env(:plausible, :hcaptcha, [])
|
||||
|> Keyword.fetch!(:sitekey)
|
||||
end
|
||||
|
||||
def verify(token) do
|
||||
if enabled?() do
|
||||
res = HTTPoison.post!(@verify_endpoint, {:form, [{"response", token}, {"secret", secret()}]})
|
||||
json = Jason.decode!(res.body)
|
||||
json["success"]
|
||||
else
|
||||
true
|
||||
end
|
||||
end
|
||||
|
||||
defp secret() do
|
||||
Application.get_env(:plausible, :hcaptcha, [])
|
||||
|> Keyword.fetch!(:secret)
|
||||
end
|
||||
end
|
@ -24,28 +24,36 @@ defmodule PlausibleWeb.AuthController do
|
||||
end
|
||||
end
|
||||
|
||||
def register(conn, %{"user" => params}) do
|
||||
user = Plausible.Auth.User.changeset(%Plausible.Auth.User{}, params)
|
||||
def register(conn, params) do
|
||||
user = Plausible.Auth.User.changeset(%Plausible.Auth.User{}, params["user"])
|
||||
|
||||
case Ecto.Changeset.apply_action(user, :insert) do
|
||||
{:ok, user} ->
|
||||
token = Auth.Token.sign_activation(user.name, user.email)
|
||||
url = PlausibleWeb.Endpoint.clean_url() <> "/claim-activation?token=#{token}"
|
||||
Logger.info(url)
|
||||
email_template = PlausibleWeb.Email.activation_email(user, url)
|
||||
Plausible.Mailer.send_email(email_template)
|
||||
if PlausibleWeb.Captcha.verify(params["h-captcha-response"]) do
|
||||
case Ecto.Changeset.apply_action(user, :insert) do
|
||||
{:ok, user} ->
|
||||
token = Auth.Token.sign_activation(user.name, user.email)
|
||||
url = PlausibleWeb.Endpoint.clean_url() <> "/claim-activation?token=#{token}"
|
||||
Logger.info(url)
|
||||
email_template = PlausibleWeb.Email.activation_email(user, url)
|
||||
Plausible.Mailer.send_email(email_template)
|
||||
|
||||
conn
|
||||
|> render("register_success.html",
|
||||
email: user.email,
|
||||
layout: {PlausibleWeb.LayoutView, "focus.html"}
|
||||
)
|
||||
conn
|
||||
|> render("register_success.html",
|
||||
email: user.email,
|
||||
layout: {PlausibleWeb.LayoutView, "focus.html"}
|
||||
)
|
||||
|
||||
{:error, changeset} ->
|
||||
render(conn, "register_form.html",
|
||||
changeset: changeset,
|
||||
layout: {PlausibleWeb.LayoutView, "focus.html"}
|
||||
)
|
||||
{:error, changeset} ->
|
||||
render(conn, "register_form.html",
|
||||
changeset: changeset,
|
||||
layout: {PlausibleWeb.LayoutView, "focus.html"}
|
||||
)
|
||||
end
|
||||
else
|
||||
render(conn, "register_form.html",
|
||||
changeset: user,
|
||||
captcha_error: "Please complete the captcha to register",
|
||||
layout: {PlausibleWeb.LayoutView, "focus.html"}
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
@ -87,23 +95,30 @@ defmodule PlausibleWeb.AuthController do
|
||||
)
|
||||
end
|
||||
|
||||
def password_reset_request(conn, %{"email" => email}) do
|
||||
user = Repo.get_by(Plausible.Auth.User, email: email)
|
||||
def password_reset_request(conn, %{"email" => email} = params) do
|
||||
if PlausibleWeb.Captcha.verify(params["h-captcha-response"]) do
|
||||
user = Repo.get_by(Plausible.Auth.User, email: email)
|
||||
|
||||
if user do
|
||||
token = Auth.Token.sign_password_reset(email)
|
||||
url = PlausibleWeb.Endpoint.clean_url() <> "/password/reset?token=#{token}"
|
||||
Logger.debug("PASSWORD RESET LINK: " <> url)
|
||||
email_template = PlausibleWeb.Email.password_reset_email(email, url)
|
||||
Plausible.Mailer.deliver_now(email_template)
|
||||
if user do
|
||||
token = Auth.Token.sign_password_reset(email)
|
||||
url = PlausibleWeb.Endpoint.clean_url() <> "/password/reset?token=#{token}"
|
||||
Logger.debug("PASSWORD RESET LINK: " <> url)
|
||||
email_template = PlausibleWeb.Email.password_reset_email(email, url)
|
||||
Plausible.Mailer.deliver_now(email_template)
|
||||
|
||||
render(conn, "password_reset_request_success.html",
|
||||
email: email,
|
||||
layout: {PlausibleWeb.LayoutView, "focus.html"}
|
||||
)
|
||||
render(conn, "password_reset_request_success.html",
|
||||
email: email,
|
||||
layout: {PlausibleWeb.LayoutView, "focus.html"}
|
||||
)
|
||||
else
|
||||
render(conn, "password_reset_request_success.html",
|
||||
email: email,
|
||||
layout: {PlausibleWeb.LayoutView, "focus.html"}
|
||||
)
|
||||
end
|
||||
else
|
||||
render(conn, "password_reset_request_success.html",
|
||||
email: email,
|
||||
render(conn, "password_reset_request_form.html",
|
||||
error: "Please complete the captcha to reset your password",
|
||||
layout: {PlausibleWeb.LayoutView, "focus.html"}
|
||||
)
|
||||
end
|
||||
|
@ -7,5 +7,16 @@
|
||||
<%= if @conn.assigns[:error] do %>
|
||||
<div class="text-red-500 text-xs italic my-2"><%= @conn.assigns[:error] %></div>
|
||||
<% end %>
|
||||
|
||||
<%= if PlausibleWeb.Captcha.enabled?() do %>
|
||||
<div class="mt-4">
|
||||
<div class="h-captcha" data-sitekey="<%= PlausibleWeb.Captcha.sitekey() %>"></div>
|
||||
<%= if assigns[:captcha_error] do %>
|
||||
<div class="text-red-500 text-xs italic mt-3"><%= @captcha_error %></div>
|
||||
<% end %>
|
||||
<script src="https://hcaptcha.com/1/api.js" async defer></script>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
<%= submit "Send reset link →", class: "button mt-4 w-full" %>
|
||||
<% end %>
|
||||
|
@ -19,6 +19,16 @@
|
||||
<%= error_tag f, :email %>
|
||||
</div>
|
||||
|
||||
<%= if PlausibleWeb.Captcha.enabled?() do %>
|
||||
<div class="mt-4">
|
||||
<div class="h-captcha" data-sitekey="<%= PlausibleWeb.Captcha.sitekey() %>"></div>
|
||||
<%= if assigns[:captcha_error] do %>
|
||||
<div class="text-red-500 text-xs italic mt-3"><%= @captcha_error %></div>
|
||||
<% end %>
|
||||
<script src="https://hcaptcha.com/1/api.js" async defer></script>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
<%= submit "Start my free trial →", class: "button mt-4 w-full" %>
|
||||
|
||||
<p class="text-center text-gray-600 text-xs mt-4">
|
||||
|
Loading…
Reference in New Issue
Block a user