Merge branch 'chores/bump-copyright' into 'develop'
[akkoma] / lib / pleroma / web / twitter_api / twitter_api.ex
index cf1d9c74c00ab9f60f1d10e73bb129e99c114430..f6d721da6ed9cc22b41ac19a66b444577e131b5a 100644 (file)
@@ -1,56 +1,30 @@
 # Pleroma: A lightweight social networking server
-# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
 # SPDX-License-Identifier: AGPL-3.0-only
 
 defmodule Pleroma.Web.TwitterAPI.TwitterAPI do
+  import Pleroma.Web.Gettext
+
   alias Pleroma.Emails.Mailer
   alias Pleroma.Emails.UserEmail
   alias Pleroma.Repo
   alias Pleroma.User
   alias Pleroma.UserInviteToken
 
-  require Pleroma.Constants
-
   def register_user(params, opts \\ []) do
     params =
       params
-      |> Map.take([
-        :nickname,
-        :password,
-        :captcha_solution,
-        :captcha_token,
-        :captcha_answer_data,
-        :token,
-        :email,
-        :trusted_app
-      ])
-      |> Map.put(:bio, User.parse_bio(params[:bio] || ""))
-      |> Map.put(:name, params.fullname)
-      |> Map.put(:password_confirmation, params[:confirm])
-
-    case validate_captcha(params) do
-      :ok ->
-        if Pleroma.Config.get([:instance, :registrations_open]) do
-          create_user(params, opts)
-        else
-          create_user_with_invite(params, opts)
-        end
-
-      {:error, error} ->
-        # I have no idea how this error handling works
-        {:error, %{error: Jason.encode!(%{captcha: [error]})}}
-    end
-  end
-
-  defp validate_captcha(params) do
-    if params[:trusted_app] || not Pleroma.Config.get([Pleroma.Captcha, :enabled]) do
-      :ok
+      |> Map.take([:email, :token, :password])
+      |> Map.put(:bio, params |> Map.get(:bio, "") |> User.parse_bio())
+      |> Map.put(:nickname, params[:username])
+      |> Map.put(:name, Map.get(params, :fullname, params[:username]))
+      |> Map.put(:password_confirmation, params[:password])
+      |> Map.put(:registration_reason, params[:reason])
+
+    if Pleroma.Config.get([:instance, :registrations_open]) do
+      create_user(params, opts)
     else
-      Pleroma.Captcha.validate(
-        params.captcha_token,
-        params.captcha_solution,
-        params.captcha_answer_data
-      )
+      create_user_with_invite(params, opts)
     end
   end
 
@@ -75,16 +49,17 @@ defmodule Pleroma.Web.TwitterAPI.TwitterAPI do
 
       {:error, changeset} ->
         errors =
-          Ecto.Changeset.traverse_errors(changeset, fn {msg, _opts} -> msg end)
+          changeset
+          |> Ecto.Changeset.traverse_errors(fn {msg, _opts} -> msg end)
           |> Jason.encode!()
 
-        {:error, %{error: errors}}
+        {:error, errors}
     end
   end
 
   def password_reset(nickname_or_email) do
     with true <- is_binary(nickname_or_email),
-         %User{local: true, email: email} = user when not is_nil(email) <-
+         %User{local: true, email: email, deactivated: false} = user when is_binary(email) <-
            User.get_by_nickname_or_email(nickname_or_email),
          {:ok, token_record} <- Pleroma.PasswordResetToken.create_token(user) do
       user
@@ -93,17 +68,62 @@ defmodule Pleroma.Web.TwitterAPI.TwitterAPI do
 
       {:ok, :enqueued}
     else
-      false ->
-        {:error, "bad user identifier"}
-
-      %User{local: true, email: nil} ->
+      _ ->
         {:ok, :noop}
+    end
+  end
+
+  def validate_captcha(app, params) do
+    if app.trusted || not Pleroma.Captcha.enabled?() do
+      :ok
+    else
+      do_validate_captcha(params)
+    end
+  end
+
+  defp do_validate_captcha(params) do
+    with :ok <- validate_captcha_presence(params),
+         :ok <-
+           Pleroma.Captcha.validate(
+             params[:captcha_token],
+             params[:captcha_solution],
+             params[:captcha_answer_data]
+           ) do
+      :ok
+    else
+      {:error, :captcha_error} ->
+        captcha_error(dgettext("errors", "CAPTCHA Error"))
+
+      {:error, :invalid} ->
+        captcha_error(dgettext("errors", "Invalid CAPTCHA"))
 
-      %User{local: false} ->
-        {:error, "remote user"}
+      {:error, :kocaptcha_service_unavailable} ->
+        captcha_error(dgettext("errors", "Kocaptcha service unavailable"))
 
-      nil ->
-        {:error, "unknown user"}
+      {:error, :expired} ->
+        captcha_error(dgettext("errors", "CAPTCHA expired"))
+
+      {:error, :already_used} ->
+        captcha_error(dgettext("errors", "CAPTCHA already used"))
+
+      {:error, :invalid_answer_data} ->
+        captcha_error(dgettext("errors", "Invalid answer data"))
+
+      {:error, error} ->
+        captcha_error(error)
     end
   end
+
+  defp validate_captcha_presence(params) do
+    [:captcha_solution, :captcha_token, :captcha_answer_data]
+    |> Enum.find_value(:ok, fn key ->
+      unless is_binary(params[key]) do
+        error = dgettext("errors", "Invalid CAPTCHA (Missing parameter: %{name})", name: key)
+        {:error, error}
+      end
+    end)
+  end
+
+  # For some reason FE expects error message to be a serialized JSON
+  defp captcha_error(error), do: {:error, Jason.encode!(%{captcha: [error]})}
 end