Merge pull request 'Akkoma interop fixes: emoji reacts, personal inbox, markers, data: URLs' (#8050) from lambadalambda/pleroma:fix/akkoma-interop into develop
Reviewed-on: https://git.pleroma.social/pleroma/pleroma/pulls/8050
This commit is contained in:
commit
4b08f7a553
15 changed files with 92 additions and 93 deletions
1
changelog.d/emoji-react-single-tag.fix
Normal file
1
changelog.d/emoji-react-single-tag.fix
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
Accept incoming emoji reactions whose tag is a single object instead of an array
|
||||||
1
changelog.d/marker-updated-at-format.fix
Normal file
1
changelog.d/marker-updated-at-format.fix
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
Mastodon API: Use the Mastodon date format for marker updated_at
|
||||||
1
changelog.d/media-proxy-data-urls.fix
Normal file
1
changelog.d/media-proxy-data-urls.fix
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
MediaProxy: Do not proxy data: URLs
|
||||||
1
changelog.d/personal-inbox-addressing.fix
Normal file
1
changelog.d/personal-inbox-addressing.fix
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
Accept activities delivered to a personal inbox that do not address the inbox owner (fixes Bridgy Fed follows)
|
||||||
|
|
@ -341,7 +341,6 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubController do
|
||||||
{:sender_exists, User.get_or_fetch_by_ap_id(params["actor"])},
|
{:sender_exists, User.get_or_fetch_by_ap_id(params["actor"])},
|
||||||
{:recipient_active, true} <- {:recipient_active, recipient.is_active},
|
{:recipient_active, true} <- {:recipient_active, recipient.is_active},
|
||||||
{:sender_active, true} <- {:sender_active, actor.is_active},
|
{:sender_active, true} <- {:sender_active, actor.is_active},
|
||||||
true <- Utils.recipient_in_message(recipient, actor, params),
|
|
||||||
params <- Utils.maybe_splice_recipient(recipient.ap_id, params) do
|
params <- Utils.maybe_splice_recipient(recipient.ap_id, params) do
|
||||||
Federator.incoming_ap_doc(params)
|
Federator.incoming_ap_doc(params)
|
||||||
json(conn, "ok")
|
json(conn, "ok")
|
||||||
|
|
|
||||||
|
|
@ -57,7 +57,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.EmojiReactValidator do
|
||||||
|> CommonFixes.fix_actor()
|
|> CommonFixes.fix_actor()
|
||||||
|> CommonFixes.fix_activity_addressing()
|
|> CommonFixes.fix_activity_addressing()
|
||||||
|
|
||||||
data = Map.put_new(data, "tag", [])
|
data = fix_tag(data)
|
||||||
|
|
||||||
case Object.normalize(data["object"]) do
|
case Object.normalize(data["object"]) do
|
||||||
%Object{} = object ->
|
%Object{} = object ->
|
||||||
|
|
@ -70,6 +70,10 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.EmojiReactValidator do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# JSON-LD compaction turns a single-element array into a bare object
|
||||||
|
defp fix_tag(%{"tag" => %{} = tag} = data), do: Map.put(data, "tag", [tag])
|
||||||
|
defp fix_tag(data), do: Map.put_new(data, "tag", [])
|
||||||
|
|
||||||
defp fix_emoji_qualification(%{"content" => emoji} = data) do
|
defp fix_emoji_qualification(%{"content" => emoji} = data) do
|
||||||
new_emoji = Pleroma.Emoji.fully_qualify_emoji(emoji)
|
new_emoji = Pleroma.Emoji.fully_qualify_emoji(emoji)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -78,22 +78,6 @@ defmodule Pleroma.Web.ActivityPub.Utils do
|
||||||
[params["to"], params["cc"], params["bto"], params["bcc"]]
|
[params["to"], params["cc"], params["bto"], params["bcc"]]
|
||||||
|> Enum.any?(&label_in_collection?(label, &1))
|
|> Enum.any?(&label_in_collection?(label, &1))
|
||||||
|
|
||||||
@spec unaddressed_message?(map()) :: boolean()
|
|
||||||
def unaddressed_message?(params),
|
|
||||||
do:
|
|
||||||
[params["to"], params["cc"], params["bto"], params["bcc"]]
|
|
||||||
|> Enum.all?(fn
|
|
||||||
nil -> true
|
|
||||||
[] -> true
|
|
||||||
_ -> false
|
|
||||||
end)
|
|
||||||
|
|
||||||
@spec recipient_in_message(User.t(), User.t(), map()) :: boolean()
|
|
||||||
def recipient_in_message(%User{ap_id: ap_id} = recipient, %User{} = actor, params),
|
|
||||||
do:
|
|
||||||
label_in_message?(ap_id, params) || unaddressed_message?(params) ||
|
|
||||||
User.following?(recipient, actor)
|
|
||||||
|
|
||||||
defp extract_list(target) when is_binary(target), do: [target]
|
defp extract_list(target) when is_binary(target), do: [target]
|
||||||
defp extract_list(lst) when is_list(lst), do: lst
|
defp extract_list(lst) when is_list(lst), do: lst
|
||||||
defp extract_list(_), do: []
|
defp extract_list(_), do: []
|
||||||
|
|
|
||||||
|
|
@ -5,13 +5,15 @@
|
||||||
defmodule Pleroma.Web.MastodonAPI.MarkerView do
|
defmodule Pleroma.Web.MastodonAPI.MarkerView do
|
||||||
use Pleroma.Web, :view
|
use Pleroma.Web, :view
|
||||||
|
|
||||||
|
alias Pleroma.Web.CommonAPI.Utils
|
||||||
|
|
||||||
def render("markers.json", %{markers: markers}) do
|
def render("markers.json", %{markers: markers}) do
|
||||||
Map.new(markers, fn m ->
|
Map.new(markers, fn m ->
|
||||||
{m.timeline,
|
{m.timeline,
|
||||||
%{
|
%{
|
||||||
last_read_id: m.last_read_id,
|
last_read_id: m.last_read_id,
|
||||||
version: m.lock_version,
|
version: m.lock_version,
|
||||||
updated_at: NaiveDateTime.to_iso8601(m.updated_at),
|
updated_at: Utils.to_masto_date(m.updated_at),
|
||||||
pleroma: %{
|
pleroma: %{
|
||||||
unread_count: m.unread_count
|
unread_count: m.unread_count
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -45,7 +45,7 @@ defmodule Pleroma.Web.MediaProxy do
|
||||||
def url("/" <> _ = url), do: url
|
def url("/" <> _ = url), do: url
|
||||||
|
|
||||||
def url(url) do
|
def url(url) do
|
||||||
if enabled?() and url_proxiable?(url) do
|
if enabled?() and not data_url?(url) and url_proxiable?(url) do
|
||||||
encode_url(url)
|
encode_url(url)
|
||||||
else
|
else
|
||||||
url
|
url
|
||||||
|
|
@ -61,7 +61,7 @@ defmodule Pleroma.Web.MediaProxy do
|
||||||
def preview_url("//" <> _ = url, pparams), do: preview_url("https:" <> url, pparams)
|
def preview_url("//" <> _ = url, pparams), do: preview_url("https:" <> url, pparams)
|
||||||
|
|
||||||
def preview_url(url, preview_params) do
|
def preview_url(url, preview_params) do
|
||||||
if preview_enabled?() do
|
if preview_enabled?() and not data_url?(url) do
|
||||||
encode_preview_url(url, preview_params)
|
encode_preview_url(url, preview_params)
|
||||||
else
|
else
|
||||||
url(url)
|
url(url)
|
||||||
|
|
@ -74,6 +74,8 @@ defmodule Pleroma.Web.MediaProxy do
|
||||||
# non-local non-whitelisted URLs through it and be sure that body size constraint is preserved.
|
# non-local non-whitelisted URLs through it and be sure that body size constraint is preserved.
|
||||||
def preview_enabled?, do: enabled?() and !!Config.get([:media_preview_proxy, :enabled])
|
def preview_enabled?, do: enabled?() and !!Config.get([:media_preview_proxy, :enabled])
|
||||||
|
|
||||||
|
defp data_url?(url), do: url |> String.slice(0, 5) |> String.downcase() == "data:"
|
||||||
|
|
||||||
def local?(url), do: String.starts_with?(url, Endpoint.url())
|
def local?(url), do: String.starts_with?(url, Endpoint.url())
|
||||||
|
|
||||||
def whitelisted?(url) do
|
def whitelisted?(url) do
|
||||||
|
|
|
||||||
|
|
@ -1872,6 +1872,30 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do
|
||||||
assert Activity.get_by_ap_id(data["id"])
|
assert Activity.get_by_ap_id(data["id"])
|
||||||
end
|
end
|
||||||
|
|
||||||
|
test "it accepts activities that do not address the inbox owner", %{conn: conn} do
|
||||||
|
user = insert(:user)
|
||||||
|
actor = insert(:user, local: false)
|
||||||
|
|
||||||
|
data = %{
|
||||||
|
"@context" => "https://www.w3.org/ns/activitystreams",
|
||||||
|
"type" => "Follow",
|
||||||
|
"id" => "#{actor.ap_id}/follows/1",
|
||||||
|
"actor" => actor.ap_id,
|
||||||
|
"object" => user.ap_id,
|
||||||
|
"to" => ["https://www.w3.org/ns/activitystreams#Public"]
|
||||||
|
}
|
||||||
|
|
||||||
|
conn =
|
||||||
|
conn
|
||||||
|
|> assign_valid_signature_for_actor(data["actor"])
|
||||||
|
|> put_req_header("content-type", "application/activity+json")
|
||||||
|
|> post("/users/#{user.nickname}/inbox", data)
|
||||||
|
|
||||||
|
assert "ok" == json_response(conn, 200)
|
||||||
|
ObanHelpers.perform(all_enqueued(worker: ReceiverWorker))
|
||||||
|
assert Activity.get_by_ap_id(data["id"])
|
||||||
|
end
|
||||||
|
|
||||||
test "it returns an error when receiving an activity sent to a deactivated user", %{
|
test "it returns an error when receiving an activity sent to a deactivated user", %{
|
||||||
conn: conn,
|
conn: conn,
|
||||||
data: data
|
data: data
|
||||||
|
|
|
||||||
|
|
@ -86,6 +86,31 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.EmojiReactHandlingTest do
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
test "it works for incoming custom emoji reactions with a single tag object" do
|
||||||
|
user = insert(:user)
|
||||||
|
other_user = insert(:user, local: false)
|
||||||
|
{:ok, activity} = CommonAPI.post(user, %{status: "hello"})
|
||||||
|
|
||||||
|
data =
|
||||||
|
File.read!("test/fixtures/custom-emoji-reaction.json")
|
||||||
|
|> Jason.decode!()
|
||||||
|
|> Map.put("object", activity.data["object"])
|
||||||
|
|> Map.put("actor", other_user.ap_id)
|
||||||
|
|
||||||
|
[tag] = data["tag"]
|
||||||
|
data = Map.put(data, "tag", tag)
|
||||||
|
|
||||||
|
{:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
|
||||||
|
|
||||||
|
assert data["content"] == ":hanapog:"
|
||||||
|
assert [%{"name" => "hanapog"}] = data["tag"]
|
||||||
|
|
||||||
|
object = Object.get_by_ap_id(data["object"])
|
||||||
|
url = tag["icon"]["url"]
|
||||||
|
|
||||||
|
assert match?([["hanapog", _, ^url]], object.data["reactions"])
|
||||||
|
end
|
||||||
|
|
||||||
test "it works for incoming unqualified emoji reactions" do
|
test "it works for incoming unqualified emoji reactions" do
|
||||||
user = insert(:user)
|
user = insert(:user)
|
||||||
other_user = insert(:user, local: false)
|
other_user = insert(:user, local: false)
|
||||||
|
|
|
||||||
|
|
@ -406,74 +406,6 @@ defmodule Pleroma.Web.ActivityPub.UtilsTest do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe "recipient_in_message/3" do
|
|
||||||
test "returns true when recipient in `to`" do
|
|
||||||
recipient = insert(:user)
|
|
||||||
actor = insert(:user)
|
|
||||||
assert Utils.recipient_in_message(recipient, actor, %{"to" => recipient.ap_id})
|
|
||||||
|
|
||||||
assert Utils.recipient_in_message(
|
|
||||||
recipient,
|
|
||||||
actor,
|
|
||||||
%{"to" => [recipient.ap_id], "cc" => ""}
|
|
||||||
)
|
|
||||||
end
|
|
||||||
|
|
||||||
test "returns true when recipient in `cc`" do
|
|
||||||
recipient = insert(:user)
|
|
||||||
actor = insert(:user)
|
|
||||||
assert Utils.recipient_in_message(recipient, actor, %{"cc" => recipient.ap_id})
|
|
||||||
|
|
||||||
assert Utils.recipient_in_message(
|
|
||||||
recipient,
|
|
||||||
actor,
|
|
||||||
%{"cc" => [recipient.ap_id], "to" => ""}
|
|
||||||
)
|
|
||||||
end
|
|
||||||
|
|
||||||
test "returns true when recipient in `bto`" do
|
|
||||||
recipient = insert(:user)
|
|
||||||
actor = insert(:user)
|
|
||||||
assert Utils.recipient_in_message(recipient, actor, %{"bto" => recipient.ap_id})
|
|
||||||
|
|
||||||
assert Utils.recipient_in_message(
|
|
||||||
recipient,
|
|
||||||
actor,
|
|
||||||
%{"bcc" => "", "bto" => [recipient.ap_id]}
|
|
||||||
)
|
|
||||||
end
|
|
||||||
|
|
||||||
test "returns true when recipient in `bcc`" do
|
|
||||||
recipient = insert(:user)
|
|
||||||
actor = insert(:user)
|
|
||||||
assert Utils.recipient_in_message(recipient, actor, %{"bcc" => recipient.ap_id})
|
|
||||||
|
|
||||||
assert Utils.recipient_in_message(
|
|
||||||
recipient,
|
|
||||||
actor,
|
|
||||||
%{"bto" => "", "bcc" => [recipient.ap_id]}
|
|
||||||
)
|
|
||||||
end
|
|
||||||
|
|
||||||
test "returns true when message without addresses fields" do
|
|
||||||
recipient = insert(:user)
|
|
||||||
actor = insert(:user)
|
|
||||||
assert Utils.recipient_in_message(recipient, actor, %{"bccc" => recipient.ap_id})
|
|
||||||
|
|
||||||
assert Utils.recipient_in_message(
|
|
||||||
recipient,
|
|
||||||
actor,
|
|
||||||
%{"btod" => "", "bccc" => [recipient.ap_id]}
|
|
||||||
)
|
|
||||||
end
|
|
||||||
|
|
||||||
test "returns false" do
|
|
||||||
recipient = insert(:user)
|
|
||||||
actor = insert(:user)
|
|
||||||
refute Utils.recipient_in_message(recipient, actor, %{"to" => "ap_id"})
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
describe "lazy_put_activity_defaults/2" do
|
describe "lazy_put_activity_defaults/2" do
|
||||||
test "returns map with id and published data" do
|
test "returns map with id and published data" do
|
||||||
note_activity = insert(:note_activity)
|
note_activity = insert(:note_activity)
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@ defmodule Pleroma.Web.MastodonAPI.MarkerControllerTest do
|
||||||
alias Pleroma.Notification
|
alias Pleroma.Notification
|
||||||
alias Pleroma.Repo
|
alias Pleroma.Repo
|
||||||
alias Pleroma.Web.CommonAPI
|
alias Pleroma.Web.CommonAPI
|
||||||
|
alias Pleroma.Web.CommonAPI.Utils
|
||||||
|
|
||||||
import Pleroma.Factory
|
import Pleroma.Factory
|
||||||
|
|
||||||
|
|
@ -33,7 +34,7 @@ defmodule Pleroma.Web.MastodonAPI.MarkerControllerTest do
|
||||||
assert response == %{
|
assert response == %{
|
||||||
"notifications" => %{
|
"notifications" => %{
|
||||||
"last_read_id" => "69420",
|
"last_read_id" => "69420",
|
||||||
"updated_at" => NaiveDateTime.to_iso8601(marker.updated_at),
|
"updated_at" => Utils.to_masto_date(marker.updated_at),
|
||||||
"version" => 0,
|
"version" => 0,
|
||||||
"pleroma" => %{"unread_count" => 7}
|
"pleroma" => %{"unread_count" => 7}
|
||||||
}
|
}
|
||||||
|
|
@ -107,7 +108,7 @@ defmodule Pleroma.Web.MastodonAPI.MarkerControllerTest do
|
||||||
assert response == %{
|
assert response == %{
|
||||||
"notifications" => %{
|
"notifications" => %{
|
||||||
"last_read_id" => "69888",
|
"last_read_id" => "69888",
|
||||||
"updated_at" => NaiveDateTime.to_iso8601(marker.updated_at),
|
"updated_at" => Utils.to_masto_date(marker.updated_at),
|
||||||
"version" => 0,
|
"version" => 0,
|
||||||
"pleroma" => %{"unread_count" => 0}
|
"pleroma" => %{"unread_count" => 0}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@
|
||||||
|
|
||||||
defmodule Pleroma.Web.MastodonAPI.MarkerViewTest do
|
defmodule Pleroma.Web.MastodonAPI.MarkerViewTest do
|
||||||
use Pleroma.DataCase, async: true
|
use Pleroma.DataCase, async: true
|
||||||
|
alias Pleroma.Web.CommonAPI.Utils
|
||||||
alias Pleroma.Web.MastodonAPI.MarkerView
|
alias Pleroma.Web.MastodonAPI.MarkerView
|
||||||
import Pleroma.Factory
|
import Pleroma.Factory
|
||||||
|
|
||||||
|
|
@ -14,16 +15,25 @@ defmodule Pleroma.Web.MastodonAPI.MarkerViewTest do
|
||||||
assert MarkerView.render("markers.json", %{markers: [marker1, marker2]}) == %{
|
assert MarkerView.render("markers.json", %{markers: [marker1, marker2]}) == %{
|
||||||
"home" => %{
|
"home" => %{
|
||||||
last_read_id: "42",
|
last_read_id: "42",
|
||||||
updated_at: NaiveDateTime.to_iso8601(marker2.updated_at),
|
updated_at: Utils.to_masto_date(marker2.updated_at),
|
||||||
version: 0,
|
version: 0,
|
||||||
pleroma: %{unread_count: 0}
|
pleroma: %{unread_count: 0}
|
||||||
},
|
},
|
||||||
"notifications" => %{
|
"notifications" => %{
|
||||||
last_read_id: "17",
|
last_read_id: "17",
|
||||||
updated_at: NaiveDateTime.to_iso8601(marker1.updated_at),
|
updated_at: Utils.to_masto_date(marker1.updated_at),
|
||||||
version: 0,
|
version: 0,
|
||||||
pleroma: %{unread_count: 5}
|
pleroma: %{unread_count: 5}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
test "renders updated_at in the Mastodon date format" do
|
||||||
|
marker = insert(:marker, timeline: "home")
|
||||||
|
|
||||||
|
%{"home" => %{updated_at: updated_at}} =
|
||||||
|
MarkerView.render("markers.json", %{markers: [marker]})
|
||||||
|
|
||||||
|
assert updated_at =~ ~r/\.\d{3}Z$/
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -45,6 +45,18 @@ defmodule Pleroma.Web.MediaProxyTest do
|
||||||
assert MediaProxy.url(local_root) == local_root
|
assert MediaProxy.url(local_root) == local_root
|
||||||
end
|
end
|
||||||
|
|
||||||
|
test "ignores data url" do
|
||||||
|
assert MediaProxy.url("data:image/png;base64,AAAA") == "data:image/png;base64,AAAA"
|
||||||
|
assert MediaProxy.url("DATA:image/png;base64,AAAA") == "DATA:image/png;base64,AAAA"
|
||||||
|
end
|
||||||
|
|
||||||
|
test "preview_url ignores data url" do
|
||||||
|
clear_config([:media_preview_proxy, :enabled], true)
|
||||||
|
|
||||||
|
assert MediaProxy.preview_url("data:image/png;base64,AAAA") ==
|
||||||
|
"data:image/png;base64,AAAA"
|
||||||
|
end
|
||||||
|
|
||||||
test "encodes and decodes URL" do
|
test "encodes and decodes URL" do
|
||||||
url = "https://pleroma.soykaf.com/static/logo.png"
|
url = "https://pleroma.soykaf.com/static/logo.png"
|
||||||
encoded = MediaProxy.url(url)
|
encoded = MediaProxy.url(url)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue