From f86a7d5d8bb07ed57dcbb50e0746bc37916eb627 Mon Sep 17 00:00:00 2001 From: eugenijm Date: Sat, 9 Nov 2019 13:56:27 +0300 Subject: Fix exclude_visibilities filter for followers-only Like notifications --- lib/pleroma/notification.ex | 34 +++++++++++++++++++++------------- 1 file changed, 21 insertions(+), 13 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/notification.ex b/lib/pleroma/notification.ex index b7ecf51e4..98bcadc98 100644 --- a/lib/pleroma/notification.ex +++ b/lib/pleroma/notification.ex @@ -87,10 +87,28 @@ defmodule Pleroma.Notification do when is_list(visibility) do if Enum.all?(visibility, &(&1 in @valid_visibilities)) do query + |> join(:left, [n, a], mutated_activity in Pleroma.Activity, + on: + fragment("?->>'context'", a.data) == + fragment("?->>'context'", mutated_activity.data) and + fragment("(?->>'type' = 'Like' or ?->>'type' = 'Announce')", a.data, a.data) and + fragment("?->>'type'", mutated_activity.data) == "Create", + as: :mutated_activity + ) |> where( - [n, a], + [n, a, mutated_activity: mutated_activity], not fragment( - "activity_visibility(?, ?, ?) = ANY (?)", + """ + CASE WHEN (?->>'type') = 'Like' or (?->>'type') = 'Announce' + THEN (activity_visibility(?, ?, ?) = ANY (?)) + ELSE (activity_visibility(?, ?, ?) = ANY (?)) END + """, + a.data, + a.data, + mutated_activity.actor, + mutated_activity.recipients, + mutated_activity.data, + ^visibility, a.actor, a.recipients, a.data, @@ -105,17 +123,7 @@ defmodule Pleroma.Notification do defp exclude_visibility(query, %{exclude_visibilities: visibility}) when visibility in @valid_visibilities do - query - |> where( - [n, a], - not fragment( - "activity_visibility(?, ?, ?) = (?)", - a.actor, - a.recipients, - a.data, - ^visibility - ) - ) + exclude_visibility(query, [visibility]) end defp exclude_visibility(query, %{exclude_visibilities: visibility}) -- cgit v1.2.3 From 4beb3ce5c57e6caf03365d32078ea58fd0c93434 Mon Sep 17 00:00:00 2001 From: Maksim Pechnikov Date: Mon, 18 Nov 2019 09:44:08 +0300 Subject: /api/v1/favourites: added sorting for activites by adds to favorites --- lib/pleroma/web/activity_pub/activity_pub.ex | 39 ++++++++++++++++++++++ .../mastodon_api/controllers/status_controller.ex | 10 +----- 2 files changed, 40 insertions(+), 9 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex index d0c014e9d..95d97615c 100644 --- a/lib/pleroma/web/activity_pub/activity_pub.ex +++ b/lib/pleroma/web/activity_pub/activity_pub.ex @@ -1055,6 +1055,45 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do |> maybe_update_cc(list_memberships, opts["user"]) end + @doc """ + Fetch favorites activities of user with order by sort adds to favorites + """ + @spec fetch_favourites(list(String.t()), User.t(), map(), atom()) :: list(Activity.t()) + def fetch_favourites(recipients, user, params \\ %{}, pagination \\ :keyset) do + opts = + %{ + "type" => "Create", + "favorited_by" => user.ap_id, + "blocking_user" => user + } + |> Map.merge(params) + + recipients + |> fetch_activities_query(opts) + |> order_by_favourites(user) + |> Pagination.fetch_paginated(opts, pagination) + end + + # sorts by adds to favorites + # + @spec order_by_favourites(Ecto.Query.t(), User.t()) :: Ecto.Query.t() + defp order_by_favourites(query, user) do + join(query, :inner, [activity, object], a1 in Activity, + on: + fragment( + "(?->>'id') = COALESCE(?->'object'->>'id', ?->>'object') AND (?->>'type' = 'Like') AND (?.actor = ?)", + object.data, + a1.data, + a1.data, + a1.data, + a1, + ^user.ap_id + ), + as: :like_activity + ) + |> order_by([_, _, like_activity], desc: like_activity.updated_at) + end + defp maybe_update_cc(activities, list_memberships, %User{ap_id: user_ap_id}) when is_list(list_memberships) and length(list_memberships) > 0 do Enum.map(activities, fn diff --git a/lib/pleroma/web/mastodon_api/controllers/status_controller.ex b/lib/pleroma/web/mastodon_api/controllers/status_controller.ex index 74b223cf4..cdc4cec9c 100644 --- a/lib/pleroma/web/mastodon_api/controllers/status_controller.ex +++ b/lib/pleroma/web/mastodon_api/controllers/status_controller.ex @@ -346,15 +346,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusController do @doc "GET /api/v1/favourites" def favourites(%{assigns: %{user: user}} = conn, params) do - params = - params - |> Map.put("type", "Create") - |> Map.put("favorited_by", user.ap_id) - |> Map.put("blocking_user", user) - - activities = - ActivityPub.fetch_activities([], params) - |> Enum.reverse() + activities = ActivityPub.fetch_favourites([], user, Map.take(params, ["limit"])) conn |> add_link_headers(activities) -- cgit v1.2.3 From 9da4c88b49b4ccdc1eac90e04e9d8948fd943f37 Mon Sep 17 00:00:00 2001 From: Maksim Pechnikov Date: Mon, 18 Nov 2019 10:00:48 +0300 Subject: fix test --- lib/pleroma/pagination.ex | 3 +++ lib/pleroma/web/mastodon_api/controllers/status_controller.ex | 7 ++++++- 2 files changed, 9 insertions(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/pleroma/pagination.ex b/lib/pleroma/pagination.ex index 9d279fba7..c77ba78bb 100644 --- a/lib/pleroma/pagination.ex +++ b/lib/pleroma/pagination.ex @@ -13,6 +13,9 @@ defmodule Pleroma.Pagination do alias Pleroma.Repo @default_limit 20 + @page_keys ["max_id", "min_id", "limit", "since_id", "order"] + + def page_keys, do: @page_keys def fetch_paginated(query, params, type \\ :keyset) diff --git a/lib/pleroma/web/mastodon_api/controllers/status_controller.ex b/lib/pleroma/web/mastodon_api/controllers/status_controller.ex index cdc4cec9c..e11bee383 100644 --- a/lib/pleroma/web/mastodon_api/controllers/status_controller.ex +++ b/lib/pleroma/web/mastodon_api/controllers/status_controller.ex @@ -346,7 +346,12 @@ defmodule Pleroma.Web.MastodonAPI.StatusController do @doc "GET /api/v1/favourites" def favourites(%{assigns: %{user: user}} = conn, params) do - activities = ActivityPub.fetch_favourites([], user, Map.take(params, ["limit"])) + activities = + ActivityPub.fetch_favourites( + [], + user, + Map.take(params, Pleroma.Pagination.page_keys()) + ) conn |> add_link_headers(activities) -- cgit v1.2.3 From 0937895182f167966872a3347098f78efe23dde9 Mon Sep 17 00:00:00 2001 From: Maksim Pechnikov Date: Mon, 18 Nov 2019 16:56:25 +0300 Subject: updated fetch_favorites --- lib/pleroma/object.ex | 17 +++++ lib/pleroma/pagination.ex | 80 +++++++++++++--------- lib/pleroma/web/activity_pub/activity_pub.ex | 44 +++--------- .../mastodon_api/controllers/status_controller.ex | 1 - 4 files changed, 74 insertions(+), 68 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/object.ex b/lib/pleroma/object.ex index d9b41d710..91cb9941f 100644 --- a/lib/pleroma/object.ex +++ b/lib/pleroma/object.ex @@ -23,6 +23,23 @@ defmodule Pleroma.Object do timestamps() end + def with_joined_activity(query, activity_type \\ "Create", join_type \\ :inner) do + object_position = Map.get(query.aliases, :object, 0) + + join(query, join_type, [{object, object_position}], a in Activity, + on: + fragment( + "COALESCE(?->'object'->>'id', ?->>'object') = (? ->> 'id') AND (?->>'type' = ?) ", + a.data, + a.data, + object.data, + a.data, + ^activity_type + ), + as: :object_activity + ) + end + def create(data) do Object.change(%Object{}, %{data: data}) |> Repo.insert() diff --git a/lib/pleroma/pagination.ex b/lib/pleroma/pagination.ex index c77ba78bb..243f1a329 100644 --- a/lib/pleroma/pagination.ex +++ b/lib/pleroma/pagination.ex @@ -17,59 +17,59 @@ defmodule Pleroma.Pagination do def page_keys, do: @page_keys - def fetch_paginated(query, params, type \\ :keyset) + def fetch_paginated(query, params, type \\ :keyset, table_binding \\ nil) - def fetch_paginated(query, %{"total" => true} = params, :keyset) do + def fetch_paginated(query, %{"total" => true} = params, :keyset, table_binding) do total = Repo.aggregate(query, :count, :id) %{ total: total, - items: fetch_paginated(query, Map.drop(params, ["total"]), :keyset) + items: fetch_paginated(query, Map.drop(params, ["total"]), :keyset, table_binding) } end - def fetch_paginated(query, params, :keyset) do + def fetch_paginated(query, params, :keyset, table_binding) do options = cast_params(params) query - |> paginate(options, :keyset) + |> paginate(options, :keyset, table_binding) |> Repo.all() |> enforce_order(options) end - def fetch_paginated(query, %{"total" => true} = params, :offset) do + def fetch_paginated(query, %{"total" => true} = params, :offset, table_binding) do total = Repo.aggregate(query, :count, :id) %{ total: total, - items: fetch_paginated(query, Map.drop(params, ["total"]), :offset) + items: fetch_paginated(query, Map.drop(params, ["total"]), :offset, table_binding) } end - def fetch_paginated(query, params, :offset) do + def fetch_paginated(query, params, :offset, table_binding) do options = cast_params(params) query - |> paginate(options, :offset) + |> paginate(options, :offset, table_binding) |> Repo.all() end - def paginate(query, options, method \\ :keyset) + def paginate(query, options, method \\ :keyset, table_binding \\ nil) - def paginate(query, options, :keyset) do + def paginate(query, options, :keyset, table_binding) do query - |> restrict(:min_id, options) - |> restrict(:since_id, options) - |> restrict(:max_id, options) - |> restrict(:order, options) - |> restrict(:limit, options) + |> restrict(:min_id, options, table_binding) + |> restrict(:since_id, options, table_binding) + |> restrict(:max_id, options, table_binding) + |> restrict(:order, options, table_binding) + |> restrict(:limit, options, table_binding) end - def paginate(query, options, :offset) do + def paginate(query, options, :offset, table_binding) do query - |> restrict(:order, options) - |> restrict(:offset, options) - |> restrict(:limit, options) + |> restrict(:order, options, table_binding) + |> restrict(:offset, options, table_binding) + |> restrict(:limit, options, table_binding) end defp cast_params(params) do @@ -91,38 +91,46 @@ defmodule Pleroma.Pagination do changeset.changes end - defp restrict(query, :min_id, %{min_id: min_id}) do - where(query, [q], q.id > ^min_id) + defp restrict(query, :min_id, %{min_id: min_id}, table_binding) do + where(query, [{q, table_position(query, table_binding)}], q.id > ^min_id) end - defp restrict(query, :since_id, %{since_id: since_id}) do - where(query, [q], q.id > ^since_id) + defp restrict(query, :since_id, %{since_id: since_id}, table_binding) do + where(query, [{q, table_position(query, table_binding)}], q.id > ^since_id) end - defp restrict(query, :max_id, %{max_id: max_id}) do - where(query, [q], q.id < ^max_id) + defp restrict(query, :max_id, %{max_id: max_id}, table_binding) do + where(query, [{q, table_position(query, table_binding)}], q.id < ^max_id) end - defp restrict(query, :order, %{min_id: _}) do - order_by(query, [u], fragment("? asc nulls last", u.id)) + defp restrict(query, :order, %{min_id: _}, table_binding) do + order_by( + query, + [{u, table_position(query, table_binding)}], + fragment("? asc nulls last", u.id) + ) end - defp restrict(query, :order, _options) do - order_by(query, [u], fragment("? desc nulls last", u.id)) + defp restrict(query, :order, _options, table_binding) do + order_by( + query, + [{u, table_position(query, table_binding)}], + fragment("? desc nulls last", u.id) + ) end - defp restrict(query, :offset, %{offset: offset}) do + defp restrict(query, :offset, %{offset: offset}, _table_binding) do offset(query, ^offset) end - defp restrict(query, :limit, options) do + defp restrict(query, :limit, options, _table_binding) do limit = Map.get(options, :limit, @default_limit) query |> limit(^limit) end - defp restrict(query, _, _), do: query + defp restrict(query, _, _, _), do: query defp enforce_order(result, %{min_id: _}) do result @@ -130,4 +138,10 @@ defmodule Pleroma.Pagination do end defp enforce_order(result, _), do: result + + defp table_position(%Ecto.Query{} = query, binding_name) do + Map.get(query.aliases, binding_name, 0) + end + + defp table_position(_, _), do: 0 end diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex index 95d97615c..e452278f0 100644 --- a/lib/pleroma/web/activity_pub/activity_pub.ex +++ b/lib/pleroma/web/activity_pub/activity_pub.ex @@ -1058,40 +1058,16 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do @doc """ Fetch favorites activities of user with order by sort adds to favorites """ - @spec fetch_favourites(list(String.t()), User.t(), map(), atom()) :: list(Activity.t()) - def fetch_favourites(recipients, user, params \\ %{}, pagination \\ :keyset) do - opts = - %{ - "type" => "Create", - "favorited_by" => user.ap_id, - "blocking_user" => user - } - |> Map.merge(params) - - recipients - |> fetch_activities_query(opts) - |> order_by_favourites(user) - |> Pagination.fetch_paginated(opts, pagination) - end - - # sorts by adds to favorites - # - @spec order_by_favourites(Ecto.Query.t(), User.t()) :: Ecto.Query.t() - defp order_by_favourites(query, user) do - join(query, :inner, [activity, object], a1 in Activity, - on: - fragment( - "(?->>'id') = COALESCE(?->'object'->>'id', ?->>'object') AND (?->>'type' = 'Like') AND (?.actor = ?)", - object.data, - a1.data, - a1.data, - a1.data, - a1, - ^user.ap_id - ), - as: :like_activity - ) - |> order_by([_, _, like_activity], desc: like_activity.updated_at) + @spec fetch_favourites(User.t(), map(), atom()) :: list(Activity.t()) + def fetch_favourites(user, params \\ %{}, pagination \\ :keyset) do + user.ap_id + |> Activity.Queries.by_actor() + |> Activity.Queries.by_type("Like") + |> Activity.with_joined_object() + |> Object.with_joined_activity() + |> select([_like, object, activity], %{activity | object: object}) + |> order_by([like, _, _], desc: like.updated_at) + |> Pagination.fetch_paginated(params, pagination, :object_activity) end defp maybe_update_cc(activities, list_memberships, %User{ap_id: user_ap_id}) diff --git a/lib/pleroma/web/mastodon_api/controllers/status_controller.ex b/lib/pleroma/web/mastodon_api/controllers/status_controller.ex index e11bee383..1149fb469 100644 --- a/lib/pleroma/web/mastodon_api/controllers/status_controller.ex +++ b/lib/pleroma/web/mastodon_api/controllers/status_controller.ex @@ -348,7 +348,6 @@ defmodule Pleroma.Web.MastodonAPI.StatusController do def favourites(%{assigns: %{user: user}} = conn, params) do activities = ActivityPub.fetch_favourites( - [], user, Map.take(params, Pleroma.Pagination.page_keys()) ) -- cgit v1.2.3 From 5cee51fac5b5feca7e85420861bf512169e499c7 Mon Sep 17 00:00:00 2001 From: Maksim Pechnikov Date: Mon, 18 Nov 2019 21:34:54 +0300 Subject: fix `order by` for fetch_favorites --- lib/pleroma/pagination.ex | 5 ++++- lib/pleroma/web/activity_pub/activity_pub.ex | 6 +++++- 2 files changed, 9 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/pagination.ex b/lib/pleroma/pagination.ex index 243f1a329..6321c2600 100644 --- a/lib/pleroma/pagination.ex +++ b/lib/pleroma/pagination.ex @@ -78,7 +78,8 @@ defmodule Pleroma.Pagination do since_id: :string, max_id: :string, offset: :integer, - limit: :integer + limit: :integer, + skip_order: :boolean } params = @@ -103,6 +104,8 @@ defmodule Pleroma.Pagination do where(query, [{q, table_position(query, table_binding)}], q.id < ^max_id) end + defp restrict(query, :order, %{skip_order: true}, _), do: query + defp restrict(query, :order, %{min_id: _}, table_binding) do order_by( query, diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex index e452278f0..f1ff0ee0d 100644 --- a/lib/pleroma/web/activity_pub/activity_pub.ex +++ b/lib/pleroma/web/activity_pub/activity_pub.ex @@ -1067,7 +1067,11 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do |> Object.with_joined_activity() |> select([_like, object, activity], %{activity | object: object}) |> order_by([like, _, _], desc: like.updated_at) - |> Pagination.fetch_paginated(params, pagination, :object_activity) + |> Pagination.fetch_paginated( + Map.merge(params, %{"skip_order" => true}), + pagination, + :object_activity + ) end defp maybe_update_cc(activities, list_memberships, %User{ap_id: user_ap_id}) -- cgit v1.2.3 From 708fd234bdff5423ca6d8003232eca0df231bbc2 Mon Sep 17 00:00:00 2001 From: Maksim Pechnikov Date: Tue, 19 Nov 2019 20:19:41 +0300 Subject: fix order favorites activites --- lib/pleroma/web/activity_pub/activity_pub.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex index f1ff0ee0d..6eb69e183 100644 --- a/lib/pleroma/web/activity_pub/activity_pub.ex +++ b/lib/pleroma/web/activity_pub/activity_pub.ex @@ -1066,7 +1066,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do |> Activity.with_joined_object() |> Object.with_joined_activity() |> select([_like, object, activity], %{activity | object: object}) - |> order_by([like, _, _], desc: like.updated_at) + |> order_by([like, _, _], desc: like.id) |> Pagination.fetch_paginated( Map.merge(params, %{"skip_order" => true}), pagination, -- cgit v1.2.3 From fa97eddf8a7e5c3a0ed51eff562d6592bd478b95 Mon Sep 17 00:00:00 2001 From: Sadposter Date: Thu, 28 Nov 2019 10:38:38 +0000 Subject: make follows take precedence over domain blocks --- lib/pleroma/user.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex index b18a4c6a5..6a97e1928 100644 --- a/lib/pleroma/user.ex +++ b/lib/pleroma/user.ex @@ -1020,7 +1020,7 @@ defmodule Pleroma.User do do: Enum.member?(user.muted_notifications, ap_id) def blocks?(%User{} = user, %User{} = target) do - blocks_ap_id?(user, target) || blocks_domain?(user, target) + blocks_ap_id?(user, target) || (!User.following?(user, target) && blocks_domain?(user, target)) end def blocks?(nil, _), do: false -- cgit v1.2.3 From c7cc80a9ee00f7bf9e307a09c5f2cc85fedd67d5 Mon Sep 17 00:00:00 2001 From: Sadposter Date: Thu, 28 Nov 2019 10:40:50 +0000 Subject: obligatory format commit --- lib/pleroma/user.ex | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex index 6a97e1928..63c5b4102 100644 --- a/lib/pleroma/user.ex +++ b/lib/pleroma/user.ex @@ -1020,7 +1020,8 @@ defmodule Pleroma.User do do: Enum.member?(user.muted_notifications, ap_id) def blocks?(%User{} = user, %User{} = target) do - blocks_ap_id?(user, target) || (!User.following?(user, target) && blocks_domain?(user, target)) + blocks_ap_id?(user, target) || + (!User.following?(user, target) && blocks_domain?(user, target)) end def blocks?(nil, _), do: false -- cgit v1.2.3 From a52da55eb9c6bbf8a08bf1d90d59a48dc25f5907 Mon Sep 17 00:00:00 2001 From: Maksim Pechnikov Date: Mon, 28 Oct 2019 12:47:23 +0300 Subject: added User.NotificationSetting struct --- lib/pleroma/notification.ex | 8 +++--- lib/pleroma/user.ex | 26 ++++------------- lib/pleroma/user/notification_setting.ex | 49 ++++++++++++++++++++++++++++++++ 3 files changed, 59 insertions(+), 24 deletions(-) create mode 100644 lib/pleroma/user/notification_setting.ex (limited to 'lib') diff --git a/lib/pleroma/notification.ex b/lib/pleroma/notification.ex index b7ecf51e4..acb635fdc 100644 --- a/lib/pleroma/notification.ex +++ b/lib/pleroma/notification.ex @@ -314,7 +314,7 @@ defmodule Pleroma.Notification do def skip?( :followers, activity, - %{notification_settings: %{"followers" => false}} = user + %{notification_settings: %{followers: false}} = user ) do actor = activity.data["actor"] follower = User.get_cached_by_ap_id(actor) @@ -324,14 +324,14 @@ defmodule Pleroma.Notification do def skip?( :non_followers, activity, - %{notification_settings: %{"non_followers" => false}} = user + %{notification_settings: %{non_followers: false}} = user ) do actor = activity.data["actor"] follower = User.get_cached_by_ap_id(actor) !User.following?(follower, user) end - def skip?(:follows, activity, %{notification_settings: %{"follows" => false}} = user) do + def skip?(:follows, activity, %{notification_settings: %{follows: false}} = user) do actor = activity.data["actor"] followed = User.get_cached_by_ap_id(actor) User.following?(user, followed) @@ -340,7 +340,7 @@ defmodule Pleroma.Notification do def skip?( :non_follows, activity, - %{notification_settings: %{"non_follows" => false}} = user + %{notification_settings: %{non_follows: false}} = user ) do actor = activity.data["actor"] followed = User.get_cached_by_ap_id(actor) diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex index b18a4c6a5..94fca2a9f 100644 --- a/lib/pleroma/user.ex +++ b/lib/pleroma/user.ex @@ -105,13 +105,10 @@ defmodule Pleroma.User do field(:invisible, :boolean, default: false) field(:skip_thread_containment, :boolean, default: false) - field(:notification_settings, :map, - default: %{ - "followers" => true, - "follows" => true, - "non_follows" => true, - "non_followers" => true - } + embeds_one( + :notification_settings, + Pleroma.User.NotificationSetting, + on_replace: :update ) has_many(:notifications, Notification) @@ -1095,20 +1092,9 @@ defmodule Pleroma.User do end def update_notification_settings(%User{} = user, settings) do - settings = - settings - |> Enum.map(fn {k, v} -> {k, v in [true, "true", "True", "1"]} end) - |> Map.new() - - notification_settings = - user.notification_settings - |> Map.merge(settings) - |> Map.take(["followers", "follows", "non_follows", "non_followers"]) - - params = %{notification_settings: notification_settings} - user - |> cast(params, [:notification_settings]) + |> cast(%{notification_settings: settings}, []) + |> cast_embed(:notification_settings) |> validate_required([:notification_settings]) |> update_and_set_cache() end diff --git a/lib/pleroma/user/notification_setting.ex b/lib/pleroma/user/notification_setting.ex new file mode 100644 index 000000000..64100c0e6 --- /dev/null +++ b/lib/pleroma/user/notification_setting.ex @@ -0,0 +1,49 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2019 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.User.NotificationSetting do + use Ecto.Schema + import Ecto.Changeset + + @derive Jason.Encoder + @primary_key false + + @privacy_options %{ + name_and_message: "name_and_message", + name_only: "name_only", + no_name_or_message: "no_name_or_message" + } + + embedded_schema do + field(:followers, :boolean, default: true) + field(:follows, :boolean, default: true) + field(:non_follows, :boolean, default: true) + field(:non_followers, :boolean, default: true) + field(:privacy_option, :string, default: @privacy_options.name_and_message) + end + + def changeset(schema, params) do + schema + |> cast(prepare_attrs(params), [ + :followers, + :follows, + :non_follows, + :non_followers, + :privacy_option + ]) + |> validate_inclusion(:privacy_option, Map.values(@privacy_options)) + end + + defp prepare_attrs(params) do + Enum.reduce(params, %{}, fn + {k, v}, acc + when k in ["followers", "follows", "non_follows", "non_followers"] and + is_binary(v) -> + Map.put(acc, k, String.downcase(v)) + + {k, v}, acc -> + Map.put(acc, k, v) + end) + end +end -- cgit v1.2.3 From 04a8ffbe84c6d40709860e75fffa0330a2db690f Mon Sep 17 00:00:00 2001 From: Maksim Pechnikov Date: Tue, 29 Oct 2019 21:33:17 +0300 Subject: added privacy option to push notifications --- lib/pleroma/user/notification_setting.ex | 13 ++----------- lib/pleroma/web/push/impl.ex | 27 ++++++++++++++++++++++----- lib/pleroma/workers/web_pusher_worker.ex | 2 +- 3 files changed, 25 insertions(+), 17 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/user/notification_setting.ex b/lib/pleroma/user/notification_setting.ex index 64100c0e6..f0899613e 100644 --- a/lib/pleroma/user/notification_setting.ex +++ b/lib/pleroma/user/notification_setting.ex @@ -9,18 +9,12 @@ defmodule Pleroma.User.NotificationSetting do @derive Jason.Encoder @primary_key false - @privacy_options %{ - name_and_message: "name_and_message", - name_only: "name_only", - no_name_or_message: "no_name_or_message" - } - embedded_schema do field(:followers, :boolean, default: true) field(:follows, :boolean, default: true) field(:non_follows, :boolean, default: true) field(:non_followers, :boolean, default: true) - field(:privacy_option, :string, default: @privacy_options.name_and_message) + field(:privacy_option, :boolean, default: false) end def changeset(schema, params) do @@ -32,14 +26,11 @@ defmodule Pleroma.User.NotificationSetting do :non_followers, :privacy_option ]) - |> validate_inclusion(:privacy_option, Map.values(@privacy_options)) end defp prepare_attrs(params) do Enum.reduce(params, %{}, fn - {k, v}, acc - when k in ["followers", "follows", "non_follows", "non_followers"] and - is_binary(v) -> + {k, v}, acc when is_binary(v) -> Map.put(acc, k, String.downcase(v)) {k, v}, acc -> diff --git a/lib/pleroma/web/push/impl.ex b/lib/pleroma/web/push/impl.ex index 3de7af708..53f93c1ed 100644 --- a/lib/pleroma/web/push/impl.ex +++ b/lib/pleroma/web/push/impl.ex @@ -22,8 +22,8 @@ defmodule Pleroma.Web.Push.Impl do @spec perform(Notification.t()) :: list(any) | :error def perform( %{ - activity: %{data: %{"type" => activity_type}, id: activity_id} = activity, - user_id: user_id + activity: %{data: %{"type" => activity_type}} = activity, + user: %User{id: user_id} } = notif ) when activity_type in @types do @@ -39,18 +39,17 @@ defmodule Pleroma.Web.Push.Impl do for subscription <- fetch_subsriptions(user_id), get_in(subscription.data, ["alerts", type]) do %{ - title: format_title(notif), access_token: subscription.token.token, - body: format_body(notif, actor, object), notification_id: notif.id, notification_type: type, icon: avatar_url, preferred_locale: "en", pleroma: %{ - activity_id: activity_id, + activity_id: notif.activity.id, direct_conversation_id: direct_conversation_id } } + |> Map.merge(build_content(notif, actor, object)) |> Jason.encode!() |> push_message(build_sub(subscription), gcm_api_key, subscription) end @@ -100,6 +99,24 @@ defmodule Pleroma.Web.Push.Impl do } end + def build_content( + %{ + activity: %{data: %{"directMessage" => true}}, + user: %{notification_settings: %{privacy_option: true}} + }, + actor, + _ + ) do + %{title: "New Direct Message", body: "@#{actor.nickname}"} + end + + def build_content(notif, actor, object) do + %{ + title: format_title(notif), + body: format_body(notif, actor, object) + } + end + def format_body( %{activity: %{data: %{"type" => "Create"}}}, actor, diff --git a/lib/pleroma/workers/web_pusher_worker.ex b/lib/pleroma/workers/web_pusher_worker.ex index 61b451e3e..a978c4013 100644 --- a/lib/pleroma/workers/web_pusher_worker.ex +++ b/lib/pleroma/workers/web_pusher_worker.ex @@ -13,7 +13,7 @@ defmodule Pleroma.Workers.WebPusherWorker do notification = Notification |> Repo.get(notification_id) - |> Repo.preload([:activity]) + |> Repo.preload([:activity, :user]) Pleroma.Web.Push.Impl.perform(notification) end -- cgit v1.2.3 From a36607c27e6a50aeca450570f7b8e4c9c0233bb1 Mon Sep 17 00:00:00 2001 From: Maksim Pechnikov Date: Wed, 30 Oct 2019 22:59:04 +0300 Subject: add mix task to set\unset privacy option of notification --- lib/mix/tasks/pleroma/notification_settings.ex | 83 ++++++++++++++++++++++++++ 1 file changed, 83 insertions(+) create mode 100644 lib/mix/tasks/pleroma/notification_settings.ex (limited to 'lib') diff --git a/lib/mix/tasks/pleroma/notification_settings.ex b/lib/mix/tasks/pleroma/notification_settings.ex new file mode 100644 index 000000000..7d65f0587 --- /dev/null +++ b/lib/mix/tasks/pleroma/notification_settings.ex @@ -0,0 +1,83 @@ +defmodule Mix.Tasks.Pleroma.NotificationSettings do + @shortdoc "Enable&Disable privacy option for push notifications" + @moduledoc """ + Example: + + > mix pleroma.notification_settings --privacy-option=false --nickname-users="parallel588" # set false only for parallel588 user + > mix pleroma.notification_settings --privacy-option=true # set true for all users + + """ + + use Mix.Task + import Mix.Pleroma + import Ecto.Query + + def run(args) do + start_pleroma() + + {options, _, _} = + OptionParser.parse( + args, + strict: [ + privacy_option: :boolean, + email_users: :string, + nickname_users: :string + ] + ) + + privacy_option = Keyword.get(options, :privacy_option) + + if not is_nil(privacy_option) do + privacy_option + |> build_query(options) + |> Pleroma.Repo.update_all([]) + end + + shell_info("Done") + end + + defp build_query(privacy_option, options) do + query = + from(u in Pleroma.User, + update: [ + set: [ + notification_settings: + fragment( + "jsonb_set(notification_settings, '{privacy_option}', ?)", + ^privacy_option + ) + ] + ] + ) + + user_emails = + options + |> Keyword.get(:email_users, "") + |> String.split(",") + |> Enum.map(&String.trim(&1)) + |> Enum.reject(&(&1 == "")) + + query = + if length(user_emails) > 0 do + where(query, [u], u.email in ^user_emails) + else + query + end + + user_nicknames = + options + |> Keyword.get(:nickname_users, "") + |> String.split(",") + |> Enum.map(&String.trim(&1)) + |> Enum.reject(&(&1 == "")) + + query = + if length(user_nicknames) > 0 do + where(query, [u], u.nickname in ^user_nicknames) + else + query + end + + query + end +end -- cgit v1.2.3 From 51111e286b316340b45b4e6a378646bed0cb0a6a Mon Sep 17 00:00:00 2001 From: Ivan Tashkinov Date: Fri, 29 Nov 2019 18:57:19 +0300 Subject: [#1427] Initial support for OAuth admin scopes. --- lib/pleroma/web/admin_api/admin_api_controller.ex | 16 +++++----- lib/pleroma/web/oauth/oauth_controller.ex | 10 +++---- lib/pleroma/web/oauth/scopes.ex | 34 ++++++++++++++++++---- .../controllers/emoji_api_controller.ex | 2 +- 4 files changed, 43 insertions(+), 19 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/admin_api/admin_api_controller.ex b/lib/pleroma/web/admin_api/admin_api_controller.ex index 8c1318d1b..01cd12c96 100644 --- a/lib/pleroma/web/admin_api/admin_api_controller.ex +++ b/lib/pleroma/web/admin_api/admin_api_controller.ex @@ -30,13 +30,13 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do plug( OAuthScopesPlug, - %{scopes: ["read:accounts"]} + %{scopes: ["admin:read:accounts", "read:accounts"]} when action in [:list_users, :user_show, :right_get, :invites] ) plug( OAuthScopesPlug, - %{scopes: ["write:accounts"]} + %{scopes: ["admin:write:accounts", "write:accounts"]} when action in [ :get_invite_token, :revoke_invite, @@ -58,35 +58,35 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do plug( OAuthScopesPlug, - %{scopes: ["read:reports"]} when action in [:list_reports, :report_show] + %{scopes: ["admin:read:reports", "read:reports"]} when action in [:list_reports, :report_show] ) plug( OAuthScopesPlug, - %{scopes: ["write:reports"]} + %{scopes: ["admin:reports", "write:reports"]} when action in [:report_update_state, :report_respond] ) plug( OAuthScopesPlug, - %{scopes: ["read:statuses"]} when action == :list_user_statuses + %{scopes: ["admin:read:statuses", "read:statuses"]} when action == :list_user_statuses ) plug( OAuthScopesPlug, - %{scopes: ["write:statuses"]} + %{scopes: ["admin:write:statuses", "write:statuses"]} when action in [:status_update, :status_delete] ) plug( OAuthScopesPlug, - %{scopes: ["read"]} + %{scopes: ["admin:read", "read"]} when action in [:config_show, :migrate_to_db, :migrate_from_db, :list_log] ) plug( OAuthScopesPlug, - %{scopes: ["write"]} + %{scopes: ["admin:write", "write"]} when action in [:relay_follow, :relay_unfollow, :config_update] ) diff --git a/lib/pleroma/web/oauth/oauth_controller.ex b/lib/pleroma/web/oauth/oauth_controller.ex index 2aee8cab2..87acdec97 100644 --- a/lib/pleroma/web/oauth/oauth_controller.ex +++ b/lib/pleroma/web/oauth/oauth_controller.ex @@ -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), + {:ok, scopes} <- validate_scopes(app, params, user), {: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), + {:ok, scopes} <- validate_scopes(app, auth_attrs, user), {: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()) :: + @spec validate_scopes(App.t(), map(), User.t()) :: {:ok, list()} | {:error, :missing_scopes | :unsupported_scopes} - defp validate_scopes(app, params) do + defp validate_scopes(%App{} = app, params, %User{} = user) do params |> Scopes.fetch_scopes(app.scopes) - |> Scopes.validate(app.scopes) + |> Scopes.validate(app.scopes, user) 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 48bd14407..0c8796ecb 100644 --- a/lib/pleroma/web/oauth/scopes.ex +++ b/lib/pleroma/web/oauth/scopes.ex @@ -7,6 +7,9 @@ defmodule Pleroma.Web.OAuth.Scopes do Functions for dealing with scopes. """ + alias Pleroma.Plugs.OAuthScopesPlug + alias Pleroma.User + @doc """ Fetch scopes from request params. @@ -53,15 +56,36 @@ defmodule Pleroma.Web.OAuth.Scopes do @doc """ Validates scopes. """ - @spec validate(list() | nil, list()) :: + @spec validate(list() | nil, list(), User.t()) :: {:ok, list()} | {:error, :missing_scopes | :unsupported_scopes} - def validate([], _app_scopes), do: {:error, :missing_scopes} - def validate(nil, _app_scopes), do: {:error, :missing_scopes} + def validate(blank_scopes, _app_scopes, _user) when blank_scopes in [nil, []], + do: {:error, :missing_scopes} - def validate(scopes, app_scopes) do - case Pleroma.Plugs.OAuthScopesPlug.filter_descendants(scopes, app_scopes) do + 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 + 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 + {:error, :unsupported_scopes} + end + end + + defp contains_admin_scopes?(scopes) do + scopes + |> OAuthScopesPlug.filter_descendants(["admin"]) + |> Enum.any?() + end end diff --git a/lib/pleroma/web/pleroma_api/controllers/emoji_api_controller.ex b/lib/pleroma/web/pleroma_api/controllers/emoji_api_controller.ex index a474d41d4..1e8c62e3a 100644 --- a/lib/pleroma/web/pleroma_api/controllers/emoji_api_controller.ex +++ b/lib/pleroma/web/pleroma_api/controllers/emoji_api_controller.ex @@ -7,7 +7,7 @@ defmodule Pleroma.Web.PleromaAPI.EmojiAPIController do plug( OAuthScopesPlug, - %{scopes: ["write"]} + %{scopes: ["admin:write", "write"]} when action in [ :create, :delete, -- cgit v1.2.3 From 356a936ecbddf6bbdfada2ef70264b99e9d9723c Mon Sep 17 00:00:00 2001 From: Egor Kislitsyn Date: Mon, 2 Dec 2019 18:11:45 +0700 Subject: Fix `mix pleroma.user list` task --- lib/mix/tasks/pleroma/user.ex | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'lib') diff --git a/lib/mix/tasks/pleroma/user.ex b/lib/mix/tasks/pleroma/user.ex index bc8eacda8..0adb78fe3 100644 --- a/lib/mix/tasks/pleroma/user.ex +++ b/lib/mix/tasks/pleroma/user.ex @@ -373,9 +373,9 @@ defmodule Mix.Tasks.Pleroma.User do users |> Enum.each(fn user -> shell_info( - "#{user.nickname} moderator: #{user.info.is_moderator}, admin: #{user.info.is_admin}, locked: #{ - user.info.locked - }, deactivated: #{user.info.deactivated}" + "#{user.nickname} moderator: #{user.is_moderator}, admin: #{user.is_admin}, locked: #{ + user.locked + }, deactivated: #{user.deactivated}" ) end) end) -- cgit v1.2.3 From 624e720aa45fd54575d17a2b5e77c67deef6eb86 Mon Sep 17 00:00:00 2001 From: Egor Kislitsyn Date: Tue, 3 Dec 2019 22:13:38 +0700 Subject: Add `with_move` query param to the notifications API --- lib/pleroma/notification.ex | 9 +++++++++ lib/pleroma/web/mastodon_api/mastodon_api.ex | 3 ++- 2 files changed, 11 insertions(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/pleroma/notification.ex b/lib/pleroma/notification.ex index f37e7ec67..6b6e1c2e1 100644 --- a/lib/pleroma/notification.ex +++ b/lib/pleroma/notification.ex @@ -57,6 +57,7 @@ defmodule Pleroma.Notification do |> exclude_muted(user, opts) |> exclude_blocked(user) |> exclude_visibility(opts) + |> exclude_move(opts) end defp exclude_blocked(query, user) do @@ -81,6 +82,14 @@ defmodule Pleroma.Notification do |> where([n, a, o, tm], is_nil(tm.user_id)) end + defp exclude_move(query, %{with_move: true}) do + query + end + + defp exclude_move(query, _opts) do + where(query, [n, a], fragment("?->>'type' != 'Move'", a.data)) + end + @valid_visibilities ~w[direct unlisted public private] defp exclude_visibility(query, %{exclude_visibilities: visibility}) diff --git a/lib/pleroma/web/mastodon_api/mastodon_api.ex b/lib/pleroma/web/mastodon_api/mastodon_api.ex index d875a5788..3e7dc4617 100644 --- a/lib/pleroma/web/mastodon_api/mastodon_api.ex +++ b/lib/pleroma/web/mastodon_api/mastodon_api.ex @@ -73,7 +73,8 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPI do exclude_types: {:array, :string}, exclude_visibilities: {:array, :string}, reblogs: :boolean, - with_muted: :boolean + with_muted: :boolean, + with_move: :boolean } changeset = cast({%{}, param_types}, params, Map.keys(param_types)) -- cgit v1.2.3 From 4b60d41db9d10e971ee91202389991da294c72de Mon Sep 17 00:00:00 2001 From: Maxim Filippov Date: Tue, 3 Dec 2019 23:54:07 +0900 Subject: Add report notes --- lib/pleroma/activity.ex | 13 +++++++ lib/pleroma/report_note.ex | 46 +++++++++++++++++++++++ lib/pleroma/web/activity_pub/activity_pub.ex | 8 ++++ lib/pleroma/web/activity_pub/utils.ex | 1 + lib/pleroma/web/admin_api/admin_api_controller.ex | 34 +++++++---------- lib/pleroma/web/admin_api/views/report_view.ex | 18 ++++++++- lib/pleroma/web/router.ex | 2 +- 7 files changed, 99 insertions(+), 23 deletions(-) create mode 100644 lib/pleroma/report_note.ex (limited to 'lib') diff --git a/lib/pleroma/activity.ex b/lib/pleroma/activity.ex index cd7a5aae9..37b2c041e 100644 --- a/lib/pleroma/activity.ex +++ b/lib/pleroma/activity.ex @@ -12,6 +12,7 @@ defmodule Pleroma.Activity do alias Pleroma.Notification alias Pleroma.Object alias Pleroma.Repo + alias Pleroma.ReportNote alias Pleroma.ThreadMute alias Pleroma.User @@ -47,6 +48,8 @@ defmodule Pleroma.Activity do has_one(:user_actor, User, on_delete: :nothing, foreign_key: :id) # This is a fake relation, do not use outside of with_preloaded_bookmark/get_bookmark has_one(:bookmark, Bookmark) + # This is a fake relation, do not use outside of with_preloaded_report_notes + has_many(:report_notes, ReportNote) has_many(:notifications, Notification, on_delete: :delete_all) # Attention: this is a fake relation, don't try to preload it blindly and expect it to work! @@ -113,6 +116,16 @@ defmodule Pleroma.Activity do def with_preloaded_bookmark(query, _), do: query + def with_preloaded_report_notes(query) do + from([a] in query, + left_join: r in ReportNote, + on: a.id == r.activity_id, + preload: [report_notes: r] + ) + end + + def with_preloaded_report_notes(query, _), do: query + def with_set_thread_muted_field(query, %User{} = user) do from([a] in query, left_join: tm in ThreadMute, diff --git a/lib/pleroma/report_note.ex b/lib/pleroma/report_note.ex new file mode 100644 index 000000000..91102696b --- /dev/null +++ b/lib/pleroma/report_note.ex @@ -0,0 +1,46 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2019 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.ReportNote do + use Ecto.Schema + + import Ecto.Changeset + import Ecto.Query + + alias Pleroma.Activity + alias Pleroma.Repo + alias Pleroma.ReportNote + alias Pleroma.User + + @type t :: %__MODULE__{} + + schema "report_notes" do + field(:content, :string) + belongs_to(:user, User, type: FlakeId.Ecto.CompatType) + belongs_to(:activity, Activity, type: FlakeId.Ecto.CompatType) + + timestamps() + end + + @spec create(FlakeId.Ecto.CompatType.t(), FlakeId.Ecto.CompatType.t(), String.t()) :: + {:ok, ReportNote.t()} | {:error, Changeset.t()} + def create(user_id, activity_id, content) do + attrs = %{ + user_id: user_id, + activity_id: activity_id, + content: content + } + + %ReportNote{} + |> cast(attrs, [:user_id, :activity_id, :content]) + |> validate_required([:user_id, :activity_id, :content]) + |> Repo.insert() + end + + def get_all_for_status(status_id) do + ReportNote + |> where(activity_id: ^status_id) + |> Repo.all() + end +end diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex index f32d04175..5c6cdfcf1 100644 --- a/lib/pleroma/web/activity_pub/activity_pub.ex +++ b/lib/pleroma/web/activity_pub/activity_pub.ex @@ -1018,6 +1018,13 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do |> Activity.with_preloaded_bookmark(opts["user"]) end + defp maybe_preload_report_notes(query, %{"preload_report_notes" => true}) do + query + |> Activity.with_preloaded_report_notes() + end + + defp maybe_preload_report_notes(query, _), do: query + defp maybe_set_thread_muted_field(query, %{"skip_preload" => true}), do: query defp maybe_set_thread_muted_field(query, opts) do @@ -1045,6 +1052,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do Activity |> maybe_preload_objects(opts) |> maybe_preload_bookmarks(opts) + |> maybe_preload_report_notes(opts) |> maybe_set_thread_muted_field(opts) |> maybe_order(opts) |> restrict_recipients(recipients, opts["user"]) diff --git a/lib/pleroma/web/activity_pub/utils.ex b/lib/pleroma/web/activity_pub/utils.ex index 01aacbde3..079d458ba 100644 --- a/lib/pleroma/web/activity_pub/utils.ex +++ b/lib/pleroma/web/activity_pub/utils.ex @@ -781,6 +781,7 @@ defmodule Pleroma.Web.ActivityPub.Utils do params |> Map.put("type", "Flag") |> Map.put("skip_preload", true) + |> Map.put("preload_report_notes", true) |> Map.put("total", true) |> Map.put("limit", page_size) |> Map.put("offset", (page - 1) * page_size) diff --git a/lib/pleroma/web/admin_api/admin_api_controller.ex b/lib/pleroma/web/admin_api/admin_api_controller.ex index 24fdc3c82..ee32bac45 100644 --- a/lib/pleroma/web/admin_api/admin_api_controller.ex +++ b/lib/pleroma/web/admin_api/admin_api_controller.ex @@ -7,6 +7,7 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do alias Pleroma.Activity alias Pleroma.ModerationLog alias Pleroma.Plugs.OAuthScopesPlug + alias Pleroma.ReportNote alias Pleroma.User alias Pleroma.UserInviteToken alias Pleroma.Web.ActivityPub.ActivityPub @@ -641,9 +642,11 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do def list_reports(conn, params) do {page, page_size} = page_params(params) + reports = Utils.get_reports(params, page, page_size) + conn |> put_view(ReportView) - |> render("index.json", %{reports: Utils.get_reports(params, page, page_size)}) + |> render("index.json", %{reports: reports}) end def list_grouped_reports(conn, _params) do @@ -687,32 +690,21 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do end end - def report_respond(%{assigns: %{user: user}} = conn, %{"id" => id} = params) do - with false <- is_nil(params["status"]), - %Activity{} <- Activity.get_by_id(id) do - params = - params - |> Map.put("in_reply_to_status_id", id) - |> Map.put("visibility", "direct") - - {:ok, activity} = CommonAPI.post(user, params) - + def report_notes_create(%{assigns: %{user: user}} = conn, %{ + "id" => status_id, + "content" => content + }) do + with {:ok, _} <- ReportNote.create(user.id, status_id, content) do ModerationLog.insert_log(%{ action: "report_response", actor: user, - subject: activity, - text: params["status"] + subject: Activity.get_by_id(status_id), + text: content }) - conn - |> put_view(StatusView) - |> render("show.json", %{activity: activity}) + json_response(conn, :no_content, "") else - true -> - {:param_cast, nil} - - nil -> - {:error, :not_found} + _ -> json_response(conn, :bad_request, "") end end diff --git a/lib/pleroma/web/admin_api/views/report_view.ex b/lib/pleroma/web/admin_api/views/report_view.ex index ca88595c7..80ca62691 100644 --- a/lib/pleroma/web/admin_api/views/report_view.ex +++ b/lib/pleroma/web/admin_api/views/report_view.ex @@ -38,7 +38,8 @@ defmodule Pleroma.Web.AdminAPI.ReportView do content: content, created_at: created_at, statuses: StatusView.render("index.json", %{activities: statuses, as: :activity}), - state: report.data["state"] + state: report.data["state"], + notes: render(__MODULE__, "index_notes.json", %{notes: report.report_notes}) } end @@ -62,6 +63,21 @@ defmodule Pleroma.Web.AdminAPI.ReportView do } end + def render("index_notes.json", %{notes: notes}) when is_list(notes) do + Enum.map(notes, &render(__MODULE__, "show_note.json", &1)) + end + + def render("index_notes.json", _), do: [] + + def render("show_note.json", %{content: content, user_id: user_id}) do + user = User.get_by_id(user_id) + + %{ + content: content, + user: merge_account_views(user) + } + end + defp merge_account_views(%User{} = user) do Pleroma.Web.MastodonAPI.AccountView.render("show.json", %{user: user}) |> Map.merge(Pleroma.Web.AdminAPI.AccountView.render("show.json", %{user: user})) diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex index e6c4f6f14..af220a98b 100644 --- a/lib/pleroma/web/router.ex +++ b/lib/pleroma/web/router.ex @@ -187,7 +187,7 @@ defmodule Pleroma.Web.Router do get("/grouped_reports", AdminAPIController, :list_grouped_reports) get("/reports/:id", AdminAPIController, :report_show) patch("/reports", AdminAPIController, :reports_update) - post("/reports/:id/respond", AdminAPIController, :report_respond) + post("/reports/:id/notes", AdminAPIController, :report_notes_create) put("/statuses/:id", AdminAPIController, :status_update) delete("/statuses/:id", AdminAPIController, :status_delete) -- cgit v1.2.3 From 05fb8d0084553a3ed7d1f10212f49771ce05570f Mon Sep 17 00:00:00 2001 From: Egor Kislitsyn Date: Tue, 3 Dec 2019 22:31:12 +0700 Subject: Fix Pleroma.FollowingRelationship.move_following/2 --- lib/pleroma/following_relationship.ex | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/following_relationship.ex b/lib/pleroma/following_relationship.ex index a03c9bd30..0b0219b82 100644 --- a/lib/pleroma/following_relationship.ex +++ b/lib/pleroma/following_relationship.ex @@ -121,8 +121,12 @@ defmodule Pleroma.FollowingRelationship do Pleroma.Web.CommonAPI.follow(following_relationship.follower, target) end) |> case do - [] -> :ok - _ -> move_following(origin, target) + [] -> + User.update_follower_count(origin) + :ok + + _ -> + move_following(origin, target) end end end -- cgit v1.2.3 From aa97fe8f175c3618a04bb45e6aa7c37e26259577 Mon Sep 17 00:00:00 2001 From: lain Date: Wed, 4 Dec 2019 12:48:34 +0100 Subject: ChatChannel: Ignore messages that are too long. --- lib/pleroma/application.ex | 2 -- lib/pleroma/web/chat_channel.ex | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/application.ex b/lib/pleroma/application.ex index 9dbd1e26b..57462740c 100644 --- a/lib/pleroma/application.ex +++ b/lib/pleroma/application.ex @@ -147,8 +147,6 @@ defmodule Pleroma.Application do defp oauth_cleanup_child(_), do: [] - defp chat_child(:test, _), do: [] - defp chat_child(_env, true) do [Pleroma.Web.ChatChannel.ChatChannelState] end diff --git a/lib/pleroma/web/chat_channel.ex b/lib/pleroma/web/chat_channel.ex index 08841a3e8..840414933 100644 --- a/lib/pleroma/web/chat_channel.ex +++ b/lib/pleroma/web/chat_channel.ex @@ -20,7 +20,7 @@ defmodule Pleroma.Web.ChatChannel do def handle_in("new_msg", %{"text" => text}, %{assigns: %{user_name: user_name}} = socket) do text = String.trim(text) - if String.length(text) > 0 do + if String.length(text) in 1..Pleroma.Config.get([:instance, :chat_limit]) do author = User.get_cached_by_nickname(user_name) author = Pleroma.Web.MastodonAPI.AccountView.render("show.json", user: author) message = ChatChannelState.add_message(%{text: text, author: author}) -- cgit v1.2.3 From 9f99640cfc81f28c0b6cdb5f6ef065b3e46f5f23 Mon Sep 17 00:00:00 2001 From: rinpatch Date: Thu, 5 Dec 2019 02:50:38 +0300 Subject: ActivityPub: Fix deletes being exempt from MRF Closes #1461 --- lib/pleroma/activity.ex | 5 +++-- lib/pleroma/activity/queries.ex | 8 ++++++++ lib/pleroma/object.ex | 2 +- lib/pleroma/web/activity_pub/activity_pub.ex | 5 +++-- 4 files changed, 15 insertions(+), 5 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/activity.ex b/lib/pleroma/activity.ex index f180c1e33..480b261cf 100644 --- a/lib/pleroma/activity.ex +++ b/lib/pleroma/activity.ex @@ -241,9 +241,10 @@ defmodule Pleroma.Activity do def normalize(ap_id) when is_binary(ap_id), do: get_by_ap_id_with_object(ap_id) def normalize(_), do: nil - def delete_by_ap_id(id) when is_binary(id) do + def delete_all_by_object_ap_id(id) when is_binary(id) do id |> Queries.by_object_id() + |> Queries.exclude_type("Delete") |> select([u], u) |> Repo.delete_all() |> elem(1) @@ -255,7 +256,7 @@ defmodule Pleroma.Activity do |> purge_web_resp_cache() end - def delete_by_ap_id(_), do: nil + def delete_all_by_object_ap_id(_), do: nil defp purge_web_resp_cache(%Activity{} = activity) do %{path: path} = URI.parse(activity.data["id"]) diff --git a/lib/pleroma/activity/queries.ex b/lib/pleroma/activity/queries.ex index 949f010a8..26bc1099d 100644 --- a/lib/pleroma/activity/queries.ex +++ b/lib/pleroma/activity/queries.ex @@ -64,4 +64,12 @@ defmodule Pleroma.Activity.Queries do where: fragment("(?)->>'type' = ?", activity.data, ^activity_type) ) end + + @spec exclude_type(query, String.t()) :: query + def exclude_type(query \\ Activity, activity_type) do + from( + activity in query, + where: fragment("(?)->>'type' != ?", activity.data, ^activity_type) + ) + end end diff --git a/lib/pleroma/object.ex b/lib/pleroma/object.ex index b4ed3a9b2..ff0e59241 100644 --- a/lib/pleroma/object.ex +++ b/lib/pleroma/object.ex @@ -147,7 +147,7 @@ defmodule Pleroma.Object do def delete(%Object{data: %{"id" => id}} = object) do with {:ok, _obj} = swap_object_with_tombstone(object), - deleted_activity = Activity.delete_by_ap_id(id), + deleted_activity = Activity.delete_all_by_object_ap_id(id), {:ok, true} <- Cachex.del(:object_cache, "object:#{id}"), {:ok, _} <- Cachex.del(:web_resp_cache, URI.parse(id).path) do {:ok, object, deleted_activity} diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex index d6a425d8b..c8160b0cf 100644 --- a/lib/pleroma/web/activity_pub/activity_pub.ex +++ b/lib/pleroma/web/activity_pub/activity_pub.ex @@ -456,17 +456,18 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do user = User.get_cached_by_ap_id(actor) to = (object.data["to"] || []) ++ (object.data["cc"] || []) - with {:ok, object, activity} <- Object.delete(object), + with create_activity <- Activity.get_create_by_object_ap_id(id), data <- %{ "type" => "Delete", "actor" => actor, "object" => id, "to" => to, - "deleted_activity_id" => activity && activity.id + "deleted_activity_id" => create_activity && create_activity.id } |> maybe_put("id", activity_id), {:ok, activity} <- insert(data, local, false), + {:ok, object, _create_activity} <- Object.delete(object), stream_out_participations(object, user), _ <- decrease_replies_count_if_reply(object), {:ok, _actor} <- decrease_note_count_if_public(user, object), -- cgit v1.2.3 From af42c00cfffb2cd8e93857cd1cf2901113c45bd2 Mon Sep 17 00:00:00 2001 From: Ivan Tashkinov Date: Fri, 6 Dec 2019 00:25:44 +0300 Subject: [#1427] Reworked admin scopes support. Requalified users.is_admin flag as legacy accessor to admin actions in case token lacks admin scope(s). --- lib/mix/tasks/pleroma/user.ex | 9 ++----- lib/pleroma/config.ex | 7 ++++++ lib/pleroma/plugs/user_is_admin_plug.ex | 28 ++++++++++++++++++---- lib/pleroma/user.ex | 28 ++++++++++++++++------ lib/pleroma/web/admin_api/admin_api_controller.ex | 18 +++++++------- lib/pleroma/web/oauth/scopes.ex | 2 +- .../controllers/emoji_api_controller.ex | 2 +- 7 files changed, 66 insertions(+), 28 deletions(-) (limited to 'lib') diff --git a/lib/mix/tasks/pleroma/user.ex b/lib/mix/tasks/pleroma/user.ex index 4e3b80db3..8c4739221 100644 --- a/lib/mix/tasks/pleroma/user.ex +++ b/lib/mix/tasks/pleroma/user.ex @@ -8,7 +8,6 @@ defmodule Mix.Tasks.Pleroma.User do alias Ecto.Changeset alias Pleroma.User alias Pleroma.UserInviteToken - alias Pleroma.Web.OAuth @shortdoc "Manages Pleroma users" @moduledoc File.read!("docs/administration/CLI_tasks/user.md") @@ -354,8 +353,7 @@ defmodule Mix.Tasks.Pleroma.User do start_pleroma() with %User{local: true} = user <- User.get_cached_by_nickname(nickname) do - OAuth.Token.delete_user_tokens(user) - OAuth.Authorization.delete_user_authorizations(user) + User.global_sign_out(user) shell_info("#{nickname} signed out from all apps.") else @@ -375,10 +373,7 @@ defmodule Mix.Tasks.Pleroma.User do end defp set_admin(user, value) do - {:ok, user} = - user - |> Changeset.change(%{is_admin: value}) - |> User.update_and_set_cache() + {:ok, user} = User.admin_api_update(user, %{is_admin: value}) shell_info("Admin status of #{user.nickname}: #{user.is_admin}") user diff --git a/lib/pleroma/config.ex b/lib/pleroma/config.ex index fcc039710..cadab2f15 100644 --- a/lib/pleroma/config.ex +++ b/lib/pleroma/config.ex @@ -65,4 +65,11 @@ defmodule Pleroma.Config do def oauth_consumer_strategies, do: get([:auth, :oauth_consumer_strategies], []) def oauth_consumer_enabled?, do: oauth_consumer_strategies() != [] + + def enforce_oauth_admin_scope_usage?, do: !!get([:auth, :enforce_oauth_admin_scope_usage]) + + def oauth_admin_scopes(scope) do + ["admin:#{scope}"] ++ + if enforce_oauth_admin_scope_usage?(), do: [], else: [scope] + end end diff --git a/lib/pleroma/plugs/user_is_admin_plug.ex b/lib/pleroma/plugs/user_is_admin_plug.ex index ee808f31f..8814556f1 100644 --- a/lib/pleroma/plugs/user_is_admin_plug.ex +++ b/lib/pleroma/plugs/user_is_admin_plug.ex @@ -5,19 +5,39 @@ defmodule Pleroma.Plugs.UserIsAdminPlug do import Pleroma.Web.TranslationHelpers import Plug.Conn + alias Pleroma.User + alias Pleroma.Web.OAuth def init(options) do options end - def call(%{assigns: %{user: %User{is_admin: true}}} = conn, _) do - conn + def call(%Plug.Conn{assigns: %{token: %OAuth.Token{scopes: oauth_scopes} = _token}} = conn, _) do + if OAuth.Scopes.contains_admin_scopes?(oauth_scopes) do + # Note: checking for _any_ admin scope presence, not necessarily fitting requested action. + # Thus, controller must explicitly invoke OAuthScopesPlug to verify scope requirements. + conn + else + fail(conn) + end + end + + unless Pleroma.Config.enforce_oauth_admin_scope_usage?() do + # To do: once AdminFE makes use of "admin" scope, disable the following func definition + # (fail on no admin scope(s) in token even if `is_admin` is true) + def call(%Plug.Conn{assigns: %{user: %User{is_admin: true}}} = conn, _) do + conn + end end def call(conn, _) do + fail(conn) + end + + defp fail(conn) do conn - |> render_error(:forbidden, "User is not admin.") - |> halt + |> render_error(:forbidden, "User is not an admin or OAuth admin scope is not granted.") + |> halt() end end diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex index fcb1d5143..d05dccd3d 100644 --- a/lib/pleroma/user.ex +++ b/lib/pleroma/user.ex @@ -1732,13 +1732,27 @@ defmodule Pleroma.User do end def admin_api_update(user, params) do - user - |> cast(params, [ - :is_moderator, - :is_admin, - :show_role - ]) - |> update_and_set_cache() + 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 + # Tokens & authorizations containing any admin scopes must be revoked (revoking all) + global_sign_out(user) + end + + {:ok, updated_user} + end + end + + @doc "Signs user out of all applications" + def global_sign_out(user) do + OAuth.Authorization.delete_user_authorizations(user) + OAuth.Token.delete_user_tokens(user) end def mascot_update(user, url) do diff --git a/lib/pleroma/web/admin_api/admin_api_controller.ex b/lib/pleroma/web/admin_api/admin_api_controller.ex index 01cd12c96..f9ace00d7 100644 --- a/lib/pleroma/web/admin_api/admin_api_controller.ex +++ b/lib/pleroma/web/admin_api/admin_api_controller.ex @@ -30,13 +30,13 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do plug( OAuthScopesPlug, - %{scopes: ["admin:read:accounts", "read:accounts"]} + %{scopes: Pleroma.Config.oauth_admin_scopes("read:accounts")} when action in [:list_users, :user_show, :right_get, :invites] ) plug( OAuthScopesPlug, - %{scopes: ["admin:write:accounts", "write:accounts"]} + %{scopes: Pleroma.Config.oauth_admin_scopes("write:accounts")} when action in [ :get_invite_token, :revoke_invite, @@ -58,35 +58,37 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do plug( OAuthScopesPlug, - %{scopes: ["admin:read:reports", "read:reports"]} when action in [:list_reports, :report_show] + %{scopes: Pleroma.Config.oauth_admin_scopes("read:reports")} + when action in [:list_reports, :report_show] ) plug( OAuthScopesPlug, - %{scopes: ["admin:reports", "write:reports"]} + %{scopes: Pleroma.Config.oauth_admin_scopes("write:reports")} when action in [:report_update_state, :report_respond] ) plug( OAuthScopesPlug, - %{scopes: ["admin:read:statuses", "read:statuses"]} when action == :list_user_statuses + %{scopes: Pleroma.Config.oauth_admin_scopes("read:statuses")} + when action == :list_user_statuses ) plug( OAuthScopesPlug, - %{scopes: ["admin:write:statuses", "write:statuses"]} + %{scopes: Pleroma.Config.oauth_admin_scopes("write:statuses")} when action in [:status_update, :status_delete] ) plug( OAuthScopesPlug, - %{scopes: ["admin:read", "read"]} + %{scopes: Pleroma.Config.oauth_admin_scopes("read")} when action in [:config_show, :migrate_to_db, :migrate_from_db, :list_log] ) plug( OAuthScopesPlug, - %{scopes: ["admin:write", "write"]} + %{scopes: Pleroma.Config.oauth_admin_scopes("write")} when action in [:relay_follow, :relay_unfollow, :config_update] ) diff --git a/lib/pleroma/web/oauth/scopes.ex b/lib/pleroma/web/oauth/scopes.ex index 0c8796ecb..5e04652c2 100644 --- a/lib/pleroma/web/oauth/scopes.ex +++ b/lib/pleroma/web/oauth/scopes.ex @@ -83,7 +83,7 @@ defmodule Pleroma.Web.OAuth.Scopes do end end - defp contains_admin_scopes?(scopes) do + def contains_admin_scopes?(scopes) do scopes |> OAuthScopesPlug.filter_descendants(["admin"]) |> Enum.any?() diff --git a/lib/pleroma/web/pleroma_api/controllers/emoji_api_controller.ex b/lib/pleroma/web/pleroma_api/controllers/emoji_api_controller.ex index 1e8c62e3a..6f286032e 100644 --- a/lib/pleroma/web/pleroma_api/controllers/emoji_api_controller.ex +++ b/lib/pleroma/web/pleroma_api/controllers/emoji_api_controller.ex @@ -7,7 +7,7 @@ defmodule Pleroma.Web.PleromaAPI.EmojiAPIController do plug( OAuthScopesPlug, - %{scopes: ["admin:write", "write"]} + %{scopes: Pleroma.Config.oauth_admin_scopes("write")} when action in [ :create, :delete, -- cgit v1.2.3 From 08c89fd2b89614baaf4bfce067cfec9db96f2d2c Mon Sep 17 00:00:00 2001 From: Maxim Filippov Date: Fri, 6 Dec 2019 17:17:24 +0900 Subject: Fix incorrect report count --- lib/pleroma/pagination.ex | 5 ++++- lib/pleroma/web/admin_api/views/report_view.ex | 5 +++-- 2 files changed, 7 insertions(+), 3 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/pagination.ex b/lib/pleroma/pagination.ex index 9d279fba7..183ef770e 100644 --- a/lib/pleroma/pagination.ex +++ b/lib/pleroma/pagination.ex @@ -35,7 +35,10 @@ defmodule Pleroma.Pagination do end def fetch_paginated(query, %{"total" => true} = params, :offset) do - total = Repo.aggregate(query, :count, :id) + total = + query + |> Ecto.Query.exclude(:left_join) + |> Repo.aggregate(:count, :id) %{ total: total, diff --git a/lib/pleroma/web/admin_api/views/report_view.ex b/lib/pleroma/web/admin_api/views/report_view.ex index 80ca62691..f5c6ba401 100644 --- a/lib/pleroma/web/admin_api/views/report_view.ex +++ b/lib/pleroma/web/admin_api/views/report_view.ex @@ -69,12 +69,13 @@ defmodule Pleroma.Web.AdminAPI.ReportView do def render("index_notes.json", _), do: [] - def render("show_note.json", %{content: content, user_id: user_id}) do + def render("show_note.json", %{content: content, user_id: user_id, inserted_at: inserted_at}) do user = User.get_by_id(user_id) %{ content: content, - user: merge_account_views(user) + user: merge_account_views(user), + created_at: inserted_at } end -- cgit v1.2.3 From e8cee4d9a0ea13db8d087e42eb17939bb8b11f0b Mon Sep 17 00:00:00 2001 From: lain Date: Fri, 6 Dec 2019 14:25:13 +0100 Subject: ActivityPub: For user timelines, respects blocks. Unless the timeline belongs to a blocked user. --- lib/pleroma/web/activity_pub/activity_pub.ex | 9 +++++++++ lib/pleroma/web/mastodon_api/controllers/account_controller.ex | 6 +++++- 2 files changed, 14 insertions(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex index b07a94701..c5bc1ef0d 100644 --- a/lib/pleroma/web/activity_pub/activity_pub.ex +++ b/lib/pleroma/web/activity_pub/activity_pub.ex @@ -748,6 +748,15 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do |> Map.put("whole_db", true) |> Map.put("pinned_activity_ids", user.pinned_activities) + params = + if User.blocks?(reading_user, user) do + params + else + params + |> Map.put("blocking_user", reading_user) + |> Map.put("muting_user", reading_user) + end + recipients = user_activities_recipients(%{ "godmode" => params["godmode"], diff --git a/lib/pleroma/web/mastodon_api/controllers/account_controller.ex b/lib/pleroma/web/mastodon_api/controllers/account_controller.ex index d71a14434..d19029cb5 100644 --- a/lib/pleroma/web/mastodon_api/controllers/account_controller.ex +++ b/lib/pleroma/web/mastodon_api/controllers/account_controller.ex @@ -249,7 +249,11 @@ defmodule Pleroma.Web.MastodonAPI.AccountController do @doc "GET /api/v1/accounts/:id/statuses" def statuses(%{assigns: %{user: reading_user}} = conn, params) do with %User{} = user <- User.get_cached_by_nickname_or_id(params["id"], for: reading_user) do - params = Map.put(params, "tag", params["tagged"]) + params = + params + |> Map.put("tag", params["tagged"]) + |> Map.delete("godmode") + activities = ActivityPub.fetch_user_activities(user, reading_user, params) conn -- cgit v1.2.3 From 93a80ee9155bf5257aa92afaca2fe017f28aabfa Mon Sep 17 00:00:00 2001 From: Ivan Tashkinov Date: Fri, 6 Dec 2019 16:56:23 +0300 Subject: [#1427] Bugfix for `enforce_oauth_admin_scope_usage`. Admin API documentation entry. --- lib/pleroma/plugs/user_is_admin_plug.ex | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/plugs/user_is_admin_plug.ex b/lib/pleroma/plugs/user_is_admin_plug.ex index 8814556f1..814029dce 100644 --- a/lib/pleroma/plugs/user_is_admin_plug.ex +++ b/lib/pleroma/plugs/user_is_admin_plug.ex @@ -6,13 +6,20 @@ defmodule Pleroma.Plugs.UserIsAdminPlug do import Pleroma.Web.TranslationHelpers import Plug.Conn - alias Pleroma.User alias Pleroma.Web.OAuth def init(options) do options end + unless Pleroma.Config.enforce_oauth_admin_scope_usage?() do + # To do: once AdminFE makes use of "admin" scope, disable the following func definition + # (fail on no admin scope(s) in token even if `is_admin` is true) + def call(%Plug.Conn{assigns: %{user: %Pleroma.User{is_admin: true}}} = conn, _) do + conn + end + end + def call(%Plug.Conn{assigns: %{token: %OAuth.Token{scopes: oauth_scopes} = _token}} = conn, _) do if OAuth.Scopes.contains_admin_scopes?(oauth_scopes) do # Note: checking for _any_ admin scope presence, not necessarily fitting requested action. @@ -23,14 +30,6 @@ defmodule Pleroma.Plugs.UserIsAdminPlug do end end - unless Pleroma.Config.enforce_oauth_admin_scope_usage?() do - # To do: once AdminFE makes use of "admin" scope, disable the following func definition - # (fail on no admin scope(s) in token even if `is_admin` is true) - def call(%Plug.Conn{assigns: %{user: %User{is_admin: true}}} = conn, _) do - conn - end - end - def call(conn, _) do fail(conn) end -- cgit v1.2.3 From 40e1817f707c3c2ef253009c7363cd81b11322a6 Mon Sep 17 00:00:00 2001 From: Ivan Tashkinov Date: Fri, 6 Dec 2019 20:33:47 +0300 Subject: [#1427] Fixes / improvements of admin scopes support. Added tests. --- lib/pleroma/plugs/oauth_scopes_plug.ex | 9 +++++ lib/pleroma/plugs/user_is_admin_plug.ex | 38 +++++++++------------- lib/pleroma/web/admin_api/admin_api_controller.ex | 16 ++++----- .../controllers/emoji_api_controller.ex | 2 +- 4 files changed, 33 insertions(+), 32 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/plugs/oauth_scopes_plug.ex b/lib/pleroma/plugs/oauth_scopes_plug.ex index a3278dbef..3201fb399 100644 --- a/lib/pleroma/plugs/oauth_scopes_plug.ex +++ b/lib/pleroma/plugs/oauth_scopes_plug.ex @@ -6,6 +6,7 @@ defmodule Pleroma.Plugs.OAuthScopesPlug do import Plug.Conn import Pleroma.Web.Gettext + alias Pleroma.Config alias Pleroma.Plugs.EnsurePublicOrAuthenticatedPlug @behaviour Plug @@ -15,6 +16,14 @@ defmodule Pleroma.Plugs.OAuthScopesPlug do def call(%Plug.Conn{assigns: assigns} = conn, %{scopes: scopes} = options) do op = options[:op] || :| token = assigns[:token] + + scopes = + if options[:admin] do + Config.oauth_admin_scopes(scopes) + else + scopes + end + matched_scopes = token && filter_descendants(scopes, token.scopes) cond do diff --git a/lib/pleroma/plugs/user_is_admin_plug.ex b/lib/pleroma/plugs/user_is_admin_plug.ex index 814029dce..4a0e43b00 100644 --- a/lib/pleroma/plugs/user_is_admin_plug.ex +++ b/lib/pleroma/plugs/user_is_admin_plug.ex @@ -12,31 +12,23 @@ defmodule Pleroma.Plugs.UserIsAdminPlug do options end - unless Pleroma.Config.enforce_oauth_admin_scope_usage?() do - # To do: once AdminFE makes use of "admin" scope, disable the following func definition - # (fail on no admin scope(s) in token even if `is_admin` is true) - def call(%Plug.Conn{assigns: %{user: %Pleroma.User{is_admin: true}}} = conn, _) do - conn - end - end + def call(%Plug.Conn{assigns: assigns} = conn, _) do + token = assigns[:token] + user = assigns[:user] - def call(%Plug.Conn{assigns: %{token: %OAuth.Token{scopes: oauth_scopes} = _token}} = conn, _) do - if OAuth.Scopes.contains_admin_scopes?(oauth_scopes) do - # Note: checking for _any_ admin scope presence, not necessarily fitting requested action. - # Thus, controller must explicitly invoke OAuthScopesPlug to verify scope requirements. - conn - else - fail(conn) - end - end + cond 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. + conn - def call(conn, _) do - fail(conn) - end + user && user.is_admin && !Pleroma.Config.enforce_oauth_admin_scope_usage?() -> + conn - defp fail(conn) do - conn - |> render_error(:forbidden, "User is not an admin or OAuth admin scope is not granted.") - |> halt() + true -> + conn + |> render_error(:forbidden, "User is not an admin or OAuth admin scope is not granted.") + |> halt() + end end end diff --git a/lib/pleroma/web/admin_api/admin_api_controller.ex b/lib/pleroma/web/admin_api/admin_api_controller.ex index 34d147107..0a63f3fe6 100644 --- a/lib/pleroma/web/admin_api/admin_api_controller.ex +++ b/lib/pleroma/web/admin_api/admin_api_controller.ex @@ -30,13 +30,13 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do plug( OAuthScopesPlug, - %{scopes: Pleroma.Config.oauth_admin_scopes("read:accounts")} + %{scopes: ["read:accounts"], admin: true} when action in [:list_users, :user_show, :right_get, :invites] ) plug( OAuthScopesPlug, - %{scopes: Pleroma.Config.oauth_admin_scopes("write:accounts")} + %{scopes: ["write:accounts"], admin: true} when action in [ :get_invite_token, :revoke_invite, @@ -58,37 +58,37 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do plug( OAuthScopesPlug, - %{scopes: Pleroma.Config.oauth_admin_scopes("read:reports")} + %{scopes: ["read:reports"], admin: true} when action in [:list_reports, :report_show] ) plug( OAuthScopesPlug, - %{scopes: Pleroma.Config.oauth_admin_scopes("write:reports")} + %{scopes: ["write:reports"], admin: true} when action in [:report_update_state, :report_respond] ) plug( OAuthScopesPlug, - %{scopes: Pleroma.Config.oauth_admin_scopes("read:statuses")} + %{scopes: ["read:statuses"], admin: true} when action == :list_user_statuses ) plug( OAuthScopesPlug, - %{scopes: Pleroma.Config.oauth_admin_scopes("write:statuses")} + %{scopes: ["write:statuses"], admin: true} when action in [:status_update, :status_delete] ) plug( OAuthScopesPlug, - %{scopes: Pleroma.Config.oauth_admin_scopes("read")} + %{scopes: ["read"], admin: true} when action in [:config_show, :migrate_to_db, :migrate_from_db, :list_log] ) plug( OAuthScopesPlug, - %{scopes: Pleroma.Config.oauth_admin_scopes("write")} + %{scopes: ["write"], admin: true} when action in [:relay_follow, :relay_unfollow, :config_update] ) diff --git a/lib/pleroma/web/pleroma_api/controllers/emoji_api_controller.ex b/lib/pleroma/web/pleroma_api/controllers/emoji_api_controller.ex index 6f286032e..69dfa92e3 100644 --- a/lib/pleroma/web/pleroma_api/controllers/emoji_api_controller.ex +++ b/lib/pleroma/web/pleroma_api/controllers/emoji_api_controller.ex @@ -7,7 +7,7 @@ defmodule Pleroma.Web.PleromaAPI.EmojiAPIController do plug( OAuthScopesPlug, - %{scopes: Pleroma.Config.oauth_admin_scopes("write")} + %{scopes: ["write"], admin: true} when action in [ :create, :delete, -- cgit v1.2.3 From 1770602747ae95d95d12c5601f99ced8699e8947 Mon Sep 17 00:00:00 2001 From: Ivan Tashkinov Date: Sat, 7 Dec 2019 17:49:53 +0300 Subject: [#1427] Extra check that admin OAuth scope is used by admin. Adjusted tests. --- lib/pleroma/plugs/user_is_admin_plug.ex | 24 ++++++++++++++++-------- lib/pleroma/user.ex | 3 ++- 2 files changed, 18 insertions(+), 9 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/plugs/user_is_admin_plug.ex b/lib/pleroma/plugs/user_is_admin_plug.ex index 4a0e43b00..582fb1f92 100644 --- a/lib/pleroma/plugs/user_is_admin_plug.ex +++ b/lib/pleroma/plugs/user_is_admin_plug.ex @@ -6,29 +6,37 @@ defmodule Pleroma.Plugs.UserIsAdminPlug do import Pleroma.Web.TranslationHelpers import Plug.Conn + alias Pleroma.User alias Pleroma.Web.OAuth def init(options) do options end - def call(%Plug.Conn{assigns: assigns} = conn, _) do + def call(%{assigns: %{user: %User{is_admin: true}} = assigns} = conn, _) do token = assigns[:token] - user = assigns[:user] cond do + not Pleroma.Config.enforce_oauth_admin_scope_usage?() -> + conn + 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. conn - user && user.is_admin && !Pleroma.Config.enforce_oauth_admin_scope_usage?() -> - conn - true -> - conn - |> render_error(:forbidden, "User is not an admin or OAuth admin scope is not granted.") - |> halt() + fail(conn) end end + + def call(conn, _) do + fail(conn) + end + + defp fail(conn) do + conn + |> render_error(:forbidden, "User is not an admin or OAuth admin scope is not granted.") + |> halt() + end end diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex index 7b8222ce1..1006b5bf9 100644 --- a/lib/pleroma/user.ex +++ b/lib/pleroma/user.ex @@ -1736,7 +1736,8 @@ defmodule Pleroma.User do with {:ok, updated_user} <- update_and_set_cache(changeset) do if user.is_admin && !updated_user.is_admin do - # Tokens & authorizations containing any admin scopes must be revoked (revoking all) + # Tokens & authorizations containing any admin scopes must be revoked (revoking all). + # This is an extra safety measure (tokens' admin scopes won't be accepted for non-admins). global_sign_out(user) end -- cgit v1.2.3 From a7f77785c2675b5f9f7ede85e92ec50444945e54 Mon Sep 17 00:00:00 2001 From: Maxim Filippov Date: Sun, 8 Dec 2019 11:27:23 +0300 Subject: Implement report notes destruction --- lib/pleroma/moderation_log.ex | 42 +++++++++++++++++++---- lib/pleroma/report_note.ex | 10 +++--- lib/pleroma/web/admin_api/admin_api_controller.ex | 26 +++++++++++--- lib/pleroma/web/admin_api/views/report_view.ex | 10 ++++-- lib/pleroma/web/router.ex | 1 + 5 files changed, 73 insertions(+), 16 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/moderation_log.ex b/lib/pleroma/moderation_log.ex index 706f089dc..c81477f48 100644 --- a/lib/pleroma/moderation_log.ex +++ b/lib/pleroma/moderation_log.ex @@ -128,17 +128,35 @@ defmodule Pleroma.ModerationLog do {:ok, ModerationLog} | {:error, any} def insert_log(%{ actor: %User{} = actor, - action: "report_response", + action: "report_note", subject: %Activity{} = subject, text: text }) do %ModerationLog{ data: %{ "actor" => user_to_map(actor), - "action" => "report_response", + "action" => "report_note", "subject" => report_to_map(subject), - "text" => text, - "message" => "" + "text" => text + } + } + |> insert_log_entry_with_message() + end + + @spec insert_log(%{actor: User, subject: Activity, action: String.t(), text: String.t()}) :: + {:ok, ModerationLog} | {:error, any} + def insert_log(%{ + actor: %User{} = actor, + action: "report_note_delete", + subject: %Activity{} = subject, + text: text + }) do + %ModerationLog{ + data: %{ + "actor" => user_to_map(actor), + "action" => "report_note_delete", + "subject" => report_to_map(subject), + "text" => text } } |> insert_log_entry_with_message() @@ -556,12 +574,24 @@ defmodule Pleroma.ModerationLog do def get_log_entry_message(%ModerationLog{ data: %{ "actor" => %{"nickname" => actor_nickname}, - "action" => "report_response", + "action" => "report_note", + "subject" => %{"id" => subject_id, "type" => "report"}, + "text" => text + } + }) do + "@#{actor_nickname} added note '#{text}' to report ##{subject_id}" + end + + @spec get_log_entry_message(ModerationLog) :: String.t() + def get_log_entry_message(%ModerationLog{ + data: %{ + "actor" => %{"nickname" => actor_nickname}, + "action" => "report_note_delete", "subject" => %{"id" => subject_id, "type" => "report"}, "text" => text } }) do - "@#{actor_nickname} responded with '#{text}' to report ##{subject_id}" + "@#{actor_nickname} deleted note '#{text}' from report ##{subject_id}" end @spec get_log_entry_message(ModerationLog) :: String.t() diff --git a/lib/pleroma/report_note.ex b/lib/pleroma/report_note.ex index 91102696b..0db86d1a1 100644 --- a/lib/pleroma/report_note.ex +++ b/lib/pleroma/report_note.ex @@ -38,9 +38,11 @@ defmodule Pleroma.ReportNote do |> Repo.insert() end - def get_all_for_status(status_id) do - ReportNote - |> where(activity_id: ^status_id) - |> Repo.all() + @spec destroy(FlakeId.Ecto.CompatType.t()) :: + {:ok, ReportNote.t()} | {:error, Changeset.t()} + def destroy(id) do + from(r in ReportNote, where: r.id == ^id) + |> Repo.one() + |> Repo.delete() end end diff --git a/lib/pleroma/web/admin_api/admin_api_controller.ex b/lib/pleroma/web/admin_api/admin_api_controller.ex index ee32bac45..d34952cda 100644 --- a/lib/pleroma/web/admin_api/admin_api_controller.ex +++ b/lib/pleroma/web/admin_api/admin_api_controller.ex @@ -691,14 +691,14 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do end def report_notes_create(%{assigns: %{user: user}} = conn, %{ - "id" => status_id, + "id" => report_id, "content" => content }) do - with {:ok, _} <- ReportNote.create(user.id, status_id, content) do + with {:ok, _} <- ReportNote.create(user.id, report_id, content) do ModerationLog.insert_log(%{ - action: "report_response", + action: "report_note", actor: user, - subject: Activity.get_by_id(status_id), + subject: Activity.get_by_id(report_id), text: content }) @@ -708,6 +708,24 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do end end + def report_notes_delete(%{assigns: %{user: user}} = conn, %{ + "id" => note_id, + "report_id" => report_id + }) do + with {:ok, note} <- ReportNote.destroy(note_id) do + ModerationLog.insert_log(%{ + action: "report_note_delete", + actor: user, + subject: Activity.get_by_id(report_id), + text: note.content + }) + + json_response(conn, :no_content, "") + else + _ -> json_response(conn, :bad_request, "") + end + end + def status_update(%{assigns: %{user: admin}} = conn, %{"id" => id} = params) do with {:ok, activity} <- CommonAPI.update_activity_scope(id, params) do {:ok, sensitive} = Ecto.Type.cast(:boolean, params["sensitive"]) diff --git a/lib/pleroma/web/admin_api/views/report_view.ex b/lib/pleroma/web/admin_api/views/report_view.ex index f5c6ba401..294861044 100644 --- a/lib/pleroma/web/admin_api/views/report_view.ex +++ b/lib/pleroma/web/admin_api/views/report_view.ex @@ -69,13 +69,19 @@ defmodule Pleroma.Web.AdminAPI.ReportView do def render("index_notes.json", _), do: [] - def render("show_note.json", %{content: content, user_id: user_id, inserted_at: inserted_at}) do + def render("show_note.json", %{ + id: id, + content: content, + user_id: user_id, + inserted_at: inserted_at + }) do user = User.get_by_id(user_id) %{ + id: id, content: content, user: merge_account_views(user), - created_at: inserted_at + created_at: Utils.to_masto_date(inserted_at) } end diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex index af220a98b..3baaa73d9 100644 --- a/lib/pleroma/web/router.ex +++ b/lib/pleroma/web/router.ex @@ -188,6 +188,7 @@ defmodule Pleroma.Web.Router do get("/reports/:id", AdminAPIController, :report_show) patch("/reports", AdminAPIController, :reports_update) post("/reports/:id/notes", AdminAPIController, :report_notes_create) + delete("/reports/:report_id/notes/:id", AdminAPIController, :report_notes_delete) put("/statuses/:id", AdminAPIController, :status_update) delete("/statuses/:id", AdminAPIController, :status_delete) -- cgit v1.2.3 From a21340caa192b41051abe3b5905fbcb2fde281d7 Mon Sep 17 00:00:00 2001 From: rinpatch Date: Sun, 8 Dec 2019 16:36:22 +0300 Subject: Fix never matching clause `length/1` is only used with lists. --- lib/pleroma/clippy.ex | 1 + lib/pleroma/html.ex | 1 + lib/pleroma/web/activity_pub/transmogrifier.ex | 2 +- 3 files changed, 3 insertions(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/pleroma/clippy.ex b/lib/pleroma/clippy.ex index bd20952a6..6e6121d4e 100644 --- a/lib/pleroma/clippy.ex +++ b/lib/pleroma/clippy.ex @@ -4,6 +4,7 @@ defmodule Pleroma.Clippy do @moduledoc false + # No software is complete until they have a Clippy implementation. # A ballmer peak _may_ be required to change this module. diff --git a/lib/pleroma/html.ex b/lib/pleroma/html.ex index 997e965f0..71c53ce0e 100644 --- a/lib/pleroma/html.ex +++ b/lib/pleroma/html.ex @@ -163,6 +163,7 @@ defmodule Pleroma.HTML.Scrubber.Default do require FastSanitize.Sanitizer.Meta alias FastSanitize.Sanitizer.Meta + # credo:disable-for-previous-line # No idea how to fix this one… diff --git a/lib/pleroma/web/activity_pub/transmogrifier.ex b/lib/pleroma/web/activity_pub/transmogrifier.ex index ce95fb6ba..ecba27bef 100644 --- a/lib/pleroma/web/activity_pub/transmogrifier.ex +++ b/lib/pleroma/web/activity_pub/transmogrifier.ex @@ -387,7 +387,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do def handle_incoming(%{"id" => nil}, _options), do: :error def handle_incoming(%{"id" => ""}, _options), do: :error # length of https:// = 8, should validate better, but good enough for now. - def handle_incoming(%{"id" => id}, _options) when not (is_binary(id) and length(id) > 8), + def handle_incoming(%{"id" => id}, _options) when is_binary(id) and byte_size(id) < 8, do: :error # TODO: validate those with a Ecto scheme -- cgit v1.2.3 From bd3aa8500c64b769a36a75fefa445668dc8da4a6 Mon Sep 17 00:00:00 2001 From: rinpatch Date: Sun, 8 Dec 2019 17:36:44 +0300 Subject: OAuth token cleanup: Get rid of compile-time configuration --- lib/pleroma/web/oauth/token/clean_worker.ex | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/oauth/token/clean_worker.ex b/lib/pleroma/web/oauth/token/clean_worker.ex index f639f9c6f..3c9c580d5 100644 --- a/lib/pleroma/web/oauth/token/clean_worker.ex +++ b/lib/pleroma/web/oauth/token/clean_worker.ex @@ -11,11 +11,6 @@ defmodule Pleroma.Web.OAuth.Token.CleanWorker do @ten_seconds 10_000 @one_day 86_400_000 - @interval Pleroma.Config.get( - [:oauth2, :clean_expired_tokens_interval], - @one_day - ) - alias Pleroma.Web.OAuth.Token alias Pleroma.Workers.BackgroundWorker @@ -29,8 +24,9 @@ defmodule Pleroma.Web.OAuth.Token.CleanWorker do @doc false def handle_info(:perform, state) do BackgroundWorker.enqueue("clean_expired_tokens", %{}) + interval = Pleroma.Config.get([:oauth2, :clean_expired_tokens_interval], @one_day) - Process.send_after(self(), :perform, @interval) + Process.send_after(self(), :perform, interval) {:noreply, state} end -- cgit v1.2.3 From d6c89068f3c6765b7a3ef63199725b7833c34c3a Mon Sep 17 00:00:00 2001 From: rinpatch Date: Sun, 8 Dec 2019 19:42:40 +0300 Subject: HTML: Compile Scrubbers on boot This makes it possible to configure their behavior on OTP releases. --- lib/pleroma/application.ex | 1 + lib/pleroma/html.ex | 232 ++++----------------------------------------- 2 files changed, 20 insertions(+), 213 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/application.ex b/lib/pleroma/application.ex index 57462740c..5b844aa41 100644 --- a/lib/pleroma/application.ex +++ b/lib/pleroma/application.ex @@ -30,6 +30,7 @@ defmodule Pleroma.Application do # See http://elixir-lang.org/docs/stable/elixir/Application.html # for more information on OTP Applications def start(_type, _args) do + Pleroma.HTML.compile_scrubbers() Pleroma.Config.DeprecationWarnings.warn() setup_instrumenters() diff --git a/lib/pleroma/html.ex b/lib/pleroma/html.ex index 71c53ce0e..2cae29f35 100644 --- a/lib/pleroma/html.ex +++ b/lib/pleroma/html.ex @@ -3,6 +3,25 @@ # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.HTML do + # Scrubbers are compiled on boot so they can be configured in OTP releases + # @on_load :compile_scrubbers + + def compile_scrubbers do + dir = Path.join(:code.priv_dir(:pleroma), "scrubbers") + + dir + |> File.ls!() + |> Enum.map(&Path.join(dir, &1)) + |> Kernel.ParallelCompiler.compile() + |> case do + {:error, _errors, _warnings} -> + raise "Compiling scrubbers failed" + + {:ok, _modules, _warnings} -> + :ok + end + end + defp get_scrubbers(scrubber) when is_atom(scrubber), do: [scrubber] defp get_scrubbers(scrubbers) when is_list(scrubbers), do: scrubbers defp get_scrubbers(_), do: [Pleroma.HTML.Scrubber.Default] @@ -99,216 +118,3 @@ defmodule Pleroma.HTML do end) end end - -defmodule Pleroma.HTML.Scrubber.TwitterText do - @moduledoc """ - An HTML scrubbing policy which limits to twitter-style text. Only - paragraphs, breaks and links are allowed through the filter. - """ - - @valid_schemes Pleroma.Config.get([:uri_schemes, :valid_schemes], []) - - require FastSanitize.Sanitizer.Meta - alias FastSanitize.Sanitizer.Meta - - Meta.strip_comments() - - # links - Meta.allow_tag_with_uri_attributes(:a, ["href", "data-user", "data-tag"], @valid_schemes) - - Meta.allow_tag_with_this_attribute_values(:a, "class", [ - "hashtag", - "u-url", - "mention", - "u-url mention", - "mention u-url" - ]) - - Meta.allow_tag_with_this_attribute_values(:a, "rel", [ - "tag", - "nofollow", - "noopener", - "noreferrer" - ]) - - Meta.allow_tag_with_these_attributes(:a, ["name", "title"]) - - # paragraphs and linebreaks - Meta.allow_tag_with_these_attributes(:br, []) - Meta.allow_tag_with_these_attributes(:p, []) - - # microformats - Meta.allow_tag_with_this_attribute_values(:span, "class", ["h-card"]) - Meta.allow_tag_with_these_attributes(:span, []) - - # allow inline images for custom emoji - if Pleroma.Config.get([:markup, :allow_inline_images]) do - # restrict img tags to http/https only, because of MediaProxy. - Meta.allow_tag_with_uri_attributes(:img, ["src"], ["http", "https"]) - - Meta.allow_tag_with_these_attributes(:img, [ - "width", - "height", - "class", - "title", - "alt" - ]) - end - - Meta.strip_everything_not_covered() -end - -defmodule Pleroma.HTML.Scrubber.Default do - @doc "The default HTML scrubbing policy: no " - - require FastSanitize.Sanitizer.Meta - alias FastSanitize.Sanitizer.Meta - - # credo:disable-for-previous-line - # No idea how to fix this one… - - @valid_schemes Pleroma.Config.get([:uri_schemes, :valid_schemes], []) - - Meta.strip_comments() - - Meta.allow_tag_with_uri_attributes(:a, ["href", "data-user", "data-tag"], @valid_schemes) - - Meta.allow_tag_with_this_attribute_values(:a, "class", [ - "hashtag", - "u-url", - "mention", - "u-url mention", - "mention u-url" - ]) - - Meta.allow_tag_with_this_attribute_values(:a, "rel", [ - "tag", - "nofollow", - "noopener", - "noreferrer", - "ugc" - ]) - - Meta.allow_tag_with_these_attributes(:a, ["name", "title"]) - - Meta.allow_tag_with_these_attributes(:abbr, ["title"]) - - Meta.allow_tag_with_these_attributes(:b, []) - Meta.allow_tag_with_these_attributes(:blockquote, []) - Meta.allow_tag_with_these_attributes(:br, []) - Meta.allow_tag_with_these_attributes(:code, []) - Meta.allow_tag_with_these_attributes(:del, []) - Meta.allow_tag_with_these_attributes(:em, []) - Meta.allow_tag_with_these_attributes(:i, []) - Meta.allow_tag_with_these_attributes(:li, []) - Meta.allow_tag_with_these_attributes(:ol, []) - Meta.allow_tag_with_these_attributes(:p, []) - Meta.allow_tag_with_these_attributes(:pre, []) - Meta.allow_tag_with_these_attributes(:strong, []) - Meta.allow_tag_with_these_attributes(:sub, []) - Meta.allow_tag_with_these_attributes(:sup, []) - Meta.allow_tag_with_these_attributes(:u, []) - Meta.allow_tag_with_these_attributes(:ul, []) - - Meta.allow_tag_with_this_attribute_values(:span, "class", ["h-card"]) - Meta.allow_tag_with_these_attributes(:span, []) - - @allow_inline_images Pleroma.Config.get([:markup, :allow_inline_images]) - - if @allow_inline_images do - # restrict img tags to http/https only, because of MediaProxy. - Meta.allow_tag_with_uri_attributes(:img, ["src"], ["http", "https"]) - - Meta.allow_tag_with_these_attributes(:img, [ - "width", - "height", - "class", - "title", - "alt" - ]) - end - - if Pleroma.Config.get([:markup, :allow_tables]) do - Meta.allow_tag_with_these_attributes(:table, []) - Meta.allow_tag_with_these_attributes(:tbody, []) - Meta.allow_tag_with_these_attributes(:td, []) - Meta.allow_tag_with_these_attributes(:th, []) - Meta.allow_tag_with_these_attributes(:thead, []) - Meta.allow_tag_with_these_attributes(:tr, []) - end - - if Pleroma.Config.get([:markup, :allow_headings]) do - Meta.allow_tag_with_these_attributes(:h1, []) - Meta.allow_tag_with_these_attributes(:h2, []) - Meta.allow_tag_with_these_attributes(:h3, []) - Meta.allow_tag_with_these_attributes(:h4, []) - Meta.allow_tag_with_these_attributes(:h5, []) - end - - if Pleroma.Config.get([:markup, :allow_fonts]) do - Meta.allow_tag_with_these_attributes(:font, ["face"]) - end - - Meta.strip_everything_not_covered() -end - -defmodule Pleroma.HTML.Transform.MediaProxy do - @moduledoc "Transforms inline image URIs to use MediaProxy." - - alias Pleroma.Web.MediaProxy - - def before_scrub(html), do: html - - def scrub_attribute(:img, {"src", "http" <> target}) do - media_url = - ("http" <> target) - |> MediaProxy.url() - - {"src", media_url} - end - - def scrub_attribute(_tag, attribute), do: attribute - - def scrub({:img, attributes, children}) do - attributes = - attributes - |> Enum.map(fn attr -> scrub_attribute(:img, attr) end) - |> Enum.reject(&is_nil(&1)) - - {:img, attributes, children} - end - - def scrub({:comment, _text, _children}), do: "" - - def scrub({tag, attributes, children}), do: {tag, attributes, children} - def scrub({_tag, children}), do: children - def scrub(text), do: text -end - -defmodule Pleroma.HTML.Scrubber.LinksOnly do - @moduledoc """ - An HTML scrubbing policy which limits to links only. - """ - - @valid_schemes Pleroma.Config.get([:uri_schemes, :valid_schemes], []) - - require FastSanitize.Sanitizer.Meta - alias FastSanitize.Sanitizer.Meta - - Meta.strip_comments() - - # links - Meta.allow_tag_with_uri_attributes(:a, ["href"], @valid_schemes) - - Meta.allow_tag_with_this_attribute_values(:a, "rel", [ - "tag", - "nofollow", - "noopener", - "noreferrer", - "me", - "ugc" - ]) - - Meta.allow_tag_with_these_attributes(:a, ["name", "title"]) - Meta.strip_everything_not_covered() -end -- cgit v1.2.3 From 3c45ed4f4752bb2dce3ca2e9a153cb278df685fb Mon Sep 17 00:00:00 2001 From: rinpatch Date: Sun, 8 Dec 2019 21:08:25 +0300 Subject: OTP: Fix runtime upload limit config being ignored Closes #1109 --- lib/pleroma/plugs/parsers_plug.ex | 21 +++++++++++++++++++++ lib/pleroma/web/endpoint.ex | 9 +-------- 2 files changed, 22 insertions(+), 8 deletions(-) create mode 100644 lib/pleroma/plugs/parsers_plug.ex (limited to 'lib') diff --git a/lib/pleroma/plugs/parsers_plug.ex b/lib/pleroma/plugs/parsers_plug.ex new file mode 100644 index 000000000..2e493ce0e --- /dev/null +++ b/lib/pleroma/plugs/parsers_plug.ex @@ -0,0 +1,21 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2019 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Plugs.Parsers do + @moduledoc "Initializes Plug.Parsers with upload limit set at boot time" + + @behaviour Plug + + def init(_opts) do + Plug.Parsers.init( + parsers: [:urlencoded, :multipart, :json], + pass: ["*/*"], + json_decoder: Jason, + length: Pleroma.Config.get([:instance, :upload_limit]), + body_reader: {Pleroma.Web.Plugs.DigestPlug, :read_body, []} + ) + end + + defdelegate call(conn, opts), to: Plug.Parsers +end diff --git a/lib/pleroma/web/endpoint.ex b/lib/pleroma/web/endpoint.ex index 49735b5c2..bbea31682 100644 --- a/lib/pleroma/web/endpoint.ex +++ b/lib/pleroma/web/endpoint.ex @@ -61,14 +61,7 @@ defmodule Pleroma.Web.Endpoint do plug(Plug.RequestId) plug(Plug.Logger) - plug( - Plug.Parsers, - parsers: [:urlencoded, :multipart, :json], - pass: ["*/*"], - json_decoder: Jason, - length: Pleroma.Config.get([:instance, :upload_limit]), - body_reader: {Pleroma.Web.Plugs.DigestPlug, :read_body, []} - ) + plug(Pleroma.Plugs.Parsers) plug(Plug.MethodOverride) plug(Plug.Head) -- cgit v1.2.3 From f4b7f32d51f9d0bd721befdd33b49d2c52a6e231 Mon Sep 17 00:00:00 2001 From: rinpatch Date: Mon, 9 Dec 2019 20:45:04 +0300 Subject: status search: prefer the status fetched by url over other results --- lib/pleroma/activity/search.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/pleroma/activity/search.ex b/lib/pleroma/activity/search.ex index f847ac238..d30a5a6a5 100644 --- a/lib/pleroma/activity/search.ex +++ b/lib/pleroma/activity/search.ex @@ -86,7 +86,7 @@ defmodule Pleroma.Activity.Search do {:ok, object} <- Fetcher.fetch_object_from_id(search_query), %Activity{} = activity <- Activity.get_create_by_object_ap_id(object.data["id"]), true <- Visibility.visible_for_user?(activity, user) do - activities ++ [activity] + [activity | activities] else _ -> activities end -- cgit v1.2.3 From 9dfaa0b832ddb09f0937c96e5e30b83957f8185f Mon Sep 17 00:00:00 2001 From: Maksim Pechnikov Date: Mon, 9 Dec 2019 22:29:44 +0300 Subject: fix loads config variable with large value from db --- lib/mix/tasks/pleroma/config.ex | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/mix/tasks/pleroma/config.ex b/lib/mix/tasks/pleroma/config.ex index 0e21408b2..590c7a914 100644 --- a/lib/mix/tasks/pleroma/config.ex +++ b/lib/mix/tasks/pleroma/config.ex @@ -52,7 +52,9 @@ defmodule Mix.Tasks.Pleroma.Config do |> Enum.each(fn config -> IO.write( file, - "config :#{config.group}, #{config.key}, #{inspect(Config.from_binary(config.value))}\r\n\r\n" + "config :#{config.group}, #{config.key}, #{ + inspect(Config.from_binary(config.value), limit: :infinity) + }\r\n\r\n" ) if delete? do -- cgit v1.2.3 From 701815e64c35160d29e418724c29cbe2d8b4024d Mon Sep 17 00:00:00 2001 From: Hakaba Hitoyo Date: Tue, 10 Dec 2019 13:19:26 +0000 Subject: [ActivityPub] Configurable ActivityPub actor type --- lib/pleroma/user.ex | 4 ++++ lib/pleroma/web/activity_pub/activity_pub.ex | 2 ++ lib/pleroma/web/activity_pub/views/user_view.ex | 2 +- lib/pleroma/web/mastodon_api/controllers/account_controller.ex | 1 + lib/pleroma/web/mastodon_api/views/account_view.ex | 5 +++-- 5 files changed, 11 insertions(+), 3 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex index e2afc6de8..694f1f110 100644 --- a/lib/pleroma/user.ex +++ b/lib/pleroma/user.ex @@ -127,6 +127,7 @@ defmodule Pleroma.User do field(:invisible, :boolean, default: false) field(:allow_following_move, :boolean, default: true) field(:skip_thread_containment, :boolean, default: false) + field(:actor_type, :string, default: "Person") field(:also_known_as, {:array, :string}, default: []) embeds_one( @@ -346,6 +347,7 @@ defmodule Pleroma.User do :following_count, :discoverable, :invisible, + :actor_type, :also_known_as ] ) @@ -396,6 +398,7 @@ defmodule Pleroma.User do :raw_fields, :pleroma_settings_store, :discoverable, + :actor_type, :also_known_as ] ) @@ -438,6 +441,7 @@ defmodule Pleroma.User do :discoverable, :hide_followers_count, :hide_follows_count, + :actor_type, :also_known_as ] ) diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex index 1e2cc2e2b..6571102a9 100644 --- a/lib/pleroma/web/activity_pub/activity_pub.ex +++ b/lib/pleroma/web/activity_pub/activity_pub.ex @@ -1217,6 +1217,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do data = Transmogrifier.maybe_fix_user_object(data) discoverable = data["discoverable"] || false invisible = data["invisible"] || false + actor_type = data["type"] || "Person" user_data = %{ ap_id: data["id"], @@ -1232,6 +1233,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do follower_address: data["followers"], following_address: data["following"], bio: data["summary"], + actor_type: actor_type, also_known_as: Map.get(data, "alsoKnownAs", []) } diff --git a/lib/pleroma/web/activity_pub/views/user_view.ex b/lib/pleroma/web/activity_pub/views/user_view.ex index cf08045c9..9059aa634 100644 --- a/lib/pleroma/web/activity_pub/views/user_view.ex +++ b/lib/pleroma/web/activity_pub/views/user_view.ex @@ -91,7 +91,7 @@ defmodule Pleroma.Web.ActivityPub.UserView do %{ "id" => user.ap_id, - "type" => "Person", + "type" => user.actor_type, "following" => "#{user.ap_id}/following", "followers" => "#{user.ap_id}/followers", "inbox" => "#{user.ap_id}/inbox", diff --git a/lib/pleroma/web/mastodon_api/controllers/account_controller.ex b/lib/pleroma/web/mastodon_api/controllers/account_controller.ex index d19029cb5..38d14256f 100644 --- a/lib/pleroma/web/mastodon_api/controllers/account_controller.ex +++ b/lib/pleroma/web/mastodon_api/controllers/account_controller.ex @@ -188,6 +188,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountController do {:ok, Map.merge(user.pleroma_settings_store, value)} end) |> add_if_present(params, "default_scope", :default_scope) + |> add_if_present(params, "actor_type", :actor_type) emojis_text = (user_params["display_name"] || "") <> (user_params["note"] || "") diff --git a/lib/pleroma/web/mastodon_api/views/account_view.ex b/lib/pleroma/web/mastodon_api/views/account_view.ex index 546cc0ed5..a5420f480 100644 --- a/lib/pleroma/web/mastodon_api/views/account_view.ex +++ b/lib/pleroma/web/mastodon_api/views/account_view.ex @@ -86,7 +86,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountView do 0 end - bot = (user.source_data["type"] || "Person") in ["Application", "Service"] + bot = user.actor_type in ["Application", "Service"] emojis = (user.source_data["tag"] || []) @@ -137,7 +137,8 @@ defmodule Pleroma.Web.MastodonAPI.AccountView do sensitive: false, fields: user.raw_fields, pleroma: %{ - discoverable: user.discoverable + discoverable: user.discoverable, + actor_type: user.actor_type } }, -- cgit v1.2.3 From 75b419d7c86d0b362ad49e011a97a8def3b786fd Mon Sep 17 00:00:00 2001 From: Egor Kislitsyn Date: Tue, 10 Dec 2019 21:46:02 +0700 Subject: Do not apply http signature pipeline to the unsubscribe route --- lib/pleroma/web/router.ex | 3 +++ 1 file changed, 3 insertions(+) (limited to 'lib') diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex index e6c4f6f14..78cb703a9 100644 --- a/lib/pleroma/web/router.ex +++ b/lib/pleroma/web/router.ex @@ -528,7 +528,10 @@ defmodule Pleroma.Web.Router do get("/users/:nickname/feed", Feed.FeedController, :feed) get("/users/:nickname", Feed.FeedController, :feed_redirect) + end + scope "/", Pleroma.Web do + pipe_through(:browser) get("/mailer/unsubscribe/:token", Mailer.SubscriptionController, :unsubscribe) end -- cgit v1.2.3 From 19d228cc586a1304ef6e982a447a77f8c3a48772 Mon Sep 17 00:00:00 2001 From: Sadposter Date: Tue, 10 Dec 2019 16:40:12 +0000 Subject: modify SQL to include followed-but-domain-blocked activities --- lib/pleroma/user.ex | 7 +++++++ lib/pleroma/web/activity_pub/activity_pub.ex | 7 +++++-- 2 files changed, 12 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex index 63c5b4102..601aa9cf0 100644 --- a/lib/pleroma/user.ex +++ b/lib/pleroma/user.ex @@ -762,6 +762,13 @@ defmodule Pleroma.User do |> Repo.all() end + def get_friends_ap_ids(user) do + user + |> get_friends_query(nil) + |> select([u], u.ap_id) + |> Repo.all() + end + def get_friends_ids(user, page \\ nil) do user |> get_friends_query(page) diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex index f25314ff6..3c4aed241 100644 --- a/lib/pleroma/web/activity_pub/activity_pub.ex +++ b/lib/pleroma/web/activity_pub/activity_pub.ex @@ -915,6 +915,9 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do defp restrict_blocked(query, %{"blocking_user" => %User{} = user}) do blocks = user.blocks || [] domain_blocks = user.domain_blocks || [] + following_ap_ids = + user + |> User.get_friends_ap_ids() query = if has_named_binding?(query, :object), do: query, else: Activity.with_joined_object(query) @@ -930,8 +933,8 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do activity.data, ^blocks ), - where: fragment("not (split_part(?, '/', 3) = ANY(?))", activity.actor, ^domain_blocks), - where: fragment("not (split_part(?->>'actor', '/', 3) = ANY(?))", o.data, ^domain_blocks) + where: fragment("(not (split_part(?, '/', 3) = ANY(?))) or ? = ANY(?)", activity.actor, ^domain_blocks, activity.actor, ^following_ap_ids), + where: fragment("(not (split_part(?->>'actor', '/', 3) = ANY(?))) or (?->>'actor') = ANY(?)", o.data, ^domain_blocks, o.data, ^following_ap_ids) ) end -- cgit v1.2.3 From 25f774f7c19a955398976b3f4462cbd51ec700d6 Mon Sep 17 00:00:00 2001 From: Sadposter Date: Tue, 10 Dec 2019 16:41:43 +0000 Subject: format activity_pub.ex --- lib/pleroma/web/activity_pub/activity_pub.ex | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex index 3c4aed241..29cc1a17b 100644 --- a/lib/pleroma/web/activity_pub/activity_pub.ex +++ b/lib/pleroma/web/activity_pub/activity_pub.ex @@ -915,9 +915,10 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do defp restrict_blocked(query, %{"blocking_user" => %User{} = user}) do blocks = user.blocks || [] domain_blocks = user.domain_blocks || [] + following_ap_ids = - user - |> User.get_friends_ap_ids() + user + |> User.get_friends_ap_ids() query = if has_named_binding?(query, :object), do: query, else: Activity.with_joined_object(query) @@ -933,8 +934,22 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do activity.data, ^blocks ), - where: fragment("(not (split_part(?, '/', 3) = ANY(?))) or ? = ANY(?)", activity.actor, ^domain_blocks, activity.actor, ^following_ap_ids), - where: fragment("(not (split_part(?->>'actor', '/', 3) = ANY(?))) or (?->>'actor') = ANY(?)", o.data, ^domain_blocks, o.data, ^following_ap_ids) + where: + fragment( + "(not (split_part(?, '/', 3) = ANY(?))) or ? = ANY(?)", + activity.actor, + ^domain_blocks, + activity.actor, + ^following_ap_ids + ), + where: + fragment( + "(not (split_part(?->>'actor', '/', 3) = ANY(?))) or (?->>'actor') = ANY(?)", + o.data, + ^domain_blocks, + o.data, + ^following_ap_ids + ) ) end -- cgit v1.2.3 From 457821adb07d899fc5094de46027b482e07daf9f Mon Sep 17 00:00:00 2001 From: Sadposter Date: Tue, 10 Dec 2019 18:49:41 +0000 Subject: Apply suggestion to lib/pleroma/user.ex --- lib/pleroma/user.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex index cebadc8ab..706aee2ff 100644 --- a/lib/pleroma/user.ex +++ b/lib/pleroma/user.ex @@ -1143,7 +1143,7 @@ defmodule Pleroma.User do def blocks?(nil, _), do: false def blocks?(%User{} = user, %User{} = target) do - blocks_ap_id?(user, target) || + blocks_user?(user, target) || (!User.following?(user, target) && blocks_domain?(user, target)) end -- cgit v1.2.3 From 3920244be5be000e33c470beb897a031ecef3ac8 Mon Sep 17 00:00:00 2001 From: Ivan Tashkinov Date: Wed, 11 Dec 2019 11:42:02 +0300 Subject: [#1427] Fixed `:admin` option handling in OAuthScopesPlug, added tests. --- lib/pleroma/config.ex | 11 ++++++++--- lib/pleroma/plugs/oauth_scopes_plug.ex | 17 ++++++++++------- 2 files changed, 18 insertions(+), 10 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/config.ex b/lib/pleroma/config.ex index cadab2f15..bad6d505c 100644 --- a/lib/pleroma/config.ex +++ b/lib/pleroma/config.ex @@ -68,8 +68,13 @@ defmodule Pleroma.Config do def enforce_oauth_admin_scope_usage?, do: !!get([:auth, :enforce_oauth_admin_scope_usage]) - def oauth_admin_scopes(scope) do - ["admin:#{scope}"] ++ - if enforce_oauth_admin_scope_usage?(), do: [], else: [scope] + def oauth_admin_scopes(scopes) when is_list(scopes) do + Enum.flat_map( + scopes, + fn scope -> + ["admin:#{scope}"] ++ + if enforce_oauth_admin_scope_usage?(), do: [], else: [scope] + end + ) end end diff --git a/lib/pleroma/plugs/oauth_scopes_plug.ex b/lib/pleroma/plugs/oauth_scopes_plug.ex index 3201fb399..174a8389c 100644 --- a/lib/pleroma/plugs/oauth_scopes_plug.ex +++ b/lib/pleroma/plugs/oauth_scopes_plug.ex @@ -17,13 +17,7 @@ defmodule Pleroma.Plugs.OAuthScopesPlug do op = options[:op] || :| token = assigns[:token] - scopes = - if options[:admin] do - Config.oauth_admin_scopes(scopes) - else - scopes - end - + scopes = transform_scopes(scopes, options) matched_scopes = token && filter_descendants(scopes, token.scopes) cond do @@ -69,6 +63,15 @@ defmodule Pleroma.Plugs.OAuthScopesPlug do ) end + @doc "Transforms scopes by applying supported options (e.g. :admin)" + def transform_scopes(scopes, options) do + if options[:admin] do + Config.oauth_admin_scopes(scopes) + else + scopes + end + end + defp maybe_perform_instance_privacy_check(%Plug.Conn{} = conn, options) do if options[:skip_instance_privacy_check] do conn -- cgit v1.2.3 From 1ad96d667ae2f8a14a0b7c701a99c7fa72985a00 Mon Sep 17 00:00:00 2001 From: Sadposter Date: Wed, 11 Dec 2019 09:08:20 +0000 Subject: remove single-step pipe --- lib/pleroma/web/activity_pub/activity_pub.ex | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex index c6744e5f2..2bb3ad635 100644 --- a/lib/pleroma/web/activity_pub/activity_pub.ex +++ b/lib/pleroma/web/activity_pub/activity_pub.ex @@ -950,9 +950,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do blocked_ap_ids = opts["blocked_users_ap_ids"] || User.blocked_users_ap_ids(user) domain_blocks = user.domain_blocks || [] - following_ap_ids = - user - |> User.get_friends_ap_ids() + following_ap_ids = User.get_friends_ap_ids(user) query = if has_named_binding?(query, :object), do: query, else: Activity.with_joined_object(query) -- cgit v1.2.3 From 82fae3e23f41d02803eeb9c1eb6151955d387102 Mon Sep 17 00:00:00 2001 From: Maxim Filippov Date: Wed, 11 Dec 2019 18:57:36 +0300 Subject: AdminAPI: Merge account views for list instance statuses --- lib/pleroma/web/admin_api/admin_api_controller.ex | 2 +- lib/pleroma/web/admin_api/views/status_view.ex | 42 +++++++++++++++++++++++ 2 files changed, 43 insertions(+), 1 deletion(-) create mode 100644 lib/pleroma/web/admin_api/views/status_view.ex (limited to 'lib') diff --git a/lib/pleroma/web/admin_api/admin_api_controller.ex b/lib/pleroma/web/admin_api/admin_api_controller.ex index 0a8a56cd8..bc90eac72 100644 --- a/lib/pleroma/web/admin_api/admin_api_controller.ex +++ b/lib/pleroma/web/admin_api/admin_api_controller.ex @@ -240,7 +240,7 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do }) conn - |> put_view(StatusView) + |> put_view(Pleroma.Web.AdminAPI.StatusView) |> render("index.json", %{activities: activities, as: :activity}) end diff --git a/lib/pleroma/web/admin_api/views/status_view.ex b/lib/pleroma/web/admin_api/views/status_view.ex new file mode 100644 index 000000000..6f2b2b09c --- /dev/null +++ b/lib/pleroma/web/admin_api/views/status_view.ex @@ -0,0 +1,42 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2019 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.AdminAPI.StatusView do + use Pleroma.Web, :view + + require Pleroma.Constants + + alias Pleroma.User + + def render("index.json", opts) do + render_many(opts.activities, __MODULE__, "show.json", opts) + end + + def render("show.json", %{activity: %{data: %{"object" => _object}} = activity} = opts) do + user = get_user(activity.data["actor"]) + + Pleroma.Web.MastodonAPI.StatusView.render("show.json", opts) + |> Map.merge(%{account: merge_account_views(user)}) + end + + defp merge_account_views(%User{} = user) do + Pleroma.Web.MastodonAPI.AccountView.render("show.json", %{user: user}) + |> Map.merge(Pleroma.Web.AdminAPI.AccountView.render("show.json", %{user: user})) + end + + defp merge_account_views(_), do: %{} + + defp get_user(ap_id) do + cond do + user = User.get_cached_by_ap_id(ap_id) -> + user + + user = User.get_by_guessed_nickname(ap_id) -> + user + + true -> + User.error_user(ap_id) + end + end +end -- cgit v1.2.3 From e53679698424a7d58c308c21d466b07e34e8c3e9 Mon Sep 17 00:00:00 2001 From: Egor Kislitsyn Date: Wed, 11 Dec 2019 22:29:31 +0700 Subject: Add native captcha and enable it by default. --- lib/pleroma/captcha/native.ex | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 lib/pleroma/captcha/native.ex (limited to 'lib') diff --git a/lib/pleroma/captcha/native.ex b/lib/pleroma/captcha/native.ex new file mode 100644 index 000000000..5306fe1aa --- /dev/null +++ b/lib/pleroma/captcha/native.ex @@ -0,0 +1,35 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2019 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Captcha.Native do + import Pleroma.Web.Gettext + alias Pleroma.Captcha.Service + @behaviour Service + + @impl Service + def new do + case Captcha.get() do + {:timeout} -> + %{error: dgettext("errors", "Captcha timeout")} + + {:ok, answer_data, img_binary} -> + %{ + type: :native, + token: token(), + url: "data:image/png;base64," <> Base.encode64(img_binary), + answer_data: answer_data + } + end + end + + @impl Service + def validate(_token, captcha, captcha) when not is_nil(captcha), do: :ok + def validate(_token, _captcha, _answer), do: {:error, dgettext("errors", "Invalid CAPTCHA")} + + defp token do + 10 + |> :crypto.strong_rand_bytes() + |> Base.url_encode64(padding: false) + end +end -- cgit v1.2.3 From 81b05340e9291e9af11727aee77f2c70a9d73498 Mon Sep 17 00:00:00 2001 From: Ivan Tashkinov Date: Thu, 12 Dec 2019 16:00:06 +0300 Subject: [#1427] Graceful clearance of OAuth admin scopes for non-admin users (no error raised). PleromaFE and other clients may safely request admin scope(s): if user isn't an admin, request is successful but only non-admin scopes from request are granted. --- lib/pleroma/web/oauth/scopes.ex | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/pleroma/web/oauth/scopes.ex b/lib/pleroma/web/oauth/scopes.ex index 5e04652c2..00da225b9 100644 --- a/lib/pleroma/web/oauth/scopes.ex +++ b/lib/pleroma/web/oauth/scopes.ex @@ -79,7 +79,9 @@ defmodule Pleroma.Web.OAuth.Scopes do if user.is_admin || !contains_admin_scopes?(scopes) || !contains_admin_scopes?(app_scopes) do {:ok, scopes} else - {:error, :unsupported_scopes} + # 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 -- cgit v1.2.3 From bcd16676a78065a1b9549189ed3d594b4c62584c Mon Sep 17 00:00:00 2001 From: rinpatch Date: Fri, 13 Dec 2019 14:27:10 +0300 Subject: Publisher: check out a connection for inserting publish_one jobs Related to #1474, federation of one post on my istance creates in best-case 360 jobs, so if they for some reason take a while to insert, it will exhaust the connection pool. This fixes it by checking out one dedicated connection for inserting them. --- lib/pleroma/web/activity_pub/publisher.ex | 55 +++++++++++++++++-------------- 1 file changed, 30 insertions(+), 25 deletions(-) (limited to 'lib') diff --git a/lib/pleroma/web/activity_pub/publisher.ex b/lib/pleroma/web/activity_pub/publisher.ex index 4ea37fc7b..4073d3d63 100644 --- a/lib/pleroma/web/activity_pub/publisher.ex +++ b/lib/pleroma/web/activity_pub/publisher.ex @@ -9,6 +9,7 @@ defmodule Pleroma.Web.ActivityPub.Publisher do alias Pleroma.HTTP alias Pleroma.Instances alias Pleroma.Object + alias Pleroma.Repo alias Pleroma.User alias Pleroma.Web.ActivityPub.Relay alias Pleroma.Web.ActivityPub.Transmogrifier @@ -188,31 +189,35 @@ defmodule Pleroma.Web.ActivityPub.Publisher do recipients = recipients(actor, activity) - recipients - |> Enum.filter(&User.ap_enabled?/1) - |> Enum.map(fn %{source_data: data} -> data["inbox"] end) - |> Enum.filter(fn inbox -> should_federate?(inbox, public) end) - |> Instances.filter_reachable() - |> Enum.each(fn {inbox, unreachable_since} -> - %User{ap_id: ap_id} = - Enum.find(recipients, fn %{source_data: data} -> data["inbox"] == inbox end) - - # Get all the recipients on the same host and add them to cc. Otherwise, a remote - # instance would only accept a first message for the first recipient and ignore the rest. - cc = get_cc_ap_ids(ap_id, recipients) - - json = - data - |> Map.put("cc", cc) - |> Jason.encode!() - - Pleroma.Web.Federator.Publisher.enqueue_one(__MODULE__, %{ - inbox: inbox, - json: json, - actor_id: actor.id, - id: activity.data["id"], - unreachable_since: unreachable_since - }) + inboxes = + recipients + |> Enum.filter(&User.ap_enabled?/1) + |> Enum.map(fn %{source_data: data} -> data["inbox"] end) + |> Enum.filter(fn inbox -> should_federate?(inbox, public) end) + |> Instances.filter_reachable() + + Repo.checkout(fn -> + Enum.each(inboxes, fn {inbox, unreachable_since} -> + %User{ap_id: ap_id} = + Enum.find(recipients, fn %{source_data: data} -> data["inbox"] == inbox end) + + # Get all the recipients on the same host and add them to cc. Otherwise, a remote + # instance would only accept a first message for the first recipient and ignore the rest. + cc = get_cc_ap_ids(ap_id, recipients) + + json = + data + |> Map.put("cc", cc) + |> Jason.encode!() + + Pleroma.Web.Federator.Publisher.enqueue_one(__MODULE__, %{ + inbox: inbox, + json: json, + actor_id: actor.id, + id: activity.data["id"], + unreachable_since: unreachable_since + }) + end) end) end -- cgit v1.2.3