diff options
| -rw-r--r-- | lib/pleroma/captcha.ex | 78 | ||||
| -rw-r--r-- | lib/pleroma/captcha/captcha.ex | 51 | ||||
| -rw-r--r-- | lib/pleroma/captcha/captcha_service.ex | 24 | ||||
| -rw-r--r-- | lib/pleroma/captcha/kocaptcha.ex | 37 | 
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 | 
