summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/mix/tasks/pleroma/openapi_spec.ex67
-rw-r--r--lib/pleroma/application.ex3
-rw-r--r--lib/pleroma/bbs/authenticator.ex20
-rw-r--r--lib/pleroma/bbs/handler.ex246
-rw-r--r--lib/pleroma/ecto_type/activity_pub/object_validators/bare_uri.ex23
-rw-r--r--lib/pleroma/emoji.ex53
-rw-r--r--lib/pleroma/notification.ex3
-rw-r--r--lib/pleroma/object.ex26
-rw-r--r--lib/pleroma/object/fetcher.ex86
-rw-r--r--lib/pleroma/object/updater.ex56
-rw-r--r--lib/pleroma/upload/filter.ex6
-rw-r--r--lib/pleroma/upload/filter/exiftool/read_description.ex5
-rw-r--r--lib/pleroma/upload/filter/exiftool/strip_location.ex1
-rw-r--r--lib/pleroma/upload/filter/only_media.ex20
-rw-r--r--lib/pleroma/user.ex13
-rw-r--r--lib/pleroma/web/activity_pub/activity_pub.ex44
-rw-r--r--lib/pleroma/web/activity_pub/builder.ex81
-rw-r--r--lib/pleroma/web/activity_pub/mrf/force_mentions_in_content.ex10
-rw-r--r--lib/pleroma/web/activity_pub/object_validator.ex15
-rw-r--r--lib/pleroma/web/activity_pub/object_validators/add_remove_validator.ex3
-rw-r--r--lib/pleroma/web/activity_pub/object_validators/audio_image_video_validator.ex (renamed from lib/pleroma/web/activity_pub/object_validators/audio_video_validator.ex)15
-rw-r--r--lib/pleroma/web/activity_pub/object_validators/common_fields.ex2
-rw-r--r--lib/pleroma/web/activity_pub/object_validators/emoji_react_validator.ex47
-rw-r--r--lib/pleroma/web/activity_pub/object_validators/tag_validator.ex6
-rw-r--r--lib/pleroma/web/activity_pub/publisher.ex2
-rw-r--r--lib/pleroma/web/activity_pub/side_effects.ex38
-rw-r--r--lib/pleroma/web/activity_pub/transmogrifier.ex44
-rw-r--r--lib/pleroma/web/activity_pub/utils.ex79
-rw-r--r--lib/pleroma/web/admin_api/controllers/frontend_controller.ex25
-rw-r--r--lib/pleroma/web/admin_api/report.ex2
-rw-r--r--lib/pleroma/web/admin_api/views/frontend_view.ex3
-rw-r--r--lib/pleroma/web/api_spec.ex24
-rw-r--r--lib/pleroma/web/api_spec/operations/account_operation.ex4
-rw-r--r--lib/pleroma/web/api_spec/operations/admin/announcement_operation.ex10
-rw-r--r--lib/pleroma/web/api_spec/operations/admin/frontend_operation.ex5
-rw-r--r--lib/pleroma/web/api_spec/operations/admin/status_operation.ex8
-rw-r--r--lib/pleroma/web/api_spec/operations/announcement_operation.ex4
-rw-r--r--lib/pleroma/web/api_spec/operations/directory_operation.ex2
-rw-r--r--lib/pleroma/web/api_spec/operations/instance_operation.ex4
-rw-r--r--lib/pleroma/web/api_spec/operations/pleroma_emoji_file_operation.ex6
-rw-r--r--lib/pleroma/web/api_spec/operations/pleroma_emoji_pack_operation.ex28
-rw-r--r--lib/pleroma/web/api_spec/operations/pleroma_instances_operation.ex2
-rw-r--r--lib/pleroma/web/api_spec/operations/status_operation.ex6
-rw-r--r--lib/pleroma/web/api_spec/operations/twitter_util_operation.ex25
-rw-r--r--lib/pleroma/web/api_spec/schemas/status.ex12
-rw-r--r--lib/pleroma/web/api_spec/scopes/compiler.ex82
-rw-r--r--lib/pleroma/web/api_spec/scopes/translator.ex10
-rw-r--r--lib/pleroma/web/common_api.ex2
-rw-r--r--lib/pleroma/web/common_api/utils.ex15
-rw-r--r--lib/pleroma/web/federator.ex13
-rw-r--r--lib/pleroma/web/feed/feed_view.ex10
-rw-r--r--lib/pleroma/web/mastodon_api/controllers/account_controller.ex20
-rw-r--r--lib/pleroma/web/mastodon_api/views/instance_view.ex3
-rw-r--r--lib/pleroma/web/mastodon_api/views/notification_view.ex5
-rw-r--r--lib/pleroma/web/mastodon_api/views/status_view.ex16
-rw-r--r--lib/pleroma/web/media_proxy/media_proxy_controller.ex7
-rw-r--r--lib/pleroma/web/metadata/providers/rel_me.ex14
-rw-r--r--lib/pleroma/web/metadata/providers/twitter_card.ex13
-rw-r--r--lib/pleroma/web/metadata/utils.ex5
-rw-r--r--lib/pleroma/web/pleroma_api/controllers/emoji_reaction_controller.ex24
-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/plugs/http_signature_plug.ex2
-rw-r--r--lib/pleroma/web/plugs/uploaded_media.ex26
-rw-r--r--lib/pleroma/web/preload.ex4
-rw-r--r--lib/pleroma/web/rel_me.ex18
-rw-r--r--lib/pleroma/web/rich_media/parsers/o_embed.ex4
-rw-r--r--lib/pleroma/web/router.ex3
-rw-r--r--lib/pleroma/web/static_fe/static_fe_controller.ex10
-rw-r--r--lib/pleroma/web/streamer.ex46
-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/web/templates/o_auth/o_auth/_scopes.html.eex2
-rw-r--r--lib/pleroma/workers/background_worker.ex2
-rw-r--r--lib/pleroma/workers/receiver_worker.ex3
-rw-r--r--lib/pleroma/workers/transmogrifier_worker.ex18
78 files changed, 928 insertions, 670 deletions
diff --git a/lib/mix/tasks/pleroma/openapi_spec.ex b/lib/mix/tasks/pleroma/openapi_spec.ex
index 884f931f8..1ea468476 100644
--- a/lib/mix/tasks/pleroma/openapi_spec.ex
+++ b/lib/mix/tasks/pleroma/openapi_spec.ex
@@ -6,7 +6,70 @@ defmodule Mix.Tasks.Pleroma.OpenapiSpec do
def run([path]) do
# Load Pleroma application to get version info
Application.load(:pleroma)
- spec = Pleroma.Web.ApiSpec.spec(server_specific: false) |> Jason.encode!()
- File.write(path, spec)
+
+ spec_json = Pleroma.Web.ApiSpec.spec(server_specific: false) |> Jason.encode!()
+ # to get rid of the structs
+ spec_regened = spec_json |> Jason.decode!()
+
+ check_specs!(spec_regened)
+
+ File.write(path, spec_json)
+ end
+
+ defp check_specs!(spec) do
+ with :ok <- check_specs(spec) do
+ :ok
+ else
+ {_, errors} ->
+ IO.puts(IO.ANSI.format([:red, :bright, "Spec check failed, errors:"]))
+ Enum.map(errors, &IO.puts/1)
+
+ raise "Spec check failed"
+ end
+ end
+
+ def check_specs(spec) do
+ errors =
+ spec["paths"]
+ |> Enum.flat_map(fn {path, %{} = endpoints} ->
+ Enum.map(
+ endpoints,
+ fn {method, endpoint} ->
+ with :ok <- check_endpoint(spec, endpoint) do
+ :ok
+ else
+ error ->
+ "#{endpoint["operationId"]} (#{method} #{path}): #{error}"
+ end
+ end
+ )
+ |> Enum.reject(fn res -> res == :ok end)
+ end)
+
+ if errors == [] do
+ :ok
+ else
+ {:error, errors}
+ end
+ end
+
+ defp check_endpoint(spec, endpoint) do
+ valid_tags = available_tags(spec)
+
+ with {_, [_ | _] = tags} <- {:tags, endpoint["tags"]},
+ {_, []} <- {:unavailable, Enum.reject(tags, &(&1 in valid_tags))} do
+ :ok
+ else
+ {:tags, _} ->
+ "No tags specified"
+
+ {:unavailable, tags} ->
+ "Tags #{inspect(tags)} not available. Please add it in \"x-tagGroups\" in Pleroma.Web.ApiSpec"
+ end
+ end
+
+ defp available_tags(spec) do
+ spec["x-tagGroups"]
+ |> Enum.flat_map(fn %{"tags" => tags} -> tags end)
end
end
diff --git a/lib/pleroma/application.ex b/lib/pleroma/application.ex
index 1c1db8c10..e68a3c57e 100644
--- a/lib/pleroma/application.ex
+++ b/lib/pleroma/application.ex
@@ -209,7 +209,8 @@ defmodule Pleroma.Application do
build_cachex("chat_message_id_idempotency_key",
expiration: chat_message_id_idempotency_key_expiration(),
limit: 500_000
- )
+ ),
+ build_cachex("rel_me", limit: 2500)
]
end
diff --git a/lib/pleroma/bbs/authenticator.ex b/lib/pleroma/bbs/authenticator.ex
deleted file mode 100644
index 0f7543ff5..000000000
--- a/lib/pleroma/bbs/authenticator.ex
+++ /dev/null
@@ -1,20 +0,0 @@
-# Pleroma: A lightweight social networking server
-# Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
-# SPDX-License-Identifier: AGPL-3.0-only
-
-defmodule Pleroma.BBS.Authenticator do
- use Sshd.PasswordAuthenticator
- alias Pleroma.User
- alias Pleroma.Web.Plugs.AuthenticationPlug
-
- def authenticate(username, password) do
- username = to_string(username)
- password = to_string(password)
-
- with %User{} = user <- User.get_by_nickname(username) do
- AuthenticationPlug.checkpw(password, user.password_hash)
- else
- _e -> false
- end
- end
-end
diff --git a/lib/pleroma/bbs/handler.ex b/lib/pleroma/bbs/handler.ex
deleted file mode 100644
index 27799338f..000000000
--- a/lib/pleroma/bbs/handler.ex
+++ /dev/null
@@ -1,246 +0,0 @@
-# Pleroma: A lightweight social networking server
-# Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
-# SPDX-License-Identifier: AGPL-3.0-only
-
-defmodule Pleroma.BBS.Handler do
- use Sshd.ShellHandler
- alias Pleroma.Activity
- alias Pleroma.HTML
- alias Pleroma.Web.ActivityPub.ActivityPub
- alias Pleroma.Web.CommonAPI
-
- def on_shell(username, _pubkey, _ip, _port) do
- :ok = IO.puts("Welcome to #{Pleroma.Config.get([:instance, :name])}!")
- user = Pleroma.User.get_cached_by_nickname(to_string(username))
- Logger.debug("#{inspect(user)}")
- loop(run_state(user: user))
- end
-
- def on_connect(username, ip, port, method) do
- Logger.debug(fn ->
- """
- Incoming SSH shell #{inspect(self())} requested for #{username} from #{inspect(ip)}:#{inspect(port)} using #{inspect(method)}
- """
- end)
- end
-
- def on_disconnect(username, ip, port) do
- Logger.debug(fn ->
- "Disconnecting SSH shell for #{username} from #{inspect(ip)}:#{inspect(port)}"
- end)
- end
-
- defp loop(state) do
- self_pid = self()
- counter = state.counter
- prefix = state.prefix
- user = state.user
-
- input = spawn(fn -> io_get(self_pid, prefix, counter, user.nickname) end)
- wait_input(state, input)
- end
-
- def puts_activity(activity) do
- status = Pleroma.Web.MastodonAPI.StatusView.render("show.json", %{activity: activity})
-
- IO.puts("-- #{status.id} by #{status.account.display_name} (#{status.account.acct})")
-
- status.content
- |> String.split("<br/>")
- |> Enum.map(&HTML.strip_tags/1)
- |> Enum.map(&HtmlEntities.decode/1)
- |> Enum.map(&IO.puts/1)
- end
-
- def puts_notification(activity, user) do
- notification =
- Pleroma.Web.MastodonAPI.NotificationView.render("show.json", %{
- notification: activity,
- for: user
- })
-
- IO.puts(
- "== (#{notification.type}) #{notification.status.id} by #{notification.account.display_name} (#{notification.account.acct})"
- )
-
- notification.status.content
- |> String.split("<br/>")
- |> Enum.map(&HTML.strip_tags/1)
- |> Enum.map(&HtmlEntities.decode/1)
- |> (fn x ->
- case x do
- [content] ->
- "> " <> content
-
- [head | _tail] ->
- # "> " <> hd <> "..."
- head
- |> String.slice(1, 80)
- |> (fn x -> "> " <> x <> "..." end).()
- end
- end).()
- |> IO.puts()
-
- IO.puts("")
- end
-
- def handle_command(state, "help") do
- IO.puts("Available commands:")
- IO.puts("help - This help")
- IO.puts("home - Show the home timeline")
- IO.puts("p <text> - Post the given text")
- IO.puts("r <id> <text> - Reply to the post with the given id")
- IO.puts("t <id> - Show a thread from the given id")
- IO.puts("n - Show notifications")
- IO.puts("n read - Mark all notifactions as read")
- IO.puts("f <id> - Favourites the post with the given id")
- IO.puts("R <id> - Repeat the post with the given id")
- IO.puts("quit - Quit")
-
- state
- end
-
- def handle_command(%{user: user} = state, "r " <> text) do
- text = String.trim(text)
- [activity_id, rest] = String.split(text, " ", parts: 2)
-
- with %Activity{} <- Activity.get_by_id(activity_id),
- {:ok, _activity} <-
- CommonAPI.post(user, %{status: rest, in_reply_to_status_id: activity_id}) do
- IO.puts("Replied!")
- else
- _e -> IO.puts("Could not reply...")
- end
-
- state
- end
-
- def handle_command(%{user: user} = state, "t " <> activity_id) do
- with %Activity{} = activity <- Activity.get_by_id(activity_id) do
- activities =
- ActivityPub.fetch_activities_for_context(activity.data["context"], %{
- blocking_user: user,
- user: user,
- exclude_id: activity.id
- })
-
- case activities do
- [] ->
- activity_id
- |> Activity.get_by_id()
- |> puts_activity()
-
- _ ->
- activities
- |> Enum.reverse()
- |> Enum.each(&puts_activity/1)
- end
- else
- _e -> IO.puts("Could not show this thread...")
- end
-
- state
- end
-
- def handle_command(%{user: user} = state, "n read") do
- Pleroma.Notification.clear(user)
- IO.puts("All notifications were marked as read")
-
- state
- end
-
- def handle_command(%{user: user} = state, "n") do
- user
- |> Pleroma.Web.MastodonAPI.MastodonAPI.get_notifications(%{})
- |> Enum.each(&puts_notification(&1, user))
-
- state
- end
-
- def handle_command(%{user: user} = state, "p " <> text) do
- text = String.trim(text)
-
- with {:ok, activity} <- CommonAPI.post(user, %{status: text}) do
- IO.puts("Posted! ID: #{activity.id}")
- else
- _e -> IO.puts("Could not post...")
- end
-
- state
- end
-
- def handle_command(%{user: user} = state, "f " <> id) do
- id = String.trim(id)
-
- with %Activity{} = activity <- Activity.get_by_id(id),
- {:ok, _activity} <- CommonAPI.favorite(user, activity) do
- IO.puts("Favourited!")
- else
- _e -> IO.puts("Could not Favourite...")
- end
-
- state
- end
-
- def handle_command(state, "home") do
- user = state.user
-
- params =
- %{}
- |> Map.put(:type, ["Create"])
- |> Map.put(:blocking_user, user)
- |> Map.put(:muting_user, user)
- |> Map.put(:user, user)
-
- activities =
- [user.ap_id | Pleroma.User.following(user)]
- |> ActivityPub.fetch_activities(params)
-
- Enum.each(activities, fn activity ->
- puts_activity(activity)
- end)
-
- state
- end
-
- def handle_command(state, command) do
- IO.puts("Unknown command '#{command}'")
- state
- end
-
- defp wait_input(state, input) do
- receive do
- {:input, ^input, "quit\n"} ->
- IO.puts("Exiting...")
-
- {:input, ^input, code} when is_binary(code) ->
- code = String.trim(code)
-
- state = handle_command(state, code)
-
- loop(%{state | counter: state.counter + 1})
-
- {:input, ^input, {:error, :interrupted}} ->
- IO.puts("Caught Ctrl+C...")
- loop(%{state | counter: state.counter + 1})
-
- {:input, ^input, msg} ->
- :ok = Logger.warn("received unknown message: #{inspect(msg)}")
- loop(%{state | counter: state.counter + 1})
- end
- end
-
- defp run_state(opts) do
- %{prefix: "pleroma", counter: 1, user: opts[:user]}
- end
-
- defp io_get(pid, prefix, counter, username) do
- prompt = prompt(prefix, counter, username)
- send(pid, {:input, self(), IO.gets(:stdio, prompt)})
- end
-
- defp prompt(prefix, counter, username) do
- prompt = "#{username}@#{prefix}:#{counter}>"
- prompt <> " "
- end
-end
diff --git a/lib/pleroma/ecto_type/activity_pub/object_validators/bare_uri.ex b/lib/pleroma/ecto_type/activity_pub/object_validators/bare_uri.ex
new file mode 100644
index 000000000..1038296e7
--- /dev/null
+++ b/lib/pleroma/ecto_type/activity_pub/object_validators/bare_uri.ex
@@ -0,0 +1,23 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2023 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.EctoType.ActivityPub.ObjectValidators.BareUri do
+ use Ecto.Type
+
+ def type, do: :string
+
+ def cast(uri) when is_binary(uri) do
+ case URI.parse(uri) do
+ %URI{scheme: nil} -> :error
+ %URI{} -> {:ok, uri}
+ _ -> :error
+ end
+ end
+
+ def cast(_), do: :error
+
+ def dump(data), do: {:ok, data}
+
+ def load(data), do: {:ok, data}
+end
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/notification.ex b/lib/pleroma/notification.ex
index aba6096bc..48d467c59 100644
--- a/lib/pleroma/notification.ex
+++ b/lib/pleroma/notification.ex
@@ -178,6 +178,7 @@ defmodule Pleroma.Notification do
from([_n, a, o] in query,
where:
fragment("not(?->>'content' ~* ?)", o.data, ^regex) or
+ fragment("?->>'content' is null", o.data) or
fragment("?->>'actor' = ?", o.data, ^user.ap_id)
)
end
@@ -679,7 +680,7 @@ defmodule Pleroma.Notification do
cond do
opts[:type] == "poll" -> false
user.ap_id == actor -> false
- !User.following?(follower, user) -> true
+ !User.following?(user, follower) -> true
true -> false
end
end
diff --git a/lib/pleroma/object.ex b/lib/pleroma/object.ex
index 38accae5d..aa137d250 100644
--- a/lib/pleroma/object.ex
+++ b/lib/pleroma/object.ex
@@ -425,4 +425,30 @@ defmodule Pleroma.Object do
end
def object_data_hashtags(_), do: []
+
+ def get_emoji_reactions(object) do
+ reactions = object.data["reactions"]
+
+ if is_list(reactions) or is_map(reactions) do
+ reactions
+ |> Enum.map(fn
+ [_emoji, users, _maybe_url] = item when is_list(users) ->
+ item
+
+ [emoji, users] when is_list(users) ->
+ [emoji, users, nil]
+
+ # This case is here to process the Map situation, which will happen
+ # only with the legacy two-value format.
+ {emoji, users} when is_list(users) ->
+ [emoji, users, nil]
+
+ _ ->
+ nil
+ end)
+ |> Enum.reject(&is_nil/1)
+ else
+ []
+ end
+ end
end
diff --git a/lib/pleroma/object/fetcher.ex b/lib/pleroma/object/fetcher.ex
index a9a9eeeed..cc3772563 100644
--- a/lib/pleroma/object/fetcher.ex
+++ b/lib/pleroma/object/fetcher.ex
@@ -8,77 +8,30 @@ defmodule Pleroma.Object.Fetcher do
alias Pleroma.Maps
alias Pleroma.Object
alias Pleroma.Object.Containment
- alias Pleroma.Repo
alias Pleroma.Signature
alias Pleroma.Web.ActivityPub.InternalFetchActor
+ alias Pleroma.Web.ActivityPub.MRF
alias Pleroma.Web.ActivityPub.ObjectValidator
+ alias Pleroma.Web.ActivityPub.Pipeline
alias Pleroma.Web.ActivityPub.Transmogrifier
alias Pleroma.Web.Federator
require Logger
require Pleroma.Constants
- defp touch_changeset(changeset) do
- updated_at =
- NaiveDateTime.utc_now()
- |> NaiveDateTime.truncate(:second)
-
- Ecto.Changeset.put_change(changeset, :updated_at, updated_at)
- end
-
- defp maybe_reinject_internal_fields(%{data: %{} = old_data}, new_data) do
- has_history? = fn
- %{"formerRepresentations" => %{"orderedItems" => list}} when is_list(list) -> true
- _ -> false
- end
-
- internal_fields = Map.take(old_data, Pleroma.Constants.object_internal_fields())
-
- remote_history_exists? = has_history?.(new_data)
-
- # If the remote history exists, we treat that as the only source of truth.
- new_data =
- if has_history?.(old_data) and not remote_history_exists? do
- Map.put(new_data, "formerRepresentations", old_data["formerRepresentations"])
- else
- new_data
- end
-
- # If the remote does not have history information, we need to manage it ourselves
- new_data =
- if not remote_history_exists? do
- changed? =
- Pleroma.Constants.status_updatable_fields()
- |> Enum.any?(fn field -> Map.get(old_data, field) != Map.get(new_data, field) end)
-
- %{updated_object: updated_object} =
- new_data
- |> Object.Updater.maybe_update_history(old_data,
- updated: changed?,
- use_history_in_new_object?: false
- )
-
- updated_object
- else
- new_data
- end
-
- Map.merge(new_data, internal_fields)
- end
-
- defp maybe_reinject_internal_fields(_, new_data), do: new_data
-
@spec reinject_object(struct(), map()) :: {:ok, Object.t()} | {:error, any()}
- defp reinject_object(%Object{data: %{"type" => "Question"}} = object, new_data) do
+ defp reinject_object(%Object{data: %{}} = object, new_data) do
Logger.debug("Reinjecting object #{new_data["id"]}")
- with data <- maybe_reinject_internal_fields(object, new_data),
- {:ok, data, _} <- ObjectValidator.validate(data, %{}),
- changeset <- Object.change(object, %{data: data}),
- changeset <- touch_changeset(changeset),
- {:ok, object} <- Repo.insert_or_update(changeset),
- {:ok, object} <- Object.set_cache(object) do
- {:ok, object}
+ with {:ok, new_data, _} <- ObjectValidator.validate(new_data, %{}),
+ {:ok, new_data} <- MRF.filter(new_data),
+ {:ok, new_object, _} <-
+ Object.Updater.do_update_and_invalidate_cache(
+ object,
+ new_data,
+ _touch_changeset? = true
+ ) do
+ {:ok, new_object}
else
e ->
Logger.error("Error while processing object: #{inspect(e)}")
@@ -86,20 +39,11 @@ defmodule Pleroma.Object.Fetcher do
end
end
- defp reinject_object(%Object{} = object, new_data) do
- Logger.debug("Reinjecting object #{new_data["id"]}")
-
- with new_data <- Transmogrifier.fix_object(new_data),
- data <- maybe_reinject_internal_fields(object, new_data),
- changeset <- Object.change(object, %{data: data}),
- changeset <- touch_changeset(changeset),
- {:ok, object} <- Repo.insert_or_update(changeset),
- {:ok, object} <- Object.set_cache(object) do
+ defp reinject_object(_, new_data) do
+ with {:ok, object, _} <- Pipeline.common_pipeline(new_data, local: false) do
{:ok, object}
else
- e ->
- Logger.error("Error while processing object: #{inspect(e)}")
- {:error, e}
+ e -> e
end
end
diff --git a/lib/pleroma/object/updater.ex b/lib/pleroma/object/updater.ex
index ab38d3ed2..b1e4870ba 100644
--- a/lib/pleroma/object/updater.ex
+++ b/lib/pleroma/object/updater.ex
@@ -5,6 +5,9 @@
defmodule Pleroma.Object.Updater do
require Pleroma.Constants
+ alias Pleroma.Object
+ alias Pleroma.Repo
+
def update_content_fields(orig_object_data, updated_object) do
Pleroma.Constants.status_updatable_fields()
|> Enum.reduce(
@@ -97,12 +100,14 @@ defmodule Pleroma.Object.Updater do
end
defp maybe_update_poll(to_be_updated, updated_object) do
- choice_key = fn data ->
- if Map.has_key?(data, "anyOf"), do: "anyOf", else: "oneOf"
+ choice_key = fn
+ %{"anyOf" => [_ | _]} -> "anyOf"
+ %{"oneOf" => [_ | _]} -> "oneOf"
+ _ -> nil
end
with true <- to_be_updated["type"] == "Question",
- key <- choice_key.(updated_object),
+ key when not is_nil(key) <- choice_key.(updated_object),
true <- key == choice_key.(to_be_updated),
orig_choices <- to_be_updated[key] |> Enum.map(&Map.drop(&1, ["replies"])),
new_choices <- updated_object[key] |> Enum.map(&Map.drop(&1, ["replies"])),
@@ -237,4 +242,49 @@ defmodule Pleroma.Object.Updater do
{:history_items, e} -> e
end
end
+
+ defp maybe_touch_changeset(changeset, true) do
+ updated_at =
+ NaiveDateTime.utc_now()
+ |> NaiveDateTime.truncate(:second)
+
+ Ecto.Changeset.put_change(changeset, :updated_at, updated_at)
+ end
+
+ defp maybe_touch_changeset(changeset, _), do: changeset
+
+ def do_update_and_invalidate_cache(orig_object, updated_object, touch_changeset? \\ false) do
+ orig_object_ap_id = updated_object["id"]
+ orig_object_data = orig_object.data
+
+ %{
+ updated_data: updated_object_data,
+ updated: updated,
+ used_history_in_new_object?: used_history_in_new_object?
+ } = make_new_object_data_from_update_object(orig_object_data, updated_object)
+
+ changeset =
+ orig_object
+ |> Repo.preload(:hashtags)
+ |> Object.change(%{data: updated_object_data})
+ |> maybe_touch_changeset(touch_changeset?)
+
+ with {:ok, new_object} <- Repo.update(changeset),
+ {:ok, _} <- Object.invalid_object_cache(new_object),
+ {:ok, _} <- Object.set_cache(new_object),
+ # The metadata/utils.ex uses the object id for the cache.
+ {:ok, _} <- Pleroma.Activity.HTML.invalidate_cache_for(new_object.id) do
+ if used_history_in_new_object? do
+ with create_activity when not is_nil(create_activity) <-
+ Pleroma.Activity.get_create_by_object_ap_id(orig_object_ap_id),
+ {:ok, _} <- Pleroma.Activity.HTML.invalidate_cache_for(create_activity.id) do
+ nil
+ else
+ _ -> nil
+ end
+ end
+
+ {:ok, new_object, updated}
+ end
+ end
end
diff --git a/lib/pleroma/upload/filter.ex b/lib/pleroma/upload/filter.ex
index 717f06621..809bc6e70 100644
--- a/lib/pleroma/upload/filter.ex
+++ b/lib/pleroma/upload/filter.ex
@@ -38,9 +38,9 @@ defmodule Pleroma.Upload.Filter do
{:ok, :noop} ->
filter(rest, upload)
- error ->
- Logger.error("#{__MODULE__}: Filter #{filter} failed: #{inspect(error)}")
- error
+ {:error, e} ->
+ Logger.error("#{__MODULE__}: Filter #{filter} failed: #{inspect(e)}")
+ {:error, e}
end
end
end
diff --git a/lib/pleroma/upload/filter/exiftool/read_description.ex b/lib/pleroma/upload/filter/exiftool/read_description.ex
index 03d698a81..543b22031 100644
--- a/lib/pleroma/upload/filter/exiftool/read_description.ex
+++ b/lib/pleroma/upload/filter/exiftool/read_description.ex
@@ -33,7 +33,10 @@ defmodule Pleroma.Upload.Filter.Exiftool.ReadDescription do
defp read_when_empty(_, file, tag) do
try do
{tag_content, 0} =
- System.cmd("exiftool", ["-b", "-s3", tag, file], stderr_to_stdout: true, parallelism: true)
+ System.cmd("exiftool", ["-b", "-s3", tag, file],
+ stderr_to_stdout: false,
+ parallelism: true
+ )
tag_content = String.trim(tag_content)
diff --git a/lib/pleroma/upload/filter/exiftool/strip_location.ex b/lib/pleroma/upload/filter/exiftool/strip_location.ex
index 6100527d3..f2bcc4622 100644
--- a/lib/pleroma/upload/filter/exiftool/strip_location.ex
+++ b/lib/pleroma/upload/filter/exiftool/strip_location.ex
@@ -14,6 +14,7 @@ defmodule Pleroma.Upload.Filter.Exiftool.StripLocation do
# Formats not compatible with exiftool at this time
def filter(%Pleroma.Upload{content_type: "image/heic"}), do: {:ok, :noop}
def filter(%Pleroma.Upload{content_type: "image/webp"}), do: {:ok, :noop}
+ def filter(%Pleroma.Upload{content_type: "image/svg" <> _}), do: {:ok, :noop}
def filter(%Pleroma.Upload{tempfile: file, content_type: "image" <> _}) do
try do
diff --git a/lib/pleroma/upload/filter/only_media.ex b/lib/pleroma/upload/filter/only_media.ex
new file mode 100644
index 000000000..a9caeba67
--- /dev/null
+++ b/lib/pleroma/upload/filter/only_media.ex
@@ -0,0 +1,20 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2023 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Upload.Filter.OnlyMedia do
+ @behaviour Pleroma.Upload.Filter
+ alias Pleroma.Upload
+
+ def filter(%Upload{content_type: content_type}) do
+ [type, _subtype] = String.split(content_type, "/")
+
+ if type in ["image", "video", "audio"] do
+ {:ok, :noop}
+ else
+ {:error, "Disallowed content-type: #{content_type}"}
+ end
+ end
+
+ def filter(_), do: {:ok, :noop}
+end
diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex
index f6e30555c..ce125d608 100644
--- a/lib/pleroma/user.ex
+++ b/lib/pleroma/user.ex
@@ -124,7 +124,6 @@ defmodule Pleroma.User do
field(:domain_blocks, {:array, :string}, default: [])
field(:is_active, :boolean, default: true)
field(:no_rich_text, :boolean, default: false)
- field(:ap_enabled, :boolean, default: false)
field(:is_moderator, :boolean, default: false)
field(:is_admin, :boolean, default: false)
field(:show_role, :boolean, default: true)
@@ -488,7 +487,6 @@ defmodule Pleroma.User do
:nickname,
:public_key,
:avatar,
- :ap_enabled,
:banner,
:is_locked,
:last_refreshed_at,
@@ -1061,11 +1059,7 @@ defmodule Pleroma.User do
end
def maybe_direct_follow(%User{} = follower, %User{} = followed) do
- if not ap_enabled?(followed) do
- follow(follower, followed)
- else
- {:ok, follower, followed}
- end
+ {:ok, follower, followed}
end
@doc "A mass follow for local users. Respects blocks in both directions but does not create activities."
@@ -1898,7 +1892,6 @@ defmodule Pleroma.User do
confirmation_token: nil,
domain_blocks: [],
is_active: false,
- ap_enabled: false,
is_moderator: false,
is_admin: false,
mascot: nil,
@@ -2151,10 +2144,6 @@ defmodule Pleroma.User do
end
end
- def ap_enabled?(%User{local: true}), do: true
- def ap_enabled?(%User{ap_enabled: ap_enabled}), do: ap_enabled
- def ap_enabled?(_), do: false
-
@doc "Gets or fetch a user by uri or nickname."
@spec get_or_fetch(String.t()) :: {:ok, User.t()} | {:error, String.t()}
def get_or_fetch("http://" <> _host = uri), do: get_or_fetch_by_ap_id(uri)
diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex
index b9206b4da..1a10aef1d 100644
--- a/lib/pleroma/web/activity_pub/activity_pub.ex
+++ b/lib/pleroma/web/activity_pub/activity_pub.ex
@@ -96,7 +96,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
defp increase_replies_count_if_reply(_create_data), do: :noop
- @object_types ~w[ChatMessage Question Answer Audio Video Event Article Note Page]
+ @object_types ~w[ChatMessage Question Answer Audio Video Image Event Article Note Page]
@impl true
def persist(%{"type" => type} = object, meta) when type in @object_types do
with {:ok, object} <- Object.create(object) do
@@ -1453,13 +1453,22 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
@spec upload(Upload.source(), keyword()) :: {:ok, Object.t()} | {:error, any()}
def upload(file, opts \\ []) do
- with {:ok, data} <- Upload.store(file, opts) do
+ with {:ok, data} <- Upload.store(sanitize_upload_file(file), opts) do
obj_data = Maps.put_if_present(data, "actor", opts[:actor])
Repo.insert(%Object{data: obj_data})
end
end
+ defp sanitize_upload_file(%Plug.Upload{filename: filename} = upload) when is_binary(filename) do
+ %Plug.Upload{
+ upload
+ | filename: Path.basename(filename)
+ }
+ end
+
+ defp sanitize_upload_file(upload), do: upload
+
@spec get_actor_url(any()) :: binary() | nil
defp get_actor_url(url) when is_binary(url), do: url
defp get_actor_url(%{"href" => href}) when is_binary(href), do: href
@@ -1538,7 +1547,6 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
%{
ap_id: data["id"],
uri: get_actor_url(data["url"]),
- ap_enabled: true,
banner: normalize_image(data["image"]),
fields: fields,
emoji: emojis,
@@ -1659,7 +1667,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
end
end
- def fetch_and_prepare_user_from_ap_id(ap_id, additional \\ []) do
+ defp fetch_and_prepare_user_from_ap_id(ap_id, additional) do
with {:ok, data} <- Fetcher.fetch_and_contain_remote_object_from_id(ap_id),
{:ok, data} <- user_data_from_user_object(data, additional) do
{:ok, maybe_update_follow_information(data)}
@@ -1742,24 +1750,20 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
def make_user_from_ap_id(ap_id, additional \\ []) do
user = User.get_cached_by_ap_id(ap_id)
- if user && !User.ap_enabled?(user) do
- Transmogrifier.upgrade_user_from_ap_id(ap_id)
- else
- with {:ok, data} <- fetch_and_prepare_user_from_ap_id(ap_id, additional) do
- {:ok, _pid} = Task.start(fn -> pinned_fetch_task(data) end)
+ with {:ok, data} <- fetch_and_prepare_user_from_ap_id(ap_id, additional) do
+ {:ok, _pid} = Task.start(fn -> pinned_fetch_task(data) end)
- if user do
- user
- |> User.remote_user_changeset(data)
- |> User.update_and_set_cache()
- else
- maybe_handle_clashing_nickname(data)
+ if user do
+ user
+ |> User.remote_user_changeset(data)
+ |> User.update_and_set_cache()
+ else
+ maybe_handle_clashing_nickname(data)
- data
- |> User.remote_user_changeset()
- |> Repo.insert()
- |> User.set_cache()
- end
+ data
+ |> User.remote_user_changeset()
+ |> Repo.insert()
+ |> User.set_cache()
end
end
end
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/mrf/force_mentions_in_content.ex b/lib/pleroma/web/activity_pub/mrf/force_mentions_in_content.ex
index 70224561c..5532093cb 100644
--- a/lib/pleroma/web/activity_pub/mrf/force_mentions_in_content.ex
+++ b/lib/pleroma/web/activity_pub/mrf/force_mentions_in_content.ex
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2023 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.ActivityPub.MRF.ForceMentionsInContent do
@@ -95,11 +95,13 @@ defmodule Pleroma.Web.ActivityPub.MRF.ForceMentionsInContent do
|> Enum.reject(&is_nil/1)
|> sort_replied_user(replied_to_user)
- explicitly_mentioned_uris = extract_mention_uris_from_content(content)
+ explicitly_mentioned_uris =
+ extract_mention_uris_from_content(content)
+ |> MapSet.new()
added_mentions =
- Enum.reduce(mention_users, "", fn %User{ap_id: uri} = user, acc ->
- unless uri in explicitly_mentioned_uris do
+ Enum.reduce(mention_users, "", fn %User{ap_id: ap_id, uri: uri} = user, acc ->
+ if MapSet.disjoint?(MapSet.new([ap_id, uri]), explicitly_mentioned_uris) do
acc <> Formatter.mention_from_user(user, %{mentions_format: :compact}) <> " "
else
acc
diff --git a/lib/pleroma/web/activity_pub/object_validator.ex b/lib/pleroma/web/activity_pub/object_validator.ex
index 5bcd6da46..5e0d1aa8e 100644
--- a/lib/pleroma/web/activity_pub/object_validator.ex
+++ b/lib/pleroma/web/activity_pub/object_validator.ex
@@ -21,7 +21,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidator do
alias Pleroma.Web.ActivityPub.ObjectValidators.AnnounceValidator
alias Pleroma.Web.ActivityPub.ObjectValidators.AnswerValidator
alias Pleroma.Web.ActivityPub.ObjectValidators.ArticleNotePageValidator
- alias Pleroma.Web.ActivityPub.ObjectValidators.AudioVideoValidator
+ alias Pleroma.Web.ActivityPub.ObjectValidators.AudioImageVideoValidator
alias Pleroma.Web.ActivityPub.ObjectValidators.BlockValidator
alias Pleroma.Web.ActivityPub.ObjectValidators.ChatMessageValidator
alias Pleroma.Web.ActivityPub.ObjectValidators.CreateChatMessageValidator
@@ -102,7 +102,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidator do
%{"type" => "Create", "object" => %{"type" => objtype} = object} = create_activity,
meta
)
- when objtype in ~w[Question Answer Audio Video Event Article Note Page] do
+ when objtype in ~w[Question Answer Audio Video Image Event Article Note Page] do
with {:ok, object_data} <- cast_and_apply_and_stringify_with_history(object),
meta = Keyword.put(meta, :object_data, object_data),
{:ok, create_activity} <-
@@ -115,13 +115,14 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidator do
end
def validate(%{"type" => type} = object, meta)
- when type in ~w[Event Question Audio Video Article Note Page] do
+ when type in ~w[Event Question Audio Video Image Article Note Page] do
validator =
case type do
"Event" -> EventValidator
"Question" -> QuestionValidator
- "Audio" -> AudioVideoValidator
- "Video" -> AudioVideoValidator
+ "Audio" -> AudioImageVideoValidator
+ "Video" -> AudioImageVideoValidator
+ "Image" -> AudioImageVideoValidator
"Article" -> ArticleNotePageValidator
"Note" -> ArticleNotePageValidator
"Page" -> ArticleNotePageValidator
@@ -233,8 +234,8 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidator do
AnswerValidator.cast_and_apply(object)
end
- def cast_and_apply(%{"type" => type} = object) when type in ~w[Audio Video] do
- AudioVideoValidator.cast_and_apply(object)
+ def cast_and_apply(%{"type" => type} = object) when type in ~w[Audio Image Video] do
+ AudioImageVideoValidator.cast_and_apply(object)
end
def cast_and_apply(%{"type" => "Event"} = object) do
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 5202db7f1..db3259550 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
@@ -73,6 +73,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.AddRemoveValidator do
end
defp maybe_refetch_user(%User{ap_id: ap_id}) do
- Pleroma.Web.ActivityPub.Transmogrifier.upgrade_user_from_ap_id(ap_id)
+ # Maybe it could use User.get_or_fetch_by_ap_id to avoid refreshing too often
+ User.fetch_by_ap_id(ap_id)
end
end
diff --git a/lib/pleroma/web/activity_pub/object_validators/audio_video_validator.ex b/lib/pleroma/web/activity_pub/object_validators/audio_image_video_validator.ex
index 671a7ef0c..79ff76104 100644
--- a/lib/pleroma/web/activity_pub/object_validators/audio_video_validator.ex
+++ b/lib/pleroma/web/activity_pub/object_validators/audio_image_video_validator.ex
@@ -2,7 +2,7 @@
# Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
-defmodule Pleroma.Web.ActivityPub.ObjectValidators.AudioVideoValidator do
+defmodule Pleroma.Web.ActivityPub.ObjectValidators.AudioImageVideoValidator do
use Ecto.Schema
alias Pleroma.Web.ActivityPub.ObjectValidators.CommonFixes
@@ -55,9 +55,14 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.AudioVideoValidator do
url
|> Enum.concat(mpeg_url["tag"] || [])
|> Enum.find(fn
- %{"mediaType" => mime_type} -> String.starts_with?(mime_type, ["video/", "audio/"])
- %{"mimeType" => mime_type} -> String.starts_with?(mime_type, ["video/", "audio/"])
- _ -> false
+ %{"mediaType" => mime_type} ->
+ String.starts_with?(mime_type, ["video/", "audio/", "image/"])
+
+ %{"mimeType" => mime_type} ->
+ String.starts_with?(mime_type, ["video/", "audio/", "image/"])
+
+ _ ->
+ false
end)
end
@@ -110,7 +115,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.AudioVideoValidator do
defp validate_data(data_cng) do
data_cng
- |> validate_inclusion(:type, ["Audio", "Video"])
+ |> validate_inclusion(:type, ~w[Audio Image Video])
|> validate_required([:id, :actor, :attributedTo, :type, :context])
|> CommonValidations.validate_any_presence([:cc, :to])
|> CommonValidations.validate_fields_match([:actor, :attributedTo])
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 7b60c139a..d580208df 100644
--- a/lib/pleroma/web/activity_pub/object_validators/common_fields.ex
+++ b/lib/pleroma/web/activity_pub/object_validators/common_fields.ex
@@ -58,7 +58,7 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.CommonFields do
field(:like_count, :integer, default: 0)
field(:announcement_count, :integer, default: 0)
field(:inReplyTo, ObjectValidators.ObjectID)
- field(:url, ObjectValidators.Uri)
+ field(:url, ObjectValidators.BareUri)
field(:likes, {:array, ObjectValidators.ObjectID}, default: [])
field(:announcements, {:array, ObjectValidators.ObjectID}, default: [])
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/object_validators/tag_validator.ex b/lib/pleroma/web/activity_pub/object_validators/tag_validator.ex
index 9f15f1981..cfd510c19 100644
--- a/lib/pleroma/web/activity_pub/object_validators/tag_validator.ex
+++ b/lib/pleroma/web/activity_pub/object_validators/tag_validator.ex
@@ -68,6 +68,12 @@ defmodule Pleroma.Web.ActivityPub.ObjectValidators.TagValidator do
|> validate_required([:type, :name, :icon])
end
+ def changeset(struct, %{"type" => _} = data) do
+ struct
+ |> cast(data, [])
+ |> Map.put(:action, :ignore)
+ end
+
def icon_changeset(struct, data) do
struct
|> cast(data, [:type, :url])
diff --git a/lib/pleroma/web/activity_pub/publisher.ex b/lib/pleroma/web/activity_pub/publisher.ex
index 6c1ba76a3..af6aa0781 100644
--- a/lib/pleroma/web/activity_pub/publisher.ex
+++ b/lib/pleroma/web/activity_pub/publisher.ex
@@ -199,7 +199,6 @@ defmodule Pleroma.Web.ActivityPub.Publisher do
inboxes =
recipients
- |> Enum.filter(&User.ap_enabled?/1)
|> Enum.map(fn actor -> actor.inbox end)
|> Enum.filter(fn inbox -> should_federate?(inbox, public) end)
|> Instances.filter_reachable()
@@ -241,7 +240,6 @@ defmodule Pleroma.Web.ActivityPub.Publisher do
json = Jason.encode!(data)
recipients(actor, activity)
- |> Enum.filter(fn user -> User.ap_enabled?(user) end)
|> Enum.map(fn %User{} = user ->
determine_inbox(activity, user)
end)
diff --git a/lib/pleroma/web/activity_pub/side_effects.ex b/lib/pleroma/web/activity_pub/side_effects.ex
index a2152b945..098c177c7 100644
--- a/lib/pleroma/web/activity_pub/side_effects.ex
+++ b/lib/pleroma/web/activity_pub/side_effects.ex
@@ -428,37 +428,13 @@ defmodule Pleroma.Web.ActivityPub.SideEffects do
end
if orig_object_data["type"] in Pleroma.Constants.updatable_object_types() do
- %{
- updated_data: updated_object_data,
- updated: updated,
- used_history_in_new_object?: used_history_in_new_object?
- } = Object.Updater.make_new_object_data_from_update_object(orig_object_data, updated_object)
-
- changeset =
- orig_object
- |> Repo.preload(:hashtags)
- |> Object.change(%{data: updated_object_data})
-
- with {:ok, new_object} <- Repo.update(changeset),
- {:ok, _} <- Object.invalid_object_cache(new_object),
- {:ok, _} <- Object.set_cache(new_object),
- # The metadata/utils.ex uses the object id for the cache.
- {:ok, _} <- Pleroma.Activity.HTML.invalidate_cache_for(new_object.id) do
- if used_history_in_new_object? do
- with create_activity when not is_nil(create_activity) <-
- Pleroma.Activity.get_create_by_object_ap_id(orig_object_ap_id),
- {:ok, _} <- Pleroma.Activity.HTML.invalidate_cache_for(create_activity.id) do
- nil
- else
- _ -> nil
- end
- end
+ {:ok, _, updated} =
+ Object.Updater.do_update_and_invalidate_cache(orig_object, updated_object)
- if updated do
- object
- |> Activity.normalize()
- |> ActivityPub.notify_and_stream()
- end
+ if updated do
+ object
+ |> Activity.normalize()
+ |> ActivityPub.notify_and_stream()
end
end
@@ -520,7 +496,7 @@ defmodule Pleroma.Web.ActivityPub.SideEffects do
end
def handle_object_creation(%{"type" => objtype} = object, _activity, meta)
- when objtype in ~w[Audio Video Event Article Note Page] do
+ when objtype in ~w[Audio Video Image Event Article Note Page] do
with {:ok, object, meta} <- Pipeline.common_pipeline(object, meta) do
{:ok, object, meta}
end
diff --git a/lib/pleroma/web/activity_pub/transmogrifier.ex b/lib/pleroma/web/activity_pub/transmogrifier.ex
index e4c04da0d..0e6c429f9 100644
--- a/lib/pleroma/web/activity_pub/transmogrifier.ex
+++ b/lib/pleroma/web/activity_pub/transmogrifier.ex
@@ -20,7 +20,6 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
alias Pleroma.Web.ActivityPub.Utils
alias Pleroma.Web.ActivityPub.Visibility
alias Pleroma.Web.Federator
- alias Pleroma.Workers.TransmogrifierWorker
import Ecto.Query
@@ -447,7 +446,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
%{"type" => "Create", "object" => %{"type" => objtype, "id" => obj_id}} = data,
options
)
- when objtype in ~w{Question Answer ChatMessage Audio Video Event Article Note Page} do
+ when objtype in ~w{Question Answer ChatMessage Audio Video Event Article Note Page Image} do
fetch_options = Keyword.put(options, :depth, (options[:depth] || 0) + 1)
object =
@@ -946,47 +945,6 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
defp strip_internal_tags(object), do: object
- def perform(:user_upgrade, user) do
- # we pass a fake user so that the followers collection is stripped away
- old_follower_address = User.ap_followers(%User{nickname: user.nickname})
-
- from(
- a in Activity,
- where: ^old_follower_address in a.recipients,
- update: [
- set: [
- recipients:
- fragment(
- "array_replace(?,?,?)",
- a.recipients,
- ^old_follower_address,
- ^user.follower_address
- )
- ]
- ]
- )
- |> Repo.update_all([])
- end
-
- def upgrade_user_from_ap_id(ap_id) do
- with %User{local: false} = user <- User.get_cached_by_ap_id(ap_id),
- {:ok, data} <- ActivityPub.fetch_and_prepare_user_from_ap_id(ap_id),
- {:ok, user} <- update_user(user, data) do
- {:ok, _pid} = Task.start(fn -> ActivityPub.pinned_fetch_task(user) end)
- TransmogrifierWorker.enqueue("user_upgrade", %{"user_id" => user.id})
- {:ok, user}
- else
- %User{} = user -> {:ok, user}
- e -> e
- end
- end
-
- defp update_user(user, data) do
- user
- |> User.remote_user_changeset(data)
- |> User.update_and_set_cache()
- end
-
def maybe_fix_user_url(%{"url" => url} = data) when is_map(url) do
Map.put(data, "url", url["href"])
end
diff --git a/lib/pleroma/web/activity_pub/utils.ex b/lib/pleroma/web/activity_pub/utils.ex
index b898d6fe8..437220077 100644
--- a/lib/pleroma/web/activity_pub/utils.ex
+++ b/lib/pleroma/web/activity_pub/utils.ex
@@ -31,7 +31,8 @@ defmodule Pleroma.Web.ActivityPub.Utils do
"Page",
"Question",
"Answer",
- "Audio"
+ "Audio",
+ "Image"
]
@strip_status_report_states ~w(closed resolved)
@supported_report_states ~w(open closed resolved)
@@ -325,21 +326,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 +357,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 +398,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)
@@ -377,11 +408,7 @@ defmodule Pleroma.Web.ActivityPub.Utils do
end
def get_cached_emoji_reactions(object) do
- if is_list(object.data["reactions"]) do
- object.data["reactions"]
- else
- []
- end
+ Object.get_emoji_reactions(object)
end
@spec add_like_to_object(Activity.t(), Object.t()) ::
@@ -489,17 +516,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/admin_api/controllers/frontend_controller.ex b/lib/pleroma/web/admin_api/controllers/frontend_controller.ex
index b4dbb82fe..9e2ed4aac 100644
--- a/lib/pleroma/web/admin_api/controllers/frontend_controller.ex
+++ b/lib/pleroma/web/admin_api/controllers/frontend_controller.ex
@@ -18,13 +18,24 @@ defmodule Pleroma.Web.AdminAPI.FrontendController do
def index(conn, _params) do
installed = installed()
+ # FIrst get frontends from config,
+ # then add frontends that are installed but not in the config
frontends =
- [:frontends, :available]
- |> Config.get([])
+ Config.get([:frontends, :available], [])
|> Enum.map(fn {name, desc} ->
- Map.put(desc, "installed", name in installed)
+ desc
+ |> Map.put("installed", name in installed)
+ |> Map.put("installed_refs", installed_refs(name))
end)
+ frontends =
+ frontends ++
+ (installed
+ |> Enum.filter(fn n -> not Enum.any?(frontends, fn f -> f["name"] == n end) end)
+ |> Enum.map(fn name ->
+ %{"name" => name, "installed" => true, "installed_refs" => installed_refs(name)}
+ end))
+
render(conn, "index.json", frontends: frontends)
end
@@ -43,4 +54,12 @@ defmodule Pleroma.Web.AdminAPI.FrontendController do
[]
end
end
+
+ def installed_refs(name) do
+ if name in installed() do
+ File.ls!(Path.join(Pleroma.Frontend.dir(), name))
+ else
+ []
+ end
+ end
end
diff --git a/lib/pleroma/web/admin_api/report.ex b/lib/pleroma/web/admin_api/report.ex
index c79bee27e..fa89e3405 100644
--- a/lib/pleroma/web/admin_api/report.ex
+++ b/lib/pleroma/web/admin_api/report.ex
@@ -31,7 +31,7 @@ defmodule Pleroma.Web.AdminAPI.Report do
defp make_fake_activity(act, user) do
%Activity{
- id: "pleroma:fake",
+ id: "pleroma:fake:#{act["id"]}",
data: %{
"actor" => user.ap_id,
"type" => "Create",
diff --git a/lib/pleroma/web/admin_api/views/frontend_view.ex b/lib/pleroma/web/admin_api/views/frontend_view.ex
index 0ca3d67cb..ae4016581 100644
--- a/lib/pleroma/web/admin_api/views/frontend_view.ex
+++ b/lib/pleroma/web/admin_api/views/frontend_view.ex
@@ -15,7 +15,8 @@ defmodule Pleroma.Web.AdminAPI.FrontendView do
git: frontend["git"],
build_url: frontend["build_url"],
ref: frontend["ref"],
- installed: frontend["installed"]
+ installed: frontend["installed"],
+ installed_refs: frontend["installed_refs"]
}
end
end
diff --git a/lib/pleroma/web/api_spec.ex b/lib/pleroma/web/api_spec.ex
index cae4241ff..2d56dc643 100644
--- a/lib/pleroma/web/api_spec.ex
+++ b/lib/pleroma/web/api_spec.ex
@@ -95,7 +95,8 @@ defmodule Pleroma.Web.ApiSpec do
"Relays",
"Report managment",
"Status administration",
- "User administration"
+ "User administration",
+ "Announcement management"
]
},
%{"name" => "Applications", "tags" => ["Applications", "Push subscriptions"]},
@@ -110,10 +111,12 @@ defmodule Pleroma.Web.ApiSpec do
"Follow requests",
"Mascot",
"Markers",
- "Notifications"
+ "Notifications",
+ "Filters",
+ "Settings"
]
},
- %{"name" => "Instance", "tags" => ["Custom emojis"]},
+ %{"name" => "Instance", "tags" => ["Custom emojis", "Instance misc"]},
%{"name" => "Messaging", "tags" => ["Chats", "Conversations"]},
%{
"name" => "Statuses",
@@ -125,10 +128,21 @@ defmodule Pleroma.Web.ApiSpec do
"Retrieve status information",
"Scheduled statuses",
"Search",
- "Status actions"
+ "Status actions",
+ "Media attachments"
]
},
- %{"name" => "Miscellaneous", "tags" => ["Emoji packs", "Reports", "Suggestions"]}
+ %{
+ "name" => "Miscellaneous",
+ "tags" => [
+ "Emoji packs",
+ "Reports",
+ "Suggestions",
+ "Announcements",
+ "Remote interaction",
+ "Others"
+ ]
+ }
]
}
}
diff --git a/lib/pleroma/web/api_spec/operations/account_operation.ex b/lib/pleroma/web/api_spec/operations/account_operation.ex
index aabe988f7..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())
}
@@ -461,7 +461,7 @@ defmodule Pleroma.Web.ApiSpec.AccountOperation do
def lookup_operation do
%Operation{
- tags: ["Account lookup"],
+ tags: ["Retrieve account information"],
summary: "Find a user by nickname",
operationId: "AccountController.lookup",
parameters: [
diff --git a/lib/pleroma/web/api_spec/operations/admin/announcement_operation.ex b/lib/pleroma/web/api_spec/operations/admin/announcement_operation.ex
index 58a039e72..49850e5d2 100644
--- a/lib/pleroma/web/api_spec/operations/admin/announcement_operation.ex
+++ b/lib/pleroma/web/api_spec/operations/admin/announcement_operation.ex
@@ -17,7 +17,7 @@ defmodule Pleroma.Web.ApiSpec.Admin.AnnouncementOperation do
def index_operation do
%Operation{
- tags: ["Announcement managment"],
+ tags: ["Announcement management"],
summary: "Retrieve a list of announcements",
operationId: "AdminAPI.AnnouncementController.index",
security: [%{"oAuth" => ["admin:read"]}],
@@ -46,7 +46,7 @@ defmodule Pleroma.Web.ApiSpec.Admin.AnnouncementOperation do
def show_operation do
%Operation{
- tags: ["Announcement managment"],
+ tags: ["Announcement management"],
summary: "Display one announcement",
operationId: "AdminAPI.AnnouncementController.show",
security: [%{"oAuth" => ["admin:read"]}],
@@ -69,7 +69,7 @@ defmodule Pleroma.Web.ApiSpec.Admin.AnnouncementOperation do
def delete_operation do
%Operation{
- tags: ["Announcement managment"],
+ tags: ["Announcement management"],
summary: "Delete one announcement",
operationId: "AdminAPI.AnnouncementController.delete",
security: [%{"oAuth" => ["admin:write"]}],
@@ -92,7 +92,7 @@ defmodule Pleroma.Web.ApiSpec.Admin.AnnouncementOperation do
def create_operation do
%Operation{
- tags: ["Announcement managment"],
+ tags: ["Announcement management"],
summary: "Create one announcement",
operationId: "AdminAPI.AnnouncementController.create",
security: [%{"oAuth" => ["admin:write"]}],
@@ -107,7 +107,7 @@ defmodule Pleroma.Web.ApiSpec.Admin.AnnouncementOperation do
def change_operation do
%Operation{
- tags: ["Announcement managment"],
+ tags: ["Announcement management"],
summary: "Change one announcement",
operationId: "AdminAPI.AnnouncementController.change",
security: [%{"oAuth" => ["admin:write"]}],
diff --git a/lib/pleroma/web/api_spec/operations/admin/frontend_operation.ex b/lib/pleroma/web/api_spec/operations/admin/frontend_operation.ex
index 4bfe5ac5a..3e85c44d2 100644
--- a/lib/pleroma/web/api_spec/operations/admin/frontend_operation.ex
+++ b/lib/pleroma/web/api_spec/operations/admin/frontend_operation.ex
@@ -51,8 +51,9 @@ defmodule Pleroma.Web.ApiSpec.Admin.FrontendOperation do
name: %Schema{type: :string},
git: %Schema{type: :string, format: :uri, nullable: true},
build_url: %Schema{type: :string, format: :uri, nullable: true},
- ref: %Schema{type: :string},
- installed: %Schema{type: :boolean}
+ ref: %Schema{type: :string, nullable: true},
+ installed: %Schema{type: :boolean},
+ installed_refs: %Schema{type: :array, items: %Schema{type: :string}}
}
}
}
diff --git a/lib/pleroma/web/api_spec/operations/admin/status_operation.ex b/lib/pleroma/web/api_spec/operations/admin/status_operation.ex
index 229912dd7..17383f1d0 100644
--- a/lib/pleroma/web/api_spec/operations/admin/status_operation.ex
+++ b/lib/pleroma/web/api_spec/operations/admin/status_operation.ex
@@ -70,7 +70,7 @@ defmodule Pleroma.Web.ApiSpec.Admin.StatusOperation do
def show_operation do
%Operation{
- tags: ["Status adminitration)"],
+ tags: ["Status administration"],
summary: "Get status",
operationId: "AdminAPI.StatusController.show",
parameters: [id_param() | admin_api_params()],
@@ -84,7 +84,7 @@ defmodule Pleroma.Web.ApiSpec.Admin.StatusOperation do
def update_operation do
%Operation{
- tags: ["Status adminitration)"],
+ tags: ["Status administration"],
summary: "Change the scope of a status",
operationId: "AdminAPI.StatusController.update",
parameters: [id_param() | admin_api_params()],
@@ -99,7 +99,7 @@ defmodule Pleroma.Web.ApiSpec.Admin.StatusOperation do
def delete_operation do
%Operation{
- tags: ["Status adminitration)"],
+ tags: ["Status administration"],
summary: "Delete status",
operationId: "AdminAPI.StatusController.delete",
parameters: [id_param() | admin_api_params()],
@@ -143,7 +143,7 @@ defmodule Pleroma.Web.ApiSpec.Admin.StatusOperation do
}
},
tags: %Schema{type: :string},
- is_confirmed: %Schema{type: :string}
+ is_confirmed: %Schema{type: :boolean}
}
}
end
diff --git a/lib/pleroma/web/api_spec/operations/announcement_operation.ex b/lib/pleroma/web/api_spec/operations/announcement_operation.ex
index 71be0002a..6f7031962 100644
--- a/lib/pleroma/web/api_spec/operations/announcement_operation.ex
+++ b/lib/pleroma/web/api_spec/operations/announcement_operation.ex
@@ -15,7 +15,7 @@ defmodule Pleroma.Web.ApiSpec.AnnouncementOperation do
def index_operation do
%Operation{
- tags: ["Announcement"],
+ tags: ["Announcements"],
summary: "Retrieve a list of announcements",
operationId: "MastodonAPI.AnnouncementController.index",
security: [%{"oAuth" => []}],
@@ -28,7 +28,7 @@ defmodule Pleroma.Web.ApiSpec.AnnouncementOperation do
def mark_read_operation do
%Operation{
- tags: ["Announcement"],
+ tags: ["Announcements"],
summary: "Mark one announcement as read",
operationId: "MastodonAPI.AnnouncementController.mark_read",
security: [%{"oAuth" => ["write:accounts"]}],
diff --git a/lib/pleroma/web/api_spec/operations/directory_operation.ex b/lib/pleroma/web/api_spec/operations/directory_operation.ex
index 55752fa62..23fa84dff 100644
--- a/lib/pleroma/web/api_spec/operations/directory_operation.ex
+++ b/lib/pleroma/web/api_spec/operations/directory_operation.ex
@@ -17,7 +17,7 @@ defmodule Pleroma.Web.ApiSpec.DirectoryOperation do
def index_operation do
%Operation{
- tags: ["Directory"],
+ tags: ["Others"],
summary: "Profile directory",
operationId: "DirectoryController.index",
parameters:
diff --git a/lib/pleroma/web/api_spec/operations/instance_operation.ex b/lib/pleroma/web/api_spec/operations/instance_operation.ex
index 3c4b504fe..a07be7e40 100644
--- a/lib/pleroma/web/api_spec/operations/instance_operation.ex
+++ b/lib/pleroma/web/api_spec/operations/instance_operation.ex
@@ -13,7 +13,7 @@ defmodule Pleroma.Web.ApiSpec.InstanceOperation do
def show_operation do
%Operation{
- tags: ["Instance"],
+ tags: ["Instance misc"],
summary: "Retrieve instance information",
description: "Information about the server",
operationId: "InstanceController.show",
@@ -25,7 +25,7 @@ defmodule Pleroma.Web.ApiSpec.InstanceOperation do
def peers_operation do
%Operation{
- tags: ["Instance"],
+ tags: ["Instance misc"],
summary: "Retrieve list of known instances",
operationId: "InstanceController.peers",
responses: %{
diff --git a/lib/pleroma/web/api_spec/operations/pleroma_emoji_file_operation.ex b/lib/pleroma/web/api_spec/operations/pleroma_emoji_file_operation.ex
index d09c1c10e..b05bad197 100644
--- a/lib/pleroma/web/api_spec/operations/pleroma_emoji_file_operation.ex
+++ b/lib/pleroma/web/api_spec/operations/pleroma_emoji_file_operation.ex
@@ -133,7 +133,11 @@ defmodule Pleroma.Web.ApiSpec.PleromaEmojiFileOperation do
defp files_object do
%Schema{
type: :object,
- additionalProperties: %Schema{type: :string},
+ additionalProperties: %Schema{
+ type: :string,
+ description: "Filename of the emoji",
+ extensions: %{"x-additionalPropertiesName": "Emoji name"}
+ },
description: "Object with emoji names as keys and filenames as values"
}
end
diff --git a/lib/pleroma/web/api_spec/operations/pleroma_emoji_pack_operation.ex b/lib/pleroma/web/api_spec/operations/pleroma_emoji_pack_operation.ex
index 6add3ff33..efa36ffdc 100644
--- a/lib/pleroma/web/api_spec/operations/pleroma_emoji_pack_operation.ex
+++ b/lib/pleroma/web/api_spec/operations/pleroma_emoji_pack_operation.ex
@@ -227,13 +227,29 @@ defmodule Pleroma.Web.ApiSpec.PleromaEmojiPackOperation do
defp emoji_packs_response do
Operation.response(
- "Object with pack names as keys and pack contents as values",
+ "Emoji packs and the count",
"application/json",
%Schema{
type: :object,
- additionalProperties: emoji_pack(),
+ properties: %{
+ packs: %Schema{
+ type: :object,
+ description: "Object with pack names as keys and pack contents as values",
+ additionalProperties: %Schema{
+ emoji_pack()
+ | extensions: %{"x-additionalPropertiesName": "Pack name"}
+ }
+ },
+ count: %Schema{
+ type: :integer,
+ description: "Number of emoji packs"
+ }
+ },
example: %{
- "emojos" => emoji_pack().example
+ "packs" => %{
+ "emojos" => emoji_pack().example
+ },
+ "count" => 1
}
}
)
@@ -274,7 +290,11 @@ defmodule Pleroma.Web.ApiSpec.PleromaEmojiPackOperation do
defp files_object do
%Schema{
type: :object,
- additionalProperties: %Schema{type: :string},
+ additionalProperties: %Schema{
+ type: :string,
+ description: "Filename",
+ extensions: %{"x-additionalPropertiesName": "Emoji name"}
+ },
description: "Object with emoji names as keys and filenames as values"
}
end
diff --git a/lib/pleroma/web/api_spec/operations/pleroma_instances_operation.ex b/lib/pleroma/web/api_spec/operations/pleroma_instances_operation.ex
index 82db4e1a8..e9319f3fb 100644
--- a/lib/pleroma/web/api_spec/operations/pleroma_instances_operation.ex
+++ b/lib/pleroma/web/api_spec/operations/pleroma_instances_operation.ex
@@ -13,7 +13,7 @@ defmodule Pleroma.Web.ApiSpec.PleromaInstancesOperation do
def show_operation do
%Operation{
- tags: ["Instance"],
+ tags: ["Instance misc"],
summary: "Retrieve federation status",
description: "Information about instances deemed unreachable by the server",
operationId: "PleromaInstances.show",
diff --git a/lib/pleroma/web/api_spec/operations/status_operation.ex b/lib/pleroma/web/api_spec/operations/status_operation.ex
index e921128c7..5d6e82f3c 100644
--- a/lib/pleroma/web/api_spec/operations/status_operation.ex
+++ b/lib/pleroma/web/api_spec/operations/status_operation.ex
@@ -440,7 +440,7 @@ defmodule Pleroma.Web.ApiSpec.StatusOperation do
def show_history_operation do
%Operation{
- tags: ["Retrieve status history"],
+ tags: ["Retrieve status information"],
summary: "Status history",
description: "View history of a status",
operationId: "StatusController.show_history",
@@ -457,7 +457,7 @@ defmodule Pleroma.Web.ApiSpec.StatusOperation do
def show_source_operation do
%Operation{
- tags: ["Retrieve status source"],
+ tags: ["Retrieve status information"],
summary: "Status source",
description: "View source of a status",
operationId: "StatusController.show_source",
@@ -474,7 +474,7 @@ defmodule Pleroma.Web.ApiSpec.StatusOperation do
def update_operation do
%Operation{
- tags: ["Update status"],
+ tags: ["Status actions"],
summary: "Update status",
description: "Change the content of a status",
operationId: "StatusController.update",
diff --git a/lib/pleroma/web/api_spec/operations/twitter_util_operation.ex b/lib/pleroma/web/api_spec/operations/twitter_util_operation.ex
index 29df03e34..084329ad7 100644
--- a/lib/pleroma/web/api_spec/operations/twitter_util_operation.ex
+++ b/lib/pleroma/web/api_spec/operations/twitter_util_operation.ex
@@ -17,7 +17,7 @@ defmodule Pleroma.Web.ApiSpec.TwitterUtilOperation do
def emoji_operation do
%Operation{
- tags: ["Emojis"],
+ tags: ["Custom emojis"],
summary: "List all custom emojis",
operationId: "UtilController.emoji",
parameters: [],
@@ -30,7 +30,8 @@ defmodule Pleroma.Web.ApiSpec.TwitterUtilOperation do
properties: %{
image_url: %Schema{type: :string},
tags: %Schema{type: :array, items: %Schema{type: :string}}
- }
+ },
+ extensions: %{"x-additionalPropertiesName": "Emoji name"}
},
example: %{
"firefox" => %{
@@ -45,7 +46,7 @@ defmodule Pleroma.Web.ApiSpec.TwitterUtilOperation do
def frontend_configurations_operation do
%Operation{
- tags: ["Configuration"],
+ tags: ["Others"],
summary: "Dump frontend configurations",
operationId: "UtilController.frontend_configurations",
parameters: [],
@@ -53,7 +54,12 @@ defmodule Pleroma.Web.ApiSpec.TwitterUtilOperation do
200 =>
Operation.response("List", "application/json", %Schema{
type: :object,
- additionalProperties: %Schema{type: :object}
+ additionalProperties: %Schema{
+ type: :object,
+ description:
+ "Opaque object representing the instance-wide configuration for the frontend",
+ extensions: %{"x-additionalPropertiesName": "Frontend name"}
+ }
})
}
}
@@ -132,7 +138,7 @@ defmodule Pleroma.Web.ApiSpec.TwitterUtilOperation do
def update_notificaton_settings_operation do
%Operation{
- tags: ["Accounts"],
+ tags: ["Settings"],
summary: "Update Notification Settings",
security: [%{"oAuth" => ["write:accounts"]}],
operationId: "UtilController.update_notificaton_settings",
@@ -207,6 +213,7 @@ defmodule Pleroma.Web.ApiSpec.TwitterUtilOperation do
%Operation{
summary: "Get a captcha",
operationId: "UtilController.captcha",
+ tags: ["Others"],
parameters: [],
responses: %{
200 => Operation.response("Success", "application/json", %Schema{type: :object})
@@ -356,7 +363,7 @@ defmodule Pleroma.Web.ApiSpec.TwitterUtilOperation do
def healthcheck_operation do
%Operation{
- tags: ["Accounts"],
+ tags: ["Others"],
summary: "Quick status check on the instance",
security: [%{"oAuth" => ["write:accounts"]}],
operationId: "UtilController.healthcheck",
@@ -371,7 +378,7 @@ defmodule Pleroma.Web.ApiSpec.TwitterUtilOperation do
def remote_subscribe_operation do
%Operation{
- tags: ["Accounts"],
+ tags: ["Remote interaction"],
summary: "Remote Subscribe",
operationId: "UtilController.remote_subscribe",
parameters: [],
@@ -381,7 +388,7 @@ defmodule Pleroma.Web.ApiSpec.TwitterUtilOperation do
def remote_interaction_operation do
%Operation{
- tags: ["Accounts"],
+ tags: ["Remote interaction"],
summary: "Remote interaction",
operationId: "UtilController.remote_interaction",
requestBody: request_body("Parameters", remote_interaction_request(), required: true),
@@ -407,7 +414,7 @@ defmodule Pleroma.Web.ApiSpec.TwitterUtilOperation do
def show_subscribe_form_operation do
%Operation{
- tags: ["Accounts"],
+ tags: ["Remote interaction"],
summary: "Show remote subscribe form",
operationId: "UtilController.show_subscribe_form",
parameters: [],
diff --git a/lib/pleroma/web/api_spec/schemas/status.ex b/lib/pleroma/web/api_spec/schemas/status.ex
index 698f11794..bc29cf4a6 100644
--- a/lib/pleroma/web/api_spec/schemas/status.ex
+++ b/lib/pleroma/web/api_spec/schemas/status.ex
@@ -144,7 +144,11 @@ defmodule Pleroma.Web.ApiSpec.Schemas.Status do
properties: %{
content: %Schema{
type: :object,
- additionalProperties: %Schema{type: :string},
+ additionalProperties: %Schema{
+ type: :string,
+ description: "Alternate representation in the MIME type specified",
+ extensions: %{"x-additionalPropertiesName": "MIME type"}
+ },
description:
"A map consisting of alternate representations of the `content` property with the key being it's mimetype. Currently the only alternate representation supported is `text/plain`"
},
@@ -195,7 +199,11 @@ defmodule Pleroma.Web.ApiSpec.Schemas.Status do
},
spoiler_text: %Schema{
type: :object,
- additionalProperties: %Schema{type: :string},
+ additionalProperties: %Schema{
+ type: :string,
+ description: "Alternate representation in the MIME type specified",
+ extensions: %{"x-additionalPropertiesName": "MIME type"}
+ },
description:
"A map consisting of alternate representations of the `spoiler_text` property with the key being it's mimetype. Currently the only alternate representation supported is `text/plain`."
},
diff --git a/lib/pleroma/web/api_spec/scopes/compiler.ex b/lib/pleroma/web/api_spec/scopes/compiler.ex
new file mode 100644
index 000000000..162edc9a3
--- /dev/null
+++ b/lib/pleroma/web/api_spec/scopes/compiler.ex
@@ -0,0 +1,82 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2023 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.ApiSpec.Scopes.Compiler do
+ defmacro __before_compile__(_env) do
+ strings = __MODULE__.extract_all_scopes()
+
+ quote do
+ def placeholder do
+ unquote do
+ Enum.map(
+ strings,
+ fn string ->
+ quote do
+ Pleroma.Web.Gettext.dgettext_noop(
+ "oauth_scopes",
+ unquote(string)
+ )
+ end
+ end
+ )
+ end
+ end
+ end
+ end
+
+ def extract_all_scopes do
+ extract_all_scopes_from(Pleroma.Web.ApiSpec.spec())
+ end
+
+ def extract_all_scopes_from(specs) do
+ specs.paths
+ |> Enum.reduce([], fn
+ {_path, %{} = path_item}, acc ->
+ extract_routes(path_item)
+ |> Enum.flat_map(fn operation -> process_operation(operation) end)
+ |> Kernel.++(acc)
+
+ {_, _}, acc ->
+ acc
+ end)
+ |> Enum.uniq()
+ end
+
+ defp extract_routes(path_item) do
+ path_item
+ |> Map.from_struct()
+ |> Enum.map(fn {_method, path_item} -> path_item end)
+ |> Enum.filter(fn
+ %OpenApiSpex.Operation{} = _operation -> true
+ _ -> false
+ end)
+ end
+
+ defp process_operation(operation) do
+ operation.security
+ |> Kernel.||([])
+ |> Enum.flat_map(fn
+ %{"oAuth" => scopes} -> process_scopes(scopes)
+ _ -> []
+ end)
+ end
+
+ defp process_scopes(scopes) do
+ scopes
+ |> Enum.flat_map(fn scope ->
+ process_scope(scope)
+ end)
+ end
+
+ def process_scope(scope) do
+ hierarchy = String.split(scope, ":")
+
+ {_, list} =
+ Enum.reduce(hierarchy, {"", []}, fn comp, {cur, list} ->
+ {cur <> comp <> ":", [cur <> comp | list]}
+ end)
+
+ list
+ end
+end
diff --git a/lib/pleroma/web/api_spec/scopes/translator.ex b/lib/pleroma/web/api_spec/scopes/translator.ex
new file mode 100644
index 000000000..54eea3593
--- /dev/null
+++ b/lib/pleroma/web/api_spec/scopes/translator.ex
@@ -0,0 +1,10 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2023 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.ApiSpec.Scopes.Translator do
+ require Pleroma.Web.ApiSpec.Scopes.Compiler
+ require Pleroma.Web.Gettext
+
+ @before_compile Pleroma.Web.ApiSpec.Scopes.Compiler
+end
diff --git a/lib/pleroma/web/common_api.ex b/lib/pleroma/web/common_api.ex
index 89cc0d6fe..65d08de49 100644
--- a/lib/pleroma/web/common_api.ex
+++ b/lib/pleroma/web/common_api.ex
@@ -142,7 +142,7 @@ defmodule Pleroma.Web.CommonAPI do
def delete(activity_id, user) do
with {_, %Activity{data: %{"object" => _, "type" => "Create"}} = activity} <-
- {:find_activity, Activity.get_by_id(activity_id)},
+ {:find_activity, Activity.get_by_id(activity_id, filter: [])},
{_, %Object{} = object, _} <-
{:find_object, Object.normalize(activity, fetch: false), activity},
true <- User.privileged?(user, :messages_delete) || user.ap_id == object.data["actor"],
diff --git a/lib/pleroma/web/common_api/utils.ex b/lib/pleroma/web/common_api/utils.ex
index ff0814329..a93c97e1e 100644
--- a/lib/pleroma/web/common_api/utils.ex
+++ b/lib/pleroma/web/common_api/utils.ex
@@ -145,6 +145,8 @@ defmodule Pleroma.Web.CommonAPI.Utils do
when is_list(options) do
limits = Config.get([:instance, :poll_limits])
+ options = options |> Enum.uniq()
+
with :ok <- validate_poll_expiration(expires_in, limits),
:ok <- validate_poll_options_amount(options, limits),
:ok <- validate_poll_options_length(options, limits) do
@@ -180,10 +182,15 @@ defmodule Pleroma.Web.CommonAPI.Utils do
end
defp validate_poll_options_amount(options, %{max_options: max_options}) do
- if Enum.count(options) > max_options do
- {:error, "Poll can't contain more than #{max_options} options"}
- else
- :ok
+ cond do
+ Enum.count(options) < 2 ->
+ {:error, "Poll must contain at least 2 options"}
+
+ Enum.count(options) > max_options ->
+ {:error, "Poll can't contain more than #{max_options} options"}
+
+ true ->
+ :ok
end
end
diff --git a/lib/pleroma/web/federator.ex b/lib/pleroma/web/federator.ex
index 318b6cb11..84b77cda1 100644
--- a/lib/pleroma/web/federator.ex
+++ b/lib/pleroma/web/federator.ex
@@ -6,7 +6,6 @@ defmodule Pleroma.Web.Federator do
alias Pleroma.Activity
alias Pleroma.Object.Containment
alias Pleroma.User
- alias Pleroma.Web.ActivityPub.ActivityPub
alias Pleroma.Web.ActivityPub.Transmogrifier
alias Pleroma.Web.ActivityPub.Utils
alias Pleroma.Web.Federator.Publisher
@@ -80,7 +79,7 @@ defmodule Pleroma.Web.Federator do
# NOTE: we use the actor ID to do the containment, this is fine because an
# actor shouldn't be acting on objects outside their own AP server.
- with {_, {:ok, _user}} <- {:actor, ap_enabled_actor(actor)},
+ with {_, {:ok, _user}} <- {:actor, User.get_or_fetch_by_ap_id(actor)},
nil <- Activity.normalize(params["id"]),
{_, :ok} <-
{:correct_origin?, Containment.contain_origin_from_id(actor, params)},
@@ -110,14 +109,4 @@ defmodule Pleroma.Web.Federator do
{:error, e}
end
end
-
- def ap_enabled_actor(id) do
- user = User.get_cached_by_ap_id(id)
-
- if User.ap_enabled?(user) do
- {:ok, user}
- else
- ActivityPub.make_user_from_ap_id(id)
- end
- end
end
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 ea6e593d9..c313a0e97 100644
--- a/lib/pleroma/web/mastodon_api/controllers/account_controller.ex
+++ b/lib/pleroma/web/mastodon_api/controllers/account_controller.ex
@@ -269,14 +269,11 @@ defmodule Pleroma.Web.MastodonAPI.AccountController do
end
defp normalize_fields_attributes(fields) do
- if Enum.all?(fields, &is_tuple/1) do
- Enum.map(fields, fn {_, v} -> v end)
- else
- Enum.map(fields, fn
- %{} = field -> %{"name" => field.name, "value" => field.value}
- field -> field
- end)
- end
+ if(Enum.all?(fields, &is_tuple/1), do: Enum.map(fields, fn {_, v} -> v end), else: fields)
+ |> Enum.map(fn
+ %{} = field -> %{"name" => field.name, "value" => field.value}
+ field -> field
+ end)
end
@doc "GET /api/v1/accounts/relationships"
@@ -543,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 917725839..efd2a0af6 100644
--- a/lib/pleroma/web/mastodon_api/views/instance_view.ex
+++ b/lib/pleroma/web/mastodon_api/views/instance_view.ex
@@ -27,7 +27,7 @@ defmodule Pleroma.Web.MastodonAPI.InstanceView do
thumbnail:
URI.merge(Pleroma.Web.Endpoint.url(), Keyword.get(instance, :instance_thumbnail))
|> to_string,
- languages: ["en"],
+ languages: Keyword.get(instance, :languages, ["en"]),
registrations: Keyword.get(instance, :registrations_open),
approval_required: Keyword.get(instance, :account_approval_required),
# Extra (not present in Mastodon):
@@ -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..dea22f9c2 100644
--- a/lib/pleroma/web/mastodon_api/views/status_view.ex
+++ b/lib/pleroma/web/mastodon_api/views/status_view.ex
@@ -334,14 +334,14 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do
end
emoji_reactions =
- object.data
- |> Map.get("reactions", [])
+ object
+ |> Object.get_emoji_reactions()
|> EmojiReactionController.filter_allowed_users(
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/media_proxy/media_proxy_controller.ex b/lib/pleroma/web/media_proxy/media_proxy_controller.ex
index d2ad62c13..bda5b36ed 100644
--- a/lib/pleroma/web/media_proxy/media_proxy_controller.ex
+++ b/lib/pleroma/web/media_proxy/media_proxy_controller.ex
@@ -12,6 +12,8 @@ defmodule Pleroma.Web.MediaProxy.MediaProxyController do
alias Pleroma.Web.MediaProxy
alias Plug.Conn
+ plug(:sandbox)
+
def remote(conn, %{"sig" => sig64, "url" => url64}) do
with {_, true} <- {:enabled, MediaProxy.enabled?()},
{:ok, url} <- MediaProxy.decode_url(sig64, url64),
@@ -202,4 +204,9 @@ defmodule Pleroma.Web.MediaProxy.MediaProxyController do
defp media_proxy_opts do
Config.get([:media_proxy, :proxy_opts], [])
end
+
+ defp sandbox(conn, _params) do
+ conn
+ |> merge_resp_headers([{"content-security-policy", "sandbox;"}])
+ 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/providers/twitter_card.ex b/lib/pleroma/web/metadata/providers/twitter_card.ex
index 2dac22ee2..426022c65 100644
--- a/lib/pleroma/web/metadata/providers/twitter_card.ex
+++ b/lib/pleroma/web/metadata/providers/twitter_card.ex
@@ -76,9 +76,10 @@ defmodule Pleroma.Web.Metadata.Providers.TwitterCard do
{:meta, [name: "twitter:card", content: "summary_large_image"], []},
{:meta,
[
- name: "twitter:player",
+ name: "twitter:image",
content: MediaProxy.url(url["href"])
- ], []}
+ ], []},
+ {:meta, [name: "twitter:image:alt", content: truncate(attachment["name"])], []}
| acc
]
|> maybe_add_dimensions(url)
@@ -130,4 +131,12 @@ defmodule Pleroma.Web.Metadata.Providers.TwitterCard do
metadata
end
end
+
+ defp truncate(nil), do: ""
+
+ defp truncate(text) do
+ # truncate to 420 characters
+ # see https://developer.twitter.com/en/docs/twitter-for-websites/cards/overview/markup
+ Pleroma.Formatter.truncate(text, 420)
+ 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..662cc15d6 100644
--- a/lib/pleroma/web/pleroma_api/controllers/emoji_reaction_controller.ex
+++ b/lib/pleroma/web/pleroma_api/controllers/emoji_reaction_controller.ex
@@ -28,8 +28,8 @@ defmodule Pleroma.Web.PleromaAPI.EmojiReactionController do
def index(%{assigns: %{user: user}} = conn, %{id: activity_id} = params) do
with true <- Pleroma.Config.get([:instance, :show_reactions]),
%Activity{} = activity <- Activity.get_by_id_with_object(activity_id),
- %Object{data: %{"reactions" => reactions}} when is_list(reactions) <-
- Object.normalize(activity, fetch: false) do
+ %Object{} = object <- Object.normalize(activity, fetch: false),
+ reactions <- Object.get_emoji_reactions(object) do
reactions =
reactions
|> filter(params)
@@ -50,29 +50,32 @@ 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)
- _ -> nil
+ [emoji, users, url] when is_list(users) -> filter_emoji.(emoji, users, url)
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 +86,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/plugs/http_signature_plug.ex b/lib/pleroma/web/plugs/http_signature_plug.ex
index 4bf325218..e814efc2c 100644
--- a/lib/pleroma/web/plugs/http_signature_plug.ex
+++ b/lib/pleroma/web/plugs/http_signature_plug.ex
@@ -16,7 +16,7 @@ defmodule Pleroma.Web.Plugs.HTTPSignaturePlug do
end
def call(conn, _opts) do
- if get_format(conn) == "activity+json" do
+ if get_format(conn) in ["json", "activity+json"] do
conn
|> maybe_assign_valid_signature()
|> maybe_require_signature()
diff --git a/lib/pleroma/web/plugs/uploaded_media.ex b/lib/pleroma/web/plugs/uploaded_media.ex
index ad8143234..9dd5eb239 100644
--- a/lib/pleroma/web/plugs/uploaded_media.ex
+++ b/lib/pleroma/web/plugs/uploaded_media.ex
@@ -35,9 +35,9 @@ defmodule Pleroma.Web.Plugs.UploadedMedia do
conn =
case fetch_query_params(conn) do
%{query_params: %{"name" => name}} = conn ->
- name = String.replace(name, "\"", "\\\"")
+ name = String.replace(name, ~s["], ~s[\\"])
- put_resp_header(conn, "content-disposition", "filename=\"#{name}\"")
+ put_resp_header(conn, "content-disposition", ~s[inline; filename="#{name}"])
conn ->
conn
@@ -46,12 +46,32 @@ defmodule Pleroma.Web.Plugs.UploadedMedia do
config = Pleroma.Config.get(Pleroma.Upload)
- with uploader <- Keyword.fetch!(config, :uploader),
+ %{scheme: media_scheme, host: media_host, port: media_port} =
+ Pleroma.Upload.base_url() |> URI.parse()
+
+ with {:valid_host, true} <- {:valid_host, match?(^media_host, conn.host)},
+ uploader <- Keyword.fetch!(config, :uploader),
proxy_remote = Keyword.get(config, :proxy_remote, false),
{:ok, get_method} <- uploader.get_file(file),
false <- media_is_banned(conn, get_method) do
get_media(conn, get_method, proxy_remote, opts)
else
+ {:valid_host, false} ->
+ redirect_url =
+ %URI{
+ scheme: media_scheme,
+ host: media_host,
+ port: media_port,
+ path: conn.request_path,
+ query: conn.query_string
+ }
+ |> URI.to_string()
+ |> String.trim_trailing("?")
+
+ conn
+ |> Phoenix.Controller.redirect(external: redirect_url)
+ |> halt()
+
_ ->
conn
|> send_resp(:internal_server_error, dgettext("errors", "Failed"))
diff --git a/lib/pleroma/web/preload.ex b/lib/pleroma/web/preload.ex
index 4485383f9..6a4a8885e 100644
--- a/lib/pleroma/web/preload.ex
+++ b/lib/pleroma/web/preload.ex
@@ -11,7 +11,7 @@ defmodule Pleroma.Web.Preload do
terms =
params
|> parser.generate_terms()
- |> Enum.map(fn {k, v} -> {k, Base.encode64(Jason.encode!(v))} end)
+ |> Enum.map(fn {k, v} -> {k, Base.encode64(Jason.encode!(v, escape: :html_safe))} end)
|> Enum.into(%{})
Map.merge(acc, terms)
@@ -19,7 +19,7 @@ defmodule Pleroma.Web.Preload do
rendered_html =
preload_data
- |> Jason.encode!()
+ |> Jason.encode!(escape: :html_safe)
|> build_script_tag()
|> HTML.safe_to_string()
diff --git a/lib/pleroma/web/rel_me.ex b/lib/pleroma/web/rel_me.ex
index 98fbc1c59..ceb6a05f0 100644
--- a/lib/pleroma/web/rel_me.ex
+++ b/lib/pleroma/web/rel_me.ex
@@ -9,17 +9,13 @@ defmodule Pleroma.Web.RelMe do
recv_timeout: 2_000
]
- if Pleroma.Config.get(:env) == :test do
- def parse(url) when is_binary(url), do: parse_url(url)
- else
- @cachex Pleroma.Config.get([:cachex, :provider], Cachex)
- def parse(url) when is_binary(url) do
- @cachex.fetch!(:rel_me_cache, url, fn _ ->
- {:commit, parse_url(url)}
- end)
- rescue
- e -> {:error, "Cachex error: #{inspect(e)}"}
- end
+ @cachex Pleroma.Config.get([:cachex, :provider], Cachex)
+ def parse(url) when is_binary(url) do
+ @cachex.fetch!(:rel_me_cache, url, fn _ ->
+ {:commit, parse_url(url)}
+ end)
+ rescue
+ e -> {:error, "Cachex error: #{inspect(e)}"}
end
def parse(_), do: {:error, "No URL provided"}
diff --git a/lib/pleroma/web/rich_media/parsers/o_embed.ex b/lib/pleroma/web/rich_media/parsers/o_embed.ex
index 75318d9c7..0f303176c 100644
--- a/lib/pleroma/web/rich_media/parsers/o_embed.ex
+++ b/lib/pleroma/web/rich_media/parsers/o_embed.ex
@@ -6,8 +6,8 @@ defmodule Pleroma.Web.RichMedia.Parsers.OEmbed do
def parse(html, _data) do
with elements = [_ | _] <- get_discovery_data(html),
oembed_url when is_binary(oembed_url) <- get_oembed_url(elements),
- {:ok, oembed_data} <- get_oembed_data(oembed_url) do
- oembed_data
+ {:ok, oembed_data = %{"html" => html}} <- get_oembed_data(oembed_url) do
+ %{oembed_data | "html" => Pleroma.HTML.filter_tags(html)}
else
_e -> %{}
end
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/static_fe/static_fe_controller.ex b/lib/pleroma/web/static_fe/static_fe_controller.ex
index 97c41c6f9..8019a218a 100644
--- a/lib/pleroma/web/static_fe/static_fe_controller.ex
+++ b/lib/pleroma/web/static_fe/static_fe_controller.ex
@@ -25,7 +25,15 @@ defmodule Pleroma.Web.StaticFE.StaticFEController do
true <- Visibility.is_public?(activity.object),
{_, true} <- {:visible?, Visibility.visible_for_user?(activity, _reading_user = nil)},
%User{} = user <- User.get_by_ap_id(activity.object.data["actor"]) do
- meta = Metadata.build_tags(%{activity_id: notice_id, object: activity.object, user: user})
+ url = Helpers.url(conn) <> conn.request_path
+
+ meta =
+ Metadata.build_tags(%{
+ activity_id: notice_id,
+ object: activity.object,
+ user: user,
+ url: url
+ })
timeline =
activity.object.data["context"]
diff --git a/lib/pleroma/web/streamer.ex b/lib/pleroma/web/streamer.ex
index 3c0da5c27..b9a04cc76 100644
--- a/lib/pleroma/web/streamer.ex
+++ b/lib/pleroma/web/streamer.ex
@@ -25,6 +25,7 @@ defmodule Pleroma.Web.Streamer do
def registry, do: @registry
@public_streams ["public", "public:local", "public:media", "public:local:media"]
+ @local_streams ["public:local", "public:local:media"]
@user_streams ["user", "user:notification", "direct", "user:pleroma_chat"]
@doc "Expands and authorizes a stream, and registers the process for streaming."
@@ -41,14 +42,37 @@ defmodule Pleroma.Web.Streamer do
end
end
+ defp can_access_stream(user, oauth_token, kind) do
+ with {_, true} <- {:restrict?, Config.restrict_unauthenticated_access?(:timelines, kind)},
+ {_, %User{id: user_id}, %Token{user_id: user_id}} <- {:user, user, oauth_token},
+ {_, true} <-
+ {:scopes,
+ OAuthScopesPlug.filter_descendants(["read:statuses"], oauth_token.scopes) != []} do
+ true
+ else
+ {:restrict?, _} ->
+ true
+
+ _ ->
+ false
+ end
+ end
+
@doc "Expand and authorizes a stream"
@spec get_topic(stream :: String.t(), User.t() | nil, Token.t() | nil, Map.t()) ::
{:ok, topic :: String.t()} | {:error, :bad_topic}
def get_topic(stream, user, oauth_token, params \\ %{})
- # Allow all public steams.
- def get_topic(stream, _user, _oauth_token, _params) when stream in @public_streams do
- {:ok, stream}
+ # Allow all public steams if the instance allows unauthenticated access.
+ # Otherwise, only allow users with valid oauth tokens.
+ def get_topic(stream, user, oauth_token, _params) when stream in @public_streams do
+ kind = if stream in @local_streams, do: :local, else: :federated
+
+ if can_access_stream(user, oauth_token, kind) do
+ {:ok, stream}
+ else
+ {:error, :unauthorized}
+ end
end
# Allow all hashtags streams.
@@ -57,12 +81,20 @@ defmodule Pleroma.Web.Streamer do
end
# Allow remote instance streams.
- def get_topic("public:remote", _user, _oauth_token, %{"instance" => instance} = _params) do
- {:ok, "public:remote:" <> instance}
+ def get_topic("public:remote", user, oauth_token, %{"instance" => instance} = _params) do
+ if can_access_stream(user, oauth_token, :federated) do
+ {:ok, "public:remote:" <> instance}
+ else
+ {:error, :unauthorized}
+ end
end
- def get_topic("public:remote:media", _user, _oauth_token, %{"instance" => instance} = _params) do
- {:ok, "public:remote:media:" <> instance}
+ def get_topic("public:remote:media", user, oauth_token, %{"instance" => instance} = _params) do
+ if can_access_stream(user, oauth_token, :federated) do
+ {:ok, "public:remote:media:" <> instance}
+ else
+ {:error, :unauthorized}
+ end
end
# Expand user streams.
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/web/templates/o_auth/o_auth/_scopes.html.eex b/lib/pleroma/web/templates/o_auth/o_auth/_scopes.html.eex
index 73115e92a..7585c4d3e 100644
--- a/lib/pleroma/web/templates/o_auth/o_auth/_scopes.html.eex
+++ b/lib/pleroma/web/templates/o_auth/o_auth/_scopes.html.eex
@@ -8,7 +8,7 @@
<%= checkbox @form, :"scope_#{scope}", value: scope in @scopes && scope, checked_value: scope, unchecked_value: "", name: "authorization[scope][]" %>
<%= label @form, :"scope_#{scope}", String.capitalize(scope) %>
<%= if scope in @scopes && scope do %>
- <%= String.capitalize(scope) %>
+ <code><%= scope %></code> <%= :"Elixir.Gettext".dgettext(Gettext, "oauth_scopes", scope) %>
<% end %>
</div>
<% else %>
diff --git a/lib/pleroma/workers/background_worker.ex b/lib/pleroma/workers/background_worker.ex
index 3805293bc..794417612 100644
--- a/lib/pleroma/workers/background_worker.ex
+++ b/lib/pleroma/workers/background_worker.ex
@@ -45,5 +45,5 @@ defmodule Pleroma.Workers.BackgroundWorker do
end
@impl Oban.Worker
- def timeout(_job), do: :timer.seconds(5)
+ def timeout(_job), do: :timer.seconds(900)
end
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/lib/pleroma/workers/transmogrifier_worker.ex b/lib/pleroma/workers/transmogrifier_worker.ex
deleted file mode 100644
index 1f3f5385e..000000000
--- a/lib/pleroma/workers/transmogrifier_worker.ex
+++ /dev/null
@@ -1,18 +0,0 @@
-# Pleroma: A lightweight social networking server
-# Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
-# SPDX-License-Identifier: AGPL-3.0-only
-
-defmodule Pleroma.Workers.TransmogrifierWorker do
- alias Pleroma.User
-
- use Pleroma.Workers.WorkerHelper, queue: "transmogrifier"
-
- @impl Oban.Worker
- def perform(%Job{args: %{"op" => "user_upgrade", "user_id" => user_id}}) do
- user = User.get_cached_by_id(user_id)
- Pleroma.Web.ActivityPub.Transmogrifier.perform(:user_upgrade, user)
- end
-
- @impl Oban.Worker
- def timeout(_job), do: :timer.seconds(5)
-end