config :pleroma, Pleroma.Repo, types: Pleroma.PostgresTypes
+config :pleroma, Pleroma.Captcha,
+ method: Pleroma.Captcha.Kocaptcha
+
+# Kocaptcha is a very simple captcha service, the source code is here: https://github.com/koto-bank/kocaptcha
+config :pleroma, Pleroma.Captcha.Kocaptcha,
+ endpoint: "http://localhost:9093"
+
# Upload configuration
config :pleroma, Pleroma.Upload,
uploader: Pleroma.Uploaders.Local,
# Start the Ecto repository
supervisor(Pleroma.Repo, []),
worker(Pleroma.Emoji, []),
+ worker(Pleroma.Captcha, []),
worker(
Cachex,
[
--- /dev/null
+defmodule Pleroma.Captcha do
+ use GenServer
+
+ @ets __MODULE__.Ets
+ @ets_options [:ordered_set, :private, :named_table, {:read_concurrency, true}]
+
+
+ @doc false
+ def start_link() do
+ GenServer.start_link(__MODULE__, [], name: __MODULE__)
+ end
+
+
+ @doc false
+ def init(_) do
+ @ets = :ets.new(@ets, @ets_options)
+
+ {:ok, nil}
+ end
+
+ def new() do
+ GenServer.call(__MODULE__, :new)
+ end
+
+ def validate(token, captcha) do
+ GenServer.call(__MODULE__, {:validate, token, captcha})
+ end
+
+ @doc false
+ def handle_call(:new, _from, state) do
+ method = Pleroma.Config.get!([__MODULE__, :method])
+
+ case method do
+ __MODULE__.Kocaptcha ->
+ endpoint = Pleroma.Config.get!([method, :endpoint])
+ case HTTPoison.get(endpoint <> "/new") do
+ {:error, _} ->
+ %{error: "Kocaptcha service unavailable"}
+ {:ok, res} ->
+ json_resp = Poison.decode!(res.body)
+
+ token = json_resp["token"]
+
+ true = :ets.insert(@ets, {token, json_resp["md5"]})
+
+ {
+ :reply,
+ %{type: :kocaptcha, token: token, url: endpoint <> json_resp["url"]},
+ state
+ }
+ end
+ end
+ end
+
+ @doc false
+ def handle_call({:validate, token, captcha}, _from, state) do
+ with false <- is_nil(captcha),
+ [{^token, saved_md5}] <- :ets.lookup(@ets, token),
+ true <- (:crypto.hash(:md5, captcha) |> Base.encode16) == String.upcase(saved_md5) do
+ # Clear the saved value
+ :ets.delete(@ets, token)
+
+ {:reply, true, state}
+ else
+ e -> IO.inspect(e); {:reply, false, state}
+ end
+ end
+end
get("/password_reset/:token", UtilController, :show_password_reset)
post("/password_reset", UtilController, :password_reset)
get("/emoji", UtilController, :emoji)
+ get("/captcha", UtilController, :captcha)
end
scope "/api/pleroma/admin", Pleroma.Web.AdminAPI do
json(conn, %{error: msg})
end
end
+
+ def captcha(conn, _params) do
+ json(conn, Pleroma.Captcha.new())
+ end
end
bio: User.parse_bio(params["bio"]),
email: params["email"],
password: params["password"],
- password_confirmation: params["confirm"]
+ password_confirmation: params["confirm"],
+ captcha_solution: params["captcha_solution"],
+ captcha_token: params["captcha_token"]
}
- registrations_open = Pleroma.Config.get([:instance, :registrations_open])
+ # Captcha invalid
+ if not Pleroma.Captcha.validate(params[:captcha_token], params[:captcha_solution]) do
+ # I have no idea how this error handling works
+ {:error, %{error: Jason.encode!(%{captcha: ["Invalid CAPTCHA"]})}}
+ else
+ registrations_open = Pleroma.Config.get([:instance, :registrations_open])
- # no need to query DB if registration is open
- token =
- unless registrations_open || is_nil(tokenString) do
+ # no need to query DB if registration is open
+ token =
+ unless registrations_open || is_nil(tokenString) do
Repo.get_by(UserInviteToken, %{token: tokenString})
end
- cond do
- registrations_open || (!is_nil(token) && !token.used) ->
- changeset = User.register_changeset(%User{info: %{}}, params)
+ cond do
+ registrations_open || (!is_nil(token) && !token.used) ->
+ changeset = User.register_changeset(%User{info: %{}}, params)
- with {:ok, user} <- Repo.insert(changeset) do
- !registrations_open && UserInviteToken.mark_as_used(token.token)
- {:ok, user}
- else
- {:error, changeset} ->
- errors =
+ with {:ok, user} <- Repo.insert(changeset) do
+ !registrations_open && UserInviteToken.mark_as_used(token.token)
+ {:ok, user}
+ else
+ {:error, changeset} ->
+ errors =
Ecto.Changeset.traverse_errors(changeset, fn {msg, _opts} -> msg end)
|> Jason.encode!()
{:error, %{error: errors}}
- end
+ end
+
- !registrations_open && is_nil(token) ->
- {:error, "Invalid token"}
+ !registrations_open && is_nil(token) ->
+ {:error, "Invalid token"}
- !registrations_open && token.used ->
- {:error, "Expired token"}
+ !registrations_open && token.used ->
+ {:error, "Expired token"}
+ end
end
end