summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGELOG.md1
-rw-r--r--lib/pleroma/emoji.ex53
-rw-r--r--lib/pleroma/web/activity_pub/builder.ex81
-rw-r--r--lib/pleroma/web/activity_pub/object_validators/emoji_react_validator.ex47
-rw-r--r--lib/pleroma/web/activity_pub/utils.ex70
-rw-r--r--lib/pleroma/web/api_spec/operations/account_operation.ex2
-rw-r--r--lib/pleroma/web/feed/feed_view.ex10
-rw-r--r--lib/pleroma/web/mastodon_api/controllers/account_controller.ex7
-rw-r--r--lib/pleroma/web/mastodon_api/views/instance_view.ex1
-rw-r--r--lib/pleroma/web/mastodon_api/views/notification_view.ex5
-rw-r--r--lib/pleroma/web/mastodon_api/views/status_view.ex12
-rw-r--r--lib/pleroma/web/metadata/providers/rel_me.ex14
-rw-r--r--lib/pleroma/web/metadata/utils.ex5
-rw-r--r--lib/pleroma/web/pleroma_api/controllers/emoji_reaction_controller.ex21
-rw-r--r--lib/pleroma/web/pleroma_api/views/emoji_reaction_view.ex17
-rw-r--r--lib/pleroma/web/plugs/authentication_plug.ex8
-rw-r--r--lib/pleroma/web/router.ex3
-rw-r--r--lib/pleroma/web/templates/feed/feed/_activity.atom.eex4
-rw-r--r--lib/pleroma/web/templates/feed/feed/_activity.rss.eex2
-rw-r--r--lib/pleroma/web/templates/feed/feed/_tag_activity.atom.eex4
-rw-r--r--lib/pleroma/web/templates/feed/feed/_tag_activity.xml.eex2
-rw-r--r--lib/pleroma/workers/receiver_worker.ex3
-rw-r--r--mix.exs1
-rw-r--r--mix.lock1
-rw-r--r--test/fixtures/custom-emoji-reaction.json28
-rw-r--r--test/pleroma/web/activity_pub/object_validators/emoji_react_handling_test.exs60
-rw-r--r--test/pleroma/web/activity_pub/side_effects_test.exs2
-rw-r--r--test/pleroma/web/activity_pub/transmogrifier/emoji_react_handling_test.exs53
-rw-r--r--test/pleroma/web/federator_test.exs2
-rw-r--r--test/pleroma/web/feed/user_controller_test.exs44
-rw-r--r--test/pleroma/web/mastodon_api/controllers/account_controller_test.exs33
-rw-r--r--test/pleroma/web/mastodon_api/views/notification_view_test.exs42
-rw-r--r--test/pleroma/web/mastodon_api/views/status_view_test.exs42
-rw-r--r--test/pleroma/web/metadata/providers/rel_me_test.exs17
-rw-r--r--test/pleroma/web/metadata/utils_test.exs2
-rw-r--r--test/pleroma/web/pleroma_api/controllers/emoji_reaction_controller_test.exs159
-rw-r--r--test/pleroma/web/plugs/authentication_plug_test.exs30
-rw-r--r--test/pleroma/workers/receiver_worker_test.exs29
38 files changed, 791 insertions, 126 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 1c15cbe3c..52ca2c865 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -15,6 +15,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
- rel="me" was missing its cache
### Removed
+- BREAKING: Support for passwords generated with `crypt(3)` (Gnu Social migration artifact)
## 2.5.1
diff --git a/lib/pleroma/emoji.ex b/lib/pleroma/emoji.ex
index dd65d56ae..43a3447c3 100644
--- a/lib/pleroma/emoji.ex
+++ b/lib/pleroma/emoji.ex
@@ -51,6 +51,8 @@ defmodule Pleroma.Emoji do
@doc "Returns the path of the emoji `name`."
@spec get(String.t()) :: String.t() | nil
def get(name) do
+ name = maybe_strip_name(name)
+
case :ets.lookup(@ets, name) do
[{_, path}] -> path
_ -> nil
@@ -139,6 +141,57 @@ defmodule Pleroma.Emoji do
def is_unicode_emoji?(_), do: false
+ @emoji_regex ~r/:[A-Za-z0-9_-]+(@.+)?:/
+
+ def is_custom_emoji?(s) when is_binary(s), do: Regex.match?(@emoji_regex, s)
+
+ def is_custom_emoji?(_), do: false
+
+ def maybe_strip_name(name) when is_binary(name), do: String.trim(name, ":")
+
+ def maybe_strip_name(name), do: name
+
+ def maybe_quote(name) when is_binary(name) do
+ if is_unicode_emoji?(name) do
+ name
+ else
+ if String.starts_with?(name, ":") do
+ name
+ else
+ ":#{name}:"
+ end
+ end
+ end
+
+ def maybe_quote(name), do: name
+
+ def emoji_url(%{"type" => "EmojiReact", "content" => _, "tag" => []}), do: nil
+
+ def emoji_url(%{"type" => "EmojiReact", "content" => emoji, "tag" => tags}) do
+ emoji = maybe_strip_name(emoji)
+
+ tag =
+ tags
+ |> Enum.find(fn tag ->
+ tag["type"] == "Emoji" && !is_nil(tag["name"]) && tag["name"] == emoji
+ end)
+
+ if is_nil(tag) do
+ nil
+ else
+ tag
+ |> Map.get("icon")
+ |> Map.get("url")
+ end
+ end
+
+ def emoji_url(_), do: nil
+
+ def emoji_name_with_instance(name, url) do
+ url = url |> URI.parse() |> Map.get(:host)
+ "#{name}@#{url}"
+ end
+
emoji_qualification_map =
emojis
|> Enum.filter(&String.contains?(&1, "\uFE0F"))
diff --git a/lib/pleroma/web/activity_pub/builder.ex b/lib/pleroma/web/activity_pub/builder.ex
index 532047599..8eab3a241 100644
--- a/lib/pleroma/web/activity_pub/builder.ex
+++ b/lib/pleroma/web/activity_pub/builder.ex
@@ -16,6 +16,7 @@ defmodule Pleroma.Web.ActivityPub.Builder do
alias Pleroma.Web.ActivityPub.Utils
alias Pleroma.Web.ActivityPub.Visibility
alias Pleroma.Web.CommonAPI.ActivityDraft
+ alias Pleroma.Web.Endpoint
require Pleroma.Constants
@@ -54,13 +55,87 @@ defmodule Pleroma.Web.ActivityPub.Builder do
{:ok, data, []}
end
+ defp unicode_emoji_react(_object, data, emoji) do
+ data
+ |> Map.put("content", emoji)
+ |> Map.put("type", "EmojiReact")
+ end
+
+ defp add_emoji_content(data, emoji, url) do
+ tag = [
+ %{
+ "id" => url,
+ "type" => "Emoji",
+ "name" => Emoji.maybe_quote(emoji),
+ "icon" => %{
+ "type" => "Image",
+ "url" => url
+ }
+ }
+ ]
+
+ data
+ |> Map.put("content", Emoji.maybe_quote(emoji))
+ |> Map.put("type", "EmojiReact")
+ |> Map.put("tag", tag)
+ end
+
+ defp remote_custom_emoji_react(
+ %{data: %{"reactions" => existing_reactions}},
+ data,
+ emoji
+ ) do
+ [emoji_code, instance] = String.split(Emoji.maybe_strip_name(emoji), "@")
+
+ matching_reaction =
+ Enum.find(
+ existing_reactions,
+ fn [name, _, url] ->
+ if url != nil do
+ url = URI.parse(url)
+ url.host == instance && name == emoji_code
+ end
+ end
+ )
+
+ if matching_reaction do
+ [name, _, url] = matching_reaction
+ add_emoji_content(data, name, url)
+ else
+ {:error, "Could not react"}
+ end
+ end
+
+ defp remote_custom_emoji_react(_object, _data, _emoji) do
+ {:error, "Could not react"}
+ end
+
+ defp local_custom_emoji_react(data, emoji) do
+ with %{file: path} = emojo <- Emoji.get(emoji) do
+ url = "#{Endpoint.url()}#{path}"
+ add_emoji_content(data, emojo.code, url)
+ else
+ _ -> {:error, "Emoji does not exist"}
+ end
+ end
+
+ defp custom_emoji_react(object, data, emoji) do
+ if String.contains?(emoji, "@") do
+ remote_custom_emoji_react(object, data, emoji)
+ else
+ local_custom_emoji_react(data, emoji)
+ end
+ end
+
@spec emoji_react(User.t(), Object.t(), String.t()) :: {:ok, map(), keyword()}
def emoji_react(actor, object, emoji) do
with {:ok, data, meta} <- object_action(actor, object) do
data =
- data
- |> Map.put("content", emoji)
- |> Map.put("type", "EmojiReact")
+ if Emoji.is_unicode_emoji?(emoji) do
+ unicode_emoji_react(object, data, emoji)
+ else
+ custom_emoji_react(object, data, emoji)
+ end
{:ok, data, meta}
end
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 0858281e5..a0b82b325 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
@@ -5,8 +5,10 @@
defmodule Pleroma.Web.ActivityPub.ObjectValidators.EmojiReactValidator do
use Ecto.Schema
+ alias Pleroma.Emoji
alias Pleroma.Object
alias Pleroma.Web.ActivityPub.ObjectValidators.CommonFixes
+ alias Pleroma.Web.ActivityPub.ObjectValidators.TagValidator
import Ecto.Changeset
import Pleroma.Web.ActivityPub.ObjectValidators.CommonValidations
@@ -19,6 +21,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.EmojiReactValidator do
import Elixir.Pleroma.Web.ActivityPub.ObjectValidators.CommonFields
message_fields()
activity_fields()
+ embeds_many(:tag, TagValidator)
end
end
@@ -43,7 +46,8 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.EmojiReactValidator do
def changeset(struct, data) do
struct
- |> cast(data, __schema__(:fields))
+ |> cast(data, __schema__(:fields) -- [:tag])
+ |> cast_embed(:tag)
end
defp fix(data) do
@@ -53,12 +57,16 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.EmojiReactValidator do
|> CommonFixes.fix_actor()
|> CommonFixes.fix_activity_addressing()
- with %Object{} = object <- Object.normalize(data["object"]) do
- data
- |> CommonFixes.fix_activity_context(object)
- |> CommonFixes.fix_object_action_recipients(object)
- else
- _ -> data
+ data = Map.put_new(data, "tag", [])
+
+ case Object.normalize(data["object"]) do
+ %Object{} = object ->
+ data
+ |> CommonFixes.fix_activity_context(object)
+ |> CommonFixes.fix_object_action_recipients(object)
+
+ _ ->
+ data
end
end
@@ -82,11 +90,31 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.EmojiReactValidator do
defp validate_emoji(cng) do
content = get_field(cng, :content)
- if Pleroma.Emoji.is_unicode_emoji?(content) do
+ if Emoji.is_unicode_emoji?(content) || Emoji.is_custom_emoji?(content) do
cng
else
cng
- |> add_error(:content, "must be a single character emoji")
+ |> add_error(:content, "is not a valid emoji")
+ end
+ end
+
+ defp maybe_validate_tag_presence(cng) do
+ content = get_field(cng, :content)
+
+ if Emoji.is_unicode_emoji?(content) do
+ cng
+ else
+ tag = get_field(cng, :tag)
+ emoji_name = Emoji.maybe_strip_name(content)
+
+ case tag do
+ [%{name: ^emoji_name, type: "Emoji", icon: %{url: _}}] ->
+ cng
+
+ _ ->
+ cng
+ |> add_error(:tag, "does not contain an Emoji tag")
+ end
end
end
@@ -97,5 +125,6 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.EmojiReactValidator do
|> validate_actor_presence()
|> validate_object_presence()
|> validate_emoji()
+ |> maybe_validate_tag_presence()
end
end
diff --git a/lib/pleroma/web/activity_pub/utils.ex b/lib/pleroma/web/activity_pub/utils.ex
index b898d6fe8..db7f79dac 100644
--- a/lib/pleroma/web/activity_pub/utils.ex
+++ b/lib/pleroma/web/activity_pub/utils.ex
@@ -325,21 +325,29 @@ defmodule Pleroma.Web.ActivityPub.Utils do
{:ok, Object.t()} | {:error, Ecto.Changeset.t()}
def add_emoji_reaction_to_object(
- %Activity{data: %{"content" => emoji, "actor" => actor}},
+ %Activity{data: %{"content" => emoji, "actor" => actor}} = activity,
object
) do
reactions = get_cached_emoji_reactions(object)
+ emoji = Pleroma.Emoji.maybe_strip_name(emoji)
+ url = maybe_emoji_url(emoji, activity)
new_reactions =
- case Enum.find_index(reactions, fn [candidate, _] -> emoji == candidate end) do
+ case Enum.find_index(reactions, fn [candidate, _, candidate_url] ->
+ if is_nil(candidate_url) do
+ emoji == candidate
+ else
+ url == candidate_url
+ end
+ end) do
nil ->
- reactions ++ [[emoji, [actor]]]
+ reactions ++ [[emoji, [actor], url]]
index ->
List.update_at(
reactions,
index,
- fn [emoji, users] -> [emoji, Enum.uniq([actor | users])] end
+ fn [emoji, users, url] -> [emoji, Enum.uniq([actor | users]), url] end
)
end
@@ -348,18 +356,40 @@ defmodule Pleroma.Web.ActivityPub.Utils do
update_element_in_object("reaction", new_reactions, object, count)
end
+ defp maybe_emoji_url(
+ name,
+ %Activity{
+ data: %{
+ "tag" => [
+ %{"type" => "Emoji", "name" => name, "icon" => %{"url" => url}}
+ ]
+ }
+ }
+ ),
+ do: url
+
+ defp maybe_emoji_url(_, _), do: nil
+
def emoji_count(reactions_list) do
- Enum.reduce(reactions_list, 0, fn [_, users], acc -> acc + length(users) end)
+ Enum.reduce(reactions_list, 0, fn [_, users, _], acc -> acc + length(users) end)
end
def remove_emoji_reaction_from_object(
- %Activity{data: %{"content" => emoji, "actor" => actor}},
+ %Activity{data: %{"content" => emoji, "actor" => actor}} = activity,
object
) do
+ emoji = Pleroma.Emoji.maybe_strip_name(emoji)
reactions = get_cached_emoji_reactions(object)
+ url = maybe_emoji_url(emoji, activity)
new_reactions =
- case Enum.find_index(reactions, fn [candidate, _] -> emoji == candidate end) do
+ case Enum.find_index(reactions, fn [candidate, _, candidate_url] ->
+ if is_nil(candidate_url) do
+ emoji == candidate
+ else
+ url == candidate_url
+ end
+ end) do
nil ->
reactions
@@ -367,9 +397,9 @@ defmodule Pleroma.Web.ActivityPub.Utils do
List.update_at(
reactions,
index,
- fn [emoji, users] -> [emoji, List.delete(users, actor)] end
+ fn [emoji, users, url] -> [emoji, List.delete(users, actor), url] end
)
- |> Enum.reject(fn [_, users] -> Enum.empty?(users) end)
+ |> Enum.reject(fn [_, users, _] -> Enum.empty?(users) end)
end
count = emoji_count(new_reactions)
@@ -489,17 +519,37 @@ defmodule Pleroma.Web.ActivityPub.Utils do
def get_latest_reaction(internal_activity_id, %{ap_id: ap_id}, emoji) do
%{data: %{"object" => object_ap_id}} = Activity.get_by_id(internal_activity_id)
+ emoji = Pleroma.Emoji.maybe_quote(emoji)
"EmojiReact"
|> Activity.Queries.by_type()
|> where(actor: ^ap_id)
- |> where([activity], fragment("?->>'content' = ?", activity.data, ^emoji))
+ |> custom_emoji_discriminator(emoji)
|> Activity.Queries.by_object_id(object_ap_id)
|> order_by([activity], fragment("? desc nulls last", activity.id))
|> limit(1)
|> Repo.one()
end
+ defp custom_emoji_discriminator(query, emoji) do
+ if String.contains?(emoji, "@") do
+ stripped = Pleroma.Emoji.maybe_strip_name(emoji)
+ [name, domain] = String.split(stripped, "@")
+ domain_pattern = "%/" <> domain <> "/%"
+ emoji_pattern = Pleroma.Emoji.maybe_quote(name)
+
+ query
+ |> where([activity], fragment("?->>'content' = ?
+ AND EXISTS (
+ SELECT FROM jsonb_array_elements(?->'tag') elem
+ WHERE elem->>'id' ILIKE ?
+ )", activity.data, ^emoji_pattern, activity.data, ^domain_pattern))
+ else
+ query
+ |> where([activity], fragment("?->>'content' = ?", activity.data, ^emoji))
+ end
+ end
+
#### Announce-related helpers
@doc """
diff --git a/lib/pleroma/web/api_spec/operations/account_operation.ex b/lib/pleroma/web/api_spec/operations/account_operation.ex
index 294590186..f2897a3a3 100644
--- a/lib/pleroma/web/api_spec/operations/account_operation.ex
+++ b/lib/pleroma/web/api_spec/operations/account_operation.ex
@@ -452,7 +452,7 @@ defmodule Pleroma.Web.ApiSpec.AccountOperation do
operationId: "AccountController.blocks",
description: "View your blocks. See also accounts/:id/{block,unblock}",
security: [%{"oAuth" => ["read:blocks"]}],
- parameters: pagination_params(),
+ parameters: [with_relationships_param() | pagination_params()],
responses: %{
200 => Operation.response("Accounts", "application/json", array_of_accounts())
}
diff --git a/lib/pleroma/web/feed/feed_view.ex b/lib/pleroma/web/feed/feed_view.ex
index 449659f4b..034722eb2 100644
--- a/lib/pleroma/web/feed/feed_view.ex
+++ b/lib/pleroma/web/feed/feed_view.ex
@@ -6,7 +6,6 @@ defmodule Pleroma.Web.Feed.FeedView do
use Phoenix.HTML
use Pleroma.Web, :view
- alias Pleroma.Formatter
alias Pleroma.Object
alias Pleroma.User
alias Pleroma.Web.Gettext
@@ -72,7 +71,9 @@ defmodule Pleroma.Web.Feed.FeedView do
def last_activity(activities), do: List.last(activities)
- def activity_title(%{"content" => content, "summary" => summary} = data, opts \\ %{}) do
+ def activity_title(%{"content" => content} = data, opts \\ %{}) do
+ summary = Map.get(data, "summary", "")
+
title =
cond do
summary != "" -> summary
@@ -81,9 +82,8 @@ defmodule Pleroma.Web.Feed.FeedView do
end
title
- |> Pleroma.Web.Metadata.Utils.scrub_html()
- |> Pleroma.Emoji.Formatter.demojify()
- |> Formatter.truncate(opts[:max_length], opts[:omission])
+ |> Pleroma.Web.Metadata.Utils.scrub_html_and_truncate(opts[:max_length], opts[:omission])
+ |> HtmlEntities.encode()
end
def activity_description(data) do
diff --git a/lib/pleroma/web/mastodon_api/controllers/account_controller.ex b/lib/pleroma/web/mastodon_api/controllers/account_controller.ex
index 02dfc552f..c313a0e97 100644
--- a/lib/pleroma/web/mastodon_api/controllers/account_controller.ex
+++ b/lib/pleroma/web/mastodon_api/controllers/account_controller.ex
@@ -540,7 +540,12 @@ defmodule Pleroma.Web.MastodonAPI.AccountController do
conn
|> add_link_headers(users)
- |> render("index.json", users: users, for: user, as: :user)
+ |> render("index.json",
+ users: users,
+ for: user,
+ as: :user,
+ embed_relationships: embed_relationships?(params)
+ )
end
@doc "GET /api/v1/accounts/lookup"
diff --git a/lib/pleroma/web/mastodon_api/views/instance_view.ex b/lib/pleroma/web/mastodon_api/views/instance_view.ex
index abf7f29ab..efd2a0af6 100644
--- a/lib/pleroma/web/mastodon_api/views/instance_view.ex
+++ b/lib/pleroma/web/mastodon_api/views/instance_view.ex
@@ -92,6 +92,7 @@ defmodule Pleroma.Web.MastodonAPI.InstanceView do
"safe_dm_mentions"
end,
"pleroma_emoji_reactions",
+ "pleroma_custom_emoji_reactions",
"pleroma_chat_messages",
if Config.get([:instance, :show_reactions]) do
"exposable_reactions"
diff --git a/lib/pleroma/web/mastodon_api/views/notification_view.ex b/lib/pleroma/web/mastodon_api/views/notification_view.ex
index b5b5b2376..2a51f3755 100644
--- a/lib/pleroma/web/mastodon_api/views/notification_view.ex
+++ b/lib/pleroma/web/mastodon_api/views/notification_view.ex
@@ -17,6 +17,7 @@ defmodule Pleroma.Web.MastodonAPI.NotificationView do
alias Pleroma.Web.MastodonAPI.AccountView
alias Pleroma.Web.MastodonAPI.NotificationView
alias Pleroma.Web.MastodonAPI.StatusView
+ alias Pleroma.Web.MediaProxy
alias Pleroma.Web.PleromaAPI.Chat.MessageReferenceView
defp object_id_for(%{data: %{"object" => %{"id" => id}}}) when is_binary(id), do: id
@@ -145,7 +146,9 @@ defmodule Pleroma.Web.MastodonAPI.NotificationView do
end
defp put_emoji(response, activity) do
- Map.put(response, :emoji, activity.data["content"])
+ response
+ |> Map.put(:emoji, activity.data["content"])
+ |> Map.put(:emoji_url, MediaProxy.url(Pleroma.Emoji.emoji_url(activity.data)))
end
defp put_chat_message(response, activity, reading_user, opts) do
diff --git a/lib/pleroma/web/mastodon_api/views/status_view.ex b/lib/pleroma/web/mastodon_api/views/status_view.ex
index 0a8c98b44..95efd9fd0 100644
--- a/lib/pleroma/web/mastodon_api/views/status_view.ex
+++ b/lib/pleroma/web/mastodon_api/views/status_view.ex
@@ -340,8 +340,8 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do
opts[:for],
Map.get(opts, :with_muted, false)
)
- |> Stream.map(fn {emoji, users} ->
- build_emoji_map(emoji, users, opts[:for])
+ |> Stream.map(fn {emoji, users, url} ->
+ build_emoji_map(emoji, users, url, opts[:for])
end)
|> Enum.to_list()
@@ -702,11 +702,13 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do
end
end
- defp build_emoji_map(emoji, users, current_user) do
+ defp build_emoji_map(emoji, users, url, current_user) do
%{
- name: emoji,
+ name: Pleroma.Web.PleromaAPI.EmojiReactionView.emoji_name(emoji, url),
count: length(users),
- me: !!(current_user && current_user.ap_id in users)
+ url: MediaProxy.url(url),
+ me: !!(current_user && current_user.ap_id in users),
+ account_ids: Enum.map(users, fn user -> User.get_cached_by_ap_id(user).id end)
}
end
diff --git a/lib/pleroma/web/metadata/providers/rel_me.ex b/lib/pleroma/web/metadata/providers/rel_me.ex
index f0bee85c8..eabd8cb00 100644
--- a/lib/pleroma/web/metadata/providers/rel_me.ex
+++ b/lib/pleroma/web/metadata/providers/rel_me.ex
@@ -8,12 +8,20 @@ defmodule Pleroma.Web.Metadata.Providers.RelMe do
@impl Provider
def build_tags(%{user: user}) do
- bio_tree = Floki.parse_fragment!(user.bio)
+ profile_tree =
+ user.bio
+ |> append_fields_tag(user.fields)
+ |> Floki.parse_fragment!()
- (Floki.attribute(bio_tree, "link[rel~=me]", "href") ++
- Floki.attribute(bio_tree, "a[rel~=me]", "href"))
+ (Floki.attribute(profile_tree, "link[rel~=me]", "href") ++
+ Floki.attribute(profile_tree, "a[rel~=me]", "href"))
|> Enum.map(fn link ->
{:link, [rel: "me", href: link], []}
end)
end
+
+ defp append_fields_tag(bio, fields) do
+ fields
+ |> Enum.reduce(bio, fn %{"value" => v}, res -> res <> v end)
+ end
end
diff --git a/lib/pleroma/web/metadata/utils.ex b/lib/pleroma/web/metadata/utils.ex
index 15414a988..80a8be9a2 100644
--- a/lib/pleroma/web/metadata/utils.ex
+++ b/lib/pleroma/web/metadata/utils.ex
@@ -30,12 +30,13 @@ defmodule Pleroma.Web.Metadata.Utils do
|> scrub_html_and_truncate_object_field(object)
end
- def scrub_html_and_truncate(content, max_length \\ 200) when is_binary(content) do
+ def scrub_html_and_truncate(content, max_length \\ 200, omission \\ "...")
+ when is_binary(content) do
content
|> scrub_html
|> Emoji.Formatter.demojify()
|> HtmlEntities.decode()
- |> Formatter.truncate(max_length)
+ |> Formatter.truncate(max_length, omission)
end
def scrub_html(content) when is_binary(content) do
diff --git a/lib/pleroma/web/pleroma_api/controllers/emoji_reaction_controller.ex b/lib/pleroma/web/pleroma_api/controllers/emoji_reaction_controller.ex
index 78fd0b219..e095fa04a 100644
--- a/lib/pleroma/web/pleroma_api/controllers/emoji_reaction_controller.ex
+++ b/lib/pleroma/web/pleroma_api/controllers/emoji_reaction_controller.ex
@@ -50,29 +50,35 @@ defmodule Pleroma.Web.PleromaAPI.EmojiReactionController do
if not with_muted, do: User.cached_muted_users_ap_ids(user), else: []
end
- filter_emoji = fn emoji, users ->
+ filter_emoji = fn emoji, users, url ->
case Enum.reject(users, &(&1 in exclude_ap_ids)) do
[] -> nil
- users -> {emoji, users}
+ users -> {emoji, users, url}
end
end
reactions
|> Stream.map(fn
- [emoji, users] when is_list(users) -> filter_emoji.(emoji, users)
- {emoji, users} when is_list(users) -> filter_emoji.(emoji, users)
+ [emoji, users, url] when is_list(users) -> filter_emoji.(emoji, users, url)
+ {emoji, users, url} when is_list(users) -> filter_emoji.(emoji, users, url)
+ {emoji, users} when is_list(users) -> filter_emoji.(emoji, users, nil)
_ -> nil
end)
|> Stream.reject(&is_nil/1)
end
defp filter(reactions, %{emoji: emoji}) when is_binary(emoji) do
- Enum.filter(reactions, fn [e, _] -> e == emoji end)
+ Enum.filter(reactions, fn [e, _, _] -> e == emoji end)
end
defp filter(reactions, _), do: reactions
def create(%{assigns: %{user: user}} = conn, %{id: activity_id, emoji: emoji}) do
+ emoji =
+ emoji
+ |> Pleroma.Emoji.fully_qualify_emoji()
+ |> Pleroma.Emoji.maybe_quote()
+
with {:ok, _activity} <- CommonAPI.react_with_emoji(activity_id, user, emoji) do
activity = Activity.get_by_id(activity_id)
@@ -83,6 +89,11 @@ defmodule Pleroma.Web.PleromaAPI.EmojiReactionController do
end
def delete(%{assigns: %{user: user}} = conn, %{id: activity_id, emoji: emoji}) do
+ emoji =
+ emoji
+ |> Pleroma.Emoji.fully_qualify_emoji()
+ |> Pleroma.Emoji.maybe_quote()
+
with {:ok, _activity} <- CommonAPI.unreact_with_emoji(activity_id, user, emoji) do
activity = Activity.get_by_id(activity_id)
diff --git a/lib/pleroma/web/pleroma_api/views/emoji_reaction_view.ex b/lib/pleroma/web/pleroma_api/views/emoji_reaction_view.ex
index 68ebd8292..6df4ab9d0 100644
--- a/lib/pleroma/web/pleroma_api/views/emoji_reaction_view.ex
+++ b/lib/pleroma/web/pleroma_api/views/emoji_reaction_view.ex
@@ -7,17 +7,30 @@ defmodule Pleroma.Web.PleromaAPI.EmojiReactionView do
alias Pleroma.Web.MastodonAPI.AccountView
+ def emoji_name(emoji, nil), do: emoji
+
+ def emoji_name(emoji, url) do
+ url = URI.parse(url)
+
+ if url.host == Pleroma.Web.Endpoint.host() do
+ emoji
+ else
+ "#{emoji}@#{url.host}"
+ end
+ end
+
def render("index.json", %{emoji_reactions: emoji_reactions} = opts) do
render_many(emoji_reactions, __MODULE__, "show.json", opts)
end
- def render("show.json", %{emoji_reaction: {emoji, user_ap_ids}, user: user}) do
+ def render("show.json", %{emoji_reaction: {emoji, user_ap_ids, url}, user: user}) do
users = fetch_users(user_ap_ids)
%{
- name: emoji,
+ name: emoji_name(emoji, url),
count: length(users),
accounts: render(AccountView, "index.json", users: users, for: user),
+ url: Pleroma.Web.MediaProxy.url(url),
me: !!(user && user.ap_id in user_ap_ids)
}
end
diff --git a/lib/pleroma/web/plugs/authentication_plug.ex b/lib/pleroma/web/plugs/authentication_plug.ex
index a7fd697b5..f912a1542 100644
--- a/lib/pleroma/web/plugs/authentication_plug.ex
+++ b/lib/pleroma/web/plugs/authentication_plug.ex
@@ -38,10 +38,6 @@ defmodule Pleroma.Web.Plugs.AuthenticationPlug do
def call(conn, _), do: conn
- def checkpw(password, "$6" <> _ = password_hash) do
- :crypt.crypt(password, password_hash) == password_hash
- end
-
def checkpw(password, "$2" <> _ = password_hash) do
# Handle bcrypt passwords for Mastodon migration
Bcrypt.verify_pass(password, password_hash)
@@ -60,10 +56,6 @@ defmodule Pleroma.Web.Plugs.AuthenticationPlug do
do_update_password(user, password)
end
- def maybe_update_password(%User{password_hash: "$6" <> _} = user, password) do
- do_update_password(user, password)
- end
-
def maybe_update_password(user, _), do: {:ok, user}
defp do_update_password(user, password) do
diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex
index ba1d64ab2..c1a690e28 100644
--- a/lib/pleroma/web/router.ex
+++ b/lib/pleroma/web/router.ex
@@ -835,8 +835,7 @@ defmodule Pleroma.Web.Router do
end
scope "/", Pleroma.Web do
- # Note: html format is supported only if static FE is enabled
- pipe_through([:accepts_html_xml, :static_fe])
+ pipe_through([:accepts_html_xml])
get("/users/:nickname/feed", Feed.UserController, :feed, as: :user_feed)
end
diff --git a/lib/pleroma/web/templates/feed/feed/_activity.atom.eex b/lib/pleroma/web/templates/feed/feed/_activity.atom.eex
index 260338772..b774f7984 100644
--- a/lib/pleroma/web/templates/feed/feed/_activity.atom.eex
+++ b/lib/pleroma/web/templates/feed/feed/_activity.atom.eex
@@ -4,8 +4,8 @@
<id><%= @data["id"] %></id>
<title><%= activity_title(@data, Keyword.get(@feed_config, :post_title, %{})) %></title>
<content type="html"><%= activity_description(@data) %></content>
- <published><%= to_rfc3339(@activity.data["published"]) %></published>
- <updated><%= to_rfc3339(@activity.data["published"]) %></updated>
+ <published><%= to_rfc3339(@data["published"]) %></published>
+ <updated><%= to_rfc3339(@data["published"]) %></updated>
<ostatus:conversation ref="<%= activity_context(@activity) %>">
<%= activity_context(@activity) %>
</ostatus:conversation>
diff --git a/lib/pleroma/web/templates/feed/feed/_activity.rss.eex b/lib/pleroma/web/templates/feed/feed/_activity.rss.eex
index 5c8f35fe4..7de98f736 100644
--- a/lib/pleroma/web/templates/feed/feed/_activity.rss.eex
+++ b/lib/pleroma/web/templates/feed/feed/_activity.rss.eex
@@ -4,7 +4,7 @@
<guid><%= @data["id"] %></guid>
<title><%= activity_title(@data, Keyword.get(@feed_config, :post_title, %{})) %></title>
<description><%= activity_description(@data) %></description>
- <pubDate><%= to_rfc2822(@activity.data["published"]) %></pubDate>
+ <pubDate><%= to_rfc2822(@data["published"]) %></pubDate>
<ostatus:conversation ref="<%= activity_context(@activity) %>">
<%= activity_context(@activity) %>
</ostatus:conversation>
diff --git a/lib/pleroma/web/templates/feed/feed/_tag_activity.atom.eex b/lib/pleroma/web/templates/feed/feed/_tag_activity.atom.eex
index 25980c1e4..03c222975 100644
--- a/lib/pleroma/web/templates/feed/feed/_tag_activity.atom.eex
+++ b/lib/pleroma/web/templates/feed/feed/_tag_activity.atom.eex
@@ -7,8 +7,8 @@
<id><%= @data["id"] %></id>
<title><%= activity_title(@data, Keyword.get(@feed_config, :post_title, %{})) %></title>
<content type="html"><%= activity_description(@data) %></content>
- <published><%= to_rfc3339(@activity.data["published"]) %></published>
- <updated><%= to_rfc3339(@activity.data["published"]) %></updated>
+ <published><%= to_rfc3339(@data["published"]) %></published>
+ <updated><%= to_rfc3339(@data["published"]) %></updated>
<ostatus:conversation ref="<%= activity_context(@activity) %>">
<%= activity_context(@activity) %>
</ostatus:conversation>
diff --git a/lib/pleroma/web/templates/feed/feed/_tag_activity.xml.eex b/lib/pleroma/web/templates/feed/feed/_tag_activity.xml.eex
index d582c83e8..1b8c34b87 100644
--- a/lib/pleroma/web/templates/feed/feed/_tag_activity.xml.eex
+++ b/lib/pleroma/web/templates/feed/feed/_tag_activity.xml.eex
@@ -4,7 +4,7 @@
<guid isPermalink="true"><%= activity_context(@activity) %></guid>
<link><%= activity_context(@activity) %></link>
- <pubDate><%= to_rfc2822(@activity.data["published"]) %></pubDate>
+ <pubDate><%= to_rfc2822(@data["published"]) %></pubDate>
<description><%= activity_description(@data) %></description>
<%= for attachment <- @data["attachment"] || [] do %>
diff --git a/lib/pleroma/workers/receiver_worker.ex b/lib/pleroma/workers/receiver_worker.ex
index 4f513b907..cf1bb62b4 100644
--- a/lib/pleroma/workers/receiver_worker.ex
+++ b/lib/pleroma/workers/receiver_worker.ex
@@ -13,6 +13,9 @@ defmodule Pleroma.Workers.ReceiverWorker do
{:ok, res}
else
{:error, :origin_containment_failed} -> {:cancel, :origin_containment_failed}
+ {:error, :already_present} -> {:cancel, :already_present}
+ {:error, {:validate_object, reason}} -> {:cancel, reason}
+ {:error, {:error, {:validate, reason}}} -> {:cancel, reason}
{:error, {:reject, reason}} -> {:cancel, reason}
e -> e
end
diff --git a/mix.exs b/mix.exs
index 8aa18d5ee..0cc57d51c 100644
--- a/mix.exs
+++ b/mix.exs
@@ -150,7 +150,6 @@ defmodule Pleroma.Mixfile do
{:sweet_xml, "~> 0.7.2"},
{:earmark, "~> 1.4.22"},
{:bbcode_pleroma, "~> 0.2.0"},
- {:crypt, "~> 1.0"},
{:cors_plug, "~> 2.0"},
{:web_push_encryption, "~> 0.3.1"},
{:swoosh, "~> 1.0"},
diff --git a/mix.lock b/mix.lock
index e5ce7b36a..f2336cf87 100644
--- a/mix.lock
+++ b/mix.lock
@@ -21,7 +21,6 @@
"cowlib": {:hex, :cowlib, "2.11.0", "0b9ff9c346629256c42ebe1eeb769a83c6cb771a6ee5960bd110ab0b9b872063", [:make, :rebar3], [], "hexpm", "2b3e9da0b21c4565751a6d4901c20d1b4cc25cbb7fd50d91d2ab6dd287bc86a9"},
"credo": {:hex, :credo, "1.6.7", "323f5734350fd23a456f2688b9430e7d517afb313fbd38671b8a4449798a7854", [:mix], [{:bunt, "~> 0.2.1", [hex: :bunt, repo: "hexpm", optional: false]}, {:file_system, "~> 0.2.8", [hex: :file_system, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "41e110bfb007f7eda7f897c10bf019ceab9a0b269ce79f015d54b0dcf4fc7dd3"},
"crontab": {:hex, :crontab, "1.1.8", "2ce0e74777dfcadb28a1debbea707e58b879e6aa0ffbf9c9bb540887bce43617", [:mix], [{:ecto, "~> 1.0 or ~> 2.0 or ~> 3.0", [hex: :ecto, repo: "hexpm", optional: true]}], "hexpm"},
- "crypt": {:hex, :crypt, "1.0.1", "a3567e1c651a2ec42c6650d9f3ab789e0f12a508c060653a9bbb5fafe60f043c", [:rebar3], [], "hexpm", "968dffe321c7a5d9f9b4577c4a4ff56a1c26d1a8a2270eb22c7636a0b43d3982"},
"custom_base": {:hex, :custom_base, "0.2.1", "4a832a42ea0552299d81652aa0b1f775d462175293e99dfbe4d7dbaab785a706", [:mix], [], "hexpm", "8df019facc5ec9603e94f7270f1ac73ddf339f56ade76a721eaa57c1493ba463"},
"db_connection": {:hex, :db_connection, "2.4.2", "f92e79aff2375299a16bcb069a14ee8615c3414863a6fef93156aee8e86c2ff3", [:mix], [{:connection, "~> 1.0", [hex: :connection, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "4fe53ca91b99f55ea249693a0229356a08f4d1a7931d8ffa79289b145fe83668"},
"decimal": {:hex, :decimal, "2.0.0", "a78296e617b0f5dd4c6caf57c714431347912ffb1d0842e998e9792b5642d697", [:mix], [], "hexpm", "34666e9c55dea81013e77d9d87370fe6cb6291d1ef32f46a1600230b1d44f577"},
diff --git a/test/fixtures/custom-emoji-reaction.json b/test/fixtures/custom-emoji-reaction.json
new file mode 100644
index 000000000..003de0511
--- /dev/null
+++ b/test/fixtures/custom-emoji-reaction.json
@@ -0,0 +1,28 @@
+{
+ "@context": [
+ "https://www.w3.org/ns/activitystreams",
+ "https://w3id.org/security/v1",
+ {
+ "Hashtag": "as:Hashtag"
+ }
+ ],
+ "type": "Like",
+ "id": "https://misskey.local.live/likes/917ocsybgp",
+ "actor": "https://misskey.local.live/users/8x8yep20u2",
+ "object": "https://pleroma.local.live/objects/89937a53-2692-4631-bb62-770091267391",
+ "content": ":hanapog:",
+ "_misskey_reaction": ":hanapog:",
+ "tag": [
+ {
+ "id": "https://misskey.local.live/emojis/hanapog",
+ "type": "Emoji",
+ "name": ":hanapog:",
+ "updated": "2022-06-07T12:00:05.773Z",
+ "icon": {
+ "type": "Image",
+ "mediaType": "image/png",
+ "url": "https://misskey.local.live/files/webpublic-8f8a9768-7264-4171-88d6-2356aabeadcd"
+ }
+ }
+ ]
+}
diff --git a/test/pleroma/web/activity_pub/object_validators/emoji_react_handling_test.exs b/test/pleroma/web/activity_pub/object_validators/emoji_react_handling_test.exs
index bbdb09c4c..9bb291a38 100644
--- a/test/pleroma/web/activity_pub/object_validators/emoji_react_handling_test.exs
+++ b/test/pleroma/web/activity_pub/object_validators/emoji_react_handling_test.exs
@@ -38,16 +38,70 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.EmojiReactHandlingTest do
assert {:content, {"can't be blank", [validation: :required]}} in cng.errors
end
- test "it is not valid with a non-emoji content field", %{valid_emoji_react: valid_emoji_react} do
+ test "it is valid when custom emoji is used", %{valid_emoji_react: valid_emoji_react} do
without_emoji_content =
valid_emoji_react
- |> Map.put("content", "x")
+ |> Map.put("content", ":hello:")
+ |> Map.put("tag", [
+ %{
+ "type" => "Emoji",
+ "name" => ":hello:",
+ "icon" => %{"url" => "http://somewhere", "type" => "Image"}
+ }
+ ])
+
+ {:ok, _, _} = ObjectValidator.validate(without_emoji_content, [])
+ end
+
+ test "it is not valid when custom emoji don't have a matching tag", %{
+ valid_emoji_react: valid_emoji_react
+ } do
+ without_emoji_content =
+ valid_emoji_react
+ |> Map.put("content", ":hello:")
+ |> Map.put("tag", [
+ %{
+ "type" => "Emoji",
+ "name" => ":whoops:",
+ "icon" => %{"url" => "http://somewhere", "type" => "Image"}
+ }
+ ])
+
+ {:error, cng} = ObjectValidator.validate(without_emoji_content, [])
+
+ refute cng.valid?
+
+ assert {:tag, {"does not contain an Emoji tag", []}} in cng.errors
+ end
+
+ test "it is not valid when custom emoji have no tags", %{
+ valid_emoji_react: valid_emoji_react
+ } do
+ without_emoji_content =
+ valid_emoji_react
+ |> Map.put("content", ":hello:")
+ |> Map.put("tag", [])
+
+ {:error, cng} = ObjectValidator.validate(without_emoji_content, [])
+
+ refute cng.valid?
+
+ assert {:tag, {"does not contain an Emoji tag", []}} in cng.errors
+ end
+
+ test "it is not valid when custom emoji doesn't match a shortcode format", %{
+ valid_emoji_react: valid_emoji_react
+ } do
+ without_emoji_content =
+ valid_emoji_react
+ |> Map.put("content", "hello")
+ |> Map.put("tag", [])
{:error, cng} = ObjectValidator.validate(without_emoji_content, [])
refute cng.valid?
- assert {:content, {"must be a single character emoji", []}} in cng.errors
+ assert {:tag, {"does not contain an Emoji tag", []}} in cng.errors
end
end
end
diff --git a/test/pleroma/web/activity_pub/side_effects_test.exs b/test/pleroma/web/activity_pub/side_effects_test.exs
index b24831e85..6820e23d0 100644
--- a/test/pleroma/web/activity_pub/side_effects_test.exs
+++ b/test/pleroma/web/activity_pub/side_effects_test.exs
@@ -453,7 +453,7 @@ defmodule Pleroma.Web.ActivityPub.SideEffectsTest do
object = Object.get_by_ap_id(emoji_react.data["object"])
assert object.data["reaction_count"] == 1
- assert ["👌", [user.ap_id]] in object.data["reactions"]
+ assert ["👌", [user.ap_id], nil] in object.data["reactions"]
end
test "creates a notification", %{emoji_react: emoji_react, poster: poster} do
diff --git a/test/pleroma/web/activity_pub/transmogrifier/emoji_react_handling_test.exs b/test/pleroma/web/activity_pub/transmogrifier/emoji_react_handling_test.exs
index 83bf59c6f..f2e1cefa3 100644
--- a/test/pleroma/web/activity_pub/transmogrifier/emoji_react_handling_test.exs
+++ b/test/pleroma/web/activity_pub/transmogrifier/emoji_react_handling_test.exs
@@ -34,7 +34,56 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.EmojiReactHandlingTest do
object = Object.get_by_ap_id(data["object"])
assert object.data["reaction_count"] == 1
- assert match?([["👌", _]], object.data["reactions"])
+ assert match?([["👌", _, nil]], object.data["reactions"])
+ end
+
+ test "it works for incoming custom emoji reactions" 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)
+
+ {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
+
+ assert data["actor"] == other_user.ap_id
+ assert data["type"] == "EmojiReact"
+ assert data["id"] == "https://misskey.local.live/likes/917ocsybgp"
+ assert data["object"] == activity.data["object"]
+ assert data["content"] == ":hanapog:"
+
+ assert data["tag"] == [
+ %{
+ "id" => "https://misskey.local.live/emojis/hanapog",
+ "type" => "Emoji",
+ "name" => "hanapog",
+ "updated" => "2022-06-07T12:00:05.773Z",
+ "icon" => %{
+ "type" => "Image",
+ "url" =>
+ "https://misskey.local.live/files/webpublic-8f8a9768-7264-4171-88d6-2356aabeadcd"
+ }
+ }
+ ]
+
+ object = Object.get_by_ap_id(data["object"])
+
+ assert object.data["reaction_count"] == 1
+
+ assert match?(
+ [
+ [
+ "hanapog",
+ _,
+ "https://misskey.local.live/files/webpublic-8f8a9768-7264-4171-88d6-2356aabeadcd"
+ ]
+ ],
+ object.data["reactions"]
+ )
end
test "it works for incoming unqualified emoji reactions" do
@@ -65,7 +114,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier.EmojiReactHandlingTest do
object = Object.get_by_ap_id(data["object"])
assert object.data["reaction_count"] == 1
- assert match?([[^emoji, _]], object.data["reactions"])
+ assert match?([[^emoji, _, _]], object.data["reactions"])
end
test "it reject invalid emoji reactions" do
diff --git a/test/pleroma/web/federator_test.exs b/test/pleroma/web/federator_test.exs
index 41d1c5d5e..1ffe6aae1 100644
--- a/test/pleroma/web/federator_test.exs
+++ b/test/pleroma/web/federator_test.exs
@@ -133,7 +133,7 @@ defmodule Pleroma.Web.FederatorTest do
assert {:ok, _activity} = ObanHelpers.perform(job)
assert {:ok, job} = Federator.incoming_ap_doc(params)
- assert {:error, :already_present} = ObanHelpers.perform(job)
+ assert {:cancel, :already_present} = ObanHelpers.perform(job)
end
test "rejects incoming AP docs with incorrect origin" do
diff --git a/test/pleroma/web/feed/user_controller_test.exs b/test/pleroma/web/feed/user_controller_test.exs
index de32d3d4b..d3c4108de 100644
--- a/test/pleroma/web/feed/user_controller_test.exs
+++ b/test/pleroma/web/feed/user_controller_test.exs
@@ -57,9 +57,23 @@ defmodule Pleroma.Web.Feed.UserControllerTest do
)
note_activity2 = insert(:note_activity, note: note2)
+
+ note3 =
+ insert(:note,
+ user: user,
+ data: %{
+ "content" => "This note tests whether HTML entities are truncated properly",
+ "summary" => "Won't, didn't fail",
+ "inReplyTo" => note_activity2.id
+ }
+ )
+
+ _note_activity3 = insert(:note_activity, note: note3)
object = Object.normalize(note_activity, fetch: false)
- [user: user, object: object, max_id: note_activity2.id]
+ encoded_title = FeedView.activity_title(note3.data)
+
+ [user: user, object: object, max_id: note_activity2.id, encoded_title: encoded_title]
end
test "gets an atom feed", %{conn: conn, user: user, object: object, max_id: max_id} do
@@ -74,7 +88,7 @@ defmodule Pleroma.Web.Feed.UserControllerTest do
|> SweetXml.parse()
|> SweetXml.xpath(~x"//entry/title/text()"l)
- assert activity_titles == ['2hu', '2hu & as']
+ assert activity_titles == ['Won\'t, didn\'...', '2hu', '2hu & as']
assert resp =~ FeedView.escape(object.data["content"])
assert resp =~ FeedView.escape(object.data["summary"])
assert resp =~ FeedView.escape(object.data["context"])
@@ -105,7 +119,7 @@ defmodule Pleroma.Web.Feed.UserControllerTest do
|> SweetXml.parse()
|> SweetXml.xpath(~x"//item/title/text()"l)
- assert activity_titles == ['2hu', '2hu & as']
+ assert activity_titles == ['Won\'t, didn\'...', '2hu', '2hu & as']
assert resp =~ FeedView.escape(object.data["content"])
assert resp =~ FeedView.escape(object.data["summary"])
assert resp =~ FeedView.escape(object.data["context"])
@@ -176,6 +190,30 @@ defmodule Pleroma.Web.Feed.UserControllerTest do
|> get("/users/#{user.nickname}/feed.rss")
|> response(200)
end
+
+ test "does not mangle HTML entities midway", %{
+ conn: conn,
+ user: user,
+ object: object,
+ encoded_title: encoded_title
+ } do
+ resp =
+ conn
+ |> put_req_header("accept", "application/atom+xml")
+ |> get(user_feed_path(conn, :feed, user.nickname))
+ |> response(200)
+
+ activity_titles =
+ resp
+ |> SweetXml.parse()
+ |> SweetXml.xpath(~x"//entry/title/text()"l)
+
+ assert activity_titles == ['Won\'t, didn\'...', '2hu', '2hu & as']
+ assert resp =~ FeedView.escape(object.data["content"])
+ assert resp =~ FeedView.escape(object.data["summary"])
+ assert resp =~ FeedView.escape(object.data["context"])
+ assert resp =~ encoded_title
+ end
end
# Note: see ActivityPubControllerTest for JSON format tests
diff --git a/test/pleroma/web/mastodon_api/controllers/account_controller_test.exs b/test/pleroma/web/mastodon_api/controllers/account_controller_test.exs
index 958b7f76f..128e60b0a 100644
--- a/test/pleroma/web/mastodon_api/controllers/account_controller_test.exs
+++ b/test/pleroma/web/mastodon_api/controllers/account_controller_test.exs
@@ -2031,6 +2031,39 @@ defmodule Pleroma.Web.MastodonAPI.AccountControllerTest do
assert [%{"id" => ^id1}] = result
end
+ test "list of blocks with with_relationships parameter" do
+ %{user: user, conn: conn} = oauth_access(["read:blocks"])
+ %{id: id1} = other_user1 = insert(:user)
+ %{id: id2} = other_user2 = insert(:user)
+ %{id: id3} = other_user3 = insert(:user)
+
+ {:ok, _, _} = User.follow(other_user1, user)
+ {:ok, _, _} = User.follow(other_user2, user)
+ {:ok, _, _} = User.follow(other_user3, user)
+
+ {:ok, _} = User.block(user, other_user1)
+ {:ok, _} = User.block(user, other_user2)
+ {:ok, _} = User.block(user, other_user3)
+
+ assert [
+ %{
+ "id" => ^id3,
+ "pleroma" => %{"relationship" => %{"blocking" => true, "followed_by" => false}}
+ },
+ %{
+ "id" => ^id2,
+ "pleroma" => %{"relationship" => %{"blocking" => true, "followed_by" => false}}
+ },
+ %{
+ "id" => ^id1,
+ "pleroma" => %{"relationship" => %{"blocking" => true, "followed_by" => false}}
+ }
+ ] =
+ conn
+ |> get("/api/v1/blocks?with_relationships=true")
+ |> json_response_and_validate_schema(200)
+ end
+
test "account lookup", %{conn: conn} do
%{nickname: acct} = insert(:user, %{nickname: "nickname"})
%{nickname: acct_two} = insert(:user, %{nickname: "nickname@notlocaldoma.in"})
diff --git a/test/pleroma/web/mastodon_api/views/notification_view_test.exs b/test/pleroma/web/mastodon_api/views/notification_view_test.exs
index 6ea894691..ddbe4557f 100644
--- a/test/pleroma/web/mastodon_api/views/notification_view_test.exs
+++ b/test/pleroma/web/mastodon_api/views/notification_view_test.exs
@@ -190,7 +190,47 @@ defmodule Pleroma.Web.MastodonAPI.NotificationViewTest do
emoji: "☕",
account: AccountView.render("show.json", %{user: other_user, for: user}),
status: StatusView.render("show.json", %{activity: activity, for: user}),
- created_at: Utils.to_masto_date(notification.inserted_at)
+ created_at: Utils.to_masto_date(notification.inserted_at),
+ emoji_url: nil
+ }
+
+ test_notifications_rendering([notification], user, [expected])
+ end
+
+ test "EmojiReact custom emoji notification" do
+ user = insert(:user)
+ other_user = insert(:user)
+
+ note =
+ insert(:note,
+ user: user,
+ data: %{
+ "reactions" => [
+ ["👍", [user.ap_id], nil],
+ ["dinosaur", [user.ap_id], "http://localhost:4001/emoji/dino walking.gif"]
+ ]
+ }
+ )
+
+ activity = insert(:note_activity, note: note, user: user)
+
+ {:ok, _activity} = CommonAPI.react_with_emoji(activity.id, other_user, "dinosaur")
+
+ activity = Repo.get(Activity, activity.id)
+
+ [notification] = Notification.for_user(user)
+
+ assert notification
+
+ expected = %{
+ id: to_string(notification.id),
+ pleroma: %{is_seen: false, is_muted: false},
+ type: "pleroma:emoji_reaction",
+ emoji: ":dinosaur:",
+ account: AccountView.render("show.json", %{user: other_user, for: user}),
+ status: StatusView.render("show.json", %{activity: activity, for: user}),
+ created_at: Utils.to_masto_date(notification.inserted_at),
+ emoji_url: "http://localhost:4001/emoji/dino walking.gif"
}
test_notifications_rendering([notification], user, [expected])
diff --git a/test/pleroma/web/mastodon_api/views/status_view_test.exs b/test/pleroma/web/mastodon_api/views/status_view_test.exs
index f76b115b7..a1f3e3e1d 100644
--- a/test/pleroma/web/mastodon_api/views/status_view_test.exs
+++ b/test/pleroma/web/mastodon_api/views/status_view_test.exs
@@ -35,16 +35,26 @@ defmodule Pleroma.Web.MastodonAPI.StatusViewTest do
{:ok, activity} = CommonAPI.post(user, %{status: "dae cofe??"})
{:ok, _} = CommonAPI.react_with_emoji(activity.id, user, "☕")
+ {:ok, _} = CommonAPI.react_with_emoji(activity.id, user, ":dinosaur:")
{:ok, _} = CommonAPI.react_with_emoji(activity.id, third_user, "🍵")
{:ok, _} = CommonAPI.react_with_emoji(activity.id, other_user, "☕")
+ {:ok, _} = CommonAPI.react_with_emoji(activity.id, other_user, ":dinosaur:")
+
activity = Repo.get(Activity, activity.id)
status = StatusView.render("show.json", activity: activity)
assert_schema(status, "Status", Pleroma.Web.ApiSpec.spec())
assert status[:pleroma][:emoji_reactions] == [
- %{name: "☕", count: 2, me: false},
- %{name: "🍵", count: 1, me: false}
+ %{name: "☕", count: 2, me: false, url: nil, account_ids: [other_user.id, user.id]},
+ %{
+ count: 2,
+ me: false,
+ name: "dinosaur",
+ url: "http://localhost:4001/emoji/dino walking.gif",
+ account_ids: [other_user.id, user.id]
+ },
+ %{name: "🍵", count: 1, me: false, url: nil, account_ids: [third_user.id]}
]
status = StatusView.render("show.json", activity: activity, for: user)
@@ -52,8 +62,15 @@ defmodule Pleroma.Web.MastodonAPI.StatusViewTest do
assert_schema(status, "Status", Pleroma.Web.ApiSpec.spec())
assert status[:pleroma][:emoji_reactions] == [
- %{name: "☕", count: 2, me: true},
- %{name: "🍵", count: 1, me: false}
+ %{name: "☕", count: 2, me: true, url: nil, account_ids: [other_user.id, user.id]},
+ %{
+ count: 2,
+ me: true,
+ name: "dinosaur",
+ url: "http://localhost:4001/emoji/dino walking.gif",
+ account_ids: [other_user.id, user.id]
+ },
+ %{name: "🍵", count: 1, me: false, url: nil, account_ids: [third_user.id]}
]
end
@@ -66,11 +83,10 @@ defmodule Pleroma.Web.MastodonAPI.StatusViewTest do
|> Object.update_data(%{"reactions" => %{"☕" => [user.ap_id], "x" => 1}})
activity = Activity.get_by_id(activity.id)
-
status = StatusView.render("show.json", activity: activity, for: user)
assert status[:pleroma][:emoji_reactions] == [
- %{name: "☕", count: 1, me: true}
+ %{name: "☕", count: 1, me: true, url: nil, account_ids: [user.id]}
]
end
@@ -90,7 +106,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusViewTest do
status = StatusView.render("show.json", activity: activity)
assert status[:pleroma][:emoji_reactions] == [
- %{name: "☕", count: 1, me: false}
+ %{name: "☕", count: 1, me: false, url: nil, account_ids: [other_user.id]}
]
status = StatusView.render("show.json", activity: activity, for: user)
@@ -102,19 +118,25 @@ defmodule Pleroma.Web.MastodonAPI.StatusViewTest do
status = StatusView.render("show.json", activity: activity)
assert status[:pleroma][:emoji_reactions] == [
- %{name: "☕", count: 2, me: false}
+ %{
+ name: "☕",
+ count: 2,
+ me: false,
+ url: nil,
+ account_ids: [third_user.id, other_user.id]
+ }
]
status = StatusView.render("show.json", activity: activity, for: user)
assert status[:pleroma][:emoji_reactions] == [
- %{name: "☕", count: 1, me: false}
+ %{name: "☕", count: 1, me: false, url: nil, account_ids: [third_user.id]}
]
status = StatusView.render("show.json", activity: activity, for: other_user)
assert status[:pleroma][:emoji_reactions] == [
- %{name: "☕", count: 1, me: true}
+ %{name: "☕", count: 1, me: true, url: nil, account_ids: [other_user.id]}
]
end
diff --git a/test/pleroma/web/metadata/providers/rel_me_test.exs b/test/pleroma/web/metadata/providers/rel_me_test.exs
index cce4f3607..793669037 100644
--- a/test/pleroma/web/metadata/providers/rel_me_test.exs
+++ b/test/pleroma/web/metadata/providers/rel_me_test.exs
@@ -11,11 +11,24 @@ defmodule Pleroma.Web.Metadata.Providers.RelMeTest do
bio =
~s(<a href="https://some-link.com">https://some-link.com</a> <a rel="me" href="https://another-link.com">https://another-link.com</a> <link href="http://some.com"> <link rel="me" href="http://some3.com">)
- user = insert(:user, %{bio: bio})
+ fields = [
+ %{
+ "name" => "profile",
+ "value" => ~S(<a rel="me" href="http://profile.com">http://profile.com</a>)
+ },
+ %{
+ "name" => "like",
+ "value" => ~S(<a href="http://cofe.io">http://cofe.io</a>)
+ },
+ %{"name" => "foo", "value" => "bar"}
+ ]
+
+ user = insert(:user, %{bio: bio, fields: fields})
assert RelMe.build_tags(%{user: user}) == [
{:link, [rel: "me", href: "http://some3.com"], []},
- {:link, [rel: "me", href: "https://another-link.com"], []}
+ {:link, [rel: "me", href: "https://another-link.com"], []},
+ {:link, [rel: "me", href: "http://profile.com"], []}
]
end
end
diff --git a/test/pleroma/web/metadata/utils_test.exs b/test/pleroma/web/metadata/utils_test.exs
index 85ef6033a..3daf852fb 100644
--- a/test/pleroma/web/metadata/utils_test.exs
+++ b/test/pleroma/web/metadata/utils_test.exs
@@ -72,7 +72,7 @@ defmodule Pleroma.Web.Metadata.UtilsTest do
end
end
- describe "scrub_html_and_truncate/2" do
+ describe "scrub_html_and_truncate/3" do
test "it returns text without encode HTML" do
assert Utils.scrub_html_and_truncate("Pleroma's really cool!") == "Pleroma's really cool!"
end
diff --git a/test/pleroma/web/pleroma_api/controllers/emoji_reaction_controller_test.exs b/test/pleroma/web/pleroma_api/controllers/emoji_reaction_controller_test.exs
index 77c75b560..d81b47a6b 100644
--- a/test/pleroma/web/pleroma_api/controllers/emoji_reaction_controller_test.exs
+++ b/test/pleroma/web/pleroma_api/controllers/emoji_reaction_controller_test.exs
@@ -17,23 +17,113 @@ defmodule Pleroma.Web.PleromaAPI.EmojiReactionControllerTest do
user = insert(:user)
other_user = insert(:user)
+ note = insert(:note, user: user, data: %{"reactions" => [["👍", [other_user.ap_id], nil]]})
+ activity = insert(:note_activity, note: note, user: user)
+
+ result =
+ conn
+ |> assign(:user, other_user)
+ |> assign(:token, insert(:oauth_token, user: other_user, scopes: ["write:statuses"]))
+ |> put("/api/v1/pleroma/statuses/#{activity.id}/reactions/\u26A0")
+ |> json_response_and_validate_schema(200)
+
+ assert %{"id" => id} = result
+ assert to_string(activity.id) == id
+
+ assert result["pleroma"]["emoji_reactions"] == [
+ %{
+ "name" => "👍",
+ "count" => 1,
+ "me" => true,
+ "url" => nil,
+ "account_ids" => [other_user.id]
+ },
+ %{
+ "name" => "\u26A0\uFE0F",
+ "count" => 1,
+ "me" => true,
+ "url" => nil,
+ "account_ids" => [other_user.id]
+ }
+ ]
+
{:ok, activity} = CommonAPI.post(user, %{status: "#cofe"})
+ ObanHelpers.perform_all()
+
+ # Reacting with a custom emoji
result =
conn
|> assign(:user, other_user)
|> assign(:token, insert(:oauth_token, user: other_user, scopes: ["write:statuses"]))
- |> put("/api/v1/pleroma/statuses/#{activity.id}/reactions/☕")
+ |> put("/api/v1/pleroma/statuses/#{activity.id}/reactions/:dinosaur:")
|> json_response_and_validate_schema(200)
- # We return the status, but this our implementation detail.
assert %{"id" => id} = result
assert to_string(activity.id) == id
assert result["pleroma"]["emoji_reactions"] == [
- %{"name" => "☕", "count" => 1, "me" => true}
+ %{
+ "name" => "dinosaur",
+ "count" => 1,
+ "me" => true,
+ "url" => "http://localhost:4001/emoji/dino walking.gif",
+ "account_ids" => [other_user.id]
+ }
+ ]
+
+ # Reacting with a remote emoji
+ note =
+ insert(:note,
+ user: user,
+ data: %{
+ "reactions" => [
+ ["👍", [other_user.ap_id], nil],
+ ["wow", [other_user.ap_id], "https://remote/emoji/wow"]
+ ]
+ }
+ )
+
+ activity = insert(:note_activity, note: note, user: user)
+
+ result =
+ conn
+ |> assign(:user, user)
+ |> assign(:token, insert(:oauth_token, user: user, scopes: ["write:statuses"]))
+ |> put("/api/v1/pleroma/statuses/#{activity.id}/reactions/:wow@remote:")
+ |> json_response(200)
+
+ assert result["pleroma"]["emoji_reactions"] == [
+ %{
+ "account_ids" => [other_user.id],
+ "count" => 1,
+ "me" => false,
+ "name" => "👍",
+ "url" => nil
+ },
+ %{
+ "name" => "wow@remote",
+ "count" => 2,
+ "me" => true,
+ "url" => "https://remote/emoji/wow",
+ "account_ids" => [user.id, other_user.id]
+ }
]
+ # Reacting with a remote custom emoji that hasn't been reacted with yet
+ note =
+ insert(:note,
+ user: user
+ )
+
+ activity = insert(:note_activity, note: note, user: user)
+
+ assert conn
+ |> assign(:user, user)
+ |> assign(:token, insert(:oauth_token, user: user, scopes: ["write:statuses"]))
+ |> put("/api/v1/pleroma/statuses/#{activity.id}/reactions/:wow@remote:")
+ |> json_response(400)
+
# Reacting with a non-emoji
assert conn
|> assign(:user, other_user)
@@ -46,8 +136,21 @@ defmodule Pleroma.Web.PleromaAPI.EmojiReactionControllerTest do
user = insert(:user)
other_user = insert(:user)
- {:ok, activity} = CommonAPI.post(user, %{status: "#cofe"})
+ note =
+ insert(:note,
+ user: user,
+ data: %{"reactions" => [["wow", [user.ap_id], "https://remote/emoji/wow"]]}
+ )
+
+ activity = insert(:note_activity, note: note, user: user)
+
+ ObanHelpers.perform_all()
+
{:ok, _reaction_activity} = CommonAPI.react_with_emoji(activity.id, other_user, "☕")
+ {:ok, _reaction_activity} = CommonAPI.react_with_emoji(activity.id, other_user, ":dinosaur:")
+
+ {:ok, _reaction_activity} =
+ CommonAPI.react_with_emoji(activity.id, other_user, ":wow@remote:")
ObanHelpers.perform_all()
@@ -60,11 +163,47 @@ defmodule Pleroma.Web.PleromaAPI.EmojiReactionControllerTest do
assert %{"id" => id} = json_response_and_validate_schema(result, 200)
assert to_string(activity.id) == id
+ # Remove custom emoji
+
+ result =
+ conn
+ |> assign(:user, other_user)
+ |> assign(:token, insert(:oauth_token, user: other_user, scopes: ["write:statuses"]))
+ |> delete("/api/v1/pleroma/statuses/#{activity.id}/reactions/:dinosaur:")
+
+ assert %{"id" => id} = json_response_and_validate_schema(result, 200)
+ assert to_string(activity.id) == id
+
ObanHelpers.perform_all()
object = Object.get_by_ap_id(activity.data["object"])
- assert object.data["reaction_count"] == 0
+ assert object.data["reaction_count"] == 2
+
+ # Remove custom remote emoji
+ result =
+ conn
+ |> assign(:user, other_user)
+ |> assign(:token, insert(:oauth_token, user: other_user, scopes: ["write:statuses"]))
+ |> delete("/api/v1/pleroma/statuses/#{activity.id}/reactions/:wow@remote:")
+ |> json_response(200)
+
+ assert result["pleroma"]["emoji_reactions"] == [
+ %{
+ "name" => "wow@remote",
+ "count" => 1,
+ "me" => false,
+ "url" => "https://remote/emoji/wow",
+ "account_ids" => [user.id]
+ }
+ ]
+
+ # Remove custom remote emoji that hasn't been reacted with yet
+ assert conn
+ |> assign(:user, other_user)
+ |> assign(:token, insert(:oauth_token, user: other_user, scopes: ["write:statuses"]))
+ |> delete("/api/v1/pleroma/statuses/#{activity.id}/reactions/:zoop@remote:")
+ |> json_response(400)
end
test "GET /api/v1/pleroma/statuses/:id/reactions", %{conn: conn} do
@@ -181,7 +320,15 @@ defmodule Pleroma.Web.PleromaAPI.EmojiReactionControllerTest do
{:ok, _} = CommonAPI.react_with_emoji(activity.id, other_user, "🎅")
{:ok, _} = CommonAPI.react_with_emoji(activity.id, other_user, "☕")
- assert [%{"name" => "🎅", "count" => 1, "accounts" => [represented_user], "me" => false}] =
+ assert [
+ %{
+ "name" => "🎅",
+ "count" => 1,
+ "accounts" => [represented_user],
+ "me" => false,
+ "url" => nil
+ }
+ ] =
conn
|> get("/api/v1/pleroma/statuses/#{activity.id}/reactions/🎅")
|> json_response_and_validate_schema(200)
diff --git a/test/pleroma/web/plugs/authentication_plug_test.exs b/test/pleroma/web/plugs/authentication_plug_test.exs
index 41fdb93bc..b8acd01c5 100644
--- a/test/pleroma/web/plugs/authentication_plug_test.exs
+++ b/test/pleroma/web/plugs/authentication_plug_test.exs
@@ -70,28 +70,6 @@ defmodule Pleroma.Web.Plugs.AuthenticationPlugTest do
assert "$pbkdf2" <> _ = user.password_hash
end
- @tag :skip_on_mac
- test "with a crypt hash, it updates to a pkbdf2 hash", %{conn: conn} do
- user =
- insert(:user,
- password_hash:
- "$6$9psBWV8gxkGOZWBz$PmfCycChoxeJ3GgGzwvhlgacb9mUoZ.KUXNCssekER4SJ7bOK53uXrHNb2e4i8yPFgSKyzaW9CcmrDXWIEMtD1"
- )
-
- conn =
- conn
- |> assign(:auth_user, user)
- |> assign(:auth_credentials, %{password: "password"})
- |> AuthenticationPlug.call(%{})
-
- assert conn.assigns.user.id == conn.assigns.auth_user.id
- assert conn.assigns.token == nil
- assert PlugHelper.plug_skipped?(conn, OAuthScopesPlug)
-
- user = User.get_by_id(user.id)
- assert "$pbkdf2" <> _ = user.password_hash
- end
-
describe "checkpw/2" do
test "check pbkdf2 hash" do
hash =
@@ -101,14 +79,6 @@ defmodule Pleroma.Web.Plugs.AuthenticationPlugTest do
refute AuthenticationPlug.checkpw("test-password1", hash)
end
- @tag :skip_on_mac
- test "check sha512-crypt hash" do
- hash =
- "$6$9psBWV8gxkGOZWBz$PmfCycChoxeJ3GgGzwvhlgacb9mUoZ.KUXNCssekER4SJ7bOK53uXrHNb2e4i8yPFgSKyzaW9CcmrDXWIEMtD1"
-
- assert AuthenticationPlug.checkpw("password", hash)
- end
-
test "check bcrypt hash" do
hash = "$2a$10$uyhC/R/zoE1ndwwCtMusK.TLVzkQ/Ugsbqp3uXI.CTTz0gBw.24jS"
diff --git a/test/pleroma/workers/receiver_worker_test.exs b/test/pleroma/workers/receiver_worker_test.exs
index 283beee4d..acea0ae00 100644
--- a/test/pleroma/workers/receiver_worker_test.exs
+++ b/test/pleroma/workers/receiver_worker_test.exs
@@ -11,7 +11,7 @@ defmodule Pleroma.Workers.ReceiverWorkerTest do
alias Pleroma.Workers.ReceiverWorker
- test "it ignores MRF reject" do
+ test "it does not retry MRF reject" do
params = insert(:note).data
with_mock Pleroma.Web.ActivityPub.Transmogrifier,
@@ -22,4 +22,31 @@ defmodule Pleroma.Workers.ReceiverWorkerTest do
})
end
end
+
+ test "it does not retry ObjectValidator reject" do
+ params =
+ insert(:note_activity).data
+ |> Map.put("id", Pleroma.Web.ActivityPub.Utils.generate_activity_id())
+ |> Map.put("object", %{
+ "type" => "Note",
+ "id" => Pleroma.Web.ActivityPub.Utils.generate_object_id()
+ })
+
+ with_mock Pleroma.Web.ActivityPub.ObjectValidator, [:passthrough],
+ validate: fn _, _ -> {:error, %Ecto.Changeset{}} end do
+ assert {:cancel, {:error, %Ecto.Changeset{}}} =
+ ReceiverWorker.perform(%Oban.Job{
+ args: %{"op" => "incoming_ap_doc", "params" => params}
+ })
+ end
+ end
+
+ test "it does not retry duplicates" do
+ params = insert(:note_activity).data
+
+ assert {:cancel, :already_present} =
+ ReceiverWorker.perform(%Oban.Job{
+ args: %{"op" => "incoming_ap_doc", "params" => params}
+ })
+ end
end