Page MenuHomePhorge

No OneTemporary

Authored By
Unknown
Size
7 KB
Referenced Files
None
Subscribers
None
diff --git a/changelog.d/search-remote-fetch.security b/changelog.d/search-remote-fetch.security
new file mode 100644
index 000000000..4211615ae
--- /dev/null
+++ b/changelog.d/search-remote-fetch.security
@@ -0,0 +1 @@
+Status search only fetches remote URLs with resolve=true, on the first page, and for anonymous users only if limit_to_local_content allows it
diff --git a/lib/pleroma/search/database_search.ex b/lib/pleroma/search/database_search.ex
index c66723d1d..dca69260d 100644
--- a/lib/pleroma/search/database_search.ex
+++ b/lib/pleroma/search/database_search.ex
@@ -45,7 +45,7 @@ defmodule Pleroma.Search.DatabaseSearch do
end
# Outside the query transaction, as it may fetch over the network.
- maybe_fetch(activities, user, search_query)
+ maybe_fetch(activities, user, search_query, options)
end
@doc """
@@ -160,7 +160,27 @@ defmodule Pleroma.Search.DatabaseSearch do
defp restrict_local(q), do: where(q, local: true)
- def maybe_fetch(activities, user, search_query) do
+ @doc """
+ Adds the status a URL query points to, fetching it if needed. As in Mastodon,
+ this only happens with `resolve: true` and on the first page, and for
+ anonymous users only if `[:instance, :limit_to_local_content]` is `false`.
+ """
+ def maybe_fetch(activities, user, search_query, options) do
+ if fetch_allowed?(user, options),
+ do: fetch(activities, user, search_query),
+ else: activities
+ end
+
+ defp fetch_allowed?(user, options) do
+ options[:resolve] == true and (options[:offset] || 0) == 0 and
+ case Config.get([:instance, :limit_to_local_content], :unauthenticated) do
+ :all -> false
+ :unauthenticated -> match?(%User{}, user)
+ false -> true
+ end
+ end
+
+ defp fetch(activities, user, search_query) do
with true <- Regex.match?(~r/https?:/, search_query),
{:ok, object} <- Fetcher.fetch_object_from_id(search_query),
%Activity{} = activity <- Activity.get_create_by_object_ap_id(object.data["id"]),
diff --git a/lib/pleroma/search/meilisearch.ex b/lib/pleroma/search/meilisearch.ex
index dc10076e1..802870b75 100644
--- a/lib/pleroma/search/meilisearch.ex
+++ b/lib/pleroma/search/meilisearch.ex
@@ -111,11 +111,11 @@ defmodule Pleroma.Search.Meilisearch do
|> maybe_restrict_local(user)
|> maybe_restrict_author(author)
|> maybe_restrict_blocked(user)
- |> maybe_fetch(user, query)
+ |> maybe_fetch(user, query, options)
|> order_by([object: obj], desc: obj.data["published"])
|> Pleroma.Repo.all()
rescue
- _ -> maybe_fetch([], user, query)
+ _ -> maybe_fetch([], user, query, options)
end
end
end
diff --git a/lib/pleroma/search/parade_db.ex b/lib/pleroma/search/parade_db.ex
index ee00e74af..78d561505 100644
--- a/lib/pleroma/search/parade_db.ex
+++ b/lib/pleroma/search/parade_db.ex
@@ -12,7 +12,7 @@ defmodule Pleroma.Search.ParadeDB do
import Pleroma.Search.DatabaseSearch,
only: [
- maybe_fetch: 3,
+ maybe_fetch: 4,
maybe_restrict_author: 2,
maybe_restrict_blocked: 2,
maybe_restrict_local: 2
@@ -149,19 +149,19 @@ defmodule Pleroma.Search.ParadeDB do
case search_ids(query, limit, offset, author) do
{:ok, []} ->
- maybe_fetch([], user, query)
+ maybe_fetch([], user, query, options)
{:ok, ids} ->
ids
- |> fetch_activities(user, query, author)
+ |> fetch_activities(user, query, author, options)
{:error, error} ->
Logger.error("ParadeDB search failed: #{inspect(error)}")
- maybe_fetch([], user, query)
+ maybe_fetch([], user, query, options)
end
end
- defp fetch_activities(ids, user, query, author) do
+ defp fetch_activities(ids, user, query, author, options) do
dumped_ids =
ids
|> Enum.map(&dump_activity_id/1)
@@ -183,7 +183,7 @@ defmodule Pleroma.Search.ParadeDB do
)
)
|> Pleroma.Repo.all()
- |> maybe_fetch(user, query)
+ |> maybe_fetch(user, query, options)
end
defp maybe_restrict_public(query, %Pleroma.User{}) do
diff --git a/lib/pleroma/search/qdrant_search.ex b/lib/pleroma/search/qdrant_search.ex
index a8c5a3eb9..a453d222f 100644
--- a/lib/pleroma/search/qdrant_search.ex
+++ b/lib/pleroma/search/qdrant_search.ex
@@ -10,7 +10,7 @@ defmodule Pleroma.Search.QdrantSearch do
alias __MODULE__.OpenAIClient
alias __MODULE__.QdrantClient
- import Pleroma.Search.DatabaseSearch, only: [maybe_fetch: 3]
+ import Pleroma.Search.DatabaseSearch, only: [maybe_fetch: 4]
@impl true
def create_index do
@@ -131,7 +131,7 @@ defmodule Pleroma.Search.QdrantSearch do
|> Activity.restrict_deactivated_users()
|> Ecto.Query.order_by([a], fragment("array_position(?, ?)", ^ids, a.id))
|> Pleroma.Repo.all()
- |> maybe_fetch(user, original_query)
+ |> maybe_fetch(user, original_query, options)
else
_ ->
[]
diff --git a/test/pleroma/web/mastodon_api/controllers/search_controller_test.exs b/test/pleroma/web/mastodon_api/controllers/search_controller_test.exs
index f0c9c1901..368c07f35 100644
--- a/test/pleroma/web/mastodon_api/controllers/search_controller_test.exs
+++ b/test/pleroma/web/mastodon_api/controllers/search_controller_test.exs
@@ -328,7 +328,9 @@ defmodule Pleroma.Web.MastodonAPI.SearchControllerTest do
assert status["id"] == to_string(activity.id)
end
- test "search fetches remote statuses and prefers them over other results", %{conn: conn} do
+ test "search fetches remote statuses and prefers them over other results" do
+ %{conn: conn} = oauth_access(["read:search"])
+
{:ok, %{id: activity_id}} =
CommonAPI.post(insert(:user), %{
status: "check out http://mastodon.example.org/@admin/99541947525187367"
@@ -336,7 +338,9 @@ defmodule Pleroma.Web.MastodonAPI.SearchControllerTest do
%{"url" => result_url, "id" => result_id} =
conn
- |> get("/api/v1/search?q=http://mastodon.example.org/@admin/99541947525187367")
+ |> get(
+ "/api/v1/search?resolve=true&q=http://mastodon.example.org/@admin/99541947525187367"
+ )
|> json_response_and_validate_schema(200)
|> Map.get("statuses")
|> List.first()
@@ -345,6 +349,28 @@ defmodule Pleroma.Web.MastodonAPI.SearchControllerTest do
assert match?(^result_url, "http://mastodon.example.org/@admin/99541947525187367")
end
+ test "search fetches remote statuses only with resolve, when logged in, on the first page",
+ %{conn: anonymous} do
+ %{conn: conn} = oauth_access(["read:search"])
+ url = "http://mastodon.example.org/@admin/99541947525187367"
+
+ for {conn, params} <- [
+ {conn, ""},
+ {conn, "&resolve=false"},
+ {conn, "&resolve=true&offset=5"},
+ {anonymous, "&resolve=true"}
+ ] do
+ assert %{"statuses" => []} =
+ conn
+ |> get("/api/v1/search?q=#{url}#{params}")
+ |> json_response_and_validate_schema(200)
+ end
+
+ refute Pleroma.Object.get_by_ap_id(
+ "http://mastodon.example.org/users/admin/statuses/99541947525187367"
+ )
+ end
+
test "search doesn't show statuses that it shouldn't", %{conn: conn} do
{:ok, activity} =
CommonAPI.post(insert(:user), %{
diff --git a/test/pleroma/web/mastodon_api/views/status_view_test.exs b/test/pleroma/web/mastodon_api/views/status_view_test.exs
index 6d1bda193..b121cf32c 100644
--- a/test/pleroma/web/mastodon_api/views/status_view_test.exs
+++ b/test/pleroma/web/mastodon_api/views/status_view_test.exs
@@ -788,7 +788,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusViewTest do
test "put the url advertised in the Activity in to the url attribute" do
id = "https://wedistribute.org/wp-json/pterotype/v1/object/85810"
- [activity] = Activity.search(nil, id)
+ [activity] = Activity.search(insert(:user), id, resolve: true)
status = StatusView.render("show.json", %{activity: activity})

File Metadata

Mime Type
text/x-diff
Expires
Mon, Nov 2, 8:20 AM (7 h, 38 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1803790
Default Alt Text
(7 KB)

Event Timeline