Merge branch 'feature/signed-object-fetches' into 'develop'

signed object fetches

See merge request pleroma/pleroma!1446
This commit is contained in:
kaniini 2019-07-18 13:27:50 +00:00
commit f9a0014681
6 changed files with 80 additions and 6 deletions

View file

@ -44,6 +44,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
- Addressable lists - Addressable lists
- Twitter API: added rate limit for `/api/account/password_reset` endpoint. - Twitter API: added rate limit for `/api/account/password_reset` endpoint.
- ActivityPub: Add an internal service actor for fetching ActivityPub objects. - ActivityPub: Add an internal service actor for fetching ActivityPub objects.
- ActivityPub: Optional signing of ActivityPub object fetches.
### Changed ### Changed
- Configuration: Filter.AnonymizeFilename added ability to retain file extension with custom text - Configuration: Filter.AnonymizeFilename added ability to retain file extension with custom text

View file

@ -305,7 +305,8 @@
accept_blocks: true, accept_blocks: true,
unfollow_blocked: true, unfollow_blocked: true,
outgoing_blocks: true, outgoing_blocks: true,
follow_handshake_timeout: 500 follow_handshake_timeout: 500,
sign_object_fetches: true
config :pleroma, :user, deny_follow_blocked: true config :pleroma, :user, deny_follow_blocked: true

View file

@ -31,6 +31,8 @@
skip_thread_containment: false, skip_thread_containment: false,
federating: false federating: false
config :pleroma, :activitypub, sign_object_fetches: false
# Configure your database # Configure your database
config :pleroma, Pleroma.Repo, config :pleroma, Pleroma.Repo,
adapter: Ecto.Adapters.Postgres, adapter: Ecto.Adapters.Postgres,

View file

@ -332,6 +332,7 @@ This will make Pleroma listen on `127.0.0.1` port `8080` and generate urls start
* ``unfollow_blocked``: Whether blocks result in people getting unfollowed * ``unfollow_blocked``: Whether blocks result in people getting unfollowed
* ``outgoing_blocks``: Whether to federate blocks to other instances * ``outgoing_blocks``: Whether to federate blocks to other instances
* ``deny_follow_blocked``: Whether to disallow following an account that has blocked the user in question * ``deny_follow_blocked``: Whether to disallow following an account that has blocked the user in question
* ``sign_object_fetches``: Sign object fetches with HTTP signatures
## :http_security ## :http_security
* ``enabled``: Whether the managed content security policy is enabled * ``enabled``: Whether the managed content security policy is enabled

View file

@ -6,6 +6,8 @@ defmodule Pleroma.Object.Fetcher do
alias Pleroma.HTTP alias Pleroma.HTTP
alias Pleroma.Object alias Pleroma.Object
alias Pleroma.Object.Containment alias Pleroma.Object.Containment
alias Pleroma.Signature
alias Pleroma.Web.ActivityPub.InternalFetchActor
alias Pleroma.Web.ActivityPub.Transmogrifier alias Pleroma.Web.ActivityPub.Transmogrifier
alias Pleroma.Web.OStatus alias Pleroma.Web.OStatus
@ -82,15 +84,52 @@ def fetch_object_from_id!(id, options \\ []) do
end end
end end
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) do def fetch_and_contain_remote_object_from_id(id) do
Logger.info("Fetching object #{id} via AP") Logger.info("Fetching object #{id} via AP")
with true <- String.starts_with?(id, "http"), date =
{:ok, %{body: body, status: code}} when code in 200..299 <- NaiveDateTime.utc_now()
HTTP.get( |> Timex.format!("{WDshort}, {0D} {Mshort} {YYYY} {h24}:{m}:{s} GMT")
id,
headers =
[{:Accept, "application/activity+json"}] [{: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, headers),
{:ok, data} <- Jason.decode(body), {:ok, data} <- Jason.decode(body),
:ok <- Containment.contain_origin_from_id(id, data) do :ok <- Containment.contain_origin_from_id(id, data) do
{:ok, data} {:ok, data}

View file

@ -150,4 +150,34 @@ test "it can refetch pruned objects" do
assert object.id != object_two.id assert object.id != object_two.id
end end
end end
describe "signed fetches" do
test_with_mock "it signs fetches when configured to do so",
Pleroma.Signature,
[:passthrough],
[] do
option = Pleroma.Config.get([:activitypub, :sign_object_fetches])
Pleroma.Config.put([:activitypub, :sign_object_fetches], true)
Fetcher.fetch_object_from_id("http://mastodon.example.org/@admin/99541947525187367")
assert called(Pleroma.Signature.sign(:_, :_))
Pleroma.Config.put([:activitypub, :sign_object_fetches], option)
end
test_with_mock "it doesn't sign fetches when not configured to do so",
Pleroma.Signature,
[:passthrough],
[] do
option = Pleroma.Config.get([:activitypub, :sign_object_fetches])
Pleroma.Config.put([:activitypub, :sign_object_fetches], false)
Fetcher.fetch_object_from_id("http://mastodon.example.org/@admin/99541947525187367")
refute called(Pleroma.Signature.sign(:_, :_))
Pleroma.Config.put([:activitypub, :sign_object_fetches], option)
end
end
end end