Merge branch 'feature/signed-object-fetches' into 'develop'
signed object fetches See merge request pleroma/pleroma!1446
This commit is contained in:
commit
f9a0014681
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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")
|
||||||
|
|
||||||
|
date =
|
||||||
|
NaiveDateTime.utc_now()
|
||||||
|
|> Timex.format!("{WDshort}, {0D} {Mshort} {YYYY} {h24}:{m}:{s} GMT")
|
||||||
|
|
||||||
|
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"),
|
with true <- String.starts_with?(id, "http"),
|
||||||
{:ok, %{body: body, status: code}} when code in 200..299 <-
|
{:ok, %{body: body, status: code}} when code in 200..299 <- HTTP.get(id, headers),
|
||||||
HTTP.get(
|
|
||||||
id,
|
|
||||||
[{:Accept, "application/activity+json"}]
|
|
||||||
),
|
|
||||||
{: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}
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in a new issue