Optionally filter local timelines according to domain
Signed-off-by: marcin mikołajczak <git@mkljczk.pl>
This commit is contained in:
parent
db533b032b
commit
1ee3ba5fd3
5 changed files with 86 additions and 0 deletions
|
@ -1071,6 +1071,11 @@
|
|||
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"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
@ -926,6 +926,24 @@ defp restrict_local(query, %{local_only: true}) 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 @@ def fetch_activities_query(recipients, opts \\ %{}) do
|
|||
|> restrict_replies(opts)
|
||||
|> restrict_since(opts)
|
||||
|> restrict_local(opts)
|
||||
|> restrict_domain(opts)
|
||||
|> restrict_remote(opts)
|
||||
|> restrict_actor(opts)
|
||||
|> restrict_type(opts)
|
||||
|
|
|
@ -50,6 +50,7 @@ def home(%{assigns: %{user: user}} = conn, params) 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 @@ def public(%{assigns: %{user: user}} = conn, params) 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 @@ defp hashtag_fetching(params, user, local_only) 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 @@ def list(%{assigns: %{user: user}} = conn, %{list_id: id} = params) 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 @@ def list(%{assigns: %{user: user}} = conn, %{list_id: id} = params) 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
|
||||
|
|
|
@ -16,5 +16,7 @@ def change do
|
|||
alter table(:users) do
|
||||
add(:domain_id, references(:domains))
|
||||
end
|
||||
|
||||
create_if_not_exists(index(:users, [:domain_id]))
|
||||
end
|
||||
end
|
||||
|
|
|
@ -408,6 +408,48 @@ test "should not return local-only posts for anonymous users" 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
|
||||
|
|
Loading…
Reference in a new issue