Page Menu
Home
Phorge
Search
Configure Global Search
Log In
Files
F85649748
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Award Token
Flag For Later
Size
5 KB
Referenced Files
None
Subscribers
None
View Options
diff --git a/lib/pleroma/captcha/captcha.ex b/lib/pleroma/captcha/captcha.ex
index 26477a214..5630f6b57 100644
--- a/lib/pleroma/captcha/captcha.ex
+++ b/lib/pleroma/captcha/captcha.ex
@@ -1,64 +1,66 @@
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)
+ # Clean up old captchas every few minutes
+ seconds_retained = Pleroma.Config.get!([__MODULE__, :seconds_retained])
+ Process.send_after(self(), :cleanup, 1000 * seconds_retained)
+
{: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
- new_captcha = method().new()
-
- seconds_retained = Pleroma.Config.get!([__MODULE__, :seconds_retained])
- # Wait several minutes and if the captcha is still there, delete it
- Process.send_after(self(), {:cleanup, new_captcha.token}, 1000 * seconds_retained)
-
- {:reply, new_captcha, state}
+ {:reply, method().new(), state}
end
end
@doc false
def handle_call({:validate, token, captcha}, _from, state) do
{:reply, method().validate(token, captcha), state}
end
@doc false
- def handle_info({:cleanup, token}, state) do
- method().cleanup(token)
+ def handle_info(:cleanup, state) do
+ :ok = method().cleanup()
+
+ seconds_retained = Pleroma.Config.get!([__MODULE__, :seconds_retained])
+ # Schedule the next clenup
+ Process.send_after(self(), :cleanup, 1000 * seconds_retained)
{:noreply, 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
index fe5a6bf66..8d0b76f86 100644
--- a/lib/pleroma/captcha/captcha_service.ex
+++ b/lib/pleroma/captcha/captcha_service.ex
@@ -1,28 +1,28 @@
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
@doc """
This function is called periodically to clean up old captchas
"""
- @callback cleanup(token :: String.t()) :: :ok
+ @callback cleanup() :: :ok
end
diff --git a/lib/pleroma/captcha/kocaptcha.ex b/lib/pleroma/captcha/kocaptcha.ex
index 9891d4031..7f9637ad0 100644
--- a/lib/pleroma/captcha/kocaptcha.ex
+++ b/lib/pleroma/captcha/kocaptcha.ex
@@ -1,48 +1,56 @@
defmodule Pleroma.Captcha.Kocaptcha do
+ alias Calendar.DateTime
+
alias Pleroma.Captcha.Service
@behaviour Service
@ets __MODULE__.Ets
@impl Service
def new() do
endpoint = Pleroma.Config.get!([__MODULE__, :endpoint])
case Tesla.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"]})
+ true = :ets.insert(@ets, {token, json_resp["md5"], DateTime.now_utc()})
%{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),
+ [{^token, saved_md5, _}] <- :ets.lookup(@ets, token),
true <- :crypto.hash(:md5, captcha) |> Base.encode16() == String.upcase(saved_md5) do
# Clear the saved value
- cleanup(token)
+ :ets.delete(@ets, token)
true
else
_ -> false
end
end
@impl Service
- def cleanup(token) do
- # Only delete the entry if it exists in the table, because ets:delete raises an exception if it does not
- case :ets.lookup(@ets, token) do
- [{^token, _}] -> :ets.delete(@ets, token)
- _ -> true
- end
+ def cleanup() do
+ seconds_retained = Pleroma.Config.get!([Pleroma.Captcha, :seconds_retained])
+
+ # Go through captchas and remove expired ones
+ :ets.tab2list(@ets)
+ |> Enum.each(fn {token, _, time_inserted} ->
+ # time created + expiration time = time when the captcha should be removed
+ remove_time = DateTime.add!(time_inserted, seconds_retained)
+ if DateTime.after?(DateTime.now_utc(), remove_time), do: :ets.delete(@ets, token)
+ end)
+
+ :ok
end
end
diff --git a/test/support/captcha_mock.ex b/test/support/captcha_mock.ex
index 560d6c457..898aa17b8 100644
--- a/test/support/captcha_mock.ex
+++ b/test/support/captcha_mock.ex
@@ -1,13 +1,13 @@
defmodule Pleroma.Captcha.Mock do
alias Pleroma.Captcha.Service
@behaviour Service
@impl Service
def new(), do: %{type: :mock}
@impl Service
def validate(_token, _captcha), do: true
@impl Service
- def cleanup(_token), do: true
+ def cleanup(), do: :ok
end
File Metadata
Details
Attached
Mime Type
text/x-diff
Expires
Sat, Aug 29, 7:41 PM (1 d, 20 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1737297
Default Alt Text
(5 KB)
Attached To
Mode
rPUBE pleroma-upstream
Attached
Detach File
Event Timeline
Log In to Comment