aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEkaterina Vaartis <vaartis@cock.li>2018-12-15 22:06:44 +0300
committerEkaterina Vaartis <vaartis@cock.li>2018-12-15 22:07:26 +0300
commitb5518da90468ab1cde40593695d75f3d72d66783 (patch)
tree48771bdffad8d605147258c439783686890abc3b
parent28c43a417e89ad68674f6e60d7d3025fbb4655ff (diff)
downloadpleroma-b5518da90468ab1cde40593695d75f3d72d66783.tar.gz
Separate captcha implementation into a behaviour and use it
-rw-r--r--lib/pleroma/captcha.ex78
-rw-r--r--lib/pleroma/captcha/captcha.ex51
-rw-r--r--lib/pleroma/captcha/captcha_service.ex24
-rw-r--r--lib/pleroma/captcha/kocaptcha.ex37
4 files changed, 112 insertions, 78 deletions
diff --git a/lib/pleroma/captcha.ex b/lib/pleroma/captcha.ex
deleted file mode 100644
index ffa5640ea..000000000
--- a/lib/pleroma/captcha.ex
+++ /dev/null
@@ -1,78 +0,0 @@
-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
- enabled = Pleroma.Config.get([__MODULE__, :enabled])
-
- if !enabled do
- {
- :reply,
- %{type: :none},
- state
- }
- else
- 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
- 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
diff --git a/lib/pleroma/captcha/captcha.ex b/lib/pleroma/captcha/captcha.ex
new file mode 100644
index 000000000..df33406ee
--- /dev/null
+++ b/lib/pleroma/captcha/captcha.ex
@@ -0,0 +1,51 @@
+defmodule Pleroma.Captcha do
+ use GenServer
+
+ @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
+ # Create a ETS table to store captchas
+ ets_name = Module.concat(method(), Ets)
+ ^ets_name = :ets.new(Module.concat(method(), Ets), @ets_options)
+
+ {:ok, nil}
+ end
+
+ @doc """
+ Ask the configured captcha service for a new captcha
+ """
+ def new() do
+ GenServer.call(__MODULE__, :new)
+ end
+
+ @doc """
+ Ask the configured captcha service to validate the captcha
+ """
+ def validate(token, captcha) do
+ GenServer.call(__MODULE__, {:validate, token, captcha})
+ end
+
+ @doc false
+ def handle_call(:new, _from, state) do
+ enabled = Pleroma.Config.get([__MODULE__, :enabled])
+
+ if !enabled do
+ {:reply, %{type: :none}, state}
+ else
+ {:reply, method().new(), state}
+ end
+ end
+
+ @doc false
+ def handle_call({:validate, token, captcha}, _from, state) do
+ {:reply, method().validate(token, captcha), state}
+ end
+
+ defp method, do: Pleroma.Config.get!([__MODULE__, :method])
+end
diff --git a/lib/pleroma/captcha/captcha_service.ex b/lib/pleroma/captcha/captcha_service.ex
new file mode 100644
index 000000000..ae1d6e7c7
--- /dev/null
+++ b/lib/pleroma/captcha/captcha_service.ex
@@ -0,0 +1,24 @@
+defmodule Pleroma.Captcha.Service do
+
+ @doc """
+ Request new captcha from a captcha service.
+
+ Returns:
+
+ Service-specific data for using the newly created captcha
+ """
+ @callback new() :: map
+
+ @doc """
+ Validated the provided captcha solution.
+
+ Arguments:
+ * `token` the captcha is associated with
+ * `captcha` solution of the captcha to validate
+
+ Returns:
+
+ `true` if captcha is valid, `false` if not
+ """
+ @callback validate(token :: String.t, captcha :: String.t) :: boolean
+end
diff --git a/lib/pleroma/captcha/kocaptcha.ex b/lib/pleroma/captcha/kocaptcha.ex
new file mode 100644
index 000000000..abccbf6d3
--- /dev/null
+++ b/lib/pleroma/captcha/kocaptcha.ex
@@ -0,0 +1,37 @@
+defmodule Pleroma.Captcha.Kocaptcha do
+ alias Pleroma.Captcha.Service
+ @behaviour Service
+
+ @ets __MODULE__.Ets
+
+ @impl Service
+ def new() do
+ endpoint = Pleroma.Config.get!([__MODULE__, :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"]})
+
+ %{type: :kocaptcha, token: token, url: endpoint <> json_resp["url"]}
+ end
+ end
+
+ @impl Service
+ def validate(token, captcha) 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)
+
+ true
+ else
+ _ -> false
+ end
+ end
+end