Merge branch 'drop-unknown-deletes' into 'develop'
Drop unwanted activities from unknown actors See merge request pleroma/pleroma!4236
This commit is contained in:
commit
61e4be396f
1
changelog.d/drop-unwanted.change
Normal file
1
changelog.d/drop-unwanted.change
Normal file
@ -0,0 +1 @@
|
|||||||
|
Restrict incoming activities from unknown actors to a subset that does not imply a previous relationship and early rejection of unrecognized activity types.
|
@ -85,6 +85,36 @@ defmodule Pleroma.Constants do
|
|||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const(activity_types,
|
||||||
|
do: [
|
||||||
|
"Create",
|
||||||
|
"Update",
|
||||||
|
"Delete",
|
||||||
|
"Follow",
|
||||||
|
"Accept",
|
||||||
|
"Reject",
|
||||||
|
"Add",
|
||||||
|
"Remove",
|
||||||
|
"Like",
|
||||||
|
"Announce",
|
||||||
|
"Undo",
|
||||||
|
"Flag",
|
||||||
|
"EmojiReact"
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
const(allowed_activity_types_from_strangers,
|
||||||
|
do: [
|
||||||
|
"Block",
|
||||||
|
"Create",
|
||||||
|
"Flag",
|
||||||
|
"Follow",
|
||||||
|
"Like",
|
||||||
|
"EmojiReact",
|
||||||
|
"Announce"
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
# basic regex, just there to weed out potential mistakes
|
# basic regex, just there to weed out potential mistakes
|
||||||
# https://datatracker.ietf.org/doc/html/rfc2045#section-5.1
|
# https://datatracker.ietf.org/doc/html/rfc2045#section-5.1
|
||||||
const(mime_regex,
|
const(mime_regex,
|
||||||
|
@ -311,7 +311,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubController do
|
|||||||
post_inbox_relayed_create(conn, params)
|
post_inbox_relayed_create(conn, params)
|
||||||
else
|
else
|
||||||
conn
|
conn
|
||||||
|> put_status(:bad_request)
|
|> put_status(403)
|
||||||
|> json("Not federating")
|
|> json("Not federating")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
89
lib/pleroma/web/plugs/inbox_guard_plug.ex
Normal file
89
lib/pleroma/web/plugs/inbox_guard_plug.ex
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
# Pleroma: A lightweight social networking server
|
||||||
|
# Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
|
||||||
|
# SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
|
defmodule Pleroma.Web.Plugs.InboxGuardPlug do
|
||||||
|
import Plug.Conn
|
||||||
|
import Pleroma.Constants, only: [activity_types: 0, allowed_activity_types_from_strangers: 0]
|
||||||
|
|
||||||
|
alias Pleroma.Config
|
||||||
|
alias Pleroma.User
|
||||||
|
|
||||||
|
def init(options) do
|
||||||
|
options
|
||||||
|
end
|
||||||
|
|
||||||
|
def call(%{assigns: %{valid_signature: true}} = conn, _opts) do
|
||||||
|
with {_, true} <- {:federating, Config.get!([:instance, :federating])} do
|
||||||
|
conn
|
||||||
|
|> filter_activity_types()
|
||||||
|
else
|
||||||
|
{:federating, false} ->
|
||||||
|
conn
|
||||||
|
|> json(403, "Not federating")
|
||||||
|
|> halt()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def call(conn, _opts) do
|
||||||
|
with {_, true} <- {:federating, Config.get!([:instance, :federating])},
|
||||||
|
conn = filter_activity_types(conn),
|
||||||
|
{:known, true} <- {:known, known_actor?(conn)} do
|
||||||
|
conn
|
||||||
|
else
|
||||||
|
{:federating, false} ->
|
||||||
|
conn
|
||||||
|
|> json(403, "Not federating")
|
||||||
|
|> halt()
|
||||||
|
|
||||||
|
{:known, false} ->
|
||||||
|
conn
|
||||||
|
|> filter_from_strangers()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# Early rejection of unrecognized types
|
||||||
|
defp filter_activity_types(%{body_params: %{"type" => type}} = conn) do
|
||||||
|
with true <- type in activity_types() do
|
||||||
|
conn
|
||||||
|
else
|
||||||
|
_ ->
|
||||||
|
conn
|
||||||
|
|> json(400, "Invalid activity type")
|
||||||
|
|> halt()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# If signature failed but we know this actor we should
|
||||||
|
# accept it as we may only need to refetch their public key
|
||||||
|
# during processing
|
||||||
|
defp known_actor?(%{body_params: data}) do
|
||||||
|
case Pleroma.Object.Containment.get_actor(data) |> User.get_cached_by_ap_id() do
|
||||||
|
%User{} -> true
|
||||||
|
_ -> false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# Only permit a subset of activity types from strangers
|
||||||
|
# or else it will add actors you've never interacted with
|
||||||
|
# to the database
|
||||||
|
defp filter_from_strangers(%{body_params: %{"type" => type}} = conn) do
|
||||||
|
with true <- type in allowed_activity_types_from_strangers() do
|
||||||
|
conn
|
||||||
|
else
|
||||||
|
_ ->
|
||||||
|
conn
|
||||||
|
|> json(400, "Invalid activity type for an unknown actor")
|
||||||
|
|> halt()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
defp json(conn, status, resp) do
|
||||||
|
json_resp = Jason.encode!(resp)
|
||||||
|
|
||||||
|
conn
|
||||||
|
|> put_resp_content_type("application/json")
|
||||||
|
|> resp(status, json_resp)
|
||||||
|
|> halt()
|
||||||
|
end
|
||||||
|
end
|
@ -217,6 +217,10 @@ defmodule Pleroma.Web.Router do
|
|||||||
plug(Pleroma.Web.Plugs.MappedSignatureToIdentityPlug)
|
plug(Pleroma.Web.Plugs.MappedSignatureToIdentityPlug)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
pipeline :inbox_guard do
|
||||||
|
plug(Pleroma.Web.Plugs.InboxGuardPlug)
|
||||||
|
end
|
||||||
|
|
||||||
pipeline :static_fe do
|
pipeline :static_fe do
|
||||||
plug(Pleroma.Web.Plugs.StaticFEPlug)
|
plug(Pleroma.Web.Plugs.StaticFEPlug)
|
||||||
end
|
end
|
||||||
@ -920,7 +924,7 @@ defmodule Pleroma.Web.Router do
|
|||||||
end
|
end
|
||||||
|
|
||||||
scope "/", Pleroma.Web.ActivityPub do
|
scope "/", Pleroma.Web.ActivityPub do
|
||||||
pipe_through(:activitypub)
|
pipe_through([:activitypub, :inbox_guard])
|
||||||
post("/inbox", ActivityPubController, :inbox)
|
post("/inbox", ActivityPubController, :inbox)
|
||||||
post("/users/:nickname/inbox", ActivityPubController, :inbox)
|
post("/users/:nickname/inbox", ActivityPubController, :inbox)
|
||||||
end
|
end
|
||||||
|
@ -657,7 +657,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do
|
|||||||
end
|
end
|
||||||
|
|
||||||
test "without valid signature, " <>
|
test "without valid signature, " <>
|
||||||
"it only accepts Create activities and requires enabled federation",
|
"it accepts Create activities and requires enabled federation",
|
||||||
%{conn: conn} do
|
%{conn: conn} do
|
||||||
data = File.read!("test/fixtures/mastodon-post-activity.json") |> Jason.decode!()
|
data = File.read!("test/fixtures/mastodon-post-activity.json") |> Jason.decode!()
|
||||||
non_create_data = File.read!("test/fixtures/mastodon-announce.json") |> Jason.decode!()
|
non_create_data = File.read!("test/fixtures/mastodon-announce.json") |> Jason.decode!()
|
||||||
@ -684,6 +684,54 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do
|
|||||||
|> json_response(400)
|
|> json_response(400)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# When activity is delivered to the inbox and we cannot immediately verify signature
|
||||||
|
# we capture all the params and process it later in the Oban job.
|
||||||
|
# Once we begin processing it through Oban we risk fetching the actor to validate the
|
||||||
|
# activity which just leads to inserting a new user to process a Delete not relevant to us.
|
||||||
|
test "Activities of certain types from an unknown actor are discarded", %{conn: conn} do
|
||||||
|
example_bad_types =
|
||||||
|
Pleroma.Constants.activity_types() --
|
||||||
|
Pleroma.Constants.allowed_activity_types_from_strangers()
|
||||||
|
|
||||||
|
Enum.each(example_bad_types, fn bad_type ->
|
||||||
|
params =
|
||||||
|
%{
|
||||||
|
"type" => bad_type,
|
||||||
|
"actor" => "https://unknown.mastodon.instance/users/somebody"
|
||||||
|
}
|
||||||
|
|> Jason.encode!()
|
||||||
|
|
||||||
|
conn
|
||||||
|
|> assign(:valid_signature, false)
|
||||||
|
|> put_req_header("content-type", "application/activity+json")
|
||||||
|
|> post("/inbox", params)
|
||||||
|
|> json_response(400)
|
||||||
|
|
||||||
|
assert all_enqueued() == []
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
test "Unknown activity types are discarded", %{conn: conn} do
|
||||||
|
unknown_types = ["Poke", "Read", "Dazzle"]
|
||||||
|
|
||||||
|
Enum.each(unknown_types, fn bad_type ->
|
||||||
|
params =
|
||||||
|
%{
|
||||||
|
"type" => bad_type,
|
||||||
|
"actor" => "https://unknown.mastodon.instance/users/somebody"
|
||||||
|
}
|
||||||
|
|> Jason.encode!()
|
||||||
|
|
||||||
|
conn
|
||||||
|
|> assign(:valid_signature, true)
|
||||||
|
|> put_req_header("content-type", "application/activity+json")
|
||||||
|
|> post("/inbox", params)
|
||||||
|
|> json_response(400)
|
||||||
|
|
||||||
|
assert all_enqueued() == []
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
test "accepts Add/Remove activities", %{conn: conn} do
|
test "accepts Add/Remove activities", %{conn: conn} do
|
||||||
object_id = "c61d6733-e256-4fe1-ab13-1e369789423f"
|
object_id = "c61d6733-e256-4fe1-ab13-1e369789423f"
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user