logo

pleroma

My custom branche(s) on git.pleroma.social/pleroma/pleroma git clone https://hacktivis.me/git/pleroma.git

create_generic_validator.ex (4411B)


  1. # Pleroma: A lightweight social networking server
  2. # Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
  3. # SPDX-License-Identifier: AGPL-3.0-only
  4. # Code based on CreateChatMessageValidator
  5. # NOTES
  6. # - doesn't embed, will only get the object id
  7. defmodule Pleroma.Web.ActivityPub.ObjectValidators.CreateGenericValidator do
  8. use Ecto.Schema
  9. alias Pleroma.EctoType.ActivityPub.ObjectValidators
  10. alias Pleroma.Object
  11. alias Pleroma.User
  12. alias Pleroma.Web.ActivityPub.ObjectValidators.CommonFixes
  13. alias Pleroma.Web.ActivityPub.ObjectValidators.CommonValidations
  14. alias Pleroma.Web.ActivityPub.Transmogrifier
  15. import Ecto.Changeset
  16. @primary_key false
  17. embedded_schema do
  18. quote do
  19. unquote do
  20. import Elixir.Pleroma.Web.ActivityPub.ObjectValidators.CommonFields
  21. message_fields()
  22. activity_fields()
  23. end
  24. end
  25. field(:expires_at, ObjectValidators.DateTime)
  26. # Should be moved to object, done for CommonAPI.Utils.make_context
  27. field(:context, :string)
  28. end
  29. def cast_data(data, meta \\ []) do
  30. data = fix(data, meta)
  31. %__MODULE__{}
  32. |> changeset(data)
  33. end
  34. def cast_and_apply(data) do
  35. data
  36. |> cast_data
  37. |> apply_action(:insert)
  38. end
  39. def cast_and_validate(data, meta \\ []) do
  40. data
  41. |> cast_data(meta)
  42. |> validate_data(meta)
  43. end
  44. def changeset(struct, data) do
  45. struct
  46. |> cast(data, __schema__(:fields))
  47. end
  48. # CommonFixes.fix_activity_addressing adapted for Create specific behavior
  49. defp fix_addressing(data, object) do
  50. %User{follower_address: follower_collection} = User.get_cached_by_ap_id(data["actor"])
  51. data
  52. |> CommonFixes.cast_and_filter_recipients("to", follower_collection, object["to"])
  53. |> CommonFixes.cast_and_filter_recipients("cc", follower_collection, object["cc"])
  54. |> CommonFixes.cast_and_filter_recipients("bto", follower_collection, object["bto"])
  55. |> CommonFixes.cast_and_filter_recipients("bcc", follower_collection, object["bcc"])
  56. |> Transmogrifier.fix_implicit_addressing(follower_collection)
  57. end
  58. def fix(data, meta) do
  59. object = meta[:object_data]
  60. data
  61. |> CommonFixes.fix_actor()
  62. |> Map.put("context", object["context"])
  63. |> fix_addressing(object)
  64. end
  65. defp validate_data(cng, meta) do
  66. object = meta[:object_data]
  67. cng
  68. |> validate_required([:actor, :type, :object, :to, :cc])
  69. |> validate_inclusion(:type, ["Create"])
  70. |> CommonValidations.validate_actor_presence()
  71. |> validate_actors_match(object)
  72. |> validate_context_match(object)
  73. |> validate_addressing_match(object)
  74. |> validate_object_nonexistence()
  75. |> validate_object_containment()
  76. end
  77. def validate_object_containment(cng) do
  78. actor = get_field(cng, :actor)
  79. cng
  80. |> validate_change(:object, fn :object, object_id ->
  81. %URI{host: object_id_host} = URI.parse(object_id)
  82. %URI{host: actor_host} = URI.parse(actor)
  83. if object_id_host == actor_host do
  84. []
  85. else
  86. [{:object, "The host of the object id doesn't match with the host of the actor"}]
  87. end
  88. end)
  89. end
  90. def validate_object_nonexistence(cng) do
  91. cng
  92. |> validate_change(:object, fn :object, object_id ->
  93. if Object.get_cached_by_ap_id(object_id) do
  94. [{:object, "The object to create already exists"}]
  95. else
  96. []
  97. end
  98. end)
  99. end
  100. def validate_actors_match(cng, object) do
  101. attributed_to = object["attributedTo"] || object["actor"]
  102. cng
  103. |> validate_change(:actor, fn :actor, actor ->
  104. if actor == attributed_to do
  105. []
  106. else
  107. [{:actor, "Actor doesn't match with object attributedTo"}]
  108. end
  109. end)
  110. end
  111. def validate_context_match(cng, %{"context" => object_context}) do
  112. cng
  113. |> validate_change(:context, fn :context, context ->
  114. if context == object_context do
  115. []
  116. else
  117. [{:context, "context field not matching between Create and object (#{object_context})"}]
  118. end
  119. end)
  120. end
  121. def validate_addressing_match(cng, object) do
  122. [:to, :cc, :bcc, :bto]
  123. |> Enum.reduce(cng, fn field, cng ->
  124. object_data = object[to_string(field)]
  125. validate_change(cng, field, fn field, data ->
  126. if data == object_data do
  127. []
  128. else
  129. [{field, "field doesn't match with object (#{inspect(object_data)})"}]
  130. end
  131. end)
  132. end)
  133. end
  134. end