Page Menu
Home
Phorge
Search
Configure Global Search
Log In
Files
F85711161
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Award Token
Flag For Later
Size
7 KB
Referenced Files
None
Subscribers
None
View Options
diff --git a/lib/pleroma/captcha/captcha.ex b/lib/pleroma/captcha/captcha.ex
index 61a0f907f..04769d4b2 100644
--- a/lib/pleroma/captcha/captcha.ex
+++ b/lib/pleroma/captcha/captcha.ex
@@ -1,45 +1,94 @@
defmodule Pleroma.Captcha do
+ alias Plug.Crypto.KeyGenerator
+ alias Plug.Crypto.MessageEncryptor
+ alias Calendar.DateTime
+
use GenServer
@doc false
def start_link() do
GenServer.start_link(__MODULE__, [], name: __MODULE__)
end
@doc false
def init(_) do
{: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, answer_data) do
GenServer.call(__MODULE__, {:validate, token, captcha, answer_data})
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}
+ new_captcha = method().new()
+
+ secret_key_base = Pleroma.Config.get!([Pleroma.Web.Endpoint, :secret_key_base])
+
+ # This make salt a little different for two keys
+ token = new_captcha[:token]
+ secret = KeyGenerator.generate(secret_key_base, token <> "_encrypt")
+ sign_secret = KeyGenerator.generate(secret_key_base, token <> "_sign")
+ # Basicallty copy what Phoenix.Token does here, add the time to
+ # the actual data and make it a binary to then encrypt it
+ encrypted_captcha_answer =
+ %{
+ at: DateTime.now_utc(),
+ answer_data: new_captcha[:answer_data]
+ }
+ |> :erlang.term_to_binary()
+ |> MessageEncryptor.encrypt(secret, sign_secret)
+
+ IO.inspect(%{new_captcha | answer_data: encrypted_captcha_answer})
+
+ {
+ :reply,
+ # Repalce the answer with the encrypted answer
+ %{new_captcha | answer_data: encrypted_captcha_answer},
+ state
+ }
end
end
@doc false
def handle_call({:validate, token, captcha, answer_data}, _from, state) do
- {:reply, method().validate(token, captcha, answer_data), state}
+ secret_key_base = Pleroma.Config.get!([Pleroma.Web.Endpoint, :secret_key_base])
+ secret = KeyGenerator.generate(secret_key_base, token <> "_encrypt")
+ sign_secret = KeyGenerator.generate(secret_key_base, token <> "_sign")
+
+ # If the time found is less than (current_time - seconds_valid), then the time has already passed.
+ # Later we check that the time found is more than the presumed invalidatation time, that means
+ # that the data is still valid and the captcha can be checked
+ seconds_valid = Pleroma.Config.get!([Pleroma.Captcha, :seconds_valid])
+ valid_if_after = DateTime.subtract!(DateTime.now_utc(), seconds_valid)
+
+ result =
+ with {:ok, data} <- MessageEncryptor.decrypt(answer_data, secret, sign_secret),
+ %{at: at, answer_data: answer_md5} <- :erlang.binary_to_term(data) do
+ if DateTime.after?(at, valid_if_after),
+ do: method().validate(token, captcha, answer_md5),
+ else: {:error, "CAPTCHA expired"}
+ else
+ _ -> {:error, "Invalid answer data"}
+ end
+
+ {:reply, result, 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 6f36d29b0..6c5ab6c36 100644
--- a/lib/pleroma/captcha/captcha_service.ex
+++ b/lib/pleroma/captcha/captcha_service.ex
@@ -1,28 +1,33 @@
defmodule Pleroma.Captcha.Service do
@doc """
Request new captcha from a captcha service.
Returns:
- Service-specific data for using the newly created captcha
+ 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() :: map
+ @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 :: String.t()
+ answer_data :: any()
) :: :ok | {:error, String.t()}
end
diff --git a/lib/pleroma/captcha/kocaptcha.ex b/lib/pleroma/captcha/kocaptcha.ex
index f881c7b65..cd0eb6f21 100644
--- a/lib/pleroma/captcha/kocaptcha.ex
+++ b/lib/pleroma/captcha/kocaptcha.ex
@@ -1,73 +1,33 @@
defmodule Pleroma.Captcha.Kocaptcha do
- alias Plug.Crypto.KeyGenerator
- alias Plug.Crypto.MessageEncryptor
- alias Calendar.DateTime
-
alias Pleroma.Captcha.Service
@behaviour Service
@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"]
- answer_md5 = json_resp["md5"]
-
- secret_key_base = Pleroma.Config.get!([Pleroma.Web.Endpoint, :secret_key_base])
-
- # This make salt a little different for two keys
- secret = KeyGenerator.generate(secret_key_base, token <> "_encrypt")
- sign_secret = KeyGenerator.generate(secret_key_base, token <> "_sign")
- # Basicallty copy what Phoenix.Token does here, add the time to
- # the actual data and make it a binary to then encrypt it
- encrypted_captcha_answer =
- %{
- at: DateTime.now_utc(),
- answer_md5: answer_md5
- }
- |> :erlang.term_to_binary()
- |> MessageEncryptor.encrypt(secret, sign_secret)
-
%{
type: :kocaptcha,
- token: token,
+ token: json_resp["token"],
url: endpoint <> json_resp["url"],
- answer_data: encrypted_captcha_answer
+ answer_data: json_resp["md5"]
}
end
end
@impl Service
- def validate(token, captcha, answer_data) do
- secret_key_base = Pleroma.Config.get!([Pleroma.Web.Endpoint, :secret_key_base])
- secret = KeyGenerator.generate(secret_key_base, token <> "_encrypt")
- sign_secret = KeyGenerator.generate(secret_key_base, token <> "_sign")
-
- # If the time found is less than (current_time - seconds_valid), then the time has already passed.
- # Later we check that the time found is more than the presumed invalidatation time, that means
- # that the data is still valid and the captcha can be checked
- seconds_valid = Pleroma.Config.get!([Pleroma.Captcha, :seconds_valid])
- valid_if_after = DateTime.subtract!(DateTime.now_utc(), seconds_valid)
-
- with {:ok, data} <- MessageEncryptor.decrypt(answer_data, secret, sign_secret),
- %{at: at, answer_md5: answer_md5} <- :erlang.binary_to_term(data) do
- if DateTime.after?(at, valid_if_after) do
- if not is_nil(captcha) and
- :crypto.hash(:md5, captcha) |> Base.encode16() == String.upcase(answer_md5),
- do: :ok,
- else: {:error, "Invalid CAPTCHA"}
- else
- {:error, "CAPTCHA expired"}
- end
- else
- _ -> {:error, "Invalid answer data"}
- end
+ 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 CAPTCHA"}
end
end
File Metadata
Details
Attached
Mime Type
text/x-diff
Expires
Sat, Sep 19, 4:15 AM (1 d, 5 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1768814
Default Alt Text
(7 KB)
Attached To
Mode
rPUBE pleroma-upstream
Attached
Detach File
Event Timeline
Log In to Comment