forked from AkkomaGang/akkoma
UndoValidator: Add UndoValidator.
This commit is contained in:
parent
8b2457bdbf
commit
f1da8882f9
5 changed files with 127 additions and 1 deletions
|
@ -10,6 +10,19 @@ defmodule Pleroma.Web.ActivityPub.Builder do
|
||||||
alias Pleroma.Web.ActivityPub.Utils
|
alias Pleroma.Web.ActivityPub.Utils
|
||||||
alias Pleroma.Web.ActivityPub.Visibility
|
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()}
|
@spec like(User.t(), Object.t()) :: {:ok, map(), keyword()}
|
||||||
def like(actor, object) do
|
def like(actor, object) do
|
||||||
object_actor = User.get_cached_by_ap_id(object.data["actor"])
|
object_actor = User.get_cached_by_ap_id(object.data["actor"])
|
||||||
|
|
|
@ -12,10 +12,19 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidator do
|
||||||
alias Pleroma.Object
|
alias Pleroma.Object
|
||||||
alias Pleroma.User
|
alias Pleroma.User
|
||||||
alias Pleroma.Web.ActivityPub.ObjectValidators.LikeValidator
|
alias Pleroma.Web.ActivityPub.ObjectValidators.LikeValidator
|
||||||
|
alias Pleroma.Web.ActivityPub.ObjectValidators.UndoValidator
|
||||||
|
|
||||||
@spec validate(map(), keyword()) :: {:ok, map(), keyword()} | {:error, any()}
|
@spec validate(map(), keyword()) :: {:ok, map(), keyword()} | {:error, any()}
|
||||||
def validate(object, meta)
|
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
|
def validate(%{"type" => "Like"} = object, meta) do
|
||||||
with {:ok, object} <-
|
with {:ok, object} <-
|
||||||
object |> LikeValidator.cast_and_validate() |> Ecto.Changeset.apply_action(:insert) do
|
object |> LikeValidator.cast_and_validate() |> Ecto.Changeset.apply_action(:insert) do
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
defmodule Pleroma.Web.ActivityPub.ObjectValidators.CommonValidations do
|
defmodule Pleroma.Web.ActivityPub.ObjectValidators.CommonValidations do
|
||||||
import Ecto.Changeset
|
import Ecto.Changeset
|
||||||
|
|
||||||
|
alias Pleroma.Activity
|
||||||
alias Pleroma.Object
|
alias Pleroma.Object
|
||||||
alias Pleroma.User
|
alias Pleroma.User
|
||||||
|
|
||||||
|
@ -22,7 +23,7 @@ def validate_actor_presence(cng, field_name \\ :actor) do
|
||||||
def validate_object_presence(cng, field_name \\ :object) do
|
def validate_object_presence(cng, field_name \\ :object) do
|
||||||
cng
|
cng
|
||||||
|> validate_change(field_name, fn field_name, object ->
|
|> 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
|
else
|
||||||
[{field_name, "can't find object"}]
|
[{field_name, "can't find object"}]
|
||||||
|
|
|
@ -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
|
|
@ -1,6 +1,7 @@
|
||||||
defmodule Pleroma.Web.ActivityPub.ObjectValidatorTest do
|
defmodule Pleroma.Web.ActivityPub.ObjectValidatorTest do
|
||||||
use Pleroma.DataCase
|
use Pleroma.DataCase
|
||||||
|
|
||||||
|
alias Pleroma.Web.ActivityPub.Builder
|
||||||
alias Pleroma.Web.ActivityPub.ObjectValidator
|
alias Pleroma.Web.ActivityPub.ObjectValidator
|
||||||
alias Pleroma.Web.ActivityPub.ObjectValidators.LikeValidator
|
alias Pleroma.Web.ActivityPub.ObjectValidators.LikeValidator
|
||||||
alias Pleroma.Web.ActivityPub.Utils
|
alias Pleroma.Web.ActivityPub.Utils
|
||||||
|
@ -8,6 +9,46 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidatorTest do
|
||||||
|
|
||||||
import Pleroma.Factory
|
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
|
describe "likes" do
|
||||||
setup do
|
setup do
|
||||||
user = insert(:user)
|
user = insert(:user)
|
||||||
|
|
Loading…
Reference in a new issue