Never fetch resource from ourselves

If it’s not already in the database,
it must be counterfeit (or just not exists at all)

Changed test URLs were only ever used from "local: false" users anyway.
This commit is contained in:
Oneric 2024-03-13 21:00:23 -01:00
parent fee57eb376
commit 59a142e0b0
14 changed files with 77 additions and 53 deletions

View file

@ -47,6 +47,19 @@ def get_object(_) do
defp compare_uris(%URI{host: host} = _id_uri, %URI{host: host} = _other_uri), do: :ok defp compare_uris(%URI{host: host} = _id_uri, %URI{host: host} = _other_uri), do: :ok
defp compare_uris(_id_uri, _other_uri), do: :error defp compare_uris(_id_uri, _other_uri), do: :error
@doc """
Checks whether an URL to fetch from is from the local server.
We never want to fetch from ourselves; if its not in the database
it cant be authentic and must be a counterfeit.
"""
def contain_local_fetch(id) do
case compare_uris(URI.parse(id), Pleroma.Web.Endpoint.struct_url()) do
:ok -> :error
_ -> :ok
end
end
@doc """ @doc """
Checks that an imported AP object's actor matches the host it came from. Checks that an imported AP object's actor matches the host it came from.
""" """

View file

@ -258,6 +258,7 @@ def fetch_and_contain_remote_object_from_id(id) when is_binary(id) do
Logger.debug("Fetching object #{id} via AP") Logger.debug("Fetching object #{id} via AP")
with {:scheme, true} <- {:scheme, String.starts_with?(id, "http")}, with {:scheme, true} <- {:scheme, String.starts_with?(id, "http")},
{_, :ok} <- {:local_fetch, Containment.contain_local_fetch(id)},
{:ok, body} <- get_object(id), {:ok, body} <- get_object(id),
{:ok, data} <- safe_json_decode(body), {:ok, data} <- safe_json_decode(body),
{_, :ok} <- {:containment, Containment.contain_origin_from_id(id, data)}, {_, :ok} <- {:containment, Containment.contain_origin_from_id(id, data)},
@ -271,6 +272,9 @@ def fetch_and_contain_remote_object_from_id(id) when is_binary(id) do
{:scheme, _} -> {:scheme, _} ->
{:error, "Unsupported URI scheme"} {:error, "Unsupported URI scheme"}
{:local_fetch, _} ->
{:error, "Trying to fetch local resource"}
{:containment, _} -> {:containment, _} ->
{:error, "Object containment failed."} {:error, "Object containment failed."}

View file

@ -13,7 +13,7 @@
"directMessage": "litepub:directMessage" "directMessage": "litepub:directMessage"
} }
], ],
"id": "http://localhost:8080/followers/fuser3", "id": "http://remote.org/followers/fuser3",
"type": "OrderedCollection", "type": "OrderedCollection",
"totalItems": 296 "totalItems": 296
} }

View file

@ -13,7 +13,7 @@
"directMessage": "litepub:directMessage" "directMessage": "litepub:directMessage"
} }
], ],
"id": "http://localhost:8080/following/fuser3", "id": "http://remote.org/following/fuser3",
"type": "OrderedCollection", "type": "OrderedCollection",
"totalItems": 32 "totalItems": 32
} }

View file

@ -1,7 +1,7 @@
{ {
"@context": "https://www.w3.org/ns/activitystreams", "@context": "https://www.w3.org/ns/activitystreams",
"id": "http://localhost:4001/users/masto_closed/followers", "id": "http://remote.org/users/masto_closed/followers",
"type": "OrderedCollection", "type": "OrderedCollection",
"totalItems": 437, "totalItems": 437,
"first": "http://localhost:4001/users/masto_closed/followers?page=1" "first": "http://remote.org/users/masto_closed/followers?page=1"
} }

View file

