From efa9a13d4e27c797ae02a44ddc95fd81fea36804 Mon Sep 17 00:00:00 2001 From: "Haelwenn (lanodan) Monnier" Date: Sun, 14 Jul 2019 13:31:43 +0200 Subject: [PATCH 1/6] HttpRequestMock: Add missing mocks for object containment tests --- test/support/http_request_mock.ex | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/test/support/http_request_mock.ex b/test/support/http_request_mock.ex index ff6bb78f9..80586426b 100644 --- a/test/support/http_request_mock.ex +++ b/test/support/http_request_mock.ex @@ -879,6 +879,30 @@ def get( }} end + def get("https://info.pleroma.site/activity.json", _, _, Accept: "application/activity+json") do + {:ok, + %Tesla.Env{ + status: 200, + body: File.read!("test/fixtures/tesla_mock/https__info.pleroma.site_activity.json") + }} + end + + def get("https://info.pleroma.site/activity2.json", _, _, Accept: "application/activity+json") do + {:ok, + %Tesla.Env{ + status: 200, + body: File.read!("test/fixtures/tesla_mock/https__info.pleroma.site_activity2.json") + }} + end + + def get("https://info.pleroma.site/activity3.json", _, _, Accept: "application/activity+json") do + {:ok, + %Tesla.Env{ + status: 200, + body: File.read!("test/fixtures/tesla_mock/https__info.pleroma.site_activity3.json") + }} + end + def get(url, query, body, headers) do {:error, "Not implemented the mock response for get #{inspect(url)}, #{query}, #{inspect(body)}, #{ From f00562ed6bef980bc14038b15078d3427876f7db Mon Sep 17 00:00:00 2001 From: "Haelwenn (lanodan) Monnier" Date: Sun, 14 Jul 2019 13:39:05 +0200 Subject: [PATCH 2/6] HttpRequestMock: Add 404s on OStatus fetching for info.pleroma.site --- test/support/http_request_mock.ex | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/test/support/http_request_mock.ex b/test/support/http_request_mock.ex index 80586426b..7811f7807 100644 --- a/test/support/http_request_mock.ex +++ b/test/support/http_request_mock.ex @@ -887,6 +887,10 @@ def get("https://info.pleroma.site/activity.json", _, _, Accept: "application/ac }} end + def get("https://info.pleroma.site/activity.json", _, _, _) do + {:ok, %Tesla.Env{status: 404, body: ""}} + end + def get("https://info.pleroma.site/activity2.json", _, _, Accept: "application/activity+json") do {:ok, %Tesla.Env{ @@ -895,6 +899,10 @@ def get("https://info.pleroma.site/activity2.json", _, _, Accept: "application/a }} end + def get("https://info.pleroma.site/activity2.json", _, _, _) do + {:ok, %Tesla.Env{status: 404, body: ""}} + end + def get("https://info.pleroma.site/activity3.json", _, _, Accept: "application/activity+json") do {:ok, %Tesla.Env{ @@ -903,6 +911,10 @@ def get("https://info.pleroma.site/activity3.json", _, _, Accept: "application/a }} end + def get("https://info.pleroma.site/activity3.json", _, _, _) do + {:ok, %Tesla.Env{status: 404, body: ""}} + end + def get(url, query, body, headers) do {:error, "Not implemented the mock response for get #{inspect(url)}, #{query}, #{inspect(body)}, #{ From 40d0a198e20d577b51339f4026d672b1aa968be1 Mon Sep 17 00:00:00 2001 From: "Haelwenn (lanodan) Monnier" Date: Sun, 14 Jul 2019 12:02:16 +0200 Subject: [PATCH 3/6] Object.Fetcher: Handle error on Containment.contain_origin/2 --- lib/pleroma/object/fetcher.ex | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/pleroma/object/fetcher.ex b/lib/pleroma/object/fetcher.ex index 101c21f96..82250ab8d 100644 --- a/lib/pleroma/object/fetcher.ex +++ b/lib/pleroma/object/fetcher.ex @@ -38,6 +38,7 @@ def fetch_object_from_id(id, options \\ []) do "type" => "Create", "to" => data["to"], "cc" => data["cc"], + # TODO: Should we seriously keep this attributedTo thing? "actor" => data["actor"] || data["attributedTo"], "object" => data }, @@ -56,6 +57,9 @@ def fetch_object_from_id(id, options \\ []) do object = %Object{} -> {:ok, object} + :error -> + {:error, "Object containment failed."} + _e -> Logger.info("Couldn't get object via AP, trying out OStatus fetching...") From e1c08a67d6f8981417fe4d5592a60a3882f454f9 Mon Sep 17 00:00:00 2001 From: "Haelwenn (lanodan) Monnier" Date: Sun, 14 Jul 2019 12:13:11 +0200 Subject: [PATCH 4/6] Object.Fetcher: Fallback to OStatus only if AP actually fails --- lib/pleroma/object/fetcher.ex | 62 ++++++++++++++++++++--------------- 1 file changed, 36 insertions(+), 26 deletions(-) diff --git a/lib/pleroma/object/fetcher.ex b/lib/pleroma/object/fetcher.ex index 82250ab8d..14454ce9d 100644 --- a/lib/pleroma/object/fetcher.ex +++ b/lib/pleroma/object/fetcher.ex @@ -31,42 +31,52 @@ def fetch_object_from_id(id, options \\ []) do {:ok, object} else Logger.info("Fetching #{id} via AP") + {status, data} = fetch_and_contain_remote_object_from_id(id) + object = Object.normalize(data, false) - with {:ok, data} <- fetch_and_contain_remote_object_from_id(id), - nil <- Object.normalize(data, false), - params <- %{ - "type" => "Create", - "to" => data["to"], - "cc" => data["cc"], - # TODO: Should we seriously keep this attributedTo thing? - "actor" => data["actor"] || data["attributedTo"], - "object" => data - }, - :ok <- Containment.contain_origin(id, params), - {:ok, activity} <- Transmogrifier.handle_incoming(params, options), - {:object, _data, %Object{} = object} <- - {:object, data, Object.normalize(activity, false)} do - {:ok, object} - else - {:error, {:reject, nil}} -> - {:reject, nil} - - {:object, data, nil} -> - reinject_object(data) - - object = %Object{} -> + if status == :ok and object == nil do + with params <- %{ + "type" => "Create", + "to" => data["to"], + "cc" => data["cc"], + # Should we seriously keep this attributedTo thing? + "actor" => data["actor"] || data["attributedTo"], + "object" => data + }, + :ok <- Containment.contain_origin(id, params), + {:ok, activity} <- Transmogrifier.handle_incoming(params, options), + {:object, _data, %Object{} = object} <- + {:object, data, Object.normalize(activity, false)} do {:ok, object} + else + {:error, {:reject, nil}} -> + {:reject, nil} - :error -> - {:error, "Object containment failed."} + {:object, data, nil} -> + reinject_object(data) - _e -> + object = %Object{} -> + {:ok, object} + + :error -> + {:error, "Object containment failed."} + + e -> + e + end + else + if status == :ok and object != nil do + {:ok, object} + else + # Only fallback when receiving a fetch/normalization error with ActivityPub Logger.info("Couldn't get object via AP, trying out OStatus fetching...") + # FIXME: OStatus Object Containment? case OStatus.fetch_activity_from_url(id) do {:ok, [activity | _]} -> {:ok, Object.normalize(activity, false)} e -> e end + end end end end From a2c601acb5e91ccfee2f38cb24ec3f86aaafc8a1 Mon Sep 17 00:00:00 2001 From: "Haelwenn (lanodan) Monnier" Date: Sun, 14 Jul 2019 14:24:56 +0200 Subject: [PATCH 5/6] FetcherTest: Containment refute called(OStatus.fetch_activity_from_url) --- test/object/fetcher_test.exs | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/test/object/fetcher_test.exs b/test/object/fetcher_test.exs index 3b666e0d1..56a9d775f 100644 --- a/test/object/fetcher_test.exs +++ b/test/object/fetcher_test.exs @@ -9,6 +9,7 @@ defmodule Pleroma.Object.FetcherTest do alias Pleroma.Object alias Pleroma.Object.Fetcher import Tesla.Mock + import Mock setup do mock(fn @@ -26,16 +27,31 @@ defmodule Pleroma.Object.FetcherTest do end describe "actor origin containment" do - test "it rejects objects with a bogus origin" do + test_with_mock "it rejects objects with a bogus origin", + Pleroma.Web.OStatus, + [:passthrough], + [] do {:error, _} = Fetcher.fetch_object_from_id("https://info.pleroma.site/activity.json") + + refute called(Pleroma.Web.OStatus.fetch_activity_from_url(:_)) end - test "it rejects objects when attributedTo is wrong (variant 1)" do + test_with_mock "it rejects objects when attributedTo is wrong (variant 1)", + Pleroma.Web.OStatus, + [:passthrough], + [] do {:error, _} = Fetcher.fetch_object_from_id("https://info.pleroma.site/activity2.json") + + refute called(Pleroma.Web.OStatus.fetch_activity_from_url(:_)) end - test "it rejects objects when attributedTo is wrong (variant 2)" do + test_with_mock "it rejects objects when attributedTo is wrong (variant 2)", + Pleroma.Web.OStatus, + [:passthrough], + [] do {:error, _} = Fetcher.fetch_object_from_id("https://info.pleroma.site/activity3.json") + + refute called(Pleroma.Web.OStatus.fetch_activity_from_url(:_)) end end From 2592934480dd704033de013491373c9dc1d173a2 Mon Sep 17 00:00:00 2001 From: "Haelwenn (lanodan) Monnier" Date: Sun, 14 Jul 2019 17:28:25 +0200 Subject: [PATCH 6/6] Object.Fetcher: Keep the with-do block as per kaniini proposition --- lib/pleroma/object/fetcher.ex | 62 +++++++++++++++-------------------- 1 file changed, 27 insertions(+), 35 deletions(-) diff --git a/lib/pleroma/object/fetcher.ex b/lib/pleroma/object/fetcher.ex index 14454ce9d..96b34ae9f 100644 --- a/lib/pleroma/object/fetcher.ex +++ b/lib/pleroma/object/fetcher.ex @@ -31,43 +31,36 @@ def fetch_object_from_id(id, options \\ []) do {:ok, object} else Logger.info("Fetching #{id} via AP") - {status, data} = fetch_and_contain_remote_object_from_id(id) - object = Object.normalize(data, false) - if status == :ok and object == nil do - with params <- %{ - "type" => "Create", - "to" => data["to"], - "cc" => data["cc"], - # Should we seriously keep this attributedTo thing? - "actor" => data["actor"] || data["attributedTo"], - "object" => data - }, - :ok <- Containment.contain_origin(id, params), - {:ok, activity} <- Transmogrifier.handle_incoming(params, options), - {:object, _data, %Object{} = object} <- - {:object, data, Object.normalize(activity, false)} do - {:ok, object} - else - {:error, {:reject, nil}} -> - {:reject, nil} - - {:object, data, nil} -> - reinject_object(data) - - object = %Object{} -> - {:ok, object} - - :error -> - {:error, "Object containment failed."} - - e -> - e - end + with {:fetch, {:ok, data}} <- {:fetch, fetch_and_contain_remote_object_from_id(id)}, + {:normalize, nil} <- {:normalize, Object.normalize(data, false)}, + params <- %{ + "type" => "Create", + "to" => data["to"], + "cc" => data["cc"], + # Should we seriously keep this attributedTo thing? + "actor" => data["actor"] || data["attributedTo"], + "object" => data + }, + {:containment, :ok} <- {:containment, Containment.contain_origin(id, params)}, + {:ok, activity} <- Transmogrifier.handle_incoming(params, options), + {:object, _data, %Object{} = object} <- + {:object, data, Object.normalize(activity, false)} do + {:ok, object} else - if status == :ok and object != nil do + {:containment, _} -> + {:error, "Object containment failed."} + + {:error, {:reject, nil}} -> + {:reject, nil} + + {:object, data, nil} -> + reinject_object(data) + + {:normalize, object = %Object{}} -> {:ok, object} - else + + _e -> # Only fallback when receiving a fetch/normalization error with ActivityPub Logger.info("Couldn't get object via AP, trying out OStatus fetching...") @@ -76,7 +69,6 @@ def fetch_object_from_id(id, options \\ []) do {:ok, [activity | _]} -> {:ok, Object.normalize(activity, false)} e -> e end - end end end end