diff options
41 files changed, 1636 insertions, 420 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md index f1beb0cd0..e1cb0243b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,8 +18,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 @@ -31,6 +29,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...)  - Uploadfilter `Pleroma.Upload.Filter.Exiftool.ReadDescription` returns description values to the FE so they can pre fill the image description field  ### Fixed diff --git a/config/config.exs b/config/config.exs index 6a5acda09..994d333aa 100644 --- a/config/config.exs +++ b/config/config.exs @@ -256,7 +256,22 @@ config :pleroma, :instance,    show_reactions: true,    password_reset_token_validity: 60 * 60 * 24,    profile_directory: true, -  privileged_staff: false, +  admin_privileges: [ +    :users_read, +    :users_manage_invites, +    :users_manage_activation_state, +    :users_manage_tags, +    :users_manage_credentials, +    :users_delete, +    :messages_read, +    :messages_delete, +    :instances_delete, +    :reports_manage_reports, +    :moderation_log_read, +    :emoji_manage_emoji, +    :statistics_read +  ], +  moderator_privileges: [],    max_endorsed_users: 20,    birthday_required: false,    birthday_min_age: 0, diff --git a/config/description.exs b/config/description.exs index 7caad18b4..b3b3a3a1e 100644 --- a/config/description.exs +++ b/config/description.exs @@ -961,10 +961,46 @@ config :pleroma, :config_description, [          description: "Enable profile directory."        },        %{ -        key: :privileged_staff, -        type: :boolean, +        key: :admin_privileges, +        type: {:list, :atom}, +        suggestions: [ +          :users_read, +          :users_manage_invites, +          :users_manage_activation_state, +          :users_manage_tags, +          :users_manage_credentials, +          :users_delete, +          :messages_read, +          :messages_delete, +          :instances_delete, +          :reports_manage_reports, +          :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)" +      }, +      %{ +        key: :moderator_privileges, +        type: {:list, :atom}, +        suggestions: [ +          :users_read, +          :users_manage_invites, +          :users_manage_activation_state, +          :users_manage_tags, +          :users_manage_credentials, +          :users_delete, +          :messages_read, +          :messages_delete, +          :instances_delete, +          :reports_manage_reports, +          :moderation_log_read, +          :emoji_manage_emoji, +          :statistics_read +        ],          description: -          "Let moderators access sensitive data (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/configuration/cheatsheet.md b/docs/configuration/cheatsheet.md index 74642397b..9cf7ce499 100644 --- a/docs/configuration/cheatsheet.md +++ b/docs/configuration/cheatsheet.md @@ -64,6 +64,36 @@ 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_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 +      * `: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`  ## :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). 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/notification.ex b/lib/pleroma/notification.ex index 52fd2656b..cfc4bfca3 100644 --- a/lib/pleroma/notification.ex +++ b/lib/pleroma/notification.ex @@ -341,14 +341,6 @@ defmodule Pleroma.Notification 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) @@ -550,7 +542,9 @@ defmodule Pleroma.Notification do    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(:reports_manage_reports) +     |> Enum.map(fn user -> user.ap_id end)) -- +      [actor]    end    def get_potential_receiver_ap_ids(activity) do diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex index 747a83e8d..11c4d0684 100644 --- a/lib/pleroma/user.ex +++ b/lib/pleroma/user.ex @@ -326,7 +326,7 @@ defmodule Pleroma.User do    end    def visible_for(%User{} = user, for_user) do -    if superuser?(for_user) do +    if privileged?(for_user, :users_manage_activation_state) do        :visible      else        visible_account_status(user) @@ -353,10 +353,45 @@ defmodule Pleroma.User do      end    end -  @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 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 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 @@ -1129,24 +1164,10 @@ defmodule Pleroma.User 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 @@ -2206,6 +2227,11 @@ defmodule Pleroma.User 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 @@ defmodule Pleroma.User.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/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex index 064f93b22..06c894efd 100644 --- a/lib/pleroma/web/activity_pub/activity_pub.ex +++ b/lib/pleroma/web/activity_pub/activity_pub.ex @@ -392,11 +392,11 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do           _ <- notify_and_stream(activity),           :ok <-             maybe_federate(stripped_activity) do -      User.all_superusers() +      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 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/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 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.CommonValidations 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..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 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.DeleteValidator do      |> validate_required([:id, :type, :actor, :to, :cc, :object])      |> validate_inclusion(:type, ["Delete"])      |> validate_delete_actor(:actor) -    |> validate_modification_rights() +    |> 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 1b95ee89c..4ac5df63f 100644 --- a/lib/pleroma/web/common_api.ex +++ b/lib/pleroma/web/common_api.ex @@ -144,7 +144,7 @@ defmodule Pleroma.Web.CommonAPI 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, :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 5e32b9611..932e5d4eb 100644 --- a/lib/pleroma/web/mastodon_api/mastodon_api.ex +++ b/lib/pleroma/web/mastodon_api/mastodon_api.ex @@ -61,7 +61,19 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPI 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, :reports_manage_reports) 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/lib/pleroma/web/mastodon_api/views/account_view.ex b/lib/pleroma/web/mastodon_api/views/account_view.ex index 988eedbb1..34b34dc19 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 @@ defmodule Pleroma.Web.MastodonAPI.AccountView do    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 +    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_role(data, _, _), do: data -    defp maybe_put_notification_settings(data, %User{id: user_id} = user, %User{id: user_id}) do      Kernel.put_in(        data, @@ -398,12 +401,12 @@ defmodule Pleroma.Web.MastodonAPI.AccountView do    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, :users_manage_activation_state), +      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/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 @@ defmodule Pleroma.Web.MastodonAPI.InstanceView 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..9e27ac26c 100644 --- a/lib/pleroma/web/nodeinfo/nodeinfo.ex +++ b/lib/pleroma/web/nodeinfo/nodeinfo.ex @@ -49,6 +49,10 @@ defmodule Pleroma.Web.Nodeinfo.Nodeinfo 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]), @@ -69,8 +73,7 @@ defmodule Pleroma.Web.Nodeinfo.Nodeinfo 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_privileged_plug.ex b/lib/pleroma/web/plugs/ensure_privileged_plug.ex new file mode 100644 index 000000000..f886c87ea --- /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 <https://pleroma.social/> +# 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, +        privilege +      ) 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 +      |> 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/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 <https://pleroma.social/> -# 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 7bbc20275..e715aaa96 100644 --- a/lib/pleroma/web/router.ex +++ b/lib/pleroma/web/router.ex @@ -101,14 +101,75 @@ 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 +  pipeline :require_privileged_role_users_delete do +    plug(:admin_api) +    plug(Pleroma.Web.Plugs.EnsurePrivilegedPlug, :users_delete) +  end + +  pipeline :require_privileged_role_users_manage_credentials do +    plug(:admin_api) +    plug(Pleroma.Web.Plugs.EnsurePrivilegedPlug, :users_manage_credentials) +  end + +  pipeline :require_privileged_role_messages_read do +    plug(:admin_api) +    plug(Pleroma.Web.Plugs.EnsurePrivilegedPlug, :messages_read) +  end + +  pipeline :require_privileged_role_users_manage_tags do +    plug(:admin_api) +    plug(Pleroma.Web.Plugs.EnsurePrivilegedPlug, :users_manage_tags) +  end + +  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_users_manage_invites do +    plug(:admin_api) +    plug(Pleroma.Web.Plugs.EnsurePrivilegedPlug, :users_manage_invites) +  end + +  pipeline :require_privileged_role_reports_manage_reports do +    plug(:admin_api) +    plug(Pleroma.Web.Plugs.EnsurePrivilegedPlug, :reports_manage_reports) +  end + +  pipeline :require_privileged_role_users_read do +    plug(:admin_api) +    plug(Pleroma.Web.Plugs.EnsurePrivilegedPlug, :users_read) +  end + +  pipeline :require_privileged_role_messages_delete do +    plug(:admin_api) +    plug(Pleroma.Web.Plugs.EnsurePrivilegedPlug, :messages_delete) +  end + +  pipeline :require_privileged_role_emoji_manage_emoji do +    plug(:admin_api) +    plug(Pleroma.Web.Plugs.EnsurePrivilegedPlug, :emoji_manage_emoji) +  end + +  pipeline :require_privileged_role_instances_delete do +    plug(:admin_api) +    plug(Pleroma.Web.Plugs.EnsurePrivilegedPlug, :instances_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_statistics_read do +    plug(:admin_api) +    plug(Pleroma.Web.Plugs.EnsurePrivilegedPlug, :statistics_read) +  end +    pipeline :pleroma_html do      plug(:browser)      plug(:authenticate) @@ -201,7 +262,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) @@ -237,14 +297,24 @@ defmodule Pleroma.Web.Router do      delete("/announcements/:id", AnnouncementController, :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(: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_users_manage_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 privileged by role) +  scope "/api/v1/pleroma/admin", Pleroma.Web.AdminAPI do +    pipe_through(:require_privileged_role_messages_read)      get("/users/:nickname/statuses", AdminAPIController, :list_user_statuses)      get("/users/:nickname/chats", AdminAPIController, :list_user_chats) @@ -253,52 +323,100 @@ 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 +  # 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_users_manage_tags)      put("/users/tag", AdminAPIController, :tag_users)      delete("/users/tag", AdminAPIController, :untag_users) +  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_users_manage_activation_state)      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 (if privileged by role) +  scope "/api/v1/pleroma/admin", Pleroma.Web.AdminAPI do +    pipe_through(:require_privileged_role_users_manage_invites) +    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 -    get("/users", UserController, :index) -    get("/users/:nickname", UserController, :show) - -    get("/instances/:instance/statuses", InstanceController, :list_statuses) -    delete("/instances/:instance", InstanceController, :delete) +  # 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_reports_manage_reports)      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 (if privileged by role) +  scope "/api/v1/pleroma/admin", Pleroma.Web.AdminAPI do +    pipe_through(:require_privileged_role_users_read) + +    get("/users", UserController, :index) +    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_messages_delete) -    get("/statuses/:id", StatusController, :show)      put("/statuses/:id", StatusController, :update)      delete("/statuses/:id", StatusController, :delete) -    get("/moderation_log", AdminAPIController, :list_log) +    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_manage_emoji)      post("/reload_emoji", AdminAPIController, :reload_emoji) -    get("/stats", AdminAPIController, :stats) +  end -    delete("/chats/:id/messages/:message_id", ChatController, :delete_message) +  # 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_instances_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_statistics_read) + +    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_manage_emoji)        post("/", EmojiPackController, :create)        patch("/", EmojiPackController, :update) @@ -313,7 +431,7 @@ defmodule Pleroma.Web.Router do      # Modifying packs      scope "/packs" do -      pipe_through(:admin_api) +      pipe_through(:require_privileged_role_emoji_manage_emoji)        get("/import", EmojiPackController, :import_from_filesystem)        get("/remote", EmojiPackController, :remote) diff --git a/test/pleroma/notification_test.exs b/test/pleroma/notification_test.exs index 805764ea4..d0f34113b 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 @@ defmodule Pleroma.NotificationTest 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], [:reports_manage_reports]) +      {: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], [:reports_manage_reports]) +        reporting_admin = insert(:user, is_admin: true)        reported_user = insert(:user)        other_admin = insert(:user, is_admin: true) @@ -520,25 +526,6 @@ defmodule Pleroma.NotificationTest 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/query_test.exs b/test/pleroma/user/query_test.exs index bd45d1bca..30a4637f2 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,63 @@ defmodule Pleroma.User.QueryTest 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" do +      clear_config([:instance, :admin_privileges], []) +      clear_config([:instance, :moderator_privileges], []) + +      assert [] = User.Query.build(%{is_privileged: :cofe}) |> Repo.all() +    end + +    test "returns moderator users if they are privileged", %{ +      moderator_user: moderator_user, +      admin_moderator_user: admin_moderator_user +    } do +      clear_config([:instance, :admin_privileges], []) +      clear_config([:instance, :moderator_privileges], [:cofe]) + +      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()) +    end + +    test "returns admin users if they are privileged", %{ +      admin_user: admin_user, +      admin_moderator_user: admin_moderator_user +    } do +      clear_config([:instance, :admin_privileges], [:cofe]) +      clear_config([:instance, :moderator_privileges], []) + +      assert [_, _] = User.Query.build(%{is_privileged: :cofe}) |> Repo.all() +      assert admin_user in (User.Query.build(%{is_privileged: :cofe}) |> Repo.all()) +      assert admin_moderator_user in (User.Query.build(%{is_privileged: :cofe}) |> Repo.all()) +    end + +    test "returns admin and moderator users if they are both privileged", %{ +      moderator_user: moderator_user, +      admin_user: admin_user, +      admin_moderator_user: admin_moderator_user +    } do +      clear_config([:instance, :admin_privileges], [:cofe]) +      clear_config([:instance, :moderator_privileges], [:cofe]) + +      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()) +    end +  end  end diff --git a/test/pleroma/user_test.exs b/test/pleroma/user_test.exs index 884b846ae..25ec44834 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 @@ -13,7 +12,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 @@ -473,12 +472,7 @@ defmodule Pleroma.UserTest 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", ""}]) @@ -1883,31 +1877,82 @@ defmodule Pleroma.UserTest do      end    end -  describe "superuser?/1" do +  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.superuser?(user) +      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.superuser?(user) -      refute User.superuser?(remote_admin_user) +      refute User.privileged?(user, :cofe) +      refute User.privileged?(remote_admin_user, :cofe)      end -    test "returns true for local moderators" do +    test "returns true for local moderators if, and only if, they are privileged" do        user = insert(:user, local: true, is_moderator: true) -      assert User.superuser?(user) +      assert User.privileged?(user, :cofe) + +      clear_config([:instance, :moderator_privileges], []) + +      refute User.privileged?(user, :cofe)      end -    test "returns true for local admins" do +    test "returns true for local admins if, and only if, they are privileged" do        user = insert(:user, local: true, is_admin: true) -      assert User.superuser?(user) +      assert User.privileged?(user, :cofe) + +      clear_config([:instance, :admin_privileges], []) + +      refute User.privileged?(user, :cofe) +    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 @@ -1950,13 +1995,77 @@ defmodule Pleroma.UserTest do        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 :users_manage_activation_state, confirmation required)" do        clear_config([:instance, :account_activation_required], true) +      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)        assert User.visible_for(user, other_user) == :visible + +      clear_config([:instance, :admin_privileges], []) + +      refute User.visible_for(user, other_user) == :visible +    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" do +      clear_config([:instance, :admin_privileges], []) +      clear_config([:instance, :moderator_privileges], []) + +      assert [] = User.Query.build(%{is_privileged: :cofe}) |> Repo.all() +    end + +    test "returns moderator users if they are privileged", %{ +      moderator_user: moderator_user, +      admin_moderator_user: admin_moderator_user +    } do +      clear_config([:instance, :admin_privileges], []) +      clear_config([:instance, :moderator_privileges], [: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) +    end + +    test "returns admin users if they are privileged", %{ +      admin_user: admin_user, +      admin_moderator_user: admin_moderator_user +    } do +      clear_config([:instance, :admin_privileges], [:cofe]) +      clear_config([:instance, :moderator_privileges], []) + +      assert [_, _] = User.Query.build(%{is_privileged: :cofe}) |> Repo.all() +      assert admin_user in User.all_users_with_privilege(:cofe) +      assert admin_moderator_user in User.all_users_with_privilege(:cofe) +    end + +    test "returns admin and moderator users if they are both privileged", %{ +      moderator_user: moderator_user, +      admin_user: admin_user, +      admin_moderator_user: admin_moderator_user +    } do +      clear_config([:instance, :admin_privileges], [:cofe]) +      clear_config([:instance, :moderator_privileges], [: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)      end    end @@ -2211,26 +2320,6 @@ defmodule Pleroma.UserTest 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 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..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 @@ -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 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.DeleteValidationTest do        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], [:messages_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 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..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 @@ -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 @@ -92,18 +92,12 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do    describe "PUT /api/pleroma/admin/users/tag" do      setup %{conn: conn} do +      clear_config([:instance, :admin_privileges], [:users_manage_tags]) +        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 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do        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 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do                 "@#{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 :users_manage_tags", %{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], [:users_manage_tags])        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 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do        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 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do                 "@#{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 :users_manage_tags", %{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 @@ -271,17 +322,32 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do      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], [:users_manage_credentials]) -    conn = -      conn -      |> put_req_header("accept", "application/json") -      |> get("/api/pleroma/admin/users/#{user.nickname}/password_reset") +      user = insert(:user) + +      conn = +        conn +        |> put_req_header("accept", "application/json") +        |> get("/api/pleroma/admin/users/#{user.nickname}/password_reset") + +      resp = json_response(conn, 200) + +      assert Regex.match?(~r/(http:\/\/|https:\/\/)/, resp["link"]) +    end + +    test "it requires privileged role :users_manage_credentials", %{conn: conn} do +      clear_config([:instance, :admin_privileges], []) -    resp = json_response(conn, 200) +      response = +        conn +        |> put_req_header("accept", "application/json") +        |> get("/api/pleroma/admin/users/nickname/password_reset") -    assert Regex.match?(~r/(http:\/\/|https:\/\/)/, resp["link"]) +      assert json_response(response, :forbidden) +    end    end    describe "PUT disable_mfa" do @@ -344,6 +410,8 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do    describe "GET /api/pleroma/admin/users/:nickname/statuses" do      setup do +      clear_config([:instance, :admin_privileges], [:messages_read]) +        user = insert(:user)        insert(:note_activity, user: user) @@ -360,6 +428,14 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do        assert length(activities) == 3      end +    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") + +      assert json_response(conn, :forbidden) +    end +      test "renders user's statuses with pagination", %{conn: conn, user: user} do        %{"total" => 3, "activities" => [activity1]} =          conn @@ -421,20 +497,31 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do    describe "GET /api/pleroma/admin/users/:nickname/chats" do      setup do +      clear_config([:instance, :admin_privileges], [:messages_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} +      conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}/chats") + +      assert json_response(conn, 200) |> length() == 3      end -    test "renders user's chats", %{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") -      assert json_response(conn, 200) |> length() == 3 +      assert json_response(conn, :forbidden)      end    end @@ -471,6 +558,7 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest 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} @@ -675,6 +763,15 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest 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", @@ -714,6 +811,8 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do      end      test "changes password and email", %{conn: conn, admin: admin, user: user} do +      clear_config([:instance, :admin_privileges], [:users_manage_credentials]) +        assert user.password_reset_pending == false        conn = @@ -756,6 +855,19 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do        assert json_response(conn, :forbidden)      end +    test "returns 403 if not privileged with :users_manage_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" @@ -858,6 +970,10 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do    end    describe "/api/pleroma/admin/stats" do +    setup do +      clear_config([:instance, :admin_privileges], [:statistics_read]) +    end +      test "status visibility count", %{conn: conn} do        user = insert(:user)        CommonAPI.post(user, %{visibility: "public", status: "hey"}) @@ -890,6 +1006,14 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do        assert %{"direct" => 0, "private" => 1, "public" => 0, "unlisted" => 1} =                 response["status_visibility"]      end + +    test "it requires privileged role :statistics_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 @@ -958,6 +1082,34 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest 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_manage_emoji]) + +      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_manage_emoji", %{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/admin_api/controllers/chat_controller_test.exs b/test/pleroma/web/admin_api/controllers/chat_controller_test.exs index ccf25a244..aa47b74e8 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 @@ -27,7 +27,10 @@ defmodule Pleroma.Web.AdminAPI.ChatControllerTest do    end    describe "DELETE /api/pleroma/admin/chats/:id/messages/:message_id" do -    setup do: admin_setup() +    setup do +      clear_config([:instance, :admin_privileges], [:messages_delete]) +      admin_setup() +    end      test "it deletes a message from the chat", %{conn: conn, admin: admin} do        user = insert(:user) @@ -60,10 +63,22 @@ defmodule Pleroma.Web.AdminAPI.ChatControllerTest 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 :messages_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 -    setup do: admin_setup() +    setup do +      clear_config([:instance, :admin_privileges], [:messages_read]) +      admin_setup() +    end      test "it paginates", %{conn: conn} do        user = insert(:user) @@ -114,10 +129,21 @@ defmodule Pleroma.Web.AdminAPI.ChatControllerTest do        assert length(result) == 3      end + +    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") + +      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], [:messages_read]) +      admin_setup() +    end      test "it returns a chat", %{conn: conn} do        user = insert(:user) @@ -135,6 +161,14 @@ defmodule Pleroma.Web.AdminAPI.ChatControllerTest do        assert %{} = result["receiver"]        refute result["account"]      end + +    test "it requires privileged role :messages_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/instance_controller_test.exs b/test/pleroma/web/admin_api/controllers/instance_controller_test.exs index 72436cd83..6cca623f3 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], [: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) @@ -60,9 +61,14 @@ defmodule Pleroma.Web.AdminAPI.InstanceControllerTest 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 +    clear_config([:instance, :admin_privileges], [:instances_delete])      user = insert(:user, nickname: "lain@lain.com")      post = insert(:note_activity, user: user) @@ -76,5 +82,11 @@ defmodule Pleroma.Web.AdminAPI.InstanceControllerTest do      assert response == "lain.com"      refute Repo.reload(user).is_active      refute Repo.reload(post) + +    clear_config([:instance, :admin_privileges], []) + +    conn +    |> delete("/api/pleroma/admin/instances/lain.com") +    |> json_response(:forbidden)    end  end 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..8051cb2e9 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 @@ -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], [:users_manage_invites]) +    end + +    test "returns 403 if not privileged with :users_manage_invites", %{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 @@ defmodule Pleroma.Web.AdminAPI.InviteControllerTest 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], [:users_manage_invites]) +    end      test "it returns 500 if `invites_enabled` is not enabled", %{conn: conn} do        clear_config([:instance, :registrations_open], false) @@ -157,6 +177,21 @@ defmodule Pleroma.Web.AdminAPI.InviteControllerTest do    end    describe "POST /api/pleroma/admin/users/invite_token" do +    setup do +      clear_config([:instance, :admin_privileges], [:users_manage_invites]) +    end + +    test "returns 403 if not privileged with :users_manage_invites", %{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 @@ defmodule Pleroma.Web.AdminAPI.InviteControllerTest do    end    describe "GET /api/pleroma/admin/users/invites" do +    setup do +      clear_config([:instance, :admin_privileges], [:users_manage_invites]) +    end + +    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") + +      assert json_response(conn, :forbidden) +    end +      test "no invites", %{conn: conn} do        conn = get(conn, "/api/pleroma/admin/users/invites") @@ -249,6 +296,21 @@ defmodule Pleroma.Web.AdminAPI.InviteControllerTest do    end    describe "POST /api/pleroma/admin/users/revoke_invite" do +    setup do +      clear_config([:instance, :admin_privileges], [:users_manage_invites]) +    end + +    test "returns 403 if not privileged with :users_manage_invites", %{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/report_controller_test.exs b/test/pleroma/web/admin_api/controllers/report_controller_test.exs index 30dcb87e2..b155cf01a 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 @@ -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], [:reports_manage_reports]) +    end + +    test "returns 403 if not privileged with :reports_manage_reports", %{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 @@ defmodule Pleroma.Web.AdminAPI.ReportControllerTest do    describe "PATCH /api/pleroma/admin/reports" do      setup do +      clear_config([:instance, :admin_privileges], [:reports_manage_reports]) +        [reporter, target_user] = insert_pair(:user)        activity = insert(:note_activity, user: target_user) @@ -86,6 +102,24 @@ defmodule Pleroma.Web.AdminAPI.ReportControllerTest do        }      end +    test "returns 403 if not privileged with :reports_manage_reports", %{ +      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 +243,20 @@ defmodule Pleroma.Web.AdminAPI.ReportControllerTest do    end    describe "GET /api/pleroma/admin/reports" do +    setup do +      clear_config([:instance, :admin_privileges], [:reports_manage_reports]) +    end + +    test "returns 403 if not privileged with :reports_manage_reports", %{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 +365,8 @@ defmodule Pleroma.Web.AdminAPI.ReportControllerTest do    describe "POST /api/pleroma/admin/reports/:id/notes" do      setup %{conn: conn, admin: admin} do +      clear_config([:instance, :admin_privileges], [:reports_manage_reports]) +        [reporter, target_user] = insert_pair(:user)        activity = insert(:note_activity, user: target_user) @@ -345,6 +395,25 @@ defmodule Pleroma.Web.AdminAPI.ReportControllerTest do        }      end +    test "returns 403 if not privileged with :reports_manage_reports", %{ +      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) 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..8908a2812 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 @@ -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], [:messages_read]) +    end +      test "not found", %{conn: conn} do        assert conn               |> get("/api/pleroma/admin/statuses/not_found") @@ -50,10 +54,17 @@ defmodule Pleroma.Web.AdminAPI.StatusControllerTest 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      setup do +      clear_config([:instance, :admin_privileges], [:messages_delete])        activity = insert(:note_activity)        %{id: activity.id} @@ -122,10 +133,20 @@ defmodule Pleroma.Web.AdminAPI.StatusControllerTest do        assert %{"error" => "test - Invalid value for enum."} =                 json_response_and_validate_schema(conn, :bad_request)      end + +    test "it requires privileged role :messages_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], [:messages_delete])        activity = insert(:note_activity)        %{id: activity.id} @@ -149,9 +170,22 @@ defmodule Pleroma.Web.AdminAPI.StatusControllerTest do        assert json_response_and_validate_schema(conn, :not_found) == %{"error" => "Not found"}      end + +    test "it requires privileged role :messages_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 +    setup do +      clear_config([:instance, :admin_privileges], [:messages_read]) +    end +      test "returns all public and unlisted statuses", %{conn: conn, admin: admin} do        blocked = insert(:user)        user = insert(:user) @@ -197,5 +231,13 @@ defmodule Pleroma.Web.AdminAPI.StatusControllerTest do        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 :messages_read", %{conn: conn} do +      clear_config([:instance, :admin_privileges], []) + +      conn = get(conn, "/api/pleroma/admin/statuses") + +      assert json_response(conn, :forbidden) +    end    end  end 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..bb9dcb4aa 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 @@ -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], [:users_read])      clear_config([:admin_token], "password123")      user = insert(:user) @@ -47,53 +48,10 @@ defmodule Pleroma.Web.AdminAPI.UserControllerTest 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) +      clear_config([:instance, :admin_privileges], [:users_delete])        user =          insert(:user, @@ -149,6 +107,8 @@ defmodule Pleroma.Web.AdminAPI.UserControllerTest do      end      test "multiple users", %{admin: admin, conn: conn} do +      clear_config([:instance, :admin_privileges], [:users_delete]) +        user_one = insert(:user)        user_two = insert(:user) @@ -168,6 +128,17 @@ defmodule Pleroma.Web.AdminAPI.UserControllerTest 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 @@ -307,7 +278,19 @@ defmodule Pleroma.Web.AdminAPI.UserControllerTest 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], [:users_read]) +    end + +    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") + +      assert json_response(conn, :forbidden) +    end +      test "Show", %{conn: conn} do        user = insert(:user) @@ -323,6 +306,50 @@ defmodule Pleroma.Web.AdminAPI.UserControllerTest 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 @@ -378,6 +405,18 @@ defmodule Pleroma.Web.AdminAPI.UserControllerTest do    end    describe "GET /api/pleroma/admin/users" do +    setup do +      clear_config([:instance, :admin_privileges], [:users_read]) +    end + +    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") + +      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") @@ -810,67 +849,42 @@ defmodule Pleroma.Web.AdminAPI.UserControllerTest 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/approve", %{admin: admin, conn: conn} do +    clear_config([:instance, :admin_privileges], [:users_manage_invites]) -  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) +    user_one = insert(:user, is_approved: false) +    user_two = insert(:user, is_approved: false)      conn =        conn        |> put_req_header("content-type", "application/json")        |> patch( -        "/api/pleroma/admin/users/deactivate", +        "/api/pleroma/admin/users/approve",          %{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] +    assert Enum.map(response["users"], & &1["is_approved"]) == [true, true]      log_entry = Repo.one(ModerationLog)      assert ModerationLog.get_log_entry_message(log_entry) == -             "@#{admin.nickname} deactivated users: @#{user_one.nickname}, @#{user_two.nickname}" +             "@#{admin.nickname} approved 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) +  test "PATCH /api/pleroma/admin/users/approve returns 403 if not privileged with :users_manage_invites", +       %{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]} +        %{nicknames: ["user_one.nickname", "user_two.nickname"]}        ) -    response = json_response_and_validate_schema(conn, 200) -    assert Enum.map(response["users"], & &1["is_approved"]) == [true, true] - -    log_entry = Repo.one(ModerationLog) - -    assert ModerationLog.get_log_entry_message(log_entry) == -             "@#{admin.nickname} approved users: @#{user_one.nickname}, @#{user_two.nickname}" +    assert json_response(conn, :forbidden)    end    test "PATCH /api/pleroma/admin/users/suggest", %{admin: admin, conn: conn} do @@ -923,24 +937,113 @@ defmodule Pleroma.Web.AdminAPI.UserControllerTest 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], [:users_manage_activation_state]) -    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) + +      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_and_validate_schema(conn, 200) == -             user_response( -               user, -               %{"is_active" => !user.is_active} -             ) +      response = json_response_and_validate_schema(conn, 200) +      assert Enum.map(response["users"], & &1["is_active"]) == [true, true] -    log_entry = Repo.one(ModerationLog) +      log_entry = Repo.one(ModerationLog) -    assert ModerationLog.get_log_entry_message(log_entry) == -             "@#{admin.nickname} deactivated users: @#{user.nickname}" +      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], [:users_manage_activation_state]) + +      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], [:users_manage_activation_state]) + +      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 diff --git a/test/pleroma/web/common_api_test.exs b/test/pleroma/web/common_api_test.exs index b502aaa03..25743daae 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 @@ defmodule Pleroma.Web.CommonAPITest 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 @@ defmodule Pleroma.Web.CommonAPITest 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], [:messages_delete])        user = insert(:user)        moderator = insert(:user, is_moderator: true) @@ -343,19 +344,20 @@ defmodule Pleroma.Web.CommonAPITest 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], [:messages_delete])        # This is the user of the ingested activity        _user =          insert(:user, @@ -364,7 +366,7 @@ defmodule Pleroma.Web.CommonAPITest 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 @@ defmodule Pleroma.Web.CommonAPITest 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/notification_controller_test.exs b/test/pleroma/web/mastodon_api/controllers/notification_controller_test.exs index 2b7a95635..696ac8bd9 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 @@ defmodule Pleroma.Web.MastodonAPI.NotificationControllerTest do    end    test "by default, does not contain pleroma:report" do -    %{user: user, conn: conn} = oauth_access(["read:notifications"]) +    clear_config([:instance, :moderator_privileges], [:reports_manage_reports]) + +    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 @@ defmodule Pleroma.Web.MastodonAPI.NotificationControllerTest do      assert [_] = result    end +  test "Pleroma:report is hidden for non-privileged users" do +    clear_config([:instance, :moderator_privileges], [:reports_manage_reports]) + +    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) 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..1d2bb3333 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 @@ defmodule Pleroma.Web.MastodonAPI.StatusControllerTest 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], [:messages_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 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..675c8409a 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 @@ -84,6 +84,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountViewTest do          tags: [],          is_admin: false,          is_moderator: false, +        privileges: [],          is_suggested: false,          hide_favorites: true,          hide_followers: false, @@ -99,6 +100,147 @@ defmodule Pleroma.Web.MastodonAPI.AccountViewTest 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 @@ defmodule Pleroma.Web.MastodonAPI.AccountViewTest do          tags: [],          is_admin: false,          is_moderator: false, +        privileges: [],          is_suggested: false,          hide_favorites: true,          hide_followers: false, @@ -214,8 +357,10 @@ defmodule Pleroma.Web.MastodonAPI.AccountViewTest 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], [:users_manage_activation_state]) + +    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 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..594378be1 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 @@ defmodule Pleroma.Web.MastodonAPI.NotificationViewTest do    end    test "Report notification" do +    clear_config([:instance, :moderator_privileges], [:reports_manage_reports]) +      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) 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 @@ defmodule Pleroma.Web.NodeInfoTest 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 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..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 @@ -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_manage_emoji])        pack_file = "#{@emoji_path}/test_pack/pack.json"        original_content = File.read!(pack_file) @@ -377,5 +378,32 @@ defmodule Pleroma.Web.PleromaAPI.EmojiFileControllerTest do                 })                 |> json_response_and_validate_schema(:bad_request)      end + +    test "it requires privileged role :emoji_manage_emoji", %{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..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 @@ -99,6 +99,10 @@ defmodule Pleroma.Web.PleromaAPI.EmojiPackControllerTest do    end    describe "GET /api/pleroma/emoji/packs/remote" do +    setup do +      clear_config([:instance, :admin_privileges], [:emoji_manage_emoji]) +    end +      test "shareable instance", %{admin_conn: admin_conn, conn: conn} do        resp =          conn @@ -136,6 +140,14 @@ defmodule Pleroma.Web.PleromaAPI.EmojiPackControllerTest do                 "error" => "The requested instance does not support sharing emoji packs"               }      end + +    test "it requires privileged role :emoji_manage_emoji", %{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 @@ defmodule Pleroma.Web.PleromaAPI.EmojiPackControllerTest do    end    describe "POST /api/pleroma/emoji/packs/download" do +    setup do +      clear_config([:instance, :admin_privileges], [:emoji_manage_emoji]) +    end +      test "shared pack from remote and non shared from fallback-src", %{        admin_conn: admin_conn,        conn: conn @@ -344,10 +360,24 @@ defmodule Pleroma.Web.PleromaAPI.EmojiPackControllerTest do                   "The pack was not set as shared and there is no fallback src to download from"               }      end + +    test "it requires privileged role :emoji_manage_emoji", %{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_manage_emoji])        pack_file = "#{@emoji_path}/test_pack/pack.json"        original_content = File.read!(pack_file) @@ -435,9 +465,25 @@ defmodule Pleroma.Web.PleromaAPI.EmojiPackControllerTest do                 "error" => "The fallback archive does not have all files specified in pack.json"               }      end + +    test "it requires privileged role :emoji_manage_emoji", %{ +      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_manage_emoji]) +    end +      test "returns an error on creates pack when file system not writable", %{        admin_conn: admin_conn      } do @@ -520,6 +566,18 @@ defmodule Pleroma.Web.PleromaAPI.EmojiPackControllerTest do                 "error" => "pack name cannot be empty"               }      end + +    test "it requires privileged role :emoji_manage_emoji", %{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 +636,12 @@ defmodule Pleroma.Web.PleromaAPI.EmojiPackControllerTest 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 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..4b6679b66 --- /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 <https://pleroma.social/> +# 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 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) +    conn = assign(build_conn(), :user, user) + +    ret_conn = EnsurePrivilegedPlug.call(conn, :cofe) + +    # privileged 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) + +    # privileged 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 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 <https://pleroma.social/> -# 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  | 