@ -1 +1 @@
{"@context":"https://www.w3.org/ns/activitystreams","id":"http://localhost:4001/users/masto_closed/followers?page=1","type":"OrderedCollectionPage","totalItems":437,"next":"http://localhost:4001/users/masto_closed/followers?page=2","partOf":"http://localhost:4001/users/masto_closed/followers","orderedItems":["https://testing.uguu.ltd/users/rin","https://patch.cx/users/rin","https://letsalllovela.in/users/xoxo","https://pleroma.site/users/crushv","https://aria.company/users/boris","https://kawen.space/users/crushv","https://freespeech.host/users/cvcvcv","https://pleroma.site/users/picpub","https://pixelfed.social/users/nosleep","https://boopsnoot.gq/users/5c1896d162f7d337f90492a3","https://pikachu.rocks/users/waifu","https://royal.crablettesare.life/users/crablettes"]} {"@context":"https://www.w3.org/ns/activitystreams","id":"http://remote.org/users/masto_closed/followers?page=1","type":"OrderedCollectionPage","totalItems":437,"next":"http://remote.org/users/masto_closed/followers?page=2","partOf":"http://remote.org/users/masto_closed/followers","orderedItems":["https://testing.uguu.ltd/users/rin","https://patch.cx/users/rin","https://letsalllovela.in/users/xoxo","https://pleroma.site/users/crushv","https://aria.company/users/boris","https://kawen.space/users/crushv","https://freespeech.host/users/cvcvcv","https://pleroma.site/users/picpub","https://pixelfed.social/users/nosleep","https://boopsnoot.gq/users/5c1896d162f7d337f90492a3","https://pikachu.rocks/users/waifu","https://royal.crablettesare.life/users/crablettes"]}

View file

@ -1,7 +1,7 @@
{ {
"@context": "https://www.w3.org/ns/activitystreams", "@context": "https://www.w3.org/ns/activitystreams",
"id": "http://localhost:4001/users/masto_closed/following", "id": "http://remote.org/users/masto_closed/following",
"type": "OrderedCollection", "type": "OrderedCollection",
"totalItems": 152, "totalItems": 152,
"first": "http://localhost:4001/users/masto_closed/following?page=1" "first": "http://remote.org/users/masto_closed/following?page=1"
} }

View file

@ -1 +1 @@
{"@context":"https://www.w3.org/ns/activitystreams","id":"http://localhost:4001/users/masto_closed/following?page=1","type":"OrderedCollectionPage","totalItems":152,"next":"http://localhost:4001/users/masto_closed/following?page=2","partOf":"http://localhost:4001/users/masto_closed/following","orderedItems":["https://testing.uguu.ltd/users/rin","https://patch.cx/users/rin","https://letsalllovela.in/users/xoxo","https://pleroma.site/users/crushv","https://aria.company/users/boris","https://kawen.space/users/crushv","https://freespeech.host/users/cvcvcv","https://pleroma.site/users/picpub","https://pixelfed.social/users/nosleep","https://boopsnoot.gq/users/5c1896d162f7d337f90492a3","https://pikachu.rocks/users/waifu","https://royal.crablettesare.life/users/crablettes"]} {"@context":"https://www.w3.org/ns/activitystreams","id":"http://remote.org/users/masto_closed/following?page=1","type":"OrderedCollectionPage","totalItems":152,"next":"http://remote.org/users/masto_closed/following?page=2","partOf":"http://remote.org/users/masto_closed/following","orderedItems":["https://testing.uguu.ltd/users/rin","https://patch.cx/users/rin","https://letsalllovela.in/users/xoxo","https://pleroma.site/users/crushv","https://aria.company/users/boris","https://kawen.space/users/crushv","https://freespeech.host/users/cvcvcv","https://pleroma.site/users/picpub","https://pixelfed.social/users/nosleep","https://boopsnoot.gq/users/5c1896d162f7d337f90492a3","https://pikachu.rocks/users/waifu","https://royal.crablettesare.life/users/crablettes"]}

View file

