diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/pleroma/captcha/error.ex | 43 | ||||
-rw-r--r-- | lib/pleroma/web/api_spec/errors/registration_user_error.ex | 33 | ||||
-rw-r--r-- | lib/pleroma/web/api_spec/operations/account_operation.ex | 31 | ||||
-rw-r--r-- | lib/pleroma/web/api_spec/render_error.ex | 64 | ||||
-rw-r--r-- | lib/pleroma/web/mastodon_api/controllers/account_controller.ex | 29 | ||||
-rw-r--r-- | lib/pleroma/web/twitter_api/twitter_api.ex | 39 |
6 files changed, 168 insertions, 71 deletions
diff --git a/lib/pleroma/captcha/error.ex b/lib/pleroma/captcha/error.ex new file mode 100644 index 000000000..ec77f1336 --- /dev/null +++ b/lib/pleroma/captcha/error.ex @@ -0,0 +1,43 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Captcha.Error do + import Pleroma.Web.Gettext + + def message(_reason, opts \\ []) + + def message(:missing_field, %{name: name}) do + dgettext( + "errors", + "Invalid CAPTCHA (Missing parameter: %{name})", + name: name + ) + end + + def message(:captcha_error, _) do + dgettext("errors", "CAPTCHA Error") + end + + def message(:invalid, _) do + dgettext("errors", "Invalid CAPTCHA") + end + + def message(:kocaptcha_service_unavailable, _) do + dgettext("errors", "Kocaptcha service unavailable") + end + + def message(:expired, _) do + dgettext("errors", "CAPTCHA expired") + end + + def message(:already_used, _) do + dgettext("errors", "CAPTCHA already used") + end + + def message(:invalid_answer_data, _) do + dgettext("errors", "Invalid answer data") + end + + def message(error, _), do: error +end diff --git a/lib/pleroma/web/api_spec/errors/registration_user_error.ex b/lib/pleroma/web/api_spec/errors/registration_user_error.ex new file mode 100644 index 000000000..1e48e12c9 --- /dev/null +++ b/lib/pleroma/web/api_spec/errors/registration_user_error.ex @@ -0,0 +1,33 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.ApiSpec.Errors.RegistrationUserError do + @behaviour Plug + + import Plug.Conn, only: [put_status: 2] + import Phoenix.Controller, only: [json: 2] + alias Pleroma.Web.ApiSpec.RenderError + + @impl Plug + def init(opts), do: opts + + @impl Plug + + def call(conn, errors) do + field_errors = + errors + |> Enum.group_by(& &1.name) + |> Enum.into(%{}, fn {field, field_errors} -> + {field, Enum.map(field_errors, &RenderError.message/1)} + end) + + conn + |> put_status(:bad_request) + |> json(%{ + error: "Please review the submission", + identifier: "review_submission", + fields: field_errors + }) + end +end diff --git a/lib/pleroma/web/api_spec/operations/account_operation.ex b/lib/pleroma/web/api_spec/operations/account_operation.ex index d90ddb787..d68501bb8 100644 --- a/lib/pleroma/web/api_spec/operations/account_operation.ex +++ b/lib/pleroma/web/api_spec/operations/account_operation.ex @@ -34,7 +34,7 @@ defmodule Pleroma.Web.ApiSpec.AccountOperation do requestBody: request_body("Parameters", create_request(), required: true), responses: %{ 200 => Operation.response("Account", "application/json", create_response()), - 400 => Operation.response("Error", "application/json", ApiError), + 400 => Operation.response("Error", "application/json", error_response()), 403 => Operation.response("Error", "application/json", ApiError), 429 => Operation.response("Error", "application/json", ApiError) } @@ -453,6 +453,35 @@ defmodule Pleroma.Web.ApiSpec.AccountOperation do } end + defp error_response do + %Schema{ + title: "AccountCreateErrorResponse", + description: "Response schema for errors", + type: :object, + properties: %{ + identifier: %Schema{type: :string}, + message: %Schema{type: :string}, + fields: %Schema{ + type: :object, + properties: %{ + captcha: %Schema{type: :array, items: %Schema{type: :string}}, + email: %Schema{type: :array, items: %Schema{type: :string}}, + invite: %Schema{type: :array, items: %Schema{type: :string}}, + password: %Schema{type: :array, items: %Schema{type: :string}}, + username: %Schema{type: :array, items: %Schema{type: :string}} + } + } + }, + example: %{ + "error" => "Please review the submission", + "identifier" => "review_submission", + "fields" => %{ + "captcha" => ["Invalid CAPTCHA"] + } + } + } + end + # Note: this is a token response (if login succeeds!), but there's no oauth operation file yet. defp create_response do %Schema{ diff --git a/lib/pleroma/web/api_spec/render_error.ex b/lib/pleroma/web/api_spec/render_error.ex index d476b8ef3..59154b39e 100644 --- a/lib/pleroma/web/api_spec/render_error.ex +++ b/lib/pleroma/web/api_spec/render_error.ex @@ -47,14 +47,14 @@ defmodule Pleroma.Web.ApiSpec.RenderError do } end - defp message(%{reason: :invalid_schema_type, type: type, name: name}) do + def message(%{reason: :invalid_schema_type, type: type, name: name}) do gettext("%{name} - Invalid schema.type. Got: %{type}.", name: name, type: inspect(type) ) end - defp message(%{reason: :null_value, name: name} = error) do + def message(%{reason: :null_value, name: name} = error) do case error.type do nil -> gettext("%{name} - null value.", name: name) @@ -67,42 +67,42 @@ defmodule Pleroma.Web.ApiSpec.RenderError do end end - defp message(%{reason: :all_of, meta: %{invalid_schema: invalid_schema}}) do + def message(%{reason: :all_of, meta: %{invalid_schema: invalid_schema}}) do gettext( "Failed to cast value as %{invalid_schema}. Value must be castable using `allOf` schemas listed.", invalid_schema: invalid_schema ) end - defp message(%{reason: :any_of, meta: %{failed_schemas: failed_schemas}}) do + def message(%{reason: :any_of, meta: %{failed_schemas: failed_schemas}}) do gettext("Failed to cast value using any of: %{failed_schemas}.", failed_schemas: failed_schemas ) end - defp message(%{reason: :one_of, meta: %{failed_schemas: failed_schemas}}) do + def message(%{reason: :one_of, meta: %{failed_schemas: failed_schemas}}) do gettext("Failed to cast value to one of: %{failed_schemas}.", failed_schemas: failed_schemas) end - defp message(%{reason: :min_length, length: length, name: name}) do + def message(%{reason: :min_length, length: length, name: name}) do gettext("%{name} - String length is smaller than minLength: %{length}.", name: name, length: length ) end - defp message(%{reason: :max_length, length: length, name: name}) do + def message(%{reason: :max_length, length: length, name: name}) do gettext("%{name} - String length is larger than maxLength: %{length}.", name: name, length: length ) end - defp message(%{reason: :unique_items, name: name}) do + def message(%{reason: :unique_items, name: name}) do gettext("%{name} - Array items must be unique.", name: name) end - defp message(%{reason: :min_items, length: min, value: array, name: name}) do + def message(%{reason: :min_items, length: min, value: array, name: name}) do gettext("%{name} - Array length %{length} is smaller than minItems: %{min}.", name: name, length: length(array), @@ -110,7 +110,7 @@ defmodule Pleroma.Web.ApiSpec.RenderError do ) end - defp message(%{reason: :max_items, length: max, value: array, name: name}) do + def message(%{reason: :max_items, length: max, value: array, name: name}) do gettext("%{name} - Array length %{length} is larger than maxItems: %{}.", name: name, length: length(array), @@ -118,7 +118,7 @@ defmodule Pleroma.Web.ApiSpec.RenderError do ) end - defp message(%{reason: :multiple_of, length: multiple, value: count, name: name}) do + def message(%{reason: :multiple_of, length: multiple, value: count, name: name}) do gettext("%{name} - %{count} is not a multiple of %{multiple}.", name: name, count: count, @@ -126,8 +126,8 @@ defmodule Pleroma.Web.ApiSpec.RenderError do ) end - defp message(%{reason: :exclusive_max, length: max, value: value, name: name}) - when value >= max do + def message(%{reason: :exclusive_max, length: max, value: value, name: name}) + when value >= max do gettext("%{name} - %{value} is larger than exclusive maximum %{max}.", name: name, value: value, @@ -135,8 +135,8 @@ defmodule Pleroma.Web.ApiSpec.RenderError do ) end - defp message(%{reason: :maximum, length: max, value: value, name: name}) - when value > max do + def message(%{reason: :maximum, length: max, value: value, name: name}) + when value > max do gettext("%{name} - %{value} is larger than inclusive maximum %{max}.", name: name, value: value, @@ -144,8 +144,8 @@ defmodule Pleroma.Web.ApiSpec.RenderError do ) end - defp message(%{reason: :exclusive_multiple, length: min, value: value, name: name}) - when value <= min do + def message(%{reason: :exclusive_multiple, length: min, value: value, name: name}) + when value <= min do gettext("%{name} - %{value} is smaller than exclusive minimum %{min}.", name: name, value: value, @@ -153,8 +153,8 @@ defmodule Pleroma.Web.ApiSpec.RenderError do ) end - defp message(%{reason: :minimum, length: min, value: value, name: name}) - when value < min do + def message(%{reason: :minimum, length: min, value: value, name: name}) + when value < min do gettext("%{name} - %{value} is smaller than inclusive minimum %{min}.", name: name, value: value, @@ -162,7 +162,7 @@ defmodule Pleroma.Web.ApiSpec.RenderError do ) end - defp message(%{reason: :invalid_type, type: type, value: value, name: name}) do + def message(%{reason: :invalid_type, type: type, value: value, name: name}) do gettext("%{name} - Invalid %{type}. Got: %{value}.", name: name, value: OpenApiSpex.TermType.type(value), @@ -170,49 +170,49 @@ defmodule Pleroma.Web.ApiSpec.RenderError do ) end - defp message(%{reason: :invalid_format, format: format, name: name}) do + def message(%{reason: :invalid_format, format: format, name: name}) do gettext("%{name} - Invalid format. Expected %{format}.", name: name, format: inspect(format)) end - defp message(%{reason: :invalid_enum, name: name}) do + def message(%{reason: :invalid_enum, name: name}) do gettext("%{name} - Invalid value for enum.", name: name) end - defp message(%{reason: :polymorphic_failed, type: polymorphic_type}) do + def message(%{reason: :polymorphic_failed, type: polymorphic_type}) do gettext("Failed to cast to any schema in %{polymorphic_type}", polymorphic_type: polymorphic_type ) end - defp message(%{reason: :unexpected_field, name: name}) do + def message(%{reason: :unexpected_field, name: name}) do gettext("Unexpected field: %{name}.", name: safe_string(name)) end - defp message(%{reason: :no_value_for_discriminator, name: field}) do + def message(%{reason: :no_value_for_discriminator, name: field}) do gettext("Value used as discriminator for `%{field}` matches no schemas.", name: field) end - defp message(%{reason: :invalid_discriminator_value, name: field}) do + def message(%{reason: :invalid_discriminator_value, name: field}) do gettext("No value provided for required discriminator `%{field}`.", name: field) end - defp message(%{reason: :unknown_schema, name: name}) do + def message(%{reason: :unknown_schema, name: name}) do gettext("Unknown schema: %{name}.", name: name) end - defp message(%{reason: :missing_field, name: name}) do + def message(%{reason: :missing_field, name: name}) do gettext("Missing field: %{name}.", name: name) end - defp message(%{reason: :missing_header, name: name}) do + def message(%{reason: :missing_header, name: name}) do gettext("Missing header: %{name}.", name: name) end - defp message(%{reason: :invalid_header, name: name}) do + def message(%{reason: :invalid_header, name: name}) do gettext("Invalid value for header: %{name}.", name: name) end - defp message(%{reason: :max_properties, meta: meta}) do + def message(%{reason: :max_properties, meta: meta}) do gettext( "Object property count %{property_count} is greater than maxProperties: %{max_properties}.", property_count: meta.property_count, @@ -220,7 +220,7 @@ defmodule Pleroma.Web.ApiSpec.RenderError do ) end - defp message(%{reason: :min_properties, meta: meta}) do + def message(%{reason: :min_properties, meta: meta}) do gettext( "Object property count %{property_count} is less than minProperties: %{min_properties}", property_count: meta.property_count, diff --git a/lib/pleroma/web/mastodon_api/controllers/account_controller.ex b/lib/pleroma/web/mastodon_api/controllers/account_controller.ex index 4f9696d52..2047e2439 100644 --- a/lib/pleroma/web/mastodon_api/controllers/account_controller.ex +++ b/lib/pleroma/web/mastodon_api/controllers/account_controller.ex @@ -19,6 +19,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountController do alias Pleroma.Web.ActivityPub.ActivityPub alias Pleroma.Web.ActivityPub.Builder alias Pleroma.Web.ActivityPub.Pipeline + alias Pleroma.Web.ApiSpec.Errors.RegistrationUserError alias Pleroma.Web.CommonAPI alias Pleroma.Web.MastodonAPI.ListView alias Pleroma.Web.MastodonAPI.MastodonAPI @@ -31,7 +32,12 @@ defmodule Pleroma.Web.MastodonAPI.AccountController do alias Pleroma.Web.Plugs.RateLimiter alias Pleroma.Web.TwitterAPI.TwitterAPI - plug(Pleroma.Web.ApiSpec.CastAndValidate) + plug( + Pleroma.Web.ApiSpec.CastAndValidate, + [render_error: RegistrationUserError] when action in [:create] + ) + + plug(Pleroma.Web.ApiSpec.CastAndValidate when action not in [:create]) plug(:skip_plug, [OAuthScopesPlug, EnsurePublicOrAuthenticatedPlug] when action == :create) @@ -101,8 +107,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountController do with :ok <- validate_email_param(params), :ok <- TwitterAPI.validate_captcha(app, params), {:ok, user} <- TwitterAPI.register_user(params), - {_, {:ok, token}} <- - {:login, OAuthController.login(user, app, app.scopes)} do + {_, {:ok, token}} <- {:login, OAuthController.login(user, app, app.scopes)} do json(conn, OAuthView.render("token.json", %{user: user, token: token})) else {:login, {:account_status, :confirmation_pending}} -> @@ -126,8 +131,12 @@ defmodule Pleroma.Web.MastodonAPI.AccountController do identifier: "manual_login_required" }) - {:error, error} -> - json_response(conn, :bad_request, %{error: error}) + {:error, errors} -> + json_response(conn, :bad_request, %{ + identifier: "review_submission", + error: "Please review the submission", + fields: errors + }) end end @@ -143,8 +152,14 @@ defmodule Pleroma.Web.MastodonAPI.AccountController do defp validate_email_param(_) do case Pleroma.Config.get([:instance, :account_activation_required]) do - true -> {:error, dgettext("errors", "Missing parameter: %{name}", name: "email")} - _ -> :ok + true -> + {:error, + %{ + email: [dgettext("errors", "Missing parameter: %{name}", name: "email")] + }} + + _ -> + :ok end end diff --git a/lib/pleroma/web/twitter_api/twitter_api.ex b/lib/pleroma/web/twitter_api/twitter_api.ex index 5d7948507..92b071a81 100644 --- a/lib/pleroma/web/twitter_api/twitter_api.ex +++ b/lib/pleroma/web/twitter_api/twitter_api.ex @@ -3,14 +3,12 @@ # 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 + @spec register_user(map(), keyword()) :: {:ok, User.t()} | {:error, map()} def register_user(params, opts \\ []) do params = params @@ -28,18 +26,20 @@ defmodule Pleroma.Web.TwitterAPI.TwitterAPI do end end + @spec create_user_with_invite(map(), keyword()) :: {:ok, User.t()} | {:error, map()} defp create_user_with_invite(params, opts) do with %{token: token} when is_binary(token) <- params, - %UserInviteToken{} = invite <- Repo.get_by(UserInviteToken, %{token: token}), + {:ok, invite} <- UserInviteToken.find_by_token(token), true <- UserInviteToken.valid_invite?(invite) do UserInviteToken.update_usage!(invite) create_user(params, opts) else - nil -> {:error, "Invalid token"} - _ -> {:error, "Expired token"} + nil -> {:error, %{invite: ["Invalid token"]}} + _ -> {:error, %{invite: ["Expired token"]}} end end + @spec create_user(map(), keyword()) :: {:ok, User.t()} | {:error, map()} defp create_user(params, opts) do changeset = User.register_changeset(%User{}, params, opts) @@ -52,7 +52,6 @@ defmodule Pleroma.Web.TwitterAPI.TwitterAPI do errors = changeset |> Ecto.Changeset.traverse_errors(fn {msg, _opts} -> msg end) - |> Jason.encode!() {:error, errors} end @@ -104,26 +103,8 @@ defmodule Pleroma.Web.TwitterAPI.TwitterAPI do ) do :ok else - {:error, :captcha_error} -> - captcha_error(dgettext("errors", "CAPTCHA Error")) - - {:error, :invalid} -> - captcha_error(dgettext("errors", "Invalid CAPTCHA")) - - {:error, :kocaptcha_service_unavailable} -> - captcha_error(dgettext("errors", "Kocaptcha service unavailable")) - - {: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) + {:error, %{captcha: [Pleroma.Captcha.Error.message(error)]}} end end @@ -131,12 +112,8 @@ defmodule Pleroma.Web.TwitterAPI.TwitterAPI 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} + {:error, Pleroma.Captcha.Error.message(:missing_field, %{name: key})} 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 |