Make sure remote Update activities can't affect local actors other than

Groups

Signed-off-by: Thomas Citharel <tcit@tcit.fr>
This commit is contained in:
Thomas Citharel 2022-04-20 11:33:13 +02:00
parent 4b869a6015
commit 00f4c0b02c
No known key found for this signature in database
GPG Key ID: A061B9DDE0CA0773
5 changed files with 54 additions and 18 deletions

View File

@ -28,7 +28,7 @@ defmodule Mobilizon.Federation.ActivityPub.Actions.Update do
Logger.debug("updating an activity") Logger.debug("updating an activity")
Logger.debug(inspect(args)) Logger.debug(inspect(args))
case Managable.update(old_entity, args, additional) do case Managable.update(old_entity, args, Map.put(additional, :local, local)) do
{:ok, entity, update_data} -> {:ok, entity, update_data} ->
{:ok, activity} = create_activity(update_data, local) {:ok, activity} = create_activity(update_data, local)
maybe_federate(activity) maybe_federate(activity)

View File

@ -407,6 +407,13 @@ defmodule Mobilizon.Federation.ActivityPub.Transmogrifier do
Actions.Update.update(old_actor, object_data, false, %{updater_actor: author}) do Actions.Update.update(old_actor, object_data, false, %{updater_actor: author}) do
{:ok, activity, new_actor} {:ok, activity, new_actor}
else else
{:error, :update_not_allowed} ->
Logger.warn("Activity tried to update an actor that's local or not a group",
activity: params
)
:error
e -> e ->
Sentry.capture_message("Error while handling an Update activity", Sentry.capture_message("Error while handling an Update activity",
extra: %{params: params} extra: %{params: params}

View File

@ -45,6 +45,8 @@ defmodule Mobilizon.Federation.ActivityPub.Types.Actors do
def update(%Actor{} = old_actor, args, additional) do def update(%Actor{} = old_actor, args, additional) do
updater_actor = Map.get(args, :updater_actor) || Map.get(additional, :updater_actor) updater_actor = Map.get(args, :updater_actor) || Map.get(additional, :updater_actor)
if Map.get(additional, :local, false) == true or not match?(%Actor{domain: nil}, old_actor) or
match?(%Actor{type: :Group}, old_actor) do
case Actors.update_actor(old_actor, args) do case Actors.update_actor(old_actor, args) do
{:ok, %Actor{} = new_actor} -> {:ok, %Actor{} = new_actor} ->
GroupActivity.insert_activity(new_actor, GroupActivity.insert_activity(new_actor,
@ -65,6 +67,9 @@ defmodule Mobilizon.Federation.ActivityPub.Types.Actors do
{:error, %Ecto.Changeset{} = err} -> {:error, %Ecto.Changeset{} = err} ->
{:error, err} {:error, err}
end end
else
{:error, :update_not_allowed}
end
end end
@public_ap "https://www.w3.org/ns/activitystreams#Public" @public_ap "https://www.w3.org/ns/activitystreams#Public"

View File

@ -195,7 +195,7 @@ defmodule Mobilizon.Federation.ActivityPubTest do
actor = insert(:actor) actor = insert(:actor)
actor_data = %{summary: @updated_actor_summary} actor_data = %{summary: @updated_actor_summary}
{:ok, update, _} = Actions.Update.update(actor, actor_data, false) {:ok, update, _} = Actions.Update.update(actor, actor_data, true)
assert update.data["actor"] == actor.url assert update.data["actor"] == actor.url
assert update.data["to"] == [@activity_pub_public_audience] assert update.data["to"] == [@activity_pub_public_audience]

View File

@ -3,12 +3,13 @@ defmodule Mobilizon.Federation.ActivityPub.Transmogrifier.UpdateTest do
use Oban.Testing, repo: Mobilizon.Storage.Repo use Oban.Testing, repo: Mobilizon.Storage.Repo
import Mobilizon.Factory import Mobilizon.Factory
import Mox import Mox
import ExUnit.CaptureLog
alias Mobilizon.{Actors, Events, Posts} alias Mobilizon.{Actors, Events, Posts}
alias Mobilizon.Actors.{Actor, Member} alias Mobilizon.Actors.{Actor, Member}
alias Mobilizon.Events.Event alias Mobilizon.Events.Event
alias Mobilizon.Posts.Post alias Mobilizon.Posts.Post
alias Mobilizon.Federation.ActivityPub.{Activity, Transmogrifier} alias Mobilizon.Federation.ActivityPub.{Activity, Relay, Transmogrifier}
alias Mobilizon.Federation.ActivityStream.Convertible alias Mobilizon.Federation.ActivityStream.Convertible
alias Mobilizon.Service.HTTP.ActivityPub.Mock alias Mobilizon.Service.HTTP.ActivityPub.Mock
@ -50,6 +51,29 @@ defmodule Mobilizon.Federation.ActivityPub.Transmogrifier.UpdateTest do
assert actor.summary == "<p>Some bio</p>" assert actor.summary == "<p>Some bio</p>"
end end
test "it fails for incoming update activies on local actors" do
%Actor{url: relay_actor_url} = Relay.get_actor()
update_data = File.read!("test/fixtures/mastodon-update.json") |> Jason.decode!()
object =
update_data["object"]
|> Map.put("actor", relay_actor_url)
|> Map.put("id", relay_actor_url)
update_data =
update_data
|> Map.put("actor", relay_actor_url)
|> Map.put("object", object)
assert capture_log([level: :warn], fn ->
:error = Transmogrifier.handle_incoming(update_data)
end) =~ "[warning] Activity tried to update an actor that's local or not a group"
{:ok, %Actor{keys: keys}} = Actors.get_actor_by_url(relay_actor_url)
assert Regex.match?(~r/BEGIN RSA PRIVATE KEY/, keys)
end
test "it works for incoming update activities on events" do test "it works for incoming update activities on events" do
data = File.read!("test/fixtures/mobilizon-post-activity.json") |> Jason.decode!() data = File.read!("test/fixtures/mobilizon-post-activity.json") |> Jason.decode!()