Merge remote-tracking branch 'pleroma/develop' into features/poll-validation
[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 |> Map.put(:registration_reason, params[:reason])
23
24 if Pleroma.Config.get([:instance, :registrations_open]) do
25 create_user(params, opts)
26 else
27 create_user_with_invite(params, opts)
28 end
29 end
30
31 defp create_user_with_invite(params, opts) do
32 with %{token: token} when is_binary(token) <- params,
33 %UserInviteToken{} = invite <- Repo.get_by(UserInviteToken, %{token: token}),
34 true <- UserInviteToken.valid_invite?(invite) do
35 UserInviteToken.update_usage!(invite)
36 create_user(params, opts)
37 else
38 nil -> {:error, "Invalid token"}
39 _ -> {:error, "Expired token"}
40 end
41 end
42
43 defp create_user(params, opts) do
44 changeset = User.register_changeset(%User{}, params, opts)
45
46 case User.register(changeset) do
47 {:ok, user} ->
48 maybe_notify_admins(user)
49 {:ok, user}
50
51 {:error, changeset} ->
52 errors =
53 changeset
54 |> Ecto.Changeset.traverse_errors(fn {msg, _opts} -> msg end)
55 |> Jason.encode!()
56
57 {:error, errors}
58 end
59 end
60
61 defp maybe_notify_admins(%User{} = account) do
62 if Pleroma.Config.get([:instance, :account_approval_required]) do
63 User.all_superusers()
64 |> Enum.filter(fn user -> not is_nil(user.email) end)
65 |> Enum.each(fn superuser ->
66 superuser
67 |> Pleroma.Emails.AdminEmail.new_unapproved_registration(account)
68 |> Pleroma.Emails.Mailer.deliver_async()
69 end)
70 end
71 end
72
73 def password_reset(nickname_or_email) do
74 with true <- is_binary(nickname_or_email),
75 %User{local: true, email: email} = user when is_binary(email) <-
76 User.get_by_nickname_or_email(nickname_or_email),
77 {:ok, token_record} <- Pleroma.PasswordResetToken.create_token(user) do
78 user
79 |> UserEmail.password_reset_email(token_record.token)
80 |> Mailer.deliver_async()
81
82 {:ok, :enqueued}
83 else
84 false ->
85 {:error, "bad user identifier"}
86
87 %User{local: true, email: nil} ->
88 {:ok, :noop}
89
90 %User{local: false} ->
91 {:error, "remote user"}
92
93 nil ->
94 {:error, "unknown user"}
95 end
96 end
97
98 def validate_captcha(app, params) do
99 if app.trusted || not Pleroma.Captcha.enabled?() do
100 :ok
101 else
102 do_validate_captcha(params)
103 end
104 end
105
106 defp do_validate_captcha(params) do
107 with :ok <- validate_captcha_presence(params),
108 :ok <-
109 Pleroma.Captcha.validate(
110 params[:captcha_token],
111 params[:captcha_solution],
112 params[:captcha_answer_data]
113 ) do
114 :ok
115 else
116 {:error, :captcha_error} ->
117 captcha_error(dgettext("errors", "CAPTCHA Error"))
118
119 {:error, :invalid} ->
120 captcha_error(dgettext("errors", "Invalid CAPTCHA"))
121
122 {:error, :kocaptcha_service_unavailable} ->
123 captcha_error(dgettext("errors", "Kocaptcha service unavailable"))
124
125 {:error, :expired} ->
126 captcha_error(dgettext("errors", "CAPTCHA expired"))
127
128 {:error, :already_used} ->
129 captcha_error(dgettext("errors", "CAPTCHA already used"))
130
131 {:error, :invalid_answer_data} ->
132 captcha_error(dgettext("errors", "Invalid answer data"))
133
134 {:error, error} ->
135 captcha_error(error)
136 end
137 end
138
139 defp validate_captcha_presence(params) do
140 [:captcha_solution, :captcha_token, :captcha_answer_data]
141 |> Enum.find_value(:ok, fn key ->
142 unless is_binary(params[key]) do
143 error = dgettext("errors", "Invalid CAPTCHA (Missing parameter: %{name})", name: key)
144 {:error, error}
145 end
146 end)
147 end
148
149 # For some reason FE expects error message to be a serialized JSON
150 defp captcha_error(error), do: {:error, Jason.encode!(%{captcha: [error]})}
151 end