Merge branch 'fix/captcha' into 'develop'
[akkoma] / lib / pleroma / web / twitter_api / twitter_api.ex
1 # Pleroma: A lightweight social networking server
2 # Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
3 # SPDX-License-Identifier: AGPL-3.0-only
4
5 defmodule Pleroma.Web.TwitterAPI.TwitterAPI do
6 import Pleroma.Web.Gettext
7
8 alias Pleroma.Emails.Mailer
9 alias Pleroma.Emails.UserEmail
10 alias Pleroma.Repo
11 alias Pleroma.User
12 alias Pleroma.UserInviteToken
13
14 def register_user(params, opts \\ []) do
15 params =
16 params
17 |> Map.take([:email, :token, :password])
18 |> Map.put(:bio, params |> Map.get(:bio, "") |> User.parse_bio())
19 |> Map.put(:nickname, params[:username])
20 |> Map.put(:name, Map.get(params, :fullname, params[:username]))
21 |> Map.put(:password_confirmation, params[:password])
22
23 if Pleroma.Config.get([:instance, :registrations_open]) do
24 create_user(params, opts)
25 else
26 create_user_with_invite(params, opts)
27 end
28 end
29
30 defp create_user_with_invite(params, opts) do
31 with %{token: token} when is_binary(token) <- params,
32 %UserInviteToken{} = invite <- Repo.get_by(UserInviteToken, %{token: token}),
33 true <- UserInviteToken.valid_invite?(invite) do
34 UserInviteToken.update_usage!(invite)
35 create_user(params, opts)
36 else
37 nil -> {:error, "Invalid token"}
38 _ -> {:error, "Expired token"}
39 end
40 end
41
42 defp create_user(params, opts) do
43 changeset = User.register_changeset(%User{}, params, opts)
44
45 case User.register(changeset) do
46 {:ok, user} ->
47 {:ok, user}
48
49 {:error, changeset} ->
50 errors =
51 changeset
52 |> Ecto.Changeset.traverse_errors(fn {msg, _opts} -> msg end)
53 |> Jason.encode!()
54
55 {:error, errors}
56 end
57 end
58
59 def password_reset(nickname_or_email) do
60 with true <- is_binary(nickname_or_email),
61 %User{local: true, email: email} = user when is_binary(email) <-
62 User.get_by_nickname_or_email(nickname_or_email),
63 {:ok, token_record} <- Pleroma.PasswordResetToken.create_token(user) do
64 user
65 |> UserEmail.password_reset_email(token_record.token)
66 |> Mailer.deliver_async()
67
68 {:ok, :enqueued}
69 else
70 false ->
71 {:error, "bad user identifier"}
72
73 %User{local: true, email: nil} ->
74 {:ok, :noop}
75
76 %User{local: false} ->
77 {:error, "remote user"}
78
79 nil ->
80 {:error, "unknown user"}
81 end
82 end
83
84 def validate_captcha(app, params) do
85 if app.trusted || not Pleroma.Captcha.enabled?() do
86 :ok
87 else
88 do_validate_captcha(params)
89 end
90 end
91
92 defp do_validate_captcha(params) do
93 with :ok <- validate_captcha_presence(params),
94 :ok <-
95 Pleroma.Captcha.validate(
96 params[:captcha_token],
97 params[:captcha_solution],
98 params[:captcha_answer_data]
99 ) do
100 :ok
101 else
102 {:error, :captcha_error} ->
103 captcha_error(dgettext("errors", "CAPTCHA Error"))
104
105 {:error, :invalid} ->
106 captcha_error(dgettext("errors", "Invalid CAPTCHA"))
107
108 {:error, :kocaptcha_service_unavailable} ->
109 captcha_error(dgettext("errors", "Kocaptcha service unavailable"))
110
111 {:error, :expired} ->
112 captcha_error(dgettext("errors", "CAPTCHA expired"))
113
114 {:error, :already_used} ->
115 captcha_error(dgettext("errors", "CAPTCHA already used"))
116
117 {:error, :invalid_answer_data} ->
118 captcha_error(dgettext("errors", "Invalid answer data"))
119
120 {:error, error} ->
121 captcha_error(error)
122 end
123 end
124
125 defp validate_captcha_presence(params) do
126 [:captcha_solution, :captcha_token, :captcha_answer_data]
127 |> Enum.find_value(:ok, fn key ->
128 unless is_binary(params[key]) do
129 error = dgettext("errors", "Invalid CAPTCHA (Missing parameter: %{name})", name: key)
130 {:error, error}
131 end
132 end)
133 end
134
135 # For some reason FE expects error message to be a serialized JSON
136 defp captcha_error(error), do: {:error, Jason.encode!(%{captcha: [error]})}
137 end