@ -1,14 +1,14 @@
{ {
"type": "OrderedCollection", "type": "OrderedCollection",
"totalItems": 527, "totalItems": 527,
"id": "http://localhost:4001/users/fuser2/followers", "id": "http://remote.org/users/fuser2/followers",
"first": { "first": {
"type": "OrderedCollectionPage", "type": "OrderedCollectionPage",
"totalItems": 527, "totalItems": 527,
"partOf": "http://localhost:4001/users/fuser2/followers", "partOf": "http://remote.org/users/fuser2/followers",
"orderedItems": [], "orderedItems": [],
"next": "http://localhost:4001/users/fuser2/followers?page=2", "next": "http://remote.org/users/fuser2/followers?page=2",
"id": "http://localhost:4001/users/fuser2/followers?page=1" "id": "http://remote.org/users/fuser2/followers?page=1"
}, },
"@context": [ "@context": [
"https://www.w3.org/ns/activitystreams", "https://www.w3.org/ns/activitystreams",

View file

@ -1,14 +1,14 @@
{ {
"type": "OrderedCollection", "type": "OrderedCollection",
"totalItems": 267, "totalItems": 267,
"id": "http://localhost:4001/users/fuser2/following", "id": "http://remote.org/users/fuser2/following",
"first": { "first": {
"type": "OrderedCollectionPage", "type": "OrderedCollectionPage",
"totalItems": 267, "totalItems": 267,
"partOf": "http://localhost:4001/users/fuser2/following", "partOf": "http://remote.org/users/fuser2/following",
"orderedItems": [], "orderedItems": [],
"next": "http://localhost:4001/users/fuser2/following?page=2", "next": "http://remote.org/users/fuser2/following?page=2",
"id": "http://localhost:4001/users/fuser2/following?page=1" "id": "http://remote.org/users/fuser2/following?page=1"
}, },
"@context": [ "@context": [
"https://www.w3.org/ns/activitystreams", "https://www.w3.org/ns/activitystreams",

View file

@ -237,6 +237,13 @@ test "it does not fetch a spoofed object with a foreign actor" do
"https://patch.cx/objects/spoof_foreign_actor" "https://patch.cx/objects/spoof_foreign_actor"
) )
end end
test "it does not fetch from localhost" do
assert {:error, "Trying to fetch local resource"} =
Fetcher.fetch_and_contain_remote_object_from_id(
Pleroma.Web.Endpoint.url() <> "/spoof_local"
)
end
end end
describe "fetching an object" do describe "fetching an object" do

View file

@ -326,9 +326,9 @@ test "unfollow with synchronizes external user" do
insert(:user, %{ insert(:user, %{
local: false, local: false,
nickname: "fuser2", nickname: "fuser2",
ap_id: "http://localhost:4001/users/fuser2", ap_id: "http://remote.org/users/fuser2",
follower_address: "http://localhost:4001/users/fuser2/followers", follower_address: "http://remote.org/users/fuser2/followers",
following_address: "http://localhost:4001/users/fuser2/following" following_address: "http://remote.org/users/fuser2/following"
}) })
{:ok, user, followed} = User.follow(user, followed, :follow_accept) {:ok, user, followed} = User.follow(user, followed, :follow_accept)
@ -2177,8 +2177,8 @@ test "it returns a list of AP ids for a given set of nicknames" do
describe "sync followers count" do describe "sync followers count" do
setup do setup do
user1 = insert(:user, local: false, ap_id: "http://localhost:4001/users/masto_closed") user1 = insert(:user, local: false, ap_id: "http://remote.org/users/masto_closed")
user2 = insert(:user, local: false, ap_id: "http://localhost:4001/users/fuser2") user2 = insert(:user, local: false, ap_id: "http://remote.org/users/fuser2")
insert(:user, local: true) insert(:user, local: true)
insert(:user, local: false, is_active: false) insert(:user, local: false, is_active: false)
{:ok, user1: user1, user2: user2} {:ok, user1: user1, user2: user2}
@ -2272,8 +2272,8 @@ test "updates the counters normally on following/getting a follow when disabled"
other_user = other_user =
insert(:user, insert(:user,
local: false, local: false,
follower_address: "http://localhost:4001/users/masto_closed/followers", follower_address: "http://remote.org/users/masto_closed/followers",
following_address: "http://localhost:4001/users/masto_closed/following", following_address: "http://remote.org/users/masto_closed/following",
ap_enabled: true ap_enabled: true
) )
@ -2294,8 +2294,8 @@ test "synchronizes the counters with the remote instance for the followed when e
other_user = other_user =
insert(:user, insert(:user,
local: false, local: false,
follower_address: "http://localhost:4001/users/masto_closed/followers", follower_address: "http://remote.org/users/masto_closed/followers",
following_address: "http://localhost:4001/users/masto_closed/following", following_address: "http://remote.org/users/masto_closed/following",
ap_enabled: true ap_enabled: true
) )
@ -2316,8 +2316,8 @@ test "synchronizes the counters with the remote instance for the follower when e
other_user = other_user =
insert(:user, insert(:user,
local: false, local: false,
follower_address: "http://localhost:4001/users/masto_closed/followers", follower_address: "http://remote.org/users/masto_closed/followers",
following_address: "http://localhost:4001/users/masto_closed/following", following_address: "http://remote.org/users/masto_closed/following",
ap_enabled: true ap_enabled: true
) )

View file

@ -1643,8 +1643,8 @@ test "synchronizes following/followers counters" do
user = user =
insert(:user, insert(:user,
local: false, local: false,
follower_address: "http://localhost:4001/users/fuser2/followers", follower_address: "http://remote.org/users/fuser2/followers",
following_address: "http://localhost:4001/users/fuser2/following" following_address: "http://remote.org/users/fuser2/following"
) )
{:ok, info} = ActivityPub.fetch_follow_information_for_user(user) {:ok, info} = ActivityPub.fetch_follow_information_for_user(user)
@ -1655,7 +1655,7 @@ test "synchronizes following/followers counters" do
test "detects hidden followers" do test "detects hidden followers" do
mock(fn env -> mock(fn env ->
case env.url do case env.url do
"http://localhost:4001/users/masto_closed/followers?page=1" -> "http://remote.org/users/masto_closed/followers?page=1" ->
%Tesla.Env{status: 403, body: ""} %Tesla.Env{status: 403, body: ""}
_ -> _ ->
@ -1666,8 +1666,8 @@ test "detects hidden followers" do
user = user =
insert(:user, insert(:user,
local: false, local: false,
follower_address: "http://localhost:4001/users/masto_closed/followers", follower_address: "http://remote.org/users/masto_closed/followers",
following_address: "http://localhost:4001/users/masto_closed/following" following_address: "http://remote.org/users/masto_closed/following"
) )
{:ok, follow_info} = ActivityPub.fetch_follow_information_for_user(user) {:ok, follow_info} = ActivityPub.fetch_follow_information_for_user(user)
@ -1678,7 +1678,7 @@ test "detects hidden followers" do
test "detects hidden follows" do test "detects hidden follows" do
mock(fn env -> mock(fn env ->
case env.url do case env.url do
"http://localhost:4001/users/masto_closed/following?page=1" -> "http://remote.org/users/masto_closed/following?page=1" ->
%Tesla.Env{status: 403, body: ""} %Tesla.Env{status: 403, body: ""}
_ -> _ ->
@ -1689,8 +1689,8 @@ test "detects hidden follows" do
user = user =
insert(:user, insert(:user,
local: false, local: false,
follower_address: "http://localhost:4001/users/masto_closed/followers", follower_address: "http://remote.org/users/masto_closed/followers",
following_address: "http://localhost:4001/users/masto_closed/following" following_address: "http://remote.org/users/masto_closed/following"
) )
{:ok, follow_info} = ActivityPub.fetch_follow_information_for_user(user) {:ok, follow_info} = ActivityPub.fetch_follow_information_for_user(user)
@ -1702,8 +1702,8 @@ test "detects hidden follows/followers for friendica" do
user = user =
insert(:user, insert(:user,
local: false, local: false,
follower_address: "http://localhost:8080/followers/fuser3", follower_address: "http://remote.org/followers/fuser3",
following_address: "http://localhost:8080/following/fuser3" following_address: "http://remote.org/following/fuser3"
) )
{:ok, follow_info} = ActivityPub.fetch_follow_information_for_user(user) {:ok, follow_info} = ActivityPub.fetch_follow_information_for_user(user)
@ -1716,28 +1716,28 @@ test "detects hidden follows/followers for friendica" do
test "doesn't crash when follower and following counters are hidden" do test "doesn't crash when follower and following counters are hidden" do
mock(fn env -> mock(fn env ->
case env.url do case env.url do
"http://localhost:4001/users/masto_hidden_counters/following" -> "http://remote.org/users/masto_hidden_counters/following" ->
json( json(
%{ %{
"@context" => "https://www.w3.org/ns/activitystreams", "@context" => "https://www.w3.org/ns/activitystreams",
"id" => "http://localhost:4001/users/masto_hidden_counters/followers" "id" => "http://remote.org/users/masto_hidden_counters/followers"
}, },
headers: HttpRequestMock.activitypub_object_headers() headers: HttpRequestMock.activitypub_object_headers()
) )
"http://localhost:4001/users/masto_hidden_counters/following?page=1" -> "http://remote.org/users/masto_hidden_counters/following?page=1" ->
%Tesla.Env{status: 403, body: ""} %Tesla.Env{status: 403, body: ""}
"http://localhost:4001/users/masto_hidden_counters/followers" -> "http://remote.org/users/masto_hidden_counters/followers" ->
json( json(
%{ %{
"@context" => "https://www.w3.org/ns/activitystreams", "@context" => "https://www.w3.org/ns/activitystreams",
"id" => "http://localhost:4001/users/masto_hidden_counters/following" "id" => "http://remote.org/users/masto_hidden_counters/following"
}, },
headers: HttpRequestMock.activitypub_object_headers() headers: HttpRequestMock.activitypub_object_headers()
) )
"http://localhost:4001/users/masto_hidden_counters/followers?page=1" -> "http://remote.org/users/masto_hidden_counters/followers?page=1" ->
%Tesla.Env{status: 403, body: ""} %Tesla.Env{status: 403, body: ""}
end end
end) end)
@ -1745,8 +1745,8 @@ test "doesn't crash when follower and following counters are hidden" do
user = user =
insert(:user, insert(:user,
local: false, local: false,
follower_address: "http://localhost:4001/users/masto_hidden_counters/followers", follower_address: "http://remote.org/users/masto_hidden_counters/followers",
following_address: "http://localhost:4001/users/masto_hidden_counters/following" following_address: "http://remote.org/users/masto_hidden_counters/following"
) )
{:ok, follow_info} = ActivityPub.fetch_follow_information_for_user(user) {:ok, follow_info} = ActivityPub.fetch_follow_information_for_user(user)

View file

@ -964,7 +964,7 @@ def get("https://pleroma.local/notice/9kCP7V", _, _, _) do
{:ok, %Tesla.Env{status: 200, body: File.read!("test/fixtures/rich_media/ogp.html")}} {:ok, %Tesla.Env{status: 200, body: File.read!("test/fixtures/rich_media/ogp.html")}}
end end
def get("http://localhost:4001/users/masto_closed/followers", _, _, _) do def get("http://remote.org/users/masto_closed/followers", _, _, _) do
{:ok, {:ok,
%Tesla.Env{ %Tesla.Env{
status: 200, status: 200,
@ -973,7 +973,7 @@ def get("http://localhost:4001/users/masto_closed/followers", _, _, _) do
}} }}
end end
def get("http://localhost:4001/users/masto_closed/followers?page=1", _, _, _) do def get("http://remote.org/users/masto_closed/followers?page=1", _, _, _) do
{:ok, {:ok,
%Tesla.Env{ %Tesla.Env{
status: 200, status: 200,
@ -982,7 +982,7 @@ def get("http://localhost:4001/users/masto_closed/followers?page=1", _, _, _) do
}} }}
end end
def get("http://localhost:4001/users/masto_closed/following", _, _, _) do def get("http://remote.org/users/masto_closed/following", _, _, _) do
{:ok, {:ok,
%Tesla.Env{ %Tesla.Env{
status: 200, status: 200,
@ -991,7 +991,7 @@ def get("http://localhost:4001/users/masto_closed/following", _, _, _) do
}} }}
end end
def get("http://localhost:4001/users/masto_closed/following?page=1", _, _, _) do def get("http://remote.org/users/masto_closed/following?page=1", _, _, _) do
{:ok, {:ok,
%Tesla.Env{ %Tesla.Env{
status: 200, status: 200,
@ -1000,7 +1000,7 @@ def get("http://localhost:4001/users/masto_closed/following?page=1", _, _, _) do
}} }}
end end
def get("http://localhost:8080/followers/fuser3", _, _, _) do def get("http://remote.org/followers/fuser3", _, _, _) do
{:ok, {:ok,
%Tesla.Env{ %Tesla.Env{
status: 200, status: 200,
@ -1009,7 +1009,7 @@ def get("http://localhost:8080/followers/fuser3", _, _, _) do
}} }}
end end
def get("http://localhost:8080/following/fuser3", _, _, _) do def get("http://remote.org/following/fuser3", _, _, _) do
{:ok, {:ok,
%Tesla.Env{ %Tesla.Env{
status: 200, status: 200,
@ -1018,7 +1018,7 @@ def get("http://localhost:8080/following/fuser3", _, _, _) do
}} }}
end end
def get("http://localhost:4001/users/fuser2/followers", _, _, _) do def get("http://remote.org/users/fuser2/followers", _, _, _) do
{:ok, {:ok,
%Tesla.Env{ %Tesla.Env{
status: 200, status: 200,
@ -1027,7 +1027,7 @@ def get("http://localhost:4001/users/fuser2/followers", _, _, _) do
}} }}
end end
def get("http://localhost:4001/users/fuser2/following", _, _, _) do def get("http://remote.org/users/fuser2/following", _, _, _) do
{:ok, {:ok,
%Tesla.Env{ %Tesla.Env{
status: 200, status: 200,