From 5b19543f0afaaad7f8fc302946547ae5c18e8bb3 Mon Sep 17 00:00:00 2001 From: Ilja Date: Sat, 21 May 2022 18:48:21 +0200 Subject: [PATCH 01/54] Add new setting and Plug to allow for privilege settings for staff --- config/config.exs | 2 + config/description.exs | 12 +++ .../web/plugs/ensure_privileged_plug.ex | 44 +++++++++ .../web/plugs/ensure_privileged_plug_test.exs | 96 +++++++++++++++++++ 4 files changed, 154 insertions(+) create mode 100644 lib/pleroma/web/plugs/ensure_privileged_plug.ex create mode 100644 test/pleroma/web/plugs/ensure_privileged_plug_test.exs diff --git a/config/config.exs b/config/config.exs index 6a5acda09..2d501e577 100644 --- a/config/config.exs +++ b/config/config.exs @@ -257,6 +257,8 @@ password_reset_token_validity: 60 * 60 * 24, profile_directory: true, privileged_staff: false, + admin_privileges: [], + moderator_privileges: [], max_endorsed_users: 20, birthday_required: false, birthday_min_age: 0, diff --git a/config/description.exs b/config/description.exs index 704af8f68..b73b92c46 100644 --- a/config/description.exs +++ b/config/description.exs @@ -966,6 +966,18 @@ description: "Let moderators access sensitive data (e.g. updating user credentials, get password reset token, delete users, index and read private statuses and chats)" }, + %{ + key: :admin_privileges, + type: {:list, :atom}, + suggestions: [], + description: "What extra priviledges to allow admins (e.g. updating user credentials, get password reset token, delete users, index and read private statuses and chats)" + }, + %{ + key: :moderator_privileges, + type: {:list, :atom}, + suggestions: [], + description: "What extra priviledges to allow moderators (e.g. updating user credentials, get password reset token, delete users, index and read private statuses and chats)" + }, %{ key: :birthday_required, type: :boolean, diff --git a/lib/pleroma/web/plugs/ensure_privileged_plug.ex b/lib/pleroma/web/plugs/ensure_privileged_plug.ex new file mode 100644 index 000000000..be09f3d81 --- /dev/null +++ b/lib/pleroma/web/plugs/ensure_privileged_plug.ex @@ -0,0 +1,44 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2022 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.Plugs.EnsurePrivilegedPlug do + @moduledoc """ + Ensures staff are privileged enough to do certain tasks. + """ + import Pleroma.Web.TranslationHelpers + import Plug.Conn + + alias Pleroma.Config + alias Pleroma.User + + def init(options) do + options + end + + def call(%{assigns: %{user: %User{is_admin: false, is_moderator: false}}} = conn, _) do + conn + |> render_error(:forbidden, "User isn't privileged.") + |> halt() + end + + def call( + %{assigns: %{user: %User{is_admin: is_admin, is_moderator: is_moderator}}} = conn, + priviledge + ) do + if (is_admin and priviledge in Config.get([:instance, :admin_privileges])) or + (is_moderator and priviledge in Config.get([:instance, :moderator_privileges])) do + conn + else + conn + |> render_error(:forbidden, "User isn't privileged.") + |> halt() + end + end + + def call(conn, _) do + conn + |> render_error(:forbidden, "User isn't privileged.") + |> halt() + end +end diff --git a/test/pleroma/web/plugs/ensure_privileged_plug_test.exs b/test/pleroma/web/plugs/ensure_privileged_plug_test.exs new file mode 100644 index 000000000..423413946 --- /dev/null +++ b/test/pleroma/web/plugs/ensure_privileged_plug_test.exs @@ -0,0 +1,96 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2022 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.Plugs.EnsurePrivilegedPlugTest do + use Pleroma.Web.ConnCase, async: true + + alias Pleroma.Web.Plugs.EnsurePrivilegedPlug + import Pleroma.Factory + + test "denies a user that isn't moderator or admin" do + clear_config([:instance, :admin_privileges], []) + user = insert(:user) + + conn = + build_conn() + |> assign(:user, user) + |> EnsurePrivilegedPlug.call(:cofe) + + assert conn.status == 403 + end + + test "accepts an admin that is privileged" do + clear_config([:instance, :admin_privileges], [:cofe]) + user = insert(:user, is_admin: true) + conn = assign(build_conn(), :user, user) + + ret_conn = EnsurePrivilegedPlug.call(conn, :cofe) + + assert conn == ret_conn + end + + test "denies an admin that isn't privileged" do + clear_config([:instance, :admin_privileges], [:suya]) + user = insert(:user, is_admin: true) + + conn = + build_conn() + |> assign(:user, user) + |> EnsurePrivilegedPlug.call(:cofe) + + assert conn.status == 403 + end + + test "accepts a moderator that is privileged" do + clear_config([:instance, :moderator_privileges], [:cofe]) + user = insert(:user, is_moderator: true) + conn = assign(build_conn(), :user, user) + + ret_conn = EnsurePrivilegedPlug.call(conn, :cofe) + + assert conn == ret_conn + end + + test "denies a moderator that isn't privileged" do + clear_config([:instance, :moderator_privileges], [:suya]) + user = insert(:user, is_moderator: true) + + conn = + build_conn() + |> assign(:user, user) + |> EnsurePrivilegedPlug.call(:cofe) + + assert conn.status == 403 + end + + test "accepts for a priviledged role even if other role isn't priviledged" do + clear_config([:instance, :admin_privileges], [:cofe]) + clear_config([:instance, :moderator_privileges], []) + user = insert(:user, is_admin: true, is_moderator: true) + conn = assign(build_conn(), :user, user) + + ret_conn = EnsurePrivilegedPlug.call(conn, :cofe) + + # priviledged through admin role + assert conn == ret_conn + + clear_config([:instance, :admin_privileges], []) + clear_config([:instance, :moderator_privileges], [:cofe]) + user = insert(:user, is_admin: true, is_moderator: true) + conn = assign(build_conn(), :user, user) + + ret_conn = EnsurePrivilegedPlug.call(conn, :cofe) + + # priviledged through moderator role + assert conn == ret_conn + end + + test "denies when no user is set" do + conn = + build_conn() + |> EnsurePrivilegedPlug.call(:cofe) + + assert conn.status == 403 + end +end From 9f6c36475914bfd1b8c02035341765b4d1bd4395 Mon Sep 17 00:00:00 2001 From: Ilja Date: Thu, 26 May 2022 12:49:09 +0200 Subject: [PATCH 02/54] Add privilege :user_deletion --- config/config.exs | 2 +- config/description.exs | 10 ++++++---- lib/pleroma/web/router.ex | 14 ++++++++++++-- .../admin_api/controllers/user_controller_test.exs | 14 ++++++++++++++ 4 files changed, 33 insertions(+), 7 deletions(-) diff --git a/config/config.exs b/config/config.exs index 2d501e577..496a1d57a 100644 --- a/config/config.exs +++ b/config/config.exs @@ -257,7 +257,7 @@ password_reset_token_validity: 60 * 60 * 24, profile_directory: true, privileged_staff: false, - admin_privileges: [], + admin_privileges: [:user_deletion], moderator_privileges: [], max_endorsed_users: 20, birthday_required: false, diff --git a/config/description.exs b/config/description.exs index b73b92c46..b45d416b1 100644 --- a/config/description.exs +++ b/config/description.exs @@ -969,14 +969,16 @@ %{ key: :admin_privileges, type: {:list, :atom}, - suggestions: [], - description: "What extra priviledges to allow admins (e.g. updating user credentials, get password reset token, delete users, index and read private statuses and chats)" + suggestions: [:user_deletion], + description: + "What extra priviledges to allow admins (e.g. updating user credentials, get password reset token, delete users, index and read private statuses and chats)" }, %{ key: :moderator_privileges, type: {:list, :atom}, - suggestions: [], - description: "What extra priviledges to allow moderators (e.g. updating user credentials, get password reset token, delete users, index and read private statuses and chats)" + suggestions: [:user_deletion], + description: + "What extra priviledges to allow moderators (e.g. updating user credentials, get password reset token, delete users, index and read private statuses and chats)" }, %{ key: :birthday_required, diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex index ceb6c3cfd..5012fbf9a 100644 --- a/lib/pleroma/web/router.ex +++ b/lib/pleroma/web/router.ex @@ -109,6 +109,11 @@ defmodule Pleroma.Web.Router do plug(Pleroma.Web.Plugs.UserIsAdminPlug) end + pipeline :require_privileged_role_user_deletion do + plug(:admin_api) + plug(Pleroma.Web.Plugs.EnsurePrivilegedPlug, :user_deletion) + end + pipeline :pleroma_html do plug(:browser) plug(:authenticate) @@ -231,12 +236,17 @@ defmodule Pleroma.Web.Router do post("/backups", AdminAPIController, :create_backup) end + # AdminAPI: admins and mods (staff) can perform these actions (if privileged by role) + scope "/api/v1/pleroma/admin", Pleroma.Web.AdminAPI do + pipe_through([:admin_api, :require_privileged_role_user_deletion]) + + delete("/users", UserController, :delete) + end + # AdminAPI: admins and mods (staff) can perform these actions (if enabled by config) scope "/api/v1/pleroma/admin", Pleroma.Web.AdminAPI do pipe_through([:admin_api, :require_privileged_staff]) - delete("/users", UserController, :delete) - get("/users/:nickname/password_reset", AdminAPIController, :get_password_reset) patch("/users/:nickname/credentials", AdminAPIController, :update_user_credentials) diff --git a/test/pleroma/web/admin_api/controllers/user_controller_test.exs b/test/pleroma/web/admin_api/controllers/user_controller_test.exs index 79971be06..54a9619e8 100644 --- a/test/pleroma/web/admin_api/controllers/user_controller_test.exs +++ b/test/pleroma/web/admin_api/controllers/user_controller_test.exs @@ -94,6 +94,7 @@ test "GET /api/pleroma/admin/users/:nickname requires admin:read:accounts or bro describe "DELETE /api/pleroma/admin/users" do test "single user", %{admin: admin, conn: conn} do clear_config([:instance, :federating], true) + clear_config([:instance, :admin_privileges], [:user_deletion]) user = insert(:user, @@ -149,6 +150,8 @@ test "single user", %{admin: admin, conn: conn} do end test "multiple users", %{admin: admin, conn: conn} do + clear_config([:instance, :admin_privileges], [:user_deletion]) + user_one = insert(:user) user_two = insert(:user) @@ -168,6 +171,17 @@ test "multiple users", %{admin: admin, conn: conn} do assert response -- [user_one.nickname, user_two.nickname] == [] end + + test "Needs privileged role", %{conn: conn} do + clear_config([:instance, :admin_privileges], []) + + response = + conn + |> put_req_header("accept", "application/json") + |> delete("/api/pleroma/admin/users?nickname=nickname") + + assert json_response(response, :forbidden) + end end describe "/api/pleroma/admin/users" do From 8a9144ca8b8e17df509dc8ac3934656b7dac8d77 Mon Sep 17 00:00:00 2001 From: Ilja Date: Thu, 26 May 2022 13:27:06 +0200 Subject: [PATCH 03/54] Add priviledges for :user_credentials I only moved the ones from the :require_privileged_staff block for now --- config/config.exs | 2 +- config/description.exs | 4 +- lib/pleroma/web/router.ex | 15 ++++-- .../controllers/admin_api_controller_test.exs | 46 +++++++++++++++---- 4 files changed, 53 insertions(+), 14 deletions(-) diff --git a/config/config.exs b/config/config.exs index 496a1d57a..2a5770bf4 100644 --- a/config/config.exs +++ b/config/config.exs @@ -257,7 +257,7 @@ password_reset_token_validity: 60 * 60 * 24, profile_directory: true, privileged_staff: false, - admin_privileges: [:user_deletion], + admin_privileges: [:user_deletion, :user_credentials], moderator_privileges: [], max_endorsed_users: 20, birthday_required: false, diff --git a/config/description.exs b/config/description.exs index b45d416b1..4986ccce6 100644 --- a/config/description.exs +++ b/config/description.exs @@ -969,14 +969,14 @@ %{ key: :admin_privileges, type: {:list, :atom}, - suggestions: [:user_deletion], + suggestions: [:user_deletion, :user_credentials], description: "What extra priviledges to allow admins (e.g. updating user credentials, get password reset token, delete users, index and read private statuses and chats)" }, %{ key: :moderator_privileges, type: {:list, :atom}, - suggestions: [:user_deletion], + suggestions: [:user_deletion, :user_credentials], description: "What extra priviledges to allow moderators (e.g. updating user credentials, get password reset token, delete users, index and read private statuses and chats)" }, diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex index 5012fbf9a..24928ffb5 100644 --- a/lib/pleroma/web/router.ex +++ b/lib/pleroma/web/router.ex @@ -114,6 +114,11 @@ defmodule Pleroma.Web.Router do plug(Pleroma.Web.Plugs.EnsurePrivilegedPlug, :user_deletion) end + pipeline :require_privileged_role_user_credentials do + plug(:admin_api) + plug(Pleroma.Web.Plugs.EnsurePrivilegedPlug, :user_credentials) + end + pipeline :pleroma_html do plug(:browser) plug(:authenticate) @@ -206,7 +211,6 @@ defmodule Pleroma.Web.Router do patch("/users/force_password_reset", AdminAPIController, :force_password_reset) get("/users/:nickname/credentials", AdminAPIController, :show_user_credentials) - patch("/users/:nickname/credentials", AdminAPIController, :update_user_credentials) get("/instance_document/:name", InstanceDocumentController, :show) patch("/instance_document/:name", InstanceDocumentController, :update) @@ -243,12 +247,17 @@ defmodule Pleroma.Web.Router do delete("/users", UserController, :delete) end - # AdminAPI: admins and mods (staff) can perform these actions (if enabled by config) + # AdminAPI: admins and mods (staff) can perform these actions (if privileged by role) scope "/api/v1/pleroma/admin", Pleroma.Web.AdminAPI do - pipe_through([:admin_api, :require_privileged_staff]) + pipe_through([:admin_api, :require_privileged_role_user_credentials]) get("/users/:nickname/password_reset", AdminAPIController, :get_password_reset) patch("/users/:nickname/credentials", AdminAPIController, :update_user_credentials) + end + + # AdminAPI: admins and mods (staff) can perform these actions (if enabled by config) + scope "/api/v1/pleroma/admin", Pleroma.Web.AdminAPI do + pipe_through([:admin_api, :require_privileged_staff]) get("/users/:nickname/statuses", AdminAPIController, :list_user_statuses) get("/users/:nickname/chats", AdminAPIController, :list_user_chats) diff --git a/test/pleroma/web/admin_api/controllers/admin_api_controller_test.exs b/test/pleroma/web/admin_api/controllers/admin_api_controller_test.exs index d83f7f011..b9b3aed3b 100644 --- a/test/pleroma/web/admin_api/controllers/admin_api_controller_test.exs +++ b/test/pleroma/web/admin_api/controllers/admin_api_controller_test.exs @@ -271,17 +271,32 @@ test "/:right DELETE, can remove from a permission group (multiple)", %{ end end - test "/api/pleroma/admin/users/:nickname/password_reset", %{conn: conn} do - user = insert(:user) + describe "/api/pleroma/admin/users/:nickname/password_reset" do + test "it returns a password reset link", %{conn: conn} do + clear_config([:instance, :admin_privileges], [:user_credentials]) - conn = - conn - |> put_req_header("accept", "application/json") - |> get("/api/pleroma/admin/users/#{user.nickname}/password_reset") + user = insert(:user) - resp = json_response(conn, 200) + conn = + conn + |> put_req_header("accept", "application/json") + |> get("/api/pleroma/admin/users/#{user.nickname}/password_reset") - assert Regex.match?(~r/(http:\/\/|https:\/\/)/, resp["link"]) + resp = json_response(conn, 200) + + assert Regex.match?(~r/(http:\/\/|https:\/\/)/, resp["link"]) + end + + test "it requires privileged role :user_credentials", %{conn: conn} do + clear_config([:instance, :admin_privileges], []) + + response = + conn + |> put_req_header("accept", "application/json") + |> get("/api/pleroma/admin/users/nickname/password_reset") + + assert json_response(response, :forbidden) + end end describe "PUT disable_mfa" do @@ -714,6 +729,8 @@ test "returns 403 if requested by a non-admin" do end test "changes password and email", %{conn: conn, admin: admin, user: user} do + clear_config([:instance, :admin_privileges], [:user_credentials]) + assert user.password_reset_pending == false conn = @@ -756,6 +773,19 @@ test "returns 403 if requested by a non-admin", %{user: user} do assert json_response(conn, :forbidden) end + test "returns 403 if not privileged with :user_credentials", %{conn: conn, user: user} do + clear_config([:instance, :admin_privileges], []) + + conn = + patch(conn, "/api/pleroma/admin/users/#{user.nickname}/credentials", %{ + "password" => "new_password", + "email" => "new_email@example.com", + "name" => "new_name" + }) + + assert json_response(conn, :forbidden) + end + test "changes actor type from permitted list", %{conn: conn, user: user} do assert user.actor_type == "Person" From b1ff5241c21dac58ec1f9171de26772debfdb283 Mon Sep 17 00:00:00 2001 From: Ilja Date: Thu, 26 May 2022 14:21:14 +0200 Subject: [PATCH 04/54] Add priviledges for :statuses_read This was the last in :require_privileged_staff. I'll remove that in the next commit --- lib/pleroma/web/router.ex | 18 +++++++++--- .../controllers/admin_api_controller_test.exs | 29 ++++++++++++++++--- .../controllers/chat_controller_test.exs | 26 +++++++++++++++-- .../controllers/status_controller_test.exs | 12 ++++++++ 4 files changed, 75 insertions(+), 10 deletions(-) diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex index 24928ffb5..4696b4007 100644 --- a/lib/pleroma/web/router.ex +++ b/lib/pleroma/web/router.ex @@ -119,6 +119,11 @@ defmodule Pleroma.Web.Router do plug(Pleroma.Web.Plugs.EnsurePrivilegedPlug, :user_credentials) end + pipeline :require_privileged_role_statuses_read do + plug(:admin_api) + plug(Pleroma.Web.Plugs.EnsurePrivilegedPlug, :statuses_read) + end + pipeline :pleroma_html do plug(:browser) plug(:authenticate) @@ -242,22 +247,22 @@ defmodule Pleroma.Web.Router do # AdminAPI: admins and mods (staff) can perform these actions (if privileged by role) scope "/api/v1/pleroma/admin", Pleroma.Web.AdminAPI do - pipe_through([:admin_api, :require_privileged_role_user_deletion]) + pipe_through(:require_privileged_role_user_deletion) delete("/users", UserController, :delete) end # AdminAPI: admins and mods (staff) can perform these actions (if privileged by role) scope "/api/v1/pleroma/admin", Pleroma.Web.AdminAPI do - pipe_through([:admin_api, :require_privileged_role_user_credentials]) + pipe_through(:require_privileged_role_user_credentials) get("/users/:nickname/password_reset", AdminAPIController, :get_password_reset) patch("/users/:nickname/credentials", AdminAPIController, :update_user_credentials) end - # AdminAPI: admins and mods (staff) can perform these actions (if enabled by config) + # AdminAPI: admins and mods (staff) can perform these actions (if privileged by role) scope "/api/v1/pleroma/admin", Pleroma.Web.AdminAPI do - pipe_through([:admin_api, :require_privileged_staff]) + pipe_through(:require_privileged_role_statuses_read) get("/users/:nickname/statuses", AdminAPIController, :list_user_statuses) get("/users/:nickname/chats", AdminAPIController, :list_user_chats) @@ -268,6 +273,11 @@ defmodule Pleroma.Web.Router do get("/chats/:id/messages", ChatController, :messages) end + # AdminAPI: admins and mods (staff) can perform these actions (if enabled by config) + scope "/api/v1/pleroma/admin", Pleroma.Web.AdminAPI do + pipe_through([:admin_api, :require_privileged_staff]) + end + # AdminAPI: admins and mods (staff) can perform these actions scope "/api/v1/pleroma/admin", Pleroma.Web.AdminAPI do pipe_through(:admin_api) diff --git a/test/pleroma/web/admin_api/controllers/admin_api_controller_test.exs b/test/pleroma/web/admin_api/controllers/admin_api_controller_test.exs index b9b3aed3b..c630ee31b 100644 --- a/test/pleroma/web/admin_api/controllers/admin_api_controller_test.exs +++ b/test/pleroma/web/admin_api/controllers/admin_api_controller_test.exs @@ -359,6 +359,8 @@ test "need_reboot flag", %{conn: conn} do describe "GET /api/pleroma/admin/users/:nickname/statuses" do setup do + clear_config([:instance, :admin_privileges], [:statuses_read]) + user = insert(:user) insert(:note_activity, user: user) @@ -375,6 +377,14 @@ test "renders user's statuses", %{conn: conn, user: user} do assert length(activities) == 3 end + test "it requires privileged role :statuses_read", %{conn: conn, user: user} do + clear_config([:instance, :admin_privileges], []) + + conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}/statuses") + + assert json_response(conn, :forbidden) + end + test "renders user's statuses with pagination", %{conn: conn, user: user} do %{"total" => 3, "activities" => [activity1]} = conn @@ -436,21 +446,32 @@ test "excludes reblogs by default", %{conn: conn, user: user} do describe "GET /api/pleroma/admin/users/:nickname/chats" do setup do + clear_config([:instance, :admin_privileges], [:statuses_read]) + user = insert(:user) + + %{user: user} + end + + test "renders user's chats", %{conn: conn, user: user} do recipients = insert_list(3, :user) Enum.each(recipients, fn recipient -> CommonAPI.post_chat_message(user, recipient, "yo") end) - %{user: user} - end - - test "renders user's chats", %{conn: conn, user: user} do conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}/chats") assert json_response(conn, 200) |> length() == 3 end + + test "it requires privileged role :statuses_read", %{conn: conn, user: user} do + clear_config([:instance, :admin_privileges], []) + + conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}/chats") + + assert json_response(conn, :forbidden) + end end describe "GET /api/pleroma/admin/users/:nickname/chats unauthorized" do diff --git a/test/pleroma/web/admin_api/controllers/chat_controller_test.exs b/test/pleroma/web/admin_api/controllers/chat_controller_test.exs index ccf25a244..4d093ff57 100644 --- a/test/pleroma/web/admin_api/controllers/chat_controller_test.exs +++ b/test/pleroma/web/admin_api/controllers/chat_controller_test.exs @@ -63,7 +63,10 @@ test "it deletes a message from the chat", %{conn: conn, admin: admin} do end describe "GET /api/pleroma/admin/chats/:id/messages" do - setup do: admin_setup() + setup do + clear_config([:instance, :admin_privileges], [:statuses_read]) + admin_setup() + end test "it paginates", %{conn: conn} do user = insert(:user) @@ -114,10 +117,21 @@ test "it returns the messages for a given chat", %{conn: conn} do assert length(result) == 3 end + + test "it requires privileged role :statuses_read", %{conn: conn} do + clear_config([:instance, :admin_privileges], []) + + conn = get(conn, "/api/pleroma/admin/chats/some_id/messages") + + assert json_response(conn, :forbidden) + end end describe "GET /api/pleroma/admin/chats/:id" do - setup do: admin_setup() + setup do + clear_config([:instance, :admin_privileges], [:statuses_read]) + admin_setup() + end test "it returns a chat", %{conn: conn} do user = insert(:user) @@ -135,6 +149,14 @@ test "it returns a chat", %{conn: conn} do assert %{} = result["receiver"] refute result["account"] end + + test "it requires privileged role :statuses_read", %{conn: conn} do + clear_config([:instance, :admin_privileges], []) + + conn = get(conn, "/api/pleroma/admin/chats/some_id") + + assert json_response(conn, :forbidden) + end end describe "unauthorized chat moderation" do diff --git a/test/pleroma/web/admin_api/controllers/status_controller_test.exs b/test/pleroma/web/admin_api/controllers/status_controller_test.exs index 8bb96ca87..238cb9aff 100644 --- a/test/pleroma/web/admin_api/controllers/status_controller_test.exs +++ b/test/pleroma/web/admin_api/controllers/status_controller_test.exs @@ -152,6 +152,10 @@ test "returns 404 when the status does not exist", %{conn: conn} do end describe "GET /api/pleroma/admin/statuses" do + setup do + clear_config([:instance, :admin_privileges], [:statuses_read]) + end + test "returns all public and unlisted statuses", %{conn: conn, admin: admin} do blocked = insert(:user) user = insert(:user) @@ -197,5 +201,13 @@ test "returns private and direct statuses with godmode on", %{conn: conn, admin: conn = get(conn, "/api/pleroma/admin/statuses?godmode=true") assert json_response_and_validate_schema(conn, 200) |> length() == 3 end + + test "it requires privileged role :statuses_read", %{conn: conn} do + clear_config([:instance, :admin_privileges], []) + + conn = get(conn, "/api/pleroma/admin/statuses") + + assert json_response(conn, :forbidden) + end end end From 5a65e2dac5e689b8067e37817bbfe4a6fe1a0426 Mon Sep 17 00:00:00 2001 From: Ilja Date: Thu, 26 May 2022 14:51:53 +0200 Subject: [PATCH 05/54] Remove privileged_staff Everything that was done through this setting, can now be set by giving the proper privileges to the roles. --- CHANGELOG.md | 2 - config/config.exs | 3 +- config/description.exs | 10 +--- .../web/mastodon_api/views/instance_view.ex | 1 - lib/pleroma/web/nodeinfo/nodeinfo.ex | 3 +- .../web/plugs/ensure_staff_privileged_plug.ex | 36 ----------- lib/pleroma/web/router.ex | 9 --- .../ensure_staff_privileged_plug_test.exs | 60 ------------------- 8 files changed, 4 insertions(+), 120 deletions(-) delete mode 100644 lib/pleroma/web/plugs/ensure_staff_privileged_plug.ex delete mode 100644 test/pleroma/web/plugs/ensure_staff_privileged_plug_test.exs diff --git a/CHANGELOG.md b/CHANGELOG.md index 19bccd115..8a18c151c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,8 +17,6 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - `activeMonth` and `activeHalfyear` fields in NodeInfo usage.users object - Experimental support for Finch. Put `config :tesla, :adapter, {Tesla.Adapter.Finch, name: MyFinch}` in your secrets file to use it. Reverse Proxy will still use Hackney. - `ForceMentionsInPostContent` MRF policy -- AdminAPI: allow moderators to manage reports, users, invites, and custom emojis -- AdminAPI: restrict moderators to access sensitive data: change user credentials, get password reset token, read private statuses and chats, etc - PleromaAPI: Add remote follow API endpoint at `POST /api/v1/pleroma/remote_interaction` - MastoAPI: Add `GET /api/v1/accounts/lookup` - MastoAPI: Profile Directory support diff --git a/config/config.exs b/config/config.exs index 2a5770bf4..4cdc90c7a 100644 --- a/config/config.exs +++ b/config/config.exs @@ -256,8 +256,7 @@ show_reactions: true, password_reset_token_validity: 60 * 60 * 24, profile_directory: true, - privileged_staff: false, - admin_privileges: [:user_deletion, :user_credentials], + admin_privileges: [:user_deletion, :user_credentials, :statuses_read], moderator_privileges: [], max_endorsed_users: 20, birthday_required: false, diff --git a/config/description.exs b/config/description.exs index 4986ccce6..b0b8ecd88 100644 --- a/config/description.exs +++ b/config/description.exs @@ -960,23 +960,17 @@ type: :boolean, description: "Enable profile directory." }, - %{ - key: :privileged_staff, - type: :boolean, - description: - "Let moderators access sensitive data (e.g. updating user credentials, get password reset token, delete users, index and read private statuses and chats)" - }, %{ key: :admin_privileges, type: {:list, :atom}, - suggestions: [:user_deletion, :user_credentials], + suggestions: [:user_deletion, :user_credentials, :statuses_read], description: "What extra priviledges to allow admins (e.g. updating user credentials, get password reset token, delete users, index and read private statuses and chats)" }, %{ key: :moderator_privileges, type: {:list, :atom}, - suggestions: [:user_deletion, :user_credentials], + suggestions: [:user_deletion, :user_credentials, :statuses_read], description: "What extra priviledges to allow moderators (e.g. updating user credentials, get password reset token, delete users, index and read private statuses and chats)" }, diff --git a/lib/pleroma/web/mastodon_api/views/instance_view.ex b/lib/pleroma/web/mastodon_api/views/instance_view.ex index ee52475d5..f89c95a1c 100644 --- a/lib/pleroma/web/mastodon_api/views/instance_view.ex +++ b/lib/pleroma/web/mastodon_api/views/instance_view.ex @@ -47,7 +47,6 @@ def render("show.json", _) do federation: federation(), fields_limits: fields_limits(), post_formats: Config.get([:instance, :allowed_post_formats]), - privileged_staff: Config.get([:instance, :privileged_staff]), birthday_required: Config.get([:instance, :birthday_required]), birthday_min_age: Config.get([:instance, :birthday_min_age]) }, diff --git a/lib/pleroma/web/nodeinfo/nodeinfo.ex b/lib/pleroma/web/nodeinfo/nodeinfo.ex index 62d445f34..c7b9ab2de 100644 --- a/lib/pleroma/web/nodeinfo/nodeinfo.ex +++ b/lib/pleroma/web/nodeinfo/nodeinfo.ex @@ -69,8 +69,7 @@ def get_nodeinfo("2.0") do mailerEnabled: Config.get([Pleroma.Emails.Mailer, :enabled], false), features: features, restrictedNicknames: Config.get([Pleroma.User, :restricted_nicknames]), - skipThreadContainment: Config.get([:instance, :skip_thread_containment], false), - privilegedStaff: Config.get([:instance, :privileged_staff]) + skipThreadContainment: Config.get([:instance, :skip_thread_containment], false) } } end diff --git a/lib/pleroma/web/plugs/ensure_staff_privileged_plug.ex b/lib/pleroma/web/plugs/ensure_staff_privileged_plug.ex deleted file mode 100644 index 3c2109496..000000000 --- a/lib/pleroma/web/plugs/ensure_staff_privileged_plug.ex +++ /dev/null @@ -1,36 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2022 Pleroma Authors -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Web.Plugs.EnsureStaffPrivilegedPlug do - @moduledoc """ - Ensures staff are privileged enough to do certain tasks. - """ - import Pleroma.Web.TranslationHelpers - import Plug.Conn - - alias Pleroma.Config - alias Pleroma.User - - def init(options) do - options - end - - def call(%{assigns: %{user: %User{is_admin: true}}} = conn, _), do: conn - - def call(%{assigns: %{user: %User{is_moderator: true}}} = conn, _) do - if Config.get!([:instance, :privileged_staff]) do - conn - else - conn - |> render_error(:forbidden, "User is not an admin.") - |> halt() - end - end - - def call(conn, _) do - conn - |> render_error(:forbidden, "User is not a staff member.") - |> halt() - end -end diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex index 4696b4007..21b77b624 100644 --- a/lib/pleroma/web/router.ex +++ b/lib/pleroma/web/router.ex @@ -101,10 +101,6 @@ defmodule Pleroma.Web.Router do plug(Pleroma.Web.Plugs.IdempotencyPlug) end - pipeline :require_privileged_staff do - plug(Pleroma.Web.Plugs.EnsureStaffPrivilegedPlug) - end - pipeline :require_admin do plug(Pleroma.Web.Plugs.UserIsAdminPlug) end @@ -273,11 +269,6 @@ defmodule Pleroma.Web.Router do get("/chats/:id/messages", ChatController, :messages) end - # AdminAPI: admins and mods (staff) can perform these actions (if enabled by config) - scope "/api/v1/pleroma/admin", Pleroma.Web.AdminAPI do - pipe_through([:admin_api, :require_privileged_staff]) - end - # AdminAPI: admins and mods (staff) can perform these actions scope "/api/v1/pleroma/admin", Pleroma.Web.AdminAPI do pipe_through(:admin_api) diff --git a/test/pleroma/web/plugs/ensure_staff_privileged_plug_test.exs b/test/pleroma/web/plugs/ensure_staff_privileged_plug_test.exs deleted file mode 100644 index c684714b8..000000000 --- a/test/pleroma/web/plugs/ensure_staff_privileged_plug_test.exs +++ /dev/null @@ -1,60 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2022 Pleroma Authors -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Web.Plugs.EnsureStaffPrivilegedPlugTest do - use Pleroma.Web.ConnCase, async: true - - alias Pleroma.Web.Plugs.EnsureStaffPrivilegedPlug - import Pleroma.Factory - - test "accepts a user that is an admin" do - user = insert(:user, is_admin: true) - - conn = assign(build_conn(), :user, user) - - ret_conn = EnsureStaffPrivilegedPlug.call(conn, %{}) - - assert conn == ret_conn - end - - test "accepts a user that is a moderator when :privileged_staff is enabled" do - clear_config([:instance, :privileged_staff], true) - user = insert(:user, is_moderator: true) - - conn = assign(build_conn(), :user, user) - - ret_conn = EnsureStaffPrivilegedPlug.call(conn, %{}) - - assert conn == ret_conn - end - - test "denies a user that is a moderator when :privileged_staff is disabled" do - clear_config([:instance, :privileged_staff], false) - user = insert(:user, is_moderator: true) - - conn = - build_conn() - |> assign(:user, user) - |> EnsureStaffPrivilegedPlug.call(%{}) - - assert conn.status == 403 - end - - test "denies a user that isn't a staff member" do - user = insert(:user) - - conn = - build_conn() - |> assign(:user, user) - |> EnsureStaffPrivilegedPlug.call(%{}) - - assert conn.status == 403 - end - - test "denies when a user isn't set" do - conn = EnsureStaffPrivilegedPlug.call(build_conn(), %{}) - - assert conn.status == 403 - end -end From cb60cc4e02af270fcccdcd552df4fa3ff858d67f Mon Sep 17 00:00:00 2001 From: Ilja Date: Thu, 26 May 2022 16:25:28 +0200 Subject: [PATCH 06/54] Add privileges for :user_tag --- config/config.exs | 2 +- config/description.exs | 4 +- lib/pleroma/web/router.ex | 14 ++- .../controllers/admin_api_controller_test.exs | 87 +++++++++++++++---- 4 files changed, 84 insertions(+), 23 deletions(-) diff --git a/config/config.exs b/config/config.exs index 4cdc90c7a..f2001eef0 100644 --- a/config/config.exs +++ b/config/config.exs @@ -256,7 +256,7 @@ show_reactions: true, password_reset_token_validity: 60 * 60 * 24, profile_directory: true, - admin_privileges: [:user_deletion, :user_credentials, :statuses_read], + admin_privileges: [:user_deletion, :user_credentials, :statuses_read, :user_tag], moderator_privileges: [], max_endorsed_users: 20, birthday_required: false, diff --git a/config/description.exs b/config/description.exs index b0b8ecd88..f455a2e46 100644 --- a/config/description.exs +++ b/config/description.exs @@ -963,14 +963,14 @@ %{ key: :admin_privileges, type: {:list, :atom}, - suggestions: [:user_deletion, :user_credentials, :statuses_read], + suggestions: [:user_deletion, :user_credentials, :statuses_read, :user_tag], description: "What extra priviledges to allow admins (e.g. updating user credentials, get password reset token, delete users, index and read private statuses and chats)" }, %{ key: :moderator_privileges, type: {:list, :atom}, - suggestions: [:user_deletion, :user_credentials, :statuses_read], + suggestions: [:user_deletion, :user_credentials, :statuses_read, :user_tag], description: "What extra priviledges to allow moderators (e.g. updating user credentials, get password reset token, delete users, index and read private statuses and chats)" }, diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex index 21b77b624..b5b9e7d07 100644 --- a/lib/pleroma/web/router.ex +++ b/lib/pleroma/web/router.ex @@ -120,6 +120,11 @@ defmodule Pleroma.Web.Router do plug(Pleroma.Web.Plugs.EnsurePrivilegedPlug, :statuses_read) end + pipeline :require_privileged_role_user_tag do + plug(:admin_api) + plug(Pleroma.Web.Plugs.EnsurePrivilegedPlug, :user_tag) + end + pipeline :pleroma_html do plug(:browser) plug(:authenticate) @@ -269,12 +274,17 @@ defmodule Pleroma.Web.Router do get("/chats/:id/messages", ChatController, :messages) end - # AdminAPI: admins and mods (staff) can perform these actions + # AdminAPI: admins and mods (staff) can perform these actions (if privileged by role) scope "/api/v1/pleroma/admin", Pleroma.Web.AdminAPI do - pipe_through(:admin_api) + pipe_through(:require_privileged_role_user_tag) put("/users/tag", AdminAPIController, :tag_users) delete("/users/tag", AdminAPIController, :untag_users) + end + + # AdminAPI: admins and mods (staff) can perform these actions + scope "/api/v1/pleroma/admin", Pleroma.Web.AdminAPI do + pipe_through(:admin_api) patch("/users/:nickname/toggle_activation", UserController, :toggle_activation) patch("/users/activate", UserController, :activate) diff --git a/test/pleroma/web/admin_api/controllers/admin_api_controller_test.exs b/test/pleroma/web/admin_api/controllers/admin_api_controller_test.exs index c630ee31b..178e0e88a 100644 --- a/test/pleroma/web/admin_api/controllers/admin_api_controller_test.exs +++ b/test/pleroma/web/admin_api/controllers/admin_api_controller_test.exs @@ -92,18 +92,12 @@ test "GET /api/pleroma/admin/users/:nickname requires admin:read:accounts or bro describe "PUT /api/pleroma/admin/users/tag" do setup %{conn: conn} do + clear_config([:instance, :admin_privileges], [:user_tag]) + user1 = insert(:user, %{tags: ["x"]}) user2 = insert(:user, %{tags: ["y"]}) user3 = insert(:user, %{tags: ["unchanged"]}) - conn = - conn - |> put_req_header("accept", "application/json") - |> put( - "/api/pleroma/admin/users/tag?nicknames[]=#{user1.nickname}&nicknames[]=" <> - "#{user2.nickname}&tags[]=foo&tags[]=bar" - ) - %{conn: conn, user1: user1, user2: user2, user3: user3} end @@ -113,6 +107,14 @@ test "it appends specified tags to users with specified nicknames", %{ user1: user1, user2: user2 } do + conn = + conn + |> put_req_header("accept", "application/json") + |> put( + "/api/pleroma/admin/users/tag?nicknames[]=#{user1.nickname}&nicknames[]=" <> + "#{user2.nickname}&tags[]=foo&tags[]=bar" + ) + assert empty_json_response(conn) assert User.get_cached_by_id(user1.id).tags == ["x", "foo", "bar"] assert User.get_cached_by_id(user2.id).tags == ["y", "foo", "bar"] @@ -130,26 +132,43 @@ test "it appends specified tags to users with specified nicknames", %{ "@#{admin.nickname} added tags: #{tags} to users: #{users}" end - test "it does not modify tags of not specified users", %{conn: conn, user3: user3} do + test "it does not modify tags of not specified users", %{ + conn: conn, + user1: user1, + user2: user2, + user3: user3 + } do + conn = + conn + |> put_req_header("accept", "application/json") + |> put( + "/api/pleroma/admin/users/tag?nicknames[]=#{user1.nickname}&nicknames[]=" <> + "#{user2.nickname}&tags[]=foo&tags[]=bar" + ) + assert empty_json_response(conn) assert User.get_cached_by_id(user3.id).tags == ["unchanged"] end + + test "it requires privileged role :user_tag", %{conn: conn} do + clear_config([:instance, :admin_privileges], []) + + response = + conn + |> put_req_header("accept", "application/json") + |> put("/api/pleroma/admin/users/tag?nicknames[]=nickname&tags[]=foo&tags[]=bar") + + assert json_response(response, :forbidden) + end end describe "DELETE /api/pleroma/admin/users/tag" do setup %{conn: conn} do + clear_config([:instance, :admin_privileges], [:user_tag]) user1 = insert(:user, %{tags: ["x"]}) user2 = insert(:user, %{tags: ["y", "z"]}) user3 = insert(:user, %{tags: ["unchanged"]}) - conn = - conn - |> put_req_header("accept", "application/json") - |> delete( - "/api/pleroma/admin/users/tag?nicknames[]=#{user1.nickname}&nicknames[]=" <> - "#{user2.nickname}&tags[]=x&tags[]=z" - ) - %{conn: conn, user1: user1, user2: user2, user3: user3} end @@ -159,6 +178,14 @@ test "it removes specified tags from users with specified nicknames", %{ user1: user1, user2: user2 } do + conn = + conn + |> put_req_header("accept", "application/json") + |> delete( + "/api/pleroma/admin/users/tag?nicknames[]=#{user1.nickname}&nicknames[]=" <> + "#{user2.nickname}&tags[]=x&tags[]=z" + ) + assert empty_json_response(conn) assert User.get_cached_by_id(user1.id).tags == [] assert User.get_cached_by_id(user2.id).tags == ["y"] @@ -176,10 +203,34 @@ test "it removes specified tags from users with specified nicknames", %{ "@#{admin.nickname} removed tags: #{tags} from users: #{users}" end - test "it does not modify tags of not specified users", %{conn: conn, user3: user3} do + test "it does not modify tags of not specified users", %{ + conn: conn, + user1: user1, + user2: user2, + user3: user3 + } do + conn = + conn + |> put_req_header("accept", "application/json") + |> delete( + "/api/pleroma/admin/users/tag?nicknames[]=#{user1.nickname}&nicknames[]=" <> + "#{user2.nickname}&tags[]=x&tags[]=z" + ) + assert empty_json_response(conn) assert User.get_cached_by_id(user3.id).tags == ["unchanged"] end + + test "it requires privileged role :user_tag", %{conn: conn} do + clear_config([:instance, :admin_privileges], []) + + response = + conn + |> put_req_header("accept", "application/json") + |> delete("/api/pleroma/admin/users/tag?nicknames[]=nickname&tags[]=foo&tags[]=bar") + + assert json_response(response, :forbidden) + end end describe "/api/pleroma/admin/users/:nickname/permission_group" do From e102d25d2385761077c08e0b280359392f0592cb Mon Sep 17 00:00:00 2001 From: Ilja Date: Thu, 26 May 2022 16:41:48 +0200 Subject: [PATCH 07/54] Add privileges for :user_activation --- config/config.exs | 8 +- config/description.exs | 16 +- lib/pleroma/web/router.ex | 16 +- .../controllers/user_controller_test.exs | 159 ++++++++++++------ 4 files changed, 137 insertions(+), 62 deletions(-) diff --git a/config/config.exs b/config/config.exs index f2001eef0..53c0cc329 100644 --- a/config/config.exs +++ b/config/config.exs @@ -256,7 +256,13 @@ show_reactions: true, password_reset_token_validity: 60 * 60 * 24, profile_directory: true, - admin_privileges: [:user_deletion, :user_credentials, :statuses_read, :user_tag], + admin_privileges: [ + :user_deletion, + :user_credentials, + :statuses_read, + :user_tag, + :user_activation + ], moderator_privileges: [], max_endorsed_users: 20, birthday_required: false, diff --git a/config/description.exs b/config/description.exs index f455a2e46..51d3ad8aa 100644 --- a/config/description.exs +++ b/config/description.exs @@ -963,14 +963,26 @@ %{ key: :admin_privileges, type: {:list, :atom}, - suggestions: [:user_deletion, :user_credentials, :statuses_read, :user_tag], + suggestions: [ + :user_deletion, + :user_credentials, + :statuses_read, + :user_tag, + :user_activation + ], description: "What extra priviledges to allow admins (e.g. updating user credentials, get password reset token, delete users, index and read private statuses and chats)" }, %{ key: :moderator_privileges, type: {:list, :atom}, - suggestions: [:user_deletion, :user_credentials, :statuses_read, :user_tag], + suggestions: [ + :user_deletion, + :user_credentials, + :statuses_read, + :user_tag, + :user_activation + ], description: "What extra priviledges to allow moderators (e.g. updating user credentials, get password reset token, delete users, index and read private statuses and chats)" }, diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex index b5b9e7d07..bfe5c7b90 100644 --- a/lib/pleroma/web/router.ex +++ b/lib/pleroma/web/router.ex @@ -125,6 +125,11 @@ defmodule Pleroma.Web.Router do plug(Pleroma.Web.Plugs.EnsurePrivilegedPlug, :user_tag) end + pipeline :require_privileged_role_user_activation do + plug(:admin_api) + plug(Pleroma.Web.Plugs.EnsurePrivilegedPlug, :user_activation) + end + pipeline :pleroma_html do plug(:browser) plug(:authenticate) @@ -282,15 +287,20 @@ defmodule Pleroma.Web.Router do delete("/users/tag", AdminAPIController, :untag_users) end - # AdminAPI: admins and mods (staff) can perform these actions + # AdminAPI: admins and mods (staff) can perform these actions (if privileged by role) scope "/api/v1/pleroma/admin", Pleroma.Web.AdminAPI do - pipe_through(:admin_api) + pipe_through(:require_privileged_role_user_activation) patch("/users/:nickname/toggle_activation", UserController, :toggle_activation) patch("/users/activate", UserController, :activate) patch("/users/deactivate", UserController, :deactivate) - patch("/users/approve", UserController, :approve) + end + # AdminAPI: admins and mods (staff) can perform these actions + scope "/api/v1/pleroma/admin", Pleroma.Web.AdminAPI do + pipe_through(:admin_api) + + patch("/users/approve", UserController, :approve) post("/users/invite_token", InviteController, :create) get("/users/invites", InviteController, :index) post("/users/revoke_invite", InviteController, :revoke) diff --git a/test/pleroma/web/admin_api/controllers/user_controller_test.exs b/test/pleroma/web/admin_api/controllers/user_controller_test.exs index 54a9619e8..ea28863f3 100644 --- a/test/pleroma/web/admin_api/controllers/user_controller_test.exs +++ b/test/pleroma/web/admin_api/controllers/user_controller_test.exs @@ -824,48 +824,6 @@ test "it omits relay user", %{admin: admin, conn: conn} do end end - test "PATCH /api/pleroma/admin/users/activate", %{admin: admin, conn: conn} do - user_one = insert(:user, is_active: false) - user_two = insert(:user, is_active: false) - - conn = - conn - |> put_req_header("content-type", "application/json") - |> patch( - "/api/pleroma/admin/users/activate", - %{nicknames: [user_one.nickname, user_two.nickname]} - ) - - response = json_response_and_validate_schema(conn, 200) - assert Enum.map(response["users"], & &1["is_active"]) == [true, true] - - log_entry = Repo.one(ModerationLog) - - assert ModerationLog.get_log_entry_message(log_entry) == - "@#{admin.nickname} activated users: @#{user_one.nickname}, @#{user_two.nickname}" - end - - test "PATCH /api/pleroma/admin/users/deactivate", %{admin: admin, conn: conn} do - user_one = insert(:user, is_active: true) - user_two = insert(:user, is_active: true) - - conn = - conn - |> put_req_header("content-type", "application/json") - |> patch( - "/api/pleroma/admin/users/deactivate", - %{nicknames: [user_one.nickname, user_two.nickname]} - ) - - response = json_response_and_validate_schema(conn, 200) - assert Enum.map(response["users"], & &1["is_active"]) == [false, false] - - log_entry = Repo.one(ModerationLog) - - assert ModerationLog.get_log_entry_message(log_entry) == - "@#{admin.nickname} deactivated users: @#{user_one.nickname}, @#{user_two.nickname}" - end - test "PATCH /api/pleroma/admin/users/approve", %{admin: admin, conn: conn} do user_one = insert(:user, is_approved: false) user_two = insert(:user, is_approved: false) @@ -937,24 +895,113 @@ test "PATCH /api/pleroma/admin/users/unsuggest", %{admin: admin, conn: conn} do "@#{admin.nickname} removed suggested users: @#{user1.nickname}, @#{user2.nickname}" end - test "PATCH /api/pleroma/admin/users/:nickname/toggle_activation", %{admin: admin, conn: conn} do - user = insert(:user) + describe "user activation" do + test "PATCH /api/pleroma/admin/users/activate", %{admin: admin, conn: conn} do + clear_config([:instance, :admin_privileges], [:user_activation]) - conn = - conn - |> put_req_header("content-type", "application/json") - |> patch("/api/pleroma/admin/users/#{user.nickname}/toggle_activation") + user_one = insert(:user, is_active: false) + user_two = insert(:user, is_active: false) - assert json_response_and_validate_schema(conn, 200) == - user_response( - user, - %{"is_active" => !user.is_active} - ) + conn = + conn + |> put_req_header("content-type", "application/json") + |> patch( + "/api/pleroma/admin/users/activate", + %{nicknames: [user_one.nickname, user_two.nickname]} + ) - log_entry = Repo.one(ModerationLog) + response = json_response_and_validate_schema(conn, 200) + assert Enum.map(response["users"], & &1["is_active"]) == [true, true] - assert ModerationLog.get_log_entry_message(log_entry) == - "@#{admin.nickname} deactivated users: @#{user.nickname}" + log_entry = Repo.one(ModerationLog) + + assert ModerationLog.get_log_entry_message(log_entry) == + "@#{admin.nickname} activated users: @#{user_one.nickname}, @#{user_two.nickname}" + end + + test "PATCH /api/pleroma/admin/users/deactivate", %{admin: admin, conn: conn} do + clear_config([:instance, :admin_privileges], [:user_activation]) + + user_one = insert(:user, is_active: true) + user_two = insert(:user, is_active: true) + + conn = + conn + |> put_req_header("content-type", "application/json") + |> patch( + "/api/pleroma/admin/users/deactivate", + %{nicknames: [user_one.nickname, user_two.nickname]} + ) + + response = json_response_and_validate_schema(conn, 200) + assert Enum.map(response["users"], & &1["is_active"]) == [false, false] + + log_entry = Repo.one(ModerationLog) + + assert ModerationLog.get_log_entry_message(log_entry) == + "@#{admin.nickname} deactivated users: @#{user_one.nickname}, @#{user_two.nickname}" + end + + test "PATCH /api/pleroma/admin/users/:nickname/toggle_activation", %{admin: admin, conn: conn} do + clear_config([:instance, :admin_privileges], [:user_activation]) + + user = insert(:user) + + conn = + conn + |> put_req_header("content-type", "application/json") + |> patch("/api/pleroma/admin/users/#{user.nickname}/toggle_activation") + + assert json_response_and_validate_schema(conn, 200) == + user_response( + user, + %{"is_active" => !user.is_active} + ) + + log_entry = Repo.one(ModerationLog) + + assert ModerationLog.get_log_entry_message(log_entry) == + "@#{admin.nickname} deactivated users: @#{user.nickname}" + end + + test "it requires privileged role :statuses_activation to activate", %{conn: conn} do + clear_config([:instance, :admin_privileges], []) + + conn = + conn + |> put_req_header("content-type", "application/json") + |> patch( + "/api/pleroma/admin/users/activate", + %{nicknames: ["user_one.nickname", "user_two.nickname"]} + ) + + assert json_response(conn, :forbidden) + end + + test "it requires privileged role :statuses_activation to deactivate", %{conn: conn} do + clear_config([:instance, :admin_privileges], []) + + conn = + conn + |> put_req_header("content-type", "application/json") + |> patch( + "/api/pleroma/admin/users/deactivate", + %{nicknames: ["user_one.nickname", "user_two.nickname"]} + ) + + assert json_response(conn, :forbidden) + end + + test "it requires privileged role :statuses_activation to toggle activation", %{conn: conn} do + clear_config([:instance, :admin_privileges], []) + + conn = + conn + |> put_req_header("content-type", "application/json") + |> patch("/api/pleroma/admin/users/user.nickname/toggle_activation") + + assert json_response(conn, :forbidden) + end end defp user_response(user, attrs \\ %{}) do From 14e697a64fe2613649634d46a71acf4d9a7d7bd6 Mon Sep 17 00:00:00 2001 From: Ilja Date: Sat, 28 May 2022 08:51:49 +0200 Subject: [PATCH 08/54] Add privileges for :user_invite --- config/config.exs | 3 +- config/description.exs | 6 +- lib/pleroma/web/router.ex | 14 +++- .../controllers/invite_controller_test.exs | 70 +++++++++++++++++-- .../controllers/user_controller_test.exs | 17 +++++ 5 files changed, 101 insertions(+), 9 deletions(-) diff --git a/config/config.exs b/config/config.exs index 53c0cc329..a0c18c75a 100644 --- a/config/config.exs +++ b/config/config.exs @@ -261,7 +261,8 @@ :user_credentials, :statuses_read, :user_tag, - :user_activation + :user_activation, + :user_invite ], moderator_privileges: [], max_endorsed_users: 20, diff --git a/config/description.exs b/config/description.exs index 51d3ad8aa..7e74778c5 100644 --- a/config/description.exs +++ b/config/description.exs @@ -968,7 +968,8 @@ :user_credentials, :statuses_read, :user_tag, - :user_activation + :user_activation, + :user_invite ], description: "What extra priviledges to allow admins (e.g. updating user credentials, get password reset token, delete users, index and read private statuses and chats)" @@ -981,7 +982,8 @@ :user_credentials, :statuses_read, :user_tag, - :user_activation + :user_activation, + :user_invite ], description: "What extra priviledges to allow moderators (e.g. updating user credentials, get password reset token, delete users, index and read private statuses and chats)" diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex index bfe5c7b90..87e564488 100644 --- a/lib/pleroma/web/router.ex +++ b/lib/pleroma/web/router.ex @@ -130,6 +130,11 @@ defmodule Pleroma.Web.Router do plug(Pleroma.Web.Plugs.EnsurePrivilegedPlug, :user_activation) end + pipeline :require_privileged_role_user_invite do + plug(:admin_api) + plug(Pleroma.Web.Plugs.EnsurePrivilegedPlug, :user_invite) + end + pipeline :pleroma_html do plug(:browser) plug(:authenticate) @@ -296,15 +301,20 @@ defmodule Pleroma.Web.Router do patch("/users/deactivate", UserController, :deactivate) end - # AdminAPI: admins and mods (staff) can perform these actions + # AdminAPI: admins and mods (staff) can perform these actions (if privileged by role) scope "/api/v1/pleroma/admin", Pleroma.Web.AdminAPI do - pipe_through(:admin_api) + pipe_through(:require_privileged_role_user_invite) patch("/users/approve", UserController, :approve) post("/users/invite_token", InviteController, :create) get("/users/invites", InviteController, :index) post("/users/revoke_invite", InviteController, :revoke) post("/users/email_invite", InviteController, :email) + end + + # AdminAPI: admins and mods (staff) can perform these actions + scope "/api/v1/pleroma/admin", Pleroma.Web.AdminAPI do + pipe_through(:admin_api) get("/users", UserController, :index) get("/users/:nickname", UserController, :show) diff --git a/test/pleroma/web/admin_api/controllers/invite_controller_test.exs b/test/pleroma/web/admin_api/controllers/invite_controller_test.exs index b9d48a4b6..17c2aa104 100644 --- a/test/pleroma/web/admin_api/controllers/invite_controller_test.exs +++ b/test/pleroma/web/admin_api/controllers/invite_controller_test.exs @@ -23,8 +23,25 @@ defmodule Pleroma.Web.AdminAPI.InviteControllerTest do end describe "POST /api/pleroma/admin/users/email_invite, with valid config" do - setup do: clear_config([:instance, :registrations_open], false) - setup do: clear_config([:instance, :invites_enabled], true) + setup do + clear_config([:instance, :registrations_open], false) + clear_config([:instance, :invites_enabled], true) + clear_config([:instance, :admin_privileges], [:user_invite]) + end + + test "returns 403 if not privileged with :user_invite", %{conn: conn} do + clear_config([:instance, :admin_privileges], []) + + conn = + conn + |> put_req_header("content-type", "application/json;charset=utf-8") + |> post("/api/pleroma/admin/users/email_invite", %{ + email: "foo@bar.com", + name: "J. D." + }) + + assert json_response(conn, :forbidden) + end test "sends invitation and returns 204", %{admin: admin, conn: conn} do recipient_email = "foo@bar.com" @@ -114,8 +131,11 @@ test "email with +", %{conn: conn, admin: admin} do end describe "POST /api/pleroma/admin/users/email_invite, with invalid config" do - setup do: clear_config([:instance, :registrations_open]) - setup do: clear_config([:instance, :invites_enabled]) + setup do + clear_config([:instance, :registrations_open]) + clear_config([:instance, :invites_enabled]) + clear_config([:instance, :admin_privileges], [:user_invite]) + end test "it returns 500 if `invites_enabled` is not enabled", %{conn: conn} do clear_config([:instance, :registrations_open], false) @@ -157,6 +177,21 @@ test "it returns 500 if `registrations_open` is enabled", %{conn: conn} do end describe "POST /api/pleroma/admin/users/invite_token" do + setup do + clear_config([:instance, :admin_privileges], [:user_invite]) + end + + test "returns 403 if not privileged with :user_invite", %{conn: conn} do + clear_config([:instance, :admin_privileges], []) + + conn = + conn + |> put_req_header("content-type", "application/json") + |> post("/api/pleroma/admin/users/invite_token") + + assert json_response(conn, :forbidden) + end + test "without options", %{conn: conn} do conn = conn @@ -221,6 +256,18 @@ test "with max use and expires_at", %{conn: conn} do end describe "GET /api/pleroma/admin/users/invites" do + setup do + clear_config([:instance, :admin_privileges], [:user_invite]) + end + + test "returns 403 if not privileged with :user_invite", %{conn: conn} do + clear_config([:instance, :admin_privileges], []) + + conn = get(conn, "/api/pleroma/admin/users/invites") + + assert json_response(conn, :forbidden) + end + test "no invites", %{conn: conn} do conn = get(conn, "/api/pleroma/admin/users/invites") @@ -249,6 +296,21 @@ test "with invite", %{conn: conn} do end describe "POST /api/pleroma/admin/users/revoke_invite" do + setup do + clear_config([:instance, :admin_privileges], [:user_invite]) + end + + test "returns 403 if not privileged with :user_invite", %{conn: conn} do + clear_config([:instance, :admin_privileges], []) + + conn = + conn + |> put_req_header("content-type", "application/json") + |> post("/api/pleroma/admin/users/revoke_invite", %{"token" => "foo"}) + + assert json_response(conn, :forbidden) + end + test "with token", %{conn: conn} do {:ok, invite} = UserInviteToken.create_invite() diff --git a/test/pleroma/web/admin_api/controllers/user_controller_test.exs b/test/pleroma/web/admin_api/controllers/user_controller_test.exs index ea28863f3..f221b9c51 100644 --- a/test/pleroma/web/admin_api/controllers/user_controller_test.exs +++ b/test/pleroma/web/admin_api/controllers/user_controller_test.exs @@ -825,6 +825,8 @@ test "it omits relay user", %{admin: admin, conn: conn} do end test "PATCH /api/pleroma/admin/users/approve", %{admin: admin, conn: conn} do + clear_config([:instance, :admin_privileges], [:user_invite]) + user_one = insert(:user, is_approved: false) user_two = insert(:user, is_approved: false) @@ -845,6 +847,21 @@ test "PATCH /api/pleroma/admin/users/approve", %{admin: admin, conn: conn} do "@#{admin.nickname} approved users: @#{user_one.nickname}, @#{user_two.nickname}" end + test "PATCH /api/pleroma/admin/users/approve returns 403 if not privileged with :user_invite", + %{conn: conn} do + clear_config([:instance, :admin_privileges], []) + + conn = + conn + |> put_req_header("content-type", "application/json") + |> patch( + "/api/pleroma/admin/users/approve", + %{nicknames: ["user_one.nickname", "user_two.nickname"]} + ) + + assert json_response(conn, :forbidden) + end + test "PATCH /api/pleroma/admin/users/suggest", %{admin: admin, conn: conn} do user1 = insert(:user, is_suggested: false) user2 = insert(:user, is_suggested: false) From 3f26f1b30fe605635e3faf610f813f3ae3ad43ec Mon Sep 17 00:00:00 2001 From: Ilja Date: Sat, 28 May 2022 09:43:57 +0200 Subject: [PATCH 09/54] Add privileges for :report_handle --- config/config.exs | 3 +- config/description.exs | 6 +- lib/pleroma/web/router.ex | 22 +++++-- .../controllers/report_controller_test.exs | 62 +++++++++++++++++++ 4 files changed, 84 insertions(+), 9 deletions(-) diff --git a/config/config.exs b/config/config.exs index a0c18c75a..6fd7044e3 100644 --- a/config/config.exs +++ b/config/config.exs @@ -262,7 +262,8 @@ :statuses_read, :user_tag, :user_activation, - :user_invite + :user_invite, + :report_handle ], moderator_privileges: [], max_endorsed_users: 20, diff --git a/config/description.exs b/config/description.exs index 7e74778c5..d0364340e 100644 --- a/config/description.exs +++ b/config/description.exs @@ -969,7 +969,8 @@ :statuses_read, :user_tag, :user_activation, - :user_invite + :user_invite, + :report_handle ], description: "What extra priviledges to allow admins (e.g. updating user credentials, get password reset token, delete users, index and read private statuses and chats)" @@ -983,7 +984,8 @@ :statuses_read, :user_tag, :user_activation, - :user_invite + :user_invite, + :report_handle ], description: "What extra priviledges to allow moderators (e.g. updating user credentials, get password reset token, delete users, index and read private statuses and chats)" diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex index 87e564488..dbcd6f399 100644 --- a/lib/pleroma/web/router.ex +++ b/lib/pleroma/web/router.ex @@ -135,6 +135,11 @@ defmodule Pleroma.Web.Router do plug(Pleroma.Web.Plugs.EnsurePrivilegedPlug, :user_invite) end + pipeline :require_privileged_role_report_handle do + plug(:admin_api) + plug(Pleroma.Web.Plugs.EnsurePrivilegedPlug, :report_handle) + end + pipeline :pleroma_html do plug(:browser) plug(:authenticate) @@ -312,6 +317,17 @@ defmodule Pleroma.Web.Router do post("/users/email_invite", InviteController, :email) end + # AdminAPI: admins and mods (staff) can perform these actions (if privileged by role) + scope "/api/v1/pleroma/admin", Pleroma.Web.AdminAPI do + pipe_through(:require_privileged_role_report_handle) + + get("/reports", ReportController, :index) + get("/reports/:id", ReportController, :show) + patch("/reports", ReportController, :update) + post("/reports/:id/notes", ReportController, :notes_create) + delete("/reports/:report_id/notes/:id", ReportController, :notes_delete) + end + # AdminAPI: admins and mods (staff) can perform these actions scope "/api/v1/pleroma/admin", Pleroma.Web.AdminAPI do pipe_through(:admin_api) @@ -322,12 +338,6 @@ defmodule Pleroma.Web.Router do get("/instances/:instance/statuses", InstanceController, :list_statuses) delete("/instances/:instance", InstanceController, :delete) - get("/reports", ReportController, :index) - get("/reports/:id", ReportController, :show) - patch("/reports", ReportController, :update) - post("/reports/:id/notes", ReportController, :notes_create) - delete("/reports/:report_id/notes/:id", ReportController, :notes_delete) - get("/statuses/:id", StatusController, :show) put("/statuses/:id", StatusController, :update) delete("/statuses/:id", StatusController, :delete) diff --git a/test/pleroma/web/admin_api/controllers/report_controller_test.exs b/test/pleroma/web/admin_api/controllers/report_controller_test.exs index 30dcb87e2..c39cf978b 100644 --- a/test/pleroma/web/admin_api/controllers/report_controller_test.exs +++ b/test/pleroma/web/admin_api/controllers/report_controller_test.exs @@ -26,6 +26,20 @@ defmodule Pleroma.Web.AdminAPI.ReportControllerTest do end describe "GET /api/pleroma/admin/reports/:id" do + setup do + clear_config([:instance, :admin_privileges], [:report_handle]) + end + + test "returns 403 if not privileged with :report_handle", %{conn: conn} do + clear_config([:instance, :admin_privileges], []) + + conn = + conn + |> get("/api/pleroma/admin/reports/report_id") + + assert json_response(conn, :forbidden) + end + test "returns report by its id", %{conn: conn} do [reporter, target_user] = insert_pair(:user) activity = insert(:note_activity, user: target_user) @@ -63,6 +77,8 @@ test "returns 404 when report id is invalid", %{conn: conn} do describe "PATCH /api/pleroma/admin/reports" do setup do + clear_config([:instance, :admin_privileges], [:report_handle]) + [reporter, target_user] = insert_pair(:user) activity = insert(:note_activity, user: target_user) @@ -86,6 +102,20 @@ test "returns 404 when report id is invalid", %{conn: conn} do } end + test "returns 403 if not privileged with :report_handle", %{conn: conn, id: id, admin: admin} do + clear_config([:instance, :admin_privileges], []) + + conn = + conn + |> assign(:token, insert(:oauth_token, user: admin, scopes: ["admin:write:reports"])) + |> put_req_header("content-type", "application/json") + |> patch("/api/pleroma/admin/reports", %{ + "reports" => [%{"state" => "resolved", "id" => id}] + }) + + assert json_response(conn, :forbidden) + end + test "requires admin:write:reports scope", %{conn: conn, id: id, admin: admin} do read_token = insert(:oauth_token, user: admin, scopes: ["admin:read"]) write_token = insert(:oauth_token, user: admin, scopes: ["admin:write:reports"]) @@ -209,6 +239,20 @@ test "updates state of multiple reports", %{ end describe "GET /api/pleroma/admin/reports" do + setup do + clear_config([:instance, :admin_privileges], [:report_handle]) + end + + test "returns 403 if not privileged with :report_handle", %{conn: conn} do + clear_config([:instance, :admin_privileges], []) + + conn = + conn + |> get(report_path(conn, :index)) + + assert json_response(conn, :forbidden) + end + test "returns empty response when no reports created", %{conn: conn} do response = conn @@ -317,6 +361,8 @@ test "returns 403 when requested by anonymous" do describe "POST /api/pleroma/admin/reports/:id/notes" do setup %{conn: conn, admin: admin} do + clear_config([:instance, :admin_privileges], [:report_handle]) + [reporter, target_user] = insert_pair(:user) activity = insert(:note_activity, user: target_user) @@ -345,6 +391,22 @@ test "returns 403 when requested by anonymous" do } end + test "returns 403 if not privileged with :report_handle", %{conn: conn, report_id: report_id} do + clear_config([:instance, :admin_privileges], []) + + post_conn = + conn + |> put_req_header("content-type", "application/json") + |> post("/api/pleroma/admin/reports/#{report_id}/notes", %{ + content: "this is disgusting2!" + }) + + delete_conn = delete(conn, "/api/pleroma/admin/reports/#{report_id}/notes/note.id") + + assert json_response(post_conn, :forbidden) + assert json_response(delete_conn, :forbidden) + end + test "it creates report note", %{admin_id: admin_id, report_id: report_id} do assert [note, _] = Repo.all(ReportNote) From cbb26262a5957d3a72bef383a394bb3b2ad0215d Mon Sep 17 00:00:00 2001 From: Ilja Date: Sat, 28 May 2022 12:15:36 +0200 Subject: [PATCH 10/54] Add privileges for :user_read --- config/config.exs | 3 +- config/description.exs | 6 +- lib/pleroma/web/router.ex | 14 ++- .../controllers/user_controller_test.exs | 115 +++++++++++------- 4 files changed, 88 insertions(+), 50 deletions(-) diff --git a/config/config.exs b/config/config.exs index 6fd7044e3..778e6bf21 100644 --- a/config/config.exs +++ b/config/config.exs @@ -263,7 +263,8 @@ :user_tag, :user_activation, :user_invite, - :report_handle + :report_handle, + :user_read ], moderator_privileges: [], max_endorsed_users: 20, diff --git a/config/description.exs b/config/description.exs index d0364340e..6d8cacace 100644 --- a/config/description.exs +++ b/config/description.exs @@ -970,7 +970,8 @@ :user_tag, :user_activation, :user_invite, - :report_handle + :report_handle, + :user_read ], description: "What extra priviledges to allow admins (e.g. updating user credentials, get password reset token, delete users, index and read private statuses and chats)" @@ -985,7 +986,8 @@ :user_tag, :user_activation, :user_invite, - :report_handle + :report_handle, + :user_read ], description: "What extra priviledges to allow moderators (e.g. updating user credentials, get password reset token, delete users, index and read private statuses and chats)" diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex index dbcd6f399..68719c570 100644 --- a/lib/pleroma/web/router.ex +++ b/lib/pleroma/web/router.ex @@ -140,6 +140,11 @@ defmodule Pleroma.Web.Router do plug(Pleroma.Web.Plugs.EnsurePrivilegedPlug, :report_handle) end + pipeline :require_privileged_role_user_read do + plug(:admin_api) + plug(Pleroma.Web.Plugs.EnsurePrivilegedPlug, :user_read) + end + pipeline :pleroma_html do plug(:browser) plug(:authenticate) @@ -328,12 +333,17 @@ defmodule Pleroma.Web.Router do delete("/reports/:report_id/notes/:id", ReportController, :notes_delete) end - # AdminAPI: admins and mods (staff) can perform these actions + # AdminAPI: admins and mods (staff) can perform these actions (if privileged by role) scope "/api/v1/pleroma/admin", Pleroma.Web.AdminAPI do - pipe_through(:admin_api) + pipe_through(:require_privileged_role_user_read) get("/users", UserController, :index) get("/users/:nickname", UserController, :show) + end + + # AdminAPI: admins and mods (staff) can perform these actions + scope "/api/v1/pleroma/admin", Pleroma.Web.AdminAPI do + pipe_through(:admin_api) get("/instances/:instance/statuses", InstanceController, :list_statuses) delete("/instances/:instance", InstanceController, :delete) diff --git a/test/pleroma/web/admin_api/controllers/user_controller_test.exs b/test/pleroma/web/admin_api/controllers/user_controller_test.exs index f221b9c51..a6e41c761 100644 --- a/test/pleroma/web/admin_api/controllers/user_controller_test.exs +++ b/test/pleroma/web/admin_api/controllers/user_controller_test.exs @@ -38,6 +38,7 @@ defmodule Pleroma.Web.AdminAPI.UserControllerTest do end test "with valid `admin_token` query parameter, skips OAuth scopes check" do + clear_config([:instance, :admin_privileges], [:user_read]) clear_config([:admin_token], "password123") user = insert(:user) @@ -47,50 +48,6 @@ test "with valid `admin_token` query parameter, skips OAuth scopes check" do assert json_response_and_validate_schema(conn, 200) end - test "GET /api/pleroma/admin/users/:nickname requires admin:read:accounts or broader scope", - %{admin: admin} do - user = insert(:user) - url = "/api/pleroma/admin/users/#{user.nickname}" - - good_token1 = insert(:oauth_token, user: admin, scopes: ["admin"]) - good_token2 = insert(:oauth_token, user: admin, scopes: ["admin:read"]) - good_token3 = insert(:oauth_token, user: admin, scopes: ["admin:read:accounts"]) - - bad_token1 = insert(:oauth_token, user: admin, scopes: ["read:accounts"]) - bad_token2 = insert(:oauth_token, user: admin, scopes: ["admin:read:accounts:partial"]) - bad_token3 = nil - - for good_token <- [good_token1, good_token2, good_token3] do - conn = - build_conn() - |> assign(:user, admin) - |> assign(:token, good_token) - |> get(url) - - assert json_response_and_validate_schema(conn, 200) - end - - for good_token <- [good_token1, good_token2, good_token3] do - conn = - build_conn() - |> assign(:user, nil) - |> assign(:token, good_token) - |> get(url) - - assert json_response(conn, :forbidden) - end - - for bad_token <- [bad_token1, bad_token2, bad_token3] do - conn = - build_conn() - |> assign(:user, admin) - |> assign(:token, bad_token) - |> get(url) - - assert json_response_and_validate_schema(conn, :forbidden) - end - end - describe "DELETE /api/pleroma/admin/users" do test "single user", %{admin: admin, conn: conn} do clear_config([:instance, :federating], true) @@ -321,7 +278,19 @@ test "Multiple user creation works in transaction", %{conn: conn} do end end - describe "/api/pleroma/admin/users/:nickname" do + describe "GET /api/pleroma/admin/users/:nickname" do + setup do + clear_config([:instance, :admin_privileges], [:user_read]) + end + + test "returns 403 if not privileged with :user_read", %{conn: conn} do + clear_config([:instance, :admin_privileges], []) + + conn = get(conn, "/api/pleroma/admin/users/user.nickname") + + assert json_response(conn, :forbidden) + end + test "Show", %{conn: conn} do user = insert(:user) @@ -337,6 +306,50 @@ test "when the user doesn't exist", %{conn: conn} do assert %{"error" => "Not found"} == json_response_and_validate_schema(conn, 404) end + + test "requires admin:read:accounts or broader scope", + %{admin: admin} do + user = insert(:user) + url = "/api/pleroma/admin/users/#{user.nickname}" + + good_token1 = insert(:oauth_token, user: admin, scopes: ["admin"]) + good_token2 = insert(:oauth_token, user: admin, scopes: ["admin:read"]) + good_token3 = insert(:oauth_token, user: admin, scopes: ["admin:read:accounts"]) + + bad_token1 = insert(:oauth_token, user: admin, scopes: ["read:accounts"]) + bad_token2 = insert(:oauth_token, user: admin, scopes: ["admin:read:accounts:partial"]) + bad_token3 = nil + + for good_token <- [good_token1, good_token2, good_token3] do + conn = + build_conn() + |> assign(:user, admin) + |> assign(:token, good_token) + |> get(url) + + assert json_response_and_validate_schema(conn, 200) + end + + for good_token <- [good_token1, good_token2, good_token3] do + conn = + build_conn() + |> assign(:user, nil) + |> assign(:token, good_token) + |> get(url) + + assert json_response(conn, :forbidden) + end + + for bad_token <- [bad_token1, bad_token2, bad_token3] do + conn = + build_conn() + |> assign(:user, admin) + |> assign(:token, bad_token) + |> get(url) + + assert json_response_and_validate_schema(conn, :forbidden) + end + end end describe "/api/pleroma/admin/users/follow" do @@ -392,6 +405,18 @@ test "allows to force-unfollow another user", %{admin: admin, conn: conn} do end describe "GET /api/pleroma/admin/users" do + setup do + clear_config([:instance, :admin_privileges], [:user_read]) + end + + test "returns 403 if not privileged with :user_read", %{conn: conn} do + clear_config([:instance, :admin_privileges], []) + + conn = get(conn, "/api/pleroma/admin/users?page=1") + + assert json_response(conn, :forbidden) + end + test "renders users array for the first page", %{conn: conn, admin: admin} do user = insert(:user, local: false, tags: ["foo", "bar"]) user2 = insert(:user, is_approved: false, registration_reason: "I'm a chill dude") From 4cb0dbb5dce93ebc6c638c99eab13d0d2c02667c Mon Sep 17 00:00:00 2001 From: Ilja Date: Sun, 5 Jun 2022 12:50:19 +0200 Subject: [PATCH 11/54] Mark relevant tests synchronous One of the things we do during the tests is change the config. But that's global state and different tests were interfering. E.g. one test would set `clear_config([:instance, :admin_privileges], [:statuses_read])`, but while that runs, another test may do `clear_config([:instance, :admin_privileges], [:user_invite])`. Now the code for the first test checks the setting, and it finds `:user_invite` instead of `:statuses_read`. Now the modules where this happens are marked to run synchronously, so they don't interfere with each other. --- .../web/admin_api/controllers/admin_api_controller_test.exs | 2 +- test/pleroma/web/admin_api/controllers/chat_controller_test.exs | 2 +- .../web/admin_api/controllers/invite_controller_test.exs | 2 +- .../web/admin_api/controllers/report_controller_test.exs | 2 +- .../web/admin_api/controllers/status_controller_test.exs | 2 +- test/pleroma/web/admin_api/controllers/user_controller_test.exs | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/test/pleroma/web/admin_api/controllers/admin_api_controller_test.exs b/test/pleroma/web/admin_api/controllers/admin_api_controller_test.exs index 178e0e88a..1df28f147 100644 --- a/test/pleroma/web/admin_api/controllers/admin_api_controller_test.exs +++ b/test/pleroma/web/admin_api/controllers/admin_api_controller_test.exs @@ -3,7 +3,7 @@ # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do - use Pleroma.Web.ConnCase + use Pleroma.Web.ConnCase, async: false use Oban.Testing, repo: Pleroma.Repo import ExUnit.CaptureLog diff --git a/test/pleroma/web/admin_api/controllers/chat_controller_test.exs b/test/pleroma/web/admin_api/controllers/chat_controller_test.exs index 4d093ff57..3798083aa 100644 --- a/test/pleroma/web/admin_api/controllers/chat_controller_test.exs +++ b/test/pleroma/web/admin_api/controllers/chat_controller_test.exs @@ -3,7 +3,7 @@ # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.AdminAPI.ChatControllerTest do - use Pleroma.Web.ConnCase, async: true + use Pleroma.Web.ConnCase, async: false import Pleroma.Factory diff --git a/test/pleroma/web/admin_api/controllers/invite_controller_test.exs b/test/pleroma/web/admin_api/controllers/invite_controller_test.exs index 17c2aa104..b8c812acc 100644 --- a/test/pleroma/web/admin_api/controllers/invite_controller_test.exs +++ b/test/pleroma/web/admin_api/controllers/invite_controller_test.exs @@ -3,7 +3,7 @@ # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.AdminAPI.InviteControllerTest do - use Pleroma.Web.ConnCase, async: true + use Pleroma.Web.ConnCase, async: false import Pleroma.Factory diff --git a/test/pleroma/web/admin_api/controllers/report_controller_test.exs b/test/pleroma/web/admin_api/controllers/report_controller_test.exs index c39cf978b..42b5000fc 100644 --- a/test/pleroma/web/admin_api/controllers/report_controller_test.exs +++ b/test/pleroma/web/admin_api/controllers/report_controller_test.exs @@ -3,7 +3,7 @@ # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.AdminAPI.ReportControllerTest do - use Pleroma.Web.ConnCase, async: true + use Pleroma.Web.ConnCase, async: false import Pleroma.Factory diff --git a/test/pleroma/web/admin_api/controllers/status_controller_test.exs b/test/pleroma/web/admin_api/controllers/status_controller_test.exs index 238cb9aff..4228dbcbb 100644 --- a/test/pleroma/web/admin_api/controllers/status_controller_test.exs +++ b/test/pleroma/web/admin_api/controllers/status_controller_test.exs @@ -3,7 +3,7 @@ # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.AdminAPI.StatusControllerTest do - use Pleroma.Web.ConnCase, async: true + use Pleroma.Web.ConnCase, async: false import Pleroma.Factory diff --git a/test/pleroma/web/admin_api/controllers/user_controller_test.exs b/test/pleroma/web/admin_api/controllers/user_controller_test.exs index a6e41c761..01bee08d1 100644 --- a/test/pleroma/web/admin_api/controllers/user_controller_test.exs +++ b/test/pleroma/web/admin_api/controllers/user_controller_test.exs @@ -3,7 +3,7 @@ # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.AdminAPI.UserControllerTest do - use Pleroma.Web.ConnCase + use Pleroma.Web.ConnCase, async: false use Oban.Testing, repo: Pleroma.Repo import Mock From 34a98990dba1e021a75a23b225cff22af23f5ca2 Mon Sep 17 00:00:00 2001 From: Ilja Date: Sat, 11 Jun 2022 09:38:43 +0200 Subject: [PATCH 12/54] last off :statuses_read From the endpoints left to do, I believe these should be under :statuses_read. These should be the last for that privilege for this MR --- lib/pleroma/web/router.ex | 6 ++++-- .../admin_api/controllers/instance_controller_test.exs | 7 ++++++- .../admin_api/controllers/status_controller_test.exs | 10 ++++++++++ 3 files changed, 20 insertions(+), 3 deletions(-) diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex index 68719c570..13e8141e4 100644 --- a/lib/pleroma/web/router.ex +++ b/lib/pleroma/web/router.ex @@ -292,6 +292,10 @@ defmodule Pleroma.Web.Router do get("/chats/:id", ChatController, :show) get("/chats/:id/messages", ChatController, :messages) + + get("/instances/:instance/statuses", InstanceController, :list_statuses) + + get("/statuses/:id", StatusController, :show) end # AdminAPI: admins and mods (staff) can perform these actions (if privileged by role) @@ -345,10 +349,8 @@ defmodule Pleroma.Web.Router do scope "/api/v1/pleroma/admin", Pleroma.Web.AdminAPI do pipe_through(:admin_api) - get("/instances/:instance/statuses", InstanceController, :list_statuses) delete("/instances/:instance", InstanceController, :delete) - get("/statuses/:id", StatusController, :show) put("/statuses/:id", StatusController, :update) delete("/statuses/:id", StatusController, :delete) diff --git a/test/pleroma/web/admin_api/controllers/instance_controller_test.exs b/test/pleroma/web/admin_api/controllers/instance_controller_test.exs index 72436cd83..2ab32fed8 100644 --- a/test/pleroma/web/admin_api/controllers/instance_controller_test.exs +++ b/test/pleroma/web/admin_api/controllers/instance_controller_test.exs @@ -3,7 +3,7 @@ # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.AdminAPI.InstanceControllerTest do - use Pleroma.Web.ConnCase + use Pleroma.Web.ConnCase, async: false use Oban.Testing, repo: Pleroma.Repo import Pleroma.Factory @@ -31,6 +31,7 @@ defmodule Pleroma.Web.AdminAPI.InstanceControllerTest do end test "GET /instances/:instance/statuses", %{conn: conn} do + clear_config([:instance, :admin_privileges], [:statuses_read]) user = insert(:user, local: false, ap_id: "https://archae.me/users/archaeme") user2 = insert(:user, local: false, ap_id: "https://test.com/users/test") insert_pair(:note_activity, user: user) @@ -60,6 +61,10 @@ test "GET /instances/:instance/statuses", %{conn: conn} do |> json_response(200) assert length(activities) == 3 + + clear_config([:instance, :admin_privileges], []) + + conn |> get("/api/pleroma/admin/instances/archae.me/statuses") |> json_response(:forbidden) end test "DELETE /instances/:instance", %{conn: conn} do diff --git a/test/pleroma/web/admin_api/controllers/status_controller_test.exs b/test/pleroma/web/admin_api/controllers/status_controller_test.exs index 4228dbcbb..d18577961 100644 --- a/test/pleroma/web/admin_api/controllers/status_controller_test.exs +++ b/test/pleroma/web/admin_api/controllers/status_controller_test.exs @@ -26,6 +26,10 @@ defmodule Pleroma.Web.AdminAPI.StatusControllerTest do end describe "GET /api/pleroma/admin/statuses/:id" do + setup do + clear_config([:instance, :admin_privileges], [:statuses_read]) + end + test "not found", %{conn: conn} do assert conn |> get("/api/pleroma/admin/statuses/not_found") @@ -50,6 +54,12 @@ test "shows activity", %{conn: conn} do assert account["is_active"] == actor.is_active assert account["is_confirmed"] == actor.is_confirmed end + + test "denies reading activity when not privileged", %{conn: conn} do + clear_config([:instance, :admin_privileges], []) + + assert conn |> get("/api/pleroma/admin/statuses/some_id") |> json_response(:forbidden) + end end describe "PUT /api/pleroma/admin/statuses/:id" do From 0ee8f33250f649c7807fd161b9d6588757f5dc94 Mon Sep 17 00:00:00 2001 From: Ilja Date: Sat, 11 Jun 2022 13:08:40 +0200 Subject: [PATCH 13/54] Add privilige :status_delete It also allows to update a message, so it's not just deleting. I need a better name... --- config/config.exs | 3 ++- config/description.exs | 6 ++++-- lib/pleroma/web/router.ex | 20 ++++++++++++++----- .../controllers/chat_controller_test.exs | 14 ++++++++++++- .../controllers/status_controller_test.exs | 20 +++++++++++++++++++ 5 files changed, 54 insertions(+), 9 deletions(-) diff --git a/config/config.exs b/config/config.exs index 778e6bf21..ef2211426 100644 --- a/config/config.exs +++ b/config/config.exs @@ -264,7 +264,8 @@ :user_activation, :user_invite, :report_handle, - :user_read + :user_read, + :status_delete ], moderator_privileges: [], max_endorsed_users: 20, diff --git a/config/description.exs b/config/description.exs index 6d8cacace..8ef649e99 100644 --- a/config/description.exs +++ b/config/description.exs @@ -971,7 +971,8 @@ :user_activation, :user_invite, :report_handle, - :user_read + :user_read, + :status_delete ], description: "What extra priviledges to allow admins (e.g. updating user credentials, get password reset token, delete users, index and read private statuses and chats)" @@ -987,7 +988,8 @@ :user_activation, :user_invite, :report_handle, - :user_read + :user_read, + :status_delete ], description: "What extra priviledges to allow moderators (e.g. updating user credentials, get password reset token, delete users, index and read private statuses and chats)" diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex index 13e8141e4..50a0ea7fc 100644 --- a/lib/pleroma/web/router.ex +++ b/lib/pleroma/web/router.ex @@ -145,6 +145,11 @@ defmodule Pleroma.Web.Router do plug(Pleroma.Web.Plugs.EnsurePrivilegedPlug, :user_read) end + pipeline :require_privileged_role_status_delete do + plug(:admin_api) + plug(Pleroma.Web.Plugs.EnsurePrivilegedPlug, :status_delete) + end + pipeline :pleroma_html do plug(:browser) plug(:authenticate) @@ -345,21 +350,26 @@ defmodule Pleroma.Web.Router do get("/users/:nickname", UserController, :show) end + # AdminAPI: admins and mods (staff) can perform these actions (if privileged by role) + scope "/api/v1/pleroma/admin", Pleroma.Web.AdminAPI do + pipe_through(:require_privileged_role_status_delete) + + put("/statuses/:id", StatusController, :update) + delete("/statuses/:id", StatusController, :delete) + + delete("/chats/:id/messages/:message_id", ChatController, :delete_message) + end + # AdminAPI: admins and mods (staff) can perform these actions scope "/api/v1/pleroma/admin", Pleroma.Web.AdminAPI do pipe_through(:admin_api) delete("/instances/:instance", InstanceController, :delete) - put("/statuses/:id", StatusController, :update) - delete("/statuses/:id", StatusController, :delete) - get("/moderation_log", AdminAPIController, :list_log) post("/reload_emoji", AdminAPIController, :reload_emoji) get("/stats", AdminAPIController, :stats) - - delete("/chats/:id/messages/:message_id", ChatController, :delete_message) end scope "/api/v1/pleroma/emoji", Pleroma.Web.PleromaAPI do diff --git a/test/pleroma/web/admin_api/controllers/chat_controller_test.exs b/test/pleroma/web/admin_api/controllers/chat_controller_test.exs index 3798083aa..e080cd225 100644 --- a/test/pleroma/web/admin_api/controllers/chat_controller_test.exs +++ b/test/pleroma/web/admin_api/controllers/chat_controller_test.exs @@ -27,7 +27,10 @@ defp admin_setup do end describe "DELETE /api/pleroma/admin/chats/:id/messages/:message_id" do - setup do: admin_setup() + setup do + clear_config([:instance, :admin_privileges], [:status_delete]) + admin_setup() + end test "it deletes a message from the chat", %{conn: conn, admin: admin} do user = insert(:user) @@ -60,6 +63,15 @@ test "it deletes a message from the chat", %{conn: conn, admin: admin} do refute MessageReference.get_by_id(recipient_cm_ref.id) assert %{data: %{"type" => "Tombstone"}} = Object.get_by_id(object.id) end + + test "it requires privileged role :status_delete", %{conn: conn} do + clear_config([:instance, :admin_privileges], []) + + assert conn + |> put_req_header("content-type", "application/json") + |> delete("/api/pleroma/admin/chats/some_id/messages/some_ref_id") + |> json_response(:forbidden) + end end describe "GET /api/pleroma/admin/chats/:id/messages" do diff --git a/test/pleroma/web/admin_api/controllers/status_controller_test.exs b/test/pleroma/web/admin_api/controllers/status_controller_test.exs index d18577961..2daf6a50d 100644 --- a/test/pleroma/web/admin_api/controllers/status_controller_test.exs +++ b/test/pleroma/web/admin_api/controllers/status_controller_test.exs @@ -64,6 +64,7 @@ test "denies reading activity when not privileged", %{conn: conn} do describe "PUT /api/pleroma/admin/statuses/:id" do setup do + clear_config([:instance, :admin_privileges], [:status_delete]) activity = insert(:note_activity) %{id: activity.id} @@ -132,10 +133,20 @@ test "returns 400 when visibility is unknown", %{conn: conn, id: id} do assert %{"error" => "test - Invalid value for enum."} = json_response_and_validate_schema(conn, :bad_request) end + + test "it requires privileged role :status_delete", %{conn: conn} do + clear_config([:instance, :admin_privileges], []) + + assert conn + |> put_req_header("content-type", "application/json") + |> put("/api/pleroma/admin/statuses/some_id", %{}) + |> json_response(:forbidden) + end end describe "DELETE /api/pleroma/admin/statuses/:id" do setup do + clear_config([:instance, :admin_privileges], [:status_delete]) activity = insert(:note_activity) %{id: activity.id} @@ -159,6 +170,15 @@ test "returns 404 when the status does not exist", %{conn: conn} do assert json_response_and_validate_schema(conn, :not_found) == %{"error" => "Not found"} end + + test "it requires privileged role :status_delete", %{conn: conn} do + clear_config([:instance, :admin_privileges], []) + + assert conn + |> put_req_header("content-type", "application/json") + |> delete("/api/pleroma/admin/statuses/some_id") + |> json_response(:forbidden) + end end describe "GET /api/pleroma/admin/statuses" do From ecd42a2ce112489bb09cadcffc3661314a37a7fa Mon Sep 17 00:00:00 2001 From: Ilja Date: Sat, 11 Jun 2022 22:18:21 +0200 Subject: [PATCH 14/54] Add privilige :emoji_management --- config/config.exs | 3 +- config/description.exs | 6 +- lib/pleroma/web/router.ex | 17 +++++- .../controllers/admin_api_controller_test.exs | 28 +++++++++ .../emoji_file_controller_test.exs | 30 ++++++++- .../emoji_pack_controller_test.exs | 61 +++++++++++++++++++ 6 files changed, 138 insertions(+), 7 deletions(-) diff --git a/config/config.exs b/config/config.exs index ef2211426..263299e4d 100644 --- a/config/config.exs +++ b/config/config.exs @@ -265,7 +265,8 @@ :user_invite, :report_handle, :user_read, - :status_delete + :status_delete, + :emoji_management ], moderator_privileges: [], max_endorsed_users: 20, diff --git a/config/description.exs b/config/description.exs index 8ef649e99..9f595fae0 100644 --- a/config/description.exs +++ b/config/description.exs @@ -972,7 +972,8 @@ :user_invite, :report_handle, :user_read, - :status_delete + :status_delete, + :emoji_management ], description: "What extra priviledges to allow admins (e.g. updating user credentials, get password reset token, delete users, index and read private statuses and chats)" @@ -989,7 +990,8 @@ :user_invite, :report_handle, :user_read, - :status_delete + :status_delete, + :emoji_management ], description: "What extra priviledges to allow moderators (e.g. updating user credentials, get password reset token, delete users, index and read private statuses and chats)" diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex index 50a0ea7fc..46f128672 100644 --- a/lib/pleroma/web/router.ex +++ b/lib/pleroma/web/router.ex @@ -150,6 +150,11 @@ defmodule Pleroma.Web.Router do plug(Pleroma.Web.Plugs.EnsurePrivilegedPlug, :status_delete) end + pipeline :require_privileged_role_emoji_management do + plug(:admin_api) + plug(Pleroma.Web.Plugs.EnsurePrivilegedPlug, :emoji_management) + end + pipeline :pleroma_html do plug(:browser) plug(:authenticate) @@ -360,6 +365,13 @@ defmodule Pleroma.Web.Router do delete("/chats/:id/messages/:message_id", ChatController, :delete_message) end + # AdminAPI: admins and mods (staff) can perform these actions (if privileged by role) + scope "/api/v1/pleroma/admin", Pleroma.Web.AdminAPI do + pipe_through(:require_privileged_role_emoji_management) + + post("/reload_emoji", AdminAPIController, :reload_emoji) + end + # AdminAPI: admins and mods (staff) can perform these actions scope "/api/v1/pleroma/admin", Pleroma.Web.AdminAPI do pipe_through(:admin_api) @@ -368,13 +380,12 @@ defmodule Pleroma.Web.Router do get("/moderation_log", AdminAPIController, :list_log) - post("/reload_emoji", AdminAPIController, :reload_emoji) get("/stats", AdminAPIController, :stats) end scope "/api/v1/pleroma/emoji", Pleroma.Web.PleromaAPI do scope "/pack" do - pipe_through(:admin_api) + pipe_through(:require_privileged_role_emoji_management) post("/", EmojiPackController, :create) patch("/", EmojiPackController, :update) @@ -389,7 +400,7 @@ defmodule Pleroma.Web.Router do # Modifying packs scope "/packs" do - pipe_through(:admin_api) + pipe_through(:require_privileged_role_emoji_management) get("/import", EmojiPackController, :import_from_filesystem) get("/remote", EmojiPackController, :remote) diff --git a/test/pleroma/web/admin_api/controllers/admin_api_controller_test.exs b/test/pleroma/web/admin_api/controllers/admin_api_controller_test.exs index 1df28f147..23c26d7db 100644 --- a/test/pleroma/web/admin_api/controllers/admin_api_controller_test.exs +++ b/test/pleroma/web/admin_api/controllers/admin_api_controller_test.exs @@ -1060,6 +1060,34 @@ test "it doesn't limit admins", %{conn: conn} do assert Repo.aggregate(Pleroma.User.Backup, :count) == 2 end end + + describe "POST /api/v1/pleroma/admin/reload_emoji" do + setup do + clear_config([:instance, :admin_privileges], [:emoji_management]) + + admin = insert(:user, is_admin: true) + token = insert(:oauth_admin_token, user: admin) + + conn = + build_conn() + |> assign(:user, admin) + |> assign(:token, token) + + {:ok, %{conn: conn, admin: admin}} + end + + test "it requires privileged role :emoji_management", %{conn: conn} do + assert conn + |> post("/api/v1/pleroma/admin/reload_emoji") + |> json_response(200) + + clear_config([:instance, :admin_privileges], []) + + assert conn + |> post("/api/v1/pleroma/admin/reload_emoji") + |> json_response(:forbidden) + end + end end # Needed for testing diff --git a/test/pleroma/web/pleroma_api/controllers/emoji_file_controller_test.exs b/test/pleroma/web/pleroma_api/controllers/emoji_file_controller_test.exs index 200ce3b68..e46a363a4 100644 --- a/test/pleroma/web/pleroma_api/controllers/emoji_file_controller_test.exs +++ b/test/pleroma/web/pleroma_api/controllers/emoji_file_controller_test.exs @@ -3,7 +3,7 @@ # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.PleromaAPI.EmojiFileControllerTest do - use Pleroma.Web.ConnCase + use Pleroma.Web.ConnCase, async: false import Mock import Tesla.Mock @@ -30,6 +30,7 @@ defmodule Pleroma.Web.PleromaAPI.EmojiFileControllerTest do describe "POST/PATCH/DELETE /api/pleroma/emoji/packs/files?name=:name" do setup do + clear_config([:instance, :admin_privileges], [:emoji_management]) pack_file = "#{@emoji_path}/test_pack/pack.json" original_content = File.read!(pack_file) @@ -377,5 +378,32 @@ test "update with empty shortcode", %{admin_conn: admin_conn} do }) |> json_response_and_validate_schema(:bad_request) end + + test "it requires privileged role :emoji_management", %{admin_conn: admin_conn} do + clear_config([:instance, :admin_privileges], []) + + assert admin_conn + |> put_req_header("content-type", "multipart/form-data") + |> post("/api/pleroma/emoji/packs/files?name=test_pack", %{ + file: %Plug.Upload{ + filename: "shortcode.png", + path: "#{Pleroma.Config.get([:instance, :static_dir])}/add/shortcode.png" + } + }) + |> json_response(:forbidden) + + assert admin_conn + |> put_req_header("content-type", "multipart/form-data") + |> patch("/api/pleroma/emoji/packs/files?name=test_pack", %{ + shortcode: "blank", + new_filename: "dir_2/blank_3.png" + }) + |> json_response(:forbidden) + + assert admin_conn + |> put_req_header("content-type", "multipart/form-data") + |> delete("/api/pleroma/emoji/packs/files?name=test_pack&shortcode=blank3") + |> json_response(:forbidden) + end end end diff --git a/test/pleroma/web/pleroma_api/controllers/emoji_pack_controller_test.exs b/test/pleroma/web/pleroma_api/controllers/emoji_pack_controller_test.exs index d1fd1cbb0..6558767d2 100644 --- a/test/pleroma/web/pleroma_api/controllers/emoji_pack_controller_test.exs +++ b/test/pleroma/web/pleroma_api/controllers/emoji_pack_controller_test.exs @@ -99,6 +99,10 @@ test "GET /api/pleroma/emoji/packs", %{conn: conn} do end describe "GET /api/pleroma/emoji/packs/remote" do + setup do + clear_config([:instance, :admin_privileges], [:emoji_management]) + end + test "shareable instance", %{admin_conn: admin_conn, conn: conn} do resp = conn @@ -136,6 +140,14 @@ test "non shareable instance", %{admin_conn: admin_conn} do "error" => "The requested instance does not support sharing emoji packs" } end + + test "it requires privileged role :emoji_management", %{admin_conn: admin_conn} do + clear_config([:instance, :admin_privileges], []) + + assert admin_conn + |> get("/api/pleroma/emoji/packs/remote?url=https://example.com") + |> json_response(:forbidden) + end end describe "GET /api/pleroma/emoji/packs/archive?name=:name" do @@ -170,6 +182,10 @@ test "non downloadable pack", %{conn: conn} do end describe "POST /api/pleroma/emoji/packs/download" do + setup do + clear_config([:instance, :admin_privileges], [:emoji_management]) + end + test "shared pack from remote and non shared from fallback-src", %{ admin_conn: admin_conn, conn: conn @@ -344,10 +360,24 @@ test "other error", %{admin_conn: admin_conn} do "The pack was not set as shared and there is no fallback src to download from" } end + + test "it requires privileged role :emoji_management", %{admin_conn: conn} do + clear_config([:instance, :admin_privileges], []) + + assert conn + |> put_req_header("content-type", "multipart/form-data") + |> post("/api/pleroma/emoji/packs/download", %{ + url: "https://example.com", + name: "test_pack", + as: "test_pack2" + }) + |> json_response(:forbidden) + end end describe "PATCH/update /api/pleroma/emoji/pack?name=:name" do setup do + clear_config([:instance, :admin_privileges], [:emoji_management]) pack_file = "#{@emoji_path}/test_pack/pack.json" original_content = File.read!(pack_file) @@ -435,9 +465,22 @@ test "when the fallback source doesn't have all the files", ctx do "error" => "The fallback archive does not have all files specified in pack.json" } end + + test "it requires privileged role :emoji_management", %{admin_conn: conn, new_data: new_data} do + clear_config([:instance, :admin_privileges], []) + + assert conn + |> put_req_header("content-type", "multipart/form-data") + |> patch("/api/pleroma/emoji/pack?name=test_pack", %{metadata: new_data}) + |> json_response(:forbidden) + end end describe "POST/DELETE /api/pleroma/emoji/pack?name=:name" do + setup do + clear_config([:instance, :admin_privileges], [:emoji_management]) + end + test "returns an error on creates pack when file system not writable", %{ admin_conn: admin_conn } do @@ -520,6 +563,18 @@ test "with empty name", %{admin_conn: admin_conn} do "error" => "pack name cannot be empty" } end + + test "it requires privileged role :emoji_management", %{admin_conn: admin_conn} do + clear_config([:instance, :admin_privileges], []) + + assert admin_conn + |> post("/api/pleroma/emoji/pack?name= ") + |> json_response(:forbidden) + + assert admin_conn + |> delete("/api/pleroma/emoji/pack?name= ") + |> json_response(:forbidden) + end end test "deleting nonexisting pack", %{admin_conn: admin_conn} do @@ -578,6 +633,12 @@ test "filesystem import", %{admin_conn: admin_conn, conn: conn} do "blank2" => "blank.png", "foo" => "blank.png" } + + clear_config([:instance, :admin_privileges], []) + + assert admin_conn + |> get("/api/pleroma/emoji/packs/import") + |> json_response(:forbidden) end describe "GET /api/pleroma/emoji/pack?name=:name" do From c842e6267545dfa88cf97cef69337296c3cb77d5 Mon Sep 17 00:00:00 2001 From: Ilja Date: Sun, 12 Jun 2022 10:07:33 +0200 Subject: [PATCH 15/54] Add last priviliges I still had three endpoints I didn't really know what to do with them. I added them under separate tags * :instance_delete * :moderation_log_read * :stats_read I also checked and these are the last changes done by MR https://git.pleroma.social/pleroma/pleroma/-/merge_requests/3480/diffs this is trying to fix --- lib/pleroma/web/router.ex | 29 +++++++++++++++++-- .../controllers/admin_api_controller_test.exs | 22 ++++++++++++++ .../controllers/instance_controller_test.exs | 8 +++++ 3 files changed, 57 insertions(+), 2 deletions(-) diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex index 46f128672..f680c8353 100644 --- a/lib/pleroma/web/router.ex +++ b/lib/pleroma/web/router.ex @@ -155,6 +155,21 @@ defmodule Pleroma.Web.Router do plug(Pleroma.Web.Plugs.EnsurePrivilegedPlug, :emoji_management) end + pipeline :require_privileged_role_instance_delete do + plug(:admin_api) + plug(Pleroma.Web.Plugs.EnsurePrivilegedPlug, :instance_delete) + end + + pipeline :require_privileged_role_moderation_log_read do + plug(:admin_api) + plug(Pleroma.Web.Plugs.EnsurePrivilegedPlug, :moderation_log_read) + end + + pipeline :require_privileged_role_stats_read do + plug(:admin_api) + plug(Pleroma.Web.Plugs.EnsurePrivilegedPlug, :stats_read) + end + pipeline :pleroma_html do plug(:browser) plug(:authenticate) @@ -372,13 +387,23 @@ defmodule Pleroma.Web.Router do post("/reload_emoji", AdminAPIController, :reload_emoji) end - # AdminAPI: admins and mods (staff) can perform these actions + # AdminAPI: admins and mods (staff) can perform these actions (if privileged by role) scope "/api/v1/pleroma/admin", Pleroma.Web.AdminAPI do - pipe_through(:admin_api) + pipe_through(:require_privileged_role_instance_delete) delete("/instances/:instance", InstanceController, :delete) + end + + # AdminAPI: admins and mods (staff) can perform these actions (if privileged by role) + scope "/api/v1/pleroma/admin", Pleroma.Web.AdminAPI do + pipe_through(:require_privileged_role_moderation_log_read) get("/moderation_log", AdminAPIController, :list_log) + end + + # AdminAPI: admins and mods (staff) can perform these actions (if privileged by role) + scope "/api/v1/pleroma/admin", Pleroma.Web.AdminAPI do + pipe_through(:require_privileged_role_stats_read) get("/stats", AdminAPIController, :stats) end diff --git a/test/pleroma/web/admin_api/controllers/admin_api_controller_test.exs b/test/pleroma/web/admin_api/controllers/admin_api_controller_test.exs index 23c26d7db..180f6c83f 100644 --- a/test/pleroma/web/admin_api/controllers/admin_api_controller_test.exs +++ b/test/pleroma/web/admin_api/controllers/admin_api_controller_test.exs @@ -558,6 +558,7 @@ test "returns 403", %{conn: conn, user: user} do describe "GET /api/pleroma/admin/moderation_log" do setup do + clear_config([:instance, :admin_privileges], [:moderation_log_read]) moderator = insert(:user, is_moderator: true) %{moderator: moderator} @@ -762,6 +763,15 @@ test "returns log filtered by search", %{conn: conn, moderator: moderator} do assert get_in(first_entry, ["data", "message"]) == "@#{moderator.nickname} unfollowed relay: https://example.org/relay" end + + test "it requires privileged role :moderation_log_read", %{conn: conn} do + clear_config([:instance, :admin_privileges], []) + + assert conn + |> put_req_header("content-type", "multipart/form-data") + |> get("/api/pleroma/admin/moderation_log") + |> json_response(:forbidden) + end end test "gets a remote users when [:instance, :limit_to_local_content] is set to :unauthenticated", @@ -960,6 +970,10 @@ test "it resend emails for two users", %{conn: conn, admin: admin} do end describe "/api/pleroma/admin/stats" do + setup do + clear_config([:instance, :admin_privileges], [:stats_read]) + end + test "status visibility count", %{conn: conn} do user = insert(:user) CommonAPI.post(user, %{visibility: "public", status: "hey"}) @@ -992,6 +1006,14 @@ test "by instance", %{conn: conn} do assert %{"direct" => 0, "private" => 1, "public" => 0, "unlisted" => 1} = response["status_visibility"] end + + test "it requires privileged role :stats_read", %{conn: conn} do + clear_config([:instance, :admin_privileges], []) + + assert conn + |> get("/api/pleroma/admin/stats", instance: "lain.wired") + |> json_response(:forbidden) + end end describe "/api/pleroma/backups" do diff --git a/test/pleroma/web/admin_api/controllers/instance_controller_test.exs b/test/pleroma/web/admin_api/controllers/instance_controller_test.exs index 2ab32fed8..b757ce469 100644 --- a/test/pleroma/web/admin_api/controllers/instance_controller_test.exs +++ b/test/pleroma/web/admin_api/controllers/instance_controller_test.exs @@ -68,6 +68,7 @@ test "GET /instances/:instance/statuses", %{conn: conn} do end test "DELETE /instances/:instance", %{conn: conn} do + clear_config([:instance, :admin_privileges], [:instance_delete]) user = insert(:user, nickname: "lain@lain.com") post = insert(:note_activity, user: user) @@ -81,5 +82,12 @@ test "DELETE /instances/:instance", %{conn: conn} do assert response == "lain.com" refute Repo.reload(user).is_active refute Repo.reload(post) + + clear_config([:instance, :admin_privileges], []) + + response = + conn + |> delete("/api/pleroma/admin/instances/lain.com") + |> json_response(:forbidden) end end From 9da81f41c6e2084973095eefebbda3b1abde587c Mon Sep 17 00:00:00 2001 From: Ilja Date: Fri, 17 Jun 2022 17:35:03 +0200 Subject: [PATCH 16/54] Fix warning during test user_test.exs Fixed the warning [warning] Please change `clear_config([section], key: value)` to `clear_config([section, key], value)` --- test/pleroma/user_test.exs | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/test/pleroma/user_test.exs b/test/pleroma/user_test.exs index 884b846ae..ea1e45e63 100644 --- a/test/pleroma/user_test.exs +++ b/test/pleroma/user_test.exs @@ -473,12 +473,7 @@ test "it sends a welcome chat message if it is set" do reject_deletes: [] ) - setup do: - clear_config(:mrf, - policies: [ - Pleroma.Web.ActivityPub.MRF.SimplePolicy - ] - ) + setup do: clear_config([:mrf, :policies], [Pleroma.Web.ActivityPub.MRF.SimplePolicy]) test "it sends a welcome chat message when Simple policy applied to local instance" do clear_config([:mrf_simple, :media_nsfw], [{"localhost", ""}]) From 7adfc2e0f429f84eb7eb2712529e9a3486354d01 Mon Sep 17 00:00:00 2001 From: Ilja Date: Mon, 13 Jun 2022 09:58:50 +0200 Subject: [PATCH 17/54] Add Pleroma.User.privileged?/2 This should eventually replace Pleroma.User.superuser?/1 --- lib/pleroma/user.ex | 18 ++++++++++++++++ test/pleroma/user_test.exs | 43 +++++++++++++++++++++++++++++++++++++- 2 files changed, 60 insertions(+), 1 deletion(-) diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex index 747a83e8d..b93ce9c2c 100644 --- a/lib/pleroma/user.ex +++ b/lib/pleroma/user.ex @@ -353,6 +353,24 @@ defp visible_account_status(user) do end end + @spec privileged?(User.t(), atom()) :: boolean() + def privileged?(%User{is_admin: false, is_moderator: false}, _), do: false + + def privileged?( + %User{local: true, is_admin: is_admin, is_moderator: is_moderator}, + privilege_tag + ), + do: + privileged_for?(privilege_tag, is_admin, :admin_privileges) or + privileged_for?(privilege_tag, is_moderator, :moderator_privileges) + + def privileged?(_, _), do: false + + defp privileged_for?(privilege_tag, true, config_role_key), + do: privilege_tag in Config.get([:instance, config_role_key]) + + defp privileged_for?(_, _, _), do: false + @spec superuser?(User.t()) :: boolean() def superuser?(%User{local: true, is_admin: true}), do: true def superuser?(%User{local: true, is_moderator: true}), do: true diff --git a/test/pleroma/user_test.exs b/test/pleroma/user_test.exs index ea1e45e63..192bffaa9 100644 --- a/test/pleroma/user_test.exs +++ b/test/pleroma/user_test.exs @@ -13,7 +13,7 @@ defmodule Pleroma.UserTest do alias Pleroma.Web.ActivityPub.ActivityPub alias Pleroma.Web.CommonAPI - use Pleroma.DataCase + use Pleroma.DataCase, async: false use Oban.Testing, repo: Pleroma.Repo import Pleroma.Factory @@ -1878,6 +1878,47 @@ test "returns :approval_pending for unapproved user" do end end + describe "privileged?/1" do + setup do + clear_config([:instance, :admin_privileges], [:cofe, :suya]) + clear_config([:instance, :moderator_privileges], [:cofe, :suya]) + end + + test "returns false for unprivileged users" do + user = insert(:user, local: true) + + refute User.privileged?(user, :cofe) + end + + test "returns false for remote users" do + user = insert(:user, local: false) + remote_admin_user = insert(:user, local: false, is_admin: true) + + refute User.privileged?(user, :cofe) + refute User.privileged?(remote_admin_user, :cofe) + end + + test "returns true for local moderators if, and only if, they are privileged" do + user = insert(:user, local: true, is_moderator: true) + + assert User.privileged?(user, :cofe) + + clear_config([:instance, :moderator_privileges], []) + + refute User.privileged?(user, :cofe) + end + + test "returns true for local admins if, and only if, they are privileged" do + user = insert(:user, local: true, is_admin: true) + + assert User.privileged?(user, :cofe) + + clear_config([:instance, :admin_privileges], []) + + refute User.privileged?(user, :cofe) + end + end + describe "superuser?/1" do test "returns false for unprivileged users" do user = insert(:user, local: true) From 7cf473c50076f31bb01bad92501a8c2353874b96 Mon Sep 17 00:00:00 2001 From: Ilja Date: Mon, 13 Jun 2022 11:00:49 +0200 Subject: [PATCH 18/54] delete statusses is now privileged by :status_delete Instead of superusers, you now need a role with privilige :status_delete to delete other users statusses I also cleaned up some other stuff I saw --- lib/pleroma/web/common_api.ex | 2 +- .../controllers/instance_controller_test.exs | 7 +++-- test/pleroma/web/common_api_test.exs | 26 ++++++++++--------- .../controllers/status_controller_test.exs | 22 +++++----------- 4 files changed, 24 insertions(+), 33 deletions(-) diff --git a/lib/pleroma/web/common_api.ex b/lib/pleroma/web/common_api.ex index 1b95ee89c..ce1d5a7cc 100644 --- a/lib/pleroma/web/common_api.ex +++ b/lib/pleroma/web/common_api.ex @@ -144,7 +144,7 @@ def delete(activity_id, user) do {:find_activity, Activity.get_by_id(activity_id)}, {_, %Object{} = object, _} <- {:find_object, Object.normalize(activity, fetch: false), activity}, - true <- User.superuser?(user) || user.ap_id == object.data["actor"], + true <- User.privileged?(user, :status_delete) || user.ap_id == object.data["actor"], {:ok, delete_data, _} <- Builder.delete(user, object.data["id"]), {:ok, delete, _} <- Pipeline.common_pipeline(delete_data, local: true) do {:ok, delete} diff --git a/test/pleroma/web/admin_api/controllers/instance_controller_test.exs b/test/pleroma/web/admin_api/controllers/instance_controller_test.exs index b757ce469..e75222f99 100644 --- a/test/pleroma/web/admin_api/controllers/instance_controller_test.exs +++ b/test/pleroma/web/admin_api/controllers/instance_controller_test.exs @@ -85,9 +85,8 @@ test "DELETE /instances/:instance", %{conn: conn} do clear_config([:instance, :admin_privileges], []) - response = - conn - |> delete("/api/pleroma/admin/instances/lain.com") - |> json_response(:forbidden) + conn + |> delete("/api/pleroma/admin/instances/lain.com") + |> json_response(:forbidden) end end diff --git a/test/pleroma/web/common_api_test.exs b/test/pleroma/web/common_api_test.exs index b502aaa03..4d960e945 100644 --- a/test/pleroma/web/common_api_test.exs +++ b/test/pleroma/web/common_api_test.exs @@ -4,7 +4,7 @@ defmodule Pleroma.Web.CommonAPITest do use Oban.Testing, repo: Pleroma.Repo - use Pleroma.DataCase + use Pleroma.DataCase, async: false alias Pleroma.Activity alias Pleroma.Chat @@ -321,7 +321,7 @@ test "it allows users to delete their posts" do refute Activity.get_by_id(post.id) end - test "it does not allow a user to delete their posts" do + test "it does not allow a user to delete posts from another user" do user = insert(:user) other_user = insert(:user) @@ -331,7 +331,8 @@ test "it does not allow a user to delete their posts" do assert Activity.get_by_id(post.id) end - test "it allows moderators to delete other user's posts" do + test "it allows privileged users to delete other user's posts" do + clear_config([:instance, :moderator_privileges], [:status_delete]) user = insert(:user) moderator = insert(:user, is_moderator: true) @@ -343,19 +344,20 @@ test "it allows moderators to delete other user's posts" do refute Activity.get_by_id(post.id) end - test "it allows admins to delete other user's posts" do + test "it doesn't allow unprivileged mods or admins to delete other user's posts" do + clear_config([:instance, :admin_privileges], []) + clear_config([:instance, :moderator_privileges], []) user = insert(:user) - moderator = insert(:user, is_admin: true) + moderator = insert(:user, is_moderator: true, is_admin: true) {:ok, post} = CommonAPI.post(user, %{status: "namu amida butsu"}) - assert {:ok, delete} = CommonAPI.delete(post.id, moderator) - assert delete.local - - refute Activity.get_by_id(post.id) + assert {:error, "Could not delete"} = CommonAPI.delete(post.id, moderator) + assert Activity.get_by_id(post.id) end - test "superusers deleting non-local posts won't federate the delete" do + test "privileged users deleting non-local posts won't federate the delete" do + clear_config([:instance, :admin_privileges], [:status_delete]) # This is the user of the ingested activity _user = insert(:user, @@ -364,7 +366,7 @@ test "superusers deleting non-local posts won't federate the delete" do last_refreshed_at: NaiveDateTime.utc_now() ) - moderator = insert(:user, is_admin: true) + admin = insert(:user, is_admin: true) data = File.read!("test/fixtures/mastodon-post-activity.json") @@ -374,7 +376,7 @@ test "superusers deleting non-local posts won't federate the delete" do with_mock Pleroma.Web.Federator, publish: fn _ -> nil end do - assert {:ok, delete} = CommonAPI.delete(post.id, moderator) + assert {:ok, delete} = CommonAPI.delete(post.id, admin) assert delete.local refute called(Pleroma.Web.Federator.publish(:_)) end diff --git a/test/pleroma/web/mastodon_api/controllers/status_controller_test.exs b/test/pleroma/web/mastodon_api/controllers/status_controller_test.exs index dc6912b7b..4ea92e329 100644 --- a/test/pleroma/web/mastodon_api/controllers/status_controller_test.exs +++ b/test/pleroma/web/mastodon_api/controllers/status_controller_test.exs @@ -3,7 +3,7 @@ # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.MastodonAPI.StatusControllerTest do - use Pleroma.Web.ConnCase + use Pleroma.Web.ConnCase, async: false use Oban.Testing, repo: Pleroma.Repo alias Pleroma.Activity @@ -968,30 +968,20 @@ test "when you didn't create it" do assert Activity.get_by_id(activity.id) == activity end - test "when you're an admin or moderator", %{conn: conn} do - activity1 = insert(:note_activity) - activity2 = insert(:note_activity) - admin = insert(:user, is_admin: true) + test "when you're privileged to", %{conn: conn} do + clear_config([:instance, :moderator_privileges], [:status_delete]) + activity = insert(:note_activity) moderator = insert(:user, is_moderator: true) - res_conn = - conn - |> assign(:user, admin) - |> assign(:token, insert(:oauth_token, user: admin, scopes: ["write:statuses"])) - |> delete("/api/v1/statuses/#{activity1.id}") - - assert %{} = json_response_and_validate_schema(res_conn, 200) - res_conn = conn |> assign(:user, moderator) |> assign(:token, insert(:oauth_token, user: moderator, scopes: ["write:statuses"])) - |> delete("/api/v1/statuses/#{activity2.id}") + |> delete("/api/v1/statuses/#{activity.id}") assert %{} = json_response_and_validate_schema(res_conn, 200) - refute Activity.get_by_id(activity1.id) - refute Activity.get_by_id(activity2.id) + refute Activity.get_by_id(activity.id) end end From bb61cfee8dc27c658215f05cce3ea58fca5b3db3 Mon Sep 17 00:00:00 2001 From: Ilja Date: Mon, 13 Jun 2022 13:58:26 +0200 Subject: [PATCH 19/54] Validator for deleting statusses is now done with priviledge instead of superuser --- .../object_validators/common_validations.ex | 6 +++--- .../object_validators/delete_validator.ex | 2 +- .../delete_validation_test.exs | 17 +++++++++++++---- 3 files changed, 17 insertions(+), 8 deletions(-) diff --git a/lib/pleroma/web/activity_pub/object_validators/common_validations.ex b/lib/pleroma/web/activity_pub/object_validators/common_validations.ex index 704b3abc9..1c5b1a059 100644 --- a/lib/pleroma/web/activity_pub/object_validators/common_validations.ex +++ b/lib/pleroma/web/activity_pub/object_validators/common_validations.ex @@ -136,11 +136,11 @@ def same_domain?(cng, fields \\ [:actor, :object]) do # This figures out if a user is able to create, delete or modify something # based on the domain and superuser status - @spec validate_modification_rights(Ecto.Changeset.t()) :: Ecto.Changeset.t() - def validate_modification_rights(cng) do + @spec validate_modification_rights(Ecto.Changeset.t(), atom()) :: Ecto.Changeset.t() + def validate_modification_rights(cng, privilege) do actor = User.get_cached_by_ap_id(get_field(cng, :actor)) - if User.superuser?(actor) || same_domain?(cng) do + if User.privileged?(actor, privilege) || same_domain?(cng) do cng else cng diff --git a/lib/pleroma/web/activity_pub/object_validators/delete_validator.ex b/lib/pleroma/web/activity_pub/object_validators/delete_validator.ex index 035fd5bc9..6e4208167 100644 --- a/lib/pleroma/web/activity_pub/object_validators/delete_validator.ex +++ b/lib/pleroma/web/activity_pub/object_validators/delete_validator.ex @@ -61,7 +61,7 @@ defp validate_data(cng) do |> validate_required([:id, :type, :actor, :to, :cc, :object]) |> validate_inclusion(:type, ["Delete"]) |> validate_delete_actor(:actor) - |> validate_modification_rights() + |> validate_modification_rights(:status_delete) |> validate_object_or_user_presence(allowed_types: @deletable_types) |> add_deleted_activity_id() end diff --git a/test/pleroma/web/activity_pub/object_validators/delete_validation_test.exs b/test/pleroma/web/activity_pub/object_validators/delete_validation_test.exs index ea4664859..ba137604b 100644 --- a/test/pleroma/web/activity_pub/object_validators/delete_validation_test.exs +++ b/test/pleroma/web/activity_pub/object_validators/delete_validation_test.exs @@ -3,7 +3,7 @@ # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.ActivityPub.ObjectValidators.DeleteValidationTest do - use Pleroma.DataCase, async: true + use Pleroma.DataCase, async: false alias Pleroma.Object alias Pleroma.Web.ActivityPub.Builder @@ -90,17 +90,26 @@ test "it's invalid if the actor of the object and the actor of delete are from d assert {:actor, {"is not allowed to modify object", []}} in cng.errors end - test "it's valid if the actor of the object is a local superuser", + test "it's only valid if the actor of the object is a privileged local user", %{valid_post_delete: valid_post_delete} do + clear_config([:instance, :moderator_privileges], [:status_delete]) + user = insert(:user, local: true, is_moderator: true, ap_id: "https://gensokyo.2hu/users/raymoo") - valid_other_actor = + post_delete_with_moderator_actor = valid_post_delete |> Map.put("actor", user.ap_id) - {:ok, _, meta} = ObjectValidator.validate(valid_other_actor, []) + {:ok, _, meta} = ObjectValidator.validate(post_delete_with_moderator_actor, []) + assert meta[:do_not_federate] + + clear_config([:instance, :moderator_privileges], []) + + {:error, cng} = ObjectValidator.validate(post_delete_with_moderator_actor, []) + + assert {:actor, {"is not allowed to modify object", []}} in cng.errors end end end From edf0013ff38ae2d7bc84431d1d1384e5fc45bc0e Mon Sep 17 00:00:00 2001 From: Ilja Date: Sat, 18 Jun 2022 08:32:05 +0200 Subject: [PATCH 20/54] User.visible_for/2 According to the tests, this was only used for unconfirmed accounts. So this just needed to be restricted to users with privilege :user_activation --- lib/pleroma/user.ex | 2 +- test/pleroma/user_test.exs | 7 ++++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex index b93ce9c2c..7dfc6ce7b 100644 --- a/lib/pleroma/user.ex +++ b/lib/pleroma/user.ex @@ -326,7 +326,7 @@ def visible_for(%User{} = user, nil) do end def visible_for(%User{} = user, for_user) do - if superuser?(for_user) do + if privileged?(for_user, :user_activation) do :visible else visible_account_status(user) diff --git a/test/pleroma/user_test.exs b/test/pleroma/user_test.exs index 192bffaa9..22d55cd53 100644 --- a/test/pleroma/user_test.exs +++ b/test/pleroma/user_test.exs @@ -1986,13 +1986,18 @@ test "returns true when the account is unconfirmed and confirmation is required assert User.visible_for(user, other_user) == :visible end - test "returns true when the account is unconfirmed and being viewed by a privileged account (confirmation required)" do + test "returns true when the account is unconfirmed and being viewed by a privileged account (privilege :user_activation, confirmation required)" do clear_config([:instance, :account_activation_required], true) + clear_config([:instance, :admin_privileges], [:user_activation]) user = insert(:user, local: true, is_confirmed: false) other_user = insert(:user, local: true, is_admin: true) assert User.visible_for(user, other_user) == :visible + + clear_config([:instance, :admin_privileges], []) + + refute User.visible_for(user, other_user) == :visible end end From e45faddb38311c799b2276cb952ac7715e2cbfab Mon Sep 17 00:00:00 2001 From: Ilja Date: Sat, 18 Jun 2022 08:38:00 +0200 Subject: [PATCH 21/54] Revert "Delete report notifs when demoting from superuser" This reverts commit 89667189b840fc79d85336739e6b2512684d7be0 and cdc5bbe8369d4fc66d642bb3e845a237d11e34d7. This is a side effect when changing user role. The goal was to not have report notifications when someone isn't admin or moderator any more. But this won't be triggered when we change the privilege tags for a role, so we can't use this sollution any more. There was another solution to filter out report notifications during fetch. It wasn't merged because this seemed 'cleaner' at the time, but now it seems the better sollution. I'll add it in the next commit. --- lib/pleroma/notification.ex | 8 -------- lib/pleroma/user.ex | 16 +--------------- test/pleroma/notification_test.exs | 19 ------------------- test/pleroma/user_test.exs | 21 --------------------- 4 files changed, 1 insertion(+), 63 deletions(-) diff --git a/lib/pleroma/notification.ex b/lib/pleroma/notification.ex index 52fd2656b..41385884b 100644 --- a/lib/pleroma/notification.ex +++ b/lib/pleroma/notification.ex @@ -341,14 +341,6 @@ def destroy_multiple(%{id: user_id} = _user, ids) do |> Repo.delete_all() end - def destroy_multiple_from_types(%{id: user_id}, types) do - from(n in Notification, - where: n.user_id == ^user_id, - where: n.type in ^types - ) - |> Repo.delete_all() - end - def dismiss(%Pleroma.Activity{} = activity) do Notification |> where([n], n.activity_id == ^activity.id) diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex index 7dfc6ce7b..b68d5cf9a 100644 --- a/lib/pleroma/user.ex +++ b/lib/pleroma/user.ex @@ -1147,24 +1147,10 @@ def update_and_set_cache(struct, params) do |> update_and_set_cache() end - def update_and_set_cache(%{data: %Pleroma.User{} = user} = changeset) do - was_superuser_before_update = User.superuser?(user) - + def update_and_set_cache(changeset) do with {:ok, user} <- Repo.update(changeset, stale_error_field: :id) do set_cache(user) end - |> maybe_remove_report_notifications(was_superuser_before_update) - end - - defp maybe_remove_report_notifications({:ok, %Pleroma.User{} = user} = result, true) do - if not User.superuser?(user), - do: user |> Notification.destroy_multiple_from_types(["pleroma:report"]) - - result - end - - defp maybe_remove_report_notifications(result, _) do - result end def get_user_friends_ap_ids(user) do diff --git a/test/pleroma/notification_test.exs b/test/pleroma/notification_test.exs index 805764ea4..340a5f841 100644 --- a/test/pleroma/notification_test.exs +++ b/test/pleroma/notification_test.exs @@ -520,25 +520,6 @@ test "it clears all notifications belonging to the user" do end end - describe "destroy_multiple_from_types/2" do - test "clears all notifications of a certain type for a given user" do - report_activity = insert(:report_activity) - user1 = insert(:user, is_moderator: true, is_admin: true) - user2 = insert(:user, is_moderator: true, is_admin: true) - {:ok, _} = Notification.create_notifications(report_activity) - - {:ok, _} = - CommonAPI.post(user2, %{ - status: "hey @#{user1.nickname} !" - }) - - Notification.destroy_multiple_from_types(user1, ["pleroma:report"]) - - assert [%Pleroma.Notification{type: "mention"}] = Notification.for_user(user1) - assert [%Pleroma.Notification{type: "pleroma:report"}] = Notification.for_user(user2) - end - end - describe "set_read_up_to()" do test "it sets all notifications as read up to a specified notification ID" do user = insert(:user) diff --git a/test/pleroma/user_test.exs b/test/pleroma/user_test.exs index 22d55cd53..d110d71da 100644 --- a/test/pleroma/user_test.exs +++ b/test/pleroma/user_test.exs @@ -5,7 +5,6 @@ defmodule Pleroma.UserTest do alias Pleroma.Activity alias Pleroma.Builders.UserBuilder - alias Pleroma.Notification alias Pleroma.Object alias Pleroma.Repo alias Pleroma.Tests.ObanHelpers @@ -2252,26 +2251,6 @@ test "performs update cache if user updated" do assert {:ok, user} = Cachex.get(:user_cache, "ap_id:#{user.ap_id}") assert %User{bio: "test-bio"} = User.get_cached_by_ap_id(user.ap_id) end - - test "removes report notifs when user isn't superuser any more" do - report_activity = insert(:report_activity) - user = insert(:user, is_moderator: true, is_admin: true) - {:ok, _} = Notification.create_notifications(report_activity) - - assert [%Pleroma.Notification{type: "pleroma:report"}] = Notification.for_user(user) - - {:ok, user} = user |> User.admin_api_update(%{is_moderator: false}) - # is still superuser because still admin - assert [%Pleroma.Notification{type: "pleroma:report"}] = Notification.for_user(user) - - {:ok, user} = user |> User.admin_api_update(%{is_moderator: true, is_admin: false}) - # is still superuser because still moderator - assert [%Pleroma.Notification{type: "pleroma:report"}] = Notification.for_user(user) - - {:ok, user} = user |> User.admin_api_update(%{is_moderator: false}) - # is not a superuser any more - assert [] = Notification.for_user(user) - end end describe "following/followers synchronization" do From eab13fed3e6ba7edd7847fd00581b45dc4292af0 Mon Sep 17 00:00:00 2001 From: Ilja Date: Wed, 2 Mar 2022 18:05:50 +0100 Subject: [PATCH 22/54] Hide pleroma:report for non-privileged users Before we deleted the notifications, but that was a side effect and didn't always trigger any more. Now we just hide them when an unprivileged user asks them. --- lib/pleroma/web/mastodon_api/mastodon_api.ex | 13 +++++- .../notification_controller_test.exs | 44 +++++++++++++++++-- 2 files changed, 52 insertions(+), 5 deletions(-) diff --git a/lib/pleroma/web/mastodon_api/mastodon_api.ex b/lib/pleroma/web/mastodon_api/mastodon_api.ex index 5e32b9611..21ee5f0d4 100644 --- a/lib/pleroma/web/mastodon_api/mastodon_api.ex +++ b/lib/pleroma/web/mastodon_api/mastodon_api.ex @@ -61,7 +61,18 @@ def get_friends(user, params \\ %{}) do end def get_notifications(user, params \\ %{}) do - options = cast_params(params) + options = + cast_params(params) |> Map.update(:include_types, [], fn include_types -> include_types end) + + options = + if "pleroma:report" not in options.include_types or User.privileged?(user, :report_handle) do + options + else + options + |> Map.update(:exclude_types, ["pleroma:report"], fn current_exclude_types -> + current_exclude_types ++ ["pleroma:report"] + end) + end user |> Notification.for_user_query(options) diff --git a/test/pleroma/web/mastodon_api/controllers/notification_controller_test.exs b/test/pleroma/web/mastodon_api/controllers/notification_controller_test.exs index 2b7a95635..e0f1d2ac1 100644 --- a/test/pleroma/web/mastodon_api/controllers/notification_controller_test.exs +++ b/test/pleroma/web/mastodon_api/controllers/notification_controller_test.exs @@ -3,7 +3,7 @@ # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.MastodonAPI.NotificationControllerTest do - use Pleroma.Web.ConnCase + use Pleroma.Web.ConnCase, async: false alias Pleroma.Notification alias Pleroma.Repo @@ -74,12 +74,15 @@ test "by default, does not contain pleroma:chat_mention" do end test "by default, does not contain pleroma:report" do - %{user: user, conn: conn} = oauth_access(["read:notifications"]) + clear_config([:instance, :moderator_privileges], [:report_handle]) + + user = insert(:user) other_user = insert(:user) third_user = insert(:user) - user - |> User.admin_api_update(%{is_moderator: true}) + {:ok, user} = user |> User.admin_api_update(%{is_moderator: true}) + + %{conn: conn} = oauth_access(["read:notifications"], user: user) {:ok, activity} = CommonAPI.post(other_user, %{status: "hey"}) @@ -101,6 +104,39 @@ test "by default, does not contain pleroma:report" do assert [_] = result end + test "Pleroma:report is hidden for non-privileged users" do + clear_config([:instance, :moderator_privileges], [:report_handle]) + + user = insert(:user) + other_user = insert(:user) + third_user = insert(:user) + + {:ok, user} = user |> User.admin_api_update(%{is_moderator: true}) + + %{conn: conn} = oauth_access(["read:notifications"], user: user) + + {:ok, activity} = CommonAPI.post(other_user, %{status: "hey"}) + + {:ok, _report} = + CommonAPI.report(third_user, %{account_id: other_user.id, status_ids: [activity.id]}) + + result = + conn + |> get("/api/v1/notifications?include_types[]=pleroma:report") + |> json_response_and_validate_schema(200) + + assert [_] = result + + clear_config([:instance, :moderator_privileges], []) + + result = + conn + |> get("/api/v1/notifications?include_types[]=pleroma:report") + |> json_response_and_validate_schema(200) + + assert [] == result + end + test "excludes mentions from blockers when blockers_visible is false" do clear_config([:activitypub, :blockers_visible], false) From a1c8aa4721de8f5edd7d69dcd745586df23f5a31 Mon Sep 17 00:00:00 2001 From: Ilja Date: Sat, 18 Jun 2022 10:55:45 +0200 Subject: [PATCH 23/54] Remove function superuser? Everything now happens with privileged?/2 --- lib/pleroma/user.ex | 5 ----- test/pleroma/user_test.exs | 28 ---------------------------- 2 files changed, 33 deletions(-) diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex index b68d5cf9a..af29f85b5 100644 --- a/lib/pleroma/user.ex +++ b/lib/pleroma/user.ex @@ -371,11 +371,6 @@ defp privileged_for?(privilege_tag, true, config_role_key), defp privileged_for?(_, _, _), do: false - @spec superuser?(User.t()) :: boolean() - def superuser?(%User{local: true, is_admin: true}), do: true - def superuser?(%User{local: true, is_moderator: true}), do: true - def superuser?(_), do: false - @spec invisible?(User.t()) :: boolean() def invisible?(%User{invisible: true}), do: true def invisible?(_), do: false diff --git a/test/pleroma/user_test.exs b/test/pleroma/user_test.exs index d110d71da..9f8be7fa2 100644 --- a/test/pleroma/user_test.exs +++ b/test/pleroma/user_test.exs @@ -1918,34 +1918,6 @@ test "returns true for local admins if, and only if, they are privileged" do end end - describe "superuser?/1" do - test "returns false for unprivileged users" do - user = insert(:user, local: true) - - refute User.superuser?(user) - end - - test "returns false for remote users" do - user = insert(:user, local: false) - remote_admin_user = insert(:user, local: false, is_admin: true) - - refute User.superuser?(user) - refute User.superuser?(remote_admin_user) - end - - test "returns true for local moderators" do - user = insert(:user, local: true, is_moderator: true) - - assert User.superuser?(user) - end - - test "returns true for local admins" do - user = insert(:user, local: true, is_admin: true) - - assert User.superuser?(user) - end - end - describe "invisible?/1" do test "returns true for an invisible user" do user = insert(:user, local: true, invisible: true) From 34adea8d28cec91f03047989cbbaaf0b402c3a55 Mon Sep 17 00:00:00 2001 From: Ilja Date: Sun, 19 Jun 2022 11:05:09 +0200 Subject: [PATCH 24/54] Add Pleroma.User.all_users_with_privilege/1 This should eventually replace the Pleroma.User.all_superusers/0 function * I added a new param `is_privileged` in User.query * Now we can fetch all users with a specified privilege --- lib/pleroma/user.ex | 5 ++ lib/pleroma/user/query.ex | 39 ++++++++++++++ test/pleroma/user/query_test.exs | 92 +++++++++++++++++++++++++++++++- test/pleroma/user_test.exs | 90 +++++++++++++++++++++++++++++++ 4 files changed, 225 insertions(+), 1 deletion(-) diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex index af29f85b5..16438e524 100644 --- a/lib/pleroma/user.ex +++ b/lib/pleroma/user.ex @@ -2205,6 +2205,11 @@ def all_superusers do |> Repo.all() end + @spec all_users_with_privilege(atom()) :: [User.t()] + def all_users_with_privilege(privilege) do + User.Query.build(%{is_privileged: privilege}) |> Repo.all() + end + def muting_reblogs?(%User{} = user, %User{} = target) do UserRelationship.reblog_mute_exists?(user, target) end diff --git a/lib/pleroma/user/query.ex b/lib/pleroma/user/query.ex index 20bc1ea61..3e090cac0 100644 --- a/lib/pleroma/user/query.ex +++ b/lib/pleroma/user/query.ex @@ -29,6 +29,7 @@ defmodule Pleroma.User.Query do import Ecto.Query import Pleroma.Web.Utils.Guards, only: [not_empty_string: 1] + alias Pleroma.Config alias Pleroma.FollowingRelationship alias Pleroma.User @@ -49,6 +50,7 @@ defmodule Pleroma.User.Query do is_suggested: boolean(), is_discoverable: boolean(), super_users: boolean(), + is_privileged: atom(), invisible: boolean(), internal: boolean(), followers: User.t(), @@ -136,6 +138,43 @@ defp compose_query({:super_users, _}, query) do ) end + defp compose_query({:is_privileged, privilege}, query) do + moderator_privileged = privilege in Config.get([:instance, :moderator_privileges]) + admin_privileged = privilege in Config.get([:instance, :admin_privileges]) + + query = compose_query({:active, true}, query) + query = compose_query({:local, true}, query) + + case {admin_privileged, moderator_privileged} do + {false, false} -> + where( + query, + false + ) + + {true, true} -> + where( + query, + [u], + u.is_admin or u.is_moderator + ) + + {true, false} -> + where( + query, + [u], + u.is_admin + ) + + {false, true} -> + where( + query, + [u], + u.is_moderator + ) + end + end + defp compose_query({:local, _}, query), do: location_query(query, true) defp compose_query({:external, _}, query), do: location_query(query, false) diff --git a/test/pleroma/user/query_test.exs b/test/pleroma/user/query_test.exs index bd45d1bca..7e443536b 100644 --- a/test/pleroma/user/query_test.exs +++ b/test/pleroma/user/query_test.exs @@ -3,7 +3,7 @@ # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.User.QueryTest do - use Pleroma.DataCase, async: true + use Pleroma.DataCase, async: false alias Pleroma.Repo alias Pleroma.User @@ -44,4 +44,94 @@ test "is_suggested param" do |> User.Query.build() |> Repo.all() end + + describe "is_privileged param" do + setup do + %{ + user: insert(:user, local: true, is_admin: false, is_moderator: false), + moderator_user: insert(:user, local: true, is_admin: false, is_moderator: true), + admin_user: insert(:user, local: true, is_admin: true, is_moderator: false), + admin_moderator_user: insert(:user, local: true, is_admin: true, is_moderator: true), + remote_user: insert(:user, local: false, is_admin: true, is_moderator: true), + non_active_user: + insert(:user, local: true, is_admin: true, is_moderator: true, is_active: false) + } + end + + test "doesn't return any users when there are no privileged roles", %{ + user: user, + moderator_user: moderator_user, + admin_user: admin_user, + admin_moderator_user: admin_moderator_user, + remote_user: remote_user, + non_active_user: non_active_user + } do + clear_config([:instance, :admin_privileges], []) + clear_config([:instance, :moderator_privileges], []) + + refute user in (User.Query.build(%{is_privileged: :cofe}) |> Repo.all()) + refute admin_user in (User.Query.build(%{is_privileged: :cofe}) |> Repo.all()) + refute moderator_user in (User.Query.build(%{is_privileged: :cofe}) |> Repo.all()) + refute admin_moderator_user in (User.Query.build(%{is_privileged: :cofe}) |> Repo.all()) + refute remote_user in (User.Query.build(%{is_privileged: :cofe}) |> Repo.all()) + refute non_active_user in (User.Query.build(%{is_privileged: :cofe}) |> Repo.all()) + end + + test "returns moderator users if they are privileged", %{ + user: user, + moderator_user: moderator_user, + admin_user: admin_user, + admin_moderator_user: admin_moderator_user, + remote_user: remote_user, + non_active_user: non_active_user + } do + clear_config([:instance, :admin_privileges], []) + clear_config([:instance, :moderator_privileges], [:cofe]) + + refute user in (User.Query.build(%{is_privileged: :cofe}) |> Repo.all()) + refute admin_user in (User.Query.build(%{is_privileged: :cofe}) |> Repo.all()) + assert moderator_user in (User.Query.build(%{is_privileged: :cofe}) |> Repo.all()) + assert admin_moderator_user in (User.Query.build(%{is_privileged: :cofe}) |> Repo.all()) + refute remote_user in (User.Query.build(%{is_privileged: :cofe}) |> Repo.all()) + refute non_active_user in (User.Query.build(%{is_privileged: :cofe}) |> Repo.all()) + end + + test "returns admin users if they are privileged", %{ + user: user, + moderator_user: moderator_user, + admin_user: admin_user, + admin_moderator_user: admin_moderator_user, + remote_user: remote_user, + non_active_user: non_active_user + } do + clear_config([:instance, :admin_privileges], [:cofe]) + clear_config([:instance, :moderator_privileges], []) + + refute user in (User.Query.build(%{is_privileged: :cofe}) |> Repo.all()) + assert admin_user in (User.Query.build(%{is_privileged: :cofe}) |> Repo.all()) + refute moderator_user in (User.Query.build(%{is_privileged: :cofe}) |> Repo.all()) + assert admin_moderator_user in (User.Query.build(%{is_privileged: :cofe}) |> Repo.all()) + refute remote_user in (User.Query.build(%{is_privileged: :cofe}) |> Repo.all()) + refute non_active_user in (User.Query.build(%{is_privileged: :cofe}) |> Repo.all()) + end + + test "returns admin and moderator users if they are both privileged", %{ + user: user, + moderator_user: moderator_user, + admin_user: admin_user, + admin_moderator_user: admin_moderator_user, + remote_user: remote_user, + non_active_user: non_active_user + } do + clear_config([:instance, :admin_privileges], [:cofe]) + clear_config([:instance, :moderator_privileges], [:cofe]) + + refute user in (User.Query.build(%{is_privileged: :cofe}) |> Repo.all()) + assert admin_user in (User.Query.build(%{is_privileged: :cofe}) |> Repo.all()) + assert moderator_user in (User.Query.build(%{is_privileged: :cofe}) |> Repo.all()) + assert admin_moderator_user in (User.Query.build(%{is_privileged: :cofe}) |> Repo.all()) + refute remote_user in (User.Query.build(%{is_privileged: :cofe}) |> Repo.all()) + refute non_active_user in (User.Query.build(%{is_privileged: :cofe}) |> Repo.all()) + end + end end diff --git a/test/pleroma/user_test.exs b/test/pleroma/user_test.exs index 9f8be7fa2..0262470b2 100644 --- a/test/pleroma/user_test.exs +++ b/test/pleroma/user_test.exs @@ -1972,6 +1972,96 @@ test "returns true when the account is unconfirmed and being viewed by a privile end end + describe "all_users_with_privilege/1" do + setup do + %{ + user: insert(:user, local: true, is_admin: false, is_moderator: false), + moderator_user: insert(:user, local: true, is_admin: false, is_moderator: true), + admin_user: insert(:user, local: true, is_admin: true, is_moderator: false), + admin_moderator_user: insert(:user, local: true, is_admin: true, is_moderator: true), + remote_user: insert(:user, local: false, is_admin: true, is_moderator: true), + non_active_user: + insert(:user, local: true, is_admin: true, is_moderator: true, is_active: false) + } + end + + test "doesn't return any users when there are no privileged roles", %{ + user: user, + moderator_user: moderator_user, + admin_user: admin_user, + admin_moderator_user: admin_moderator_user, + remote_user: remote_user, + non_active_user: non_active_user + } do + clear_config([:instance, :admin_privileges], []) + clear_config([:instance, :moderator_privileges], []) + + refute user in User.all_users_with_privilege(:cofe) + refute admin_user in User.all_users_with_privilege(:cofe) + refute moderator_user in User.all_users_with_privilege(:cofe) + refute admin_moderator_user in User.all_users_with_privilege(:cofe) + refute remote_user in User.all_users_with_privilege(:cofe) + refute non_active_user in User.all_users_with_privilege(:cofe) + end + + test "returns moderator users if they are privileged", %{ + user: user, + moderator_user: moderator_user, + admin_user: admin_user, + admin_moderator_user: admin_moderator_user, + remote_user: remote_user, + non_active_user: non_active_user + } do + clear_config([:instance, :admin_privileges], []) + clear_config([:instance, :moderator_privileges], [:cofe]) + + refute user in User.all_users_with_privilege(:cofe) + refute admin_user in User.all_users_with_privilege(:cofe) + assert moderator_user in User.all_users_with_privilege(:cofe) + assert admin_moderator_user in User.all_users_with_privilege(:cofe) + refute remote_user in User.all_users_with_privilege(:cofe) + refute non_active_user in User.all_users_with_privilege(:cofe) + end + + test "returns admin users if they are privileged", %{ + user: user, + moderator_user: moderator_user, + admin_user: admin_user, + admin_moderator_user: admin_moderator_user, + remote_user: remote_user, + non_active_user: non_active_user + } do + clear_config([:instance, :admin_privileges], [:cofe]) + clear_config([:instance, :moderator_privileges], []) + + refute user in User.all_users_with_privilege(:cofe) + assert admin_user in User.all_users_with_privilege(:cofe) + refute moderator_user in User.all_users_with_privilege(:cofe) + assert admin_moderator_user in User.all_users_with_privilege(:cofe) + refute remote_user in User.all_users_with_privilege(:cofe) + refute non_active_user in User.all_users_with_privilege(:cofe) + end + + test "returns admin and moderator users if they are both privileged", %{ + user: user, + moderator_user: moderator_user, + admin_user: admin_user, + admin_moderator_user: admin_moderator_user, + remote_user: remote_user, + non_active_user: non_active_user + } do + clear_config([:instance, :admin_privileges], [:cofe]) + clear_config([:instance, :moderator_privileges], [:cofe]) + + refute user in User.all_users_with_privilege(:cofe) + assert admin_user in User.all_users_with_privilege(:cofe) + assert moderator_user in User.all_users_with_privilege(:cofe) + assert admin_moderator_user in User.all_users_with_privilege(:cofe) + refute remote_user in User.all_users_with_privilege(:cofe) + refute non_active_user in User.all_users_with_privilege(:cofe) + end + end + describe "parse_bio/2" do test "preserves hosts in user links text" do remote_user = insert(:user, local: false, nickname: "nick@domain.com") From e21ef5aef389f7cef9ba53525d2d38bb29f5e257 Mon Sep 17 00:00:00 2001 From: Ilja Date: Sun, 19 Jun 2022 16:26:56 +0200 Subject: [PATCH 25/54] report notifications for privileged users Instead of `Pleroma.User.all_superusers()` we now use `Pleroma.User.all_superusers(:report_handle)` I also changed it for sending emails, but there were no tests. --- lib/pleroma/notification.ex | 3 ++- lib/pleroma/web/activity_pub/activity_pub.ex | 6 +++--- test/pleroma/notification_test.exs | 18 ++++++++++++------ .../views/notification_view_test.exs | 6 ++++-- 4 files changed, 21 insertions(+), 12 deletions(-) diff --git a/lib/pleroma/notification.ex b/lib/pleroma/notification.ex index 41385884b..9a3ffc0c2 100644 --- a/lib/pleroma/notification.ex +++ b/lib/pleroma/notification.ex @@ -542,7 +542,8 @@ def get_potential_receiver_ap_ids(%{data: %{"type" => "Follow", "object" => obje end def get_potential_receiver_ap_ids(%{data: %{"type" => "Flag", "actor" => actor}}) do - (User.all_superusers() |> Enum.map(fn user -> user.ap_id end)) -- [actor] + (User.all_users_with_privilege(:report_handle) |> Enum.map(fn user -> user.ap_id end)) -- + [actor] end def get_potential_receiver_ap_ids(activity) do diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex index 064f93b22..68cd818b9 100644 --- a/lib/pleroma/web/activity_pub/activity_pub.ex +++ b/lib/pleroma/web/activity_pub/activity_pub.ex @@ -392,11 +392,11 @@ defp do_flag( _ <- notify_and_stream(activity), :ok <- maybe_federate(stripped_activity) do - User.all_superusers() + User.all_users_with_privilege(:report_handle) |> Enum.filter(fn user -> user.ap_id != actor end) |> Enum.filter(fn user -> not is_nil(user.email) end) - |> Enum.each(fn superuser -> - superuser + |> Enum.each(fn privileged_user -> + privileged_user |> Pleroma.Emails.AdminEmail.report(actor, account, statuses, content) |> Pleroma.Emails.Mailer.deliver_async() end) diff --git a/test/pleroma/notification_test.exs b/test/pleroma/notification_test.exs index 340a5f841..e1f4b1771 100644 --- a/test/pleroma/notification_test.exs +++ b/test/pleroma/notification_test.exs @@ -3,7 +3,7 @@ # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.NotificationTest do - use Pleroma.DataCase + use Pleroma.DataCase, async: false import Pleroma.Factory import Mock @@ -32,20 +32,26 @@ test "never returns nil" do refute {:ok, [nil]} == Notification.create_notifications(activity) end - test "creates a notification for a report" do + test "creates a report notification only for privileged users" do reporting_user = insert(:user) reported_user = insert(:user) - {:ok, moderator_user} = insert(:user) |> User.admin_api_update(%{is_moderator: true}) + moderator_user = insert(:user, is_moderator: true) - {:ok, activity} = CommonAPI.report(reporting_user, %{account_id: reported_user.id}) + clear_config([:instance, :moderator_privileges], []) + {:ok, activity1} = CommonAPI.report(reporting_user, %{account_id: reported_user.id}) + {:ok, []} = Notification.create_notifications(activity1) - {:ok, [notification]} = Notification.create_notifications(activity) + clear_config([:instance, :moderator_privileges], [:report_handle]) + {:ok, activity2} = CommonAPI.report(reporting_user, %{account_id: reported_user.id}) + {:ok, [notification]} = Notification.create_notifications(activity2) assert notification.user_id == moderator_user.id assert notification.type == "pleroma:report" end - test "suppresses notification to reporter if reporter is an admin" do + test "suppresses notifications for own reports" do + clear_config([:instance, :admin_privileges], [:report_handle]) + reporting_admin = insert(:user, is_admin: true) reported_user = insert(:user) other_admin = insert(:user, is_admin: true) diff --git a/test/pleroma/web/mastodon_api/views/notification_view_test.exs b/test/pleroma/web/mastodon_api/views/notification_view_test.exs index 8e4c9136a..76338877e 100644 --- a/test/pleroma/web/mastodon_api/views/notification_view_test.exs +++ b/test/pleroma/web/mastodon_api/views/notification_view_test.exs @@ -3,7 +3,7 @@ # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.MastodonAPI.NotificationViewTest do - use Pleroma.DataCase + use Pleroma.DataCase, async: false alias Pleroma.Activity alias Pleroma.Chat @@ -218,9 +218,11 @@ test "Poll notification" do end test "Report notification" do + clear_config([:instance, :moderator_privileges], [:report_handle]) + reporting_user = insert(:user) reported_user = insert(:user) - {:ok, moderator_user} = insert(:user) |> User.admin_api_update(%{is_moderator: true}) + moderator_user = insert(:user, is_moderator: true) {:ok, activity} = CommonAPI.report(reporting_user, %{account_id: reported_user.id}) {:ok, [notification]} = Notification.create_notifications(activity) From 143ea7b80a228d9bd23a77354fe214553ca2b8cc Mon Sep 17 00:00:00 2001 From: Ilja Date: Tue, 21 Jun 2022 09:21:45 +0200 Subject: [PATCH 26/54] Add deactivated status for privileged users Deactivated users are only visible to users privileged with :user_activation since fc317f3b17 Here we also make sure the users who are deactivated get the status deactivated for users who are allowed to see these users --- lib/pleroma/web/mastodon_api/views/account_view.ex | 8 ++++---- test/pleroma/web/mastodon_api/views/account_view_test.exs | 8 +++++--- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/lib/pleroma/web/mastodon_api/views/account_view.ex b/lib/pleroma/web/mastodon_api/views/account_view.ex index 988eedbb1..d3f2245e2 100644 --- a/lib/pleroma/web/mastodon_api/views/account_view.ex +++ b/lib/pleroma/web/mastodon_api/views/account_view.ex @@ -398,12 +398,12 @@ defp maybe_put_allow_following_move(data, %User{id: user_id} = user, %User{id: u defp maybe_put_allow_following_move(data, _, _), do: data - defp maybe_put_activation_status(data, user, %User{is_admin: true}) do - Kernel.put_in(data, [:pleroma, :deactivated], !user.is_active) + defp maybe_put_activation_status(data, user, user_for) do + if User.privileged?(user_for, :user_activation), + do: Kernel.put_in(data, [:pleroma, :deactivated], !user.is_active), + else: data end - defp maybe_put_activation_status(data, _, _), do: data - defp maybe_put_unread_conversation_count(data, %User{id: user_id} = user, %User{id: user_id}) do data |> Kernel.put_in( diff --git a/test/pleroma/web/mastodon_api/views/account_view_test.exs b/test/pleroma/web/mastodon_api/views/account_view_test.exs index 8ed37fe58..d9d3866e7 100644 --- a/test/pleroma/web/mastodon_api/views/account_view_test.exs +++ b/test/pleroma/web/mastodon_api/views/account_view_test.exs @@ -3,7 +3,7 @@ # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.MastodonAPI.AccountViewTest do - use Pleroma.DataCase + use Pleroma.DataCase, async: false alias Pleroma.User alias Pleroma.UserRelationship @@ -214,8 +214,10 @@ test "Represent a Funkwhale channel" do assert represented.url == "https://channels.tests.funkwhale.audio/channels/compositions" end - test "Represent a deactivated user for an admin" do - admin = insert(:user, is_admin: true) + test "Represent a deactivated user for a privileged user" do + clear_config([:instance, :moderator_privileges], [:user_activation]) + + admin = insert(:user, is_moderator: true) deactivated_user = insert(:user, is_active: false) represented = AccountView.render("show.json", %{user: deactivated_user, for: admin}) assert represented[:pleroma][:deactivated] == true From 211e561e2ad862c75a1b34f783d3210523dc211e Mon Sep 17 00:00:00 2001 From: Ilja Date: Tue, 21 Jun 2022 11:13:32 +0200 Subject: [PATCH 27/54] Show privileges to FE I added an extra key We already had is_admin and is_moderator, now we have an extra privileges key --- lib/pleroma/user.ex | 22 +++ .../web/mastodon_api/views/account_view.ex | 15 +- test/pleroma/user_test.exs | 38 +++++ .../mastodon_api/views/account_view_test.exs | 143 ++++++++++++++++++ 4 files changed, 212 insertions(+), 6 deletions(-) diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex index 16438e524..fb2fade42 100644 --- a/lib/pleroma/user.ex +++ b/lib/pleroma/user.ex @@ -371,6 +371,28 @@ defp privileged_for?(privilege_tag, true, config_role_key), defp privileged_for?(_, _, _), do: false + @spec privileges(User.t()) :: [atom()] + def privileges(%User{local: false}) do + [] + end + + def privileges(%User{is_moderator: false, is_admin: false}) do + [] + end + + def privileges(%User{local: true, is_moderator: true, is_admin: true}) do + (Config.get([:instance, :moderator_privileges]) ++ Config.get([:instance, :admin_privileges])) + |> Enum.uniq() + end + + def privileges(%User{local: true, is_moderator: true, is_admin: false}) do + Config.get([:instance, :moderator_privileges]) + end + + def privileges(%User{local: true, is_moderator: false, is_admin: true}) do + Config.get([:instance, :admin_privileges]) + end + @spec invisible?(User.t()) :: boolean() def invisible?(%User{invisible: true}), do: true def invisible?(_), do: false diff --git a/lib/pleroma/web/mastodon_api/views/account_view.ex b/lib/pleroma/web/mastodon_api/views/account_view.ex index d3f2245e2..a28ad9d85 100644 --- a/lib/pleroma/web/mastodon_api/views/account_view.ex +++ b/lib/pleroma/web/mastodon_api/views/account_view.ex @@ -369,19 +369,22 @@ defp maybe_put_chat_token(data, %User{id: id}, %User{id: id}, %{ defp maybe_put_chat_token(data, _, _, _), do: data defp maybe_put_role(data, %User{show_role: true} = user, _) do - data - |> Kernel.put_in([:pleroma, :is_admin], user.is_admin) - |> Kernel.put_in([:pleroma, :is_moderator], user.is_moderator) + put_role(data, user) end defp maybe_put_role(data, %User{id: user_id} = user, %User{id: user_id}) do - data - |> Kernel.put_in([:pleroma, :is_admin], user.is_admin) - |> Kernel.put_in([:pleroma, :is_moderator], user.is_moderator) + put_role(data, user) end defp maybe_put_role(data, _, _), do: data + defp put_role(data, user) do + data + |> Kernel.put_in([:pleroma, :is_admin], user.is_admin) + |> Kernel.put_in([:pleroma, :is_moderator], user.is_moderator) + |> Kernel.put_in([:pleroma, :privileges], User.privileges(user)) + end + defp maybe_put_notification_settings(data, %User{id: user_id} = user, %User{id: user_id}) do Kernel.put_in( data, diff --git a/test/pleroma/user_test.exs b/test/pleroma/user_test.exs index 0262470b2..477553fe5 100644 --- a/test/pleroma/user_test.exs +++ b/test/pleroma/user_test.exs @@ -1918,6 +1918,44 @@ test "returns true for local admins if, and only if, they are privileged" do end end + describe "privileges/1" do + setup do + clear_config([:instance, :moderator_privileges], [:cofe, :only_moderator]) + clear_config([:instance, :admin_privileges], [:cofe, :only_admin]) + end + + test "returns empty list for users without roles" do + user = insert(:user, local: true) + + assert [] == User.privileges(user) + end + + test "returns list of privileges for moderators" do + moderator = insert(:user, is_moderator: true, local: true) + + assert [:cofe, :only_moderator] == User.privileges(moderator) |> Enum.sort() + end + + test "returns list of privileges for admins" do + admin = insert(:user, is_admin: true, local: true) + + assert [:cofe, :only_admin] == User.privileges(admin) |> Enum.sort() + end + + test "returns list of unique privileges for users who are both moderator and admin" do + moderator_admin = insert(:user, is_moderator: true, is_admin: true, local: true) + + assert [:cofe, :only_admin, :only_moderator] == + User.privileges(moderator_admin) |> Enum.sort() + end + + test "returns empty list for remote users" do + remote_moderator_admin = insert(:user, is_moderator: true, is_admin: true, local: false) + + assert [] == User.privileges(remote_moderator_admin) + end + end + describe "invisible?/1" do test "returns true for an invisible user" do user = insert(:user, local: true, invisible: true) diff --git a/test/pleroma/web/mastodon_api/views/account_view_test.exs b/test/pleroma/web/mastodon_api/views/account_view_test.exs index d9d3866e7..ce94ec7e4 100644 --- a/test/pleroma/web/mastodon_api/views/account_view_test.exs +++ b/test/pleroma/web/mastodon_api/views/account_view_test.exs @@ -84,6 +84,7 @@ test "Represent a user account" do tags: [], is_admin: false, is_moderator: false, + privileges: [], is_suggested: false, hide_favorites: true, hide_followers: false, @@ -99,6 +100,147 @@ test "Represent a user account" do assert expected == AccountView.render("show.json", %{user: user, skip_visibility_check: true}) end + describe "roles and privileges" do + setup do + clear_config([:instance, :moderator_privileges], [:cofe, :only_moderator]) + clear_config([:instance, :admin_privileges], [:cofe, :only_admin]) + + %{ + user: insert(:user), + moderator: insert(:user, is_moderator: true), + admin: insert(:user, is_admin: true), + moderator_admin: insert(:user, is_moderator: true, is_admin: true), + user_no_show_roles: insert(:user, show_role: false), + moderator_admin_no_show_roles: + insert(:user, is_moderator: true, is_admin: true, show_role: false) + } + end + + test "shows roles and privileges when show_role: true", %{ + user: user, + moderator: moderator, + admin: admin, + moderator_admin: moderator_admin, + user_no_show_roles: user_no_show_roles, + moderator_admin_no_show_roles: moderator_admin_no_show_roles + } do + assert %{pleroma: %{is_moderator: false, is_admin: false}} = + AccountView.render("show.json", %{user: user, skip_visibility_check: true}) + + assert [] == + AccountView.render("show.json", %{user: user, skip_visibility_check: true})[ + :pleroma + ][:privileges] + |> Enum.sort() + + assert %{pleroma: %{is_moderator: true, is_admin: false}} = + AccountView.render("show.json", %{user: moderator, skip_visibility_check: true}) + + assert [:cofe, :only_moderator] == + AccountView.render("show.json", %{user: moderator, skip_visibility_check: true})[ + :pleroma + ][:privileges] + |> Enum.sort() + + assert %{pleroma: %{is_moderator: false, is_admin: true}} = + AccountView.render("show.json", %{user: admin, skip_visibility_check: true}) + + assert [:cofe, :only_admin] == + AccountView.render("show.json", %{user: admin, skip_visibility_check: true})[ + :pleroma + ][:privileges] + |> Enum.sort() + + assert %{pleroma: %{is_moderator: true, is_admin: true}} = + AccountView.render("show.json", %{ + user: moderator_admin, + skip_visibility_check: true + }) + + assert [:cofe, :only_admin, :only_moderator] == + AccountView.render("show.json", %{ + user: moderator_admin, + skip_visibility_check: true + })[:pleroma][:privileges] + |> Enum.sort() + + refute match?( + %{pleroma: %{is_moderator: _}}, + AccountView.render("show.json", %{ + user: user_no_show_roles, + skip_visibility_check: true + }) + ) + + refute match?( + %{pleroma: %{is_admin: _}}, + AccountView.render("show.json", %{ + user: user_no_show_roles, + skip_visibility_check: true + }) + ) + + refute match?( + %{pleroma: %{privileges: _}}, + AccountView.render("show.json", %{ + user: user_no_show_roles, + skip_visibility_check: true + }) + ) + + refute match?( + %{pleroma: %{is_moderator: _}}, + AccountView.render("show.json", %{ + user: moderator_admin_no_show_roles, + skip_visibility_check: true + }) + ) + + refute match?( + %{pleroma: %{is_admin: _}}, + AccountView.render("show.json", %{ + user: moderator_admin_no_show_roles, + skip_visibility_check: true + }) + ) + + refute match?( + %{pleroma: %{privileges: _}}, + AccountView.render("show.json", %{ + user: moderator_admin_no_show_roles, + skip_visibility_check: true + }) + ) + end + + test "shows roles and privileges when viewing own account, even when show_role: false", %{ + user_no_show_roles: user_no_show_roles, + moderator_admin_no_show_roles: moderator_admin_no_show_roles + } do + assert %{pleroma: %{is_moderator: false, is_admin: false, privileges: []}} = + AccountView.render("show.json", %{ + user: user_no_show_roles, + skip_visibility_check: true, + for: user_no_show_roles + }) + + assert %{ + pleroma: %{ + is_moderator: true, + is_admin: true, + privileges: privileges + } + } = + AccountView.render("show.json", %{ + user: moderator_admin_no_show_roles, + skip_visibility_check: true, + for: moderator_admin_no_show_roles + }) + + assert [:cofe, :only_admin, :only_moderator] == privileges |> Enum.sort() + end + end + describe "favicon" do setup do [user: insert(:user)] @@ -186,6 +328,7 @@ test "Represent a Service(bot) account" do tags: [], is_admin: false, is_moderator: false, + privileges: [], is_suggested: false, hide_favorites: true, hide_followers: false, From 4e4eb81749076ada5692b92061c77a72832a9cc8 Mon Sep 17 00:00:00 2001 From: Ilja Date: Tue, 21 Jun 2022 12:03:35 +0200 Subject: [PATCH 28/54] Add nodes and privileges to nodeinfo I didn't add it to /api/v1/instance I was wondering if I should, but since it e.g. also didn't show staff, it felt better not to --- lib/pleroma/web/nodeinfo/nodeinfo.ex | 4 ++++ test/pleroma/web/node_info_test.exs | 15 ++++++++++++++- 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/lib/pleroma/web/nodeinfo/nodeinfo.ex b/lib/pleroma/web/nodeinfo/nodeinfo.ex index c7b9ab2de..9e27ac26c 100644 --- a/lib/pleroma/web/nodeinfo/nodeinfo.ex +++ b/lib/pleroma/web/nodeinfo/nodeinfo.ex @@ -49,6 +49,10 @@ def get_nodeinfo("2.0") do enabled: false }, staffAccounts: staff_accounts, + roles: %{ + admin: Config.get([:instance, :admin_privileges]), + moderator: Config.get([:instance, :moderator_privileges]) + }, federation: federation, pollLimits: Config.get([:instance, :poll_limits]), postFormats: Config.get([:instance, :allowed_post_formats]), diff --git a/test/pleroma/web/node_info_test.exs b/test/pleroma/web/node_info_test.exs index 247ad7501..f474220be 100644 --- a/test/pleroma/web/node_info_test.exs +++ b/test/pleroma/web/node_info_test.exs @@ -3,7 +3,7 @@ # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.NodeInfoTest do - use Pleroma.Web.ConnCase + use Pleroma.Web.ConnCase, async: false import Pleroma.Factory @@ -40,6 +40,19 @@ test "nodeinfo shows staff accounts", %{conn: conn} do assert admin.ap_id in result["metadata"]["staffAccounts"] end + test "nodeinfo shows roles and privileges", %{conn: conn} do + clear_config([:instance, :moderator_privileges], [:cofe]) + clear_config([:instance, :admin_privileges], [:suya, :cofe]) + + conn = + conn + |> get("/nodeinfo/2.1.json") + + assert result = json_response(conn, 200) + + assert %{"admin" => ["suya", "cofe"], "moderator" => ["cofe"]} == result["metadata"]["roles"] + end + test "nodeinfo shows restricted nicknames", %{conn: conn} do conn = conn From 37fdf148b0963b62ab746a8ece2aacf893ba8934 Mon Sep 17 00:00:00 2001 From: Ilja Date: Fri, 1 Jul 2022 09:54:05 +0200 Subject: [PATCH 29/54] Rename privilege tags I first focussed on getting things working Now that they do and we know what tags there are, I put some thought in providing better names I use the form _ :statuses_read => :messages_read :status_delete => :messages_delete :user_read => :users_read :user_deletion => :users_delete :user_activation => :users_manage_activation_state :user_invite => :users_manage_invites :user_tag => :users_manage_tags :user_credentials => :users_manage_credentials :report_handle => :reports_manage_reports :emoji_management => :emoji_manage_emoji --- config/config.exs | 20 +++++----- config/description.exs | 40 +++++++++---------- lib/pleroma/notification.ex | 3 +- lib/pleroma/user.ex | 2 +- lib/pleroma/web/activity_pub/activity_pub.ex | 2 +- .../object_validators/delete_validator.ex | 2 +- lib/pleroma/web/common_api.ex | 2 +- lib/pleroma/web/mastodon_api/mastodon_api.ex | 3 +- .../web/mastodon_api/views/account_view.ex | 2 +- lib/pleroma/web/router.ex | 20 +++++----- test/pleroma/notification_test.exs | 4 +- test/pleroma/user_test.exs | 4 +- .../delete_validation_test.exs | 2 +- .../controllers/admin_api_controller_test.exs | 28 ++++++------- .../controllers/chat_controller_test.exs | 12 +++--- .../controllers/instance_controller_test.exs | 2 +- .../controllers/invite_controller_test.exs | 18 ++++----- .../controllers/report_controller_test.exs | 23 +++++++---- .../controllers/status_controller_test.exs | 14 +++---- .../controllers/user_controller_test.exs | 24 +++++------ test/pleroma/web/common_api_test.exs | 4 +- .../notification_controller_test.exs | 4 +- .../controllers/status_controller_test.exs | 2 +- .../mastodon_api/views/account_view_test.exs | 2 +- .../views/notification_view_test.exs | 2 +- .../emoji_file_controller_test.exs | 4 +- .../emoji_pack_controller_test.exs | 19 +++++---- 27 files changed, 138 insertions(+), 126 deletions(-) diff --git a/config/config.exs b/config/config.exs index 263299e4d..935d4fc98 100644 --- a/config/config.exs +++ b/config/config.exs @@ -257,16 +257,16 @@ password_reset_token_validity: 60 * 60 * 24, profile_directory: true, admin_privileges: [ - :user_deletion, - :user_credentials, - :statuses_read, - :user_tag, - :user_activation, - :user_invite, - :report_handle, - :user_read, - :status_delete, - :emoji_management + :users_delete, + :users_manage_credentials, + :messages_read, + :users_manage_tags, + :users_manage_activation_state, + :users_manage_invites, + :reports_manage_reports, + :users_read, + :messages_delete, + :emoji_manage_emoji ], moderator_privileges: [], max_endorsed_users: 20, diff --git a/config/description.exs b/config/description.exs index 9f595fae0..e5a49139e 100644 --- a/config/description.exs +++ b/config/description.exs @@ -964,16 +964,16 @@ key: :admin_privileges, type: {:list, :atom}, suggestions: [ - :user_deletion, - :user_credentials, - :statuses_read, - :user_tag, - :user_activation, - :user_invite, - :report_handle, - :user_read, - :status_delete, - :emoji_management + :users_delete, + :users_manage_credentials, + :messages_read, + :users_manage_tags, + :users_manage_activation_state, + :users_manage_invites, + :reports_manage_reports, + :users_read, + :messages_delete, + :emoji_manage_emoji ], description: "What extra priviledges to allow admins (e.g. updating user credentials, get password reset token, delete users, index and read private statuses and chats)" @@ -982,16 +982,16 @@ key: :moderator_privileges, type: {:list, :atom}, suggestions: [ - :user_deletion, - :user_credentials, - :statuses_read, - :user_tag, - :user_activation, - :user_invite, - :report_handle, - :user_read, - :status_delete, - :emoji_management + :users_delete, + :users_manage_credentials, + :messages_read, + :users_manage_tags, + :users_manage_activation_state, + :users_manage_invites, + :reports_manage_reports, + :users_read, + :messages_delete, + :emoji_manage_emoji ], description: "What extra priviledges to allow moderators (e.g. updating user credentials, get password reset token, delete users, index and read private statuses and chats)" diff --git a/lib/pleroma/notification.ex b/lib/pleroma/notification.ex index 9a3ffc0c2..cfc4bfca3 100644 --- a/lib/pleroma/notification.ex +++ b/lib/pleroma/notification.ex @@ -542,7 +542,8 @@ def get_potential_receiver_ap_ids(%{data: %{"type" => "Follow", "object" => obje end def get_potential_receiver_ap_ids(%{data: %{"type" => "Flag", "actor" => actor}}) do - (User.all_users_with_privilege(:report_handle) |> Enum.map(fn user -> user.ap_id end)) -- + (User.all_users_with_privilege(:reports_manage_reports) + |> Enum.map(fn user -> user.ap_id end)) -- [actor] end diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex index fb2fade42..11c4d0684 100644 --- a/lib/pleroma/user.ex +++ b/lib/pleroma/user.ex @@ -326,7 +326,7 @@ def visible_for(%User{} = user, nil) do end def visible_for(%User{} = user, for_user) do - if privileged?(for_user, :user_activation) do + if privileged?(for_user, :users_manage_activation_state) do :visible else visible_account_status(user) diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex index 68cd818b9..06c894efd 100644 --- a/lib/pleroma/web/activity_pub/activity_pub.ex +++ b/lib/pleroma/web/activity_pub/activity_pub.ex @@ -392,7 +392,7 @@ defp do_flag( _ <- notify_and_stream(activity), :ok <- maybe_federate(stripped_activity) do - User.all_users_with_privilege(:report_handle) + User.all_users_with_privilege(:reports_manage_reports) |> Enum.filter(fn user -> user.ap_id != actor end) |> Enum.filter(fn user -> not is_nil(user.email) end) |> Enum.each(fn privileged_user -> diff --git a/lib/pleroma/web/activity_pub/object_validators/delete_validator.ex b/lib/pleroma/web/activity_pub/object_validators/delete_validator.ex index 6e4208167..4d8502ada 100644 --- a/lib/pleroma/web/activity_pub/object_validators/delete_validator.ex +++ b/lib/pleroma/web/activity_pub/object_validators/delete_validator.ex @@ -61,7 +61,7 @@ defp validate_data(cng) do |> validate_required([:id, :type, :actor, :to, :cc, :object]) |> validate_inclusion(:type, ["Delete"]) |> validate_delete_actor(:actor) - |> validate_modification_rights(:status_delete) + |> validate_modification_rights(:messages_delete) |> validate_object_or_user_presence(allowed_types: @deletable_types) |> add_deleted_activity_id() end diff --git a/lib/pleroma/web/common_api.ex b/lib/pleroma/web/common_api.ex index ce1d5a7cc..4ac5df63f 100644 --- a/lib/pleroma/web/common_api.ex +++ b/lib/pleroma/web/common_api.ex @@ -144,7 +144,7 @@ def delete(activity_id, user) do {:find_activity, Activity.get_by_id(activity_id)}, {_, %Object{} = object, _} <- {:find_object, Object.normalize(activity, fetch: false), activity}, - true <- User.privileged?(user, :status_delete) || user.ap_id == object.data["actor"], + true <- User.privileged?(user, :messages_delete) || user.ap_id == object.data["actor"], {:ok, delete_data, _} <- Builder.delete(user, object.data["id"]), {:ok, delete, _} <- Pipeline.common_pipeline(delete_data, local: true) do {:ok, delete} diff --git a/lib/pleroma/web/mastodon_api/mastodon_api.ex b/lib/pleroma/web/mastodon_api/mastodon_api.ex index 21ee5f0d4..932e5d4eb 100644 --- a/lib/pleroma/web/mastodon_api/mastodon_api.ex +++ b/lib/pleroma/web/mastodon_api/mastodon_api.ex @@ -65,7 +65,8 @@ def get_notifications(user, params \\ %{}) do cast_params(params) |> Map.update(:include_types, [], fn include_types -> include_types end) options = - if "pleroma:report" not in options.include_types or User.privileged?(user, :report_handle) do + if "pleroma:report" not in options.include_types or + User.privileged?(user, :reports_manage_reports) do options else options diff --git a/lib/pleroma/web/mastodon_api/views/account_view.ex b/lib/pleroma/web/mastodon_api/views/account_view.ex index a28ad9d85..34b34dc19 100644 --- a/lib/pleroma/web/mastodon_api/views/account_view.ex +++ b/lib/pleroma/web/mastodon_api/views/account_view.ex @@ -402,7 +402,7 @@ defp maybe_put_allow_following_move(data, %User{id: user_id} = user, %User{id: u defp maybe_put_allow_following_move(data, _, _), do: data defp maybe_put_activation_status(data, user, user_for) do - if User.privileged?(user_for, :user_activation), + if User.privileged?(user_for, :users_manage_activation_state), do: Kernel.put_in(data, [:pleroma, :deactivated], !user.is_active), else: data end diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex index f680c8353..cbb5ca55f 100644 --- a/lib/pleroma/web/router.ex +++ b/lib/pleroma/web/router.ex @@ -107,52 +107,52 @@ defmodule Pleroma.Web.Router do pipeline :require_privileged_role_user_deletion do plug(:admin_api) - plug(Pleroma.Web.Plugs.EnsurePrivilegedPlug, :user_deletion) + plug(Pleroma.Web.Plugs.EnsurePrivilegedPlug, :users_delete) end pipeline :require_privileged_role_user_credentials do plug(:admin_api) - plug(Pleroma.Web.Plugs.EnsurePrivilegedPlug, :user_credentials) + plug(Pleroma.Web.Plugs.EnsurePrivilegedPlug, :users_manage_credentials) end pipeline :require_privileged_role_statuses_read do plug(:admin_api) - plug(Pleroma.Web.Plugs.EnsurePrivilegedPlug, :statuses_read) + plug(Pleroma.Web.Plugs.EnsurePrivilegedPlug, :messages_read) end pipeline :require_privileged_role_user_tag do plug(:admin_api) - plug(Pleroma.Web.Plugs.EnsurePrivilegedPlug, :user_tag) + plug(Pleroma.Web.Plugs.EnsurePrivilegedPlug, :users_manage_tags) end pipeline :require_privileged_role_user_activation do plug(:admin_api) - plug(Pleroma.Web.Plugs.EnsurePrivilegedPlug, :user_activation) + plug(Pleroma.Web.Plugs.EnsurePrivilegedPlug, :users_manage_activation_state) end pipeline :require_privileged_role_user_invite do plug(:admin_api) - plug(Pleroma.Web.Plugs.EnsurePrivilegedPlug, :user_invite) + plug(Pleroma.Web.Plugs.EnsurePrivilegedPlug, :users_manage_invites) end pipeline :require_privileged_role_report_handle do plug(:admin_api) - plug(Pleroma.Web.Plugs.EnsurePrivilegedPlug, :report_handle) + plug(Pleroma.Web.Plugs.EnsurePrivilegedPlug, :reports_manage_reports) end pipeline :require_privileged_role_user_read do plug(:admin_api) - plug(Pleroma.Web.Plugs.EnsurePrivilegedPlug, :user_read) + plug(Pleroma.Web.Plugs.EnsurePrivilegedPlug, :users_read) end pipeline :require_privileged_role_status_delete do plug(:admin_api) - plug(Pleroma.Web.Plugs.EnsurePrivilegedPlug, :status_delete) + plug(Pleroma.Web.Plugs.EnsurePrivilegedPlug, :messages_delete) end pipeline :require_privileged_role_emoji_management do plug(:admin_api) - plug(Pleroma.Web.Plugs.EnsurePrivilegedPlug, :emoji_management) + plug(Pleroma.Web.Plugs.EnsurePrivilegedPlug, :emoji_manage_emoji) end pipeline :require_privileged_role_instance_delete do diff --git a/test/pleroma/notification_test.exs b/test/pleroma/notification_test.exs index e1f4b1771..d0f34113b 100644 --- a/test/pleroma/notification_test.exs +++ b/test/pleroma/notification_test.exs @@ -41,7 +41,7 @@ test "creates a report notification only for privileged users" do {:ok, activity1} = CommonAPI.report(reporting_user, %{account_id: reported_user.id}) {:ok, []} = Notification.create_notifications(activity1) - clear_config([:instance, :moderator_privileges], [:report_handle]) + clear_config([:instance, :moderator_privileges], [:reports_manage_reports]) {:ok, activity2} = CommonAPI.report(reporting_user, %{account_id: reported_user.id}) {:ok, [notification]} = Notification.create_notifications(activity2) @@ -50,7 +50,7 @@ test "creates a report notification only for privileged users" do end test "suppresses notifications for own reports" do - clear_config([:instance, :admin_privileges], [:report_handle]) + clear_config([:instance, :admin_privileges], [:reports_manage_reports]) reporting_admin = insert(:user, is_admin: true) reported_user = insert(:user) diff --git a/test/pleroma/user_test.exs b/test/pleroma/user_test.exs index 477553fe5..98e00cecb 100644 --- a/test/pleroma/user_test.exs +++ b/test/pleroma/user_test.exs @@ -1995,9 +1995,9 @@ test "returns true when the account is unconfirmed and confirmation is required assert User.visible_for(user, other_user) == :visible end - test "returns true when the account is unconfirmed and being viewed by a privileged account (privilege :user_activation, confirmation required)" do + test "returns true when the account is unconfirmed and being viewed by a privileged account (privilege :users_manage_activation_state, confirmation required)" do clear_config([:instance, :account_activation_required], true) - clear_config([:instance, :admin_privileges], [:user_activation]) + clear_config([:instance, :admin_privileges], [:users_manage_activation_state]) user = insert(:user, local: true, is_confirmed: false) other_user = insert(:user, local: true, is_admin: true) diff --git a/test/pleroma/web/activity_pub/object_validators/delete_validation_test.exs b/test/pleroma/web/activity_pub/object_validators/delete_validation_test.exs index ba137604b..bbb31516c 100644 --- a/test/pleroma/web/activity_pub/object_validators/delete_validation_test.exs +++ b/test/pleroma/web/activity_pub/object_validators/delete_validation_test.exs @@ -92,7 +92,7 @@ test "it's invalid if the actor of the object and the actor of delete are from d test "it's only valid if the actor of the object is a privileged local user", %{valid_post_delete: valid_post_delete} do - clear_config([:instance, :moderator_privileges], [:status_delete]) + clear_config([:instance, :moderator_privileges], [:messages_delete]) user = insert(:user, local: true, is_moderator: true, ap_id: "https://gensokyo.2hu/users/raymoo") diff --git a/test/pleroma/web/admin_api/controllers/admin_api_controller_test.exs b/test/pleroma/web/admin_api/controllers/admin_api_controller_test.exs index 180f6c83f..34ec28012 100644 --- a/test/pleroma/web/admin_api/controllers/admin_api_controller_test.exs +++ b/test/pleroma/web/admin_api/controllers/admin_api_controller_test.exs @@ -92,7 +92,7 @@ test "GET /api/pleroma/admin/users/:nickname requires admin:read:accounts or bro describe "PUT /api/pleroma/admin/users/tag" do setup %{conn: conn} do - clear_config([:instance, :admin_privileges], [:user_tag]) + clear_config([:instance, :admin_privileges], [:users_manage_tags]) user1 = insert(:user, %{tags: ["x"]}) user2 = insert(:user, %{tags: ["y"]}) @@ -150,7 +150,7 @@ test "it does not modify tags of not specified users", %{ assert User.get_cached_by_id(user3.id).tags == ["unchanged"] end - test "it requires privileged role :user_tag", %{conn: conn} do + test "it requires privileged role :users_manage_tags", %{conn: conn} do clear_config([:instance, :admin_privileges], []) response = @@ -164,7 +164,7 @@ test "it requires privileged role :user_tag", %{conn: conn} do describe "DELETE /api/pleroma/admin/users/tag" do setup %{conn: conn} do - clear_config([:instance, :admin_privileges], [:user_tag]) + clear_config([:instance, :admin_privileges], [:users_manage_tags]) user1 = insert(:user, %{tags: ["x"]}) user2 = insert(:user, %{tags: ["y", "z"]}) user3 = insert(:user, %{tags: ["unchanged"]}) @@ -221,7 +221,7 @@ test "it does not modify tags of not specified users", %{ assert User.get_cached_by_id(user3.id).tags == ["unchanged"] end - test "it requires privileged role :user_tag", %{conn: conn} do + test "it requires privileged role :users_manage_tags", %{conn: conn} do clear_config([:instance, :admin_privileges], []) response = @@ -324,7 +324,7 @@ test "/:right DELETE, can remove from a permission group (multiple)", %{ describe "/api/pleroma/admin/users/:nickname/password_reset" do test "it returns a password reset link", %{conn: conn} do - clear_config([:instance, :admin_privileges], [:user_credentials]) + clear_config([:instance, :admin_privileges], [:users_manage_credentials]) user = insert(:user) @@ -338,7 +338,7 @@ test "it returns a password reset link", %{conn: conn} do assert Regex.match?(~r/(http:\/\/|https:\/\/)/, resp["link"]) end - test "it requires privileged role :user_credentials", %{conn: conn} do + test "it requires privileged role :users_manage_credentials", %{conn: conn} do clear_config([:instance, :admin_privileges], []) response = @@ -410,7 +410,7 @@ test "need_reboot flag", %{conn: conn} do describe "GET /api/pleroma/admin/users/:nickname/statuses" do setup do - clear_config([:instance, :admin_privileges], [:statuses_read]) + clear_config([:instance, :admin_privileges], [:messages_read]) user = insert(:user) @@ -428,7 +428,7 @@ test "renders user's statuses", %{conn: conn, user: user} do assert length(activities) == 3 end - test "it requires privileged role :statuses_read", %{conn: conn, user: user} do + test "it requires privileged role :messages_read", %{conn: conn, user: user} do clear_config([:instance, :admin_privileges], []) conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}/statuses") @@ -497,7 +497,7 @@ test "excludes reblogs by default", %{conn: conn, user: user} do describe "GET /api/pleroma/admin/users/:nickname/chats" do setup do - clear_config([:instance, :admin_privileges], [:statuses_read]) + clear_config([:instance, :admin_privileges], [:messages_read]) user = insert(:user) @@ -516,7 +516,7 @@ test "renders user's chats", %{conn: conn, user: user} do assert json_response(conn, 200) |> length() == 3 end - test "it requires privileged role :statuses_read", %{conn: conn, user: user} do + test "it requires privileged role :messages_read", %{conn: conn, user: user} do clear_config([:instance, :admin_privileges], []) conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}/chats") @@ -811,7 +811,7 @@ test "returns 403 if requested by a non-admin" do end test "changes password and email", %{conn: conn, admin: admin, user: user} do - clear_config([:instance, :admin_privileges], [:user_credentials]) + clear_config([:instance, :admin_privileges], [:users_manage_credentials]) assert user.password_reset_pending == false @@ -855,7 +855,7 @@ test "returns 403 if requested by a non-admin", %{user: user} do assert json_response(conn, :forbidden) end - test "returns 403 if not privileged with :user_credentials", %{conn: conn, user: user} do + test "returns 403 if not privileged with :users_manage_credentials", %{conn: conn, user: user} do clear_config([:instance, :admin_privileges], []) conn = @@ -1085,7 +1085,7 @@ test "it doesn't limit admins", %{conn: conn} do describe "POST /api/v1/pleroma/admin/reload_emoji" do setup do - clear_config([:instance, :admin_privileges], [:emoji_management]) + clear_config([:instance, :admin_privileges], [:emoji_manage_emoji]) admin = insert(:user, is_admin: true) token = insert(:oauth_admin_token, user: admin) @@ -1098,7 +1098,7 @@ test "it doesn't limit admins", %{conn: conn} do {:ok, %{conn: conn, admin: admin}} end - test "it requires privileged role :emoji_management", %{conn: conn} do + test "it requires privileged role :emoji_manage_emoji", %{conn: conn} do assert conn |> post("/api/v1/pleroma/admin/reload_emoji") |> json_response(200) diff --git a/test/pleroma/web/admin_api/controllers/chat_controller_test.exs b/test/pleroma/web/admin_api/controllers/chat_controller_test.exs index e080cd225..aa47b74e8 100644 --- a/test/pleroma/web/admin_api/controllers/chat_controller_test.exs +++ b/test/pleroma/web/admin_api/controllers/chat_controller_test.exs @@ -28,7 +28,7 @@ defp admin_setup do describe "DELETE /api/pleroma/admin/chats/:id/messages/:message_id" do setup do - clear_config([:instance, :admin_privileges], [:status_delete]) + clear_config([:instance, :admin_privileges], [:messages_delete]) admin_setup() end @@ -64,7 +64,7 @@ test "it deletes a message from the chat", %{conn: conn, admin: admin} do assert %{data: %{"type" => "Tombstone"}} = Object.get_by_id(object.id) end - test "it requires privileged role :status_delete", %{conn: conn} do + test "it requires privileged role :messages_delete", %{conn: conn} do clear_config([:instance, :admin_privileges], []) assert conn @@ -76,7 +76,7 @@ test "it requires privileged role :status_delete", %{conn: conn} do describe "GET /api/pleroma/admin/chats/:id/messages" do setup do - clear_config([:instance, :admin_privileges], [:statuses_read]) + clear_config([:instance, :admin_privileges], [:messages_read]) admin_setup() end @@ -130,7 +130,7 @@ test "it returns the messages for a given chat", %{conn: conn} do assert length(result) == 3 end - test "it requires privileged role :statuses_read", %{conn: conn} do + test "it requires privileged role :messages_read", %{conn: conn} do clear_config([:instance, :admin_privileges], []) conn = get(conn, "/api/pleroma/admin/chats/some_id/messages") @@ -141,7 +141,7 @@ test "it requires privileged role :statuses_read", %{conn: conn} do describe "GET /api/pleroma/admin/chats/:id" do setup do - clear_config([:instance, :admin_privileges], [:statuses_read]) + clear_config([:instance, :admin_privileges], [:messages_read]) admin_setup() end @@ -162,7 +162,7 @@ test "it returns a chat", %{conn: conn} do refute result["account"] end - test "it requires privileged role :statuses_read", %{conn: conn} do + test "it requires privileged role :messages_read", %{conn: conn} do clear_config([:instance, :admin_privileges], []) conn = get(conn, "/api/pleroma/admin/chats/some_id") diff --git a/test/pleroma/web/admin_api/controllers/instance_controller_test.exs b/test/pleroma/web/admin_api/controllers/instance_controller_test.exs index e75222f99..47af8e7d9 100644 --- a/test/pleroma/web/admin_api/controllers/instance_controller_test.exs +++ b/test/pleroma/web/admin_api/controllers/instance_controller_test.exs @@ -31,7 +31,7 @@ defmodule Pleroma.Web.AdminAPI.InstanceControllerTest do end test "GET /instances/:instance/statuses", %{conn: conn} do - clear_config([:instance, :admin_privileges], [:statuses_read]) + clear_config([:instance, :admin_privileges], [:messages_read]) user = insert(:user, local: false, ap_id: "https://archae.me/users/archaeme") user2 = insert(:user, local: false, ap_id: "https://test.com/users/test") insert_pair(:note_activity, user: user) diff --git a/test/pleroma/web/admin_api/controllers/invite_controller_test.exs b/test/pleroma/web/admin_api/controllers/invite_controller_test.exs index b8c812acc..8051cb2e9 100644 --- a/test/pleroma/web/admin_api/controllers/invite_controller_test.exs +++ b/test/pleroma/web/admin_api/controllers/invite_controller_test.exs @@ -26,10 +26,10 @@ defmodule Pleroma.Web.AdminAPI.InviteControllerTest do setup do clear_config([:instance, :registrations_open], false) clear_config([:instance, :invites_enabled], true) - clear_config([:instance, :admin_privileges], [:user_invite]) + clear_config([:instance, :admin_privileges], [:users_manage_invites]) end - test "returns 403 if not privileged with :user_invite", %{conn: conn} do + test "returns 403 if not privileged with :users_manage_invites", %{conn: conn} do clear_config([:instance, :admin_privileges], []) conn = @@ -134,7 +134,7 @@ test "email with +", %{conn: conn, admin: admin} do setup do clear_config([:instance, :registrations_open]) clear_config([:instance, :invites_enabled]) - clear_config([:instance, :admin_privileges], [:user_invite]) + clear_config([:instance, :admin_privileges], [:users_manage_invites]) end test "it returns 500 if `invites_enabled` is not enabled", %{conn: conn} do @@ -178,10 +178,10 @@ test "it returns 500 if `registrations_open` is enabled", %{conn: conn} do describe "POST /api/pleroma/admin/users/invite_token" do setup do - clear_config([:instance, :admin_privileges], [:user_invite]) + clear_config([:instance, :admin_privileges], [:users_manage_invites]) end - test "returns 403 if not privileged with :user_invite", %{conn: conn} do + test "returns 403 if not privileged with :users_manage_invites", %{conn: conn} do clear_config([:instance, :admin_privileges], []) conn = @@ -257,10 +257,10 @@ test "with max use and expires_at", %{conn: conn} do describe "GET /api/pleroma/admin/users/invites" do setup do - clear_config([:instance, :admin_privileges], [:user_invite]) + clear_config([:instance, :admin_privileges], [:users_manage_invites]) end - test "returns 403 if not privileged with :user_invite", %{conn: conn} do + test "returns 403 if not privileged with :users_manage_invites", %{conn: conn} do clear_config([:instance, :admin_privileges], []) conn = get(conn, "/api/pleroma/admin/users/invites") @@ -297,10 +297,10 @@ test "with invite", %{conn: conn} do describe "POST /api/pleroma/admin/users/revoke_invite" do setup do - clear_config([:instance, :admin_privileges], [:user_invite]) + clear_config([:instance, :admin_privileges], [:users_manage_invites]) end - test "returns 403 if not privileged with :user_invite", %{conn: conn} do + test "returns 403 if not privileged with :users_manage_invites", %{conn: conn} do clear_config([:instance, :admin_privileges], []) conn = diff --git a/test/pleroma/web/admin_api/controllers/report_controller_test.exs b/test/pleroma/web/admin_api/controllers/report_controller_test.exs index 42b5000fc..b155cf01a 100644 --- a/test/pleroma/web/admin_api/controllers/report_controller_test.exs +++ b/test/pleroma/web/admin_api/controllers/report_controller_test.exs @@ -27,10 +27,10 @@ defmodule Pleroma.Web.AdminAPI.ReportControllerTest do describe "GET /api/pleroma/admin/reports/:id" do setup do - clear_config([:instance, :admin_privileges], [:report_handle]) + clear_config([:instance, :admin_privileges], [:reports_manage_reports]) end - test "returns 403 if not privileged with :report_handle", %{conn: conn} do + test "returns 403 if not privileged with :reports_manage_reports", %{conn: conn} do clear_config([:instance, :admin_privileges], []) conn = @@ -77,7 +77,7 @@ test "returns 404 when report id is invalid", %{conn: conn} do describe "PATCH /api/pleroma/admin/reports" do setup do - clear_config([:instance, :admin_privileges], [:report_handle]) + clear_config([:instance, :admin_privileges], [:reports_manage_reports]) [reporter, target_user] = insert_pair(:user) activity = insert(:note_activity, user: target_user) @@ -102,7 +102,11 @@ test "returns 404 when report id is invalid", %{conn: conn} do } end - test "returns 403 if not privileged with :report_handle", %{conn: conn, id: id, admin: admin} do + test "returns 403 if not privileged with :reports_manage_reports", %{ + conn: conn, + id: id, + admin: admin + } do clear_config([:instance, :admin_privileges], []) conn = @@ -240,10 +244,10 @@ test "updates state of multiple reports", %{ describe "GET /api/pleroma/admin/reports" do setup do - clear_config([:instance, :admin_privileges], [:report_handle]) + clear_config([:instance, :admin_privileges], [:reports_manage_reports]) end - test "returns 403 if not privileged with :report_handle", %{conn: conn} do + test "returns 403 if not privileged with :reports_manage_reports", %{conn: conn} do clear_config([:instance, :admin_privileges], []) conn = @@ -361,7 +365,7 @@ test "returns 403 when requested by anonymous" do describe "POST /api/pleroma/admin/reports/:id/notes" do setup %{conn: conn, admin: admin} do - clear_config([:instance, :admin_privileges], [:report_handle]) + clear_config([:instance, :admin_privileges], [:reports_manage_reports]) [reporter, target_user] = insert_pair(:user) activity = insert(:note_activity, user: target_user) @@ -391,7 +395,10 @@ test "returns 403 when requested by anonymous" do } end - test "returns 403 if not privileged with :report_handle", %{conn: conn, report_id: report_id} do + test "returns 403 if not privileged with :reports_manage_reports", %{ + conn: conn, + report_id: report_id + } do clear_config([:instance, :admin_privileges], []) post_conn = diff --git a/test/pleroma/web/admin_api/controllers/status_controller_test.exs b/test/pleroma/web/admin_api/controllers/status_controller_test.exs index 2daf6a50d..8908a2812 100644 --- a/test/pleroma/web/admin_api/controllers/status_controller_test.exs +++ b/test/pleroma/web/admin_api/controllers/status_controller_test.exs @@ -27,7 +27,7 @@ defmodule Pleroma.Web.AdminAPI.StatusControllerTest do describe "GET /api/pleroma/admin/statuses/:id" do setup do - clear_config([:instance, :admin_privileges], [:statuses_read]) + clear_config([:instance, :admin_privileges], [:messages_read]) end test "not found", %{conn: conn} do @@ -64,7 +64,7 @@ test "denies reading activity when not privileged", %{conn: conn} do describe "PUT /api/pleroma/admin/statuses/:id" do setup do - clear_config([:instance, :admin_privileges], [:status_delete]) + clear_config([:instance, :admin_privileges], [:messages_delete]) activity = insert(:note_activity) %{id: activity.id} @@ -134,7 +134,7 @@ test "returns 400 when visibility is unknown", %{conn: conn, id: id} do json_response_and_validate_schema(conn, :bad_request) end - test "it requires privileged role :status_delete", %{conn: conn} do + test "it requires privileged role :messages_delete", %{conn: conn} do clear_config([:instance, :admin_privileges], []) assert conn @@ -146,7 +146,7 @@ test "it requires privileged role :status_delete", %{conn: conn} do describe "DELETE /api/pleroma/admin/statuses/:id" do setup do - clear_config([:instance, :admin_privileges], [:status_delete]) + clear_config([:instance, :admin_privileges], [:messages_delete]) activity = insert(:note_activity) %{id: activity.id} @@ -171,7 +171,7 @@ test "returns 404 when the status does not exist", %{conn: conn} do assert json_response_and_validate_schema(conn, :not_found) == %{"error" => "Not found"} end - test "it requires privileged role :status_delete", %{conn: conn} do + test "it requires privileged role :messages_delete", %{conn: conn} do clear_config([:instance, :admin_privileges], []) assert conn @@ -183,7 +183,7 @@ test "it requires privileged role :status_delete", %{conn: conn} do describe "GET /api/pleroma/admin/statuses" do setup do - clear_config([:instance, :admin_privileges], [:statuses_read]) + clear_config([:instance, :admin_privileges], [:messages_read]) end test "returns all public and unlisted statuses", %{conn: conn, admin: admin} do @@ -232,7 +232,7 @@ test "returns private and direct statuses with godmode on", %{conn: conn, admin: assert json_response_and_validate_schema(conn, 200) |> length() == 3 end - test "it requires privileged role :statuses_read", %{conn: conn} do + test "it requires privileged role :messages_read", %{conn: conn} do clear_config([:instance, :admin_privileges], []) conn = get(conn, "/api/pleroma/admin/statuses") diff --git a/test/pleroma/web/admin_api/controllers/user_controller_test.exs b/test/pleroma/web/admin_api/controllers/user_controller_test.exs index 01bee08d1..bb9dcb4aa 100644 --- a/test/pleroma/web/admin_api/controllers/user_controller_test.exs +++ b/test/pleroma/web/admin_api/controllers/user_controller_test.exs @@ -38,7 +38,7 @@ defmodule Pleroma.Web.AdminAPI.UserControllerTest do end test "with valid `admin_token` query parameter, skips OAuth scopes check" do - clear_config([:instance, :admin_privileges], [:user_read]) + clear_config([:instance, :admin_privileges], [:users_read]) clear_config([:admin_token], "password123") user = insert(:user) @@ -51,7 +51,7 @@ test "with valid `admin_token` query parameter, skips OAuth scopes check" do describe "DELETE /api/pleroma/admin/users" do test "single user", %{admin: admin, conn: conn} do clear_config([:instance, :federating], true) - clear_config([:instance, :admin_privileges], [:user_deletion]) + clear_config([:instance, :admin_privileges], [:users_delete]) user = insert(:user, @@ -107,7 +107,7 @@ test "single user", %{admin: admin, conn: conn} do end test "multiple users", %{admin: admin, conn: conn} do - clear_config([:instance, :admin_privileges], [:user_deletion]) + clear_config([:instance, :admin_privileges], [:users_delete]) user_one = insert(:user) user_two = insert(:user) @@ -280,10 +280,10 @@ test "Multiple user creation works in transaction", %{conn: conn} do describe "GET /api/pleroma/admin/users/:nickname" do setup do - clear_config([:instance, :admin_privileges], [:user_read]) + clear_config([:instance, :admin_privileges], [:users_read]) end - test "returns 403 if not privileged with :user_read", %{conn: conn} do + test "returns 403 if not privileged with :users_read", %{conn: conn} do clear_config([:instance, :admin_privileges], []) conn = get(conn, "/api/pleroma/admin/users/user.nickname") @@ -406,10 +406,10 @@ test "allows to force-unfollow another user", %{admin: admin, conn: conn} do describe "GET /api/pleroma/admin/users" do setup do - clear_config([:instance, :admin_privileges], [:user_read]) + clear_config([:instance, :admin_privileges], [:users_read]) end - test "returns 403 if not privileged with :user_read", %{conn: conn} do + test "returns 403 if not privileged with :users_read", %{conn: conn} do clear_config([:instance, :admin_privileges], []) conn = get(conn, "/api/pleroma/admin/users?page=1") @@ -850,7 +850,7 @@ test "it omits relay user", %{admin: admin, conn: conn} do end test "PATCH /api/pleroma/admin/users/approve", %{admin: admin, conn: conn} do - clear_config([:instance, :admin_privileges], [:user_invite]) + clear_config([:instance, :admin_privileges], [:users_manage_invites]) user_one = insert(:user, is_approved: false) user_two = insert(:user, is_approved: false) @@ -872,7 +872,7 @@ test "PATCH /api/pleroma/admin/users/approve", %{admin: admin, conn: conn} do "@#{admin.nickname} approved users: @#{user_one.nickname}, @#{user_two.nickname}" end - test "PATCH /api/pleroma/admin/users/approve returns 403 if not privileged with :user_invite", + test "PATCH /api/pleroma/admin/users/approve returns 403 if not privileged with :users_manage_invites", %{conn: conn} do clear_config([:instance, :admin_privileges], []) @@ -939,7 +939,7 @@ test "PATCH /api/pleroma/admin/users/unsuggest", %{admin: admin, conn: conn} do describe "user activation" do test "PATCH /api/pleroma/admin/users/activate", %{admin: admin, conn: conn} do - clear_config([:instance, :admin_privileges], [:user_activation]) + clear_config([:instance, :admin_privileges], [:users_manage_activation_state]) user_one = insert(:user, is_active: false) user_two = insert(:user, is_active: false) @@ -962,7 +962,7 @@ test "PATCH /api/pleroma/admin/users/activate", %{admin: admin, conn: conn} do end test "PATCH /api/pleroma/admin/users/deactivate", %{admin: admin, conn: conn} do - clear_config([:instance, :admin_privileges], [:user_activation]) + clear_config([:instance, :admin_privileges], [:users_manage_activation_state]) user_one = insert(:user, is_active: true) user_two = insert(:user, is_active: true) @@ -985,7 +985,7 @@ test "PATCH /api/pleroma/admin/users/deactivate", %{admin: admin, conn: conn} do end test "PATCH /api/pleroma/admin/users/:nickname/toggle_activation", %{admin: admin, conn: conn} do - clear_config([:instance, :admin_privileges], [:user_activation]) + clear_config([:instance, :admin_privileges], [:users_manage_activation_state]) user = insert(:user) diff --git a/test/pleroma/web/common_api_test.exs b/test/pleroma/web/common_api_test.exs index 4d960e945..25743daae 100644 --- a/test/pleroma/web/common_api_test.exs +++ b/test/pleroma/web/common_api_test.exs @@ -332,7 +332,7 @@ test "it does not allow a user to delete posts from another user" do end test "it allows privileged users to delete other user's posts" do - clear_config([:instance, :moderator_privileges], [:status_delete]) + clear_config([:instance, :moderator_privileges], [:messages_delete]) user = insert(:user) moderator = insert(:user, is_moderator: true) @@ -357,7 +357,7 @@ test "it doesn't allow unprivileged mods or admins to delete other user's posts" end test "privileged users deleting non-local posts won't federate the delete" do - clear_config([:instance, :admin_privileges], [:status_delete]) + clear_config([:instance, :admin_privileges], [:messages_delete]) # This is the user of the ingested activity _user = insert(:user, diff --git a/test/pleroma/web/mastodon_api/controllers/notification_controller_test.exs b/test/pleroma/web/mastodon_api/controllers/notification_controller_test.exs index e0f1d2ac1..696ac8bd9 100644 --- a/test/pleroma/web/mastodon_api/controllers/notification_controller_test.exs +++ b/test/pleroma/web/mastodon_api/controllers/notification_controller_test.exs @@ -74,7 +74,7 @@ test "by default, does not contain pleroma:chat_mention" do end test "by default, does not contain pleroma:report" do - clear_config([:instance, :moderator_privileges], [:report_handle]) + clear_config([:instance, :moderator_privileges], [:reports_manage_reports]) user = insert(:user) other_user = insert(:user) @@ -105,7 +105,7 @@ test "by default, does not contain pleroma:report" do end test "Pleroma:report is hidden for non-privileged users" do - clear_config([:instance, :moderator_privileges], [:report_handle]) + clear_config([:instance, :moderator_privileges], [:reports_manage_reports]) user = insert(:user) other_user = insert(:user) diff --git a/test/pleroma/web/mastodon_api/controllers/status_controller_test.exs b/test/pleroma/web/mastodon_api/controllers/status_controller_test.exs index 4ea92e329..1d2bb3333 100644 --- a/test/pleroma/web/mastodon_api/controllers/status_controller_test.exs +++ b/test/pleroma/web/mastodon_api/controllers/status_controller_test.exs @@ -969,7 +969,7 @@ test "when you didn't create it" do end test "when you're privileged to", %{conn: conn} do - clear_config([:instance, :moderator_privileges], [:status_delete]) + clear_config([:instance, :moderator_privileges], [:messages_delete]) activity = insert(:note_activity) moderator = insert(:user, is_moderator: true) diff --git a/test/pleroma/web/mastodon_api/views/account_view_test.exs b/test/pleroma/web/mastodon_api/views/account_view_test.exs index ce94ec7e4..675c8409a 100644 --- a/test/pleroma/web/mastodon_api/views/account_view_test.exs +++ b/test/pleroma/web/mastodon_api/views/account_view_test.exs @@ -358,7 +358,7 @@ test "Represent a Funkwhale channel" do end test "Represent a deactivated user for a privileged user" do - clear_config([:instance, :moderator_privileges], [:user_activation]) + clear_config([:instance, :moderator_privileges], [:users_manage_activation_state]) admin = insert(:user, is_moderator: true) deactivated_user = insert(:user, is_active: false) diff --git a/test/pleroma/web/mastodon_api/views/notification_view_test.exs b/test/pleroma/web/mastodon_api/views/notification_view_test.exs index 76338877e..594378be1 100644 --- a/test/pleroma/web/mastodon_api/views/notification_view_test.exs +++ b/test/pleroma/web/mastodon_api/views/notification_view_test.exs @@ -218,7 +218,7 @@ test "Poll notification" do end test "Report notification" do - clear_config([:instance, :moderator_privileges], [:report_handle]) + clear_config([:instance, :moderator_privileges], [:reports_manage_reports]) reporting_user = insert(:user) reported_user = insert(:user) diff --git a/test/pleroma/web/pleroma_api/controllers/emoji_file_controller_test.exs b/test/pleroma/web/pleroma_api/controllers/emoji_file_controller_test.exs index e46a363a4..540b452c7 100644 --- a/test/pleroma/web/pleroma_api/controllers/emoji_file_controller_test.exs +++ b/test/pleroma/web/pleroma_api/controllers/emoji_file_controller_test.exs @@ -30,7 +30,7 @@ defmodule Pleroma.Web.PleromaAPI.EmojiFileControllerTest do describe "POST/PATCH/DELETE /api/pleroma/emoji/packs/files?name=:name" do setup do - clear_config([:instance, :admin_privileges], [:emoji_management]) + clear_config([:instance, :admin_privileges], [:emoji_manage_emoji]) pack_file = "#{@emoji_path}/test_pack/pack.json" original_content = File.read!(pack_file) @@ -379,7 +379,7 @@ test "update with empty shortcode", %{admin_conn: admin_conn} do |> json_response_and_validate_schema(:bad_request) end - test "it requires privileged role :emoji_management", %{admin_conn: admin_conn} do + test "it requires privileged role :emoji_manage_emoji", %{admin_conn: admin_conn} do clear_config([:instance, :admin_privileges], []) assert admin_conn diff --git a/test/pleroma/web/pleroma_api/controllers/emoji_pack_controller_test.exs b/test/pleroma/web/pleroma_api/controllers/emoji_pack_controller_test.exs index 6558767d2..1d5240639 100644 --- a/test/pleroma/web/pleroma_api/controllers/emoji_pack_controller_test.exs +++ b/test/pleroma/web/pleroma_api/controllers/emoji_pack_controller_test.exs @@ -100,7 +100,7 @@ test "GET /api/pleroma/emoji/packs", %{conn: conn} do describe "GET /api/pleroma/emoji/packs/remote" do setup do - clear_config([:instance, :admin_privileges], [:emoji_management]) + clear_config([:instance, :admin_privileges], [:emoji_manage_emoji]) end test "shareable instance", %{admin_conn: admin_conn, conn: conn} do @@ -141,7 +141,7 @@ test "non shareable instance", %{admin_conn: admin_conn} do } end - test "it requires privileged role :emoji_management", %{admin_conn: admin_conn} do + test "it requires privileged role :emoji_manage_emoji", %{admin_conn: admin_conn} do clear_config([:instance, :admin_privileges], []) assert admin_conn @@ -183,7 +183,7 @@ test "non downloadable pack", %{conn: conn} do describe "POST /api/pleroma/emoji/packs/download" do setup do - clear_config([:instance, :admin_privileges], [:emoji_management]) + clear_config([:instance, :admin_privileges], [:emoji_manage_emoji]) end test "shared pack from remote and non shared from fallback-src", %{ @@ -361,7 +361,7 @@ test "other error", %{admin_conn: admin_conn} do } end - test "it requires privileged role :emoji_management", %{admin_conn: conn} do + test "it requires privileged role :emoji_manage_emoji", %{admin_conn: conn} do clear_config([:instance, :admin_privileges], []) assert conn @@ -377,7 +377,7 @@ test "it requires privileged role :emoji_management", %{admin_conn: conn} do describe "PATCH/update /api/pleroma/emoji/pack?name=:name" do setup do - clear_config([:instance, :admin_privileges], [:emoji_management]) + clear_config([:instance, :admin_privileges], [:emoji_manage_emoji]) pack_file = "#{@emoji_path}/test_pack/pack.json" original_content = File.read!(pack_file) @@ -466,7 +466,10 @@ test "when the fallback source doesn't have all the files", ctx do } end - test "it requires privileged role :emoji_management", %{admin_conn: conn, new_data: new_data} do + test "it requires privileged role :emoji_manage_emoji", %{ + admin_conn: conn, + new_data: new_data + } do clear_config([:instance, :admin_privileges], []) assert conn @@ -478,7 +481,7 @@ test "it requires privileged role :emoji_management", %{admin_conn: conn, new_da describe "POST/DELETE /api/pleroma/emoji/pack?name=:name" do setup do - clear_config([:instance, :admin_privileges], [:emoji_management]) + clear_config([:instance, :admin_privileges], [:emoji_manage_emoji]) end test "returns an error on creates pack when file system not writable", %{ @@ -564,7 +567,7 @@ test "with empty name", %{admin_conn: admin_conn} do } end - test "it requires privileged role :emoji_management", %{admin_conn: admin_conn} do + test "it requires privileged role :emoji_manage_emoji", %{admin_conn: admin_conn} do clear_config([:instance, :admin_privileges], []) assert admin_conn From 0d697bc15a535eed17f017b9a18d60b2e4cef34e Mon Sep 17 00:00:00 2001 From: Ilja Date: Fri, 1 Jul 2022 10:50:32 +0200 Subject: [PATCH 30/54] Add docs and CHANGELOG entries --- CHANGELOG.md | 1 + docs/configuration/cheatsheet.md | 14 ++++++++++++++ 2 files changed, 15 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8a18c151c..35a31d70d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -28,6 +28,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - Configuration: Add `birthday_required` and `birthday_min_age` settings to provide a way to require users to enter their birth date. - PleromaAPI: Add `GET /api/v1/pleroma/birthdays` API endpoint - Make backend-rendered pages translatable. This includes emails. Pages returned as a HTTP response are translated using the language specified in the `userLanguage` cookie, or the `Accept-Language` header. Emails are translated using the `language` field when registering. This language can be changed by `PATCH /api/v1/accounts/update_credentials` with the `language` field. +- Add fine grained options to provide privileges to moderators and admins (e.g. delete messages, manage reports...) ### Fixed - Subscription(Bell) Notifications: Don't create from Pipeline Ingested replies diff --git a/docs/configuration/cheatsheet.md b/docs/configuration/cheatsheet.md index 1e74d40e6..c59c914f2 100644 --- a/docs/configuration/cheatsheet.md +++ b/docs/configuration/cheatsheet.md @@ -64,6 +64,20 @@ To add configuration to your config file, you can copy it from the base config. * `cleanup_attachments`: Remove attachments along with statuses. Does not affect duplicate files and attachments without status. Enabling this will increase load to database when deleting statuses on larger instances. * `show_reactions`: Let favourites and emoji reactions be viewed through the API (default: `true`). * `password_reset_token_validity`: The time after which reset tokens aren't accepted anymore, in seconds (default: one day). +* `admin_privileges`: A list of privileges an admin has (e.g. delete messages, manage reports...) + * Possible values are: + * `:users_delete` + * `:users_manage_credentials` + * `:messages_read` + * `:users_manage_tags` + * `:users_manage_activation_state` + * `:users_manage_invites` + * `:reports_manage_reports` + * `:users_read` + * `:messages_delete` + * `:emoji_manage_emoji` +* `moderator_privileges`: A list of privileges a moderator has (e.g. delete messages, manage reports...) + * Possible values are the same as for `admin_privileges` ## :database * `improved_hashtag_timeline`: Setting to force toggle / force disable improved hashtags timeline. `:enabled` forces hashtags to be fetched from `hashtags` table for hashtags timeline. `:disabled` forces object-embedded hashtags to be used (slower). Keep it `:auto` for automatic behaviour (it is auto-set to `:enabled` [unless overridden] when HashtagsTableMigrator completes). From c0e4b1b3e27a4a8f8f02ea6a33b76c6f2a386d95 Mon Sep 17 00:00:00 2001 From: Ilja Date: Sat, 2 Jul 2022 07:52:39 +0200 Subject: [PATCH 31/54] Fix typo's priviledge |-> privilege --- config/description.exs | 4 ++-- docs/installation/migrating_from_source_otp_en.md | 2 +- docs/installation/otp_en.md | 2 +- lib/pleroma/web/plugs/ensure_privileged_plug.ex | 6 +++--- test/pleroma/web/plugs/ensure_privileged_plug_test.exs | 6 +++--- 5 files changed, 10 insertions(+), 10 deletions(-) diff --git a/config/description.exs b/config/description.exs index e5a49139e..e2ff91fb3 100644 --- a/config/description.exs +++ b/config/description.exs @@ -976,7 +976,7 @@ :emoji_manage_emoji ], description: - "What extra priviledges to allow admins (e.g. updating user credentials, get password reset token, delete users, index and read private statuses and chats)" + "What extra privileges to allow admins (e.g. updating user credentials, get password reset token, delete users, index and read private statuses and chats)" }, %{ key: :moderator_privileges, @@ -994,7 +994,7 @@ :emoji_manage_emoji ], description: - "What extra priviledges to allow moderators (e.g. updating user credentials, get password reset token, delete users, index and read private statuses and chats)" + "What extra privileges to allow moderators (e.g. updating user credentials, get password reset token, delete users, index and read private statuses and chats)" }, %{ key: :birthday_required, diff --git a/docs/installation/migrating_from_source_otp_en.md b/docs/installation/migrating_from_source_otp_en.md index e4a01d8db..f6f23400a 100644 --- a/docs/installation/migrating_from_source_otp_en.md +++ b/docs/installation/migrating_from_source_otp_en.md @@ -5,7 +5,7 @@ In this guide we cover how you can migrate from a from source installation to one using OTP releases. ## Pre-requisites -You will be running commands as root. If you aren't root already, please elevate your priviledges by executing `sudo su`/`su`. +You will be running commands as root. If you aren't root already, please elevate your privileges by executing `sudo su`/`su`. The system needs to have `curl` and `unzip` installed for downloading and unpacking release builds. diff --git a/docs/installation/otp_en.md b/docs/installation/otp_en.md index 0861a8157..8c02201e6 100644 --- a/docs/installation/otp_en.md +++ b/docs/installation/otp_en.md @@ -8,7 +8,7 @@ This guide covers a installation using an OTP release. To install Pleroma from s * A machine running Linux with GNU (e.g. Debian, Ubuntu) or musl (e.g. Alpine) libc and `x86_64`, `aarch64` or `armv7l` CPU, you have root access to. If you are not sure if it's compatible see [Detecting flavour section](#detecting-flavour) below * A (sub)domain pointed to the machine -You will be running commands as root. If you aren't root already, please elevate your priviledges by executing `sudo su`/`su`. +You will be running commands as root. If you aren't root already, please elevate your privileges by executing `sudo su`/`su`. While in theory OTP releases are possbile to install on any compatible machine, for the sake of simplicity this guide focuses only on Debian/Ubuntu and Alpine. diff --git a/lib/pleroma/web/plugs/ensure_privileged_plug.ex b/lib/pleroma/web/plugs/ensure_privileged_plug.ex index be09f3d81..f886c87ea 100644 --- a/lib/pleroma/web/plugs/ensure_privileged_plug.ex +++ b/lib/pleroma/web/plugs/ensure_privileged_plug.ex @@ -24,10 +24,10 @@ def call(%{assigns: %{user: %User{is_admin: false, is_moderator: false}}} = conn def call( %{assigns: %{user: %User{is_admin: is_admin, is_moderator: is_moderator}}} = conn, - priviledge + privilege ) do - if (is_admin and priviledge in Config.get([:instance, :admin_privileges])) or - (is_moderator and priviledge in Config.get([:instance, :moderator_privileges])) do + if (is_admin and privilege in Config.get([:instance, :admin_privileges])) or + (is_moderator and privilege in Config.get([:instance, :moderator_privileges])) do conn else conn diff --git a/test/pleroma/web/plugs/ensure_privileged_plug_test.exs b/test/pleroma/web/plugs/ensure_privileged_plug_test.exs index 423413946..4b6679b66 100644 --- a/test/pleroma/web/plugs/ensure_privileged_plug_test.exs +++ b/test/pleroma/web/plugs/ensure_privileged_plug_test.exs @@ -64,7 +64,7 @@ test "denies a moderator that isn't privileged" do assert conn.status == 403 end - test "accepts for a priviledged role even if other role isn't priviledged" do + test "accepts for a privileged role even if other role isn't privileged" do clear_config([:instance, :admin_privileges], [:cofe]) clear_config([:instance, :moderator_privileges], []) user = insert(:user, is_admin: true, is_moderator: true) @@ -72,7 +72,7 @@ test "accepts for a priviledged role even if other role isn't priviledged" do ret_conn = EnsurePrivilegedPlug.call(conn, :cofe) - # priviledged through admin role + # privileged through admin role assert conn == ret_conn clear_config([:instance, :admin_privileges], []) @@ -82,7 +82,7 @@ test "accepts for a priviledged role even if other role isn't priviledged" do ret_conn = EnsurePrivilegedPlug.call(conn, :cofe) - # priviledged through moderator role + # privileged through moderator role assert conn == ret_conn end From 51f87ba30cf20a1ca6bc19d2229913d8e1eecda5 Mon Sep 17 00:00:00 2001 From: Ilja Date: Sat, 2 Jul 2022 07:59:46 +0200 Subject: [PATCH 32/54] Change order of privilege tags to make more sense The tags were listed in different places They were listed in a rather randomly order I reordered them in a way I think makes more sense --- config/config.exs | 14 +++++++------- config/description.exs | 28 ++++++++++++++-------------- docs/configuration/cheatsheet.md | 14 +++++++------- 3 files changed, 28 insertions(+), 28 deletions(-) diff --git a/config/config.exs b/config/config.exs index 935d4fc98..eb56723fa 100644 --- a/config/config.exs +++ b/config/config.exs @@ -257,15 +257,15 @@ password_reset_token_validity: 60 * 60 * 24, profile_directory: true, admin_privileges: [ - :users_delete, - :users_manage_credentials, - :messages_read, - :users_manage_tags, - :users_manage_activation_state, - :users_manage_invites, - :reports_manage_reports, :users_read, + :users_manage_invites, + :users_manage_activation_state, + :users_manage_tags, + :users_manage_credentials, + :users_delete, + :messages_read, :messages_delete, + :reports_manage_reports, :emoji_manage_emoji ], moderator_privileges: [], diff --git a/config/description.exs b/config/description.exs index e2ff91fb3..66ae53d42 100644 --- a/config/description.exs +++ b/config/description.exs @@ -964,15 +964,15 @@ key: :admin_privileges, type: {:list, :atom}, suggestions: [ - :users_delete, - :users_manage_credentials, - :messages_read, - :users_manage_tags, - :users_manage_activation_state, - :users_manage_invites, - :reports_manage_reports, :users_read, + :users_manage_invites, + :users_manage_activation_state, + :users_manage_tags, + :users_manage_credentials, + :users_delete, + :messages_read, :messages_delete, + :reports_manage_reports, :emoji_manage_emoji ], description: @@ -982,15 +982,15 @@ key: :moderator_privileges, type: {:list, :atom}, suggestions: [ - :users_delete, - :users_manage_credentials, - :messages_read, - :users_manage_tags, - :users_manage_activation_state, - :users_manage_invites, - :reports_manage_reports, :users_read, + :users_manage_invites, + :users_manage_activation_state, + :users_manage_tags, + :users_manage_credentials, + :users_delete, + :messages_read, :messages_delete, + :reports_manage_reports, :emoji_manage_emoji ], description: diff --git a/docs/configuration/cheatsheet.md b/docs/configuration/cheatsheet.md index c59c914f2..af82b6948 100644 --- a/docs/configuration/cheatsheet.md +++ b/docs/configuration/cheatsheet.md @@ -66,15 +66,15 @@ To add configuration to your config file, you can copy it from the base config. * `password_reset_token_validity`: The time after which reset tokens aren't accepted anymore, in seconds (default: one day). * `admin_privileges`: A list of privileges an admin has (e.g. delete messages, manage reports...) * Possible values are: - * `:users_delete` - * `:users_manage_credentials` - * `:messages_read` - * `:users_manage_tags` - * `:users_manage_activation_state` - * `:users_manage_invites` - * `:reports_manage_reports` * `:users_read` + * `:users_manage_invites` + * `:users_manage_activation_state` + * `:users_manage_tags` + * `:users_manage_credentials` + * `:users_delete` + * `:messages_read` * `:messages_delete` + * `:reports_manage_reports` * `:emoji_manage_emoji` * `moderator_privileges`: A list of privileges a moderator has (e.g. delete messages, manage reports...) * Possible values are the same as for `admin_privileges` From 15748fd30148b8188824bf10fac4c49b6821b041 Mon Sep 17 00:00:00 2001 From: Ilja Date: Sat, 2 Jul 2022 08:17:22 +0200 Subject: [PATCH 33/54] Add better explanation in the Cheatsheet about what each tag does --- docs/configuration/cheatsheet.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/docs/configuration/cheatsheet.md b/docs/configuration/cheatsheet.md index af82b6948..043f819c7 100644 --- a/docs/configuration/cheatsheet.md +++ b/docs/configuration/cheatsheet.md @@ -67,15 +67,25 @@ To add configuration to your config file, you can copy it from the base config. * `admin_privileges`: A list of privileges an admin has (e.g. delete messages, manage reports...) * Possible values are: * `:users_read` + * Allows you to fetch users through the admin api * `:users_manage_invites` + * Allows you to manage invites. This includes sending, resending, revoking and approving invites * `:users_manage_activation_state` + * Allows you to activate and deactive accounts. This also allows you to see deactivated users through the Mastodon-API. * `:users_manage_tags` + * Allows you to set and remove tags for users. This can be useful in combination with MRF policy `Pleroma.Web.ActivityPub.MRF.TagPolicy`. * `:users_manage_credentials` + * Allows you to trigger a password reset and set new credentials * `:users_delete` + * Allows you to delete accounts. Note that deleting an account is actually deactivating it and removing all data like posts, profile information, etc. * `:messages_read` + * Allows you to view messages through the Admin-API, including non-public posts and chats * `:messages_delete` + * Allows you to delete messages from otehr people * `:reports_manage_reports` + * Allows you to see and manage reports * `:emoji_manage_emoji` + * Allows you to manage emoji on your instance * `moderator_privileges`: A list of privileges a moderator has (e.g. delete messages, manage reports...) * Possible values are the same as for `admin_privileges` From 42d4bd3a5d49a472b8fcb85e6cd413eb0d6dab3f Mon Sep 17 00:00:00 2001 From: Ilja Date: Sat, 2 Jul 2022 08:55:14 +0200 Subject: [PATCH 34/54] Rename pipelines and add forgotten tags I renamed some tags before, but forgot to rename the pipelines I also had some tags which I forgot to add to the config, description, etc. These have now been done/added --- config/config.exs | 5 +- config/description.exs | 10 +++- docs/configuration/cheatsheet.md | 6 ++ lib/pleroma/web/router.ex | 56 +++++++++---------- .../controllers/admin_api_controller_test.exs | 4 +- .../controllers/instance_controller_test.exs | 2 +- 6 files changed, 49 insertions(+), 34 deletions(-) diff --git a/config/config.exs b/config/config.exs index eb56723fa..994d333aa 100644 --- a/config/config.exs +++ b/config/config.exs @@ -265,8 +265,11 @@ :users_delete, :messages_read, :messages_delete, + :instances_delete, :reports_manage_reports, - :emoji_manage_emoji + :moderation_log_read, + :emoji_manage_emoji, + :statistics_read ], moderator_privileges: [], max_endorsed_users: 20, diff --git a/config/description.exs b/config/description.exs index 66ae53d42..134cefa85 100644 --- a/config/description.exs +++ b/config/description.exs @@ -972,8 +972,11 @@ :users_delete, :messages_read, :messages_delete, + :instances_delete, :reports_manage_reports, - :emoji_manage_emoji + :moderation_log_read, + :emoji_manage_emoji, + :statistics_read ], description: "What extra privileges to allow admins (e.g. updating user credentials, get password reset token, delete users, index and read private statuses and chats)" @@ -990,8 +993,11 @@ :users_delete, :messages_read, :messages_delete, + :instances_delete, :reports_manage_reports, - :emoji_manage_emoji + :moderation_log_read, + :emoji_manage_emoji, + :statistics_read ], description: "What extra privileges to allow moderators (e.g. updating user credentials, get password reset token, delete users, index and read private statuses and chats)" diff --git a/docs/configuration/cheatsheet.md b/docs/configuration/cheatsheet.md index 043f819c7..a12cfff92 100644 --- a/docs/configuration/cheatsheet.md +++ b/docs/configuration/cheatsheet.md @@ -82,10 +82,16 @@ To add configuration to your config file, you can copy it from the base config. * Allows you to view messages through the Admin-API, including non-public posts and chats * `:messages_delete` * Allows you to delete messages from otehr people + * `:instances_delete,` + * Allows you to delete a whole remote instance from your instance. This will delete all users and messages from that remote instance. * `:reports_manage_reports` * Allows you to see and manage reports + * `:moderation_log_read,` + * Allows you to read the entries in the moderation log * `:emoji_manage_emoji` * Allows you to manage emoji on your instance + * `:statistics_read,` + * Allows you to see some simple statistics from your instance * `moderator_privileges`: A list of privileges a moderator has (e.g. delete messages, manage reports...) * Possible values are the same as for `admin_privileges` diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex index cbb5ca55f..e781d3673 100644 --- a/lib/pleroma/web/router.ex +++ b/lib/pleroma/web/router.ex @@ -105,59 +105,59 @@ defmodule Pleroma.Web.Router do plug(Pleroma.Web.Plugs.UserIsAdminPlug) end - pipeline :require_privileged_role_user_deletion do + pipeline :require_privileged_role_users_delete do plug(:admin_api) plug(Pleroma.Web.Plugs.EnsurePrivilegedPlug, :users_delete) end - pipeline :require_privileged_role_user_credentials do + pipeline :require_privileged_role_users_manage_credentials do plug(:admin_api) plug(Pleroma.Web.Plugs.EnsurePrivilegedPlug, :users_manage_credentials) end - pipeline :require_privileged_role_statuses_read do + pipeline :require_privileged_role_messages_read do plug(:admin_api) plug(Pleroma.Web.Plugs.EnsurePrivilegedPlug, :messages_read) end - pipeline :require_privileged_role_user_tag do + pipeline :require_privileged_role_users_manage_tags do plug(:admin_api) plug(Pleroma.Web.Plugs.EnsurePrivilegedPlug, :users_manage_tags) end - pipeline :require_privileged_role_user_activation do + pipeline :require_privileged_role_users_manage_activation_state do plug(:admin_api) plug(Pleroma.Web.Plugs.EnsurePrivilegedPlug, :users_manage_activation_state) end - pipeline :require_privileged_role_user_invite do + pipeline :require_privileged_role_users_manage_invites do plug(:admin_api) plug(Pleroma.Web.Plugs.EnsurePrivilegedPlug, :users_manage_invites) end - pipeline :require_privileged_role_report_handle do + pipeline :require_privileged_role_reports_manage_reports do plug(:admin_api) plug(Pleroma.Web.Plugs.EnsurePrivilegedPlug, :reports_manage_reports) end - pipeline :require_privileged_role_user_read do + pipeline :require_privileged_role_users_read do plug(:admin_api) plug(Pleroma.Web.Plugs.EnsurePrivilegedPlug, :users_read) end - pipeline :require_privileged_role_status_delete do + pipeline :require_privileged_role_messages_delete do plug(:admin_api) plug(Pleroma.Web.Plugs.EnsurePrivilegedPlug, :messages_delete) end - pipeline :require_privileged_role_emoji_management do + pipeline :require_privileged_role_emoji_manage_emoji do plug(:admin_api) plug(Pleroma.Web.Plugs.EnsurePrivilegedPlug, :emoji_manage_emoji) end - pipeline :require_privileged_role_instance_delete do + pipeline :require_privileged_role_instances_delete do plug(:admin_api) - plug(Pleroma.Web.Plugs.EnsurePrivilegedPlug, :instance_delete) + plug(Pleroma.Web.Plugs.EnsurePrivilegedPlug, :instances_delete) end pipeline :require_privileged_role_moderation_log_read do @@ -165,9 +165,9 @@ defmodule Pleroma.Web.Router do plug(Pleroma.Web.Plugs.EnsurePrivilegedPlug, :moderation_log_read) end - pipeline :require_privileged_role_stats_read do + pipeline :require_privileged_role_statistics_read do plug(:admin_api) - plug(Pleroma.Web.Plugs.EnsurePrivilegedPlug, :stats_read) + plug(Pleroma.Web.Plugs.EnsurePrivilegedPlug, :statistics_read) end pipeline :pleroma_html do @@ -293,14 +293,14 @@ defmodule Pleroma.Web.Router do # AdminAPI: admins and mods (staff) can perform these actions (if privileged by role) scope "/api/v1/pleroma/admin", Pleroma.Web.AdminAPI do - pipe_through(:require_privileged_role_user_deletion) + pipe_through(:require_privileged_role_users_delete) delete("/users", UserController, :delete) end # AdminAPI: admins and mods (staff) can perform these actions (if privileged by role) scope "/api/v1/pleroma/admin", Pleroma.Web.AdminAPI do - pipe_through(:require_privileged_role_user_credentials) + pipe_through(:require_privileged_role_users_manage_credentials) get("/users/:nickname/password_reset", AdminAPIController, :get_password_reset) patch("/users/:nickname/credentials", AdminAPIController, :update_user_credentials) @@ -308,7 +308,7 @@ defmodule Pleroma.Web.Router do # AdminAPI: admins and mods (staff) can perform these actions (if privileged by role) scope "/api/v1/pleroma/admin", Pleroma.Web.AdminAPI do - pipe_through(:require_privileged_role_statuses_read) + pipe_through(:require_privileged_role_messages_read) get("/users/:nickname/statuses", AdminAPIController, :list_user_statuses) get("/users/:nickname/chats", AdminAPIController, :list_user_chats) @@ -325,7 +325,7 @@ defmodule Pleroma.Web.Router do # AdminAPI: admins and mods (staff) can perform these actions (if privileged by role) scope "/api/v1/pleroma/admin", Pleroma.Web.AdminAPI do - pipe_through(:require_privileged_role_user_tag) + pipe_through(:require_privileged_role_users_manage_tags) put("/users/tag", AdminAPIController, :tag_users) delete("/users/tag", AdminAPIController, :untag_users) @@ -333,7 +333,7 @@ defmodule Pleroma.Web.Router do # AdminAPI: admins and mods (staff) can perform these actions (if privileged by role) scope "/api/v1/pleroma/admin", Pleroma.Web.AdminAPI do - pipe_through(:require_privileged_role_user_activation) + pipe_through(:require_privileged_role_users_manage_activation_state) patch("/users/:nickname/toggle_activation", UserController, :toggle_activation) patch("/users/activate", UserController, :activate) @@ -342,7 +342,7 @@ defmodule Pleroma.Web.Router do # AdminAPI: admins and mods (staff) can perform these actions (if privileged by role) scope "/api/v1/pleroma/admin", Pleroma.Web.AdminAPI do - pipe_through(:require_privileged_role_user_invite) + pipe_through(:require_privileged_role_users_manage_invites) patch("/users/approve", UserController, :approve) post("/users/invite_token", InviteController, :create) @@ -353,7 +353,7 @@ defmodule Pleroma.Web.Router do # AdminAPI: admins and mods (staff) can perform these actions (if privileged by role) scope "/api/v1/pleroma/admin", Pleroma.Web.AdminAPI do - pipe_through(:require_privileged_role_report_handle) + pipe_through(:require_privileged_role_reports_manage_reports) get("/reports", ReportController, :index) get("/reports/:id", ReportController, :show) @@ -364,7 +364,7 @@ defmodule Pleroma.Web.Router do # AdminAPI: admins and mods (staff) can perform these actions (if privileged by role) scope "/api/v1/pleroma/admin", Pleroma.Web.AdminAPI do - pipe_through(:require_privileged_role_user_read) + pipe_through(:require_privileged_role_users_read) get("/users", UserController, :index) get("/users/:nickname", UserController, :show) @@ -372,7 +372,7 @@ defmodule Pleroma.Web.Router do # AdminAPI: admins and mods (staff) can perform these actions (if privileged by role) scope "/api/v1/pleroma/admin", Pleroma.Web.AdminAPI do - pipe_through(:require_privileged_role_status_delete) + pipe_through(:require_privileged_role_messages_delete) put("/statuses/:id", StatusController, :update) delete("/statuses/:id", StatusController, :delete) @@ -382,14 +382,14 @@ defmodule Pleroma.Web.Router do # AdminAPI: admins and mods (staff) can perform these actions (if privileged by role) scope "/api/v1/pleroma/admin", Pleroma.Web.AdminAPI do - pipe_through(:require_privileged_role_emoji_management) + pipe_through(:require_privileged_role_emoji_manage_emoji) post("/reload_emoji", AdminAPIController, :reload_emoji) end # AdminAPI: admins and mods (staff) can perform these actions (if privileged by role) scope "/api/v1/pleroma/admin", Pleroma.Web.AdminAPI do - pipe_through(:require_privileged_role_instance_delete) + pipe_through(:require_privileged_role_instances_delete) delete("/instances/:instance", InstanceController, :delete) end @@ -403,14 +403,14 @@ defmodule Pleroma.Web.Router do # AdminAPI: admins and mods (staff) can perform these actions (if privileged by role) scope "/api/v1/pleroma/admin", Pleroma.Web.AdminAPI do - pipe_through(:require_privileged_role_stats_read) + pipe_through(:require_privileged_role_statistics_read) get("/stats", AdminAPIController, :stats) end scope "/api/v1/pleroma/emoji", Pleroma.Web.PleromaAPI do scope "/pack" do - pipe_through(:require_privileged_role_emoji_management) + pipe_through(:require_privileged_role_emoji_manage_emoji) post("/", EmojiPackController, :create) patch("/", EmojiPackController, :update) @@ -425,7 +425,7 @@ defmodule Pleroma.Web.Router do # Modifying packs scope "/packs" do - pipe_through(:require_privileged_role_emoji_management) + pipe_through(:require_privileged_role_emoji_manage_emoji) get("/import", EmojiPackController, :import_from_filesystem) get("/remote", EmojiPackController, :remote) diff --git a/test/pleroma/web/admin_api/controllers/admin_api_controller_test.exs b/test/pleroma/web/admin_api/controllers/admin_api_controller_test.exs index 34ec28012..372f4fe63 100644 --- a/test/pleroma/web/admin_api/controllers/admin_api_controller_test.exs +++ b/test/pleroma/web/admin_api/controllers/admin_api_controller_test.exs @@ -971,7 +971,7 @@ test "it resend emails for two users", %{conn: conn, admin: admin} do describe "/api/pleroma/admin/stats" do setup do - clear_config([:instance, :admin_privileges], [:stats_read]) + clear_config([:instance, :admin_privileges], [:statistics_read]) end test "status visibility count", %{conn: conn} do @@ -1007,7 +1007,7 @@ test "by instance", %{conn: conn} do response["status_visibility"] end - test "it requires privileged role :stats_read", %{conn: conn} do + test "it requires privileged role :statistics_read", %{conn: conn} do clear_config([:instance, :admin_privileges], []) assert conn diff --git a/test/pleroma/web/admin_api/controllers/instance_controller_test.exs b/test/pleroma/web/admin_api/controllers/instance_controller_test.exs index 47af8e7d9..6cca623f3 100644 --- a/test/pleroma/web/admin_api/controllers/instance_controller_test.exs +++ b/test/pleroma/web/admin_api/controllers/instance_controller_test.exs @@ -68,7 +68,7 @@ test "GET /instances/:instance/statuses", %{conn: conn} do end test "DELETE /instances/:instance", %{conn: conn} do - clear_config([:instance, :admin_privileges], [:instance_delete]) + clear_config([:instance, :admin_privileges], [:instances_delete]) user = insert(:user, nickname: "lain@lain.com") post = insert(:note_activity, user: user) From 6ef38c6523fc8b7f28ef92d38b9ca829d8a7248e Mon Sep 17 00:00:00 2001 From: Ilja Date: Tue, 5 Jul 2022 08:57:50 +0200 Subject: [PATCH 35/54] Improve tests after code review --- test/pleroma/user/query_test.exs | 47 ++++++-------------------------- test/pleroma/user_test.exs | 47 ++++++-------------------------- 2 files changed, 16 insertions(+), 78 deletions(-) diff --git a/test/pleroma/user/query_test.exs b/test/pleroma/user/query_test.exs index 7e443536b..30a4637f2 100644 --- a/test/pleroma/user/query_test.exs +++ b/test/pleroma/user/query_test.exs @@ -58,80 +58,49 @@ test "is_suggested param" do } end - test "doesn't return any users when there are no privileged roles", %{ - user: user, - moderator_user: moderator_user, - admin_user: admin_user, - admin_moderator_user: admin_moderator_user, - remote_user: remote_user, - non_active_user: non_active_user - } do + test "doesn't return any users when there are no privileged roles" do clear_config([:instance, :admin_privileges], []) clear_config([:instance, :moderator_privileges], []) - refute user in (User.Query.build(%{is_privileged: :cofe}) |> Repo.all()) - refute admin_user in (User.Query.build(%{is_privileged: :cofe}) |> Repo.all()) - refute moderator_user in (User.Query.build(%{is_privileged: :cofe}) |> Repo.all()) - refute admin_moderator_user in (User.Query.build(%{is_privileged: :cofe}) |> Repo.all()) - refute remote_user in (User.Query.build(%{is_privileged: :cofe}) |> Repo.all()) - refute non_active_user in (User.Query.build(%{is_privileged: :cofe}) |> Repo.all()) + assert [] = User.Query.build(%{is_privileged: :cofe}) |> Repo.all() end test "returns moderator users if they are privileged", %{ - user: user, moderator_user: moderator_user, - admin_user: admin_user, - admin_moderator_user: admin_moderator_user, - remote_user: remote_user, - non_active_user: non_active_user + admin_moderator_user: admin_moderator_user } do clear_config([:instance, :admin_privileges], []) clear_config([:instance, :moderator_privileges], [:cofe]) - refute user in (User.Query.build(%{is_privileged: :cofe}) |> Repo.all()) - refute admin_user in (User.Query.build(%{is_privileged: :cofe}) |> Repo.all()) + assert [_, _] = User.Query.build(%{is_privileged: :cofe}) |> Repo.all() assert moderator_user in (User.Query.build(%{is_privileged: :cofe}) |> Repo.all()) assert admin_moderator_user in (User.Query.build(%{is_privileged: :cofe}) |> Repo.all()) - refute remote_user in (User.Query.build(%{is_privileged: :cofe}) |> Repo.all()) - refute non_active_user in (User.Query.build(%{is_privileged: :cofe}) |> Repo.all()) end test "returns admin users if they are privileged", %{ - user: user, - moderator_user: moderator_user, admin_user: admin_user, - admin_moderator_user: admin_moderator_user, - remote_user: remote_user, - non_active_user: non_active_user + admin_moderator_user: admin_moderator_user } do clear_config([:instance, :admin_privileges], [:cofe]) clear_config([:instance, :moderator_privileges], []) - refute user in (User.Query.build(%{is_privileged: :cofe}) |> Repo.all()) + assert [_, _] = User.Query.build(%{is_privileged: :cofe}) |> Repo.all() assert admin_user in (User.Query.build(%{is_privileged: :cofe}) |> Repo.all()) - refute moderator_user in (User.Query.build(%{is_privileged: :cofe}) |> Repo.all()) assert admin_moderator_user in (User.Query.build(%{is_privileged: :cofe}) |> Repo.all()) - refute remote_user in (User.Query.build(%{is_privileged: :cofe}) |> Repo.all()) - refute non_active_user in (User.Query.build(%{is_privileged: :cofe}) |> Repo.all()) end test "returns admin and moderator users if they are both privileged", %{ - user: user, moderator_user: moderator_user, admin_user: admin_user, - admin_moderator_user: admin_moderator_user, - remote_user: remote_user, - non_active_user: non_active_user + admin_moderator_user: admin_moderator_user } do clear_config([:instance, :admin_privileges], [:cofe]) clear_config([:instance, :moderator_privileges], [:cofe]) - refute user in (User.Query.build(%{is_privileged: :cofe}) |> Repo.all()) + assert [_, _, _] = User.Query.build(%{is_privileged: :cofe}) |> Repo.all() assert admin_user in (User.Query.build(%{is_privileged: :cofe}) |> Repo.all()) assert moderator_user in (User.Query.build(%{is_privileged: :cofe}) |> Repo.all()) assert admin_moderator_user in (User.Query.build(%{is_privileged: :cofe}) |> Repo.all()) - refute remote_user in (User.Query.build(%{is_privileged: :cofe}) |> Repo.all()) - refute non_active_user in (User.Query.build(%{is_privileged: :cofe}) |> Repo.all()) end end end diff --git a/test/pleroma/user_test.exs b/test/pleroma/user_test.exs index 98e00cecb..25ec44834 100644 --- a/test/pleroma/user_test.exs +++ b/test/pleroma/user_test.exs @@ -2023,80 +2023,49 @@ test "returns true when the account is unconfirmed and being viewed by a privile } end - test "doesn't return any users when there are no privileged roles", %{ - user: user, - moderator_user: moderator_user, - admin_user: admin_user, - admin_moderator_user: admin_moderator_user, - remote_user: remote_user, - non_active_user: non_active_user - } do + test "doesn't return any users when there are no privileged roles" do clear_config([:instance, :admin_privileges], []) clear_config([:instance, :moderator_privileges], []) - refute user in User.all_users_with_privilege(:cofe) - refute admin_user in User.all_users_with_privilege(:cofe) - refute moderator_user in User.all_users_with_privilege(:cofe) - refute admin_moderator_user in User.all_users_with_privilege(:cofe) - refute remote_user in User.all_users_with_privilege(:cofe) - refute non_active_user in User.all_users_with_privilege(:cofe) + assert [] = User.Query.build(%{is_privileged: :cofe}) |> Repo.all() end test "returns moderator users if they are privileged", %{ - user: user, moderator_user: moderator_user, - admin_user: admin_user, - admin_moderator_user: admin_moderator_user, - remote_user: remote_user, - non_active_user: non_active_user + admin_moderator_user: admin_moderator_user } do clear_config([:instance, :admin_privileges], []) clear_config([:instance, :moderator_privileges], [:cofe]) - refute user in User.all_users_with_privilege(:cofe) - refute admin_user in User.all_users_with_privilege(:cofe) + assert [_, _] = User.Query.build(%{is_privileged: :cofe}) |> Repo.all() assert moderator_user in User.all_users_with_privilege(:cofe) assert admin_moderator_user in User.all_users_with_privilege(:cofe) - refute remote_user in User.all_users_with_privilege(:cofe) - refute non_active_user in User.all_users_with_privilege(:cofe) end test "returns admin users if they are privileged", %{ - user: user, - moderator_user: moderator_user, admin_user: admin_user, - admin_moderator_user: admin_moderator_user, - remote_user: remote_user, - non_active_user: non_active_user + admin_moderator_user: admin_moderator_user } do clear_config([:instance, :admin_privileges], [:cofe]) clear_config([:instance, :moderator_privileges], []) - refute user in User.all_users_with_privilege(:cofe) + assert [_, _] = User.Query.build(%{is_privileged: :cofe}) |> Repo.all() assert admin_user in User.all_users_with_privilege(:cofe) - refute moderator_user in User.all_users_with_privilege(:cofe) assert admin_moderator_user in User.all_users_with_privilege(:cofe) - refute remote_user in User.all_users_with_privilege(:cofe) - refute non_active_user in User.all_users_with_privilege(:cofe) end test "returns admin and moderator users if they are both privileged", %{ - user: user, moderator_user: moderator_user, admin_user: admin_user, - admin_moderator_user: admin_moderator_user, - remote_user: remote_user, - non_active_user: non_active_user + admin_moderator_user: admin_moderator_user } do clear_config([:instance, :admin_privileges], [:cofe]) clear_config([:instance, :moderator_privileges], [:cofe]) - refute user in User.all_users_with_privilege(:cofe) + assert [_, _, _] = User.Query.build(%{is_privileged: :cofe}) |> Repo.all() assert admin_user in User.all_users_with_privilege(:cofe) assert moderator_user in User.all_users_with_privilege(:cofe) assert admin_moderator_user in User.all_users_with_privilege(:cofe) - refute remote_user in User.all_users_with_privilege(:cofe) - refute non_active_user in User.all_users_with_privilege(:cofe) end end From c045a49909c2a1078864484d0327e03dac73687b Mon Sep 17 00:00:00 2001 From: Ilja Date: Thu, 14 Jul 2022 08:40:26 +0200 Subject: [PATCH 36/54] Add privilege for announcements --- config/config.exs | 1 + config/description.exs | 2 + lib/pleroma/web/router.ex | 10 ++ .../announcement_controller_test.exs | 96 ++++++++++++++++++- 4 files changed, 108 insertions(+), 1 deletion(-) diff --git a/config/config.exs b/config/config.exs index b0b43e75a..6c5ac2ceb 100644 --- a/config/config.exs +++ b/config/config.exs @@ -269,6 +269,7 @@ :instances_delete, :reports_manage_reports, :moderation_log_read, + :announcements_manage_announcements, :emoji_manage_emoji, :statistics_read ], diff --git a/config/description.exs b/config/description.exs index 2e7f06f81..b53354a79 100644 --- a/config/description.exs +++ b/config/description.exs @@ -984,6 +984,7 @@ :instances_delete, :reports_manage_reports, :moderation_log_read, + :announcements_manage_announcements, :emoji_manage_emoji, :statistics_read ], @@ -1005,6 +1006,7 @@ :instances_delete, :reports_manage_reports, :moderation_log_read, + :announcements_manage_announcements, :emoji_manage_emoji, :statistics_read ], diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex index e715aaa96..f77513046 100644 --- a/lib/pleroma/web/router.ex +++ b/lib/pleroma/web/router.ex @@ -170,6 +170,11 @@ defmodule Pleroma.Web.Router do plug(Pleroma.Web.Plugs.EnsurePrivilegedPlug, :statistics_read) end + pipeline :require_privileged_role_announcements_manage_announcements do + plug(:admin_api) + plug(Pleroma.Web.Plugs.EnsurePrivilegedPlug, :announcements_manage_announcements) + end + pipeline :pleroma_html do plug(:browser) plug(:authenticate) @@ -289,6 +294,11 @@ defmodule Pleroma.Web.Router do post("/frontends/install", FrontendController, :install) post("/backups", AdminAPIController, :create_backup) + end + + # AdminAPI: admins and mods (staff) can perform these actions (if privileged by role) + scope "/api/v1/pleroma/admin", Pleroma.Web.AdminAPI do + pipe_through(:require_privileged_role_announcements_manage_announcements) get("/announcements", AnnouncementController, :index) post("/announcements", AnnouncementController, :create) diff --git a/test/pleroma/web/admin_api/controllers/announcement_controller_test.exs b/test/pleroma/web/admin_api/controllers/announcement_controller_test.exs index 5b8148c05..cf60bcad5 100644 --- a/test/pleroma/web/admin_api/controllers/announcement_controller_test.exs +++ b/test/pleroma/web/admin_api/controllers/announcement_controller_test.exs @@ -3,11 +3,12 @@ # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Web.AdminAPI.AnnouncementControllerTest do - use Pleroma.Web.ConnCase + use Pleroma.Web.ConnCase, async: false import Pleroma.Factory setup do + clear_config([:instance, :admin_privileges], [:announcements_manage_announcements]) admin = insert(:user, is_admin: true) token = insert(:oauth_admin_token, user: admin) @@ -31,6 +32,18 @@ test "it lists all announcements", %{conn: conn} do assert [%{"id" => ^id}] = response end + test "it requires privileged role :announcements_manage_announcements", %{conn: conn} do + conn + |> get("/api/v1/pleroma/admin/announcements") + |> json_response_and_validate_schema(:ok) + + clear_config([:instance, :admin_privileges], []) + + conn + |> get("/api/v1/pleroma/admin/announcements") + |> json_response(:forbidden) + end + test "it paginates announcements", %{conn: conn} do _announcements = Enum.map(0..20, fn _ -> insert(:announcement) end) @@ -92,6 +105,20 @@ test "it displays one announcement", %{conn: conn} do assert %{"id" => ^id} = response end + test "it requires privileged role :announcements_manage_announcements", %{conn: conn} do + %{id: id} = insert(:announcement) + + conn + |> get("/api/v1/pleroma/admin/announcements/#{id}") + |> json_response_and_validate_schema(:ok) + + clear_config([:instance, :admin_privileges], []) + + conn + |> get("/api/v1/pleroma/admin/announcements/#{id}") + |> json_response(:forbidden) + end + test "it returns not found for non-existent id", %{conn: conn} do %{id: id} = insert(:announcement) @@ -112,6 +139,20 @@ test "it deletes specified announcement", %{conn: conn} do |> json_response_and_validate_schema(:ok) end + test "it requires privileged role :announcements_manage_announcements", %{conn: conn} do + %{id: id} = insert(:announcement) + + conn + |> delete("/api/v1/pleroma/admin/announcements/#{id}") + |> json_response_and_validate_schema(:ok) + + clear_config([:instance, :admin_privileges], []) + + conn + |> delete("/api/v1/pleroma/admin/announcements/#{id}") + |> json_response(:forbidden) + end + test "it returns not found for non-existent id", %{conn: conn} do %{id: id} = insert(:announcement) @@ -156,6 +197,29 @@ test "it updates a field", %{conn: conn} do assert NaiveDateTime.compare(new.starts_at, starts_at) == :eq end + test "it requires privileged role :announcements_manage_announcements", %{conn: conn} do + %{id: id} = insert(:announcement) + + now = NaiveDateTime.utc_now() |> NaiveDateTime.truncate(:second) + starts_at = NaiveDateTime.add(now, -10, :second) + + conn + |> put_req_header("content-type", "application/json") + |> patch("/api/v1/pleroma/admin/announcements/#{id}", %{ + starts_at: NaiveDateTime.to_iso8601(starts_at) + }) + |> json_response_and_validate_schema(:ok) + + clear_config([:instance, :admin_privileges], []) + + conn + |> put_req_header("content-type", "application/json") + |> patch("/api/v1/pleroma/admin/announcements/#{id}", %{ + starts_at: NaiveDateTime.to_iso8601(starts_at) + }) + |> json_response(:forbidden) + end + test "it updates with time with utc timezone", %{conn: conn} do %{id: id} = insert(:announcement) @@ -250,6 +314,36 @@ test "it creates an announcement", %{conn: conn} do assert NaiveDateTime.compare(announcement.ends_at, ends_at) == :eq end + test "it requires privileged role :announcements_manage_announcements", %{conn: conn} do + content = "test post announcement api" + + now = NaiveDateTime.utc_now() |> NaiveDateTime.truncate(:second) + starts_at = NaiveDateTime.add(now, -10, :second) + ends_at = NaiveDateTime.add(now, 10, :second) + + conn + |> put_req_header("content-type", "application/json") + |> post("/api/v1/pleroma/admin/announcements", %{ + "content" => content, + "starts_at" => NaiveDateTime.to_iso8601(starts_at), + "ends_at" => NaiveDateTime.to_iso8601(ends_at), + "all_day" => true + }) + |> json_response_and_validate_schema(:ok) + + clear_config([:instance, :admin_privileges], []) + + conn + |> put_req_header("content-type", "application/json") + |> post("/api/v1/pleroma/admin/announcements", %{ + "content" => content, + "starts_at" => NaiveDateTime.to_iso8601(starts_at), + "ends_at" => NaiveDateTime.to_iso8601(ends_at), + "all_day" => true + }) + |> json_response(:forbidden) + end + test "creating with time with utc timezones", %{conn: conn} do content = "test post announcement api" From 275c60208bf96ed4956d823ffe3e2b2920022353 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9l=C3=A8ne?= Date: Mon, 18 Jul 2022 05:37:27 +0000 Subject: [PATCH 37/54] Apply ilja's suggestion(s) to 1 file(s) --- docs/configuration/cheatsheet.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/configuration/cheatsheet.md b/docs/configuration/cheatsheet.md index 4f398a14b..d79967a51 100644 --- a/docs/configuration/cheatsheet.md +++ b/docs/configuration/cheatsheet.md @@ -72,7 +72,7 @@ To add configuration to your config file, you can copy it from the base config. * `:users_manage_invites` * Allows you to manage invites. This includes sending, resending, revoking and approving invites * `:users_manage_activation_state` - * Allows you to activate and deactive accounts. This also allows you to see deactivated users through the Mastodon-API. + * Allows admins to activate and deactivate accounts. This also allows them to see deactivated users through the Mastodon API. * `:users_manage_tags` * Allows you to set and remove tags for users. This can be useful in combination with MRF policy `Pleroma.Web.ActivityPub.MRF.TagPolicy`. * `:users_manage_credentials` From 92da9c4a470c8824bcf662c2be4f922dfaabc943 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9l=C3=A8ne?= Date: Mon, 18 Jul 2022 05:37:41 +0000 Subject: [PATCH 38/54] Apply ilja's suggestion(s) to 1 file(s) --- docs/configuration/cheatsheet.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/configuration/cheatsheet.md b/docs/configuration/cheatsheet.md index d79967a51..366e307d2 100644 --- a/docs/configuration/cheatsheet.md +++ b/docs/configuration/cheatsheet.md @@ -68,7 +68,7 @@ To add configuration to your config file, you can copy it from the base config. * `admin_privileges`: A list of privileges an admin has (e.g. delete messages, manage reports...) * Possible values are: * `:users_read` - * Allows you to fetch users through the admin api + * Allows admins to fetch users through the admin API. * `:users_manage_invites` * Allows you to manage invites. This includes sending, resending, revoking and approving invites * `:users_manage_activation_state` From 2baf3084a1edb275e8c9cc33793ddfaa5dbe9b99 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9l=C3=A8ne?= Date: Mon, 18 Jul 2022 05:38:01 +0000 Subject: [PATCH 39/54] Apply ilja's suggestion(s) to 1 file(s) --- docs/configuration/cheatsheet.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/configuration/cheatsheet.md b/docs/configuration/cheatsheet.md index 366e307d2..d593f51c7 100644 --- a/docs/configuration/cheatsheet.md +++ b/docs/configuration/cheatsheet.md @@ -70,7 +70,7 @@ To add configuration to your config file, you can copy it from the base config. * `:users_read` * Allows admins to fetch users through the admin API. * `:users_manage_invites` - * Allows you to manage invites. This includes sending, resending, revoking and approving invites + * Allows admins to manage invites. This includes sending, resending, revoking and approving invites. * `:users_manage_activation_state` * Allows admins to activate and deactivate accounts. This also allows them to see deactivated users through the Mastodon API. * `:users_manage_tags` From ad730c2135858cbc3a050d89a8d67b406d1b4802 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9l=C3=A8ne?= Date: Mon, 18 Jul 2022 05:38:23 +0000 Subject: [PATCH 40/54] Apply ilja's suggestion(s) to 1 file(s) --- docs/configuration/cheatsheet.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/configuration/cheatsheet.md b/docs/configuration/cheatsheet.md index d593f51c7..4dacf3bb2 100644 --- a/docs/configuration/cheatsheet.md +++ b/docs/configuration/cheatsheet.md @@ -74,7 +74,7 @@ To add configuration to your config file, you can copy it from the base config. * `:users_manage_activation_state` * Allows admins to activate and deactivate accounts. This also allows them to see deactivated users through the Mastodon API. * `:users_manage_tags` - * Allows you to set and remove tags for users. This can be useful in combination with MRF policy `Pleroma.Web.ActivityPub.MRF.TagPolicy`. + * Allows admins to set and remove tags for users. This can be useful in combination with MRF policies, such as `Pleroma.Web.ActivityPub.MRF.TagPolicy`. * `:users_manage_credentials` * Allows you to trigger a password reset and set new credentials * `:users_delete` From 02947bafeb8d2b2841f3e19df380ca47efbad125 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9l=C3=A8ne?= Date: Mon, 18 Jul 2022 05:38:30 +0000 Subject: [PATCH 41/54] Apply ilja's suggestion(s) to 1 file(s) --- docs/configuration/cheatsheet.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/configuration/cheatsheet.md b/docs/configuration/cheatsheet.md index 4dacf3bb2..3966346a3 100644 --- a/docs/configuration/cheatsheet.md +++ b/docs/configuration/cheatsheet.md @@ -76,7 +76,7 @@ To add configuration to your config file, you can copy it from the base config. * `:users_manage_tags` * Allows admins to set and remove tags for users. This can be useful in combination with MRF policies, such as `Pleroma.Web.ActivityPub.MRF.TagPolicy`. * `:users_manage_credentials` - * Allows you to trigger a password reset and set new credentials + * Allows admins to trigger a password reset and set new credentials for an user. * `:users_delete` * Allows you to delete accounts. Note that deleting an account is actually deactivating it and removing all data like posts, profile information, etc. * `:messages_read` From 02b4b4da4753725c9508da3d0da01ce829958bfa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9l=C3=A8ne?= Date: Mon, 18 Jul 2022 05:38:45 +0000 Subject: [PATCH 42/54] Apply ilja's suggestion(s) to 1 file(s) --- docs/configuration/cheatsheet.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/configuration/cheatsheet.md b/docs/configuration/cheatsheet.md index 3966346a3..4fa508e3b 100644 --- a/docs/configuration/cheatsheet.md +++ b/docs/configuration/cheatsheet.md @@ -78,7 +78,7 @@ To add configuration to your config file, you can copy it from the base config. * `:users_manage_credentials` * Allows admins to trigger a password reset and set new credentials for an user. * `:users_delete` - * Allows you to delete accounts. Note that deleting an account is actually deactivating it and removing all data like posts, profile information, etc. + * Allows admins to delete accounts. Note that deleting an account is actually deactivating it and removing all data like posts, profile information, etc. * `:messages_read` * Allows you to view messages through the Admin-API, including non-public posts and chats * `:messages_delete` From d622fe8d487765dcc59aa94c6156bd4739bdf7a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9l=C3=A8ne?= Date: Mon, 18 Jul 2022 05:39:03 +0000 Subject: [PATCH 43/54] Apply ilja's suggestion(s) to 1 file(s) --- docs/configuration/cheatsheet.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/configuration/cheatsheet.md b/docs/configuration/cheatsheet.md index 4fa508e3b..9ad0718d0 100644 --- a/docs/configuration/cheatsheet.md +++ b/docs/configuration/cheatsheet.md @@ -80,7 +80,7 @@ To add configuration to your config file, you can copy it from the base config. * `:users_delete` * Allows admins to delete accounts. Note that deleting an account is actually deactivating it and removing all data like posts, profile information, etc. * `:messages_read` - * Allows you to view messages through the Admin-API, including non-public posts and chats + * Allows admins to read messages through the admin API, including non-public posts and chats. * `:messages_delete` * Allows you to delete messages from otehr people * `:instances_delete,` From db789acf1e8f14ca9ae73e9ae257d3011d6d44f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9l=C3=A8ne?= Date: Mon, 18 Jul 2022 05:39:11 +0000 Subject: [PATCH 44/54] Apply ilja's suggestion(s) to 1 file(s) --- docs/configuration/cheatsheet.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/configuration/cheatsheet.md b/docs/configuration/cheatsheet.md index 9ad0718d0..ab676f2c5 100644 --- a/docs/configuration/cheatsheet.md +++ b/docs/configuration/cheatsheet.md @@ -84,7 +84,7 @@ To add configuration to your config file, you can copy it from the base config. * `:messages_delete` * Allows you to delete messages from otehr people * `:instances_delete,` - * Allows you to delete a whole remote instance from your instance. This will delete all users and messages from that remote instance. + * Allows admins to remove a whole remote instance from your instance. This will delete all users and messages from that remote instance. * `:reports_manage_reports` * Allows you to see and manage reports * `:moderation_log_read,` From d24d74b1a72037fc4b5b4e3925de1423bb9c5e21 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9l=C3=A8ne?= Date: Mon, 18 Jul 2022 05:39:21 +0000 Subject: [PATCH 45/54] Apply ilja's suggestion(s) to 1 file(s) --- docs/configuration/cheatsheet.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/configuration/cheatsheet.md b/docs/configuration/cheatsheet.md index ab676f2c5..c96a91794 100644 --- a/docs/configuration/cheatsheet.md +++ b/docs/configuration/cheatsheet.md @@ -88,7 +88,7 @@ To add configuration to your config file, you can copy it from the base config. * `:reports_manage_reports` * Allows you to see and manage reports * `:moderation_log_read,` - * Allows you to read the entries in the moderation log + * Allows admins to read the entries in the moderation log. * `:emoji_manage_emoji` * Allows you to manage emoji on your instance * `:statistics_read,` From 97e8c8a10a57f82c4c4a9f0bc7f992fa96988206 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9l=C3=A8ne?= Date: Mon, 18 Jul 2022 05:39:26 +0000 Subject: [PATCH 46/54] Apply ilja's suggestion(s) to 1 file(s) --- docs/configuration/cheatsheet.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/configuration/cheatsheet.md b/docs/configuration/cheatsheet.md index c96a91794..60c70d12b 100644 --- a/docs/configuration/cheatsheet.md +++ b/docs/configuration/cheatsheet.md @@ -90,7 +90,7 @@ To add configuration to your config file, you can copy it from the base config. * `:moderation_log_read,` * Allows admins to read the entries in the moderation log. * `:emoji_manage_emoji` - * Allows you to manage emoji on your instance + * Allows admins to manage custom emoji on the instance. * `:statistics_read,` * Allows you to see some simple statistics from your instance * `moderator_privileges`: A list of privileges a moderator has (e.g. delete messages, manage reports...) From ce0a6737e72e79afb55c68ffb8a04c073a937140 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9l=C3=A8ne?= Date: Mon, 18 Jul 2022 05:40:02 +0000 Subject: [PATCH 47/54] Apply ilja's suggestion(s) to 1 file(s) --- docs/configuration/cheatsheet.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/configuration/cheatsheet.md b/docs/configuration/cheatsheet.md index 60c70d12b..e6e62bf60 100644 --- a/docs/configuration/cheatsheet.md +++ b/docs/configuration/cheatsheet.md @@ -82,7 +82,7 @@ To add configuration to your config file, you can copy it from the base config. * `:messages_read` * Allows admins to read messages through the admin API, including non-public posts and chats. * `:messages_delete` - * Allows you to delete messages from otehr people + * Allows admins to delete messages from other users. * `:instances_delete,` * Allows admins to remove a whole remote instance from your instance. This will delete all users and messages from that remote instance. * `:reports_manage_reports` From f9fc3a153d44fc72174d2bdf5c7e3f6df4125f37 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9l=C3=A8ne?= Date: Mon, 18 Jul 2022 05:40:10 +0000 Subject: [PATCH 48/54] Apply ilja's suggestion(s) to 1 file(s) --- docs/configuration/cheatsheet.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/configuration/cheatsheet.md b/docs/configuration/cheatsheet.md index e6e62bf60..81ac41605 100644 --- a/docs/configuration/cheatsheet.md +++ b/docs/configuration/cheatsheet.md @@ -86,7 +86,7 @@ To add configuration to your config file, you can copy it from the base config. * `:instances_delete,` * Allows admins to remove a whole remote instance from your instance. This will delete all users and messages from that remote instance. * `:reports_manage_reports` - * Allows you to see and manage reports + * Allows admins to see and manage reports. * `:moderation_log_read,` * Allows admins to read the entries in the moderation log. * `:emoji_manage_emoji` From 1a67a203643f9e19f2b76855d288f020c2af0963 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9l=C3=A8ne?= Date: Mon, 18 Jul 2022 05:40:24 +0000 Subject: [PATCH 49/54] Apply ilja's suggestion(s) to 1 file(s) --- docs/configuration/cheatsheet.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/configuration/cheatsheet.md b/docs/configuration/cheatsheet.md index 81ac41605..c236f53d3 100644 --- a/docs/configuration/cheatsheet.md +++ b/docs/configuration/cheatsheet.md @@ -92,7 +92,7 @@ To add configuration to your config file, you can copy it from the base config. * `:emoji_manage_emoji` * Allows admins to manage custom emoji on the instance. * `:statistics_read,` - * Allows you to see some simple statistics from your instance + * Allows admins to see some simple statistics about the instance. * `moderator_privileges`: A list of privileges a moderator has (e.g. delete messages, manage reports...) * Possible values are the same as for `admin_privileges` From b53cf7d4b3991bde21e05277d7fb2ee01bf57f46 Mon Sep 17 00:00:00 2001 From: Ilja Date: Sun, 7 Aug 2022 07:22:33 +0200 Subject: [PATCH 50/54] Change default moderator privileges to better match what we previously had Moderators were able to delete statusses via pleroma-fe. For that reason I now gave them :messages_delete by default. They are also able to recieve reports through the notifications. For that reason I now gave them :reports_manage_reports by default. They were also able to see deactivated accounts through pleroma-fe. However * they were unable to tell if the account is deactivated or not (which was a bug and fixed by thes privileges MR this commit is part of) * they were not able to actually change the activation state. Because of this, I decided to *not* give them the privilege :users_manage_activation_state as this would give significantly more privileges, while not giving it will actually improve the current experience as it works around the existing bug of not showing activation state. --- config/config.exs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/config.exs b/config/config.exs index 6c5ac2ceb..7f2927e37 100644 --- a/config/config.exs +++ b/config/config.exs @@ -273,7 +273,7 @@ :emoji_manage_emoji, :statistics_read ], - moderator_privileges: [], + moderator_privileges: [:messages_delete, :reports_manage_reports], max_endorsed_users: 20, birthday_required: false, birthday_min_age: 0, From 2d7ea263a1f7dba8e0a7667a95ea8af110e9be27 Mon Sep 17 00:00:00 2001 From: Ilja Date: Sat, 24 Sep 2022 13:52:28 +0200 Subject: [PATCH 51/54] Add extra routes to :users_manage_credentials privilege --- lib/pleroma/web/router.ex | 13 ++-- .../controllers/admin_api_controller_test.exs | 59 +++++++++++++++++++ 2 files changed, 64 insertions(+), 8 deletions(-) diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex index f77513046..a50232422 100644 --- a/lib/pleroma/web/router.ex +++ b/lib/pleroma/web/router.ex @@ -233,8 +233,6 @@ defmodule Pleroma.Web.Router do scope "/api/v1/pleroma/admin", Pleroma.Web.AdminAPI do pipe_through([:admin_api, :require_admin]) - put("/users/disable_mfa", AdminAPIController, :disable_mfa) - get("/users/:nickname/permission_group", AdminAPIController, :right_get) get("/users/:nickname/permission_group/:permission_group", AdminAPIController, :right_get) @@ -265,16 +263,10 @@ defmodule Pleroma.Web.Router do post("/relay", RelayController, :follow) delete("/relay", RelayController, :unfollow) - patch("/users/force_password_reset", AdminAPIController, :force_password_reset) - get("/users/:nickname/credentials", AdminAPIController, :show_user_credentials) - get("/instance_document/:name", InstanceDocumentController, :show) patch("/instance_document/:name", InstanceDocumentController, :update) delete("/instance_document/:name", InstanceDocumentController, :delete) - patch("/users/confirm_email", AdminAPIController, :confirm_email) - patch("/users/resend_confirmation_email", AdminAPIController, :resend_confirmation_email) - get("/config", ConfigController, :show) post("/config", ConfigController, :update) get("/config/descriptions", ConfigController, :descriptions) @@ -319,7 +311,12 @@ defmodule Pleroma.Web.Router do pipe_through(:require_privileged_role_users_manage_credentials) get("/users/:nickname/password_reset", AdminAPIController, :get_password_reset) + get("/users/:nickname/credentials", AdminAPIController, :show_user_credentials) patch("/users/:nickname/credentials", AdminAPIController, :update_user_credentials) + put("/users/disable_mfa", AdminAPIController, :disable_mfa) + patch("/users/force_password_reset", AdminAPIController, :force_password_reset) + patch("/users/confirm_email", AdminAPIController, :confirm_email) + patch("/users/resend_confirmation_email", AdminAPIController, :resend_confirmation_email) end # AdminAPI: admins and mods (staff) can perform these actions (if privileged by role) diff --git a/test/pleroma/web/admin_api/controllers/admin_api_controller_test.exs b/test/pleroma/web/admin_api/controllers/admin_api_controller_test.exs index 372f4fe63..e1ab50542 100644 --- a/test/pleroma/web/admin_api/controllers/admin_api_controller_test.exs +++ b/test/pleroma/web/admin_api/controllers/admin_api_controller_test.exs @@ -352,6 +352,8 @@ test "it requires privileged role :users_manage_credentials", %{conn: conn} do describe "PUT disable_mfa" do test "returns 200 and disable 2fa", %{conn: conn} do + clear_config([:instance, :admin_privileges], [:users_manage_credentials]) + user = insert(:user, multi_factor_authentication_settings: %MFA.Settings{ @@ -373,6 +375,8 @@ test "returns 200 and disable 2fa", %{conn: conn} do end test "returns 404 if user not found", %{conn: conn} do + clear_config([:instance, :admin_privileges], [:users_manage_credentials]) + response = conn |> put("/api/pleroma/admin/users/disable_mfa", %{nickname: "nickname"}) @@ -380,6 +384,16 @@ test "returns 404 if user not found", %{conn: conn} do assert response == %{"error" => "Not found"} end + + test "it requires privileged role :users_manage_credentials", %{conn: conn} do + clear_config([:instance, :admin_privileges], []) + + response = + conn + |> put("/api/pleroma/admin/users/disable_mfa", %{nickname: "nickname"}) + + assert json_response(response, :forbidden) + end end describe "GET /api/pleroma/admin/restart" do @@ -785,6 +799,7 @@ test "gets a remote users when [:instance, :limit_to_local_content] is set to :u describe "GET /users/:nickname/credentials" do test "gets the user credentials", %{conn: conn} do + clear_config([:instance, :admin_privileges], [:users_manage_credentials]) user = insert(:user) conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}/credentials") @@ -793,6 +808,7 @@ test "gets the user credentials", %{conn: conn} do end test "returns 403 if requested by a non-admin" do + clear_config([:instance, :admin_privileges], [:users_manage_credentials]) user = insert(:user) conn = @@ -802,6 +818,16 @@ test "returns 403 if requested by a non-admin" do assert json_response(conn, :forbidden) end + + test "it requires privileged role :users_manage_credentials", %{conn: conn} do + clear_config([:instance, :admin_privileges], []) + + response = + conn + |> get("/api/pleroma/admin/users/nickname/credentials") + + assert json_response(response, :forbidden) + end end describe "PATCH /users/:nickname/credentials" do @@ -896,6 +922,7 @@ test "update non existing user", %{conn: conn} do describe "PATCH /users/:nickname/force_password_reset" do test "sets password_reset_pending to true", %{conn: conn} do + clear_config([:instance, :admin_privileges], [:users_manage_credentials]) user = insert(:user) assert user.password_reset_pending == false @@ -908,10 +935,21 @@ test "sets password_reset_pending to true", %{conn: conn} do assert User.get_by_id(user.id).password_reset_pending == true end + + test "it requires privileged role :users_manage_credentials", %{conn: conn} do + clear_config([:instance, :admin_privileges], []) + + response = + conn + |> patch("/api/pleroma/admin/users/force_password_reset", %{nickname: "nickname"}) + + assert json_response(response, :forbidden) + end end describe "PATCH /confirm_email" do test "it confirms emails of two users", %{conn: conn, admin: admin} do + clear_config([:instance, :admin_privileges], [:users_manage_credentials]) [first_user, second_user] = insert_pair(:user, is_confirmed: false) refute first_user.is_confirmed @@ -938,10 +976,21 @@ test "it confirms emails of two users", %{conn: conn, admin: admin} do assert ModerationLog.get_log_entry_message(log_entry) == "@#{admin.nickname} confirmed email for users: @#{first_user.nickname}, @#{second_user.nickname}" end + + test "it requires privileged role :users_manage_credentials", %{conn: conn} do + clear_config([:instance, :admin_privileges], []) + + response = + conn + |> patch("/api/pleroma/admin/users/confirm_email", %{nicknames: ["nickname"]}) + + assert json_response(response, :forbidden) + end end describe "PATCH /resend_confirmation_email" do test "it resend emails for two users", %{conn: conn, admin: admin} do + clear_config([:instance, :admin_privileges], [:users_manage_credentials]) [first_user, second_user] = insert_pair(:user, is_confirmed: false) ret_conn = @@ -967,6 +1016,16 @@ test "it resend emails for two users", %{conn: conn, admin: admin} do |> Swoosh.Email.put_private(:hackney_options, ssl_options: [versions: [:"tlsv1.2"]]) |> assert_email_sent() end + + test "it requires privileged role :users_manage_credentials", %{conn: conn} do + clear_config([:instance, :admin_privileges], []) + + response = + conn + |> patch("/api/pleroma/admin/users/resend_confirmation_email", %{nicknames: ["nickname"]}) + + assert json_response(response, :forbidden) + end end describe "/api/pleroma/admin/stats" do From c58eb873dd47ebd1b207c9f79ccffe2c3819949d Mon Sep 17 00:00:00 2001 From: Sean King Date: Sun, 18 Dec 2022 22:05:07 -0700 Subject: [PATCH 52/54] Fix CommonAPI delete function to use User.privileged? instead of User.superuser? --- lib/pleroma/web/common_api.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pleroma/web/common_api.ex b/lib/pleroma/web/common_api.ex index 97f2aec3b..89cc0d6fe 100644 --- a/lib/pleroma/web/common_api.ex +++ b/lib/pleroma/web/common_api.ex @@ -148,7 +148,7 @@ def delete(activity_id, user) do true <- User.privileged?(user, :messages_delete) || user.ap_id == object.data["actor"], {:ok, delete_data, _} <- Builder.delete(user, object.data["id"]), {:ok, delete, _} <- Pipeline.common_pipeline(delete_data, local: true) do - if User.superuser?(user) and user.ap_id != object.data["actor"] do + if User.privileged?(user, :messages_delete) and user.ap_id != object.data["actor"] do action = if object.data["type"] == "ChatMessage" do "chat_message_delete" From 351b5a9df406a8a093d10dec3cdfa3bb2d709efb Mon Sep 17 00:00:00 2001 From: Sean King Date: Wed, 21 Dec 2022 23:35:39 -0700 Subject: [PATCH 53/54] Use crazy hack to finally get pleroma:report notifications not visible after revoking privileges --- lib/pleroma/web/mastodon_api/mastodon_api.ex | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/pleroma/web/mastodon_api/mastodon_api.ex b/lib/pleroma/web/mastodon_api/mastodon_api.ex index c51230b92..98bf90af7 100644 --- a/lib/pleroma/web/mastodon_api/mastodon_api.ex +++ b/lib/pleroma/web/mastodon_api/mastodon_api.ex @@ -65,7 +65,8 @@ def get_notifications(user, params \\ %{}) do cast_params(params) |> Map.update(:include_types, [], fn include_types -> include_types end) options = - if "pleroma:report" not in options.include_types or + if ("pleroma:report" not in options.include_types and + User.privileged?(user, :reports_manage_reports)) or User.privileged?(user, :reports_manage_reports) do options else From 90681c720d4c0530b67b0105db1204fff82835d8 Mon Sep 17 00:00:00 2001 From: Sean King Date: Wed, 21 Dec 2022 23:40:39 -0700 Subject: [PATCH 54/54] Make lint happy --- lib/pleroma/web/mastodon_api/mastodon_api.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pleroma/web/mastodon_api/mastodon_api.ex b/lib/pleroma/web/mastodon_api/mastodon_api.ex index 98bf90af7..467dc2fac 100644 --- a/lib/pleroma/web/mastodon_api/mastodon_api.ex +++ b/lib/pleroma/web/mastodon_api/mastodon_api.ex @@ -66,7 +66,7 @@ def get_notifications(user, params \\ %{}) do options = if ("pleroma:report" not in options.include_types and - User.privileged?(user, :reports_manage_reports)) or + User.privileged?(user, :reports_manage_reports)) or User.privileged?(user, :reports_manage_reports) do options else