forked from AkkomaGang/akkoma
Merge branch 'update-validator' into 'develop'
Update validator See merge request pleroma/pleroma!2668
This commit is contained in:
commit
98af7b59e4
13 changed files with 363 additions and 278 deletions
|
@ -321,28 +321,6 @@ defp accept_or_reject(type, %{to: to, actor: actor, object: object} = params) do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@spec update(map()) :: {:ok, Activity.t()} | {:error, any()}
|
|
||||||
def update(%{to: to, cc: cc, actor: actor, object: object} = params) do
|
|
||||||
local = !(params[:local] == false)
|
|
||||||
activity_id = params[:activity_id]
|
|
||||||
|
|
||||||
data =
|
|
||||||
%{
|
|
||||||
"to" => to,
|
|
||||||
"cc" => cc,
|
|
||||||
"type" => "Update",
|
|
||||||
"actor" => actor,
|
|
||||||
"object" => object
|
|
||||||
}
|
|
||||||
|> Maps.put_if_present("id", activity_id)
|
|
||||||
|
|
||||||
with {:ok, activity} <- insert(data, local),
|
|
||||||
_ <- notify_and_stream(activity),
|
|
||||||
:ok <- maybe_federate(activity) do
|
|
||||||
{:ok, activity}
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
@spec follow(User.t(), User.t(), String.t() | nil, boolean(), keyword()) ::
|
@spec follow(User.t(), User.t(), String.t() | nil, boolean(), keyword()) ::
|
||||||
{:ok, Activity.t()} | {:error, any()}
|
{:ok, Activity.t()} | {:error, any()}
|
||||||
def follow(follower, followed, activity_id \\ nil, local \\ true, opts \\ []) do
|
def follow(follower, followed, activity_id \\ nil, local \\ true, opts \\ []) do
|
||||||
|
|
|
@ -123,6 +123,21 @@ def like(actor, object) do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Retricted to user updates for now, always public
|
||||||
|
@spec update(User.t(), Object.t()) :: {:ok, map(), keyword()}
|
||||||
|
def update(actor, object) do
|
||||||
|
to = [Pleroma.Constants.as_public(), actor.follower_address]
|
||||||
|
|
||||||
|
{:ok,
|
||||||
|
%{
|
||||||
|
"id" => Utils.generate_activity_id(),
|
||||||
|
"type" => "Update",
|
||||||
|
"actor" => actor.ap_id,
|
||||||
|
"object" => object,
|
||||||
|
"to" => to
|
||||||
|
}, []}
|
||||||
|
end
|
||||||
|
|
||||||
@spec announce(User.t(), Object.t(), keyword()) :: {:ok, map(), keyword()}
|
@spec announce(User.t(), Object.t(), keyword()) :: {:ok, map(), keyword()}
|
||||||
def announce(actor, object, options \\ []) do
|
def announce(actor, object, options \\ []) do
|
||||||
public? = Keyword.get(options, :public, false)
|
public? = Keyword.get(options, :public, false)
|
||||||
|
|
|
@ -19,10 +19,21 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidator do
|
||||||
alias Pleroma.Web.ActivityPub.ObjectValidators.EmojiReactValidator
|
alias Pleroma.Web.ActivityPub.ObjectValidators.EmojiReactValidator
|
||||||
alias Pleroma.Web.ActivityPub.ObjectValidators.LikeValidator
|
alias Pleroma.Web.ActivityPub.ObjectValidators.LikeValidator
|
||||||
alias Pleroma.Web.ActivityPub.ObjectValidators.UndoValidator
|
alias Pleroma.Web.ActivityPub.ObjectValidators.UndoValidator
|
||||||
|
alias Pleroma.Web.ActivityPub.ObjectValidators.UpdateValidator
|
||||||
|
|
||||||
@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" => "Update"} = update_activity, meta) do
|
||||||
|
with {:ok, update_activity} <-
|
||||||
|
update_activity
|
||||||
|
|> UpdateValidator.cast_and_validate()
|
||||||
|
|> Ecto.Changeset.apply_action(:insert) do
|
||||||
|
update_activity = stringify_keys(update_activity)
|
||||||
|
{:ok, update_activity, meta}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def validate(%{"type" => "Undo"} = object, meta) do
|
def validate(%{"type" => "Undo"} = object, meta) do
|
||||||
with {:ok, object} <-
|
with {:ok, object} <-
|
||||||
object
|
object
|
||||||
|
|
|
@ -0,0 +1,59 @@
|
||||||
|
# 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.UpdateValidator do
|
||||||
|
use Ecto.Schema
|
||||||
|
|
||||||
|
alias Pleroma.EctoType.ActivityPub.ObjectValidators
|
||||||
|
|
||||||
|
import Ecto.Changeset
|
||||||
|
import Pleroma.Web.ActivityPub.ObjectValidators.CommonValidations
|
||||||
|
|
||||||
|
@primary_key false
|
||||||
|
|
||||||
|
embedded_schema do
|
||||||
|
field(:id, ObjectValidators.ObjectID, primary_key: true)
|
||||||
|
field(:type, :string)
|
||||||
|
field(:actor, ObjectValidators.ObjectID)
|
||||||
|
field(:to, ObjectValidators.Recipients, default: [])
|
||||||
|
field(:cc, ObjectValidators.Recipients, default: [])
|
||||||
|
# In this case, we save the full object in this activity instead of just a
|
||||||
|
# reference, so we can always see what was actually changed by this.
|
||||||
|
field(:object, :map)
|
||||||
|
end
|
||||||
|
|
||||||
|
def cast_data(data) do
|
||||||
|
%__MODULE__{}
|
||||||
|
|> cast(data, __schema__(:fields))
|
||||||
|
end
|
||||||
|
|
||||||
|
def validate_data(cng) do
|
||||||
|
cng
|
||||||
|
|> validate_required([:id, :type, :actor, :to, :cc, :object])
|
||||||
|
|> validate_inclusion(:type, ["Update"])
|
||||||
|
|> validate_actor_presence()
|
||||||
|
|> validate_updating_rights()
|
||||||
|
end
|
||||||
|
|
||||||
|
def cast_and_validate(data) do
|
||||||
|
data
|
||||||
|
|> cast_data
|
||||||
|
|> validate_data
|
||||||
|
end
|
||||||
|
|
||||||
|
# For now we only support updating users, and here the rule is easy:
|
||||||
|
# object id == actor id
|
||||||
|
def validate_updating_rights(cng) do
|
||||||
|
with actor = get_field(cng, :actor),
|
||||||
|
object = get_field(cng, :object),
|
||||||
|
{:ok, object_id} <- ObjectValidators.ObjectID.cast(object),
|
||||||
|
true <- actor == object_id do
|
||||||
|
cng
|
||||||
|
else
|
||||||
|
_e ->
|
||||||
|
cng
|
||||||
|
|> add_error(:object, "Can't be updated by this actor")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -20,6 +20,26 @@ defmodule Pleroma.Web.ActivityPub.SideEffects do
|
||||||
|
|
||||||
def handle(object, meta \\ [])
|
def handle(object, meta \\ [])
|
||||||
|
|
||||||
|
# Tasks this handles:
|
||||||
|
# - Update the user
|
||||||
|
#
|
||||||
|
# For a local user, we also get a changeset with the full information, so we
|
||||||
|
# can update non-federating, non-activitypub settings as well.
|
||||||
|
def handle(%{data: %{"type" => "Update", "object" => updated_object}} = object, meta) do
|
||||||
|
if changeset = Keyword.get(meta, :user_update_changeset) do
|
||||||
|
changeset
|
||||||
|
|> User.update_and_set_cache()
|
||||||
|
else
|
||||||
|
{:ok, new_user_data} = ActivityPub.user_data_from_user_object(updated_object)
|
||||||
|
|
||||||
|
User.get_by_ap_id(updated_object["id"])
|
||||||
|
|> User.remote_user_changeset(new_user_data)
|
||||||
|
|> User.update_and_set_cache()
|
||||||
|
end
|
||||||
|
|
||||||
|
{:ok, object, meta}
|
||||||
|
end
|
||||||
|
|
||||||
# Tasks this handles:
|
# Tasks this handles:
|
||||||
# - Add like to object
|
# - Add like to object
|
||||||
# - Set up notification
|
# - Set up notification
|
||||||
|
|
|
@ -684,35 +684,12 @@ def handle_incoming(%{"type" => type} = data, _options)
|
||||||
end
|
end
|
||||||
|
|
||||||
def handle_incoming(
|
def handle_incoming(
|
||||||
%{"type" => "Update", "object" => %{"type" => object_type} = object, "actor" => actor_id} =
|
%{"type" => "Update"} = data,
|
||||||
data,
|
|
||||||
_options
|
_options
|
||||||
)
|
) do
|
||||||
when object_type in [
|
with {:ok, %User{}} <- ObjectValidator.fetch_actor(data),
|
||||||
"Person",
|
{:ok, activity, _} <- Pipeline.common_pipeline(data, local: false) do
|
||||||
"Application",
|
{:ok, activity}
|
||||||
"Service",
|
|
||||||
"Organization"
|
|
||||||
] do
|
|
||||||
with %User{ap_id: ^actor_id} = actor <- User.get_cached_by_ap_id(object["id"]) do
|
|
||||||
{:ok, new_user_data} = ActivityPub.user_data_from_user_object(object)
|
|
||||||
|
|
||||||
actor
|
|
||||||
|> User.remote_user_changeset(new_user_data)
|
|
||||||
|> User.update_and_set_cache()
|
|
||||||
|
|
||||||
ActivityPub.update(%{
|
|
||||||
local: false,
|
|
||||||
to: data["to"] || [],
|
|
||||||
cc: data["cc"] || [],
|
|
||||||
object: object,
|
|
||||||
actor: actor_id,
|
|
||||||
activity_id: data["id"]
|
|
||||||
})
|
|
||||||
else
|
|
||||||
e ->
|
|
||||||
Logger.error(e)
|
|
||||||
:error
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -20,6 +20,8 @@ defmodule Pleroma.Web.MastodonAPI.AccountController do
|
||||||
alias Pleroma.Plugs.RateLimiter
|
alias Pleroma.Plugs.RateLimiter
|
||||||
alias Pleroma.User
|
alias Pleroma.User
|
||||||
alias Pleroma.Web.ActivityPub.ActivityPub
|
alias Pleroma.Web.ActivityPub.ActivityPub
|
||||||
|
alias Pleroma.Web.ActivityPub.Builder
|
||||||
|
alias Pleroma.Web.ActivityPub.Pipeline
|
||||||
alias Pleroma.Web.CommonAPI
|
alias Pleroma.Web.CommonAPI
|
||||||
alias Pleroma.Web.MastodonAPI.ListView
|
alias Pleroma.Web.MastodonAPI.ListView
|
||||||
alias Pleroma.Web.MastodonAPI.MastodonAPI
|
alias Pleroma.Web.MastodonAPI.MastodonAPI
|
||||||
|
@ -182,34 +184,39 @@ def update_credentials(%{assigns: %{user: user}, body_params: params} = conn, _p
|
||||||
end)
|
end)
|
||||||
|> Maps.put_if_present(:actor_type, params[:actor_type])
|
|> Maps.put_if_present(:actor_type, params[:actor_type])
|
||||||
|
|
||||||
changeset = User.update_changeset(user, user_params)
|
# What happens here:
|
||||||
|
#
|
||||||
with {:ok, user} <- User.update_and_set_cache(changeset) do
|
# We want to update the user through the pipeline, but the ActivityPub
|
||||||
user
|
# update information is not quite enough for this, because this also
|
||||||
|> build_update_activity_params()
|
# contains local settings that don't federate and don't even appear
|
||||||
|> ActivityPub.update()
|
# in the Update activity.
|
||||||
|
#
|
||||||
render(conn, "show.json", user: user, for: user, with_pleroma_settings: true)
|
# So we first build the normal local changeset, then apply it to the
|
||||||
|
# user data, but don't persist it. With this, we generate the object
|
||||||
|
# data for our update activity. We feed this and the changeset as meta
|
||||||
|
# inforation into the pipeline, where they will be properly updated and
|
||||||
|
# federated.
|
||||||
|
with changeset <- User.update_changeset(user, user_params),
|
||||||
|
{:ok, unpersisted_user} <- Ecto.Changeset.apply_action(changeset, :update),
|
||||||
|
updated_object <-
|
||||||
|
Pleroma.Web.ActivityPub.UserView.render("user.json", user: user)
|
||||||
|
|> Map.delete("@context"),
|
||||||
|
{:ok, update_data, []} <- Builder.update(user, updated_object),
|
||||||
|
{:ok, _update, _} <-
|
||||||
|
Pipeline.common_pipeline(update_data,
|
||||||
|
local: true,
|
||||||
|
user_update_changeset: changeset
|
||||||
|
) do
|
||||||
|
render(conn, "show.json",
|
||||||
|
user: unpersisted_user,
|
||||||
|
for: unpersisted_user,
|
||||||
|
with_pleroma_settings: true
|
||||||
|
)
|
||||||
else
|
else
|
||||||
_e -> render_error(conn, :forbidden, "Invalid request")
|
_e -> render_error(conn, :forbidden, "Invalid request")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# Hotfix, handling will be redone with the pipeline
|
|
||||||
defp build_update_activity_params(user) do
|
|
||||||
object =
|
|
||||||
Pleroma.Web.ActivityPub.UserView.render("user.json", user: user)
|
|
||||||
|> Map.delete("@context")
|
|
||||||
|
|
||||||
%{
|
|
||||||
local: true,
|
|
||||||
to: [user.follower_address],
|
|
||||||
cc: [],
|
|
||||||
object: object,
|
|
||||||
actor: user.ap_id
|
|
||||||
}
|
|
||||||
end
|
|
||||||
|
|
||||||
defp normalize_fields_attributes(fields) do
|
defp normalize_fields_attributes(fields) do
|
||||||
if Enum.all?(fields, &is_tuple/1) do
|
if Enum.all?(fields, &is_tuple/1) do
|
||||||
Enum.map(fields, fn {_, v} -> v end)
|
Enum.map(fields, fn {_, v} -> v end)
|
||||||
|
|
|
@ -536,6 +536,7 @@ test "accept follow activity", %{conn: conn} do
|
||||||
assert_receive {:mix_shell, :info, ["relay.mastodon.host"]}
|
assert_receive {:mix_shell, :info, ["relay.mastodon.host"]}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@tag capture_log: true
|
||||||
test "without valid signature, " <>
|
test "without valid signature, " <>
|
||||||
"it only accepts Create activities and requires enabled federation",
|
"it only accepts Create activities and requires enabled federation",
|
||||||
%{conn: conn} do
|
%{conn: conn} do
|
||||||
|
@ -648,11 +649,14 @@ test "it accepts messages with bcc as string instead of array", %{conn: conn, da
|
||||||
test "it accepts announces with to as string instead of array", %{conn: conn} do
|
test "it accepts announces with to as string instead of array", %{conn: conn} do
|
||||||
user = insert(:user)
|
user = insert(:user)
|
||||||
|
|
||||||
|
{:ok, post} = CommonAPI.post(user, %{status: "hey"})
|
||||||
|
announcer = insert(:user, local: false)
|
||||||
|
|
||||||
data = %{
|
data = %{
|
||||||
"@context" => "https://www.w3.org/ns/activitystreams",
|
"@context" => "https://www.w3.org/ns/activitystreams",
|
||||||
"actor" => "http://mastodon.example.org/users/admin",
|
"actor" => announcer.ap_id,
|
||||||
"id" => "http://mastodon.example.org/users/admin/statuses/19512778738411822/activity",
|
"id" => "#{announcer.ap_id}/statuses/19512778738411822/activity",
|
||||||
"object" => "https://mastodon.social/users/emelie/statuses/101849165031453009",
|
"object" => post.data["object"],
|
||||||
"to" => "https://www.w3.org/ns/activitystreams#Public",
|
"to" => "https://www.w3.org/ns/activitystreams#Public",
|
||||||
"cc" => [user.ap_id],
|
"cc" => [user.ap_id],
|
||||||
"type" => "Announce"
|
"type" => "Announce"
|
||||||
|
|
|
@ -1092,52 +1092,6 @@ test "it filters broken threads" do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe "update" do
|
|
||||||
setup do: clear_config([:instance, :max_pinned_statuses])
|
|
||||||
|
|
||||||
test "it creates an update activity with the new user data" do
|
|
||||||
user = insert(:user)
|
|
||||||
{:ok, user} = User.ensure_keys_present(user)
|
|
||||||
user_data = Pleroma.Web.ActivityPub.UserView.render("user.json", %{user: user})
|
|
||||||
|
|
||||||
{:ok, update} =
|
|
||||||
ActivityPub.update(%{
|
|
||||||
actor: user_data["id"],
|
|
||||||
to: [user.follower_address],
|
|
||||||
cc: [],
|
|
||||||
object: user_data
|
|
||||||
})
|
|
||||||
|
|
||||||
assert update.data["actor"] == user.ap_id
|
|
||||||
assert update.data["to"] == [user.follower_address]
|
|
||||||
assert embedded_object = update.data["object"]
|
|
||||||
assert embedded_object["id"] == user_data["id"]
|
|
||||||
assert embedded_object["type"] == user_data["type"]
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
test "returned pinned statuses" do
|
|
||||||
Config.put([:instance, :max_pinned_statuses], 3)
|
|
||||||
user = insert(:user)
|
|
||||||
|
|
||||||
{:ok, activity_one} = CommonAPI.post(user, %{status: "HI!!!"})
|
|
||||||
{:ok, activity_two} = CommonAPI.post(user, %{status: "HI!!!"})
|
|
||||||
{:ok, activity_three} = CommonAPI.post(user, %{status: "HI!!!"})
|
|
||||||
|
|
||||||
CommonAPI.pin(activity_one.id, user)
|
|
||||||
user = refresh_record(user)
|
|
||||||
|
|
||||||
CommonAPI.pin(activity_two.id, user)
|
|
||||||
user = refresh_record(user)
|
|
||||||
|
|
||||||
CommonAPI.pin(activity_three.id, user)
|
|
||||||
user = refresh_record(user)
|
|
||||||
|
|
||||||
activities = ActivityPub.fetch_user_activities(user, nil, %{pinned: true})
|
|
||||||
|
|
||||||
assert 3 = length(activities)
|
|
||||||
end
|
|
||||||
|
|
||||||
describe "flag/1" do
|
describe "flag/1" do
|
||||||
setup do
|
setup do
|
||||||
reporter = insert(:user)
|
reporter = insert(:user)
|
||||||
|
|
|
@ -622,4 +622,36 @@ test "returns an error if the actor can't announce the object", %{
|
||||||
assert {:actor, {"can not announce this object publicly", []}} in cng.errors
|
assert {:actor, {"can not announce this object publicly", []}} in cng.errors
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe "updates" do
|
||||||
|
setup do
|
||||||
|
user = insert(:user)
|
||||||
|
|
||||||
|
object = %{
|
||||||
|
"id" => user.ap_id,
|
||||||
|
"name" => "A new name",
|
||||||
|
"summary" => "A new bio"
|
||||||
|
}
|
||||||
|
|
||||||
|
{:ok, valid_update, []} = Builder.update(user, object)
|
||||||
|
|
||||||
|
%{user: user, valid_update: valid_update}
|
||||||
|
end
|
||||||
|
|
||||||
|
test "validates a basic object", %{valid_update: valid_update} do
|
||||||
|
assert {:ok, _update, []} = ObjectValidator.validate(valid_update, [])
|
||||||
|
end
|
||||||
|
|
||||||
|
test "returns an error if the object can't be updated by the actor", %{
|
||||||
|
valid_update: valid_update
|
||||||
|
} do
|
||||||
|
other_user = insert(:user)
|
||||||
|
|
||||||
|
update =
|
||||||
|
valid_update
|
||||||
|
|> Map.put("actor", other_user.ap_id)
|
||||||
|
|
||||||
|
assert {:error, _cng} = ObjectValidator.validate(update, [])
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -64,6 +64,31 @@ test "it streams out notifications and streams" do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe "update users" do
|
||||||
|
setup do
|
||||||
|
user = insert(:user)
|
||||||
|
{:ok, update_data, []} = Builder.update(user, %{"id" => user.ap_id, "name" => "new name!"})
|
||||||
|
{:ok, update, _meta} = ActivityPub.persist(update_data, local: true)
|
||||||
|
|
||||||
|
%{user: user, update_data: update_data, update: update}
|
||||||
|
end
|
||||||
|
|
||||||
|
test "it updates the user", %{user: user, update: update} do
|
||||||
|
{:ok, _, _} = SideEffects.handle(update)
|
||||||
|
user = User.get_by_id(user.id)
|
||||||
|
assert user.name == "new name!"
|
||||||
|
end
|
||||||
|
|
||||||
|
test "it uses a given changeset to update", %{user: user, update: update} do
|
||||||
|
changeset = Ecto.Changeset.change(user, %{default_scope: "direct"})
|
||||||
|
|
||||||
|
assert user.default_scope == "public"
|
||||||
|
{:ok, _, _} = SideEffects.handle(update, user_update_changeset: changeset)
|
||||||
|
user = User.get_by_id(user.id)
|
||||||
|
assert user.default_scope == "direct"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
describe "delete objects" do
|
describe "delete objects" do
|
||||||
setup do
|
setup do
|
||||||
user = insert(:user)
|
user = insert(:user)
|
||||||
|
|
|
@ -0,0 +1,159 @@
|
||||||
|
# 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.Transmogrifier.UserUpdateHandlingTest do
|
||||||
|
use Pleroma.DataCase
|
||||||
|
|
||||||
|
alias Pleroma.Activity
|
||||||
|
alias Pleroma.User
|
||||||
|
alias Pleroma.Web.ActivityPub.Transmogrifier
|
||||||
|
|
||||||
|
import Pleroma.Factory
|
||||||
|
|
||||||
|
test "it works for incoming update activities" do
|
||||||
|
user = insert(:user, local: false)
|
||||||
|
|
||||||
|
update_data = File.read!("test/fixtures/mastodon-update.json") |> Poison.decode!()
|
||||||
|
|
||||||
|
object =
|
||||||
|
update_data["object"]
|
||||||
|
|> Map.put("actor", user.ap_id)
|
||||||
|
|> Map.put("id", user.ap_id)
|
||||||
|
|
||||||
|
update_data =
|
||||||
|
update_data
|
||||||
|
|> Map.put("actor", user.ap_id)
|
||||||
|
|> Map.put("object", object)
|
||||||
|
|
||||||
|
{:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(update_data)
|
||||||
|
|
||||||
|
assert data["id"] == update_data["id"]
|
||||||
|
|
||||||
|
user = User.get_cached_by_ap_id(data["actor"])
|
||||||
|
assert user.name == "gargle"
|
||||||
|
|
||||||
|
assert user.avatar["url"] == [
|
||||||
|
%{
|
||||||
|
"href" =>
|
||||||
|
"https://cd.niu.moe/accounts/avatars/000/033/323/original/fd7f8ae0b3ffedc9.jpeg"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
assert user.banner["url"] == [
|
||||||
|
%{
|
||||||
|
"href" =>
|
||||||
|
"https://cd.niu.moe/accounts/headers/000/033/323/original/850b3448fa5fd477.png"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
assert user.bio == "<p>Some bio</p>"
|
||||||
|
end
|
||||||
|
|
||||||
|
test "it works with alsoKnownAs" do
|
||||||
|
%{ap_id: actor} = insert(:user, local: false)
|
||||||
|
|
||||||
|
assert User.get_cached_by_ap_id(actor).also_known_as == []
|
||||||
|
|
||||||
|
{:ok, _activity} =
|
||||||
|
"test/fixtures/mastodon-update.json"
|
||||||
|
|> File.read!()
|
||||||
|
|> Poison.decode!()
|
||||||
|
|> Map.put("actor", actor)
|
||||||
|
|> Map.update!("object", fn object ->
|
||||||
|
object
|
||||||
|
|> Map.put("actor", actor)
|
||||||
|
|> Map.put("id", actor)
|
||||||
|
|> Map.put("alsoKnownAs", [
|
||||||
|
"http://mastodon.example.org/users/foo",
|
||||||
|
"http://example.org/users/bar"
|
||||||
|
])
|
||||||
|
end)
|
||||||
|
|> Transmogrifier.handle_incoming()
|
||||||
|
|
||||||
|
assert User.get_cached_by_ap_id(actor).also_known_as == [
|
||||||
|
"http://mastodon.example.org/users/foo",
|
||||||
|
"http://example.org/users/bar"
|
||||||
|
]
|
||||||
|
end
|
||||||
|
|
||||||
|
test "it works with custom profile fields" do
|
||||||
|
user = insert(:user, local: false)
|
||||||
|
|
||||||
|
assert user.fields == []
|
||||||
|
|
||||||
|
update_data = File.read!("test/fixtures/mastodon-update.json") |> Poison.decode!()
|
||||||
|
|
||||||
|
object =
|
||||||
|
update_data["object"]
|
||||||
|
|> Map.put("actor", user.ap_id)
|
||||||
|
|> Map.put("id", user.ap_id)
|
||||||
|
|
||||||
|
update_data =
|
||||||
|
update_data
|
||||||
|
|> Map.put("actor", user.ap_id)
|
||||||
|
|> Map.put("object", object)
|
||||||
|
|
||||||
|
{:ok, _update_activity} = Transmogrifier.handle_incoming(update_data)
|
||||||
|
|
||||||
|
user = User.get_cached_by_ap_id(user.ap_id)
|
||||||
|
|
||||||
|
assert user.fields == [
|
||||||
|
%{"name" => "foo", "value" => "updated"},
|
||||||
|
%{"name" => "foo1", "value" => "updated"}
|
||||||
|
]
|
||||||
|
|
||||||
|
Pleroma.Config.put([:instance, :max_remote_account_fields], 2)
|
||||||
|
|
||||||
|
update_data =
|
||||||
|
update_data
|
||||||
|
|> put_in(["object", "attachment"], [
|
||||||
|
%{"name" => "foo", "type" => "PropertyValue", "value" => "bar"},
|
||||||
|
%{"name" => "foo11", "type" => "PropertyValue", "value" => "bar11"},
|
||||||
|
%{"name" => "foo22", "type" => "PropertyValue", "value" => "bar22"}
|
||||||
|
])
|
||||||
|
|> Map.put("id", update_data["id"] <> ".")
|
||||||
|
|
||||||
|
{:ok, _} = Transmogrifier.handle_incoming(update_data)
|
||||||
|
|
||||||
|
user = User.get_cached_by_ap_id(user.ap_id)
|
||||||
|
|
||||||
|
assert user.fields == [
|
||||||
|
%{"name" => "foo", "value" => "updated"},
|
||||||
|
%{"name" => "foo1", "value" => "updated"}
|
||||||
|
]
|
||||||
|
|
||||||
|
update_data =
|
||||||
|
update_data
|
||||||
|
|> put_in(["object", "attachment"], [])
|
||||||
|
|> Map.put("id", update_data["id"] <> ".")
|
||||||
|
|
||||||
|
{:ok, _} = Transmogrifier.handle_incoming(update_data)
|
||||||
|
|
||||||
|
user = User.get_cached_by_ap_id(user.ap_id)
|
||||||
|
|
||||||
|
assert user.fields == []
|
||||||
|
end
|
||||||
|
|
||||||
|
test "it works for incoming update activities which lock the account" do
|
||||||
|
user = insert(:user, local: false)
|
||||||
|
|
||||||
|
update_data = File.read!("test/fixtures/mastodon-update.json") |> Poison.decode!()
|
||||||
|
|
||||||
|
object =
|
||||||
|
update_data["object"]
|
||||||
|
|> Map.put("actor", user.ap_id)
|
||||||
|
|> Map.put("id", user.ap_id)
|
||||||
|
|> Map.put("manuallyApprovesFollowers", true)
|
||||||
|
|
||||||
|
update_data =
|
||||||
|
update_data
|
||||||
|
|> Map.put("actor", user.ap_id)
|
||||||
|
|> Map.put("object", object)
|
||||||
|
|
||||||
|
{:ok, %Activity{local: false}} = Transmogrifier.handle_incoming(update_data)
|
||||||
|
|
||||||
|
user = User.get_cached_by_ap_id(user.ap_id)
|
||||||
|
assert user.locked == true
|
||||||
|
end
|
||||||
|
end
|
|
@ -401,162 +401,6 @@ test "it strips internal reactions" do
|
||||||
refute Map.has_key?(object_data, "reaction_count")
|
refute Map.has_key?(object_data, "reaction_count")
|
||||||
end
|
end
|
||||||
|
|
||||||
test "it works for incoming update activities" do
|
|
||||||
data = File.read!("test/fixtures/mastodon-post-activity.json") |> Poison.decode!()
|
|
||||||
|
|
||||||
{:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
|
|
||||||
update_data = File.read!("test/fixtures/mastodon-update.json") |> Poison.decode!()
|
|
||||||
|
|
||||||
object =
|
|
||||||
update_data["object"]
|
|
||||||
|> Map.put("actor", data["actor"])
|
|
||||||
|> Map.put("id", data["actor"])
|
|
||||||
|
|
||||||
update_data =
|
|
||||||
update_data
|
|
||||||
|> Map.put("actor", data["actor"])
|
|
||||||
|> Map.put("object", object)
|
|
||||||
|
|
||||||
{:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(update_data)
|
|
||||||
|
|
||||||
assert data["id"] == update_data["id"]
|
|
||||||
|
|
||||||
user = User.get_cached_by_ap_id(data["actor"])
|
|
||||||
assert user.name == "gargle"
|
|
||||||
|
|
||||||
assert user.avatar["url"] == [
|
|
||||||
%{
|
|
||||||
"href" =>
|
|
||||||
"https://cd.niu.moe/accounts/avatars/000/033/323/original/fd7f8ae0b3ffedc9.jpeg"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
|
|
||||||
assert user.banner["url"] == [
|
|
||||||
%{
|
|
||||||
"href" =>
|
|
||||||
"https://cd.niu.moe/accounts/headers/000/033/323/original/850b3448fa5fd477.png"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
|
|
||||||
assert user.bio == "<p>Some bio</p>"
|
|
||||||
end
|
|
||||||
|
|
||||||
test "it works with alsoKnownAs" do
|
|
||||||
{:ok, %Activity{data: %{"actor" => actor}}} =
|
|
||||||
"test/fixtures/mastodon-post-activity.json"
|
|
||||||
|> File.read!()
|
|
||||||
|> Poison.decode!()
|
|
||||||
|> Transmogrifier.handle_incoming()
|
|
||||||
|
|
||||||
assert User.get_cached_by_ap_id(actor).also_known_as == ["http://example.org/users/foo"]
|
|
||||||
|
|
||||||
{:ok, _activity} =
|
|
||||||
"test/fixtures/mastodon-update.json"
|
|
||||||
|> File.read!()
|
|
||||||
|> Poison.decode!()
|
|
||||||
|> Map.put("actor", actor)
|
|
||||||
|> Map.update!("object", fn object ->
|
|
||||||
object
|
|
||||||
|> Map.put("actor", actor)
|
|
||||||
|> Map.put("id", actor)
|
|
||||||
|> Map.put("alsoKnownAs", [
|
|
||||||
"http://mastodon.example.org/users/foo",
|
|
||||||
"http://example.org/users/bar"
|
|
||||||
])
|
|
||||||
end)
|
|
||||||
|> Transmogrifier.handle_incoming()
|
|
||||||
|
|
||||||
assert User.get_cached_by_ap_id(actor).also_known_as == [
|
|
||||||
"http://mastodon.example.org/users/foo",
|
|
||||||
"http://example.org/users/bar"
|
|
||||||
]
|
|
||||||
end
|
|
||||||
|
|
||||||
test "it works with custom profile fields" do
|
|
||||||
{:ok, activity} =
|
|
||||||
"test/fixtures/mastodon-post-activity.json"
|
|
||||||
|> File.read!()
|
|
||||||
|> Poison.decode!()
|
|
||||||
|> Transmogrifier.handle_incoming()
|
|
||||||
|
|
||||||
user = User.get_cached_by_ap_id(activity.actor)
|
|
||||||
|
|
||||||
assert user.fields == [
|
|
||||||
%{"name" => "foo", "value" => "bar"},
|
|
||||||
%{"name" => "foo1", "value" => "bar1"}
|
|
||||||
]
|
|
||||||
|
|
||||||
update_data = File.read!("test/fixtures/mastodon-update.json") |> Poison.decode!()
|
|
||||||
|
|
||||||
object =
|
|
||||||
update_data["object"]
|
|
||||||
|> Map.put("actor", user.ap_id)
|
|
||||||
|> Map.put("id", user.ap_id)
|
|
||||||
|
|
||||||
update_data =
|
|
||||||
update_data
|
|
||||||
|> Map.put("actor", user.ap_id)
|
|
||||||
|> Map.put("object", object)
|
|
||||||
|
|
||||||
{:ok, _update_activity} = Transmogrifier.handle_incoming(update_data)
|
|
||||||
|
|
||||||
user = User.get_cached_by_ap_id(user.ap_id)
|
|
||||||
|
|
||||||
assert user.fields == [
|
|
||||||
%{"name" => "foo", "value" => "updated"},
|
|
||||||
%{"name" => "foo1", "value" => "updated"}
|
|
||||||
]
|
|
||||||
|
|
||||||
Pleroma.Config.put([:instance, :max_remote_account_fields], 2)
|
|
||||||
|
|
||||||
update_data =
|
|
||||||
put_in(update_data, ["object", "attachment"], [
|
|
||||||
%{"name" => "foo", "type" => "PropertyValue", "value" => "bar"},
|
|
||||||
%{"name" => "foo11", "type" => "PropertyValue", "value" => "bar11"},
|
|
||||||
%{"name" => "foo22", "type" => "PropertyValue", "value" => "bar22"}
|
|
||||||
])
|
|
||||||
|
|
||||||
{:ok, _} = Transmogrifier.handle_incoming(update_data)
|
|
||||||
|
|
||||||
user = User.get_cached_by_ap_id(user.ap_id)
|
|
||||||
|
|
||||||
assert user.fields == [
|
|
||||||
%{"name" => "foo", "value" => "updated"},
|
|
||||||
%{"name" => "foo1", "value" => "updated"}
|
|
||||||
]
|
|
||||||
|
|
||||||
update_data = put_in(update_data, ["object", "attachment"], [])
|
|
||||||
|
|
||||||
{:ok, _} = Transmogrifier.handle_incoming(update_data)
|
|
||||||
|
|
||||||
user = User.get_cached_by_ap_id(user.ap_id)
|
|
||||||
|
|
||||||
assert user.fields == []
|
|
||||||
end
|
|
||||||
|
|
||||||
test "it works for incoming update activities which lock the account" do
|
|
||||||
data = File.read!("test/fixtures/mastodon-post-activity.json") |> Poison.decode!()
|
|
||||||
|
|
||||||
{:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
|
|
||||||
update_data = File.read!("test/fixtures/mastodon-update.json") |> Poison.decode!()
|
|
||||||
|
|
||||||
object =
|
|
||||||
update_data["object"]
|
|
||||||
|> Map.put("actor", data["actor"])
|
|
||||||
|> Map.put("id", data["actor"])
|
|
||||||
|> Map.put("manuallyApprovesFollowers", true)
|
|
||||||
|
|
||||||
update_data =
|
|
||||||
update_data
|
|
||||||
|> Map.put("actor", data["actor"])
|
|
||||||
|> Map.put("object", object)
|
|
||||||
|
|
||||||
{:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(update_data)
|
|
||||||
|
|
||||||
user = User.get_cached_by_ap_id(data["actor"])
|
|
||||||
assert user.locked == true
|
|
||||||
end
|
|
||||||
|
|
||||||
test "it works for incomming unfollows with an existing follow" do
|
test "it works for incomming unfollows with an existing follow" do
|
||||||
user = insert(:user)
|
user = insert(:user)
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue