Optionally filter local timelines according to domain

Signed-off-by: marcin mikołajczak <git@mkljczk.pl>
This commit is contained in:
marcin mikołajczak 2023-11-16 01:18:09 +01:00
parent db533b032b
commit 1ee3ba5fd3
5 changed files with 86 additions and 0 deletions

View file

@ -1071,6 +1071,11 @@ config :pleroma, :config_description, [
key: :enabled,
type: :boolean,
description: "Enables allowing multiple Webfinger domains"
},
%{
key: :separate_timelines,
type: :boolean,
description: "Only display posts from own domain on local timeline"
}
]
}

View file

@ -926,6 +926,24 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
defp restrict_local(query, _), do: query
defp restrict_domain(query, %{domain_id: 0}) do
query
|> join(:inner, [activity], u in User,
as: :domain_user,
on: activity.actor == u.ap_id and is_nil(u.domain_id)
)
end
defp restrict_domain(query, %{domain_id: domain_id}) do
query
|> join(:inner, [activity], u in User,
as: :domain_user,
on: activity.actor == u.ap_id and u.domain_id == ^domain_id
)
end
defp restrict_domain(query, _), do: query
defp restrict_remote(query, %{remote: true}) do
from(activity in query, where: activity.local == false)
end
@ -1404,6 +1422,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
|> restrict_replies(opts)
|> restrict_since(opts)
|> restrict_local(opts)
|> restrict_domain(opts)
|> restrict_remote(opts)
|> restrict_actor(opts)
|> restrict_type(opts)

View file

@ -50,6 +50,7 @@ defmodule Pleroma.Web.MastodonAPI.TimelineController do
|> Map.put(:user, user)
|> Map.put(:local_only, params[:local])
|> Map.delete(:local)
|> ActivityPub.fetch_public_activities()
activities =
[user.ap_id | User.following(user)]
@ -114,6 +115,7 @@ defmodule Pleroma.Web.MastodonAPI.TimelineController do
|> Map.put(:instance, params[:instance])
# Restricts unfederated content to authenticated users
|> Map.put(:includes_local_public, not is_nil(user))
|> maybe_put_domain_id(user)
|> ActivityPub.fetch_public_activities()
conn
@ -150,6 +152,7 @@ defmodule Pleroma.Web.MastodonAPI.TimelineController do
|> Map.put(:tag, tags_any)
|> Map.put(:tag_all, tag_all)
|> Map.put(:tag_reject, tag_reject)
|> maybe_put_domain_id(user)
|> ActivityPub.fetch_public_activities()
end
@ -183,6 +186,7 @@ defmodule Pleroma.Web.MastodonAPI.TimelineController do
|> Map.put(:user, user)
|> Map.put(:muting_user, user)
|> Map.put(:local_only, params[:local])
|> ActivityPub.fetch_public_activities()
# we must filter the following list for the user to avoid leaking statuses the user
# does not actually have permission to see (for more info, peruse security issue #270).
@ -207,4 +211,18 @@ defmodule Pleroma.Web.MastodonAPI.TimelineController do
_e -> render_error(conn, :forbidden, "Error.")
end
end
defp maybe_put_domain_id(%{local_only: true} = params, user) do
separate_timelines = Config.get([:instance, :multitenancy, :separate_timelines])
domain_id = if(user, do: user.domain_id || 0, else: 0)
if separate_timelines do
params
|> Map.put(:domain_id, domain_id)
else
params
end
end
defp maybe_put_domain_id(params, _user), do: params
end

View file

@ -16,5 +16,7 @@ defmodule Pleroma.Repo.Migrations.CreateDomains do
alter table(:users) do
add(:domain_id, references(:domains))
end
create_if_not_exists(index(:users, [:domain_id]))
end
end

View file

@ -408,6 +408,48 @@ defmodule Pleroma.Web.MastodonAPI.TimelineControllerTest do
assert [] = result
end
test "filtering local posts basing on domain", %{conn: conn} do
clear_config([:instance, :multitenancy], %{separate_timelines: false})
{:ok, domain} = Pleroma.Domain.create(%{domain: "pleroma.example.org"})
user1 = insert(:user)
user2 = insert(:user, %{domain_id: domain.id})
%{id: note1} = insert(:note_activity, user: user1)
%{id: note2} = insert(:note_activity, user: user2)
assert [
%{"id" => ^note2},
%{"id" => ^note1}
] =
conn
|> get("/api/v1/timelines/public?local=true")
|> json_response_and_validate_schema(200)
clear_config([:instance, :multitenancy], %{separate_timelines: true})
assert [%{"id" => ^note1}] =
conn
|> get("/api/v1/timelines/public?local=true")
|> json_response_and_validate_schema(200)
assert [%{"id" => ^note1}] =
conn
|> assign(:user, user1)
|> assign(:token, insert(:oauth_token, user: user1, scopes: ["read:statuses"]))
|> get("/api/v1/timelines/public?local=true")
|> json_response_and_validate_schema(200)
assert [%{"id" => ^note2}] =
conn
|> assign(:user, user2)
|> assign(:token, insert(:oauth_token, user: user2, scopes: ["read:statuses"]))
|> get("/api/v1/timelines/public?local=true")
|> json_response_and_validate_schema(200)
end
end
defp local_and_remote_activities do