Restrict statuses that contain user's irreversible filters
This commit is contained in:
parent
c2a052a346
commit
4a8c26654e
|
@ -34,10 +34,18 @@ def get(id, %{id: user_id} = _user) do
|
||||||
Repo.one(query)
|
Repo.one(query)
|
||||||
end
|
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 =
|
query =
|
||||||
from(
|
from(
|
||||||
f in Pleroma.Filter,
|
f in query,
|
||||||
where: f.user_id == ^user_id,
|
where: f.user_id == ^user_id,
|
||||||
order_by: [desc: :id]
|
order_by: [desc: :id]
|
||||||
)
|
)
|
||||||
|
@ -95,4 +103,34 @@ def update(%Pleroma.Filter{} = filter, params) do
|
||||||
|> validate_required([:phrase, :context])
|
|> validate_required([:phrase, :context])
|
||||||
|> Repo.update()
|
|> Repo.update()
|
||||||
end
|
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
|
end
|
||||||
|
|
|
@ -10,6 +10,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
|
||||||
alias Pleroma.Constants
|
alias Pleroma.Constants
|
||||||
alias Pleroma.Conversation
|
alias Pleroma.Conversation
|
||||||
alias Pleroma.Conversation.Participation
|
alias Pleroma.Conversation.Participation
|
||||||
|
alias Pleroma.Filter
|
||||||
alias Pleroma.Maps
|
alias Pleroma.Maps
|
||||||
alias Pleroma.Notification
|
alias Pleroma.Notification
|
||||||
alias Pleroma.Object
|
alias Pleroma.Object
|
||||||
|
@ -961,6 +962,26 @@ defp restrict_instance(query, %{instance: instance}) do
|
||||||
|
|
||||||
defp restrict_instance(query, _), do: query
|
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, %{include_poll_votes: true}), do: query
|
||||||
|
|
||||||
defp exclude_poll_votes(query, _) do
|
defp exclude_poll_votes(query, _) do
|
||||||
|
@ -1099,6 +1120,7 @@ def fetch_activities_query(recipients, opts \\ %{}) do
|
||||||
|> restrict_muted_reblogs(restrict_muted_reblogs_opts)
|
|> restrict_muted_reblogs(restrict_muted_reblogs_opts)
|
||||||
|> restrict_instance(opts)
|
|> restrict_instance(opts)
|
||||||
|> restrict_announce_object_actor(opts)
|
|> restrict_announce_object_actor(opts)
|
||||||
|
|> restrict_filtered(opts)
|
||||||
|> Activity.restrict_deactivated_users()
|
|> Activity.restrict_deactivated_users()
|
||||||
|> exclude_poll_votes(opts)
|
|> exclude_poll_votes(opts)
|
||||||
|> exclude_chat_messages(opts)
|
|> exclude_chat_messages(opts)
|
||||||
|
|
|
@ -22,7 +22,7 @@ defmodule Pleroma.Web.MastodonAPI.FilterController do
|
||||||
|
|
||||||
@doc "GET /api/v1/filters"
|
@doc "GET /api/v1/filters"
|
||||||
def index(%{assigns: %{user: user}} = conn, _) do
|
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)
|
render(conn, "index.json", filters: filters)
|
||||||
end
|
end
|
||||||
|
|
|
@ -126,7 +126,7 @@ test "getting all filters by an user" do
|
||||||
|
|
||||||
{:ok, filter_one} = Pleroma.Filter.create(query_one)
|
{:ok, filter_one} = Pleroma.Filter.create(query_one)
|
||||||
{:ok, filter_two} = Pleroma.Filter.create(query_two)
|
{: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_one in filters
|
||||||
assert filter_two in filters
|
assert filter_two in filters
|
||||||
end
|
end
|
||||||
|
|
|
@ -428,4 +428,12 @@ def mfa_token_factory do
|
||||||
user: build(:user)
|
user: build(:user)
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def filter_factory do
|
||||||
|
%Pleroma.Filter{
|
||||||
|
user: build(:user),
|
||||||
|
filter_id: sequence(:filter_id, & &1),
|
||||||
|
phrase: "cofe"
|
||||||
|
}
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -785,6 +785,75 @@ test "excludes reblogs on request" do
|
||||||
assert activity == expected_activity
|
assert activity == expected_activity
|
||||||
end
|
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
|
describe "public fetch activities" do
|
||||||
test "doesn't retrieve unlisted activities" do
|
test "doesn't retrieve unlisted activities" do
|
||||||
user = insert(:user)
|
user = insert(:user)
|
||||||
|
|
Loading…
Reference in a new issue