Merge branch 'develop' into 'remove-twitter-api'
# Conflicts: # lib/pleroma/web/nodeinfo/nodeinfo_controller.ex
This commit is contained in:
commit
d15aa9d950
598 changed files with 28836 additions and 10625 deletions
|
|
@ -8,10 +8,12 @@ defmodule Pleroma.Web.TwitterAPI.RemoteFollowController do
|
|||
require Logger
|
||||
|
||||
alias Pleroma.Activity
|
||||
alias Pleroma.MFA
|
||||
alias Pleroma.Object.Fetcher
|
||||
alias Pleroma.Plugs.OAuthScopesPlug
|
||||
alias Pleroma.User
|
||||
alias Pleroma.Web.Auth.Authenticator
|
||||
alias Pleroma.Web.Auth.TOTPAuthenticator
|
||||
alias Pleroma.Web.CommonAPI
|
||||
|
||||
@status_types ["Article", "Event", "Note", "Video", "Page", "Question"]
|
||||
|
|
@ -68,6 +70,8 @@ defmodule Pleroma.Web.TwitterAPI.RemoteFollowController do
|
|||
|
||||
# POST /ostatus_subscribe
|
||||
#
|
||||
# adds a remote account in followers if user already is signed in.
|
||||
#
|
||||
def do_follow(%{assigns: %{user: %User{} = user}} = conn, %{"user" => %{"id" => id}}) do
|
||||
with {:fetch_user, %User{} = followee} <- {:fetch_user, User.get_cached_by_id(id)},
|
||||
{:ok, _, _, _} <- CommonAPI.follow(user, followee) do
|
||||
|
|
@ -78,9 +82,33 @@ defmodule Pleroma.Web.TwitterAPI.RemoteFollowController do
|
|||
end
|
||||
end
|
||||
|
||||
# POST /ostatus_subscribe
|
||||
#
|
||||
# step 1.
|
||||
# checks login\password and displays step 2 form of MFA if need.
|
||||
#
|
||||
def do_follow(conn, %{"authorization" => %{"name" => _, "password" => _, "id" => id}}) do
|
||||
with {:fetch_user, %User{} = followee} <- {:fetch_user, User.get_cached_by_id(id)},
|
||||
with {_, %User{} = followee} <- {:fetch_user, User.get_cached_by_id(id)},
|
||||
{_, {:ok, user}, _} <- {:auth, Authenticator.get_user(conn), followee},
|
||||
{_, _, _, false} <- {:mfa_required, followee, user, MFA.require?(user)},
|
||||
{:ok, _, _, _} <- CommonAPI.follow(user, followee) do
|
||||
redirect(conn, to: "/users/#{followee.id}")
|
||||
else
|
||||
error ->
|
||||
handle_follow_error(conn, error)
|
||||
end
|
||||
end
|
||||
|
||||
# POST /ostatus_subscribe
|
||||
#
|
||||
# step 2
|
||||
# checks TOTP code. otherwise displays form with errors
|
||||
#
|
||||
def do_follow(conn, %{"mfa" => %{"code" => code, "token" => token, "id" => id}}) do
|
||||
with {_, %User{} = followee} <- {:fetch_user, User.get_cached_by_id(id)},
|
||||
{_, _, {:ok, %{user: user}}} <- {:mfa_token, followee, MFA.Token.validate(token)},
|
||||
{_, _, _, {:ok, _}} <-
|
||||
{:verify_mfa_code, followee, token, TOTPAuthenticator.verify(code, user)},
|
||||
{:ok, _, _, _} <- CommonAPI.follow(user, followee) do
|
||||
redirect(conn, to: "/users/#{followee.id}")
|
||||
else
|
||||
|
|
@ -94,6 +122,23 @@ defmodule Pleroma.Web.TwitterAPI.RemoteFollowController do
|
|||
render(conn, "followed.html", %{error: "Insufficient permissions: follow | write:follows."})
|
||||
end
|
||||
|
||||
defp handle_follow_error(conn, {:mfa_token, followee, _} = _) do
|
||||
render(conn, "follow_login.html", %{error: "Wrong username or password", followee: followee})
|
||||
end
|
||||
|
||||
defp handle_follow_error(conn, {:verify_mfa_code, followee, token, _} = _) do
|
||||
render(conn, "follow_mfa.html", %{
|
||||
error: "Wrong authentication code",
|
||||
followee: followee,
|
||||
mfa_token: token
|
||||
})
|
||||
end
|
||||
|
||||
defp handle_follow_error(conn, {:mfa_required, followee, user, _} = _) do
|
||||
{:ok, %{token: token}} = MFA.Token.create_token(user)
|
||||
render(conn, "follow_mfa.html", %{followee: followee, mfa_token: token, error: false})
|
||||
end
|
||||
|
||||
defp handle_follow_error(conn, {:auth, _, followee} = _) do
|
||||
render(conn, "follow_login.html", %{error: "Wrong username or password", followee: followee})
|
||||
end
|
||||
|
|
|
|||
|
|
@ -24,13 +24,6 @@ defmodule Pleroma.Web.TwitterAPI.UtilController do
|
|||
when action == :follow_import
|
||||
)
|
||||
|
||||
# Note: follower can submit the form (with password auth) not being signed in (having no token)
|
||||
plug(
|
||||
OAuthScopesPlug,
|
||||
%{fallback: :proceed_unauthenticated, scopes: ["follow", "write:follows"]}
|
||||
when action == :do_remote_follow
|
||||
)
|
||||
|
||||
plug(OAuthScopesPlug, %{scopes: ["follow", "write:blocks"]} when action == :blocks_import)
|
||||
|
||||
plug(
|
||||
|
|
@ -128,15 +121,16 @@ defmodule Pleroma.Web.TwitterAPI.UtilController do
|
|||
end
|
||||
|
||||
def follow_import(%{assigns: %{user: follower}} = conn, %{"list" => list}) do
|
||||
with lines <- String.split(list, "\n"),
|
||||
followed_identifiers <-
|
||||
Enum.map(lines, fn line ->
|
||||
String.split(line, ",") |> List.first()
|
||||
end)
|
||||
|> List.delete("Account address") do
|
||||
User.follow_import(follower, followed_identifiers)
|
||||
json(conn, "job started")
|
||||
end
|
||||
followed_identifiers =
|
||||
list
|
||||
|> String.split("\n")
|
||||
|> Enum.map(&(&1 |> String.split(",") |> List.first()))
|
||||
|> List.delete("Account address")
|
||||
|> Enum.map(&(&1 |> String.trim() |> String.trim_leading("@")))
|
||||
|> Enum.reject(&(&1 == ""))
|
||||
|
||||
User.follow_import(follower, followed_identifiers)
|
||||
json(conn, "job started")
|
||||
end
|
||||
|
||||
def blocks_import(conn, %{"list" => %Plug.Upload{} = listfile}) do
|
||||
|
|
@ -144,10 +138,9 @@ defmodule Pleroma.Web.TwitterAPI.UtilController do
|
|||
end
|
||||
|
||||
def blocks_import(%{assigns: %{user: blocker}} = conn, %{"list" => list}) do
|
||||
with blocked_identifiers <- String.split(list) do
|
||||
User.blocks_import(blocker, blocked_identifiers)
|
||||
json(conn, "job started")
|
||||
end
|
||||
blocked_identifiers = list |> String.split() |> Enum.map(&String.trim_leading(&1, "@"))
|
||||
User.blocks_import(blocker, blocked_identifiers)
|
||||
json(conn, "job started")
|
||||
end
|
||||
|
||||
def change_password(%{assigns: %{user: user}} = conn, params) do
|
||||
|
|
|
|||
|
|
@ -3,81 +3,39 @@
|
|||
# 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
|
||||
token = params["token"]
|
||||
params =
|
||||
params
|
||||
|> 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])
|
||||
|
||||
params = %{
|
||||
nickname: params["nickname"],
|
||||
name: params["fullname"],
|
||||
bio: User.parse_bio(params["bio"]),
|
||||
email: params["email"],
|
||||
password: params["password"],
|
||||
password_confirmation: params["confirm"],
|
||||
captcha_solution: params["captcha_solution"],
|
||||
captcha_token: params["captcha_token"],
|
||||
captcha_answer_data: params["captcha_answer_data"]
|
||||
}
|
||||
|
||||
captcha_enabled = Pleroma.Config.get([Pleroma.Captcha, :enabled])
|
||||
# true if captcha is disabled or enabled and valid, false otherwise
|
||||
captcha_ok =
|
||||
if not captcha_enabled do
|
||||
:ok
|
||||
else
|
||||
Pleroma.Captcha.validate(
|
||||
params[:captcha_token],
|
||||
params[:captcha_solution],
|
||||
params[:captcha_answer_data]
|
||||
)
|
||||
end
|
||||
|
||||
# Captcha invalid
|
||||
if captcha_ok != :ok do
|
||||
{:error, error} = captcha_ok
|
||||
# I have no idea how this error handling works
|
||||
{:error, %{error: Jason.encode!(%{captcha: [error]})}}
|
||||
if Pleroma.Config.get([:instance, :registrations_open]) do
|
||||
create_user(params, opts)
|
||||
else
|
||||
registration_process(
|
||||
params,
|
||||
%{
|
||||
registrations_open: Pleroma.Config.get([:instance, :registrations_open]),
|
||||
token: token
|
||||
},
|
||||
opts
|
||||
)
|
||||
create_user_with_invite(params, opts)
|
||||
end
|
||||
end
|
||||
|
||||
defp registration_process(params, %{registrations_open: true}, opts) do
|
||||
create_user(params, opts)
|
||||
end
|
||||
|
||||
defp registration_process(params, %{token: token}, opts) do
|
||||
invite =
|
||||
unless is_nil(token) do
|
||||
Repo.get_by(UserInviteToken, %{token: token})
|
||||
end
|
||||
|
||||
valid_invite? = invite && UserInviteToken.valid_invite?(invite)
|
||||
|
||||
case invite do
|
||||
nil ->
|
||||
{:error, "Invalid token"}
|
||||
|
||||
invite when valid_invite? ->
|
||||
UserInviteToken.update_usage!(invite)
|
||||
create_user(params, opts)
|
||||
|
||||
_ ->
|
||||
{:error, "Expired token"}
|
||||
defp create_user_with_invite(params, opts) do
|
||||
with %{token: token} when is_binary(token) <- params,
|
||||
%UserInviteToken{} = invite <- Repo.get_by(UserInviteToken, %{token: token}),
|
||||
true <- UserInviteToken.valid_invite?(invite) do
|
||||
UserInviteToken.update_usage!(invite)
|
||||
create_user(params, opts)
|
||||
else
|
||||
nil -> {:error, "Invalid token"}
|
||||
_ -> {:error, "Expired token"}
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -90,16 +48,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} = user when is_binary(email) <-
|
||||
User.get_by_nickname_or_email(nickname_or_email),
|
||||
{:ok, token_record} <- Pleroma.PasswordResetToken.create_token(user) do
|
||||
user
|
||||
|
|
@ -121,4 +80,58 @@ defmodule Pleroma.Web.TwitterAPI.TwitterAPI do
|
|||
{:error, "unknown user"}
|
||||
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"))
|
||||
|
||||
{: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)
|
||||
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
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ defmodule Pleroma.Web.TwitterAPI.Controller do
|
|||
use Pleroma.Web, :controller
|
||||
|
||||
alias Pleroma.Notification
|
||||
alias Pleroma.Plugs.EnsurePublicOrAuthenticatedPlug
|
||||
alias Pleroma.Plugs.OAuthScopesPlug
|
||||
alias Pleroma.User
|
||||
alias Pleroma.Web.OAuth.Token
|
||||
|
|
@ -13,9 +14,17 @@ defmodule Pleroma.Web.TwitterAPI.Controller do
|
|||
|
||||
require Logger
|
||||
|
||||
plug(OAuthScopesPlug, %{scopes: ["write:notifications"]} when action == :notifications_read)
|
||||
plug(
|
||||
OAuthScopesPlug,
|
||||
%{scopes: ["write:notifications"]} when action == :mark_notifications_as_read
|
||||
)
|
||||
|
||||
plug(Pleroma.Plugs.EnsurePublicOrAuthenticatedPlug)
|
||||
plug(
|
||||
:skip_plug,
|
||||
[OAuthScopesPlug, EnsurePublicOrAuthenticatedPlug] when action == :confirm_email
|
||||
)
|
||||
|
||||
plug(:skip_plug, OAuthScopesPlug when action in [:oauth_tokens, :revoke_token])
|
||||
|
||||
action_fallback(:errors)
|
||||
|
||||
|
|
@ -44,13 +53,13 @@ defmodule Pleroma.Web.TwitterAPI.Controller do
|
|||
json_reply(conn, 201, "")
|
||||
end
|
||||
|
||||
def errors(conn, {:param_cast, _}) do
|
||||
defp errors(conn, {:param_cast, _}) do
|
||||
conn
|
||||
|> put_status(400)
|
||||
|> json("Invalid parameters")
|
||||
end
|
||||
|
||||
def errors(conn, _) do
|
||||
defp errors(conn, _) do
|
||||
conn
|
||||
|> put_status(500)
|
||||
|> json("Something went wrong")
|
||||
|
|
@ -62,7 +71,10 @@ defmodule Pleroma.Web.TwitterAPI.Controller do
|
|||
|> send_resp(status, json)
|
||||
end
|
||||
|
||||
def notifications_read(%{assigns: %{user: user}} = conn, %{"latest_id" => latest_id} = params) do
|
||||
def mark_notifications_as_read(
|
||||
%{assigns: %{user: user}} = conn,
|
||||
%{"latest_id" => latest_id} = params
|
||||
) do
|
||||
Notification.set_read_up_to(user, latest_id)
|
||||
|
||||
notifications = Notification.for_user(user, params)
|
||||
|
|
@ -73,7 +85,7 @@ defmodule Pleroma.Web.TwitterAPI.Controller do
|
|||
|> render("index.json", %{notifications: notifications, for: user})
|
||||
end
|
||||
|
||||
def notifications_read(%{assigns: %{user: _user}} = conn, _) do
|
||||
def mark_notifications_as_read(%{assigns: %{user: _user}} = conn, _) do
|
||||
bad_request_reply(conn, "You need to specify latest_id")
|
||||
end
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue