account visibility

This commit is contained in:
Alexander Strizhakov 2020-05-07 13:44:38 +03:00
parent b0ccdb5af4
commit e7bc2f980c
No known key found for this signature in database
GPG key ID: 022896A53AEF1381
6 changed files with 105 additions and 47 deletions

View file

@ -262,37 +262,51 @@ defmodule Pleroma.User do
def account_status(%User{password_reset_pending: true}), do: :password_reset_pending def account_status(%User{password_reset_pending: true}), do: :password_reset_pending
def account_status(%User{confirmation_pending: true}) do def account_status(%User{confirmation_pending: true}) do
case Config.get([:instance, :account_activation_required]) do if Config.get([:instance, :account_activation_required]) do
true -> :confirmation_pending :confirmation_pending
_ -> :active else
:active
end end
end end
def account_status(%User{}), do: :active def account_status(%User{}), do: :active
@spec visible_for?(User.t(), User.t() | nil) :: boolean() @spec visible_for(User.t(), User.t() | nil) ::
def visible_for?(user, for_user \\ 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 def visible_for(%User{} = user, nil) do
cfg_key = if restrict_unauthenticated?(user) do
if local, :restrict_unauthenticated
do: :local, else
else: :remote visible_account_status(user)
end
if Config.get([:restrict_unauthenticated, :profiles, cfg_key]),
do: false,
else: account_status(user) == :active
end end
def visible_for?(%User{} = user, for_user) do def visible_for(%User{} = user, for_user) do
account_status(user) == :active || superuser?(for_user) superuser?(for_user) || visible_account_status(user)
end end
def visible_for?(_, _), do: false 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
defp visible_account_status(user) do
status = account_status(user)
status in [:active, :password_reset_pending] || status
end
@spec superuser?(User.t()) :: boolean() @spec superuser?(User.t()) :: boolean()
def superuser?(%User{local: true, is_admin: true}), do: true def superuser?(%User{local: true, is_admin: true}), do: true

View file

@ -102,7 +102,9 @@ defmodule Pleroma.Web.ApiSpec.AccountOperation do
parameters: [%Reference{"$ref": "#/components/parameters/accountIdOrNickname"}], parameters: [%Reference{"$ref": "#/components/parameters/accountIdOrNickname"}],
responses: %{ responses: %{
200 => Operation.response("Account", "application/json", Account), 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 end
@ -142,7 +144,9 @@ defmodule Pleroma.Web.ApiSpec.AccountOperation do
] ++ pagination_params(), ] ++ pagination_params(),
responses: %{ responses: %{
200 => Operation.response("Statuses", "application/json", array_of_statuses()), 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 end

View file

@ -221,17 +221,17 @@ defmodule Pleroma.Web.MastodonAPI.AccountController do
@doc "GET /api/v1/accounts/:id" @doc "GET /api/v1/accounts/:id"
def show(%{assigns: %{user: for_user}} = conn, %{id: nickname_or_id}) do 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), 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) render(conn, "show.json", user: user, for: for_user)
else else
_e -> render_error(conn, :not_found, "Can't find user") error -> user_visibility_error(conn, error)
end end
end end
@doc "GET /api/v1/accounts/:id/statuses" @doc "GET /api/v1/accounts/:id/statuses"
def statuses(%{assigns: %{user: reading_user}} = conn, params) do def statuses(%{assigns: %{user: reading_user}} = conn, params) do
with %User{} = user <- User.get_cached_by_nickname_or_id(params.id, for: reading_user), 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 =
params params
|> Map.delete(:tagged) |> Map.delete(:tagged)
@ -250,7 +250,20 @@ defmodule Pleroma.Web.MastodonAPI.AccountController do
as: :activity as: :activity
) )
else 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
end end

View file

@ -35,7 +35,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountView do
end end
def render("show.json", %{user: user} = opts) do 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) do_render("show.json", opts)
else else
%{} %{}

View file

@ -1289,11 +1289,11 @@ defmodule Pleroma.UserTest do
end end
end end
describe "visible_for?/2" do describe "visible_for/2" do
test "returns true when the account is itself" do test "returns true when the account is itself" do
user = insert(:user, local: true) user = insert(:user, local: true)
assert User.visible_for?(user, user) assert User.visible_for(user, user)
end end
test "returns false when the account is unauthenticated and auth is required" do 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) user = insert(:user, local: true, confirmation_pending: true)
other_user = insert(:user, local: true) other_user = insert(:user, local: true)
refute User.visible_for?(user, other_user) refute User.visible_for(user, other_user) == true
end end
test "returns true when the account is unauthenticated and auth is not required" do test "returns true when the account is unauthenticated and auth is not required" do
user = insert(:user, local: true, confirmation_pending: true) user = insert(:user, local: true, confirmation_pending: true)
other_user = insert(:user, local: true) other_user = insert(:user, local: true)
assert User.visible_for?(user, other_user) assert User.visible_for(user, other_user)
end end
test "returns true when the account is unauthenticated and being viewed by a privileged account (auth required)" do 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) user = insert(:user, local: true, confirmation_pending: true)
other_user = insert(:user, local: true, is_admin: 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
end end

View file

@ -127,6 +127,15 @@ defmodule Pleroma.Web.MastodonAPI.AccountControllerTest do
|> get("/api/v1/accounts/internal.fetch") |> get("/api/v1/accounts/internal.fetch")
|> json_response_and_validate_schema(404) |> json_response_and_validate_schema(404)
end 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 end
defp local_and_remote_users do 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) setup do: clear_config([:restrict_unauthenticated, :profiles, :remote], true)
test "if user is unauthenticated", %{conn: conn, local: local, remote: remote} do 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 conn
|> get("/api/v1/accounts/#{local.id}") |> 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 conn
|> get("/api/v1/accounts/#{remote.id}") |> get("/api/v1/accounts/#{remote.id}")
|> json_response_and_validate_schema(:not_found) |> json_response_and_validate_schema(:unauthorized)
end end
test "if user is authenticated", %{local: local, remote: remote} do 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 test "if user is unauthenticated", %{conn: conn, local: local, remote: remote} do
res_conn = get(conn, "/api/v1/accounts/#{local.id}") res_conn = get(conn, "/api/v1/accounts/#{local.id}")
assert json_response_and_validate_schema(res_conn, :not_found) == %{ assert json_response_and_validate_schema(res_conn, :unauthorized) == %{
"error" => "Can't find user" "error" => "This API requires an authenticated user"
} }
res_conn = get(conn, "/api/v1/accounts/#{remote.id}") 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}") res_conn = get(conn, "/api/v1/accounts/#{remote.id}")
assert json_response_and_validate_schema(res_conn, :not_found) == %{ assert json_response_and_validate_schema(res_conn, :unauthorized) == %{
"error" => "Can't find user" "error" => "This API requires an authenticated user"
} }
end end
@ -249,6 +258,24 @@ defmodule Pleroma.Web.MastodonAPI.AccountControllerTest do
assert id == announce.id assert id == announce.id
end 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 test "respects blocks", %{user: user_one, conn: conn} do
user_two = insert(:user) user_two = insert(:user)
user_three = 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) setup do: clear_config([:restrict_unauthenticated, :profiles, :remote], true)
test "if user is unauthenticated", %{conn: conn, local: local, remote: remote} do 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 conn
|> get("/api/v1/accounts/#{local.id}/statuses") |> 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 conn
|> get("/api/v1/accounts/#{remote.id}/statuses") |> get("/api/v1/accounts/#{remote.id}/statuses")
|> json_response_and_validate_schema(:not_found) |> json_response_and_validate_schema(:unauthorized)
end end
test "if user is authenticated", %{local: local, remote: remote} do 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) setup do: clear_config([:restrict_unauthenticated, :profiles, :local], true)
test "if user is unauthenticated", %{conn: conn, local: local, remote: remote} do 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 conn
|> get("/api/v1/accounts/#{local.id}/statuses") |> 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") res_conn = get(conn, "/api/v1/accounts/#{remote.id}/statuses")
assert length(json_response_and_validate_schema(res_conn, 200)) == 1 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") res_conn = get(conn, "/api/v1/accounts/#{local.id}/statuses")
assert length(json_response_and_validate_schema(res_conn, 200)) == 1 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 conn
|> get("/api/v1/accounts/#{remote.id}/statuses") |> get("/api/v1/accounts/#{remote.id}/statuses")
|> json_response_and_validate_schema(:not_found) |> json_response_and_validate_schema(:unauthorized)
end end
test "if user is authenticated", %{local: local, remote: remote} do test "if user is authenticated", %{local: local, remote: remote} do