@@ -262,37 +262,51 @@ defmodule Pleroma.User do | |||
def account_status(%User{password_reset_pending: true}), do: :password_reset_pending | |||
def account_status(%User{confirmation_pending: true}) do | |||
case Config.get([:instance, :account_activation_required]) do | |||
true -> :confirmation_pending | |||
_ -> :active | |||
if Config.get([:instance, :account_activation_required]) do | |||
:confirmation_pending | |||
else | |||
:active | |||
end | |||
end | |||
def account_status(%User{}), do: :active | |||
@spec visible_for?(User.t(), User.t() | nil) :: boolean() | |||
def visible_for?(user, for_user \\ nil) | |||
@spec visible_for(User.t(), User.t() | nil) :: | |||
boolean() | |||
| :invisible | |||
| :restricted_unauthenticated | |||
| :deactivated | |||
| :confirmation_pending | |||
def visible_for(user, for_user \\ nil) | |||
def visible_for?(%User{invisible: true}, _), do: false | |||
def visible_for(%User{invisible: true}, _), do: :invisible | |||
def visible_for?(%User{id: user_id}, %User{id: user_id}), do: true | |||
def visible_for(%User{id: user_id}, %User{id: user_id}), do: true | |||
def visible_for?(%User{local: local} = user, nil) do | |||
cfg_key = | |||
if local, | |||
do: :local, | |||
else: :remote | |||
def visible_for(%User{} = user, nil) do | |||
if restrict_unauthenticated?(user) do | |||
:restrict_unauthenticated | |||
else | |||
visible_account_status(user) | |||
end | |||
end | |||
if Config.get([:restrict_unauthenticated, :profiles, cfg_key]), | |||
do: false, | |||
else: account_status(user) == :active | |||
def visible_for(%User{} = user, for_user) do | |||
superuser?(for_user) || visible_account_status(user) | |||
end | |||
def visible_for?(%User{} = user, for_user) do | |||
account_status(user) == :active || superuser?(for_user) | |||
def visible_for(_, _), do: false | |||
defp restrict_unauthenticated?(%User{local: local}) do | |||
config_key = if local, do: :local, else: :remote | |||
Config.get([:restrict_unauthenticated, :profiles, config_key], false) | |||
end | |||
def visible_for?(_, _), do: false | |||
defp visible_account_status(user) do | |||
status = account_status(user) | |||
status in [:active, :password_reset_pending] || status | |||
end | |||
@spec superuser?(User.t()) :: boolean() | |||
def superuser?(%User{local: true, is_admin: true}), do: true | |||
@@ -102,7 +102,9 @@ defmodule Pleroma.Web.ApiSpec.AccountOperation do | |||
parameters: [%Reference{"$ref": "#/components/parameters/accountIdOrNickname"}], | |||
responses: %{ | |||
200 => Operation.response("Account", "application/json", Account), | |||
404 => Operation.response("Error", "application/json", ApiError) | |||
401 => Operation.response("Error", "application/json", ApiError), | |||
404 => Operation.response("Error", "application/json", ApiError), | |||
410 => Operation.response("Error", "application/json", ApiError) | |||
} | |||
} | |||
end | |||
@@ -142,7 +144,9 @@ defmodule Pleroma.Web.ApiSpec.AccountOperation do | |||
] ++ pagination_params(), | |||
responses: %{ | |||
200 => Operation.response("Statuses", "application/json", array_of_statuses()), | |||
404 => Operation.response("Error", "application/json", ApiError) | |||
401 => Operation.response("Error", "application/json", ApiError), | |||
404 => Operation.response("Error", "application/json", ApiError), | |||
410 => Operation.response("Error", "application/json", ApiError) | |||
} | |||
} | |||
end | |||
@@ -221,17 +221,17 @@ defmodule Pleroma.Web.MastodonAPI.AccountController do | |||
@doc "GET /api/v1/accounts/:id" | |||
def show(%{assigns: %{user: for_user}} = conn, %{id: nickname_or_id}) do | |||
with %User{} = user <- User.get_cached_by_nickname_or_id(nickname_or_id, for: for_user), | |||
true <- User.visible_for?(user, for_user) do | |||
true <- User.visible_for(user, for_user) do | |||
render(conn, "show.json", user: user, for: for_user) | |||
else | |||
_e -> render_error(conn, :not_found, "Can't find user") | |||
error -> user_visibility_error(conn, error) | |||
end | |||
end | |||
@doc "GET /api/v1/accounts/:id/statuses" | |||
def statuses(%{assigns: %{user: reading_user}} = conn, params) do | |||
with %User{} = user <- User.get_cached_by_nickname_or_id(params.id, for: reading_user), | |||
true <- User.visible_for?(user, reading_user) do | |||
true <- User.visible_for(user, reading_user) do | |||
params = | |||
params | |||
|> Map.delete(:tagged) | |||
@@ -250,7 +250,20 @@ defmodule Pleroma.Web.MastodonAPI.AccountController do | |||
as: :activity | |||
) | |||
else | |||
_e -> render_error(conn, :not_found, "Can't find user") | |||
error -> user_visibility_error(conn, error) | |||
end | |||
end | |||
defp user_visibility_error(conn, error) do | |||
case error do | |||
:deactivated -> | |||
render_error(conn, :gone, "") | |||
:restrict_unauthenticated -> | |||
render_error(conn, :unauthorized, "This API requires an authenticated user") | |||
_ -> | |||
render_error(conn, :not_found, "Can't find user") | |||
end | |||
end | |||
@@ -35,7 +35,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountView do | |||
end | |||
def render("show.json", %{user: user} = opts) do | |||
if User.visible_for?(user, opts[:for]) do | |||
if User.visible_for(user, opts[:for]) == true do | |||
do_render("show.json", opts) | |||
else | |||
%{} | |||
@@ -1289,11 +1289,11 @@ defmodule Pleroma.UserTest do | |||
end | |||
end | |||
describe "visible_for?/2" do | |||
describe "visible_for/2" do | |||
test "returns true when the account is itself" do | |||
user = insert(:user, local: true) | |||
assert User.visible_for?(user, user) | |||
assert User.visible_for(user, user) | |||
end | |||
test "returns false when the account is unauthenticated and auth is required" do | |||
@@ -1302,14 +1302,14 @@ defmodule Pleroma.UserTest do | |||
user = insert(:user, local: true, confirmation_pending: true) | |||
other_user = insert(:user, local: true) | |||
refute User.visible_for?(user, other_user) | |||
refute User.visible_for(user, other_user) == true | |||
end | |||
test "returns true when the account is unauthenticated and auth is not required" do | |||
user = insert(:user, local: true, confirmation_pending: true) | |||
other_user = insert(:user, local: true) | |||
assert User.visible_for?(user, other_user) | |||
assert User.visible_for(user, other_user) | |||
end | |||
test "returns true when the account is unauthenticated and being viewed by a privileged account (auth required)" do | |||
@@ -1318,7 +1318,7 @@ defmodule Pleroma.UserTest do | |||
user = insert(:user, local: true, confirmation_pending: true) | |||
other_user = insert(:user, local: true, is_admin: true) | |||
assert User.visible_for?(user, other_user) | |||
assert User.visible_for(user, other_user) | |||
end | |||
end | |||
@@ -127,6 +127,15 @@ defmodule Pleroma.Web.MastodonAPI.AccountControllerTest do | |||
|> get("/api/v1/accounts/internal.fetch") | |||
|> json_response_and_validate_schema(404) | |||
end | |||
test "returns 401 for deactivated user", %{conn: conn} do | |||
user = insert(:user, deactivated: true) | |||
assert %{} = | |||
conn | |||
|> get("/api/v1/accounts/#{user.id}") | |||
|> json_response_and_validate_schema(:gone) | |||
end | |||
end | |||
defp local_and_remote_users do | |||
@@ -143,15 +152,15 @@ defmodule Pleroma.Web.MastodonAPI.AccountControllerTest do | |||
setup do: clear_config([:restrict_unauthenticated, :profiles, :remote], true) | |||
test "if user is unauthenticated", %{conn: conn, local: local, remote: remote} do | |||
assert %{"error" => "Can't find user"} == | |||
assert %{"error" => "This API requires an authenticated user"} == | |||
conn | |||
|> get("/api/v1/accounts/#{local.id}") | |||
|> json_response_and_validate_schema(:not_found) | |||
|> json_response_and_validate_schema(:unauthorized) | |||
assert %{"error" => "Can't find user"} == | |||
assert %{"error" => "This API requires an authenticated user"} == | |||
conn | |||
|> get("/api/v1/accounts/#{remote.id}") | |||
|> json_response_and_validate_schema(:not_found) | |||
|> json_response_and_validate_schema(:unauthorized) | |||
end | |||
test "if user is authenticated", %{local: local, remote: remote} do | |||
@@ -173,8 +182,8 @@ defmodule Pleroma.Web.MastodonAPI.AccountControllerTest do | |||
test "if user is unauthenticated", %{conn: conn, local: local, remote: remote} do | |||
res_conn = get(conn, "/api/v1/accounts/#{local.id}") | |||
assert json_response_and_validate_schema(res_conn, :not_found) == %{ | |||
"error" => "Can't find user" | |||
assert json_response_and_validate_schema(res_conn, :unauthorized) == %{ | |||
"error" => "This API requires an authenticated user" | |||
} | |||
res_conn = get(conn, "/api/v1/accounts/#{remote.id}") | |||
@@ -203,8 +212,8 @@ defmodule Pleroma.Web.MastodonAPI.AccountControllerTest do | |||
res_conn = get(conn, "/api/v1/accounts/#{remote.id}") | |||
assert json_response_and_validate_schema(res_conn, :not_found) == %{ | |||
"error" => "Can't find user" | |||
assert json_response_and_validate_schema(res_conn, :unauthorized) == %{ | |||
"error" => "This API requires an authenticated user" | |||
} | |||
end | |||
@@ -249,6 +258,24 @@ defmodule Pleroma.Web.MastodonAPI.AccountControllerTest do | |||
assert id == announce.id | |||
end | |||
test "deactivated user", %{conn: conn} do | |||
user = insert(:user, deactivated: true) | |||
assert %{} == | |||
conn | |||
|> get("/api/v1/accounts/#{user.id}/statuses") | |||
|> json_response_and_validate_schema(:gone) | |||
end | |||
test "returns 404 when user is invisible", %{conn: conn} do | |||
user = insert(:user, %{invisible: true}) | |||
assert %{"error" => "Can't find user"} = | |||
conn | |||
|> get("/api/v1/accounts/#{user.id}") | |||
|> json_response_and_validate_schema(404) | |||
end | |||
test "respects blocks", %{user: user_one, conn: conn} do | |||
user_two = insert(:user) | |||
user_three = insert(:user) | |||
@@ -422,15 +449,15 @@ defmodule Pleroma.Web.MastodonAPI.AccountControllerTest do | |||
setup do: clear_config([:restrict_unauthenticated, :profiles, :remote], true) | |||
test "if user is unauthenticated", %{conn: conn, local: local, remote: remote} do | |||
assert %{"error" => "Can't find user"} == | |||
assert %{"error" => "This API requires an authenticated user"} == | |||
conn | |||
|> get("/api/v1/accounts/#{local.id}/statuses") | |||
|> json_response_and_validate_schema(:not_found) | |||
|> json_response_and_validate_schema(:unauthorized) | |||
assert %{"error" => "Can't find user"} == | |||
assert %{"error" => "This API requires an authenticated user"} == | |||
conn | |||
|> get("/api/v1/accounts/#{remote.id}/statuses") | |||
|> json_response_and_validate_schema(:not_found) | |||
|> json_response_and_validate_schema(:unauthorized) | |||
end | |||
test "if user is authenticated", %{local: local, remote: remote} do | |||
@@ -451,10 +478,10 @@ defmodule Pleroma.Web.MastodonAPI.AccountControllerTest do | |||
setup do: clear_config([:restrict_unauthenticated, :profiles, :local], true) | |||
test "if user is unauthenticated", %{conn: conn, local: local, remote: remote} do | |||
assert %{"error" => "Can't find user"} == | |||
assert %{"error" => "This API requires an authenticated user"} == | |||
conn | |||
|> get("/api/v1/accounts/#{local.id}/statuses") | |||
|> json_response_and_validate_schema(:not_found) | |||
|> json_response_and_validate_schema(:unauthorized) | |||
res_conn = get(conn, "/api/v1/accounts/#{remote.id}/statuses") | |||
assert length(json_response_and_validate_schema(res_conn, 200)) == 1 | |||
@@ -481,10 +508,10 @@ defmodule Pleroma.Web.MastodonAPI.AccountControllerTest do | |||
res_conn = get(conn, "/api/v1/accounts/#{local.id}/statuses") | |||
assert length(json_response_and_validate_schema(res_conn, 200)) == 1 | |||
assert %{"error" => "Can't find user"} == | |||
assert %{"error" => "This API requires an authenticated user"} == | |||
conn | |||
|> get("/api/v1/accounts/#{remote.id}/statuses") | |||
|> json_response_and_validate_schema(:not_found) | |||
|> json_response_and_validate_schema(:unauthorized) | |||
end | |||
test "if user is authenticated", %{local: local, remote: remote} do | |||