diff --git a/changelog.d/pipeline-local-create.skip b/changelog.d/pipeline-local-create.skip new file mode 100644 index 000000000..e69de29bb diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex index 2017c696d..ea3a7e090 100644 --- a/lib/pleroma/web/activity_pub/activity_pub.ex +++ b/lib/pleroma/web/activity_pub/activity_pub.ex @@ -231,6 +231,20 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do end end + defp maybe_create_activity_expiration(%{data: %{"expires_at" => expires_at}} = activity) when is_bitstring(expires_at) do + with {_, {:ok, expires_at, _}} <- {:datetime, DateTime.from_iso8601(expires_at)}, + {:ok, _job} <- + Pleroma.Workers.PurgeExpiredActivity.enqueue(%{ + activity_id: activity.id, + expires_at: expires_at + }) do + {:ok, activity} + else + {:datetime, _} -> {:ok, activity} + e -> e + end + end + defp maybe_create_activity_expiration(activity), do: {:ok, activity} defp create_or_bump_conversation(activity, actor) do diff --git a/lib/pleroma/web/activity_pub/builder.ex b/lib/pleroma/web/activity_pub/builder.ex index 2a1e56278..4078980b5 100644 --- a/lib/pleroma/web/activity_pub/builder.ex +++ b/lib/pleroma/web/activity_pub/builder.ex @@ -207,6 +207,7 @@ defmodule Pleroma.Web.ActivityPub.Builder do data = %{ "type" => "Note", + "id" => Utils.generate_object_id(), "to" => draft.to, "cc" => draft.cc, "content" => draft.content_html, diff --git a/lib/pleroma/web/activity_pub/object_validator.ex b/lib/pleroma/web/activity_pub/object_validator.ex index b3043b93a..61ac1e9a2 100644 --- a/lib/pleroma/web/activity_pub/object_validator.ex +++ b/lib/pleroma/web/activity_pub/object_validator.ex @@ -132,7 +132,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidator do do_separate_with_history(object, fn object -> with {:ok, object} <- object - |> validator.cast_and_validate() + |> validator.cast_and_validate(meta) |> Ecto.Changeset.apply_action(:insert) do object = stringify_keys(object) diff --git a/lib/pleroma/web/activity_pub/object_validators/accept_reject_validator.ex b/lib/pleroma/web/activity_pub/object_validators/accept_reject_validator.ex index d611da051..4aa31c7b6 100644 --- a/lib/pleroma/web/activity_pub/object_validators/accept_reject_validator.ex +++ b/lib/pleroma/web/activity_pub/object_validators/accept_reject_validator.ex @@ -36,7 +36,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.AcceptRejectValidator do |> validate_accept_reject_rights() end - def cast_and_validate(data) do + def cast_and_validate(data, _meta \\ []) do data |> cast_data |> validate_data diff --git a/lib/pleroma/web/activity_pub/object_validators/add_remove_validator.ex b/lib/pleroma/web/activity_pub/object_validators/add_remove_validator.ex index db3259550..70b405201 100644 --- a/lib/pleroma/web/activity_pub/object_validators/add_remove_validator.ex +++ b/lib/pleroma/web/activity_pub/object_validators/add_remove_validator.ex @@ -26,7 +26,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.AddRemoveValidator do end end - def cast_and_validate(data) do + def cast_and_validate(data, _meta \\ []) do {:ok, actor} = User.get_or_fetch_by_ap_id(data["actor"]) {:ok, actor} = maybe_refetch_user(actor) diff --git a/lib/pleroma/web/activity_pub/object_validators/announce_validator.ex b/lib/pleroma/web/activity_pub/object_validators/announce_validator.ex index d0218583e..2650a279a 100644 --- a/lib/pleroma/web/activity_pub/object_validators/announce_validator.ex +++ b/lib/pleroma/web/activity_pub/object_validators/announce_validator.ex @@ -32,7 +32,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.AnnounceValidator do field(:published, ObjectValidators.DateTime) end - def cast_and_validate(data) do + def cast_and_validate(data, _meta \\ []) do data |> cast_data() |> validate_data() diff --git a/lib/pleroma/web/activity_pub/object_validators/answer_validator.ex b/lib/pleroma/web/activity_pub/object_validators/answer_validator.ex index 2d9b8ba02..19cbb719c 100644 --- a/lib/pleroma/web/activity_pub/object_validators/answer_validator.ex +++ b/lib/pleroma/web/activity_pub/object_validators/answer_validator.ex @@ -37,7 +37,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.AnswerValidator do |> apply_action(:insert) end - def cast_and_validate(data) do + def cast_and_validate(data, _meta \\ []) do data |> cast_data() |> validate_data() diff --git a/lib/pleroma/web/activity_pub/object_validators/article_note_page_validator.ex b/lib/pleroma/web/activity_pub/object_validators/article_note_page_validator.ex index 1b5b2e8fb..d75c01c77 100644 --- a/lib/pleroma/web/activity_pub/object_validators/article_note_page_validator.ex +++ b/lib/pleroma/web/activity_pub/object_validators/article_note_page_validator.ex @@ -34,13 +34,15 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.ArticleNotePageValidator do |> apply_action(:insert) end - def cast_and_validate(data) do + def cast_and_validate(data, meta \\ []) do data - |> cast_data() - |> validate_data() + |> cast_data(meta) + |> validate_data(meta) end - def cast_data(data) do + def cast_data(data, meta \\ []) do + data = fix(data, meta) + %__MODULE__{} |> changeset(data) end @@ -76,7 +78,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.ArticleNotePageValidator do def fix_attachments(data), do: data - defp fix(data) do + defp fix(data, _meta) do data |> CommonFixes.fix_actor() |> CommonFixes.fix_object_defaults() @@ -90,21 +92,29 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.ArticleNotePageValidator do end def changeset(struct, data) do - data = fix(data) - struct - |> cast(data, __schema__(:fields) -- [:attachment, :tag]) + |> cast(data, __schema__(:fields) -- [:attachment, :tag, :generator]) |> cast_embed(:attachment) |> cast_embed(:tag) + |> cast_embed(:generator) end - defp validate_data(data_cng) do + defp validate_data(data_cng, meta) do data_cng |> validate_inclusion(:type, ["Article", "Note", "Page"]) |> validate_required([:id, :actor, :attributedTo, :type, :context]) - |> CommonValidations.validate_any_presence([:cc, :to]) + |> maybe_to_cc(meta) |> CommonValidations.validate_fields_match([:actor, :attributedTo]) |> CommonValidations.validate_actor_presence() |> CommonValidations.validate_host_match() end + + defp maybe_to_cc(data_cng, meta) do + if meta[:local] != true do + data_cng + |> CommonValidations.validate_any_presence([:cc, :to]) + else + data_cng + end + end end diff --git a/lib/pleroma/web/activity_pub/object_validators/attachment_validator.ex b/lib/pleroma/web/activity_pub/object_validators/attachment_validator.ex index 398020bff..ea3ebc683 100644 --- a/lib/pleroma/web/activity_pub/object_validators/attachment_validator.ex +++ b/lib/pleroma/web/activity_pub/object_validators/attachment_validator.ex @@ -26,7 +26,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.AttachmentValidator do end end - def cast_and_validate(data) do + def cast_and_validate(data, _meta \\ []) do data |> cast_data() |> validate_data() diff --git a/lib/pleroma/web/activity_pub/object_validators/audio_image_video_validator.ex b/lib/pleroma/web/activity_pub/object_validators/audio_image_video_validator.ex index 65ac6bb93..124158e31 100644 --- a/lib/pleroma/web/activity_pub/object_validators/audio_image_video_validator.ex +++ b/lib/pleroma/web/activity_pub/object_validators/audio_image_video_validator.ex @@ -31,7 +31,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.AudioImageVideoValidator do |> apply_action(:insert) end - def cast_and_validate(data) do + def cast_and_validate(data, _meta \\ []) do data |> cast_data() |> validate_data() @@ -109,9 +109,10 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.AudioImageVideoValidator do data = fix(data) struct - |> cast(data, __schema__(:fields) -- [:attachment, :tag]) + |> cast(data, __schema__(:fields) -- [:attachment, :tag, :generator]) |> cast_embed(:attachment, required: true) |> cast_embed(:tag) + |> cast_embed(:generator) end defp validate_data(data_cng) do diff --git a/lib/pleroma/web/activity_pub/object_validators/block_validator.ex b/lib/pleroma/web/activity_pub/object_validators/block_validator.ex index 0de87a27e..e7aec126c 100644 --- a/lib/pleroma/web/activity_pub/object_validators/block_validator.ex +++ b/lib/pleroma/web/activity_pub/object_validators/block_validator.ex @@ -35,7 +35,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.BlockValidator do |> CommonValidations.validate_actor_presence(field_name: :object) end - def cast_and_validate(data) do + def cast_and_validate(data, _meta \\ []) do data |> cast_data |> validate_data diff --git a/lib/pleroma/web/activity_pub/object_validators/chat_message_validator.ex b/lib/pleroma/web/activity_pub/object_validators/chat_message_validator.ex index 09e25be89..878e578a5 100644 --- a/lib/pleroma/web/activity_pub/object_validators/chat_message_validator.ex +++ b/lib/pleroma/web/activity_pub/object_validators/chat_message_validator.ex @@ -33,7 +33,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.ChatMessageValidator do |> apply_action(:insert) end - def cast_and_validate(data) do + def cast_and_validate(data, _meta \\ []) do data |> cast_data() |> validate_data() diff --git a/lib/pleroma/web/activity_pub/object_validators/common_fields.ex b/lib/pleroma/web/activity_pub/object_validators/common_fields.ex index 1a5d02601..2b6eca48e 100644 --- a/lib/pleroma/web/activity_pub/object_validators/common_fields.ex +++ b/lib/pleroma/web/activity_pub/object_validators/common_fields.ex @@ -5,6 +5,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.CommonFields do alias Pleroma.EctoType.ActivityPub.ObjectValidators alias Pleroma.Web.ActivityPub.ObjectValidators.AttachmentValidator + alias Pleroma.Web.ActivityPub.ObjectValidators.GeneratorValidator alias Pleroma.Web.ActivityPub.ObjectValidators.TagValidator # Activities and Objects, except (Create)ChatMessage @@ -64,6 +65,8 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.CommonFields do field(:likes, {:array, ObjectValidators.ObjectID}, default: []) field(:announcements, {:array, ObjectValidators.ObjectID}, default: []) + + embeds_one(:generator, GeneratorValidator) end end end diff --git a/lib/pleroma/web/activity_pub/object_validators/create_generic_validator.ex b/lib/pleroma/web/activity_pub/object_validators/create_generic_validator.ex index 2395abfd4..1451cb561 100644 --- a/lib/pleroma/web/activity_pub/object_validators/create_generic_validator.ex +++ b/lib/pleroma/web/activity_pub/object_validators/create_generic_validator.ex @@ -82,8 +82,16 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.CreateGenericValidator do defp validate_data(cng, meta) do object = meta[:object_data] + required = [:actor, :type, :object] + + required = if meta[:local] == true do + required + else + required ++ [:to, :cc] + end + cng - |> validate_required([:actor, :type, :object, :to, :cc]) + |> validate_required(required) |> validate_inclusion(:type, ["Create"]) |> CommonValidations.validate_actor_presence() |> validate_actors_match(object) diff --git a/lib/pleroma/web/activity_pub/object_validators/delete_validator.ex b/lib/pleroma/web/activity_pub/object_validators/delete_validator.ex index 4d8502ada..2f0a59a43 100644 --- a/lib/pleroma/web/activity_pub/object_validators/delete_validator.ex +++ b/lib/pleroma/web/activity_pub/object_validators/delete_validator.ex @@ -70,7 +70,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.DeleteValidator do !same_domain?(cng) end - def cast_and_validate(data) do + def cast_and_validate(data, _meta \\ []) do data |> cast_data |> validate_data diff --git a/lib/pleroma/web/activity_pub/object_validators/emoji_react_validator.ex b/lib/pleroma/web/activity_pub/object_validators/emoji_react_validator.ex index 65ba047e6..b533b34e7 100644 --- a/lib/pleroma/web/activity_pub/object_validators/emoji_react_validator.ex +++ b/lib/pleroma/web/activity_pub/object_validators/emoji_react_validator.ex @@ -29,7 +29,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.EmojiReactValidator do field(:content, :string) end - def cast_and_validate(data) do + def cast_and_validate(data, _meta \\ []) do data |> cast_data() |> validate_data() diff --git a/lib/pleroma/web/activity_pub/object_validators/event_validator.ex b/lib/pleroma/web/activity_pub/object_validators/event_validator.ex index ab204f69a..615710dd9 100644 --- a/lib/pleroma/web/activity_pub/object_validators/event_validator.ex +++ b/lib/pleroma/web/activity_pub/object_validators/event_validator.ex @@ -32,7 +32,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.EventValidator do |> apply_action(:insert) end - def cast_and_validate(data) do + def cast_and_validate(data, _meta \\ []) do data |> cast_data() |> validate_data() @@ -54,9 +54,10 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.EventValidator do data = fix(data) struct - |> cast(data, __schema__(:fields) -- [:attachment, :tag]) + |> cast(data, __schema__(:fields) -- [:attachment, :tag, :generator]) |> cast_embed(:attachment) |> cast_embed(:tag) + |> cast_embed(:generator) end defp validate_data(data_cng) do diff --git a/lib/pleroma/web/activity_pub/object_validators/follow_validator.ex b/lib/pleroma/web/activity_pub/object_validators/follow_validator.ex index b3ca5b691..5ce3f2021 100644 --- a/lib/pleroma/web/activity_pub/object_validators/follow_validator.ex +++ b/lib/pleroma/web/activity_pub/object_validators/follow_validator.ex @@ -36,7 +36,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.FollowValidator do |> validate_actor_presence(field_name: :object) end - def cast_and_validate(data) do + def cast_and_validate(data, _meta \\ []) do data |> cast_data |> validate_data diff --git a/lib/pleroma/web/activity_pub/object_validators/generator_validator.ex b/lib/pleroma/web/activity_pub/object_validators/generator_validator.ex new file mode 100644 index 000000000..82504150f --- /dev/null +++ b/lib/pleroma/web/activity_pub/object_validators/generator_validator.ex @@ -0,0 +1,40 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2022 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.ActivityPub.ObjectValidators.GeneratorValidator do + use Ecto.Schema + + alias Pleroma.EctoType.ActivityPub.ObjectValidators + + import Ecto.Changeset + + @primary_key false + embedded_schema do + field(:type, :string) + field(:name, :string) + field(:url, ObjectValidators.BareUri) + end + + def cast_and_validate(data, _meta \\ []) 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 + + defp validate_data(cng) do + cng + |> validate_inclusion(:type, ~w[Application]) + |> validate_required([:name, :url]) + end +end diff --git a/lib/pleroma/web/activity_pub/object_validators/like_validator.ex b/lib/pleroma/web/activity_pub/object_validators/like_validator.ex index bdc4d7181..827eab324 100644 --- a/lib/pleroma/web/activity_pub/object_validators/like_validator.ex +++ b/lib/pleroma/web/activity_pub/object_validators/like_validator.ex @@ -26,7 +26,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.LikeValidator do field(:context, :string) end - def cast_and_validate(data) do + def cast_and_validate(data, _meta \\ []) do data |> cast_data() |> validate_data() diff --git a/lib/pleroma/web/activity_pub/object_validators/question_validator.ex b/lib/pleroma/web/activity_pub/object_validators/question_validator.ex index 621085e6c..962a3fad4 100644 --- a/lib/pleroma/web/activity_pub/object_validators/question_validator.ex +++ b/lib/pleroma/web/activity_pub/object_validators/question_validator.ex @@ -39,7 +39,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.QuestionValidator do |> apply_action(:insert) end - def cast_and_validate(data) do + def cast_and_validate(data, _meta \\ []) do data |> cast_data() |> validate_data() @@ -71,11 +71,12 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.QuestionValidator do data = fix(data) struct - |> cast(data, __schema__(:fields) -- [:anyOf, :oneOf, :attachment, :tag]) + |> cast(data, __schema__(:fields) -- [:anyOf, :oneOf, :attachment, :tag, :generator]) |> cast_embed(:attachment) |> cast_embed(:anyOf) |> cast_embed(:oneOf) |> cast_embed(:tag) + |> cast_embed(:generator) end defp validate_data(data_cng) do diff --git a/lib/pleroma/web/activity_pub/object_validators/tag_validator.ex b/lib/pleroma/web/activity_pub/object_validators/tag_validator.ex index 47cf7b415..5207756c1 100644 --- a/lib/pleroma/web/activity_pub/object_validators/tag_validator.ex +++ b/lib/pleroma/web/activity_pub/object_validators/tag_validator.ex @@ -33,7 +33,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.TagValidator do field(:id, ObjectValidators.Uri) end - def cast_and_validate(data) do + def cast_and_validate(data, _meta \\ []) do data |> cast_data() end diff --git a/lib/pleroma/web/activity_pub/object_validators/undo_validator.ex b/lib/pleroma/web/activity_pub/object_validators/undo_validator.ex index f03051491..4f202b6ae 100644 --- a/lib/pleroma/web/activity_pub/object_validators/undo_validator.ex +++ b/lib/pleroma/web/activity_pub/object_validators/undo_validator.ex @@ -23,7 +23,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.UndoValidator do end end - def cast_and_validate(data) do + def cast_and_validate(data, _meta \\ []) do data |> cast_data() |> validate_data() 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..ebeedb19e 100644 --- a/lib/pleroma/web/activity_pub/object_validators/update_validator.ex +++ b/lib/pleroma/web/activity_pub/object_validators/update_validator.ex @@ -39,7 +39,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.UpdateValidator do |> validate_updating_rights() end - def cast_and_validate(data) do + def cast_and_validate(data, _meta \\ []) do data |> cast_data |> validate_data diff --git a/lib/pleroma/web/activity_pub/side_effects.ex b/lib/pleroma/web/activity_pub/side_effects.ex index 5cb8a9700..9e2487720 100644 --- a/lib/pleroma/web/activity_pub/side_effects.ex +++ b/lib/pleroma/web/activity_pub/side_effects.ex @@ -195,7 +195,6 @@ defmodule Pleroma.Web.ActivityPub.SideEffects do # - Increase the user note count # - Increase the reply count # - Increase replies count - # - Set up ActivityExpiration # - Set up notifications # - Index incoming posts for search (if needed) @impl true diff --git a/lib/pleroma/web/activity_pub/utils.ex b/lib/pleroma/web/activity_pub/utils.ex index 52cb64fc5..9f3e1e53b 100644 --- a/lib/pleroma/web/activity_pub/utils.ex +++ b/lib/pleroma/web/activity_pub/utils.ex @@ -691,7 +691,7 @@ defmodule Pleroma.Web.ActivityPub.Utils do #### Create-related helpers def make_create_data(params, additional) do - published = params.published || make_date() + published = Map.get(params, :published) || make_date() %{ "type" => "Create", @@ -702,6 +702,7 @@ defmodule Pleroma.Web.ActivityPub.Utils do "context" => params.context } |> Map.merge(additional) + |> Maps.put_if_present("expires_at", additional["expires_at"], &{:ok, DateTime.to_iso8601(&1)}) end #### Listen-related helpers diff --git a/lib/pleroma/web/common_api.ex b/lib/pleroma/web/common_api.ex index 27e82ecc8..59de65dfa 100644 --- a/lib/pleroma/web/common_api.ex +++ b/lib/pleroma/web/common_api.ex @@ -425,8 +425,27 @@ defmodule Pleroma.Web.CommonAPI do end def post(user, %{status: _} = data) do - with {:ok, draft} <- ActivityDraft.create(user, data) do - ActivityPub.create(draft.changes, draft.preview?) + published = Utils.make_date() + with {:ok, %{changes: changes, preview?: fake} = _draft} <- ActivityDraft.create(user, data), + changes <- changes + |> Map.put_new(:published, published) + |> Map.put("object", + changes.object + |> Map.put_new("id", Utils.generate_object_id()) + |> Map.put_new("published", published) + |> Map.merge(changes.additional) + ), + create_data <- changes + |> Utils.make_create_data(changes.additional), + {:fake, false, _data} <- {:fake, fake, create_data}, + {:ok, create, _} <- Pipeline.common_pipeline(create_data, local: true) do + {:ok, create} + else + {:fake, true, activity} -> {:ok, activity} + + {:error, _} = e -> e + + e -> {:error, e} end end