From 422a1d1475bd3db41a05b1a36036f8ae0c27b3c9 Mon Sep 17 00:00:00 2001 From: Lain Soykaf Date: Tue, 27 Oct 2026 12:50:04 +0400 Subject: [PATCH] fix(filters): honour whole_word The whole_word field was stored and returned by the API, but the regex always used word boundaries. As in Mastodon, a filter with whole_word false now also matches inside words. --- changelog.d/filter-whole-word.fix | 1 + lib/pleroma/filter.ex | 11 +++++++---- test/pleroma/filter_test.exs | 11 +++++++++++ 3 files changed, 19 insertions(+), 4 deletions(-) create mode 100644 changelog.d/filter-whole-word.fix diff --git a/changelog.d/filter-whole-word.fix b/changelog.d/filter-whole-word.fix new file mode 100644 index 000000000..a831a74cb --- /dev/null +++ b/changelog.d/filter-whole-word.fix @@ -0,0 +1 @@ +Filters with whole_word set to false now also match inside words diff --git a/lib/pleroma/filter.ex b/lib/pleroma/filter.ex index 3ab44efb0..fe3fb1c27 100644 --- a/lib/pleroma/filter.ex +++ b/lib/pleroma/filter.ex @@ -212,7 +212,7 @@ defmodule Pleroma.Filter do phrases = filters - |> Enum.map(&phrase_regex(&1.phrase, boundary)) + |> Enum.map(&phrase_regex(&1, boundary)) |> Enum.join("|") case format do @@ -223,9 +223,12 @@ defmodule Pleroma.Filter do def compose_regex(_, _), do: nil - # Phrases are literal text. Like Mastodon, only add a word boundary - # where the phrase starts or ends with a word character. - defp phrase_regex(phrase, boundary) do + # Phrases are literal text. Like Mastodon, whole-word filters only get a + # word boundary where the phrase starts or ends with a word character. + defp phrase_regex(%__MODULE__{phrase: phrase, whole_word: false}, _boundary), + do: Regex.escape(phrase) + + defp phrase_regex(%__MODULE__{phrase: phrase}, boundary) do prefix = if String.match?(phrase, ~r/^\w/u), do: boundary, else: "" suffix = if String.match?(phrase, ~r/\w$/u), do: boundary, else: "" diff --git a/test/pleroma/filter_test.exs b/test/pleroma/filter_test.exs index 5018b30bc..2fc72d9f5 100644 --- a/test/pleroma/filter_test.exs +++ b/test/pleroma/filter_test.exs @@ -233,6 +233,17 @@ defmodule Pleroma.FilterTest do end end + test "matches inside words when whole_word is false" do + filters = [%Filter{phrase: "cat", whole_word: false}, %Filter{phrase: "dog"}] + pg = Filter.compose_regex(filters) + re = Filter.compose_regex(filters, :re) + + for {text, expected} <- [{"a catalog", true}, {"a hotdog", false}, {"a dog", true}] do + assert pg_match?(pg, text) == expected + assert Regex.match?(re, text) == expected + end + end + test "keeps word boundaries for every phrase in Elixir" do regex = Filter.compose_regex(filters(["cat", "dog"]), :re)