summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorlain <lain@soykaf.club>2020-05-05 14:17:47 +0200
committerlain <lain@soykaf.club>2020-05-05 14:17:47 +0200
commitf1da8882f971f932b65f655b6457759387dafe51 (patch)
tree25a5cd5a2fa27bafc0d75bda972ca951ee8c56ab
parent8b2457bdbf8791923701b0b015f6ddf2e7c89bf7 (diff)
UndoValidator: Add UndoValidator.
-rw-r--r--lib/pleroma/web/activity_pub/builder.ex13
-rw-r--r--lib/pleroma/web/activity_pub/object_validator.ex9
-rw-r--r--lib/pleroma/web/activity_pub/object_validators/common_validations.ex3
-rw-r--r--lib/pleroma/web/activity_pub/object_validators/undo_validator.ex62
-rw-r--r--test/web/activity_pub/object_validator_test.exs41
5 files changed, 127 insertions, 1 deletions
diff --git a/lib/pleroma/web/activity_pub/builder.ex b/lib/pleroma/web/activity_pub/builder.ex
index 429a510b8..380d8f565 100644
--- a/lib/pleroma/web/activity_pub/builder.ex
+++ b/lib/pleroma/web/activity_pub/builder.ex
@@ -10,6 +10,19 @@ defmodule Pleroma.Web.ActivityPub.Builder do
alias Pleroma.Web.ActivityPub.Utils
alias Pleroma.Web.ActivityPub.Visibility
+ @spec undo(User.t(), Activity.t()) :: {:ok, map(), keyword()}
+ def undo(actor, object) do
+ {:ok,
+ %{
+ "id" => Utils.generate_activity_id(),
+ "actor" => actor.ap_id,
+ "type" => "Undo",
+ "object" => object.data["id"],
+ "to" => object.data["to"] || [],
+ "cc" => object.data["cc"] || []
+ }, []}
+ end
+
@spec like(User.t(), Object.t()) :: {:ok, map(), keyword()}
def like(actor, object) do
object_actor = User.get_cached_by_ap_id(object.data["actor"])
diff --git a/lib/pleroma/web/activity_pub/object_validator.ex b/lib/pleroma/web/activity_pub/object_validator.ex
index dc4bce059..b6937d2e1 100644
--- a/lib/pleroma/web/activity_pub/object_validator.ex
+++ b/lib/pleroma/web/activity_pub/object_validator.ex
@@ -12,10 +12,19 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidator do
alias Pleroma.Object
alias Pleroma.User
alias Pleroma.Web.ActivityPub.ObjectValidators.LikeValidator
+ alias Pleroma.Web.ActivityPub.ObjectValidators.UndoValidator
@spec validate(map(), keyword()) :: {:ok, map(), keyword()} | {:error, any()}
def validate(object, meta)
+ def validate(%{"type" => "Undo"} = object, meta) do
+ with {:ok, object} <-
+ object |> UndoValidator.cast_and_validate() |> Ecto.Changeset.apply_action(:insert) do
+ object = stringify_keys(object |> Map.from_struct())
+ {:ok, object, meta}
+ end
+ end
+
def validate(%{"type" => "Like"} = object, meta) do
with {:ok, object} <-
object |> LikeValidator.cast_and_validate() |> Ecto.Changeset.apply_action(:insert) do
diff --git a/lib/pleroma/web/activity_pub/object_validators/common_validations.ex b/lib/pleroma/web/activity_pub/object_validators/common_validations.ex
index b479c3918..067ee4f9a 100644
--- a/lib/pleroma/web/activity_pub/object_validators/common_validations.ex
+++ b/lib/pleroma/web/activity_pub/object_validators/common_validations.ex
@@ -5,6 +5,7 @@
defmodule Pleroma.Web.ActivityPub.ObjectValidators.CommonValidations do
import Ecto.Changeset
+ alias Pleroma.Activity
alias Pleroma.Object
alias Pleroma.User
@@ -22,7 +23,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.CommonValidations do
def validate_object_presence(cng, field_name \\ :object) do
cng
|> validate_change(field_name, fn field_name, object ->
- if Object.get_cached_by_ap_id(object) do
+ if Object.get_cached_by_ap_id(object) || Activity.get_by_ap_id(object) do
[]
else
[{field_name, "can't find object"}]
diff --git a/lib/pleroma/web/activity_pub/object_validators/undo_validator.ex b/lib/pleroma/web/activity_pub/object_validators/undo_validator.ex
new file mode 100644
index 000000000..d0ba418e8
--- /dev/null
+++ b/lib/pleroma/web/activity_pub/object_validators/undo_validator.ex
@@ -0,0 +1,62 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.ActivityPub.ObjectValidators.UndoValidator do
+ use Ecto.Schema
+
+ alias Pleroma.Activity
+ alias Pleroma.Web.ActivityPub.ObjectValidators.Types
+
+ import Ecto.Changeset
+ import Pleroma.Web.ActivityPub.ObjectValidators.CommonValidations
+
+ @primary_key false
+
+ embedded_schema do
+ field(:id, Types.ObjectID, primary_key: true)
+ field(:type, :string)
+ field(:object, Types.ObjectID)
+ field(:actor, Types.ObjectID)
+ field(:to, {:array, :string}, default: [])
+ field(:cc, {:array, :string}, default: [])
+ end
+
+ def cast_and_validate(data) do
+ data
+ |> cast_data()
+ |> validate_data()
+ end
+
+ def cast_data(data) do
+ %__MODULE__{}
+ |> changeset(data)
+ end
+
+ def changeset(struct, data) do
+ struct
+ |> cast(data, __schema__(:fields))
+ end
+
+ def validate_data(data_cng) do
+ data_cng
+ |> validate_inclusion(:type, ["Undo"])
+ |> validate_required([:id, :type, :object, :actor, :to, :cc])
+ |> validate_actor_presence()
+ |> validate_object_presence()
+ |> validate_undo_rights()
+ end
+
+ def validate_undo_rights(cng) do
+ actor = get_field(cng, :actor)
+ object = get_field(cng, :object)
+
+ with %Activity{data: %{"actor" => object_actor}} <- Activity.get_by_ap_id(object),
+ true <- object_actor != actor do
+ cng
+ |> add_error(:actor, "not the same as object actor")
+ else
+ _ -> cng
+ end
+ end
+end
diff --git a/test/web/activity_pub/object_validator_test.exs b/test/web/activity_pub/object_validator_test.exs
index 93989e28a..8626e127e 100644
--- a/test/web/activity_pub/object_validator_test.exs
+++ b/test/web/activity_pub/object_validator_test.exs
@@ -1,6 +1,7 @@
defmodule Pleroma.Web.ActivityPub.ObjectValidatorTest do
use Pleroma.DataCase
+ alias Pleroma.Web.ActivityPub.Builder
alias Pleroma.Web.ActivityPub.ObjectValidator
alias Pleroma.Web.ActivityPub.ObjectValidators.LikeValidator
alias Pleroma.Web.ActivityPub.Utils
@@ -8,6 +9,46 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidatorTest do
import Pleroma.Factory
+ describe "Undos" do
+ setup do
+ user = insert(:user)
+ {:ok, post_activity} = CommonAPI.post(user, %{"status" => "uguu"})
+ {:ok, like} = CommonAPI.favorite(user, post_activity.id)
+ {:ok, valid_like_undo, []} = Builder.undo(user, like)
+
+ %{user: user, like: like, valid_like_undo: valid_like_undo}
+ end
+
+ test "it validates a basic like undo", %{valid_like_undo: valid_like_undo} do
+ assert {:ok, _, _} = ObjectValidator.validate(valid_like_undo, [])
+ end
+
+ test "it does not validate if the actor of the undo is not the actor of the object", %{
+ valid_like_undo: valid_like_undo
+ } do
+ other_user = insert(:user, ap_id: "https://gensokyo.2hu/users/raymoo")
+
+ bad_actor =
+ valid_like_undo
+ |> Map.put("actor", other_user.ap_id)
+
+ {:error, cng} = ObjectValidator.validate(bad_actor, [])
+
+ assert {:actor, {"not the same as object actor", []}} in cng.errors
+ end
+
+ test "it does not validate if the object is missing", %{valid_like_undo: valid_like_undo} do
+ missing_object =
+ valid_like_undo
+ |> Map.put("object", "https://gensokyo.2hu/objects/1")
+
+ {:error, cng} = ObjectValidator.validate(missing_object, [])
+
+ assert {:object, {"can't find object", []}} in cng.errors
+ assert length(cng.errors) == 1
+ end
+ end
+
describe "likes" do
setup do
user = insert(:user)