summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHaelwenn <contact+git.pleroma.social@hacktivis.me>2021-07-12 05:01:36 +0000
committerHaelwenn <contact+git.pleroma.social@hacktivis.me>2021-07-12 05:01:36 +0000
commitebcc28fef07236e6094998c230b10345abf8b307 (patch)
tree9b339fd0ebf3621cc3a9d71d8d7c6700984477bc
parentaa9a6c3c056fde45b4c13c9c873cef9492b279e9 (diff)
parent6dc78f5f6f8c607c90246ff30520aeb2f84634df (diff)
Merge branch 'features/validators-apc2s' into 'develop'
AP C2S: Remove restrictions and make it go through pipeline See merge request pleroma/pleroma!3203
-rw-r--r--CHANGELOG.md1
-rw-r--r--lib/pleroma/activity.ex3
-rw-r--r--lib/pleroma/web/activity_pub/activity_pub_controller.ex104
-rw-r--r--lib/pleroma/web/activity_pub/object_validator.ex2
-rw-r--r--test/pleroma/web/activity_pub/activity_pub_controller_test.exs31
5 files changed, 77 insertions, 64 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 9854eb531..036b9e775 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -14,6 +14,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
- HTTPSecurityPlug now sends a response header to opt out of Google's FLoC (Federated Learning of Cohorts) targeted advertising.
- Email address is now returned if requesting user is the owner of the user account so it can be exposed in client and FE user settings UIs.
- Improved Twittercard and OpenGraph meta tag generation including thumbnails and image dimension metadata when available.
+- ActivityPub Client-to-Server(C2S): Limitation on the type of Activity/Object are lifted as they are now passed through ObjectValidators
### Added
diff --git a/lib/pleroma/activity.ex b/lib/pleroma/activity.ex
index 7e36c1b53..6a991c48e 100644
--- a/lib/pleroma/activity.ex
+++ b/lib/pleroma/activity.ex
@@ -292,7 +292,8 @@ defmodule Pleroma.Activity do
get_in_reply_to_activity_from_object(Object.normalize(activity, fetch: false))
end
- def normalize(obj) when is_map(obj), do: get_by_ap_id_with_object(obj["id"])
+ def normalize(%Activity{data: %{"id" => ap_id}}), do: get_by_ap_id_with_object(ap_id)
+ def normalize(%{"id" => ap_id}), do: get_by_ap_id_with_object(ap_id)
def normalize(ap_id) when is_binary(ap_id), do: get_by_ap_id_with_object(ap_id)
def normalize(_), do: nil
diff --git a/lib/pleroma/web/activity_pub/activity_pub_controller.ex b/lib/pleroma/web/activity_pub/activity_pub_controller.ex
index 5aa3b281a..57ac40b42 100644
--- a/lib/pleroma/web/activity_pub/activity_pub_controller.ex
+++ b/lib/pleroma/web/activity_pub/activity_pub_controller.ex
@@ -11,7 +11,6 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubController do
alias Pleroma.Object.Fetcher
alias Pleroma.User
alias Pleroma.Web.ActivityPub.ActivityPub
- alias Pleroma.Web.ActivityPub.Builder
alias Pleroma.Web.ActivityPub.InternalFetchActor
alias Pleroma.Web.ActivityPub.ObjectView
alias Pleroma.Web.ActivityPub.Pipeline
@@ -403,83 +402,90 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubController do
|> json(err)
end
- defp handle_user_activity(
- %User{} = user,
- %{"type" => "Create", "object" => %{"type" => "Note"} = object} = params
- ) do
- content = if is_binary(object["content"]), do: object["content"], else: ""
- name = if is_binary(object["name"]), do: object["name"], else: ""
- summary = if is_binary(object["summary"]), do: object["summary"], else: ""
- length = String.length(content <> name <> summary)
+ defp fix_user_message(%User{ap_id: actor}, %{"type" => "Create", "object" => object} = activity)
+ when is_map(object) do
+ length =
+ [object["content"], object["summary"], object["name"]]
+ |> Enum.filter(&is_binary(&1))
+ |> Enum.join("")
+ |> String.length()
- if length > Pleroma.Config.get([:instance, :limit]) do
- {:error, dgettext("errors", "Note is over the character limit")}
- else
+ limit = Pleroma.Config.get([:instance, :limit])
+
+ if length < limit do
object =
object
- |> Map.merge(Map.take(params, ["to", "cc"]))
- |> Map.put("attributedTo", user.ap_id)
- |> Transmogrifier.fix_object()
-
- ActivityPub.create(%{
- to: params["to"],
- actor: user,
- context: object["context"],
- object: object,
- additional: Map.take(params, ["cc"])
- })
- end
- end
+ |> Transmogrifier.strip_internal_fields()
+ |> Map.put("attributedTo", actor)
+ |> Map.put("actor", actor)
+ |> Map.put("id", Utils.generate_object_id())
- defp handle_user_activity(%User{} = user, %{"type" => "Delete"} = params) do
- with %Object{} = object <- Object.normalize(params["object"], fetch: false),
- true <- user.is_moderator || user.ap_id == object.data["actor"],
- {:ok, delete_data, _} <- Builder.delete(user, object.data["id"]),
- {:ok, delete, _} <- Pipeline.common_pipeline(delete_data, local: true) do
- {:ok, delete}
+ {:ok, Map.put(activity, "object", object)}
else
- _ -> {:error, dgettext("errors", "Can't delete object")}
+ {:error,
+ dgettext(
+ "errors",
+ "Character limit (%{limit} characters) exceeded, contains %{length} characters",
+ limit: limit,
+ length: length
+ )}
end
end
- defp handle_user_activity(%User{} = user, %{"type" => "Like"} = params) do
- with %Object{} = object <- Object.normalize(params["object"], fetch: false),
- {_, {:ok, like_object, meta}} <- {:build_object, Builder.like(user, object)},
- {_, {:ok, %Activity{} = activity, _meta}} <-
- {:common_pipeline,
- Pipeline.common_pipeline(like_object, Keyword.put(meta, :local, true))} do
+ defp fix_user_message(
+ %User{ap_id: actor} = user,
+ %{"type" => "Delete", "object" => object} = activity
+ ) do
+ with {_, %Object{data: object_data}} <- {:normalize, Object.normalize(object, fetch: false)},
+ {_, true} <- {:permission, user.is_moderator || actor == object_data["actor"]} do
{:ok, activity}
else
- _ -> {:error, dgettext("errors", "Can't like object")}
+ {:normalize, _} ->
+ {:error, "No such object found"}
+
+ {:permission, _} ->
+ {:forbidden, "You can't delete this object"}
end
end
- defp handle_user_activity(_, _) do
- {:error, dgettext("errors", "Unhandled activity type")}
+ defp fix_user_message(%User{}, activity) do
+ {:ok, activity}
end
def update_outbox(
- %{assigns: %{user: %User{nickname: nickname} = user}} = conn,
+ %{assigns: %{user: %User{nickname: nickname, ap_id: actor} = user}} = conn,
%{"nickname" => nickname} = params
) do
- actor = user.ap_id
-
params =
params
- |> Map.drop(["id"])
+ |> Map.drop(["nickname"])
+ |> Map.put("id", Utils.generate_activity_id())
|> Map.put("actor", actor)
- |> Transmogrifier.fix_addressing()
- with {:ok, %Activity{} = activity} <- handle_user_activity(user, params) do
+ with {:ok, params} <- fix_user_message(user, params),
+ {:ok, activity, _} <- Pipeline.common_pipeline(params, local: true),
+ %Activity{data: activity_data} <- Activity.normalize(activity) do
conn
|> put_status(:created)
- |> put_resp_header("location", activity.data["id"])
- |> json(activity.data)
+ |> put_resp_header("location", activity_data["id"])
+ |> json(activity_data)
else
+ {:forbidden, message} ->
+ conn
+ |> put_status(:forbidden)
+ |> json(message)
+
{:error, message} ->
conn
|> put_status(:bad_request)
|> json(message)
+
+ e ->
+ Logger.warn(fn -> "AP C2S: #{inspect(e)}" end)
+
+ conn
+ |> put_status(:bad_request)
+ |> json("Bad Request")
end
end
diff --git a/lib/pleroma/web/activity_pub/object_validator.ex b/lib/pleroma/web/activity_pub/object_validator.ex
index 248a12a36..50999539c 100644
--- a/lib/pleroma/web/activity_pub/object_validator.ex
+++ b/lib/pleroma/web/activity_pub/object_validator.ex
@@ -175,6 +175,8 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidator do
end
end
+ def validate(o, m), do: {:error, {:validator_not_set, {o, m}}}
+
def cast_and_apply(%{"type" => "ChatMessage"} = object) do
ChatMessageValidator.cast_and_apply(object)
end
diff --git a/test/pleroma/web/activity_pub/activity_pub_controller_test.exs b/test/pleroma/web/activity_pub/activity_pub_controller_test.exs
index c7039d1f8..50315e21f 100644
--- a/test/pleroma/web/activity_pub/activity_pub_controller_test.exs
+++ b/test/pleroma/web/activity_pub/activity_pub_controller_test.exs
@@ -1334,9 +1334,12 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do
activity: %{
"@context" => "https://www.w3.org/ns/activitystreams",
"type" => "Create",
- "object" => %{"type" => "Note", "content" => "AP C2S test"},
- "to" => "https://www.w3.org/ns/activitystreams#Public",
- "cc" => []
+ "object" => %{
+ "type" => "Note",
+ "content" => "AP C2S test",
+ "to" => "https://www.w3.org/ns/activitystreams#Public",
+ "cc" => []
+ }
}
]
end
@@ -1442,19 +1445,19 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do
user = User.get_cached_by_ap_id(note_activity.data["actor"])
data = %{
- type: "Delete",
- object: %{
- id: note_object.data["id"]
+ "type" => "Delete",
+ "object" => %{
+ "id" => note_object.data["id"]
}
}
- conn =
+ result =
conn
|> assign(:user, user)
|> put_req_header("content-type", "application/activity+json")
|> post("/users/#{user.nickname}/outbox", data)
+ |> json_response(201)
- result = json_response(conn, 201)
assert Activity.get_by_ap_id(result["id"])
assert object = Object.get_by_ap_id(note_object.data["id"])
@@ -1479,7 +1482,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do
|> put_req_header("content-type", "application/activity+json")
|> post("/users/#{user.nickname}/outbox", data)
- assert json_response(conn, 400)
+ assert json_response(conn, 403)
end
test "it increases like count when receiving a like action", %{conn: conn} do
@@ -1557,7 +1560,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do
|> post("/users/#{user.nickname}/outbox", activity)
|> json_response(400)
- assert result == "Note is over the character limit"
+ assert result == "Character limit (5 characters) exceeded, contains 11 characters"
end
end
@@ -1934,10 +1937,10 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do
"object" => %{
"type" => "Note",
"content" => "AP C2S test, attachment",
- "attachment" => [object]
- },
- "to" => "https://www.w3.org/ns/activitystreams#Public",
- "cc" => []
+ "attachment" => [object],
+ "to" => "https://www.w3.org/ns/activitystreams#Public",
+ "cc" => []
+ }
}
activity_response =