diff options
Diffstat (limited to 'lib')
| -rw-r--r-- | lib/pleroma/application.ex | 1 | ||||
| -rw-r--r-- | lib/pleroma/plugs/user_is_admin_plug.ex | 1 | ||||
| -rw-r--r-- | lib/pleroma/repo.ex | 35 | ||||
| -rw-r--r-- | lib/pleroma/user.ex | 23 | ||||
| -rw-r--r-- | lib/pleroma/web/activity_pub/mrf/vocabulary_policy.ex | 2 | ||||
| -rw-r--r-- | lib/pleroma/web/activity_pub/transmogrifier.ex | 18 | ||||
| -rw-r--r-- | lib/pleroma/web/admin_api/admin_api_controller.ex | 27 | ||||
| -rw-r--r-- | lib/pleroma/web/common_api/common_api.ex | 16 | ||||
| -rw-r--r-- | lib/pleroma/web/mastodon_api/controllers/notification_controller.ex | 17 | ||||
| -rw-r--r-- | lib/pleroma/web/mastodon_api/controllers/subscription_controller.ex | 2 | ||||
| -rw-r--r-- | lib/pleroma/web/mastodon_api/controllers/timeline_controller.ex | 14 | ||||
| -rw-r--r-- | lib/pleroma/web/mastodon_api/mastodon_api.ex | 8 | ||||
| -rw-r--r-- | lib/pleroma/web/oauth/oauth_controller.ex | 12 | ||||
| -rw-r--r-- | lib/pleroma/web/oauth/scopes.ex | 24 | ||||
| -rw-r--r-- | lib/pleroma/web/pleroma_api/controllers/pleroma_api_controller.ex | 2 | 
15 files changed, 120 insertions, 82 deletions
| diff --git a/lib/pleroma/application.ex b/lib/pleroma/application.ex index 2ae052069..e17068876 100644 --- a/lib/pleroma/application.ex +++ b/lib/pleroma/application.ex @@ -33,6 +33,7 @@ defmodule Pleroma.Application do    def start(_type, _args) do      Pleroma.HTML.compile_scrubbers()      Pleroma.Config.DeprecationWarnings.warn() +    Pleroma.Repo.check_migrations_applied!()      setup_instrumenters()      load_custom_modules() diff --git a/lib/pleroma/plugs/user_is_admin_plug.ex b/lib/pleroma/plugs/user_is_admin_plug.ex index 582fb1f92..3190163d3 100644 --- a/lib/pleroma/plugs/user_is_admin_plug.ex +++ b/lib/pleroma/plugs/user_is_admin_plug.ex @@ -23,6 +23,7 @@ defmodule Pleroma.Plugs.UserIsAdminPlug do        token && OAuth.Scopes.contains_admin_scopes?(token.scopes) ->          # Note: checking for _any_ admin scope presence, not necessarily fitting requested action.          #   Thus, controller must explicitly invoke OAuthScopesPlug to verify scope requirements. +        #   Admin might opt out of admin scope for some apps to block any admin actions from them.          conn        true -> diff --git a/lib/pleroma/repo.ex b/lib/pleroma/repo.ex index f57e088bc..cb0b6653c 100644 --- a/lib/pleroma/repo.ex +++ b/lib/pleroma/repo.ex @@ -8,6 +8,8 @@ defmodule Pleroma.Repo do      adapter: Ecto.Adapters.Postgres,      migration_timestamps: [type: :naive_datetime_usec] +  require Logger +    defmodule Instrumenter do      use Prometheus.EctoInstrumenter    end @@ -47,4 +49,37 @@ defmodule Pleroma.Repo do        _ -> {:error, :not_found}      end    end + +  def check_migrations_applied!() do +    unless Pleroma.Config.get( +             [:i_am_aware_this_may_cause_data_loss, :disable_migration_check], +             false +           ) do +      Ecto.Migrator.with_repo(__MODULE__, fn repo -> +        down_migrations = +          Ecto.Migrator.migrations(repo) +          |> Enum.reject(fn +            {:up, _, _} -> true +            {:down, _, _} -> false +          end) + +        if length(down_migrations) > 0 do +          down_migrations_text = +            Enum.map(down_migrations, fn {:down, id, name} -> "- #{name} (#{id})\n" end) + +          Logger.error( +            "The following migrations were not applied:\n#{down_migrations_text}If you want to start Pleroma anyway, set\nconfig :pleroma, :i_am_aware_this_may_cause_data_loss, disable_migration_check: true" +          ) + +          raise Pleroma.Repo.UnappliedMigrationsError +        end +      end) +    else +      :ok +    end +  end +end + +defmodule Pleroma.Repo.UnappliedMigrationsError do +  defexception message: "Unapplied Migrations detected"  end diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex index 2e225415c..430f04ae9 100644 --- a/lib/pleroma/user.ex +++ b/lib/pleroma/user.ex @@ -1874,22 +1874,13 @@ defmodule Pleroma.User do    end    def admin_api_update(user, params) do -    changeset = -      cast(user, params, [ -        :is_moderator, -        :is_admin, -        :show_role -      ]) - -    with {:ok, updated_user} <- update_and_set_cache(changeset) do -      if user.is_admin != updated_user.is_admin do -        # Admin status change results in change of accessible OAuth scopes, and instead of changing -        #   already issued tokens we revoke them, requiring user to sign in again -        global_sign_out(user) -      end - -      {:ok, updated_user} -    end +    user +    |> cast(params, [ +      :is_moderator, +      :is_admin, +      :show_role +    ]) +    |> update_and_set_cache()    end    @doc "Signs user out of all applications" diff --git a/lib/pleroma/web/activity_pub/mrf/vocabulary_policy.ex b/lib/pleroma/web/activity_pub/mrf/vocabulary_policy.ex index 4eaea00d8..c184c3b66 100644 --- a/lib/pleroma/web/activity_pub/mrf/vocabulary_policy.ex +++ b/lib/pleroma/web/activity_pub/mrf/vocabulary_policy.ex @@ -20,7 +20,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.VocabularyPolicy do      with accepted_vocabulary <- Pleroma.Config.get([:mrf_vocabulary, :accept]),           rejected_vocabulary <- Pleroma.Config.get([:mrf_vocabulary, :reject]),           true <- -           length(accepted_vocabulary) == 0 || Enum.member?(accepted_vocabulary, message_type), +           Enum.empty?(accepted_vocabulary) || Enum.member?(accepted_vocabulary, message_type),           false <-             length(rejected_vocabulary) > 0 && Enum.member?(rejected_vocabulary, message_type),           {:ok, _} <- filter(message["object"]) do diff --git a/lib/pleroma/web/activity_pub/transmogrifier.ex b/lib/pleroma/web/activity_pub/transmogrifier.ex index 3fa789d53..2b8bfc3bd 100644 --- a/lib/pleroma/web/activity_pub/transmogrifier.ex +++ b/lib/pleroma/web/activity_pub/transmogrifier.ex @@ -658,24 +658,8 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do      with %User{ap_id: ^actor_id} = actor <- User.get_cached_by_ap_id(object["id"]) do        {:ok, new_user_data} = ActivityPub.user_data_from_user_object(object) -      locked = new_user_data[:locked] || false -      attachment = get_in(new_user_data, [:source_data, "attachment"]) || [] -      invisible = new_user_data[:invisible] || false - -      fields = -        attachment -        |> Enum.filter(fn %{"type" => t} -> t == "PropertyValue" end) -        |> Enum.map(fn fields -> Map.take(fields, ["name", "value"]) end) - -      update_data = -        new_user_data -        |> Map.take([:avatar, :banner, :bio, :name, :also_known_as]) -        |> Map.put(:fields, fields) -        |> Map.put(:locked, locked) -        |> Map.put(:invisible, invisible) -        actor -      |> User.upgrade_changeset(update_data, true) +      |> User.upgrade_changeset(new_user_data, true)        |> User.update_and_set_cache()        ActivityPub.update(%{ diff --git a/lib/pleroma/web/admin_api/admin_api_controller.ex b/lib/pleroma/web/admin_api/admin_api_controller.ex index c8abeff06..7118faf94 100644 --- a/lib/pleroma/web/admin_api/admin_api_controller.ex +++ b/lib/pleroma/web/admin_api/admin_api_controller.ex @@ -32,19 +32,14 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do    plug(      OAuthScopesPlug,      %{scopes: ["read:accounts"], admin: true} -    when action in [:list_users, :user_show, :right_get, :invites] +    when action in [:list_users, :user_show, :right_get]    )    plug(      OAuthScopesPlug,      %{scopes: ["write:accounts"], admin: true}      when action in [ -           :get_invite_token, -           :revoke_invite, -           :email_invite,             :get_password_reset, -           :user_follow, -           :user_unfollow,             :user_delete,             :users_create,             :user_toggle_activation, @@ -57,6 +52,20 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do           ]    ) +  plug(OAuthScopesPlug, %{scopes: ["read:invites"], admin: true} when action == :invites) + +  plug( +    OAuthScopesPlug, +    %{scopes: ["write:invites"], admin: true} +    when action in [:create_invite_token, :revoke_invite, :email_invite] +  ) + +  plug( +    OAuthScopesPlug, +    %{scopes: ["write:follows"], admin: true} +    when action in [:user_follow, :user_unfollow, :relay_follow, :relay_unfollow] +  ) +    plug(      OAuthScopesPlug,      %{scopes: ["read:reports"], admin: true} @@ -66,7 +75,7 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do    plug(      OAuthScopesPlug,      %{scopes: ["write:reports"], admin: true} -    when action in [:report_update_state, :report_respond] +    when action in [:reports_update]    )    plug( @@ -90,7 +99,7 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do    plug(      OAuthScopesPlug,      %{scopes: ["write"], admin: true} -    when action in [:relay_follow, :relay_unfollow, :config_update] +    when action == :config_update    )    @users_page_size 50 @@ -630,7 +639,7 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do    def force_password_reset(%{assigns: %{user: admin}} = conn, %{"nicknames" => nicknames}) do      users = nicknames |> Enum.map(&User.get_cached_by_nickname/1) -    Enum.map(users, &User.force_password_reset_async/1) +    Enum.each(users, &User.force_password_reset_async/1)      ModerationLog.insert_log(%{        actor: admin, diff --git a/lib/pleroma/web/common_api/common_api.ex b/lib/pleroma/web/common_api/common_api.ex index 2f3bcfc3c..c05a6c544 100644 --- a/lib/pleroma/web/common_api/common_api.ex +++ b/lib/pleroma/web/common_api/common_api.ex @@ -85,9 +85,13 @@ defmodule Pleroma.Web.CommonAPI do    def repeat(id_or_ap_id, user, params \\ %{}) do      with %Activity{} = activity <- get_by_id_or_ap_id(id_or_ap_id),           object <- Object.normalize(activity), -         nil <- Utils.get_existing_announce(user.ap_id, object), +         announce_activity <- Utils.get_existing_announce(user.ap_id, object),           public <- public_announce?(object, params) do -      ActivityPub.announce(user, object, nil, true, public) +      if announce_activity do +        {:ok, announce_activity, object} +      else +        ActivityPub.announce(user, object, nil, true, public) +      end      else        _ -> {:error, dgettext("errors", "Could not repeat")}      end @@ -105,8 +109,12 @@ defmodule Pleroma.Web.CommonAPI do    def favorite(id_or_ap_id, user) do      with %Activity{} = activity <- get_by_id_or_ap_id(id_or_ap_id),           object <- Object.normalize(activity), -         nil <- Utils.get_existing_like(user.ap_id, object) do -      ActivityPub.like(user, object) +         like_activity <- Utils.get_existing_like(user.ap_id, object) do +      if like_activity do +        {:ok, like_activity, object} +      else +        ActivityPub.like(user, object) +      end      else        _ -> {:error, dgettext("errors", "Could not favorite")}      end diff --git a/lib/pleroma/web/mastodon_api/controllers/notification_controller.ex b/lib/pleroma/web/mastodon_api/controllers/notification_controller.ex index 16759be6a..f2508aca4 100644 --- a/lib/pleroma/web/mastodon_api/controllers/notification_controller.ex +++ b/lib/pleroma/web/mastodon_api/controllers/notification_controller.ex @@ -23,6 +23,23 @@ defmodule Pleroma.Web.MastodonAPI.NotificationController do    plug(Pleroma.Plugs.EnsurePublicOrAuthenticatedPlug)    # GET /api/v1/notifications +  def index(conn, %{"account_id" => account_id} = params) do +    case Pleroma.User.get_cached_by_id(account_id) do +      %{ap_id: account_ap_id} -> +        params = +          params +          |> Map.delete("account_id") +          |> Map.put("account_ap_id", account_ap_id) + +        index(conn, params) + +      _ -> +        conn +        |> put_status(:not_found) +        |> json(%{"error" => "Account is not found"}) +    end +  end +    def index(%{assigns: %{user: user}} = conn, params) do      notifications = MastodonAPI.get_notifications(user, params) diff --git a/lib/pleroma/web/mastodon_api/controllers/subscription_controller.ex b/lib/pleroma/web/mastodon_api/controllers/subscription_controller.ex index fc7d52824..11f7b85d3 100644 --- a/lib/pleroma/web/mastodon_api/controllers/subscription_controller.ex +++ b/lib/pleroma/web/mastodon_api/controllers/subscription_controller.ex @@ -6,9 +6,9 @@ defmodule Pleroma.Web.MastodonAPI.SubscriptionController do    @moduledoc "The module represents functions to manage user subscriptions."    use Pleroma.Web, :controller +  alias Pleroma.Web.MastodonAPI.PushSubscriptionView, as: View    alias Pleroma.Web.Push    alias Pleroma.Web.Push.Subscription -  alias Pleroma.Web.MastodonAPI.PushSubscriptionView, as: View    action_fallback(:errors) diff --git a/lib/pleroma/web/mastodon_api/controllers/timeline_controller.ex b/lib/pleroma/web/mastodon_api/controllers/timeline_controller.ex index 384159336..29964a1d4 100644 --- a/lib/pleroma/web/mastodon_api/controllers/timeline_controller.ex +++ b/lib/pleroma/web/mastodon_api/controllers/timeline_controller.ex @@ -77,10 +77,7 @@ defmodule Pleroma.Web.MastodonAPI.TimelineController do      |> render("index.json", activities: activities, for: user, as: :activity)    end -  # GET /api/v1/timelines/tag/:tag -  def hashtag(%{assigns: %{user: user}} = conn, params) do -    local_only = truthy_param?(params["local"]) - +  def hashtag_fetching(params, user, local_only) do      tags =        [params["tag"], params["any"]]        |> List.flatten() @@ -98,7 +95,7 @@ defmodule Pleroma.Web.MastodonAPI.TimelineController do        |> Map.get("none", [])        |> Enum.map(&String.downcase(&1)) -    activities = +    _activities =        params        |> Map.put("type", "Create")        |> Map.put("local_only", local_only) @@ -109,6 +106,13 @@ defmodule Pleroma.Web.MastodonAPI.TimelineController do        |> Map.put("tag_all", tag_all)        |> Map.put("tag_reject", tag_reject)        |> ActivityPub.fetch_public_activities() +  end + +  # GET /api/v1/timelines/tag/:tag +  def hashtag(%{assigns: %{user: user}} = conn, params) do +    local_only = truthy_param?(params["local"]) + +    activities = hashtag_fetching(params, user, local_only)      conn      |> add_link_headers(activities, %{"local" => local_only}) diff --git a/lib/pleroma/web/mastodon_api/mastodon_api.ex b/lib/pleroma/web/mastodon_api/mastodon_api.ex index b1816370e..390a2b190 100644 --- a/lib/pleroma/web/mastodon_api/mastodon_api.ex +++ b/lib/pleroma/web/mastodon_api/mastodon_api.ex @@ -56,6 +56,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPI do      user      |> Notification.for_user_query(options)      |> restrict(:exclude_types, options) +    |> restrict(:account_ap_id, options)      |> Pagination.fetch_paginated(params)    end @@ -71,7 +72,8 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPI do        exclude_visibilities: {:array, :string},        reblogs: :boolean,        with_muted: :boolean, -      with_move: :boolean +      with_move: :boolean, +      account_ap_id: :string      }      changeset = cast({%{}, param_types}, params, Map.keys(param_types)) @@ -88,5 +90,9 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPI do      |> where([q, a], not fragment("? @> ARRAY[?->>'type']::varchar[]", ^ap_types, a.data))    end +  defp restrict(query, :account_ap_id, %{account_ap_id: account_ap_id}) do +    where(query, [n, a], a.actor == ^account_ap_id) +  end +    defp restrict(query, _, _), do: query  end diff --git a/lib/pleroma/web/oauth/oauth_controller.ex b/lib/pleroma/web/oauth/oauth_controller.ex index 87acdec97..5292aedf2 100644 --- a/lib/pleroma/web/oauth/oauth_controller.ex +++ b/lib/pleroma/web/oauth/oauth_controller.ex @@ -14,10 +14,10 @@ defmodule Pleroma.Web.OAuth.OAuthController do    alias Pleroma.Web.ControllerHelper    alias Pleroma.Web.OAuth.App    alias Pleroma.Web.OAuth.Authorization +  alias Pleroma.Web.OAuth.Scopes    alias Pleroma.Web.OAuth.Token    alias Pleroma.Web.OAuth.Token.Strategy.RefreshToken    alias Pleroma.Web.OAuth.Token.Strategy.Revoke, as: RevokeToken -  alias Pleroma.Web.OAuth.Scopes    require Logger @@ -222,7 +222,7 @@ defmodule Pleroma.Web.OAuth.OAuthController do           {:user_active, true} <- {:user_active, !user.deactivated},           {:password_reset_pending, false} <-             {:password_reset_pending, user.password_reset_pending}, -         {:ok, scopes} <- validate_scopes(app, params, user), +         {:ok, scopes} <- validate_scopes(app, params),           {:ok, auth} <- Authorization.create_authorization(app, user, scopes),           {:ok, token} <- Token.exchange_token(app, auth) do        json(conn, Token.Response.build(user, token)) @@ -471,7 +471,7 @@ defmodule Pleroma.Web.OAuth.OAuthController do             {:get_user, (user && {:ok, user}) || Authenticator.get_user(conn)},           %App{} = app <- Repo.get_by(App, client_id: client_id),           true <- redirect_uri in String.split(app.redirect_uris), -         {:ok, scopes} <- validate_scopes(app, auth_attrs, user), +         {:ok, scopes} <- validate_scopes(app, auth_attrs),           {:auth_active, true} <- {:auth_active, User.auth_active?(user)} do        Authorization.create_authorization(app, user, scopes)      end @@ -487,12 +487,12 @@ defmodule Pleroma.Web.OAuth.OAuthController do    defp put_session_registration_id(%Plug.Conn{} = conn, registration_id),      do: put_session(conn, :registration_id, registration_id) -  @spec validate_scopes(App.t(), map(), User.t()) :: +  @spec validate_scopes(App.t(), map()) ::            {:ok, list()} | {:error, :missing_scopes | :unsupported_scopes} -  defp validate_scopes(%App{} = app, params, %User{} = user) do +  defp validate_scopes(%App{} = app, params) do      params      |> Scopes.fetch_scopes(app.scopes) -    |> Scopes.validate(app.scopes, user) +    |> Scopes.validate(app.scopes)    end    def default_redirect_uri(%App{} = app) do diff --git a/lib/pleroma/web/oauth/scopes.ex b/lib/pleroma/web/oauth/scopes.ex index 00da225b9..151467494 100644 --- a/lib/pleroma/web/oauth/scopes.ex +++ b/lib/pleroma/web/oauth/scopes.ex @@ -8,7 +8,6 @@ defmodule Pleroma.Web.OAuth.Scopes do    """    alias Pleroma.Plugs.OAuthScopesPlug -  alias Pleroma.User    @doc """    Fetch scopes from request params. @@ -56,35 +55,18 @@ defmodule Pleroma.Web.OAuth.Scopes do    @doc """    Validates scopes.    """ -  @spec validate(list() | nil, list(), User.t()) :: +  @spec validate(list() | nil, list()) ::            {:ok, list()} | {:error, :missing_scopes | :unsupported_scopes} -  def validate(blank_scopes, _app_scopes, _user) when blank_scopes in [nil, []], +  def validate(blank_scopes, _app_scopes) when blank_scopes in [nil, []],      do: {:error, :missing_scopes} -  def validate(scopes, app_scopes, %User{} = user) do -    with {:ok, _} <- ensure_scopes_support(scopes, app_scopes), -         {:ok, scopes} <- authorize_admin_scopes(scopes, app_scopes, user) do -      {:ok, scopes} -    end -  end - -  defp ensure_scopes_support(scopes, app_scopes) do +  def validate(scopes, app_scopes) do      case OAuthScopesPlug.filter_descendants(scopes, app_scopes) do        ^scopes -> {:ok, scopes}        _ -> {:error, :unsupported_scopes}      end    end -  defp authorize_admin_scopes(scopes, app_scopes, %User{} = user) do -    if user.is_admin || !contains_admin_scopes?(scopes) || !contains_admin_scopes?(app_scopes) do -      {:ok, scopes} -    else -      # Gracefully dropping admin scopes from requested scopes if user isn't an admin (not raising) -      scopes = scopes -- OAuthScopesPlug.filter_descendants(scopes, ["admin"]) -      validate(scopes, app_scopes, user) -    end -  end -    def contains_admin_scopes?(scopes) do      scopes      |> OAuthScopesPlug.filter_descendants(["admin"]) diff --git a/lib/pleroma/web/pleroma_api/controllers/pleroma_api_controller.ex b/lib/pleroma/web/pleroma_api/controllers/pleroma_api_controller.ex index 772c535a4..3285dc11b 100644 --- a/lib/pleroma/web/pleroma_api/controllers/pleroma_api_controller.ex +++ b/lib/pleroma/web/pleroma_api/controllers/pleroma_api_controller.ex @@ -23,7 +23,7 @@ defmodule Pleroma.Web.PleromaAPI.PleromaAPIController do    plug(      OAuthScopesPlug,      %{scopes: ["read:statuses"]} -    when action in [:conversation, :conversation_statuses, :emoji_reactions_by] +    when action in [:conversation, :conversation_statuses]    )    plug( | 
