Add a configurable auto-cleanup for captchas
authorEkaterina Vaartis <vaartis@cock.li>
Sun, 16 Dec 2018 19:04:43 +0000 (22:04 +0300)
committerEkaterina Vaartis <vaartis@cock.li>
Sun, 16 Dec 2018 19:08:17 +0000 (22:08 +0300)
config/config.exs
config/config.md
lib/pleroma/captcha/captcha.ex
lib/pleroma/captcha/captcha_service.ex
lib/pleroma/captcha/kocaptcha.ex

index 5149e9c417018d6f21a8aacbe124da0d7234cbd7..21cdc053775e3184075ea0d04a36ca861ba7c530 100644 (file)
@@ -12,6 +12,7 @@ config :pleroma, Pleroma.Repo, types: Pleroma.PostgresTypes
 
 config :pleroma, Pleroma.Captcha,
   enabled: false,
+  minutes_retained: 5,
   method: Pleroma.Captcha.Kocaptcha
 
 config :pleroma, Pleroma.Captcha.Kocaptcha, endpoint: "http://localhost:9093"
index e8b5e52cbf3c317e045091082073916d47f117e4..65f0866fd1507d53cd4751c3d553e094ae8f8c98 100644 (file)
@@ -167,6 +167,7 @@ Web Push Notifications configuration. You can use the mix task `mix web_push.gen
 ## Pleroma.Captcha
 * `enabled`: Whether the captcha should be shown on registration
 * `method`: The method/service to use for captcha
+* `minutes_retained`: The time in minutes for which the captcha is valid (stored in the cache)
 
 ### Pleroma.Captcha.Kocaptcha
 Kocaptcha is a very simple captcha service with a single API endpoint,
index df33406ee7777f0235ee34db0ffd60293d6b8848..2dcbc47174a5f4b62ffceaf1f78d80eac9c57c4e 100644 (file)
@@ -38,7 +38,13 @@ defmodule Pleroma.Captcha do
     if !enabled do
       {:reply, %{type: :none}, state}
     else
-      {:reply, method().new(), state}
+      new_captcha = method().new()
+
+      minutes_retained = Pleroma.Config.get!([__MODULE__, :minutes_retained])
+      # Wait several minutes and if the captcha is still there, delete it
+      Process.send_after(self(), {:cleanup, new_captcha.token}, 1000 * 60 * minutes_retained)
+
+      {:reply, new_captcha, state}
     end
   end
 
@@ -47,5 +53,12 @@ defmodule Pleroma.Captcha do
     {:reply, method().validate(token, captcha), state}
   end
 
+  @doc false
+  def handle_info({:cleanup, token}, state) do
+    method().cleanup(token)
+
+    {:noreply, state}
+  end
+
   defp method, do: Pleroma.Config.get!([__MODULE__, :method])
 end
index 907a73ad06477bdda81f40a2a3442f67b9ade15e..fe5a6bf66b9b2c9131ef1cb8abb2e28647f74122 100644 (file)
@@ -20,4 +20,9 @@ defmodule Pleroma.Captcha.Service do
   `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
 end
index 4ecd1a81f9472fde6308f7d3d3b3cfe7bb608457..9891d403179422b650a02765330446c704eed998 100644 (file)
@@ -29,11 +29,20 @@ defmodule Pleroma.Captcha.Kocaptcha do
          [{^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)
+      cleanup(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
+  end
 end