X-Git-Url: http://git.squeep.com/?a=blobdiff_plain;f=lib%2Fpleroma%2Fweb%2Ftwitter_api%2Fcontrollers%2Futil_controller.ex;h=a0c3e5c52907d50e237e9912d27433088e769f1c;hb=4a94c9a31ef11f63ea71ad9c1f085c18cf8ef083;hp=f05a84c7f0419201188865ab3aae680831999002;hpb=c4fbb56984d8f86df948cfd9b0f7c081d688c365;p=akkoma
diff --git a/lib/pleroma/web/twitter_api/controllers/util_controller.ex b/lib/pleroma/web/twitter_api/controllers/util_controller.ex
index f05a84c7f..a0c3e5c52 100644
--- a/lib/pleroma/web/twitter_api/controllers/util_controller.ex
+++ b/lib/pleroma/web/twitter_api/controllers/util_controller.ex
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2019 Pleroma Authors
+# Copyright © 2017-2021 Pleroma Authors
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.TwitterAPI.UtilController do
@@ -11,20 +11,49 @@ defmodule Pleroma.Web.TwitterAPI.UtilController do
alias Pleroma.Config
alias Pleroma.Emoji
alias Pleroma.Healthcheck
- alias Pleroma.Notification
- alias Pleroma.Plugs.AuthenticationPlug
alias Pleroma.User
- alias Pleroma.Web
+ alias Pleroma.Web.ActivityPub.ActivityPub
alias Pleroma.Web.CommonAPI
+ alias Pleroma.Web.Plugs.OAuthScopesPlug
alias Pleroma.Web.WebFinger
- plug(Pleroma.Plugs.SetFormatPlug when action in [:config, :version])
-
- def help_test(conn, _params) do
- json(conn, "ok")
- end
-
- def remote_subscribe(conn, %{"nickname" => nick, "profile" => _}) do
+ plug(
+ Pleroma.Web.ApiSpec.CastAndValidate
+ when action != :remote_subscribe and action != :show_subscribe_form
+ )
+
+ plug(
+ Pleroma.Web.Plugs.FederatingPlug
+ when action == :remote_subscribe
+ when action == :show_subscribe_form
+ )
+
+ plug(
+ OAuthScopesPlug,
+ %{scopes: ["write:accounts"]}
+ when action in [
+ :change_email,
+ :change_password,
+ :delete_account,
+ :update_notificaton_settings,
+ :disable_account,
+ :move_account,
+ :add_alias,
+ :delete_alias
+ ]
+ )
+
+ plug(
+ OAuthScopesPlug,
+ %{scopes: ["read:accounts"]}
+ when action in [
+ :list_aliases
+ ]
+ )
+
+ defdelegate open_api_operation(action), to: Pleroma.Web.ApiSpec.TwitterUtilOperation
+
+ def show_subscribe_form(conn, %{"nickname" => nick}) do
with %User{} = user <- User.get_cached_by_nickname(nick),
avatar = User.avatar_url(user) do
conn
@@ -34,207 +63,113 @@ defmodule Pleroma.Web.TwitterAPI.UtilController do
render(conn, "subscribe.html", %{
nickname: nick,
avatar: nil,
- error: "Could not find user"
+ error:
+ Pleroma.Web.Gettext.dpgettext(
+ "static_pages",
+ "remote follow error message - user not found",
+ "Could not find user"
+ )
})
end
end
- def remote_subscribe(conn, %{"user" => %{"nickname" => nick, "profile" => profile}}) do
- with {:ok, %{"subscribe_address" => template}} <- WebFinger.finger(profile),
- %User{ap_id: ap_id} <- User.get_cached_by_nickname(nick) do
+ def show_subscribe_form(conn, %{"status_id" => id}) do
+ with %Activity{} = activity <- Activity.get_by_id(id),
+ {:ok, ap_id} <- get_ap_id(activity),
+ %User{} = user <- User.get_cached_by_ap_id(activity.actor),
+ avatar = User.avatar_url(user) do
conn
- |> Phoenix.Controller.redirect(external: String.replace(template, "{uri}", ap_id))
+ |> render("status_interact.html", %{
+ status_link: ap_id,
+ status_id: id,
+ nickname: user.nickname,
+ avatar: avatar,
+ error: false
+ })
else
_e ->
- render(conn, "subscribe.html", %{
- nickname: nick,
+ render(conn, "status_interact.html", %{
+ status_id: id,
avatar: nil,
- error: "Something went wrong."
+ error:
+ Pleroma.Web.Gettext.dpgettext(
+ "static_pages",
+ "status interact error message - status not found",
+ "Could not find status"
+ )
})
end
end
- def remote_follow(%{assigns: %{user: user}} = conn, %{"acct" => acct}) do
- if is_status?(acct) do
- {:ok, object} = Pleroma.Object.Fetcher.fetch_object_from_id(acct)
- %Activity{id: activity_id} = Activity.get_create_by_object_ap_id(object.data["id"])
- redirect(conn, to: "/notice/#{activity_id}")
- else
- with {:ok, followee} <- User.get_or_fetch(acct) do
- conn
- |> render(follow_template(user), %{
- error: false,
- acct: acct,
- avatar: User.avatar_url(followee),
- name: followee.nickname,
- id: followee.id
- })
- else
- {:error, _reason} ->
- render(conn, follow_template(user), %{error: :error})
- end
- end
+ def remote_subscribe(conn, %{"nickname" => nick, "profile" => _}) do
+ show_subscribe_form(conn, %{"nickname" => nick})
end
- defp follow_template(%User{} = _user), do: "follow.html"
- defp follow_template(_), do: "follow_login.html"
-
- defp is_status?(acct) do
- case Pleroma.Object.Fetcher.fetch_and_contain_remote_object_from_id(acct) do
- {:ok, %{"type" => type}} when type in ["Article", "Note", "Video", "Page", "Question"] ->
- true
-
- _ ->
- false
- end
+ def remote_subscribe(conn, %{"status_id" => id, "profile" => _}) do
+ show_subscribe_form(conn, %{"status_id" => id})
end
- def do_remote_follow(conn, %{
- "authorization" => %{"name" => username, "password" => password, "id" => id}
- }) do
- with %User{} = followee <- User.get_cached_by_id(id),
- {_, %User{} = user, _} <- {:auth, User.get_cached_by_nickname(username), followee},
- {_, true, _} <- {
- :auth,
- AuthenticationPlug.checkpw(password, user.password_hash),
- followee
- },
- {:ok, _follower, _followee, _activity} <- CommonAPI.follow(user, followee) do
+ def remote_subscribe(conn, %{"user" => %{"nickname" => nick, "profile" => profile}}) do
+ with {:ok, %{"subscribe_address" => template}} <- WebFinger.finger(profile),
+ %User{ap_id: ap_id} <- User.get_cached_by_nickname(nick) do
conn
- |> render("followed.html", %{error: false})
+ |> Phoenix.Controller.redirect(external: String.replace(template, "{uri}", ap_id))
else
- # Was already following user
- {:error, "Could not follow user:" <> _rest} ->
- render(conn, "followed.html", %{error: "Error following account"})
-
- {:auth, _, followee} ->
- conn
- |> render("follow_login.html", %{
- error: "Wrong username or password",
- id: id,
- name: followee.nickname,
- avatar: User.avatar_url(followee)
+ _e ->
+ render(conn, "subscribe.html", %{
+ nickname: nick,
+ avatar: nil,
+ error:
+ Pleroma.Web.Gettext.dpgettext(
+ "static_pages",
+ "remote follow error message - unknown error",
+ "Something went wrong."
+ )
})
-
- e ->
- Logger.debug("Remote follow failed with error #{inspect(e)}")
- render(conn, "followed.html", %{error: "Something went wrong."})
end
end
- def do_remote_follow(%{assigns: %{user: user}} = conn, %{"user" => %{"id" => id}}) do
- with {:fetch_user, %User{} = followee} <- {:fetch_user, User.get_cached_by_id(id)},
- {:ok, _follower, _followee, _activity} <- CommonAPI.follow(user, followee) do
+ def remote_subscribe(conn, %{"status" => %{"status_id" => id, "profile" => profile}}) do
+ with {:ok, %{"subscribe_address" => template}} <- WebFinger.finger(profile),
+ %Activity{} = activity <- Activity.get_by_id(id),
+ {:ok, ap_id} <- get_ap_id(activity) do
conn
- |> render("followed.html", %{error: false})
+ |> Phoenix.Controller.redirect(external: String.replace(template, "{uri}", ap_id))
else
- # Was already following user
- {:error, "Could not follow user:" <> _rest} ->
- render(conn, "followed.html", %{error: "Error following account"})
-
- {:fetch_user, error} ->
- Logger.debug("Remote follow failed with error #{inspect(error)}")
- render(conn, "followed.html", %{error: "Could not find user"})
-
- e ->
- Logger.debug("Remote follow failed with error #{inspect(e)}")
- render(conn, "followed.html", %{error: "Something went wrong."})
+ _e ->
+ render(conn, "status_interact.html", %{
+ status_id: id,
+ avatar: nil,
+ error:
+ Pleroma.Web.Gettext.dpgettext(
+ "static_pages",
+ "status interact error message - unknown error",
+ "Something went wrong."
+ )
+ })
end
end
- def notifications_read(%{assigns: %{user: user}} = conn, %{"id" => notification_id}) do
- with {:ok, _} <- Notification.read_one(user, notification_id) do
- json(conn, %{status: "success"})
+ def remote_interaction(%{body_params: %{ap_id: ap_id, profile: profile}} = conn, _params) do
+ with {:ok, %{"subscribe_address" => template}} <- WebFinger.finger(profile) do
+ conn
+ |> json(%{url: String.replace(template, "{uri}", ap_id)})
else
- {:error, message} ->
- conn
- |> put_resp_content_type("application/json")
- |> send_resp(403, Jason.encode!(%{"error" => message}))
+ _e -> json(conn, %{error: "Couldn't find user"})
end
end
- def config(%{assigns: %{format: "xml"}} = conn, _params) do
- instance = Pleroma.Config.get(:instance)
-
- response = """
-
-
- #{Keyword.get(instance, :name)}
- #{Web.base_url()}
- #{Keyword.get(instance, :limit)}
- #{!Keyword.get(instance, :registrations_open)}
-
-
- """
+ defp get_ap_id(activity) do
+ object = Pleroma.Object.normalize(activity, fetch: false)
- conn
- |> put_resp_content_type("application/xml")
- |> send_resp(200, response)
- end
-
- def config(conn, _params) do
- instance = Pleroma.Config.get(:instance)
-
- vapid_public_key = Keyword.get(Pleroma.Web.Push.vapid_config(), :public_key)
-
- uploadlimit = %{
- uploadlimit: to_string(Keyword.get(instance, :upload_limit)),
- avatarlimit: to_string(Keyword.get(instance, :avatar_upload_limit)),
- backgroundlimit: to_string(Keyword.get(instance, :background_upload_limit)),
- bannerlimit: to_string(Keyword.get(instance, :banner_upload_limit))
- }
-
- data = %{
- name: Keyword.get(instance, :name),
- description: Keyword.get(instance, :description),
- server: Web.base_url(),
- textlimit: to_string(Keyword.get(instance, :limit)),
- uploadlimit: uploadlimit,
- closed: bool_to_val(Keyword.get(instance, :registrations_open), "0", "1"),
- private: bool_to_val(Keyword.get(instance, :public, true), "0", "1"),
- vapidPublicKey: vapid_public_key,
- accountActivationRequired:
- bool_to_val(Keyword.get(instance, :account_activation_required, false)),
- invitesEnabled: bool_to_val(Keyword.get(instance, :invites_enabled, false)),
- safeDMMentionsEnabled: bool_to_val(Pleroma.Config.get([:instance, :safe_dm_mentions]))
- }
-
- managed_config = Keyword.get(instance, :managed_config)
-
- data =
- if managed_config do
- pleroma_fe = Pleroma.Config.get([:frontend_configurations, :pleroma_fe])
- Map.put(data, "pleromafe", pleroma_fe)
- else
- data
- end
-
- json(conn, %{site: data})
+ case object do
+ %{data: %{"id" => ap_id}} -> {:ok, ap_id}
+ _ -> {:no_ap_id, nil}
+ end
end
- defp bool_to_val(true), do: "1"
- defp bool_to_val(_), do: "0"
- defp bool_to_val(true, val, _), do: val
- defp bool_to_val(_, _, val), do: val
-
def frontend_configurations(conn, _params) do
- config =
- Pleroma.Config.get(:frontend_configurations, %{})
- |> Enum.into(%{})
-
- json(conn, config)
- end
-
- def version(%{assigns: %{format: "xml"}} = conn, _params) do
- version = Pleroma.Application.named_version()
-
- conn
- |> put_resp_content_type("application/xml")
- |> send_resp(200, "#{version}")
- end
-
- def version(conn, _params) do
- json(conn, Pleroma.Application.named_version())
+ render(conn, "frontend_configurations.json")
end
def emoji(conn, _params) do
@@ -252,40 +187,13 @@ defmodule Pleroma.Web.TwitterAPI.UtilController do
end
end
- def follow_import(conn, %{"list" => %Plug.Upload{} = listfile}) do
- follow_import(conn, %{"list" => File.read!(listfile.path)})
- 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
- end
-
- def blocks_import(conn, %{"list" => %Plug.Upload{} = listfile}) do
- blocks_import(conn, %{"list" => File.read!(listfile.path)})
- 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
- end
-
- def change_password(%{assigns: %{user: user}} = conn, params) do
- case CommonAPI.Utils.confirm_current_password(user, params["password"]) do
+ def change_password(%{assigns: %{user: user}, body_params: body_params} = conn, %{}) do
+ case CommonAPI.Utils.confirm_current_password(user, body_params.password) do
{:ok, user} ->
with {:ok, _user} <-
User.reset_password(user, %{
- password: params["new_password"],
- password_confirmation: params["new_password_confirmation"]
+ password: body_params.new_password,
+ password_confirmation: body_params.new_password_confirmation
}) do
json(conn, %{status: "success"})
else
@@ -302,10 +210,10 @@ defmodule Pleroma.Web.TwitterAPI.UtilController do
end
end
- def change_email(%{assigns: %{user: user}} = conn, params) do
- case CommonAPI.Utils.confirm_current_password(user, params["password"]) do
+ def change_email(%{assigns: %{user: user}, body_params: body_params} = conn, %{}) do
+ case CommonAPI.Utils.confirm_current_password(user, body_params.password) do
{:ok, user} ->
- with {:ok, _user} <- User.change_email(user, params["email"]) do
+ with {:ok, _user} <- User.change_email(user, body_params.email) do
json(conn, %{status: "success"})
else
{:error, changeset} ->
@@ -321,8 +229,12 @@ defmodule Pleroma.Web.TwitterAPI.UtilController do
end
end
- def delete_account(%{assigns: %{user: user}} = conn, params) do
- case CommonAPI.Utils.confirm_current_password(user, params["password"]) do
+ def delete_account(%{assigns: %{user: user}, body_params: body_params} = conn, params) do
+ # This endpoint can accept a query param or JSON body for backwards-compatibility.
+ # Submitting a JSON body is recommended, so passwords don't end up in server logs.
+ password = body_params[:password] || params[:password] || ""
+
+ case CommonAPI.Utils.confirm_current_password(user, password) do
{:ok, user} ->
User.delete(user)
json(conn, %{status: "success"})
@@ -333,9 +245,9 @@ defmodule Pleroma.Web.TwitterAPI.UtilController do
end
def disable_account(%{assigns: %{user: user}} = conn, params) do
- case CommonAPI.Utils.confirm_current_password(user, params["password"]) do
+ case CommonAPI.Utils.confirm_current_password(user, params[:password]) do
{:ok, user} ->
- User.deactivate_async(user)
+ User.set_activation_async(user, false)
json(conn, %{status: "success"})
{:error, msg} ->
@@ -343,6 +255,91 @@ defmodule Pleroma.Web.TwitterAPI.UtilController do
end
end
+ def move_account(%{assigns: %{user: user}, body_params: body_params} = conn, %{}) do
+ case CommonAPI.Utils.confirm_current_password(user, body_params.password) do
+ {:ok, user} ->
+ with {:ok, target_user} <- find_or_fetch_user_by_nickname(body_params.target_account),
+ {:ok, _user} <- ActivityPub.move(user, target_user) do
+ json(conn, %{status: "success"})
+ else
+ {:not_found, _} ->
+ conn
+ |> put_status(404)
+ |> json(%{error: "Target account not found."})
+
+ {:error, error} ->
+ json(conn, %{error: error})
+ end
+
+ {:error, msg} ->
+ json(conn, %{error: msg})
+ end
+ end
+
+ def add_alias(%{assigns: %{user: user}, body_params: body_params} = conn, _) do
+ with {:ok, alias_user} <- find_user_by_nickname(body_params.alias),
+ {:ok, _user} <- user |> User.add_alias(alias_user) do
+ json(conn, %{status: "success"})
+ else
+ {:not_found, _} ->
+ conn
+ |> put_status(404)
+ |> json(%{error: "Target account does not exist."})
+
+ {:error, error} ->
+ json(conn, %{error: error})
+ end
+ end
+
+ def delete_alias(%{assigns: %{user: user}, body_params: body_params} = conn, _) do
+ with {:ok, alias_user} <- find_user_by_nickname(body_params.alias),
+ {:ok, _user} <- user |> User.delete_alias(alias_user) do
+ json(conn, %{status: "success"})
+ else
+ {:error, :no_such_alias} ->
+ conn
+ |> put_status(404)
+ |> json(%{error: "Account has no such alias."})
+
+ {:error, error} ->
+ json(conn, %{error: error})
+ end
+ end
+
+ def list_aliases(%{assigns: %{user: user}} = conn, %{}) do
+ alias_nicks =
+ user
+ |> User.alias_users()
+ |> Enum.map(&User.full_nickname/1)
+
+ json(conn, %{aliases: alias_nicks})
+ end
+
+ defp find_user_by_nickname(nickname) do
+ user = User.get_cached_by_nickname(nickname)
+
+ if user == nil do
+ {:not_found, nil}
+ else
+ {:ok, user}
+ end
+ end
+
+ defp find_or_fetch_user_by_nickname(nickname) do
+ user = User.get_by_nickname(nickname)
+
+ if user != nil and user.local do
+ {:ok, user}
+ else
+ with {:ok, user} <- User.fetch_by_nickname(nickname) do
+ {:ok, user}
+ else
+ _ ->
+ {:not_found, nil}
+ end
+ end
+ end
+
def captcha(conn, _params) do
json(conn, Pleroma.Captcha.new())
end