diff options
| author | Sergey Suprunenko <suprunenko.s@gmail.com> | 2019-11-16 22:54:13 +0100 | 
|---|---|---|
| committer | Alexander Strizhakov <alex.strizhakov@gmail.com> | 2020-07-06 09:28:21 +0300 | 
| commit | 4a8c26654eb7ca7ce049dd4c485c16672b5837a6 (patch) | |
| tree | a85c4f8b2e949b7f9e8952c30091b1182b4956a0 | |
| parent | c2a052a346d5104c3657343a885255d4d7179c75 (diff) | |
| download | pleroma-4a8c26654eb7ca7ce049dd4c485c16672b5837a6.tar.gz pleroma-4a8c26654eb7ca7ce049dd4c485c16672b5837a6.zip | |
Restrict statuses that contain user's irreversible filters
| -rw-r--r-- | lib/pleroma/filter.ex | 42 | ||||
| -rw-r--r-- | lib/pleroma/web/activity_pub/activity_pub.ex | 22 | ||||
| -rw-r--r-- | lib/pleroma/web/mastodon_api/controllers/filter_controller.ex | 2 | ||||
| -rw-r--r-- | test/filter_test.exs | 2 | ||||
| -rw-r--r-- | test/support/factory.ex | 8 | ||||
| -rw-r--r-- | test/web/activity_pub/activity_pub_test.exs | 69 | 
6 files changed, 141 insertions, 4 deletions
| diff --git a/lib/pleroma/filter.ex b/lib/pleroma/filter.ex index 4d61b3650..91884c6b3 100644 --- a/lib/pleroma/filter.ex +++ b/lib/pleroma/filter.ex @@ -34,10 +34,18 @@ defmodule Pleroma.Filter do      Repo.one(query)    end -  def get_filters(%User{id: user_id} = _user) do +  def get_active(query) do +    from(f in query, where: is_nil(f.expires_at) or f.expires_at > ^NaiveDateTime.utc_now()) +  end + +  def get_irreversible(query) do +    from(f in query, where: f.hide) +  end + +  def get_by_user(query, %User{id: user_id} = _user) do      query =        from( -        f in Pleroma.Filter, +        f in query,          where: f.user_id == ^user_id,          order_by: [desc: :id]        ) @@ -95,4 +103,34 @@ defmodule Pleroma.Filter do      |> validate_required([:phrase, :context])      |> Repo.update()    end + +  def compose_regex(user_or_filters, format \\ :postgres) + +  def compose_regex(%User{} = user, format) do +    __MODULE__ +    |> get_active() +    |> get_irreversible() +    |> get_by_user(user) +    |> compose_regex(format) +  end + +  def compose_regex([_ | _] = filters, format) do +    phrases = +      filters +      |> Enum.map(& &1.phrase) +      |> Enum.join("|") + +    case format do +      :postgres -> +        "\\y(#{phrases})\\y" + +      :re -> +        ~r/\b#{phrases}\b/i + +      _ -> +        nil +    end +  end + +  def compose_regex(_, _), do: nil  end diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex index 94117202c..31353c866 100644 --- a/lib/pleroma/web/activity_pub/activity_pub.ex +++ b/lib/pleroma/web/activity_pub/activity_pub.ex @@ -10,6 +10,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do    alias Pleroma.Constants    alias Pleroma.Conversation    alias Pleroma.Conversation.Participation +  alias Pleroma.Filter    alias Pleroma.Maps    alias Pleroma.Notification    alias Pleroma.Object @@ -961,6 +962,26 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do    defp restrict_instance(query, _), do: query +  defp restrict_filtered(query, %{user: %User{} = user}) do +    case Filter.compose_regex(user) do +      nil -> +        query + +      regex -> +        from([activity, object] in query, +          where: +            fragment("not(?->>'content' ~* ?)", object.data, ^regex) or +              activity.actor == ^user.ap_id +        ) +    end +  end + +  defp restrict_filtered(query, %{blocking_user: %User{} = user}) do +    restrict_filtered(query, %{user: user}) +  end + +  defp restrict_filtered(query, _), do: query +    defp exclude_poll_votes(query, %{include_poll_votes: true}), do: query    defp exclude_poll_votes(query, _) do @@ -1099,6 +1120,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do      |> restrict_muted_reblogs(restrict_muted_reblogs_opts)      |> restrict_instance(opts)      |> restrict_announce_object_actor(opts) +    |> restrict_filtered(opts)      |> Activity.restrict_deactivated_users()      |> exclude_poll_votes(opts)      |> exclude_chat_messages(opts) diff --git a/lib/pleroma/web/mastodon_api/controllers/filter_controller.ex b/lib/pleroma/web/mastodon_api/controllers/filter_controller.ex index abbf0ce02..db1ff3189 100644 --- a/lib/pleroma/web/mastodon_api/controllers/filter_controller.ex +++ b/lib/pleroma/web/mastodon_api/controllers/filter_controller.ex @@ -22,7 +22,7 @@ defmodule Pleroma.Web.MastodonAPI.FilterController do    @doc "GET /api/v1/filters"    def index(%{assigns: %{user: user}} = conn, _) do -    filters = Filter.get_filters(user) +    filters = Filter.get_by_user(Filter, user)      render(conn, "index.json", filters: filters)    end diff --git a/test/filter_test.exs b/test/filter_test.exs index 63a30c736..061a95ad0 100644 --- a/test/filter_test.exs +++ b/test/filter_test.exs @@ -126,7 +126,7 @@ defmodule Pleroma.FilterTest do      {:ok, filter_one} = Pleroma.Filter.create(query_one)      {:ok, filter_two} = Pleroma.Filter.create(query_two) -    filters = Pleroma.Filter.get_filters(user) +    filters = Pleroma.Filter.get_by_user(Pleroma.Filter, user)      assert filter_one in filters      assert filter_two in filters    end diff --git a/test/support/factory.ex b/test/support/factory.ex index af580021c..635d83650 100644 --- a/test/support/factory.ex +++ b/test/support/factory.ex @@ -428,4 +428,12 @@ defmodule Pleroma.Factory do        user: build(:user)      }    end + +  def filter_factory do +    %Pleroma.Filter{ +      user: build(:user), +      filter_id: sequence(:filter_id, & &1), +      phrase: "cofe" +    } +  end  end diff --git a/test/web/activity_pub/activity_pub_test.exs b/test/web/activity_pub/activity_pub_test.exs index 575e0c5db..4968403dc 100644 --- a/test/web/activity_pub/activity_pub_test.exs +++ b/test/web/activity_pub/activity_pub_test.exs @@ -785,6 +785,75 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubTest do      assert activity == expected_activity    end +  describe "irreversible filters" do +    setup do +      user = insert(:user) +      user_two = insert(:user) + +      insert(:filter, user: user_two, phrase: "cofe", hide: true) +      insert(:filter, user: user_two, phrase: "ok boomer", hide: true) +      insert(:filter, user: user_two, phrase: "test", hide: false) + +      params = %{ +        "type" => ["Create", "Announce"], +        "user" => user_two +      } + +      {:ok, %{user: user, user_two: user_two, params: params}} +    end + +    test "it returns statuses if they don't contain exact filter words", %{ +      user: user, +      params: params +    } do +      {:ok, _} = CommonAPI.post(user, %{"status" => "hey"}) +      {:ok, _} = CommonAPI.post(user, %{"status" => "got cofefe?"}) +      {:ok, _} = CommonAPI.post(user, %{"status" => "I am not a boomer"}) +      {:ok, _} = CommonAPI.post(user, %{"status" => "ok boomers"}) +      {:ok, _} = CommonAPI.post(user, %{"status" => "ccofee is not a word"}) +      {:ok, _} = CommonAPI.post(user, %{"status" => "this is a test"}) + +      activities = ActivityPub.fetch_activities([], params) + +      assert Enum.count(activities) == 6 +    end + +    test "it does not filter user's own statuses", %{user_two: user_two, params: params} do +      {:ok, _} = CommonAPI.post(user_two, %{"status" => "Give me some cofe!"}) +      {:ok, _} = CommonAPI.post(user_two, %{"status" => "ok boomer"}) + +      activities = ActivityPub.fetch_activities([], params) + +      assert Enum.count(activities) == 2 +    end + +    test "it excludes statuses with filter words", %{user: user, params: params} do +      {:ok, _} = CommonAPI.post(user, %{"status" => "Give me some cofe!"}) +      {:ok, _} = CommonAPI.post(user, %{"status" => "ok boomer"}) +      {:ok, _} = CommonAPI.post(user, %{"status" => "is it a cOfE?"}) +      {:ok, _} = CommonAPI.post(user, %{"status" => "cofe is all I need"}) +      {:ok, _} = CommonAPI.post(user, %{"status" => "— ok BOOMER\n"}) + +      activities = ActivityPub.fetch_activities([], params) + +      assert Enum.empty?(activities) +    end + +    test "it returns all statuses if user does not have any filters" do +      another_user = insert(:user) +      {:ok, _} = CommonAPI.post(another_user, %{"status" => "got cofe?"}) +      {:ok, _} = CommonAPI.post(another_user, %{"status" => "test!"}) + +      activities = +        ActivityPub.fetch_activities([], %{ +          "type" => ["Create", "Announce"], +          "user" => another_user +        }) + +      assert Enum.count(activities) == 2 +    end +  end +    describe "public fetch activities" do      test "doesn't retrieve unlisted activities" do        user = insert(:user) | 
