aboutsummaryrefslogtreecommitdiff
path: root/lib/pleroma/captcha
diff options
context:
space:
mode:
Diffstat (limited to 'lib/pleroma/captcha')
-rw-r--r--lib/pleroma/captcha/kocaptcha.ex38
-rw-r--r--lib/pleroma/captcha/native.ex35
-rw-r--r--lib/pleroma/captcha/service.ex37
3 files changed, 110 insertions, 0 deletions
diff --git a/lib/pleroma/captcha/kocaptcha.ex b/lib/pleroma/captcha/kocaptcha.ex
new file mode 100644
index 0000000..e786e28
--- /dev/null
+++ b/lib/pleroma/captcha/kocaptcha.ex
@@ -0,0 +1,38 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Captcha.Kocaptcha do
+ alias Pleroma.Captcha.Service
+ @behaviour Service
+
+ @impl Service
+ def new do
+ endpoint = Pleroma.Config.get!([__MODULE__, :endpoint])
+
+ case Pleroma.HTTP.get(endpoint <> "/new") do
+ {:error, _} ->
+ %{error: :kocaptcha_service_unavailable}
+
+ {:ok, res} ->
+ json_resp = Jason.decode!(res.body)
+
+ %{
+ type: :kocaptcha,
+ token: json_resp["token"],
+ url: endpoint <> json_resp["url"],
+ answer_data: json_resp["md5"],
+ seconds_valid: Pleroma.Config.get([Pleroma.Captcha, :seconds_valid])
+ }
+ end
+ end
+
+ @impl Service
+ def validate(_token, captcha, answer_data) do
+ # Here the token is unsed, because the unencrypted captcha answer is just passed to method
+ if not is_nil(captcha) and
+ :crypto.hash(:md5, captcha) |> Base.encode16() == String.upcase(answer_data),
+ do: :ok,
+ else: {:error, :invalid}
+ end
+end
diff --git a/lib/pleroma/captcha/native.ex b/lib/pleroma/captcha/native.ex
new file mode 100644
index 0000000..9ba0f30
--- /dev/null
+++ b/lib/pleroma/captcha/native.ex
@@ -0,0 +1,35 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Captcha.Native do
+ alias Pleroma.Captcha.Service
+ @behaviour Service
+
+ @impl Service
+ def new do
+ case Captcha.get() do
+ :error ->
+ %{error: :captcha_error}
+
+ {:ok, answer_data, img_binary} ->
+ %{
+ type: :native,
+ token: token(),
+ url: "data:image/png;base64," <> Base.encode64(img_binary),
+ answer_data: answer_data,
+ seconds_valid: Pleroma.Config.get([Pleroma.Captcha, :seconds_valid])
+ }
+ end
+ end
+
+ @impl Service
+ def validate(_token, captcha, captcha) when not is_nil(captcha), do: :ok
+ def validate(_token, _captcha, _answer), do: {:error, :invalid}
+
+ defp token do
+ 10
+ |> :crypto.strong_rand_bytes()
+ |> Base.url_encode64(padding: false)
+ end
+end
diff --git a/lib/pleroma/captcha/service.ex b/lib/pleroma/captcha/service.ex
new file mode 100644
index 0000000..7479760
--- /dev/null
+++ b/lib/pleroma/captcha/service.ex
@@ -0,0 +1,37 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Captcha.Service do
+ @doc """
+ Request new captcha from a captcha service.
+
+ Returns:
+
+ Type/Name of the service, the token to identify the captcha,
+ the data of the answer and service-specific data to use the newly created captcha
+ """
+ @callback new() :: %{
+ type: atom(),
+ token: String.t(),
+ answer_data: any()
+ }
+
+ @doc """
+ Validated the provided captcha solution.
+
+ Arguments:
+ * `token` the captcha is associated with
+ * `captcha` solution of the captcha to validate
+ * `answer_data` is the data needed to validate the answer (presumably encrypted)
+
+ Returns:
+
+ `true` if captcha is valid, `false` if not
+ """
+ @callback validate(
+ token :: String.t(),
+ captcha :: String.t(),
+ answer_data :: any()
+ ) :: :ok | {:error, String.t()}
+end