fix(fetcher): require fetched documents to have the fetched id
The fetcher accepted any document whose id was on the same host as the fetch URL. Anyone who can place a JSON file on a host, for example through an upload, could pass it off as another object or actor from that host. The id of a fetched document must now be the URL it came from (after redirects), ignoring a trailing slash, the fragment, the host case and differences that our URL encoding removes. If it differs, as for Mastodon's /@user/123 display URLs, we refetch once from that id, which must be on the same host. The refetch must not redirect and must match exactly. Test mocks that served a document under a different URL now serve it from its own id. Based on Akkoma 8684964c5 and 940792f8b.
This commit is contained in:
parent
695dd340de
commit
20354e0aee
8 changed files with 259 additions and 15 deletions
|
|
@ -140,17 +140,39 @@ defmodule Pleroma.Object.Fetcher do
|
|||
def fetch_and_contain_remote_object_from_id(%{"id" => id}),
|
||||
do: fetch_and_contain_remote_object_from_id(id)
|
||||
|
||||
def fetch_and_contain_remote_object_from_id(id) when is_binary(id) do
|
||||
def fetch_and_contain_remote_object_from_id(id) when is_binary(id),
|
||||
do: fetch_and_contain(id, false)
|
||||
|
||||
def fetch_and_contain_remote_object_from_id(_id),
|
||||
do: {:error, "id must be a string"}
|
||||
|
||||
# The fetched document's id must be the URL it came from. Display URLs
|
||||
# (e.g. Mastodon's /@user/123) serve the object under another id, so
|
||||
# if the id differs we refetch once from that id, which has to be on the
|
||||
# same host, must not redirect, and must then match exactly.
|
||||
# Based on Akkoma 8684964c5 and 940792f8b.
|
||||
defp fetch_and_contain(id, canonical?) do
|
||||
Logger.debug("Fetching object #{id} via AP")
|
||||
|
||||
with {:scheme, true} <- {:scheme, String.starts_with?(id, "http")},
|
||||
{_, true} <- {:mrf, MRF.id_filter(id)},
|
||||
{_, :ok} <- {:local_fetch, Containment.contain_local_fetch(id)},
|
||||
{:ok, body} <- get_object(id),
|
||||
{:ok, final_url, body} <- get_object(id),
|
||||
{_, true} <- {:redirect, not canonical? or same_url?(final_url, id)},
|
||||
{:ok, data} <- safe_json_decode(body),
|
||||
:ok <- Containment.contain_origin_from_id(id, data) do
|
||||
:ok <- Containment.contain_origin_from_id(id, data),
|
||||
{_, _, :ok} <- {:id, data, Containment.contain_id_to_fetch(final_url, data)} do
|
||||
{:ok, data}
|
||||
else
|
||||
{:id, %{"id" => canonical_id}, :error} when is_binary(canonical_id) and not canonical? ->
|
||||
fetch_and_contain(canonical_id, true)
|
||||
|
||||
{:id, _, :error} ->
|
||||
{:error, :id_mismatch}
|
||||
|
||||
{:redirect, false} ->
|
||||
{:error, :canonical_id_redirect}
|
||||
|
||||
{:scheme, _} ->
|
||||
{:error, "Unsupported URI scheme"}
|
||||
|
||||
|
|
@ -168,8 +190,7 @@ defmodule Pleroma.Object.Fetcher do
|
|||
end
|
||||
end
|
||||
|
||||
def fetch_and_contain_remote_object_from_id(_id),
|
||||
do: {:error, "id must be a string"}
|
||||
defp same_url?(url, other), do: Containment.contain_id_to_fetch(url, %{"id" => other}) == :ok
|
||||
|
||||
defp check_crossdomain_redirect(final_host, _original_url) when is_nil(final_host) do
|
||||
{:cross_domain_redirect, false}
|
||||
|
|
@ -195,7 +216,7 @@ defmodule Pleroma.Object.Fetcher do
|
|||
with {:cross_domain_redirect, false} <- check_crossdomain_redirect(remote_host, id),
|
||||
{_, content_type} <- List.keyfind(headers, "content-type", 0),
|
||||
{:ok, _media_type} <- verify_content_type(content_type) do
|
||||
{:ok, body}
|
||||
{:ok, if(final_url in [nil, ""], do: id, else: final_url), body}
|
||||
else
|
||||
{:cross_domain_redirect, true} ->
|
||||
{:error, {:cross_domain_redirect, true}}
|
||||
|
|
@ -209,7 +230,7 @@ defmodule Pleroma.Object.Fetcher do
|
|||
case List.keyfind(headers, "content-type", 0) do
|
||||
{_, content_type} ->
|
||||
case verify_content_type(content_type) do
|
||||
{:ok, _} -> {:ok, body}
|
||||
{:ok, _} -> {:ok, id, body}
|
||||
error -> error
|
||||
end
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue