summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authortusooa <tusooa@kazv.moe>2024-10-15 20:03:20 -0400
committerLain Soykaf <lain@lain.com>2024-12-09 12:43:08 +0400
commitb51f5a84eb7e2f3acb2d7fed54213a9680983bce (patch)
treeba352253d491ea7b6700d99853a807e204556162 /lib
parent8c6b3d3ce6c01e4d3285fe5d370855507e11e814 (diff)
downloadpleroma-b51f5a84eb7e2f3acb2d7fed54213a9680983bce.tar.gz
pleroma-b51f5a84eb7e2f3acb2d7fed54213a9680983bce.zip
Verify a local Update sent through AP C2S so users can only update their own objects
Diffstat (limited to 'lib')
-rw-r--r--lib/pleroma/web/activity_pub/activity_pub_controller.ex2
-rw-r--r--lib/pleroma/web/activity_pub/object_validator.ex13
-rw-r--r--lib/pleroma/web/activity_pub/object_validators/update_validator.ex43
3 files changed, 47 insertions, 11 deletions
diff --git a/lib/pleroma/web/activity_pub/activity_pub_controller.ex b/lib/pleroma/web/activity_pub/activity_pub_controller.ex
index a08eda5f4..7ac0bbab4 100644
--- a/lib/pleroma/web/activity_pub/activity_pub_controller.ex
+++ b/lib/pleroma/web/activity_pub/activity_pub_controller.ex
@@ -482,7 +482,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubController do
|> put_status(:forbidden)
|> json(message)
- {:error, message} ->
+ {:error, message} when is_binary(message) ->
conn
|> put_status(:bad_request)
|> json(message)
diff --git a/lib/pleroma/web/activity_pub/object_validator.ex b/lib/pleroma/web/activity_pub/object_validator.ex
index 35774d410..c509890f6 100644
--- a/lib/pleroma/web/activity_pub/object_validator.ex
+++ b/lib/pleroma/web/activity_pub/object_validator.ex
@@ -169,7 +169,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidator do
meta = Keyword.put(meta, :object_data, object_data),
{:ok, update_activity} <-
update_activity
- |> UpdateValidator.cast_and_validate()
+ |> UpdateValidator.cast_and_validate(meta)
|> Ecto.Changeset.apply_action(:insert) do
update_activity = stringify_keys(update_activity)
{:ok, update_activity, meta}
@@ -177,7 +177,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidator do
{:local, _} ->
with {:ok, object} <-
update_activity
- |> UpdateValidator.cast_and_validate()
+ |> UpdateValidator.cast_and_validate(meta)
|> Ecto.Changeset.apply_action(:insert) do
object = stringify_keys(object)
{:ok, object, meta}
@@ -207,9 +207,16 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidator do
"Answer" -> AnswerValidator
end
+ cast_func =
+ if type == "Update" do
+ fn o -> validator.cast_and_validate(o, meta) end
+ else
+ fn o -> validator.cast_and_validate(o) end
+ end
+
with {:ok, object} <-
object
- |> validator.cast_and_validate()
+ |> cast_func.()
|> Ecto.Changeset.apply_action(:insert) do
object = stringify_keys(object)
{:ok, object, meta}
diff --git a/lib/pleroma/web/activity_pub/object_validators/update_validator.ex b/lib/pleroma/web/activity_pub/object_validators/update_validator.ex
index 1e940a400..aab90235f 100644
--- a/lib/pleroma/web/activity_pub/object_validators/update_validator.ex
+++ b/lib/pleroma/web/activity_pub/object_validators/update_validator.ex
@@ -6,6 +6,8 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.UpdateValidator do
use Ecto.Schema
alias Pleroma.EctoType.ActivityPub.ObjectValidators
+ alias Pleroma.Object
+ alias Pleroma.User
import Ecto.Changeset
import Pleroma.Web.ActivityPub.ObjectValidators.CommonValidations
@@ -31,23 +33,50 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.UpdateValidator do
|> cast(data, __schema__(:fields))
end
- defp validate_data(cng) do
+ defp validate_data(cng, meta) do
cng
|> validate_required([:id, :type, :actor, :to, :cc, :object])
|> validate_inclusion(:type, ["Update"])
|> validate_actor_presence()
- |> validate_updating_rights()
+ |> validate_updating_rights(meta)
end
- def cast_and_validate(data) do
+ def cast_and_validate(data, meta \\ []) do
data
|> cast_data
- |> validate_data
+ |> validate_data(meta)
end
- # For now we only support updating users, and here the rule is easy:
- # object id == actor id
- def validate_updating_rights(cng) do
+ def validate_updating_rights(cng, meta) do
+ if meta[:local] do
+ validate_updating_rights_local(cng)
+ else
+ validate_updating_rights_remote(cng)
+ end
+ end
+
+ # For local Updates, verify the actor can edit the object
+ def validate_updating_rights_local(cng) do
+ actor = get_field(cng, :actor)
+ updated_object = get_field(cng, :object)
+
+ if {:ok, actor} == ObjectValidators.ObjectID.cast(updated_object) do
+ cng
+ else
+ with %User{} = user <- User.get_cached_by_ap_id(actor),
+ {_, %Object{} = orig_object} <- {:object, Object.normalize(updated_object)},
+ :ok <- Object.authorize_access(orig_object, user) do
+ cng
+ else
+ _e ->
+ cng
+ |> add_error(:object, "Can't be updated by this actor")
+ end
+ end
+ end
+
+ # For remote Updates, verify the host is the same.
+ def validate_updating_rights_remote(cng) do
with actor = get_field(cng, :actor),
object = get_field(cng, :object),
{:ok, object_id} <- ObjectValidators.ObjectID.cast(object),