alias Pleroma.HTTP
alias Pleroma.Object
alias Pleroma.Object.Containment
+ alias Pleroma.Signature
+ alias Pleroma.Web.ActivityPub.InternalFetchActor
alias Pleroma.Web.ActivityPub.Transmogrifier
alias Pleroma.Web.OStatus
else
Logger.info("Fetching #{id} via AP")
- with {:ok, data} <- fetch_and_contain_remote_object_from_id(id),
- nil <- Object.normalize(data, false),
+ 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"],
- # TODO: Should we seriously keep this attributedTo thing?
+ # Should we seriously keep this attributedTo thing?
"actor" => data["actor"] || data["attributedTo"],
"object" => data
},
- :ok <- Containment.contain_origin(id, params),
+ {: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
+ {:containment, _} ->
+ {:error, "Object containment failed."}
+
{:error, {:reject, nil}} ->
{:reject, nil}
{:object, data, nil} ->
reinject_object(data)
- object = %Object{} ->
+ {:normalize, object = %Object{}} ->
{:ok, object}
- :error ->
- {:error, "Object containment failed."}
-
_e ->
+ # 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
- def fetch_and_contain_remote_object_from_id(id) do
+ defp make_signature(id, date) do
+ uri = URI.parse(id)
+
+ signature =
+ InternalFetchActor.get_actor()
+ |> Signature.sign(%{
+ "(request-target)": "get #{uri.path}",
+ host: uri.host,
+ date: date
+ })
+
+ [{:Signature, signature}]
+ end
+
+ defp sign_fetch(headers, id, date) do
+ if Pleroma.Config.get([:activitypub, :sign_object_fetches]) do
+ headers ++ make_signature(id, date)
+ else
+ headers
+ end
+ end
+
+ defp maybe_date_fetch(headers, date) do
+ if Pleroma.Config.get([:activitypub, :sign_object_fetches]) do
+ headers ++ [{:Date, date}]
+ else
+ headers
+ end
+ end
+
+ def fetch_and_contain_remote_object_from_id(id) when is_binary(id) do
Logger.info("Fetching object #{id} via AP")
+ date = Pleroma.Signature.signed_date()
+
+ headers =
+ [{:Accept, "application/activity+json"}]
+ |> maybe_date_fetch(date)
+ |> sign_fetch(id, date)
+
+ Logger.debug("Fetch headers: #{inspect(headers)}")
+
with true <- String.starts_with?(id, "http"),
- {:ok, %{body: body, status: code}} when code in 200..299 <-
- HTTP.get(
- id,
- [{:Accept, "application/activity+json"}]
- ),
+ {:ok, %{body: body, status: code}} when code in 200..299 <- HTTP.get(id, headers),
{:ok, data} <- Jason.decode(body),
:ok <- Containment.contain_origin_from_id(id, data) do
{:ok, data}
{:error, e}
end
end
+
+ 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), do: {:error, "id must be a string"}
end