aboutsummaryrefslogtreecommitdiff
path: root/lib/pleroma/web
diff options
context:
space:
mode:
Diffstat (limited to 'lib/pleroma/web')
-rw-r--r--lib/pleroma/web/activity_pub/activity_pub.ex102
-rw-r--r--lib/pleroma/web/activity_pub/activity_pub_controller.ex107
-rw-r--r--lib/pleroma/web/activity_pub/builder.ex43
-rw-r--r--lib/pleroma/web/activity_pub/internal_fetch_actor.ex2
-rw-r--r--lib/pleroma/web/activity_pub/mrf.ex2
-rw-r--r--lib/pleroma/web/activity_pub/mrf/anti_followbot_policy.ex2
-rw-r--r--lib/pleroma/web/activity_pub/mrf/drop_policy.ex2
-rw-r--r--lib/pleroma/web/activity_pub/mrf/ensure_re_prepended.ex2
-rw-r--r--lib/pleroma/web/activity_pub/mrf/hellthread_policy.ex2
-rw-r--r--lib/pleroma/web/activity_pub/mrf/keyword_policy.ex2
-rw-r--r--lib/pleroma/web/activity_pub/mrf/media_proxy_warming_policy.ex14
-rw-r--r--lib/pleroma/web/activity_pub/mrf/mention_policy.ex2
-rw-r--r--lib/pleroma/web/activity_pub/mrf/no_placeholder_text_policy.ex2
-rw-r--r--lib/pleroma/web/activity_pub/mrf/normalize_markup.ex2
-rw-r--r--lib/pleroma/web/activity_pub/mrf/object_age_policy.ex10
-rw-r--r--lib/pleroma/web/activity_pub/mrf/reject_non_public.ex2
-rw-r--r--lib/pleroma/web/activity_pub/mrf/simple_policy.ex15
-rw-r--r--lib/pleroma/web/activity_pub/mrf/tag_policy.ex2
-rw-r--r--lib/pleroma/web/activity_pub/object_validator.ex37
-rw-r--r--lib/pleroma/web/activity_pub/object_validators/common_validations.ex32
-rw-r--r--lib/pleroma/web/activity_pub/object_validators/create_validator.ex30
-rw-r--r--lib/pleroma/web/activity_pub/object_validators/like_validator.ex57
-rw-r--r--lib/pleroma/web/activity_pub/object_validators/note_validator.ex64
-rw-r--r--lib/pleroma/web/activity_pub/object_validators/types/date_time.ex34
-rw-r--r--lib/pleroma/web/activity_pub/object_validators/types/object_id.ex23
-rw-r--r--lib/pleroma/web/activity_pub/object_validators/types/uri.ex20
-rw-r--r--lib/pleroma/web/activity_pub/pipeline.ex42
-rw-r--r--lib/pleroma/web/activity_pub/publisher.ex13
-rw-r--r--lib/pleroma/web/activity_pub/relay.ex19
-rw-r--r--lib/pleroma/web/activity_pub/side_effects.ex30
-rw-r--r--lib/pleroma/web/activity_pub/transmogrifier.ex149
-rw-r--r--lib/pleroma/web/activity_pub/utils.ex140
-rw-r--r--lib/pleroma/web/activity_pub/views/object_view.ex2
-rw-r--r--lib/pleroma/web/activity_pub/views/user_view.ex16
-rw-r--r--lib/pleroma/web/activity_pub/visibility.ex16
-rw-r--r--lib/pleroma/web/admin_api/admin_api_controller.ex206
-rw-r--r--lib/pleroma/web/admin_api/report.ex2
-rw-r--r--lib/pleroma/web/admin_api/views/account_view.ex46
-rw-r--r--lib/pleroma/web/admin_api/views/moderation_log_view.ex2
-rw-r--r--lib/pleroma/web/admin_api/views/report_view.ex37
-rw-r--r--lib/pleroma/web/api_spec.ex44
-rw-r--r--lib/pleroma/web/api_spec/helpers.ex27
-rw-r--r--lib/pleroma/web/api_spec/operations/app_operation.ex96
-rw-r--r--lib/pleroma/web/api_spec/operations/custom_emoji_operation.ex25
-rw-r--r--lib/pleroma/web/api_spec/operations/domain_block_operation.ex64
-rw-r--r--lib/pleroma/web/api_spec/schemas/app_create_request.ex33
-rw-r--r--lib/pleroma/web/api_spec/schemas/app_create_response.ex33
-rw-r--r--lib/pleroma/web/api_spec/schemas/custom_emoji.ex30
-rw-r--r--lib/pleroma/web/api_spec/schemas/custom_emojis_response.ex42
-rw-r--r--lib/pleroma/web/api_spec/schemas/domain_block_request.ex20
-rw-r--r--lib/pleroma/web/api_spec/schemas/domain_blocks_response.ex16
-rw-r--r--lib/pleroma/web/auth/authenticator.ex2
-rw-r--r--lib/pleroma/web/auth/ldap_authenticator.ex2
-rw-r--r--lib/pleroma/web/auth/pleroma_authenticator.ex2
-rw-r--r--lib/pleroma/web/channels/user_socket.ex2
-rw-r--r--lib/pleroma/web/chat_channel.ex2
-rw-r--r--lib/pleroma/web/common_api/activity_draft.ex4
-rw-r--r--lib/pleroma/web/common_api/common_api.ex97
-rw-r--r--lib/pleroma/web/common_api/utils.ex21
-rw-r--r--lib/pleroma/web/controller_helper.ex38
-rw-r--r--lib/pleroma/web/endpoint.ex2
-rw-r--r--lib/pleroma/web/fallback_redirect_controller.ex2
-rw-r--r--lib/pleroma/web/federator/publisher.ex2
-rw-r--r--lib/pleroma/web/feed/feed_view.ex9
-rw-r--r--lib/pleroma/web/feed/tag_controller.ex6
-rw-r--r--lib/pleroma/web/feed/user_controller.ex24
-rw-r--r--lib/pleroma/web/gettext.ex2
-rw-r--r--lib/pleroma/web/masto_fe_controller.ex2
-rw-r--r--lib/pleroma/web/mastodon_api/controllers/account_controller.ex124
-rw-r--r--lib/pleroma/web/mastodon_api/controllers/app_controller.ex11
-rw-r--r--lib/pleroma/web/mastodon_api/controllers/auth_controller.ex4
-rw-r--r--lib/pleroma/web/mastodon_api/controllers/conversation_controller.ex2
-rw-r--r--lib/pleroma/web/mastodon_api/controllers/custom_emoji_controller.ex6
-rw-r--r--lib/pleroma/web/mastodon_api/controllers/domain_block_controller.ex9
-rw-r--r--lib/pleroma/web/mastodon_api/controllers/fallback_controller.ex2
-rw-r--r--lib/pleroma/web/mastodon_api/controllers/filter_controller.ex2
-rw-r--r--lib/pleroma/web/mastodon_api/controllers/follow_request_controller.ex2
-rw-r--r--lib/pleroma/web/mastodon_api/controllers/instance_controller.ex2
-rw-r--r--lib/pleroma/web/mastodon_api/controllers/list_controller.ex2
-rw-r--r--lib/pleroma/web/mastodon_api/controllers/marker_controller.ex2
-rw-r--r--lib/pleroma/web/mastodon_api/controllers/mastodon_api_controller.ex20
-rw-r--r--lib/pleroma/web/mastodon_api/controllers/media_controller.ex2
-rw-r--r--lib/pleroma/web/mastodon_api/controllers/notification_controller.ex11
-rw-r--r--lib/pleroma/web/mastodon_api/controllers/poll_controller.ex2
-rw-r--r--lib/pleroma/web/mastodon_api/controllers/report_controller.ex2
-rw-r--r--lib/pleroma/web/mastodon_api/controllers/scheduled_activity_controller.ex2
-rw-r--r--lib/pleroma/web/mastodon_api/controllers/search_controller.ex24
-rw-r--r--lib/pleroma/web/mastodon_api/controllers/status_controller.ex37
-rw-r--r--lib/pleroma/web/mastodon_api/controllers/subscription_controller.ex34
-rw-r--r--lib/pleroma/web/mastodon_api/controllers/suggestion_controller.ex9
-rw-r--r--lib/pleroma/web/mastodon_api/controllers/timeline_controller.ex73
-rw-r--r--lib/pleroma/web/mastodon_api/mastodon_api.ex23
-rw-r--r--lib/pleroma/web/mastodon_api/views/account_view.ex172
-rw-r--r--lib/pleroma/web/mastodon_api/views/app_view.ex15
-rw-r--r--lib/pleroma/web/mastodon_api/views/conversation_view.ex2
-rw-r--r--lib/pleroma/web/mastodon_api/views/custom_emoji_view.ex2
-rw-r--r--lib/pleroma/web/mastodon_api/views/filter_view.ex2
-rw-r--r--lib/pleroma/web/mastodon_api/views/instance_view.ex2
-rw-r--r--lib/pleroma/web/mastodon_api/views/list_view.ex2
-rw-r--r--lib/pleroma/web/mastodon_api/views/marker_view.ex2
-rw-r--r--lib/pleroma/web/mastodon_api/views/notification_view.ex119
-rw-r--r--lib/pleroma/web/mastodon_api/views/report_view.ex2
-rw-r--r--lib/pleroma/web/mastodon_api/views/scheduled_activity_view.ex2
-rw-r--r--lib/pleroma/web/mastodon_api/views/status_view.ex104
-rw-r--r--lib/pleroma/web/mastodon_api/views/subscription_view.ex (renamed from lib/pleroma/web/mastodon_api/views/push_subscription_view.ex)6
-rw-r--r--lib/pleroma/web/mastodon_api/websocket_handler.ex2
-rw-r--r--lib/pleroma/web/media_proxy/media_proxy.ex2
-rw-r--r--lib/pleroma/web/media_proxy/media_proxy_controller.ex2
-rw-r--r--lib/pleroma/web/metadata.ex9
-rw-r--r--lib/pleroma/web/metadata/opengraph.ex4
-rw-r--r--lib/pleroma/web/metadata/player_view.ex2
-rw-r--r--lib/pleroma/web/metadata/provider.ex2
-rw-r--r--lib/pleroma/web/metadata/restrict_indexing.ex25
-rw-r--r--lib/pleroma/web/metadata/twitter_card.ex2
-rw-r--r--lib/pleroma/web/mongooseim/mongoose_im_controller.ex2
-rw-r--r--lib/pleroma/web/nodeinfo/nodeinfo_controller.ex4
-rw-r--r--lib/pleroma/web/oauth.ex2
-rw-r--r--lib/pleroma/web/oauth/app.ex84
-rw-r--r--lib/pleroma/web/oauth/authorization.ex2
-rw-r--r--lib/pleroma/web/oauth/fallback_controller.ex2
-rw-r--r--lib/pleroma/web/oauth/oauth_controller.ex2
-rw-r--r--lib/pleroma/web/oauth/oauth_view.ex2
-rw-r--r--lib/pleroma/web/oauth/scopes.ex7
-rw-r--r--lib/pleroma/web/oauth/token.ex2
-rw-r--r--lib/pleroma/web/oauth/token/query.ex2
-rw-r--r--lib/pleroma/web/oauth/token/response.ex2
-rw-r--r--lib/pleroma/web/oauth/token/strategy/refresh_token.ex2
-rw-r--r--lib/pleroma/web/oauth/token/strategy/revoke.ex2
-rw-r--r--lib/pleroma/web/oauth/token/utils.ex2
-rw-r--r--lib/pleroma/web/ostatus/ostatus_controller.ex12
-rw-r--r--lib/pleroma/web/pleroma_api/controllers/account_controller.ex26
-rw-r--r--lib/pleroma/web/pleroma_api/controllers/mascot_controller.ex2
-rw-r--r--lib/pleroma/web/pleroma_api/controllers/pleroma_api_controller.ex56
-rw-r--r--lib/pleroma/web/pleroma_api/controllers/scrobble_controller.ex2
-rw-r--r--lib/pleroma/web/push/impl.ex79
-rw-r--r--lib/pleroma/web/push/push.ex2
-rw-r--r--lib/pleroma/web/push/subscription.ex10
-rw-r--r--lib/pleroma/web/rel_me.ex18
-rw-r--r--lib/pleroma/web/rich_media/helpers.ex7
-rw-r--r--lib/pleroma/web/rich_media/parser.ex18
-rw-r--r--lib/pleroma/web/rich_media/parsers/oembed_parser.ex2
-rw-r--r--lib/pleroma/web/rich_media/parsers/ogp.ex2
-rw-r--r--lib/pleroma/web/rich_media/parsers/twitter_card.ex2
-rw-r--r--lib/pleroma/web/router.ex149
-rw-r--r--lib/pleroma/web/static_fe/static_fe_controller.ex37
-rw-r--r--lib/pleroma/web/static_fe/static_fe_view.ex11
-rw-r--r--lib/pleroma/web/streamer/ping.ex2
-rw-r--r--lib/pleroma/web/streamer/state.ex2
-rw-r--r--lib/pleroma/web/streamer/streamer.ex2
-rw-r--r--lib/pleroma/web/streamer/streamer_socket.ex2
-rw-r--r--lib/pleroma/web/streamer/supervisor.ex2
-rw-r--r--lib/pleroma/web/streamer/worker.ex2
-rw-r--r--lib/pleroma/web/templates/feed/feed/_activity.atom.eex (renamed from lib/pleroma/web/templates/feed/feed/_activity.xml.eex)8
-rw-r--r--lib/pleroma/web/templates/feed/feed/_activity.rss.eex49
-rw-r--r--lib/pleroma/web/templates/feed/feed/_author.atom.eex (renamed from lib/pleroma/web/templates/feed/feed/_author.xml.eex)0
-rw-r--r--lib/pleroma/web/templates/feed/feed/_author.rss.eex17
-rw-r--r--lib/pleroma/web/templates/feed/feed/_tag_activity.atom.eex16
-rw-r--r--lib/pleroma/web/templates/feed/feed/_tag_activity.xml.eex15
-rw-r--r--lib/pleroma/web/templates/feed/feed/user.atom.eex (renamed from lib/pleroma/web/templates/feed/feed/user.xml.eex)4
-rw-r--r--lib/pleroma/web/templates/feed/feed/user.rss.eex20
-rw-r--r--lib/pleroma/web/templates/static_fe/static_fe/_user_card.html.eex4
-rw-r--r--lib/pleroma/web/templates/static_fe/static_fe/profile.html.eex4
-rw-r--r--lib/pleroma/web/translation_helpers.ex2
-rw-r--r--lib/pleroma/web/twitter_api/controllers/password_controller.ex2
-rw-r--r--lib/pleroma/web/twitter_api/controllers/remote_follow_controller.ex2
-rw-r--r--lib/pleroma/web/twitter_api/controllers/util_controller.ex2
-rw-r--r--lib/pleroma/web/twitter_api/twitter_api.ex11
-rw-r--r--lib/pleroma/web/twitter_api/twitter_api_controller.ex4
-rw-r--r--lib/pleroma/web/twitter_api/views/password_view.ex2
-rw-r--r--lib/pleroma/web/twitter_api/views/token_view.ex2
-rw-r--r--lib/pleroma/web/twitter_api/views/util_view.ex2
-rw-r--r--lib/pleroma/web/uploader_controller.ex2
-rw-r--r--lib/pleroma/web/views/error_helpers.ex2
-rw-r--r--lib/pleroma/web/views/error_view.ex2
-rw-r--r--lib/pleroma/web/views/layout_view.ex2
-rw-r--r--lib/pleroma/web/views/masto_fe_view.ex2
-rw-r--r--lib/pleroma/web/views/streamer_view.ex2
-rw-r--r--lib/pleroma/web/web.ex65
-rw-r--r--lib/pleroma/web/web_finger/web_finger.ex7
-rw-r--r--lib/pleroma/web/web_finger/web_finger_controller.ex2
-rw-r--r--lib/pleroma/web/xml/xml.ex2
181 files changed, 2747 insertions, 943 deletions
diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex
index 04b853dcf..eedea08a2 100644
--- a/lib/pleroma/web/activity_pub/activity_pub.ex
+++ b/lib/pleroma/web/activity_pub/activity_pub.ex
@@ -125,6 +125,21 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
def increase_poll_votes_if_vote(_create_data), do: :noop
+ @spec persist(map(), keyword()) :: {:ok, Activity.t() | Object.t()}
+ def persist(object, meta) do
+ with local <- Keyword.fetch!(meta, :local),
+ {recipients, _, _} <- get_recipients(object),
+ {:ok, activity} <-
+ Repo.insert(%Activity{
+ data: object,
+ local: local,
+ recipients: recipients,
+ actor: object["actor"]
+ }) do
+ {:ok, activity, meta}
+ end
+ end
+
@spec insert(map(), boolean(), boolean(), boolean()) :: {:ok, Activity.t()} | {:error, any()}
def insert(map, local \\ true, fake \\ false, bypass_actor_check \\ false) when is_map(map) do
with nil <- Activity.normalize(map),
@@ -503,8 +518,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
defp do_follow(follower, followed, activity_id, local) do
with data <- make_follow_data(follower, followed, activity_id),
{:ok, activity} <- insert(data, local),
- :ok <- maybe_federate(activity),
- _ <- User.set_follow_state_cache(follower.ap_id, followed.ap_id, activity.data["state"]) do
+ :ok <- maybe_federate(activity) do
{:ok, activity}
else
{:error, error} -> Repo.rollback(error)
@@ -584,6 +598,16 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
end
end
+ defp do_delete(%Object{data: %{"type" => "Tombstone", "id" => ap_id}}, _) do
+ activity =
+ ap_id
+ |> Activity.Queries.by_object_id()
+ |> Activity.Queries.by_type("Delete")
+ |> Repo.one()
+
+ {:ok, activity}
+ end
+
@spec block(User.t(), User.t(), String.t() | nil, boolean()) ::
{:ok, Activity.t()} | {:error, any()}
def block(blocker, blocked, activity_id \\ nil, local \\ true) do
@@ -660,7 +684,9 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
{:ok, activity} <- insert(flag_data, local),
{:ok, stripped_activity} <- strip_report_status_data(activity),
:ok <- maybe_federate(stripped_activity) do
- Enum.each(User.all_superusers(), fn superuser ->
+ User.all_superusers()
+ |> Enum.filter(fn user -> not is_nil(user.email) end)
+ |> Enum.each(fn superuser ->
superuser
|> Pleroma.Emails.AdminEmail.report(actor, account, statuses, content)
|> Pleroma.Emails.Mailer.deliver_async()
@@ -695,7 +721,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
end
end
- defp fetch_activities_for_context_query(context, opts) do
+ def fetch_activities_for_context_query(context, opts) do
public = [Constants.as_public()]
recipients =
@@ -1228,17 +1254,17 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
defp fetch_activities_query_ap_ids_ops(opts) do
source_user = opts["muting_user"]
- ap_id_relations = if source_user, do: [:mute, :reblog_mute], else: []
+ ap_id_relationships = if source_user, do: [:mute, :reblog_mute], else: []
- ap_id_relations =
- ap_id_relations ++
+ ap_id_relationships =
+ ap_id_relationships ++
if opts["blocking_user"] && opts["blocking_user"] == source_user do
[:block]
else
[]
end
- preloaded_ap_ids = User.outgoing_relations_ap_ids(source_user, ap_id_relations)
+ preloaded_ap_ids = User.outgoing_relationships_ap_ids(source_user, ap_id_relationships)
restrict_blocked_opts = Map.merge(%{"blocked_users_ap_ids" => preloaded_ap_ids[:block]}, opts)
restrict_muted_opts = Map.merge(%{"muted_users_ap_ids" => preloaded_ap_ids[:mute]}, opts)
@@ -1368,6 +1394,18 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
end
end
+ @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
+
+ defp get_actor_url(url) when is_list(url) do
+ url
+ |> List.first()
+ |> get_actor_url()
+ end
+
+ defp get_actor_url(_url), do: nil
+
defp object_to_user_data(data) do
avatar =
data["icon"]["url"] &&
@@ -1389,18 +1427,44 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
|> Enum.filter(fn %{"type" => t} -> t == "PropertyValue" end)
|> Enum.map(fn fields -> Map.take(fields, ["name", "value"]) end)
+ emojis =
+ data
+ |> Map.get("tag", [])
+ |> Enum.filter(fn
+ %{"type" => "Emoji"} -> true
+ _ -> false
+ end)
+ |> Enum.reduce(%{}, fn %{"icon" => %{"url" => url}, "name" => name}, acc ->
+ Map.put(acc, String.trim(name, ":"), url)
+ end)
+
locked = data["manuallyApprovesFollowers"] || false
data = Transmogrifier.maybe_fix_user_object(data)
discoverable = data["discoverable"] || false
invisible = data["invisible"] || false
actor_type = data["type"] || "Person"
+ public_key =
+ if is_map(data["publicKey"]) && is_binary(data["publicKey"]["publicKeyPem"]) do
+ data["publicKey"]["publicKeyPem"]
+ else
+ nil
+ end
+
+ shared_inbox =
+ if is_map(data["endpoints"]) && is_binary(data["endpoints"]["sharedInbox"]) do
+ data["endpoints"]["sharedInbox"]
+ else
+ nil
+ end
+
user_data = %{
ap_id: data["id"],
+ uri: get_actor_url(data["url"]),
ap_enabled: true,
- source_data: data,
banner: banner,
fields: fields,
+ emoji: emojis,
locked: locked,
discoverable: discoverable,
invisible: invisible,
@@ -1410,7 +1474,10 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
following_address: data["following"],
bio: data["summary"],
actor_type: actor_type,
- also_known_as: Map.get(data, "alsoKnownAs", [])
+ also_known_as: Map.get(data, "alsoKnownAs", []),
+ public_key: public_key,
+ inbox: data["inbox"],
+ shared_inbox: shared_inbox
}
# nickname can be nil because of virtual actors
@@ -1512,11 +1579,22 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
end
def make_user_from_ap_id(ap_id) do
- if _user = User.get_cached_by_ap_id(ap_id) 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) do
- User.insert_or_update_user(data)
+ if user do
+ user
+ |> User.remote_user_changeset(data)
+ |> User.update_and_set_cache()
+ else
+ data
+ |> User.remote_user_changeset()
+ |> Repo.insert()
+ |> User.set_cache()
+ end
else
e -> {:error, e}
end
diff --git a/lib/pleroma/web/activity_pub/activity_pub_controller.ex b/lib/pleroma/web/activity_pub/activity_pub_controller.ex
index 5059e3984..8b9eb4a2c 100644
--- a/lib/pleroma/web/activity_pub/activity_pub_controller.ex
+++ b/lib/pleroma/web/activity_pub/activity_pub_controller.ex
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.ActivityPub.ActivityPubController do
@@ -9,6 +9,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubController do
alias Pleroma.Delivery
alias Pleroma.Object
alias Pleroma.Object.Fetcher
+ alias Pleroma.Plugs.EnsureAuthenticatedPlug
alias Pleroma.User
alias Pleroma.Web.ActivityPub.ActivityPub
alias Pleroma.Web.ActivityPub.InternalFetchActor
@@ -18,23 +19,37 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubController do
alias Pleroma.Web.ActivityPub.UserView
alias Pleroma.Web.ActivityPub.Utils
alias Pleroma.Web.ActivityPub.Visibility
+ alias Pleroma.Web.FederatingPlug
alias Pleroma.Web.Federator
require Logger
action_fallback(:errors)
+ @federating_only_actions [:internal_fetch, :relay, :relay_following, :relay_followers]
+
+ plug(FederatingPlug when action in @federating_only_actions)
+
+ plug(
+ EnsureAuthenticatedPlug,
+ [unless_func: &FederatingPlug.federating?/0] when action not in @federating_only_actions
+ )
+
+ plug(
+ EnsureAuthenticatedPlug
+ when action in [:read_inbox, :update_outbox, :whoami, :upload_media, :following, :followers]
+ )
+
plug(
Pleroma.Plugs.Cache,
[query_params: false, tracking_fun: &__MODULE__.track_object_fetch/2]
when action in [:activity, :object]
)
- plug(Pleroma.Web.FederatingPlug when action in [:inbox, :relay])
plug(:set_requester_reachable when action in [:inbox])
plug(:relay_active? when action in [:relay])
- def relay_active?(conn, _) do
+ defp relay_active?(conn, _) do
if Pleroma.Config.get([:instance, :allow_relay]) do
conn
else
@@ -127,11 +142,13 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubController do
end
# GET /relay/following
- def following(%{assigns: %{relay: true}} = conn, _params) do
- conn
- |> put_resp_content_type("application/activity+json")
- |> put_view(UserView)
- |> render("following.json", %{user: Relay.get_actor()})
+ def relay_following(conn, _params) do
+ with %{halted: false} = conn <- FederatingPlug.call(conn, []) do
+ conn
+ |> put_resp_content_type("application/activity+json")
+ |> put_view(UserView)
+ |> render("following.json", %{user: Relay.get_actor()})
+ end
end
def following(%{assigns: %{user: for_user}} = conn, %{"nickname" => nickname, "page" => page}) do
@@ -164,11 +181,13 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubController do
end
# GET /relay/followers
- def followers(%{assigns: %{relay: true}} = conn, _params) do
- conn
- |> put_resp_content_type("application/activity+json")
- |> put_view(UserView)
- |> render("followers.json", %{user: Relay.get_actor()})
+ def relay_followers(conn, _params) do
+ with %{halted: false} = conn <- FederatingPlug.call(conn, []) do
+ conn
+ |> put_resp_content_type("application/activity+json")
+ |> put_view(UserView)
+ |> render("followers.json", %{user: Relay.get_actor()})
+ end
end
def followers(%{assigns: %{user: for_user}} = conn, %{"nickname" => nickname, "page" => page}) do
@@ -200,13 +219,16 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubController do
end
end
- def outbox(conn, %{"nickname" => nickname, "page" => page?} = params)
+ def outbox(
+ %{assigns: %{user: for_user}} = conn,
+ %{"nickname" => nickname, "page" => page?} = params
+ )
when page? in [true, "true"] do
with %User{} = user <- User.get_cached_by_nickname(nickname),
{:ok, user} <- User.ensure_keys_present(user) do
activities =
if params["max_id"] do
- ActivityPub.fetch_user_activities(user, nil, %{
+ ActivityPub.fetch_user_activities(user, for_user, %{
"max_id" => params["max_id"],
# This is a hack because postgres generates inefficient queries when filtering by
# 'Answer', poll votes will be hidden by the visibility filter in this case anyway
@@ -214,7 +236,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubController do
"limit" => 10
})
else
- ActivityPub.fetch_user_activities(user, nil, %{
+ ActivityPub.fetch_user_activities(user, for_user, %{
"limit" => 10,
"include_poll_votes" => true
})
@@ -255,8 +277,16 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubController do
json(conn, "ok")
end
- # only accept relayed Creates
- def inbox(conn, %{"type" => "Create"} = params) do
+ # POST /relay/inbox -or- POST /internal/fetch/inbox
+ def inbox(conn, params) do
+ if params["type"] == "Create" && FederatingPlug.federating?() do
+ post_inbox_relayed_create(conn, params)
+ else
+ post_inbox_fallback(conn, params)
+ end
+ end
+
+ defp post_inbox_relayed_create(conn, params) do
Logger.debug(
"Signature missing or not from author, relayed Create message, fetching object from source"
)
@@ -266,10 +296,11 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubController do
json(conn, "ok")
end
- def inbox(conn, params) do
+ defp post_inbox_fallback(conn, params) do
headers = Enum.into(conn.req_headers, %{})
- if String.contains?(headers["signature"], params["actor"]) do
+ if headers["signature"] && params["actor"] &&
+ String.contains?(headers["signature"], params["actor"]) do
Logger.debug(
"Signature validation error for: #{params["actor"]}, make sure you are forwarding the HTTP Host header!"
)
@@ -277,7 +308,9 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubController do
Logger.debug(inspect(conn.req_headers))
end
- json(conn, dgettext("errors", "error"))
+ conn
+ |> put_status(:bad_request)
+ |> json(dgettext("errors", "error"))
end
defp represent_service_actor(%User{} = user, conn) do
@@ -311,10 +344,8 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubController do
|> render("user.json", %{user: user})
end
- def whoami(_conn, _params), do: {:error, :not_found}
-
def read_inbox(
- %{assigns: %{user: %{nickname: nickname} = user}} = conn,
+ %{assigns: %{user: %User{nickname: nickname} = user}} = conn,
%{"nickname" => nickname, "page" => page?} = params
)
when page? in [true, "true"] do
@@ -337,7 +368,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubController do
})
end
- def read_inbox(%{assigns: %{user: %{nickname: nickname} = user}} = conn, %{
+ def read_inbox(%{assigns: %{user: %User{nickname: nickname} = user}} = conn, %{
"nickname" => nickname
}) do
with {:ok, user} <- User.ensure_keys_present(user) do
@@ -348,15 +379,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubController do
end
end
- def read_inbox(%{assigns: %{user: nil}} = conn, %{"nickname" => nickname}) do
- err = dgettext("errors", "can't read inbox of %{nickname}", nickname: nickname)
-
- conn
- |> put_status(:forbidden)
- |> json(err)
- end
-
- def read_inbox(%{assigns: %{user: %{nickname: as_nickname}}} = conn, %{
+ def read_inbox(%{assigns: %{user: %User{nickname: as_nickname}}} = conn, %{
"nickname" => nickname
}) do
err =
@@ -370,7 +393,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubController do
|> json(err)
end
- def handle_user_activity(user, %{"type" => "Create"} = params) do
+ defp handle_user_activity(%User{} = user, %{"type" => "Create"} = params) do
object =
params["object"]
|> Map.merge(Map.take(params, ["to", "cc"]))
@@ -386,7 +409,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubController do
})
end
- def handle_user_activity(user, %{"type" => "Delete"} = params) do
+ defp handle_user_activity(%User{} = user, %{"type" => "Delete"} = params) do
with %Object{} = object <- Object.normalize(params["object"]),
true <- user.is_moderator || user.ap_id == object.data["actor"],
{:ok, delete} <- ActivityPub.delete(object) do
@@ -396,7 +419,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubController do
end
end
- def handle_user_activity(user, %{"type" => "Like"} = params) do
+ defp handle_user_activity(%User{} = user, %{"type" => "Like"} = params) do
with %Object{} = object <- Object.normalize(params["object"]),
{:ok, activity, _object} <- ActivityPub.like(user, object) do
{:ok, activity}
@@ -405,7 +428,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubController do
end
end
- def handle_user_activity(_, _) do
+ defp handle_user_activity(_, _) do
{:error, dgettext("errors", "Unhandled activity type")}
end
@@ -434,7 +457,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubController do
end
end
- def update_outbox(%{assigns: %{user: user}} = conn, %{"nickname" => nickname} = _) do
+ def update_outbox(%{assigns: %{user: %User{} = user}} = conn, %{"nickname" => nickname}) do
err =
dgettext("errors", "can't update outbox of %{nickname} as %{as_nickname}",
nickname: nickname,
@@ -446,13 +469,13 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubController do
|> json(err)
end
- def errors(conn, {:error, :not_found}) do
+ defp errors(conn, {:error, :not_found}) do
conn
|> put_status(:not_found)
|> json(dgettext("errors", "Not found"))
end
- def errors(conn, _e) do
+ defp errors(conn, _e) do
conn
|> put_status(:internal_server_error)
|> json(dgettext("errors", "error"))
@@ -492,7 +515,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubController do
- HTTP Code: 201 Created
- HTTP Body: ActivityPub object to be inserted into another's `attachment` field
"""
- def upload_media(%{assigns: %{user: user}} = conn, %{"file" => file} = data) do
+ def upload_media(%{assigns: %{user: %User{} = user}} = conn, %{"file" => file} = data) do
with {:ok, object} <-
ActivityPub.upload(
file,
diff --git a/lib/pleroma/web/activity_pub/builder.ex b/lib/pleroma/web/activity_pub/builder.ex
new file mode 100644
index 000000000..429a510b8
--- /dev/null
+++ b/lib/pleroma/web/activity_pub/builder.ex
@@ -0,0 +1,43 @@
+defmodule Pleroma.Web.ActivityPub.Builder do
+ @moduledoc """
+ This module builds the objects. Meant to be used for creating local objects.
+
+ This module encodes our addressing policies and general shape of our objects.
+ """
+
+ alias Pleroma.Object
+ alias Pleroma.User
+ alias Pleroma.Web.ActivityPub.Utils
+ alias Pleroma.Web.ActivityPub.Visibility
+
+ @spec like(User.t(), Object.t()) :: {:ok, map(), keyword()}
+ def like(actor, object) do
+ object_actor = User.get_cached_by_ap_id(object.data["actor"])
+
+ # Address the actor of the object, and our actor's follower collection if the post is public.
+ to =
+ if Visibility.is_public?(object) do
+ [actor.follower_address, object.data["actor"]]
+ else
+ [object.data["actor"]]
+ end
+
+ # CC everyone who's been addressed in the object, except ourself and the object actor's
+ # follower collection
+ cc =
+ (object.data["to"] ++ (object.data["cc"] || []))
+ |> List.delete(actor.ap_id)
+ |> List.delete(object_actor.follower_address)
+
+ {:ok,
+ %{
+ "id" => Utils.generate_activity_id(),
+ "actor" => actor.ap_id,
+ "type" => "Like",
+ "object" => object.data["id"],
+ "to" => to,
+ "cc" => cc,
+ "context" => object.data["context"]
+ }, []}
+ end
+end
diff --git a/lib/pleroma/web/activity_pub/internal_fetch_actor.ex b/lib/pleroma/web/activity_pub/internal_fetch_actor.ex
index 9213ddde7..c80272b8f 100644
--- a/lib/pleroma/web/activity_pub/internal_fetch_actor.ex
+++ b/lib/pleroma/web/activity_pub/internal_fetch_actor.ex
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.ActivityPub.InternalFetchActor do
diff --git a/lib/pleroma/web/activity_pub/mrf.ex b/lib/pleroma/web/activity_pub/mrf.ex
index 263ed11af..a0b3af432 100644
--- a/lib/pleroma/web/activity_pub/mrf.ex
+++ b/lib/pleroma/web/activity_pub/mrf.ex
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.ActivityPub.MRF do
diff --git a/lib/pleroma/web/activity_pub/mrf/anti_followbot_policy.ex b/lib/pleroma/web/activity_pub/mrf/anti_followbot_policy.ex
index b3547ecd4..0270b96ae 100644
--- a/lib/pleroma/web/activity_pub/mrf/anti_followbot_policy.ex
+++ b/lib/pleroma/web/activity_pub/mrf/anti_followbot_policy.ex
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2019 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.ActivityPub.MRF.AntiFollowbotPolicy do
diff --git a/lib/pleroma/web/activity_pub/mrf/drop_policy.ex b/lib/pleroma/web/activity_pub/mrf/drop_policy.ex
index 4a5709974..5ab9844ff 100644
--- a/lib/pleroma/web/activity_pub/mrf/drop_policy.ex
+++ b/lib/pleroma/web/activity_pub/mrf/drop_policy.ex
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.ActivityPub.MRF.DropPolicy do
diff --git a/lib/pleroma/web/activity_pub/mrf/ensure_re_prepended.ex b/lib/pleroma/web/activity_pub/mrf/ensure_re_prepended.ex
index 3a3e72910..2627a0007 100644
--- a/lib/pleroma/web/activity_pub/mrf/ensure_re_prepended.ex
+++ b/lib/pleroma/web/activity_pub/mrf/ensure_re_prepended.ex
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.ActivityPub.MRF.EnsureRePrepended do
diff --git a/lib/pleroma/web/activity_pub/mrf/hellthread_policy.ex b/lib/pleroma/web/activity_pub/mrf/hellthread_policy.ex
index b3c742954..1764bc789 100644
--- a/lib/pleroma/web/activity_pub/mrf/hellthread_policy.ex
+++ b/lib/pleroma/web/activity_pub/mrf/hellthread_policy.ex
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.ActivityPub.MRF.HellthreadPolicy do
diff --git a/lib/pleroma/web/activity_pub/mrf/keyword_policy.ex b/lib/pleroma/web/activity_pub/mrf/keyword_policy.ex
index d6d1396bc..88b0d2b39 100644
--- a/lib/pleroma/web/activity_pub/mrf/keyword_policy.ex
+++ b/lib/pleroma/web/activity_pub/mrf/keyword_policy.ex
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.ActivityPub.MRF.KeywordPolicy do
diff --git a/lib/pleroma/web/activity_pub/mrf/media_proxy_warming_policy.ex b/lib/pleroma/web/activity_pub/mrf/media_proxy_warming_policy.ex
index d9a0acfd3..dfab105a3 100644
--- a/lib/pleroma/web/activity_pub/mrf/media_proxy_warming_policy.ex
+++ b/lib/pleroma/web/activity_pub/mrf/media_proxy_warming_policy.ex
@@ -12,17 +12,23 @@ defmodule Pleroma.Web.ActivityPub.MRF.MediaProxyWarmingPolicy do
require Logger
- @hackney_options [
- pool: :media,
- recv_timeout: 10_000
+ @options [
+ pool: :media
]
def perform(:prefetch, url) do
Logger.debug("Prefetching #{inspect(url)}")
+ opts =
+ if Application.get_env(:tesla, :adapter) == Tesla.Adapter.Hackney do
+ Keyword.put(@options, :recv_timeout, 10_000)
+ else
+ @options
+ end
+
url
|> MediaProxy.url()
- |> HTTP.get([], adapter: @hackney_options)
+ |> HTTP.get([], adapter: opts)
end
def perform(:preload, %{"object" => %{"attachment" => attachments}} = _message) do
diff --git a/lib/pleroma/web/activity_pub/mrf/mention_policy.ex b/lib/pleroma/web/activity_pub/mrf/mention_policy.ex
index ce8bc4580..06f003921 100644
--- a/lib/pleroma/web/activity_pub/mrf/mention_policy.ex
+++ b/lib/pleroma/web/activity_pub/mrf/mention_policy.ex
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.ActivityPub.MRF.MentionPolicy do
diff --git a/lib/pleroma/web/activity_pub/mrf/no_placeholder_text_policy.ex b/lib/pleroma/web/activity_pub/mrf/no_placeholder_text_policy.ex
index f67f48ab6..fc3475048 100644
--- a/lib/pleroma/web/activity_pub/mrf/no_placeholder_text_policy.ex
+++ b/lib/pleroma/web/activity_pub/mrf/no_placeholder_text_policy.ex
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2019 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.ActivityPub.MRF.NoPlaceholderTextPolicy do
diff --git a/lib/pleroma/web/activity_pub/mrf/normalize_markup.ex b/lib/pleroma/web/activity_pub/mrf/normalize_markup.ex
index daa4c88ad..7abae37ae 100644
--- a/lib/pleroma/web/activity_pub/mrf/normalize_markup.ex
+++ b/lib/pleroma/web/activity_pub/mrf/normalize_markup.ex
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.ActivityPub.MRF.NormalizeMarkup do
diff --git a/lib/pleroma/web/activity_pub/mrf/object_age_policy.ex b/lib/pleroma/web/activity_pub/mrf/object_age_policy.ex
index 4a8bc91ae..b0ccb63c8 100644
--- a/lib/pleroma/web/activity_pub/mrf/object_age_policy.ex
+++ b/lib/pleroma/web/activity_pub/mrf/object_age_policy.ex
@@ -11,7 +11,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.ObjectAgePolicy do
@moduledoc "Filter activities depending on their age"
@behaviour Pleroma.Web.ActivityPub.MRF
- defp check_date(%{"published" => published} = message) do
+ defp check_date(%{"object" => %{"published" => published}} = message) do
with %DateTime{} = now <- DateTime.utc_now(),
{:ok, %DateTime{} = then, _} <- DateTime.from_iso8601(published),
max_ttl <- Config.get([:mrf_object_age, :threshold]),
@@ -96,5 +96,11 @@ defmodule Pleroma.Web.ActivityPub.MRF.ObjectAgePolicy do
def filter(message), do: {:ok, message}
@impl true
- def describe, do: {:ok, %{}}
+ def describe do
+ mrf_object_age =
+ Pleroma.Config.get(:mrf_object_age)
+ |> Enum.into(%{})
+
+ {:ok, %{mrf_object_age: mrf_object_age}}
+ end
end
diff --git a/lib/pleroma/web/activity_pub/mrf/reject_non_public.ex b/lib/pleroma/web/activity_pub/mrf/reject_non_public.ex
index 5a809a321..3092f3272 100644
--- a/lib/pleroma/web/activity_pub/mrf/reject_non_public.ex
+++ b/lib/pleroma/web/activity_pub/mrf/reject_non_public.ex
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.ActivityPub.MRF.RejectNonPublic do
diff --git a/lib/pleroma/web/activity_pub/mrf/simple_policy.ex b/lib/pleroma/web/activity_pub/mrf/simple_policy.ex
index 4edc007fd..b7dcb1b86 100644
--- a/lib/pleroma/web/activity_pub/mrf/simple_policy.ex
+++ b/lib/pleroma/web/activity_pub/mrf/simple_policy.ex
@@ -149,6 +149,21 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicy do
defp check_banner_removal(_actor_info, object), do: {:ok, object}
@impl true
+ def filter(%{"type" => "Delete", "actor" => actor} = object) do
+ %{host: actor_host} = URI.parse(actor)
+
+ reject_deletes =
+ Pleroma.Config.get([:mrf_simple, :reject_deletes])
+ |> MRF.subdomains_regex()
+
+ if MRF.subdomain_match?(reject_deletes, actor_host) do
+ {:reject, nil}
+ else
+ {:ok, object}
+ end
+ end
+
+ @impl true
def filter(%{"actor" => actor} = object) do
actor_info = URI.parse(actor)
diff --git a/lib/pleroma/web/activity_pub/mrf/tag_policy.ex b/lib/pleroma/web/activity_pub/mrf/tag_policy.ex
index c1801d2ec..c310462cb 100644
--- a/lib/pleroma/web/activity_pub/mrf/tag_policy.ex
+++ b/lib/pleroma/web/activity_pub/mrf/tag_policy.ex
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.ActivityPub.MRF.TagPolicy do
diff --git a/lib/pleroma/web/activity_pub/object_validator.ex b/lib/pleroma/web/activity_pub/object_validator.ex
new file mode 100644
index 000000000..dc4bce059
--- /dev/null
+++ b/lib/pleroma/web/activity_pub/object_validator.ex
@@ -0,0 +1,37 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.ActivityPub.ObjectValidator do
+ @moduledoc """
+ This module is responsible for validating an object (which can be an activity)
+ and checking if it is both well formed and also compatible with our view of
+ the system.
+ """
+
+ alias Pleroma.Object
+ alias Pleroma.User
+ alias Pleroma.Web.ActivityPub.ObjectValidators.LikeValidator
+
+ @spec validate(map(), keyword()) :: {:ok, map(), keyword()} | {:error, any()}
+ def validate(object, meta)
+
+ def validate(%{"type" => "Like"} = object, meta) do
+ with {:ok, object} <-
+ object |> LikeValidator.cast_and_validate() |> Ecto.Changeset.apply_action(:insert) do
+ object = stringify_keys(object |> Map.from_struct())
+ {:ok, object, meta}
+ end
+ end
+
+ def stringify_keys(object) do
+ object
+ |> Map.new(fn {key, val} -> {to_string(key), val} end)
+ end
+
+ def fetch_actor_and_object(object) do
+ User.get_or_fetch_by_ap_id(object["actor"])
+ Object.normalize(object["object"])
+ :ok
+ end
+end
diff --git a/lib/pleroma/web/activity_pub/object_validators/common_validations.ex b/lib/pleroma/web/activity_pub/object_validators/common_validations.ex
new file mode 100644
index 000000000..b479c3918
--- /dev/null
+++ b/lib/pleroma/web/activity_pub/object_validators/common_validations.ex
@@ -0,0 +1,32 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.ActivityPub.ObjectValidators.CommonValidations do
+ import Ecto.Changeset
+
+ alias Pleroma.Object
+ alias Pleroma.User
+
+ def validate_actor_presence(cng, field_name \\ :actor) do
+ cng
+ |> validate_change(field_name, fn field_name, actor ->
+ if User.get_cached_by_ap_id(actor) do
+ []
+ else
+ [{field_name, "can't find user"}]
+ end
+ end)
+ end
+
+ def validate_object_presence(cng, field_name \\ :object) do
+ cng
+ |> validate_change(field_name, fn field_name, object ->
+ if Object.get_cached_by_ap_id(object) do
+ []
+ else
+ [{field_name, "can't find object"}]
+ end
+ end)
+ end
+end
diff --git a/lib/pleroma/web/activity_pub/object_validators/create_validator.ex b/lib/pleroma/web/activity_pub/object_validators/create_validator.ex
new file mode 100644
index 000000000..926804ce7
--- /dev/null
+++ b/lib/pleroma/web/activity_pub/object_validators/create_validator.ex
@@ -0,0 +1,30 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.ActivityPub.ObjectValidators.CreateNoteValidator do
+ use Ecto.Schema
+
+ alias Pleroma.Web.ActivityPub.ObjectValidators.NoteValidator
+ alias Pleroma.Web.ActivityPub.ObjectValidators.Types
+
+ import Ecto.Changeset
+
+ @primary_key false
+
+ embedded_schema do
+ field(:id, Types.ObjectID, primary_key: true)
+ field(:actor, Types.ObjectID)
+ field(:type, :string)
+ field(:to, {:array, :string})
+ field(:cc, {:array, :string})
+ field(:bto, {:array, :string}, default: [])
+ field(:bcc, {:array, :string}, default: [])
+
+ embeds_one(:object, NoteValidator)
+ end
+
+ def cast_data(data) do
+ cast(%__MODULE__{}, data, __schema__(:fields))
+ end
+end
diff --git a/lib/pleroma/web/activity_pub/object_validators/like_validator.ex b/lib/pleroma/web/activity_pub/object_validators/like_validator.ex
new file mode 100644
index 000000000..49546ceaa
--- /dev/null
+++ b/lib/pleroma/web/activity_pub/object_validators/like_validator.ex
@@ -0,0 +1,57 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.ActivityPub.ObjectValidators.LikeValidator do
+ use Ecto.Schema
+
+ alias Pleroma.Web.ActivityPub.ObjectValidators.Types
+ alias Pleroma.Web.ActivityPub.Utils
+
+ import Ecto.Changeset
+ import Pleroma.Web.ActivityPub.ObjectValidators.CommonValidations
+
+ @primary_key false
+
+ embedded_schema do
+ field(:id, Types.ObjectID, primary_key: true)
+ field(:type, :string)
+ field(:object, Types.ObjectID)
+ field(:actor, Types.ObjectID)
+ field(:context, :string)
+ field(:to, {:array, :string})
+ field(:cc, {:array, :string})
+ end
+
+ def cast_and_validate(data) do
+ data
+ |> cast_data()
+ |> validate_data()
+ end
+
+ def cast_data(data) do
+ %__MODULE__{}
+ |> cast(data, [:id, :type, :object, :actor, :context, :to, :cc])
+ end
+
+ def validate_data(data_cng) do
+ data_cng
+ |> validate_inclusion(:type, ["Like"])
+ |> validate_required([:id, :type, :object, :actor, :context, :to, :cc])
+ |> validate_actor_presence()
+ |> validate_object_presence()
+ |> validate_existing_like()
+ end
+
+ def validate_existing_like(%{changes: %{actor: actor, object: object}} = cng) do
+ if Utils.get_existing_like(actor, %{data: %{"id" => object}}) do
+ cng
+ |> add_error(:actor, "already liked this object")
+ |> add_error(:object, "already liked by this actor")
+ else
+ cng
+ end
+ end
+
+ def validate_existing_like(cng), do: cng
+end
diff --git a/lib/pleroma/web/activity_pub/object_validators/note_validator.ex b/lib/pleroma/web/activity_pub/object_validators/note_validator.ex
new file mode 100644
index 000000000..462a5620a
--- /dev/null
+++ b/lib/pleroma/web/activity_pub/object_validators/note_validator.ex
@@ -0,0 +1,64 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.ActivityPub.ObjectValidators.NoteValidator do
+ use Ecto.Schema
+
+ alias Pleroma.Web.ActivityPub.ObjectValidators.Types
+
+ import Ecto.Changeset
+
+ @primary_key false
+
+ embedded_schema do
+ field(:id, Types.ObjectID, primary_key: true)
+ field(:to, {:array, :string}, default: [])
+ field(:cc, {:array, :string}, default: [])
+ field(:bto, {:array, :string}, default: [])
+ field(:bcc, {:array, :string}, default: [])
+ # TODO: Write type
+ field(:tag, {:array, :map}, default: [])
+ field(:type, :string)
+ field(:content, :string)
+ field(:context, :string)
+ field(:actor, Types.ObjectID)
+ field(:attributedTo, Types.ObjectID)
+ field(:summary, :string)
+ field(:published, Types.DateTime)
+ # TODO: Write type
+ field(:emoji, :map, default: %{})
+ field(:sensitive, :boolean, default: false)
+ # TODO: Write type
+ field(:attachment, {:array, :map}, default: [])
+ field(:replies_count, :integer, default: 0)
+ field(:like_count, :integer, default: 0)
+ field(:announcement_count, :integer, default: 0)
+ field(:inRepyTo, :string)
+ field(:uri, Types.Uri)
+
+ field(:likes, {:array, :string}, default: [])
+ field(:announcements, {:array, :string}, default: [])
+
+ # see if needed
+ field(:conversation, :string)
+ field(:context_id, :string)
+ end
+
+ def cast_and_validate(data) do
+ data
+ |> cast_data()
+ |> validate_data()
+ end
+
+ def cast_data(data) do
+ %__MODULE__{}
+ |> cast(data, __schema__(:fields))
+ end
+
+ def validate_data(data_cng) do
+ data_cng
+ |> validate_inclusion(:type, ["Note"])
+ |> validate_required([:id, :actor, :to, :cc, :type, :content, :context])
+ end
+end
diff --git a/lib/pleroma/web/activity_pub/object_validators/types/date_time.ex b/lib/pleroma/web/activity_pub/object_validators/types/date_time.ex
new file mode 100644
index 000000000..4f412fcde
--- /dev/null
+++ b/lib/pleroma/web/activity_pub/object_validators/types/date_time.ex
@@ -0,0 +1,34 @@
+defmodule Pleroma.Web.ActivityPub.ObjectValidators.Types.DateTime do
+ @moduledoc """
+ The AP standard defines the date fields in AP as xsd:DateTime. Elixir's
+ DateTime can't parse this, but it can parse the related iso8601. This
+ module punches the date until it looks like iso8601 and normalizes to
+ it.
+
+ DateTimes without a timezone offset are treated as UTC.
+
+ Reference: https://www.w3.org/TR/activitystreams-vocabulary/#dfn-published
+ """
+ use Ecto.Type
+
+ def type, do: :string
+
+ def cast(datetime) when is_binary(datetime) do
+ with {:ok, datetime, _} <- DateTime.from_iso8601(datetime) do
+ {:ok, DateTime.to_iso8601(datetime)}
+ else
+ {:error, :missing_offset} -> cast("#{datetime}Z")
+ _e -> :error
+ end
+ end
+
+ def cast(_), do: :error
+
+ def dump(data) do
+ {:ok, data}
+ end
+
+ def load(data) do
+ {:ok, data}
+ end
+end
diff --git a/lib/pleroma/web/activity_pub/object_validators/types/object_id.ex b/lib/pleroma/web/activity_pub/object_validators/types/object_id.ex
new file mode 100644
index 000000000..f71f76370
--- /dev/null
+++ b/lib/pleroma/web/activity_pub/object_validators/types/object_id.ex
@@ -0,0 +1,23 @@
+defmodule Pleroma.Web.ActivityPub.ObjectValidators.Types.ObjectID do
+ use Ecto.Type
+
+ def type, do: :string
+
+ def cast(object) when is_binary(object) do
+ # Host has to be present and scheme has to be an http scheme (for now)
+ case URI.parse(object) do
+ %URI{host: nil} -> :error
+ %URI{host: ""} -> :error
+ %URI{scheme: scheme} when scheme in ["https", "http"] -> {:ok, object}
+ _ -> :error
+ end
+ end
+
+ def cast(%{"id" => object}), do: cast(object)
+
+ def cast(_), do: :error
+
+ def dump(data), do: {:ok, data}
+
+ def load(data), do: {:ok, data}
+end
diff --git a/lib/pleroma/web/activity_pub/object_validators/types/uri.ex b/lib/pleroma/web/activity_pub/object_validators/types/uri.ex
new file mode 100644
index 000000000..24845bcc0
--- /dev/null
+++ b/lib/pleroma/web/activity_pub/object_validators/types/uri.ex
@@ -0,0 +1,20 @@
+defmodule Pleroma.Web.ActivityPub.ObjectValidators.Types.Uri do
+ use Ecto.Type
+
+ def type, do: :string
+
+ def cast(uri) when is_binary(uri) do
+ case URI.parse(uri) do
+ %URI{host: nil} -> :error
+ %URI{host: ""} -> :error
+ %URI{scheme: scheme} when scheme in ["https", "http"] -> {: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/web/activity_pub/pipeline.ex b/lib/pleroma/web/activity_pub/pipeline.ex
new file mode 100644
index 000000000..7ccee54c9
--- /dev/null
+++ b/lib/pleroma/web/activity_pub/pipeline.ex
@@ -0,0 +1,42 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.ActivityPub.Pipeline do
+ alias Pleroma.Activity
+ alias Pleroma.Web.ActivityPub.ActivityPub
+ alias Pleroma.Web.ActivityPub.MRF
+ alias Pleroma.Web.ActivityPub.ObjectValidator
+ alias Pleroma.Web.ActivityPub.SideEffects
+ alias Pleroma.Web.Federator
+
+ @spec common_pipeline(map(), keyword()) :: {:ok, Activity.t(), keyword()} | {:error, any()}
+ def common_pipeline(object, meta) do
+ with {_, {:ok, validated_object, meta}} <-
+ {:validate_object, ObjectValidator.validate(object, meta)},
+ {_, {:ok, mrfd_object}} <- {:mrf_object, MRF.filter(validated_object)},
+ {_, {:ok, %Activity{} = activity, meta}} <-
+ {:persist_object, ActivityPub.persist(mrfd_object, meta)},
+ {_, {:ok, %Activity{} = activity, meta}} <-
+ {:execute_side_effects, SideEffects.handle(activity, meta)},
+ {_, {:ok, _}} <- {:federation, maybe_federate(activity, meta)} do
+ {:ok, activity, meta}
+ else
+ {:mrf_object, {:reject, _}} -> {:ok, nil, meta}
+ e -> {:error, e}
+ end
+ end
+
+ defp maybe_federate(activity, meta) do
+ with {:ok, local} <- Keyword.fetch(meta, :local) do
+ if local do
+ Federator.publish(activity)
+ {:ok, :federated}
+ else
+ {:ok, :not_federated}
+ end
+ else
+ _e -> {:error, :badarg}
+ end
+ end
+end
diff --git a/lib/pleroma/web/activity_pub/publisher.ex b/lib/pleroma/web/activity_pub/publisher.ex
index 6c558e7f0..b70cbd043 100644
--- a/lib/pleroma/web/activity_pub/publisher.ex
+++ b/lib/pleroma/web/activity_pub/publisher.ex
@@ -141,8 +141,8 @@ defmodule Pleroma.Web.ActivityPub.Publisher do
|> Enum.map(& &1.ap_id)
end
- defp maybe_use_sharedinbox(%User{source_data: data}),
- do: (is_map(data["endpoints"]) && Map.get(data["endpoints"], "sharedInbox")) || data["inbox"]
+ defp maybe_use_sharedinbox(%User{shared_inbox: nil, inbox: inbox}), do: inbox
+ defp maybe_use_sharedinbox(%User{shared_inbox: shared_inbox}), do: shared_inbox
@doc """
Determine a user inbox to use based on heuristics. These heuristics
@@ -157,7 +157,7 @@ defmodule Pleroma.Web.ActivityPub.Publisher do
"""
def determine_inbox(
%Activity{data: activity_data},
- %User{source_data: data} = user
+ %User{inbox: inbox} = user
) do
to = activity_data["to"] || []
cc = activity_data["cc"] || []
@@ -174,7 +174,7 @@ defmodule Pleroma.Web.ActivityPub.Publisher do
maybe_use_sharedinbox(user)
true ->
- data["inbox"]
+ inbox
end
end
@@ -192,14 +192,13 @@ defmodule Pleroma.Web.ActivityPub.Publisher do
inboxes =
recipients
|> Enum.filter(&User.ap_enabled?/1)
- |> Enum.map(fn %{source_data: data} -> data["inbox"] end)
+ |> Enum.map(fn actor -> actor.inbox end)
|> Enum.filter(fn inbox -> should_federate?(inbox, public) end)
|> Instances.filter_reachable()
Repo.checkout(fn ->
Enum.each(inboxes, fn {inbox, unreachable_since} ->
- %User{ap_id: ap_id} =
- Enum.find(recipients, fn %{source_data: data} -> data["inbox"] == inbox end)
+ %User{ap_id: ap_id} = Enum.find(recipients, fn actor -> actor.inbox == inbox end)
# Get all the recipients on the same host and add them to cc. Otherwise, a remote
# instance would only accept a first message for the first recipient and ignore the rest.
diff --git a/lib/pleroma/web/activity_pub/relay.ex b/lib/pleroma/web/activity_pub/relay.ex
index bb5542c89..729c23af7 100644
--- a/lib/pleroma/web/activity_pub/relay.ex
+++ b/lib/pleroma/web/activity_pub/relay.ex
@@ -60,15 +60,28 @@ defmodule Pleroma.Web.ActivityPub.Relay do
def publish(_), do: {:error, "Not implemented"}
- @spec list() :: {:ok, [String.t()]} | {:error, any()}
- def list do
+ @spec list(boolean()) :: {:ok, [String.t()]} | {:error, any()}
+ def list(with_not_accepted \\ false) do
with %User{} = user <- get_actor() do
- list =
+ accepted =
user
|> User.following()
|> Enum.map(fn entry -> URI.parse(entry).host end)
|> Enum.uniq()
+ list =
+ if with_not_accepted do
+ without_accept =
+ user
+ |> Pleroma.Activity.following_requests_for_actor()
+ |> Enum.map(fn a -> URI.parse(a.data["object"]).host <> " (no Accept received)" end)
+ |> Enum.uniq()
+
+ accepted ++ without_accept
+ else
+ accepted
+ end
+
{:ok, list}
else
error -> format_error(error)
diff --git a/lib/pleroma/web/activity_pub/side_effects.ex b/lib/pleroma/web/activity_pub/side_effects.ex
new file mode 100644
index 000000000..6a8f1af96
--- /dev/null
+++ b/lib/pleroma/web/activity_pub/side_effects.ex
@@ -0,0 +1,30 @@
+defmodule Pleroma.Web.ActivityPub.SideEffects do
+ @moduledoc """
+ This module looks at an inserted object and executes the side effects that it
+ implies. For example, a `Like` activity will increase the like count on the
+ liked object, a `Follow` activity will add the user to the follower
+ collection, and so on.
+ """
+ alias Pleroma.Notification
+ alias Pleroma.Object
+ alias Pleroma.Web.ActivityPub.Utils
+
+ def handle(object, meta \\ [])
+
+ # Tasks this handles:
+ # - Add like to object
+ # - Set up notification
+ def handle(%{data: %{"type" => "Like"}} = object, meta) do
+ liked_object = Object.get_by_ap_id(object.data["object"])
+ Utils.add_like_to_object(object, liked_object)
+
+ Notification.create_notifications(object)
+
+ {:ok, object, meta}
+ end
+
+ # Nothing to do
+ def handle(object, meta) do
+ {:ok, object, meta}
+ end
+end
diff --git a/lib/pleroma/web/activity_pub/transmogrifier.ex b/lib/pleroma/web/activity_pub/transmogrifier.ex
index 9cd3de705..09119137b 100644
--- a/lib/pleroma/web/activity_pub/transmogrifier.ex
+++ b/lib/pleroma/web/activity_pub/transmogrifier.ex
@@ -13,6 +13,9 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
alias Pleroma.Repo
alias Pleroma.User
alias Pleroma.Web.ActivityPub.ActivityPub
+ alias Pleroma.Web.ActivityPub.ObjectValidator
+ alias Pleroma.Web.ActivityPub.ObjectValidators.LikeValidator
+ alias Pleroma.Web.ActivityPub.Pipeline
alias Pleroma.Web.ActivityPub.Utils
alias Pleroma.Web.ActivityPub.Visibility
alias Pleroma.Web.Federator
@@ -202,16 +205,46 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
|> Map.put("conversation", context)
end
+ defp add_if_present(map, _key, nil), do: map
+
+ defp add_if_present(map, key, value) do
+ Map.put(map, key, value)
+ end
+
def fix_attachments(%{"attachment" => attachment} = object) when is_list(attachment) do
attachments =
Enum.map(attachment, fn data ->
- media_type = data["mediaType"] || data["mimeType"]
- href = data["url"] || data["href"]
- url = [%{"type" => "Link", "mediaType" => media_type, "href" => href}]
+ url =
+ cond do
+ is_list(data["url"]) -> List.first(data["url"])
+ is_map(data["url"]) -> data["url"]
+ true -> nil
+ end
- data
- |> Map.put("mediaType", media_type)
- |> Map.put("url", url)
+ media_type =
+ cond do
+ is_map(url) && is_binary(url["mediaType"]) -> url["mediaType"]
+ is_binary(data["mediaType"]) -> data["mediaType"]
+ is_binary(data["mimeType"]) -> data["mimeType"]
+ true -> nil
+ end
+
+ href =
+ cond do
+ is_map(url) && is_binary(url["href"]) -> url["href"]
+ is_binary(data["url"]) -> data["url"]
+ is_binary(data["href"]) -> data["href"]
+ end
+
+ attachment_url =
+ %{"href" => href}
+ |> add_if_present("mediaType", media_type)
+ |> add_if_present("type", Map.get(url || %{}, "type"))
+
+ %{"url" => [attachment_url]}
+ |> add_if_present("mediaType", media_type)
+ |> add_if_present("type", data["type"])
+ |> add_if_present("name", data["name"])
end)
Map.put(object, "attachment", attachments)
@@ -229,7 +262,8 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
Map.put(object, "url", url["href"])
end
- def fix_url(%{"type" => "Video", "url" => url} = object) when is_list(url) do
+ def fix_url(%{"type" => object_type, "url" => url} = object)
+ when object_type in ["Video", "Audio"] and is_list(url) do
first_element = Enum.at(url, 0)
link_element = Enum.find(url, fn x -> is_map(x) and x["mimeType"] == "text/html" end)
@@ -398,7 +432,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
%{"type" => "Create", "object" => %{"type" => objtype} = object} = data,
options
)
- when objtype in ["Article", "Event", "Note", "Video", "Page", "Question", "Answer"] do
+ when objtype in ["Article", "Event", "Note", "Video", "Page", "Question", "Answer", "Audio"] do
actor = Containment.get_actor(data)
data =
@@ -490,7 +524,8 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
{_, {:ok, follower}} <- {:follow, User.follow(follower, followed)},
{_, {:ok, _}} <-
{:follow_state_update, Utils.update_follow_state_for_all(activity, "accept")},
- {:ok, _relationship} <- FollowingRelationship.update(follower, followed, "accept") do
+ {:ok, _relationship} <-
+ FollowingRelationship.update(follower, followed, :follow_accept) do
ActivityPub.accept(%{
to: [follower.ap_id],
actor: followed,
@@ -500,7 +535,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
else
{:user_blocked, true} ->
{:ok, _} = Utils.update_follow_state_for_all(activity, "reject")
- {:ok, _relationship} = FollowingRelationship.update(follower, followed, "reject")
+ {:ok, _relationship} = FollowingRelationship.update(follower, followed, :follow_reject)
ActivityPub.reject(%{
to: [follower.ap_id],
@@ -511,7 +546,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
{:follow, {:error, _}} ->
{:ok, _} = Utils.update_follow_state_for_all(activity, "reject")
- {:ok, _relationship} = FollowingRelationship.update(follower, followed, "reject")
+ {:ok, _relationship} = FollowingRelationship.update(follower, followed, :follow_reject)
ActivityPub.reject(%{
to: [follower.ap_id],
@@ -521,7 +556,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
})
{:user_locked, true} ->
- {:ok, _relationship} = FollowingRelationship.update(follower, followed, "pending")
+ {:ok, _relationship} = FollowingRelationship.update(follower, followed, :follow_pending)
:noop
end
@@ -541,7 +576,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
{:ok, follow_activity} <- get_follow_activity(follow_object, followed),
{:ok, follow_activity} <- Utils.update_follow_state_for_all(follow_activity, "accept"),
%User{local: true} = follower <- User.get_cached_by_ap_id(follow_activity.data["actor"]),
- {:ok, _relationship} <- FollowingRelationship.update(follower, followed, "accept") do
+ {:ok, _relationship} <- FollowingRelationship.update(follower, followed, :follow_accept) do
ActivityPub.accept(%{
to: follow_activity.data["to"],
type: "Accept",
@@ -564,7 +599,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
{:ok, follow_activity} <- get_follow_activity(follow_object, followed),
{:ok, follow_activity} <- Utils.update_follow_state_for_all(follow_activity, "reject"),
%User{local: true} = follower <- User.get_cached_by_ap_id(follow_activity.data["actor"]),
- {:ok, _relationship} <- FollowingRelationship.update(follower, followed, "reject"),
+ {:ok, _relationship} <- FollowingRelationship.update(follower, followed, :follow_reject),
{:ok, activity} <-
ActivityPub.reject(%{
to: follow_activity.data["to"],
@@ -608,17 +643,20 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
|> handle_incoming(options)
end
- def handle_incoming(
- %{"type" => "Like", "object" => object_id, "actor" => _actor, "id" => id} = data,
- _options
- ) do
- with actor <- Containment.get_actor(data),
- {:ok, %User{} = actor} <- User.get_or_fetch_by_ap_id(actor),
- {:ok, object} <- get_obj_helper(object_id),
- {:ok, activity, _object} <- ActivityPub.like(actor, object, id, false) do
+ def handle_incoming(%{"type" => "Like"} = data, _options) do
+ with {_, {:ok, cast_data_sym}} <-
+ {:casting_data,
+ data |> LikeValidator.cast_data() |> Ecto.Changeset.apply_action(:insert)},
+ cast_data = ObjectValidator.stringify_keys(Map.from_struct(cast_data_sym)),
+ :ok <- ObjectValidator.fetch_actor_and_object(cast_data),
+ {_, {:ok, cast_data}} <- {:ensure_context_presence, ensure_context_presence(cast_data)},
+ {_, {:ok, cast_data}} <-
+ {:ensure_recipients_presence, ensure_recipients_presence(cast_data)},
+ {_, {:ok, activity, _meta}} <-
+ {:common_pipeline, Pipeline.common_pipeline(cast_data, local: false)} do
{:ok, activity}
else
- _e -> :error
+ e -> {:error, e}
end
end
@@ -673,7 +711,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
{:ok, new_user_data} = ActivityPub.user_data_from_user_object(object)
actor
- |> User.upgrade_changeset(new_user_data, true)
+ |> User.remote_user_changeset(new_user_data)
|> User.update_and_set_cache()
ActivityPub.update(%{
@@ -1108,13 +1146,11 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
end
def add_mention_tags(object) do
- mentions =
- object
- |> Utils.get_notified_from_object()
- |> Enum.map(&build_mention_tag/1)
+ {enabled_receivers, disabled_receivers} = Utils.get_notified_from_object(object)
+ potential_receivers = enabled_receivers ++ disabled_receivers
+ mentions = Enum.map(potential_receivers, &build_mention_tag/1)
tags = object["tag"] || []
-
Map.put(object, "tag", tags ++ mentions)
end
@@ -1124,7 +1160,7 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
def take_emoji_tags(%User{emoji: emoji}) do
emoji
- |> Enum.flat_map(&Map.to_list/1)
+ |> Map.to_list()
|> Enum.map(&build_emoji_tag/1)
end
@@ -1218,12 +1254,8 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
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),
- already_ap <- User.ap_enabled?(user),
- {:ok, user} <- upgrade_user(user, data) do
- if not already_ap do
- TransmogrifierWorker.enqueue("user_upgrade", %{"user_id" => user.id})
- end
-
+ {:ok, user} <- update_user(user, data) do
+ TransmogrifierWorker.enqueue("user_upgrade", %{"user_id" => user.id})
{:ok, user}
else
%User{} = user -> {:ok, user}
@@ -1231,9 +1263,9 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
end
end
- defp upgrade_user(user, data) do
+ defp update_user(user, data) do
user
- |> User.upgrade_changeset(data, true)
+ |> User.remote_user_changeset(data)
|> User.update_and_set_cache()
end
@@ -1244,4 +1276,45 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
def maybe_fix_user_url(data), do: data
def maybe_fix_user_object(data), do: maybe_fix_user_url(data)
+
+ defp ensure_context_presence(%{"context" => context} = data) when is_binary(context),
+ do: {:ok, data}
+
+ defp ensure_context_presence(%{"object" => object} = data) when is_binary(object) do
+ with %{data: %{"context" => context}} when is_binary(context) <- Object.normalize(object) do
+ {:ok, Map.put(data, "context", context)}
+ else
+ _ ->
+ {:error, :no_context}
+ end
+ end
+
+ defp ensure_context_presence(_) do
+ {:error, :no_context}
+ end
+
+ defp ensure_recipients_presence(%{"to" => [_ | _], "cc" => [_ | _]} = data),
+ do: {:ok, data}
+
+ defp ensure_recipients_presence(%{"object" => object} = data) do
+ case Object.normalize(object) do
+ %{data: %{"actor" => actor}} ->
+ data =
+ data
+ |> Map.put("to", [actor])
+ |> Map.put("cc", data["cc"] || [])
+
+ {:ok, data}
+
+ nil ->
+ {:error, :no_object}
+
+ _ ->
+ {:error, :no_actor}
+ end
+ end
+
+ defp ensure_recipients_presence(_) do
+ {:error, :no_object}
+ end
end
diff --git a/lib/pleroma/web/activity_pub/utils.ex b/lib/pleroma/web/activity_pub/utils.ex
index 2bc958670..2d685ecc0 100644
--- a/lib/pleroma/web/activity_pub/utils.ex
+++ b/lib/pleroma/web/activity_pub/utils.ex
@@ -440,22 +440,19 @@ defmodule Pleroma.Web.ActivityPub.Utils do
|> update(set: [data: fragment("jsonb_set(data, '{state}', ?)", ^state)])
|> Repo.update_all([])
- User.set_follow_state_cache(actor, object, state)
-
activity = Activity.get_by_id(activity.id)
{:ok, activity}
end
def update_follow_state(
- %Activity{data: %{"actor" => actor, "object" => object}} = activity,
+ %Activity{} = activity,
state
) do
new_data = Map.put(activity.data, "state", state)
changeset = Changeset.change(activity, data: new_data)
with {:ok, activity} <- Repo.update(changeset) do
- User.set_follow_state_cache(actor, object, state)
{:ok, activity}
end
end
@@ -784,45 +781,6 @@ defmodule Pleroma.Web.ActivityPub.Utils do
defp build_flag_object(_), do: []
- @doc """
- Fetches the OrderedCollection/OrderedCollectionPage from `from`, limiting the amount of pages fetched after
- the first one to `pages_left` pages.
- If the amount of pages is higher than the collection has, it returns whatever was there.
- """
- def fetch_ordered_collection(from, pages_left, acc \\ []) do
- with {:ok, response} <- Tesla.get(from),
- {:ok, collection} <- Jason.decode(response.body) do
- case collection["type"] do
- "OrderedCollection" ->
- # If we've encountered the OrderedCollection and not the page,
- # just call the same function on the page address
- fetch_ordered_collection(collection["first"], pages_left)
-
- "OrderedCollectionPage" ->
- if pages_left > 0 do
- # There are still more pages
- if Map.has_key?(collection, "next") do
- # There are still more pages, go deeper saving what we have into the accumulator
- fetch_ordered_collection(
- collection["next"],
- pages_left - 1,
- acc ++ collection["orderedItems"]
- )
- else
- # No more pages left, just return whatever we already have
- acc ++ collection["orderedItems"]
- end
- else
- # Got the amount of pages needed, add them all to the accumulator
- acc ++ collection["orderedItems"]
- end
-
- _ ->
- {:error, "Not an OrderedCollection or OrderedCollectionPage"}
- end
- end
- end
-
#### Report-related helpers
def get_reports(params, page, page_size) do
params =
@@ -837,102 +795,6 @@ defmodule Pleroma.Web.ActivityPub.Utils do
ActivityPub.fetch_activities([], params, :offset)
end
- def parse_report_group(activity) do
- reports = get_reports_by_status_id(activity["id"])
- max_date = Enum.max_by(reports, &NaiveDateTime.from_iso8601!(&1.data["published"]))
- actors = Enum.map(reports, & &1.user_actor)
- [%{data: %{"object" => [account_id | _]}} | _] = reports
-
- account =
- AccountView.render("show.json", %{
- user: User.get_by_ap_id(account_id)
- })
-
- status = get_status_data(activity)
-
- %{
- date: max_date.data["published"],
- account: account,
- status: status,
- actors: Enum.uniq(actors),
- reports: reports
- }
- end
-
- defp get_status_data(status) do
- case status["deleted"] do
- true ->
- %{
- "id" => status["id"],
- "deleted" => true
- }
-
- _ ->
- Activity.get_by_ap_id(status["id"])
- end
- end
-
- def get_reports_by_status_id(ap_id) do
- from(a in Activity,
- where: fragment("(?)->>'type' = 'Flag'", a.data),
- where: fragment("(?)->'object' @> ?", a.data, ^[%{id: ap_id}]),
- or_where: fragment("(?)->'object' @> ?", a.data, ^[ap_id])
- )
- |> Activity.with_preloaded_user_actor()
- |> Repo.all()
- end
-
- @spec get_reports_grouped_by_status([String.t()]) :: %{
- required(:groups) => [
- %{
- required(:date) => String.t(),
- required(:account) => %{},
- required(:status) => %{},
- required(:actors) => [%User{}],
- required(:reports) => [%Activity{}]
- }
- ]
- }
- def get_reports_grouped_by_status(activity_ids) do
- parsed_groups =
- activity_ids
- |> Enum.map(fn id ->
- id
- |> build_flag_object()
- |> parse_report_group()
- end)
-
- %{
- groups: parsed_groups
- }
- end
-
- @spec get_reported_activities() :: [
- %{
- required(:activity) => String.t(),
- required(:date) => String.t()
- }
- ]
- def get_reported_activities do
- reported_activities_query =
- from(a in Activity,
- where: fragment("(?)->>'type' = 'Flag'", a.data),
- select: %{
- activity: fragment("jsonb_array_elements((? #- '{object,0}')->'object')", a.data)
- },
- group_by: fragment("activity")
- )
-
- from(a in subquery(reported_activities_query),
- distinct: true,
- select: %{
- id: fragment("COALESCE(?->>'id'::text, ? #>> '{}')", a.activity, a.activity)
- }
- )
- |> Repo.all()
- |> Enum.map(& &1.id)
- end
-
def update_report_state(%Activity{} = activity, state)
when state in @strip_status_report_states do
{:ok, stripped_activity} = strip_report_status_data(activity)
diff --git a/lib/pleroma/web/activity_pub/views/object_view.ex b/lib/pleroma/web/activity_pub/views/object_view.ex
index d8a3ec288..e555e9999 100644
--- a/lib/pleroma/web/activity_pub/views/object_view.ex
+++ b/lib/pleroma/web/activity_pub/views/object_view.ex
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.ActivityPub.ObjectView do
diff --git a/lib/pleroma/web/activity_pub/views/user_view.ex b/lib/pleroma/web/activity_pub/views/user_view.ex
index 350c4391d..34590b16d 100644
--- a/lib/pleroma/web/activity_pub/views/user_view.ex
+++ b/lib/pleroma/web/activity_pub/views/user_view.ex
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.ActivityPub.UserView do
@@ -73,21 +73,13 @@ defmodule Pleroma.Web.ActivityPub.UserView do
{:ok, _, public_key} = Keys.keys_from_pem(user.keys)
public_key = :public_key.pem_entry_encode(:SubjectPublicKeyInfo, public_key)
public_key = :public_key.pem_encode([public_key])
+ user = User.sanitize_html(user)
endpoints = render("endpoints.json", %{user: user})
emoji_tags = Transmogrifier.take_emoji_tags(user)
- fields =
- user
- |> User.fields()
- |> Enum.map(fn %{"name" => name, "value" => value} ->
- %{
- "name" => Pleroma.HTML.strip_tags(name),
- "value" => Pleroma.HTML.filter_tags(value, Pleroma.HTML.Scrubber.LinksOnly)
- }
- end)
- |> Enum.map(&Map.put(&1, "type", "PropertyValue"))
+ fields = Enum.map(user.fields, &Map.put(&1, "type", "PropertyValue"))
%{
"id" => user.ap_id,
@@ -108,7 +100,7 @@ defmodule Pleroma.Web.ActivityPub.UserView do
},
"endpoints" => endpoints,
"attachment" => fields,
- "tag" => (user.source_data["tag"] || []) ++ emoji_tags,
+ "tag" => emoji_tags,
"discoverable" => user.discoverable
}
|> Map.merge(maybe_make_image(&User.avatar_url/2, "icon", user))
diff --git a/lib/pleroma/web/activity_pub/visibility.ex b/lib/pleroma/web/activity_pub/visibility.ex
index e172f6d3f..453a6842e 100644
--- a/lib/pleroma/web/activity_pub/visibility.ex
+++ b/lib/pleroma/web/activity_pub/visibility.ex
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.ActivityPub.Visibility do
@@ -44,6 +44,7 @@ defmodule Pleroma.Web.ActivityPub.Visibility do
def is_list?(%{data: %{"listMessage" => _}}), do: true
def is_list?(_), do: false
+ @spec visible_for_user?(Activity.t(), User.t() | nil) :: boolean()
def visible_for_user?(%{actor: ap_id}, %User{ap_id: ap_id}), do: true
def visible_for_user?(%{data: %{"listMessage" => list_ap_id}} = activity, %User{} = user) do
@@ -55,14 +56,21 @@ defmodule Pleroma.Web.ActivityPub.Visibility do
def visible_for_user?(%{data: %{"listMessage" => _}}, nil), do: false
- def visible_for_user?(activity, nil) do
- is_public?(activity)
+ def visible_for_user?(%{local: local} = activity, nil) do
+ cfg_key =
+ if local,
+ do: :local,
+ else: :remote
+
+ if Pleroma.Config.get([:restrict_unauthenticated, :activities, cfg_key]),
+ do: false,
+ else: is_public?(activity)
end
def visible_for_user?(activity, user) do
x = [user.ap_id | User.following(user)]
y = [activity.actor] ++ activity.data["to"] ++ (activity.data["cc"] || [])
- visible_for_user?(activity, nil) || Enum.any?(x, &(&1 in y))
+ is_public?(activity) || Enum.any?(x, &(&1 in y))
end
def entire_thread_visible_for_user?(%Activity{} = activity, %User{} = user) do
diff --git a/lib/pleroma/web/admin_api/admin_api_controller.ex b/lib/pleroma/web/admin_api/admin_api_controller.ex
index 558832703..9c79310c0 100644
--- a/lib/pleroma/web/admin_api/admin_api_controller.ex
+++ b/lib/pleroma/web/admin_api/admin_api_controller.ex
@@ -27,7 +27,9 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do
alias Pleroma.Web.AdminAPI.Search
alias Pleroma.Web.CommonAPI
alias Pleroma.Web.Endpoint
+ alias Pleroma.Web.MastodonAPI.AppView
alias Pleroma.Web.MastodonAPI.StatusView
+ alias Pleroma.Web.OAuth.App
alias Pleroma.Web.Router
require Logger
@@ -38,7 +40,7 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do
plug(
OAuthScopesPlug,
%{scopes: ["read:accounts"], admin: true}
- when action in [:list_users, :user_show, :right_get]
+ when action in [:list_users, :user_show, :right_get, :show_user_credentials]
)
plug(
@@ -54,7 +56,8 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do
:tag_users,
:untag_users,
:right_add,
- :right_delete
+ :right_delete,
+ :update_user_credentials
]
)
@@ -257,7 +260,7 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do
conn
|> put_view(Pleroma.Web.AdminAPI.StatusView)
- |> render("index.json", %{activities: activities, as: :activity})
+ |> render("index.json", %{activities: activities, as: :activity, skip_relationships: false})
end
def list_user_statuses(conn, %{"nickname" => nickname} = params) do
@@ -276,7 +279,7 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do
conn
|> put_view(StatusView)
- |> render("index.json", %{activities: activities, as: :activity})
+ |> render("index.json", %{activities: activities, as: :activity, skip_relationships: false})
else
_ -> {:error, :not_found}
end
@@ -575,9 +578,8 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do
@doc "Sends registration invite via email"
def email_invite(%{assigns: %{user: user}} = conn, %{"email" => email} = params) do
- with true <-
- Config.get([:instance, :invites_enabled]) &&
- !Config.get([:instance, :registrations_open]),
+ with {_, false} <- {:registrations_open, Config.get([:instance, :registrations_open])},
+ {_, true} <- {:invites_enabled, Config.get([:instance, :invites_enabled])},
{:ok, invite_token} <- UserInviteToken.create_invite(),
email <-
Pleroma.Emails.UserEmail.user_invitation_email(
@@ -588,6 +590,18 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do
),
{:ok, _} <- Pleroma.Emails.Mailer.deliver(email) do
json_response(conn, :no_content, "")
+ else
+ {:registrations_open, _} ->
+ errors(
+ conn,
+ {:error, "To send invites you need to set the `registrations_open` option to false."}
+ )
+
+ {:invites_enabled, _} ->
+ errors(
+ conn,
+ {:error, "To send invites you need to set the `invites_enabled` option to true."}
+ )
end
end
@@ -658,6 +672,52 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do
json_response(conn, :no_content, "")
end
+ @doc "Show a given user's credentials"
+ def show_user_credentials(%{assigns: %{user: admin}} = conn, %{"nickname" => nickname}) do
+ with %User{} = user <- User.get_cached_by_nickname_or_id(nickname) do
+ conn
+ |> put_view(AccountView)
+ |> render("credentials.json", %{user: user, for: admin})
+ else
+ _ -> {:error, :not_found}
+ end
+ end
+
+ @doc "Updates a given user"
+ def update_user_credentials(
+ %{assigns: %{user: admin}} = conn,
+ %{"nickname" => nickname} = params
+ ) do
+ with {_, user} <- {:user, User.get_cached_by_nickname(nickname)},
+ {:ok, _user} <-
+ User.update_as_admin(user, params) do
+ ModerationLog.insert_log(%{
+ actor: admin,
+ subject: [user],
+ action: "updated_users"
+ })
+
+ if params["password"] do
+ User.force_password_reset_async(user)
+ end
+
+ ModerationLog.insert_log(%{
+ actor: admin,
+ subject: [user],
+ action: "force_password_reset"
+ })
+
+ json(conn, %{status: "success"})
+ else
+ {:error, changeset} ->
+ {_, {error, _}} = Enum.at(changeset.errors, 0)
+ json(conn, %{error: "New password #{error}."})
+
+ _ ->
+ json(conn, %{error: "Unable to change password."})
+ end
+ end
+
def list_reports(conn, params) do
{page, page_size} = page_params(params)
@@ -668,14 +728,6 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do
|> render("index.json", %{reports: reports})
end
- def list_grouped_reports(conn, _params) do
- statuses = Utils.get_reported_activities()
-
- conn
- |> put_view(ReportView)
- |> render("index_grouped.json", Utils.get_reports_grouped_by_status(statuses))
- end
-
def report_show(conn, %{"id" => id}) do
with %Activity{} = report <- Activity.get_by_id(id) do
conn
@@ -745,22 +797,24 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do
end
end
- def list_statuses(%{assigns: %{user: admin}} = conn, params) do
+ def list_statuses(%{assigns: %{user: _admin}} = conn, params) do
godmode = params["godmode"] == "true" || params["godmode"] == true
local_only = params["local_only"] == "true" || params["local_only"] == true
+ with_reblogs = params["with_reblogs"] == "true" || params["with_reblogs"] == true
{page, page_size} = page_params(params)
activities =
- ActivityPub.fetch_statuses(admin, %{
+ ActivityPub.fetch_statuses(nil, %{
"godmode" => godmode,
"local_only" => local_only,
"limit" => page_size,
- "offset" => (page - 1) * page_size
+ "offset" => (page - 1) * page_size,
+ "exclude_reblogs" => !with_reblogs && "true"
})
conn
|> put_view(Pleroma.Web.AdminAPI.StatusView)
- |> render("index.json", %{activities: activities, as: :activity})
+ |> render("index.json", %{activities: activities, as: :activity, skip_relationships: false})
end
def status_update(%{assigns: %{user: admin}} = conn, %{"id" => id} = params) do
@@ -832,7 +886,7 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do
configs = ConfigDB.get_all_as_keyword()
merged =
- Config.Holder.config()
+ Config.Holder.default_config()
|> ConfigDB.merge(configs)
|> Enum.map(fn {group, values} ->
Enum.map(values, fn {key, value} ->
@@ -862,16 +916,7 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do
end)
|> List.flatten()
- response = %{configs: merged}
-
- response =
- if Restarter.Pleroma.need_reboot?() do
- Map.put(response, :need_reboot, true)
- else
- response
- end
-
- json(conn, response)
+ json(conn, %{configs: merged, need_reboot: Restarter.Pleroma.need_reboot?()})
end
end
@@ -898,28 +943,22 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do
Config.TransferTask.load_and_update_env(deleted, false)
- need_reboot? =
- Restarter.Pleroma.need_reboot?() ||
- Enum.any?(updated, fn config ->
+ if !Restarter.Pleroma.need_reboot?() do
+ changed_reboot_settings? =
+ (updated ++ deleted)
+ |> Enum.any?(fn config ->
group = ConfigDB.from_string(config.group)
key = ConfigDB.from_string(config.key)
value = ConfigDB.from_binary(config.value)
Config.TransferTask.pleroma_need_restart?(group, key, value)
end)
- response = %{configs: updated}
-
- response =
- if need_reboot? do
- Restarter.Pleroma.need_reboot()
- Map.put(response, :need_reboot, need_reboot?)
- else
- response
- end
+ if changed_reboot_settings?, do: Restarter.Pleroma.need_reboot()
+ end
conn
|> put_view(ConfigView)
- |> render("index.json", response)
+ |> render("index.json", %{configs: updated, need_reboot: Restarter.Pleroma.need_reboot?()})
end
end
@@ -931,6 +970,10 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do
end
end
+ def need_reboot(conn, _params) do
+ json(conn, %{need_reboot: Restarter.Pleroma.need_reboot?()})
+ end
+
defp configurable_from_database(conn) do
if Config.get(:configurable_from_database) do
:ok
@@ -976,6 +1019,83 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do
conn |> json("")
end
+ def oauth_app_create(conn, params) do
+ params =
+ if params["name"] do
+ Map.put(params, "client_name", params["name"])
+ else
+ params
+ end
+
+ result =
+ case App.create(params) do
+ {:ok, app} ->
+ AppView.render("show.json", %{app: app, admin: true})
+
+ {:error, changeset} ->
+ App.errors(changeset)
+ end
+
+ json(conn, result)
+ end
+
+ def oauth_app_update(conn, params) do
+ params =
+ if params["name"] do
+ Map.put(params, "client_name", params["name"])
+ else
+ params
+ end
+
+ with {:ok, app} <- App.update(params) do
+ json(conn, AppView.render("show.json", %{app: app, admin: true}))
+ else
+ {:error, changeset} ->
+ json(conn, App.errors(changeset))
+
+ nil ->
+ json_response(conn, :bad_request, "")
+ end
+ end
+
+ def oauth_app_list(conn, params) do
+ {page, page_size} = page_params(params)
+
+ search_params = %{
+ client_name: params["name"],
+ client_id: params["client_id"],
+ page: page,
+ page_size: page_size
+ }
+
+ search_params =
+ if Map.has_key?(params, "trusted") do
+ Map.put(search_params, :trusted, params["trusted"])
+ else
+ search_params
+ end
+
+ with {:ok, apps, count} <- App.search(search_params) do
+ json(
+ conn,
+ AppView.render("index.json",
+ apps: apps,
+ count: count,
+ page_size: page_size,
+ admin: true
+ )
+ )
+ end
+ end
+
+ def oauth_app_delete(conn, params) do
+ with {:ok, _app} <- App.destroy(params["id"]) do
+ json_response(conn, :no_content, "")
+ else
+ _ -> json_response(conn, :bad_request, "")
+ end
+ end
+
def stats(conn, _) do
count = Stats.get_status_visibility_count()
diff --git a/lib/pleroma/web/admin_api/report.ex b/lib/pleroma/web/admin_api/report.ex
index 9c3468570..8660d6520 100644
--- a/lib/pleroma/web/admin_api/report.ex
+++ b/lib/pleroma/web/admin_api/report.ex
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.AdminAPI.Report do
diff --git a/lib/pleroma/web/admin_api/views/account_view.ex b/lib/pleroma/web/admin_api/views/account_view.ex
index d9dba5c51..a16a3ebf0 100644
--- a/lib/pleroma/web/admin_api/views/account_view.ex
+++ b/lib/pleroma/web/admin_api/views/account_view.ex
@@ -1,11 +1,10 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.AdminAPI.AccountView do
use Pleroma.Web, :view
- alias Pleroma.HTML
alias Pleroma.User
alias Pleroma.Web.AdminAPI.AccountView
alias Pleroma.Web.MediaProxy
@@ -24,9 +23,47 @@ defmodule Pleroma.Web.AdminAPI.AccountView do
}
end
+ def render("credentials.json", %{user: user, for: for_user}) do
+ user = User.sanitize_html(user, User.html_filter_policy(for_user))
+ avatar = User.avatar_url(user) |> MediaProxy.url()
+ banner = User.banner_url(user) |> MediaProxy.url()
+ background = image_url(user.background) |> MediaProxy.url()
+
+ user
+ |> Map.take([
+ :id,
+ :bio,
+ :email,
+ :fields,
+ :name,
+ :nickname,
+ :locked,
+ :no_rich_text,
+ :default_scope,
+ :hide_follows,
+ :hide_followers_count,
+ :hide_follows_count,
+ :hide_followers,
+ :hide_favorites,
+ :allow_following_move,
+ :show_role,
+ :skip_thread_containment,
+ :pleroma_settings_store,
+ :raw_fields,
+ :discoverable,
+ :actor_type
+ ])
+ |> Map.merge(%{
+ "avatar" => avatar,
+ "banner" => banner,
+ "background" => background
+ })
+ end
+
def render("show.json", %{user: user}) do
avatar = User.avatar_url(user) |> MediaProxy.url()
- display_name = HTML.strip_tags(user.name || user.nickname)
+ display_name = Pleroma.HTML.strip_tags(user.name || user.nickname)
+ user = User.sanitize_html(user, FastSanitize.Sanitizer.StripTags)
%{
"id" => user.id,
@@ -104,4 +141,7 @@ defmodule Pleroma.Web.AdminAPI.AccountView do
""
end
end
+
+ defp image_url(%{"url" => [%{"href" => href} | _]}), do: href
+ defp image_url(_), do: nil
end
diff --git a/lib/pleroma/web/admin_api/views/moderation_log_view.ex b/lib/pleroma/web/admin_api/views/moderation_log_view.ex
index e7752d1f3..112f9e0e1 100644
--- a/lib/pleroma/web/admin_api/views/moderation_log_view.ex
+++ b/lib/pleroma/web/admin_api/views/moderation_log_view.ex
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.AdminAPI.ModerationLogView do
diff --git a/lib/pleroma/web/admin_api/views/report_view.ex b/lib/pleroma/web/admin_api/views/report_view.ex
index 4880d2992..d50969b2a 100644
--- a/lib/pleroma/web/admin_api/views/report_view.ex
+++ b/lib/pleroma/web/admin_api/views/report_view.ex
@@ -1,10 +1,10 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.AdminAPI.ReportView do
use Pleroma.Web, :view
- alias Pleroma.Activity
+
alias Pleroma.HTML
alias Pleroma.User
alias Pleroma.Web.AdminAPI.Report
@@ -38,38 +38,17 @@ defmodule Pleroma.Web.AdminAPI.ReportView do
actor: merge_account_views(user),
content: content,
created_at: created_at,
- statuses: StatusView.render("index.json", %{activities: statuses, as: :activity}),
+ statuses:
+ StatusView.render("index.json", %{
+ activities: statuses,
+ as: :activity,
+ skip_relationships: false
+ }),
state: report.data["state"],
notes: render(__MODULE__, "index_notes.json", %{notes: report.report_notes})
}
end
- def render("index_grouped.json", %{groups: groups}) do
- reports =
- Enum.map(groups, fn group ->
- status =
- case group.status do
- %Activity{} = activity -> StatusView.render("show.json", %{activity: activity})
- _ -> group.status
- end
-
- %{
- date: group[:date],
- account: group[:account],
- status: Map.put_new(status, "deleted", false),
- actors: Enum.map(group[:actors], &merge_account_views/1),
- reports:
- group[:reports]
- |> Enum.map(&Report.extract_report_info(&1))
- |> Enum.map(&render(__MODULE__, "show.json", &1))
- }
- end)
-
- %{
- reports: reports
- }
- end
-
def render("index_notes.json", %{notes: notes}) when is_list(notes) do
Enum.map(notes, &render(__MODULE__, "show_note.json", &1))
end
diff --git a/lib/pleroma/web/api_spec.ex b/lib/pleroma/web/api_spec.ex
new file mode 100644
index 000000000..3890489e3
--- /dev/null
+++ b/lib/pleroma/web/api_spec.ex
@@ -0,0 +1,44 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.ApiSpec do
+ alias OpenApiSpex.OpenApi
+ alias Pleroma.Web.Endpoint
+ alias Pleroma.Web.Router
+
+ @behaviour OpenApi
+
+ @impl OpenApi
+ def spec do
+ %OpenApi{
+ servers: [
+ # Populate the Server info from a phoenix endpoint
+ OpenApiSpex.Server.from_endpoint(Endpoint)
+ ],
+ info: %OpenApiSpex.Info{
+ title: "Pleroma",
+ description: Application.spec(:pleroma, :description) |> to_string(),
+ version: Application.spec(:pleroma, :vsn) |> to_string()
+ },
+ # populate the paths from a phoenix router
+ paths: OpenApiSpex.Paths.from_router(Router),
+ components: %OpenApiSpex.Components{
+ securitySchemes: %{
+ "oAuth" => %OpenApiSpex.SecurityScheme{
+ type: "oauth2",
+ flows: %OpenApiSpex.OAuthFlows{
+ password: %OpenApiSpex.OAuthFlow{
+ authorizationUrl: "/oauth/authorize",
+ tokenUrl: "/oauth/token",
+ scopes: %{"read" => "read", "write" => "write", "follow" => "follow"}
+ }
+ }
+ }
+ }
+ }
+ }
+ # discover request/response schemas from path specs
+ |> OpenApiSpex.resolve_schema_modules()
+ end
+end
diff --git a/lib/pleroma/web/api_spec/helpers.ex b/lib/pleroma/web/api_spec/helpers.ex
new file mode 100644
index 000000000..7348dcbee
--- /dev/null
+++ b/lib/pleroma/web/api_spec/helpers.ex
@@ -0,0 +1,27 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.ApiSpec.Helpers do
+ def request_body(description, schema_ref, opts \\ []) do
+ media_types = ["application/json", "multipart/form-data", "application/x-www-form-urlencoded"]
+
+ content =
+ media_types
+ |> Enum.map(fn type ->
+ {type,
+ %OpenApiSpex.MediaType{
+ schema: schema_ref,
+ example: opts[:example],
+ examples: opts[:examples]
+ }}
+ end)
+ |> Enum.into(%{})
+
+ %OpenApiSpex.RequestBody{
+ description: description,
+ content: content,
+ required: opts[:required] || false
+ }
+ end
+end
diff --git a/lib/pleroma/web/api_spec/operations/app_operation.ex b/lib/pleroma/web/api_spec/operations/app_operation.ex
new file mode 100644
index 000000000..26d8dbd42
--- /dev/null
+++ b/lib/pleroma/web/api_spec/operations/app_operation.ex
@@ -0,0 +1,96 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.ApiSpec.AppOperation do
+ alias OpenApiSpex.Operation
+ alias OpenApiSpex.Schema
+ alias Pleroma.Web.ApiSpec.Helpers
+ alias Pleroma.Web.ApiSpec.Schemas.AppCreateRequest
+ alias Pleroma.Web.ApiSpec.Schemas.AppCreateResponse
+
+ @spec open_api_operation(atom) :: Operation.t()
+ def open_api_operation(action) do
+ operation = String.to_existing_atom("#{action}_operation")
+ apply(__MODULE__, operation, [])
+ end
+
+ @spec create_operation() :: Operation.t()
+ def create_operation do
+ %Operation{
+ tags: ["apps"],
+ summary: "Create an application",
+ description: "Create a new application to obtain OAuth2 credentials",
+ operationId: "AppController.create",
+ requestBody: Helpers.request_body("Parameters", AppCreateRequest, required: true),
+ responses: %{
+ 200 => Operation.response("App", "application/json", AppCreateResponse),
+ 422 =>
+ Operation.response(
+ "Unprocessable Entity",
+ "application/json",
+ %Schema{
+ type: :object,
+ description:
+ "If a required parameter is missing or improperly formatted, the request will fail.",
+ properties: %{
+ error: %Schema{type: :string}
+ },
+ example: %{
+ "error" => "Validation failed: Redirect URI must be an absolute URI."
+ }
+ }
+ )
+ }
+ }
+ end
+
+ def verify_credentials_operation do
+ %Operation{
+ tags: ["apps"],
+ summary: "Verify your app works",
+ description: "Confirm that the app's OAuth2 credentials work.",
+ operationId: "AppController.verify_credentials",
+ security: [
+ %{
+ "oAuth" => ["read"]
+ }
+ ],
+ responses: %{
+ 200 =>
+ Operation.response("App", "application/json", %Schema{
+ type: :object,
+ description:
+ "If the Authorization header was provided with a valid token, you should see your app returned as an Application entity.",
+ properties: %{
+ name: %Schema{type: :string},
+ vapid_key: %Schema{type: :string},
+ website: %Schema{type: :string, nullable: true}
+ },
+ example: %{
+ "name" => "My App",
+ "vapid_key" =>
+ "BCk-QqERU0q-CfYZjcuB6lnyyOYfJ2AifKqfeGIm7Z-HiTU5T9eTG5GxVA0_OH5mMlI4UkkDTpaZwozy0TzdZ2M=",
+ "website" => "https://myapp.com/"
+ }
+ }),
+ 422 =>
+ Operation.response(
+ "Unauthorized",
+ "application/json",
+ %Schema{
+ type: :object,
+ description:
+ "If the Authorization header contains an invalid token, is malformed, or is not present, an error will be returned indicating an authorization failure.",
+ properties: %{
+ error: %Schema{type: :string}
+ },
+ example: %{
+ "error" => "The access token is invalid."
+ }
+ }
+ )
+ }
+ }
+ end
+end
diff --git a/lib/pleroma/web/api_spec/operations/custom_emoji_operation.ex b/lib/pleroma/web/api_spec/operations/custom_emoji_operation.ex
new file mode 100644
index 000000000..cf2215823
--- /dev/null
+++ b/lib/pleroma/web/api_spec/operations/custom_emoji_operation.ex
@@ -0,0 +1,25 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.ApiSpec.CustomEmojiOperation do
+ alias OpenApiSpex.Operation
+ alias Pleroma.Web.ApiSpec.Schemas.CustomEmojisResponse
+
+ def open_api_operation(action) do
+ operation = String.to_existing_atom("#{action}_operation")
+ apply(__MODULE__, operation, [])
+ end
+
+ def index_operation do
+ %Operation{
+ tags: ["custom_emojis"],
+ summary: "List custom custom emojis",
+ description: "Returns custom emojis that are available on the server.",
+ operationId: "CustomEmojiController.index",
+ responses: %{
+ 200 => Operation.response("Custom Emojis", "application/json", CustomEmojisResponse)
+ }
+ }
+ end
+end
diff --git a/lib/pleroma/web/api_spec/operations/domain_block_operation.ex b/lib/pleroma/web/api_spec/operations/domain_block_operation.ex
new file mode 100644
index 000000000..dd14837c3
--- /dev/null
+++ b/lib/pleroma/web/api_spec/operations/domain_block_operation.ex
@@ -0,0 +1,64 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.ApiSpec.DomainBlockOperation do
+ alias OpenApiSpex.Operation
+ alias OpenApiSpex.Schema
+ alias Pleroma.Web.ApiSpec.Helpers
+ alias Pleroma.Web.ApiSpec.Schemas.DomainBlockRequest
+ alias Pleroma.Web.ApiSpec.Schemas.DomainBlocksResponse
+
+ def open_api_operation(action) do
+ operation = String.to_existing_atom("#{action}_operation")
+ apply(__MODULE__, operation, [])
+ end
+
+ def index_operation do
+ %Operation{
+ tags: ["domain_blocks"],
+ summary: "Fetch domain blocks",
+ description: "View domains the user has blocked.",
+ security: [%{"oAuth" => ["follow", "read:blocks"]}],
+ operationId: "DomainBlockController.index",
+ responses: %{
+ 200 => Operation.response("Domain blocks", "application/json", DomainBlocksResponse)
+ }
+ }
+ end
+
+ def create_operation do
+ %Operation{
+ tags: ["domain_blocks"],
+ summary: "Block a domain",
+ description: """
+ Block a domain to:
+
+ - hide all public posts from it
+ - hide all notifications from it
+ - remove all followers from it
+ - prevent following new users from it (but does not remove existing follows)
+ """,
+ operationId: "DomainBlockController.create",
+ requestBody: Helpers.request_body("Parameters", DomainBlockRequest, required: true),
+ security: [%{"oAuth" => ["follow", "write:blocks"]}],
+ responses: %{
+ 200 => Operation.response("Empty object", "application/json", %Schema{type: :object})
+ }
+ }
+ end
+
+ def delete_operation do
+ %Operation{
+ tags: ["domain_blocks"],
+ summary: "Unblock a domain",
+ description: "Remove a domain block, if it exists in the user's array of blocked domains.",
+ operationId: "DomainBlockController.delete",
+ requestBody: Helpers.request_body("Parameters", DomainBlockRequest, required: true),
+ security: [%{"oAuth" => ["follow", "write:blocks"]}],
+ responses: %{
+ 200 => Operation.response("Empty object", "application/json", %Schema{type: :object})
+ }
+ }
+ end
+end
diff --git a/lib/pleroma/web/api_spec/schemas/app_create_request.ex b/lib/pleroma/web/api_spec/schemas/app_create_request.ex
new file mode 100644
index 000000000..8a83abef3
--- /dev/null
+++ b/lib/pleroma/web/api_spec/schemas/app_create_request.ex
@@ -0,0 +1,33 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.ApiSpec.Schemas.AppCreateRequest do
+ alias OpenApiSpex.Schema
+ require OpenApiSpex
+
+ OpenApiSpex.schema(%{
+ title: "AppCreateRequest",
+ description: "POST body for creating an app",
+ type: :object,
+ properties: %{
+ client_name: %Schema{type: :string, description: "A name for your application."},
+ redirect_uris: %Schema{
+ type: :string,
+ description:
+ "Where the user should be redirected after authorization. To display the authorization code to the user instead of redirecting to a web page, use `urn:ietf:wg:oauth:2.0:oob` in this parameter."
+ },
+ scopes: %Schema{
+ type: :string,
+ description: "Space separated list of scopes. If none is provided, defaults to `read`."
+ },
+ website: %Schema{type: :string, description: "A URL to the homepage of your app"}
+ },
+ required: [:client_name, :redirect_uris],
+ example: %{
+ "client_name" => "My App",
+ "redirect_uris" => "https://myapp.com/auth/callback",
+ "website" => "https://myapp.com/"
+ }
+ })
+end
diff --git a/lib/pleroma/web/api_spec/schemas/app_create_response.ex b/lib/pleroma/web/api_spec/schemas/app_create_response.ex
new file mode 100644
index 000000000..f290fb031
--- /dev/null
+++ b/lib/pleroma/web/api_spec/schemas/app_create_response.ex
@@ -0,0 +1,33 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.ApiSpec.Schemas.AppCreateResponse do
+ alias OpenApiSpex.Schema
+
+ require OpenApiSpex
+
+ OpenApiSpex.schema(%{
+ title: "AppCreateResponse",
+ description: "Response schema for an app",
+ type: :object,
+ properties: %{
+ id: %Schema{type: :string},
+ name: %Schema{type: :string},
+ client_id: %Schema{type: :string},
+ client_secret: %Schema{type: :string},
+ redirect_uri: %Schema{type: :string},
+ vapid_key: %Schema{type: :string},
+ website: %Schema{type: :string, nullable: true}
+ },
+ example: %{
+ "id" => "123",
+ "name" => "My App",
+ "client_id" => "TWhM-tNSuncnqN7DBJmoyeLnk6K3iJJ71KKXxgL1hPM",
+ "client_secret" => "ZEaFUFmF0umgBX1qKJDjaU99Q31lDkOU8NutzTOoliw",
+ "vapid_key" =>
+ "BCk-QqERU0q-CfYZjcuB6lnyyOYfJ2AifKqfeGIm7Z-HiTU5T9eTG5GxVA0_OH5mMlI4UkkDTpaZwozy0TzdZ2M=",
+ "website" => "https://myapp.com/"
+ }
+ })
+end
diff --git a/lib/pleroma/web/api_spec/schemas/custom_emoji.ex b/lib/pleroma/web/api_spec/schemas/custom_emoji.ex
new file mode 100644
index 000000000..5531b2081
--- /dev/null
+++ b/lib/pleroma/web/api_spec/schemas/custom_emoji.ex
@@ -0,0 +1,30 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.ApiSpec.Schemas.CustomEmoji do
+ alias OpenApiSpex.Schema
+
+ require OpenApiSpex
+
+ OpenApiSpex.schema(%{
+ title: "CustomEmoji",
+ description: "Response schema for an CustomEmoji",
+ type: :object,
+ properties: %{
+ shortcode: %Schema{type: :string},
+ url: %Schema{type: :string},
+ static_url: %Schema{type: :string},
+ visible_in_picker: %Schema{type: :boolean},
+ category: %Schema{type: :string},
+ tags: %Schema{type: :array}
+ },
+ example: %{
+ "shortcode" => "aaaa",
+ "url" => "https://files.mastodon.social/custom_emojis/images/000/007/118/original/aaaa.png",
+ "static_url" =>
+ "https://files.mastodon.social/custom_emojis/images/000/007/118/static/aaaa.png",
+ "visible_in_picker" => true
+ }
+ })
+end
diff --git a/lib/pleroma/web/api_spec/schemas/custom_emojis_response.ex b/lib/pleroma/web/api_spec/schemas/custom_emojis_response.ex
new file mode 100644
index 000000000..01582a63d
--- /dev/null
+++ b/lib/pleroma/web/api_spec/schemas/custom_emojis_response.ex
@@ -0,0 +1,42 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.ApiSpec.Schemas.CustomEmojisResponse do
+ alias Pleroma.Web.ApiSpec.Schemas.CustomEmoji
+
+ require OpenApiSpex
+
+ OpenApiSpex.schema(%{
+ title: "CustomEmojisResponse",
+ description: "Response schema for custom emojis",
+ type: :array,
+ items: CustomEmoji,
+ example: [
+ %{
+ "category" => "Fun",
+ "shortcode" => "blank",
+ "static_url" => "https://lain.com/emoji/blank.png",
+ "tags" => ["Fun"],
+ "url" => "https://lain.com/emoji/blank.png",
+ "visible_in_picker" => true
+ },
+ %{
+ "category" => "Gif,Fun",
+ "shortcode" => "firefox",
+ "static_url" => "https://lain.com/emoji/Firefox.gif",
+ "tags" => ["Gif", "Fun"],
+ "url" => "https://lain.com/emoji/Firefox.gif",
+ "visible_in_picker" => true
+ },
+ %{
+ "category" => "pack:mixed",
+ "shortcode" => "sadcat",
+ "static_url" => "https://lain.com/emoji/mixed/sadcat.png",
+ "tags" => ["pack:mixed"],
+ "url" => "https://lain.com/emoji/mixed/sadcat.png",
+ "visible_in_picker" => true
+ }
+ ]
+ })
+end
diff --git a/lib/pleroma/web/api_spec/schemas/domain_block_request.ex b/lib/pleroma/web/api_spec/schemas/domain_block_request.ex
new file mode 100644
index 000000000..ee9238361
--- /dev/null
+++ b/lib/pleroma/web/api_spec/schemas/domain_block_request.ex
@@ -0,0 +1,20 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.ApiSpec.Schemas.DomainBlockRequest do
+ alias OpenApiSpex.Schema
+ require OpenApiSpex
+
+ OpenApiSpex.schema(%{
+ title: "DomainBlockRequest",
+ type: :object,
+ properties: %{
+ domain: %Schema{type: :string}
+ },
+ required: [:domain],
+ example: %{
+ "domain" => "facebook.com"
+ }
+ })
+end
diff --git a/lib/pleroma/web/api_spec/schemas/domain_blocks_response.ex b/lib/pleroma/web/api_spec/schemas/domain_blocks_response.ex
new file mode 100644
index 000000000..d895aca4e
--- /dev/null
+++ b/lib/pleroma/web/api_spec/schemas/domain_blocks_response.ex
@@ -0,0 +1,16 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.ApiSpec.Schemas.DomainBlocksResponse do
+ require OpenApiSpex
+ alias OpenApiSpex.Schema
+
+ OpenApiSpex.schema(%{
+ title: "DomainBlocksResponse",
+ description: "Response schema for domain blocks",
+ type: :array,
+ items: %Schema{type: :string},
+ example: ["google.com", "facebook.com"]
+ })
+end
diff --git a/lib/pleroma/web/auth/authenticator.ex b/lib/pleroma/web/auth/authenticator.ex
index dd49987f7..b4db312fb 100644
--- a/lib/pleroma/web/auth/authenticator.ex
+++ b/lib/pleroma/web/auth/authenticator.ex
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.Auth.Authenticator do
diff --git a/lib/pleroma/web/auth/ldap_authenticator.ex b/lib/pleroma/web/auth/ldap_authenticator.ex
index 177c05636..f63a66c03 100644
--- a/lib/pleroma/web/auth/ldap_authenticator.ex
+++ b/lib/pleroma/web/auth/ldap_authenticator.ex
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.Auth.LDAPAuthenticator do
diff --git a/lib/pleroma/web/auth/pleroma_authenticator.ex b/lib/pleroma/web/auth/pleroma_authenticator.ex
index f4234b743..cb09664ce 100644
--- a/lib/pleroma/web/auth/pleroma_authenticator.ex
+++ b/lib/pleroma/web/auth/pleroma_authenticator.ex
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.Auth.PleromaAuthenticator do
diff --git a/lib/pleroma/web/channels/user_socket.ex b/lib/pleroma/web/channels/user_socket.ex
index 8e2759e3b..306ef1916 100644
--- a/lib/pleroma/web/channels/user_socket.ex
+++ b/lib/pleroma/web/channels/user_socket.ex
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.UserSocket do
diff --git a/lib/pleroma/web/chat_channel.ex b/lib/pleroma/web/chat_channel.ex
index 840414933..38ec774f7 100644
--- a/lib/pleroma/web/chat_channel.ex
+++ b/lib/pleroma/web/chat_channel.ex
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.ChatChannel do
diff --git a/lib/pleroma/web/common_api/activity_draft.ex b/lib/pleroma/web/common_api/activity_draft.ex
index f7da81b34..c1cd15bb2 100644
--- a/lib/pleroma/web/common_api/activity_draft.ex
+++ b/lib/pleroma/web/common_api/activity_draft.ex
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.CommonAPI.ActivityDraft do
@@ -187,7 +187,7 @@ defmodule Pleroma.Web.CommonAPI.ActivityDraft do
end
defp preview?(draft) do
- preview? = Pleroma.Web.ControllerHelper.truthy_param?(draft.params["preview"]) || false
+ preview? = Pleroma.Web.ControllerHelper.truthy_param?(draft.params["preview"])
%__MODULE__{draft | preview?: preview?}
end
diff --git a/lib/pleroma/web/common_api/common_api.ex b/lib/pleroma/web/common_api/common_api.ex
index 027b3dc30..f50a909aa 100644
--- a/lib/pleroma/web/common_api/common_api.ex
+++ b/lib/pleroma/web/common_api/common_api.ex
@@ -12,6 +12,8 @@ defmodule Pleroma.Web.CommonAPI do
alias Pleroma.User
alias Pleroma.UserRelationship
alias Pleroma.Web.ActivityPub.ActivityPub
+ alias Pleroma.Web.ActivityPub.Builder
+ alias Pleroma.Web.ActivityPub.Pipeline
alias Pleroma.Web.ActivityPub.Utils
alias Pleroma.Web.ActivityPub.Visibility
@@ -19,6 +21,7 @@ defmodule Pleroma.Web.CommonAPI do
import Pleroma.Web.CommonAPI.Utils
require Pleroma.Constants
+ require Logger
def follow(follower, followed) do
timeout = Pleroma.Config.get([:activitypub, :follow_handshake_timeout])
@@ -42,7 +45,7 @@ defmodule Pleroma.Web.CommonAPI do
with {:ok, follower} <- User.follow(follower, followed),
%Activity{} = follow_activity <- Utils.fetch_latest_follow(follower, followed),
{:ok, follow_activity} <- Utils.update_follow_state_for_all(follow_activity, "accept"),
- {:ok, _relationship} <- FollowingRelationship.update(follower, followed, "accept"),
+ {:ok, _relationship} <- FollowingRelationship.update(follower, followed, :follow_accept),
{:ok, _activity} <-
ActivityPub.accept(%{
to: [follower.ap_id],
@@ -57,7 +60,7 @@ defmodule Pleroma.Web.CommonAPI do
def reject_follow_request(follower, followed) do
with %Activity{} = follow_activity <- Utils.fetch_latest_follow(follower, followed),
{:ok, follow_activity} <- Utils.update_follow_state_for_all(follow_activity, "reject"),
- {:ok, _relationship} <- FollowingRelationship.update(follower, followed, "reject"),
+ {:ok, _relationship} <- FollowingRelationship.update(follower, followed, :follow_reject),
{:ok, _activity} <-
ActivityPub.reject(%{
to: [follower.ap_id],
@@ -70,20 +73,21 @@ defmodule Pleroma.Web.CommonAPI do
end
def delete(activity_id, user) do
- with %Activity{data: %{"object" => _}} = activity <-
- Activity.get_by_id_with_object(activity_id),
+ with {_, %Activity{data: %{"object" => _}} = activity} <-
+ {:find_activity, Activity.get_by_id_with_object(activity_id)},
%Object{} = object <- Object.normalize(activity),
true <- User.superuser?(user) || user.ap_id == object.data["actor"],
{:ok, _} <- unpin(activity_id, user),
{:ok, delete} <- ActivityPub.delete(object) do
{:ok, delete}
else
+ {:find_activity, _} -> {:error, :not_found}
_ -> {:error, dgettext("errors", "Could not delete")}
end
end
def repeat(id_or_ap_id, user, params \\ %{}) do
- with %Activity{} = activity <- get_by_id_or_ap_id(id_or_ap_id),
+ with {_, %Activity{} = activity} <- {:find_activity, get_by_id_or_ap_id(id_or_ap_id)},
object <- Object.normalize(activity),
announce_activity <- Utils.get_existing_announce(user.ap_id, object),
public <- public_announce?(object, params) do
@@ -93,38 +97,75 @@ defmodule Pleroma.Web.CommonAPI do
ActivityPub.announce(user, object, nil, true, public)
end
else
+ {:find_activity, _} -> {:error, :not_found}
_ -> {:error, dgettext("errors", "Could not repeat")}
end
end
def unrepeat(id_or_ap_id, user) do
- with %Activity{} = activity <- get_by_id_or_ap_id(id_or_ap_id) do
+ with {_, %Activity{} = activity} <- {:find_activity, get_by_id_or_ap_id(id_or_ap_id)} do
object = Object.normalize(activity)
ActivityPub.unannounce(user, object)
else
+ {:find_activity, _} -> {:error, :not_found}
_ -> {:error, dgettext("errors", "Could not unrepeat")}
end
end
- def favorite(id_or_ap_id, user) do
- with %Activity{} = activity <- get_by_id_or_ap_id(id_or_ap_id),
- object <- Object.normalize(activity),
- like_activity <- Utils.get_existing_like(user.ap_id, object) do
- if like_activity do
- {:ok, like_activity, object}
- else
- ActivityPub.like(user, object)
- end
+ @spec favorite(User.t(), binary()) :: {:ok, Activity.t() | :already_liked} | {:error, any()}
+ def favorite(%User{} = user, id) do
+ case favorite_helper(user, id) do
+ {:ok, _} = res ->
+ res
+
+ {:error, :not_found} = res ->
+ res
+
+ {:error, e} ->
+ Logger.error("Could not favorite #{id}. Error: #{inspect(e, pretty: true)}")
+ {:error, dgettext("errors", "Could not favorite")}
+ end
+ end
+
+ def favorite_helper(user, id) do
+ with {_, %Activity{object: object}} <- {:find_object, Activity.get_by_id_with_object(id)},
+ {_, {:ok, like_object, meta}} <- {:build_object, Builder.like(user, object)},
+ {_, {:ok, %Activity{} = activity, _meta}} <-
+ {:common_pipeline,
+ Pipeline.common_pipeline(like_object, Keyword.put(meta, :local, true))} do
+ {:ok, activity}
else
- _ -> {:error, dgettext("errors", "Could not favorite")}
+ {:find_object, _} ->
+ {:error, :not_found}
+
+ {:common_pipeline,
+ {
+ :error,
+ {
+ :validate_object,
+ {
+ :error,
+ changeset
+ }
+ }
+ }} = e ->
+ if {:object, {"already liked by this actor", []}} in changeset.errors do
+ {:ok, :already_liked}
+ else
+ {:error, e}
+ end
+
+ e ->
+ {:error, e}
end
end
def unfavorite(id_or_ap_id, user) do
- with %Activity{} = activity <- get_by_id_or_ap_id(id_or_ap_id) do
+ with {_, %Activity{} = activity} <- {:find_activity, get_by_id_or_ap_id(id_or_ap_id)} do
object = Object.normalize(activity)
ActivityPub.unlike(user, object)
else
+ {:find_activity, _} -> {:error, :not_found}
_ -> {:error, dgettext("errors", "Could not unfavorite")}
end
end
@@ -291,26 +332,6 @@ defmodule Pleroma.Web.CommonAPI do
defp maybe_create_activity_expiration(result, _), do: result
- # Updates the emojis for a user based on their profile
- def update(user) do
- emoji = emoji_from_profile(user)
- source_data = Map.put(user.source_data, "tag", emoji)
-
- user =
- case User.update_source_data(user, source_data) do
- {:ok, user} -> user
- _ -> user
- end
-
- ActivityPub.update(%{
- local: true,
- to: [Pleroma.Constants.as_public(), user.follower_address],
- cc: [],
- actor: user.ap_id,
- object: Pleroma.Web.ActivityPub.UserView.render("user.json", %{user: user})
- })
- end
-
def pin(id_or_ap_id, %{ap_id: user_ap_id} = user) do
with %Activity{
actor: ^user_ap_id,
@@ -353,7 +374,7 @@ defmodule Pleroma.Web.CommonAPI do
def thread_muted?(%{id: nil} = _user, _activity), do: false
def thread_muted?(user, activity) do
- ThreadMute.check_muted(user.id, activity.data["context"]) != []
+ ThreadMute.exists?(user.id, activity.data["context"])
end
def report(user, %{"account_id" => account_id} = data) do
diff --git a/lib/pleroma/web/common_api/utils.ex b/lib/pleroma/web/common_api/utils.ex
index 8746273c4..7eec5aa09 100644
--- a/lib/pleroma/web/common_api/utils.ex
+++ b/lib/pleroma/web/common_api/utils.ex
@@ -10,7 +10,6 @@ defmodule Pleroma.Web.CommonAPI.Utils do
alias Pleroma.Activity
alias Pleroma.Config
alias Pleroma.Conversation.Participation
- alias Pleroma.Emoji
alias Pleroma.Formatter
alias Pleroma.Object
alias Pleroma.Plugs.AuthenticationPlug
@@ -18,7 +17,6 @@ defmodule Pleroma.Web.CommonAPI.Utils do
alias Pleroma.User
alias Pleroma.Web.ActivityPub.Utils
alias Pleroma.Web.ActivityPub.Visibility
- alias Pleroma.Web.Endpoint
alias Pleroma.Web.MediaProxy
require Logger
@@ -175,7 +173,7 @@ defmodule Pleroma.Web.CommonAPI.Utils do
"replies" => %{"type" => "Collection", "totalItems" => 0}
}
- {note, Map.merge(emoji, Emoji.Formatter.get_emoji_map(option))}
+ {note, Map.merge(emoji, Pleroma.Emoji.Formatter.get_emoji_map(option))}
end)
end_time =
@@ -331,7 +329,7 @@ defmodule Pleroma.Web.CommonAPI.Utils do
def format_input(text, "text/markdown", options) do
text
|> Formatter.mentions_escape(options)
- |> Earmark.as_html!()
+ |> Earmark.as_html!(%Earmark.Options{renderer: Pleroma.EarmarkRenderer})
|> Formatter.linkify(options)
|> Formatter.html_escape("text/html")
end
@@ -431,19 +429,6 @@ defmodule Pleroma.Web.CommonAPI.Utils do
end
end
- def emoji_from_profile(%User{bio: bio, name: name}) do
- [bio, name]
- |> Enum.map(&Emoji.Formatter.get_emoji/1)
- |> Enum.concat()
- |> Enum.map(fn {shortcode, %Emoji{file: path}} ->
- %{
- "type" => "Emoji",
- "icon" => %{"type" => "Image", "url" => "#{Endpoint.url()}#{path}"},
- "name" => ":#{shortcode}:"
- }
- end)
- end
-
def maybe_notify_to_recipients(
recipients,
%Activity{data: %{"to" => to, "type" => _type}} = _activity
@@ -591,7 +576,7 @@ defmodule Pleroma.Web.CommonAPI.Utils do
limit = Pleroma.Config.get([:instance, :limit])
length = String.length(full_payload)
- if length < limit do
+ if length <= limit do
:ok
else
{:error, dgettext("errors", "The status is over the character limit")}
diff --git a/lib/pleroma/web/controller_helper.ex b/lib/pleroma/web/controller_helper.ex
index c9a3a2585..4780081b2 100644
--- a/lib/pleroma/web/controller_helper.ex
+++ b/lib/pleroma/web/controller_helper.ex
@@ -5,10 +5,18 @@
defmodule Pleroma.Web.ControllerHelper do
use Pleroma.Web, :controller
- # As in MastoAPI, per https://api.rubyonrails.org/classes/ActiveModel/Type/Boolean.html
+ alias Pleroma.Config
+
+ # As in Mastodon API, per https://api.rubyonrails.org/classes/ActiveModel/Type/Boolean.html
@falsy_param_values [false, 0, "0", "f", "F", "false", "False", "FALSE", "off", "OFF"]
- def truthy_param?(blank_value) when blank_value in [nil, ""], do: nil
- def truthy_param?(value), do: value not in @falsy_param_values
+
+ def explicitly_falsy_param?(value), do: value in @falsy_param_values
+
+ # Note: `nil` and `""` are considered falsy values in Pleroma
+ def falsy_param?(value),
+ do: explicitly_falsy_param?(value) or value in [nil, ""]
+
+ def truthy_param?(value), do: not falsy_param?(value)
def json_response(conn, status, json) do
conn
@@ -34,7 +42,12 @@ defmodule Pleroma.Web.ControllerHelper do
defp param_to_integer(_, default), do: default
- def add_link_headers(conn, activities, extra_params \\ %{}) do
+ def add_link_headers(conn, activities, extra_params \\ %{})
+
+ def add_link_headers(%{assigns: %{skip_link_headers: true}} = conn, _activities, _extra_params),
+ do: conn
+
+ def add_link_headers(conn, activities, extra_params) do
case List.last(activities) do
%{id: max_id} ->
params =
@@ -87,7 +100,18 @@ defmodule Pleroma.Web.ControllerHelper do
render_error(conn, :not_implemented, "Can't display this activity")
end
- @spec put_in_if_exist(map(), atom() | String.t(), any) :: map()
- def put_in_if_exist(map, _key, nil), do: map
- def put_in_if_exist(map, key, value), do: put_in(map, key, value)
+ @spec put_if_exist(map(), atom() | String.t(), any) :: map()
+ def put_if_exist(map, _key, nil), do: map
+
+ def put_if_exist(map, key, value), do: Map.put(map, key, value)
+
+ @doc "Whether to skip rendering `[:account][:pleroma][:relationship]`for statuses/notifications"
+ def skip_relationships?(params) do
+ if Config.get([:extensions, :output_relationships_in_statuses_by_default]) do
+ false
+ else
+ # BREAKING: older PleromaFE versions do not send this param but _do_ expect relationships.
+ not truthy_param?(params["with_relationships"])
+ end
+ end
end
diff --git a/lib/pleroma/web/endpoint.ex b/lib/pleroma/web/endpoint.ex
index 118c3ac6f..72cb3ee27 100644
--- a/lib/pleroma/web/endpoint.ex
+++ b/lib/pleroma/web/endpoint.ex
@@ -12,7 +12,7 @@ defmodule Pleroma.Web.Endpoint do
plug(Pleroma.Plugs.HTTPSecurityPlug)
plug(Pleroma.Plugs.UploadedMedia)
- @static_cache_control "public max-age=86400 must-revalidate"
+ @static_cache_control "public, no-cache"
# InstanceStatic needs to be before Plug.Static to be able to override shipped-static files
# If you're adding new paths to `only:` you'll need to configure them in InstanceStatic as well
diff --git a/lib/pleroma/web/fallback_redirect_controller.ex b/lib/pleroma/web/fallback_redirect_controller.ex
index 5fbf3695f..c13518030 100644
--- a/lib/pleroma/web/fallback_redirect_controller.ex
+++ b/lib/pleroma/web/fallback_redirect_controller.ex
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Fallback.RedirectController do
diff --git a/lib/pleroma/web/federator/publisher.ex b/lib/pleroma/web/federator/publisher.ex
index 1d045c644..ad0201361 100644
--- a/lib/pleroma/web/federator/publisher.ex
+++ b/lib/pleroma/web/federator/publisher.ex
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.Federator.Publisher do
diff --git a/lib/pleroma/web/feed/feed_view.ex b/lib/pleroma/web/feed/feed_view.ex
index e18adaea8..1ae03e7e2 100644
--- a/lib/pleroma/web/feed/feed_view.ex
+++ b/lib/pleroma/web/feed/feed_view.ex
@@ -23,7 +23,7 @@ defmodule Pleroma.Web.Feed.FeedView do
def pub_date(%DateTime{} = date), do: Timex.format!(date, "{RFC822}")
def prepare_activity(activity, opts \\ []) do
- object = activity_object(activity)
+ object = Object.normalize(activity)
actor =
if opts[:actor] do
@@ -33,7 +33,6 @@ defmodule Pleroma.Web.Feed.FeedView do
%{
activity: activity,
data: Map.get(object, :data),
- object: object,
actor: actor
}
end
@@ -68,9 +67,7 @@ defmodule Pleroma.Web.Feed.FeedView do
def last_activity(activities), do: List.last(activities)
- def activity_object(activity), do: Object.normalize(activity)
-
- def activity_title(%{data: %{"content" => content}}, opts \\ %{}) do
+ def activity_title(%{"content" => content}, opts \\ %{}) do
content
|> Pleroma.Web.Metadata.Utils.scrub_html()
|> Pleroma.Emoji.Formatter.demojify()
@@ -78,7 +75,7 @@ defmodule Pleroma.Web.Feed.FeedView do
|> escape()
end
- def activity_content(%{data: %{"content" => content}}) do
+ def activity_content(%{"content" => content}) do
content
|> String.replace(~r/[\n\r]/, "")
|> escape()
diff --git a/lib/pleroma/web/feed/tag_controller.ex b/lib/pleroma/web/feed/tag_controller.ex
index 75c9ea17e..8133f8480 100644
--- a/lib/pleroma/web/feed/tag_controller.ex
+++ b/lib/pleroma/web/feed/tag_controller.ex
@@ -9,18 +9,18 @@ defmodule Pleroma.Web.Feed.TagController do
alias Pleroma.Web.ActivityPub.ActivityPub
alias Pleroma.Web.Feed.FeedView
- import Pleroma.Web.ControllerHelper, only: [put_in_if_exist: 3]
+ import Pleroma.Web.ControllerHelper, only: [put_if_exist: 3]
def feed(conn, %{"tag" => raw_tag} = params) do
{format, tag} = parse_tag(raw_tag)
activities =
%{"type" => ["Create"], "tag" => tag}
- |> put_in_if_exist("max_id", params["max_id"])
+ |> put_if_exist("max_id", params["max_id"])
|> ActivityPub.fetch_public_activities()
conn
- |> put_resp_content_type("application/atom+xml")
+ |> put_resp_content_type("application/#{format}+xml")
|> put_view(FeedView)
|> render("tag.#{format}",
activities: activities,
diff --git a/lib/pleroma/web/feed/user_controller.ex b/lib/pleroma/web/feed/user_controller.ex
index 59aabb549..e27f85929 100644
--- a/lib/pleroma/web/feed/user_controller.ex
+++ b/lib/pleroma/web/feed/user_controller.ex
@@ -11,7 +11,7 @@ defmodule Pleroma.Web.Feed.UserController do
alias Pleroma.Web.ActivityPub.ActivityPubController
alias Pleroma.Web.Feed.FeedView
- import Pleroma.Web.ControllerHelper, only: [put_in_if_exist: 3]
+ import Pleroma.Web.ControllerHelper, only: [put_if_exist: 3]
plug(Pleroma.Plugs.SetFormatPlug when action in [:feed_redirect])
@@ -25,7 +25,12 @@ defmodule Pleroma.Web.Feed.UserController do
def feed_redirect(%{assigns: %{format: format}} = conn, _params)
when format in ["json", "activity+json"] do
- ActivityPubController.call(conn, :user)
+ with %{halted: false} = conn <-
+ Pleroma.Plugs.EnsureAuthenticatedPlug.call(conn,
+ unless_func: &Pleroma.Web.FederatingPlug.federating?/0
+ ) do
+ ActivityPubController.call(conn, :user)
+ end
end
def feed_redirect(conn, %{"nickname" => nickname}) do
@@ -35,19 +40,28 @@ defmodule Pleroma.Web.Feed.UserController do
end
def feed(conn, %{"nickname" => nickname} = params) do
+ format = get_format(conn)
+
+ format =
+ if format in ["rss", "atom"] do
+ format
+ else
+ "atom"
+ end
+
with {_, %User{} = user} <- {:fetch_user, User.get_cached_by_nickname(nickname)} do
activities =
%{
"type" => ["Create"],
"actor_id" => user.ap_id
}
- |> put_in_if_exist("max_id", params["max_id"])
+ |> put_if_exist("max_id", params["max_id"])
|> ActivityPub.fetch_public_activities()
conn
- |> put_resp_content_type("application/atom+xml")
+ |> put_resp_content_type("application/#{format}+xml")
|> put_view(FeedView)
- |> render("user.xml",
+ |> render("user.#{format}",
user: user,
activities: activities,
feed_config: Pleroma.Config.get([:feed])
diff --git a/lib/pleroma/web/gettext.ex b/lib/pleroma/web/gettext.ex
index 1328b46cc..0adf428ec 100644
--- a/lib/pleroma/web/gettext.ex
+++ b/lib/pleroma/web/gettext.ex
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.Gettext do
diff --git a/lib/pleroma/web/masto_fe_controller.ex b/lib/pleroma/web/masto_fe_controller.ex
index 43649ad26..557cde328 100644
--- a/lib/pleroma/web/masto_fe_controller.ex
+++ b/lib/pleroma/web/masto_fe_controller.ex
@@ -17,7 +17,7 @@ defmodule Pleroma.Web.MastoFEController do
when action == :index
)
- plug(Pleroma.Plugs.EnsurePublicOrAuthenticatedPlug when action != :index)
+ plug(Pleroma.Plugs.EnsurePublicOrAuthenticatedPlug when action not in [:index, :manifest])
@doc "GET /web/*path"
def index(%{assigns: %{user: user, token: token}} = conn, _params)
diff --git a/lib/pleroma/web/mastodon_api/controllers/account_controller.ex b/lib/pleroma/web/mastodon_api/controllers/account_controller.ex
index 38d14256f..e8e59ac66 100644
--- a/lib/pleroma/web/mastodon_api/controllers/account_controller.ex
+++ b/lib/pleroma/web/mastodon_api/controllers/account_controller.ex
@@ -1,14 +1,19 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.MastodonAPI.AccountController do
use Pleroma.Web, :controller
import Pleroma.Web.ControllerHelper,
- only: [add_link_headers: 2, truthy_param?: 1, assign_account_by_id: 2, json_response: 3]
+ only: [
+ add_link_headers: 2,
+ truthy_param?: 1,
+ assign_account_by_id: 2,
+ json_response: 3,
+ skip_relationships?: 1
+ ]
- alias Pleroma.Emoji
alias Pleroma.Plugs.OAuthScopesPlug
alias Pleroma.Plugs.RateLimiter
alias Pleroma.User
@@ -16,10 +21,13 @@ defmodule Pleroma.Web.MastodonAPI.AccountController do
alias Pleroma.Web.CommonAPI
alias Pleroma.Web.MastodonAPI.ListView
alias Pleroma.Web.MastodonAPI.MastodonAPI
+ alias Pleroma.Web.MastodonAPI.MastodonAPIController
alias Pleroma.Web.MastodonAPI.StatusView
alias Pleroma.Web.OAuth.Token
alias Pleroma.Web.TwitterAPI.TwitterAPI
+ plug(:skip_plug, OAuthScopesPlug when action == :identity_proofs)
+
plug(
OAuthScopesPlug,
%{fallback: :proceed_unauthenticated, scopes: ["read:accounts"]}
@@ -60,14 +68,18 @@ defmodule Pleroma.Web.MastodonAPI.AccountController do
plug(
Pleroma.Plugs.EnsurePublicOrAuthenticatedPlug
- when action != :create
+ when action not in [:create, :show, :statuses]
)
- @relations [:follow, :unfollow]
+ @relationship_actions [:follow, :unfollow]
@needs_account ~W(followers following lists follow unfollow mute unmute block unblock)a
- plug(RateLimiter, [name: :relations_id_action, params: ["id", "uri"]] when action in @relations)
- plug(RateLimiter, [name: :relations_actions] when action in @relations)
+ plug(
+ RateLimiter,
+ [name: :relation_id_action, params: ["id", "uri"]] when action in @relationship_actions
+ )
+
+ plug(RateLimiter, [name: :relations_actions] when action in @relationship_actions)
plug(RateLimiter, [name: :app_account_creation] when action == :create)
plug(:assign_account_by_id when action in @needs_account)
@@ -76,7 +88,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountController do
@doc "POST /api/v1/accounts"
def create(
%{assigns: %{app: app}} = conn,
- %{"username" => nickname, "email" => _, "password" => _, "agreement" => true} = params
+ %{"username" => nickname, "password" => _, "agreement" => true} = params
) do
params =
params
@@ -92,8 +104,10 @@ defmodule Pleroma.Web.MastodonAPI.AccountController do
|> Map.put("fullname", params["fullname"] || nickname)
|> Map.put("bio", params["bio"] || "")
|> Map.put("confirm", params["password"])
+ |> Map.put("trusted_app", app.trusted)
- with {:ok, user} <- TwitterAPI.register_user(params, need_confirmation: true),
+ with :ok <- validate_email_param(params),
+ {:ok, user} <- TwitterAPI.register_user(params, need_confirmation: true),
{:ok, token} <- Token.create_token(app, user, %{scopes: app.scopes}) do
json(conn, %{
token_type: "Bearer",
@@ -114,6 +128,15 @@ defmodule Pleroma.Web.MastodonAPI.AccountController do
render_error(conn, :forbidden, "Invalid credentials")
end
+ defp validate_email_param(%{"email" => _}), do: :ok
+
+ defp validate_email_param(_) do
+ case Pleroma.Config.get([:instance, :account_activation_required]) do
+ true -> {:error, %{"error" => "Missing parameters"}}
+ _ -> :ok
+ end
+ end
+
@doc "GET /api/v1/accounts/verify_credentials"
def verify_credentials(%{assigns: %{user: user}} = conn, _) do
chat_token = Phoenix.Token.sign(conn, "user socket", user.id)
@@ -127,20 +150,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountController do
end
@doc "PATCH /api/v1/accounts/update_credentials"
- def update_credentials(%{assigns: %{user: original_user}} = conn, params) do
- user = original_user
-
- params =
- if Map.has_key?(params, "fields_attributes") do
- Map.update!(params, "fields_attributes", fn fields ->
- fields
- |> normalize_fields_attributes()
- |> Enum.filter(fn %{"name" => n} -> n != "" end)
- end)
- else
- params
- end
-
+ def update_credentials(%{assigns: %{user: user}} = conn, params) do
user_params =
[
:no_rich_text,
@@ -159,51 +169,23 @@ defmodule Pleroma.Web.MastodonAPI.AccountController do
add_if_present(acc, params, to_string(key), key, &{:ok, truthy_param?(&1)})
end)
|> add_if_present(params, "display_name", :name)
- |> add_if_present(params, "note", :bio, fn value -> {:ok, User.parse_bio(value, user)} end)
- |> add_if_present(params, "avatar", :avatar, fn value ->
- with %Plug.Upload{} <- value,
- {:ok, object} <- ActivityPub.upload(value, type: :avatar) do
- {:ok, object.data}
- end
- end)
- |> add_if_present(params, "header", :banner, fn value ->
- with %Plug.Upload{} <- value,
- {:ok, object} <- ActivityPub.upload(value, type: :banner) do
- {:ok, object.data}
- end
- end)
- |> add_if_present(params, "pleroma_background_image", :background, fn value ->
- with %Plug.Upload{} <- value,
- {:ok, object} <- ActivityPub.upload(value, type: :background) do
- {:ok, object.data}
- end
- end)
- |> add_if_present(params, "fields_attributes", :fields, fn fields ->
- fields = Enum.map(fields, fn f -> Map.update!(f, "value", &AutoLinker.link(&1)) end)
-
- {:ok, fields}
- end)
- |> add_if_present(params, "fields_attributes", :raw_fields)
- |> add_if_present(params, "pleroma_settings_store", :pleroma_settings_store, fn value ->
- {:ok, Map.merge(user.pleroma_settings_store, value)}
- end)
+ |> add_if_present(params, "note", :bio)
+ |> add_if_present(params, "avatar", :avatar)
+ |> add_if_present(params, "header", :banner)
+ |> add_if_present(params, "pleroma_background_image", :background)
+ |> add_if_present(
+ params,
+ "fields_attributes",
+ :raw_fields,
+ &{:ok, normalize_fields_attributes(&1)}
+ )
+ |> add_if_present(params, "pleroma_settings_store", :pleroma_settings_store)
|> add_if_present(params, "default_scope", :default_scope)
|> add_if_present(params, "actor_type", :actor_type)
- emojis_text = (user_params["display_name"] || "") <> (user_params["note"] || "")
-
- user_emojis =
- user
- |> Map.get(:emoji, [])
- |> Enum.concat(Emoji.Formatter.get_emoji_map(emojis_text))
- |> Enum.dedup()
-
- user_params = Map.put(user_params, :emoji, user_emojis)
changeset = User.update_changeset(user, user_params)
with {:ok, user} <- User.update_and_set_cache(changeset) do
- if original_user != user, do: CommonAPI.update(user)
-
render(conn, "show.json", user: user, for: user, with_pleroma_settings: true)
else
_e -> render_error(conn, :forbidden, "Invalid request")
@@ -249,7 +231,8 @@ defmodule Pleroma.Web.MastodonAPI.AccountController do
@doc "GET /api/v1/accounts/:id/statuses"
def statuses(%{assigns: %{user: reading_user}} = conn, params) do
- with %User{} = user <- User.get_cached_by_nickname_or_id(params["id"], for: reading_user) do
+ with %User{} = user <- User.get_cached_by_nickname_or_id(params["id"], for: reading_user),
+ true <- User.visible_for?(user, reading_user) do
params =
params
|> Map.put("tag", params["tagged"])
@@ -260,7 +243,14 @@ defmodule Pleroma.Web.MastodonAPI.AccountController do
conn
|> add_link_headers(activities)
|> put_view(StatusView)
- |> render("index.json", activities: activities, for: reading_user, as: :activity)
+ |> render("index.json",
+ activities: activities,
+ for: reading_user,
+ as: :activity,
+ skip_relationships: skip_relationships?(params)
+ )
+ else
+ _e -> render_error(conn, :not_found, "Can't find user")
end
end
@@ -390,6 +380,8 @@ defmodule Pleroma.Web.MastodonAPI.AccountController do
end
@doc "GET /api/v1/endorsements"
- def endorsements(conn, params),
- do: Pleroma.Web.MastodonAPI.MastodonAPIController.empty_array(conn, params)
+ def endorsements(conn, params), do: MastodonAPIController.empty_array(conn, params)
+
+ @doc "GET /api/v1/identity_proofs"
+ def identity_proofs(conn, params), do: MastodonAPIController.empty_array(conn, params)
end
diff --git a/lib/pleroma/web/mastodon_api/controllers/app_controller.ex b/lib/pleroma/web/mastodon_api/controllers/app_controller.ex
index 13a30a34d..005c60444 100644
--- a/lib/pleroma/web/mastodon_api/controllers/app_controller.ex
+++ b/lib/pleroma/web/mastodon_api/controllers/app_controller.ex
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.MastodonAPI.AppController do
@@ -14,17 +14,20 @@ defmodule Pleroma.Web.MastodonAPI.AppController do
action_fallback(Pleroma.Web.MastodonAPI.FallbackController)
plug(OAuthScopesPlug, %{scopes: ["read"]} when action == :verify_credentials)
+ plug(OpenApiSpex.Plug.CastAndValidate)
@local_mastodon_name "Mastodon-Local"
+ defdelegate open_api_operation(action), to: Pleroma.Web.ApiSpec.AppOperation
+
@doc "POST /api/v1/apps"
- def create(conn, params) do
+ def create(%{body_params: params} = conn, _params) do
scopes = Scopes.fetch_scopes(params, ["read"])
app_attrs =
params
- |> Map.drop(["scope", "scopes"])
- |> Map.put("scopes", scopes)
+ |> Map.take([:client_name, :redirect_uris, :website])
+ |> Map.put(:scopes, scopes)
with cs <- App.register_changeset(%App{}, app_attrs),
false <- cs.changes[:client_name] == @local_mastodon_name,
diff --git a/lib/pleroma/web/mastodon_api/controllers/auth_controller.ex b/lib/pleroma/web/mastodon_api/controllers/auth_controller.ex
index d9e51de7f..37b389382 100644
--- a/lib/pleroma/web/mastodon_api/controllers/auth_controller.ex
+++ b/lib/pleroma/web/mastodon_api/controllers/auth_controller.ex
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.MastodonAPI.AuthController do
@@ -86,6 +86,6 @@ defmodule Pleroma.Web.MastodonAPI.AuthController do
@spec get_or_make_app() :: {:ok, App.t()} | {:error, Ecto.Changeset.t()}
defp get_or_make_app do
%{client_name: @local_mastodon_name, redirect_uris: "."}
- |> App.get_or_make(["read", "write", "follow", "push"])
+ |> App.get_or_make(["read", "write", "follow", "push", "admin"])
end
end
diff --git a/lib/pleroma/web/mastodon_api/controllers/conversation_controller.ex b/lib/pleroma/web/mastodon_api/controllers/conversation_controller.ex
index 6c0584c54..7c9b11bf1 100644
--- a/lib/pleroma/web/mastodon_api/controllers/conversation_controller.ex
+++ b/lib/pleroma/web/mastodon_api/controllers/conversation_controller.ex
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.MastodonAPI.ConversationController do
diff --git a/lib/pleroma/web/mastodon_api/controllers/custom_emoji_controller.ex b/lib/pleroma/web/mastodon_api/controllers/custom_emoji_controller.ex
index 391c0648b..3bfebef8b 100644
--- a/lib/pleroma/web/mastodon_api/controllers/custom_emoji_controller.ex
+++ b/lib/pleroma/web/mastodon_api/controllers/custom_emoji_controller.ex
@@ -1,10 +1,14 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.MastodonAPI.CustomEmojiController do
use Pleroma.Web, :controller
+ plug(OpenApiSpex.Plug.CastAndValidate)
+
+ defdelegate open_api_operation(action), to: Pleroma.Web.ApiSpec.CustomEmojiOperation
+
def index(conn, _params) do
render(conn, "index.json", custom_emojis: Pleroma.Emoji.get_all())
end
diff --git a/lib/pleroma/web/mastodon_api/controllers/domain_block_controller.ex b/lib/pleroma/web/mastodon_api/controllers/domain_block_controller.ex
index 456fe7ab2..84de79413 100644
--- a/lib/pleroma/web/mastodon_api/controllers/domain_block_controller.ex
+++ b/lib/pleroma/web/mastodon_api/controllers/domain_block_controller.ex
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.MastodonAPI.DomainBlockController do
@@ -8,6 +8,9 @@ defmodule Pleroma.Web.MastodonAPI.DomainBlockController do
alias Pleroma.Plugs.OAuthScopesPlug
alias Pleroma.User
+ plug(OpenApiSpex.Plug.CastAndValidate)
+ defdelegate open_api_operation(action), to: Pleroma.Web.ApiSpec.DomainBlockOperation
+
plug(
OAuthScopesPlug,
%{scopes: ["follow", "read:blocks"]} when action == :index
@@ -26,13 +29,13 @@ defmodule Pleroma.Web.MastodonAPI.DomainBlockController do
end
@doc "POST /api/v1/domain_blocks"
- def create(%{assigns: %{user: blocker}} = conn, %{"domain" => domain}) do
+ def create(%{assigns: %{user: blocker}, body_params: %{domain: domain}} = conn, _params) do
User.block_domain(blocker, domain)
json(conn, %{})
end
@doc "DELETE /api/v1/domain_blocks"
- def delete(%{assigns: %{user: blocker}} = conn, %{"domain" => domain}) do
+ def delete(%{assigns: %{user: blocker}, body_params: %{domain: domain}} = conn, _params) do
User.unblock_domain(blocker, domain)
json(conn, %{})
end
diff --git a/lib/pleroma/web/mastodon_api/controllers/fallback_controller.ex b/lib/pleroma/web/mastodon_api/controllers/fallback_controller.ex
index 41243d5e7..0a257f604 100644
--- a/lib/pleroma/web/mastodon_api/controllers/fallback_controller.ex
+++ b/lib/pleroma/web/mastodon_api/controllers/fallback_controller.ex
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.MastodonAPI.FallbackController do
diff --git a/lib/pleroma/web/mastodon_api/controllers/filter_controller.ex b/lib/pleroma/web/mastodon_api/controllers/filter_controller.ex
index cadef72e1..7b0b937a2 100644
--- a/lib/pleroma/web/mastodon_api/controllers/filter_controller.ex
+++ b/lib/pleroma/web/mastodon_api/controllers/filter_controller.ex
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.MastodonAPI.FilterController do
diff --git a/lib/pleroma/web/mastodon_api/controllers/follow_request_controller.ex b/lib/pleroma/web/mastodon_api/controllers/follow_request_controller.ex
index 3ccbdf1c6..1ca86f63f 100644
--- a/lib/pleroma/web/mastodon_api/controllers/follow_request_controller.ex
+++ b/lib/pleroma/web/mastodon_api/controllers/follow_request_controller.ex
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.MastodonAPI.FollowRequestController do
diff --git a/lib/pleroma/web/mastodon_api/controllers/instance_controller.ex b/lib/pleroma/web/mastodon_api/controllers/instance_controller.ex
index a55f60fec..27b5b1a52 100644
--- a/lib/pleroma/web/mastodon_api/controllers/instance_controller.ex
+++ b/lib/pleroma/web/mastodon_api/controllers/instance_controller.ex
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.MastodonAPI.InstanceController do
diff --git a/lib/pleroma/web/mastodon_api/controllers/list_controller.ex b/lib/pleroma/web/mastodon_api/controllers/list_controller.ex
index e0ffdba21..dac4daa7b 100644
--- a/lib/pleroma/web/mastodon_api/controllers/list_controller.ex
+++ b/lib/pleroma/web/mastodon_api/controllers/list_controller.ex
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.MastodonAPI.ListController do
diff --git a/lib/pleroma/web/mastodon_api/controllers/marker_controller.ex b/lib/pleroma/web/mastodon_api/controllers/marker_controller.ex
index ce025624d..58e8a30c2 100644
--- a/lib/pleroma/web/mastodon_api/controllers/marker_controller.ex
+++ b/lib/pleroma/web/mastodon_api/controllers/marker_controller.ex
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.MastodonAPI.MarkerController do
diff --git a/lib/pleroma/web/mastodon_api/controllers/mastodon_api_controller.ex b/lib/pleroma/web/mastodon_api/controllers/mastodon_api_controller.ex
index 7d839a8cf..ac8c18f24 100644
--- a/lib/pleroma/web/mastodon_api/controllers/mastodon_api_controller.ex
+++ b/lib/pleroma/web/mastodon_api/controllers/mastodon_api_controller.ex
@@ -1,23 +1,33 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
+ @moduledoc """
+ Contains stubs for unimplemented Mastodon API endpoints.
+
+ Note: instead of routing directly to this controller's action,
+ it's preferable to define an action in relevant (non-generic) controller,
+ set up OAuth rules for it and call this controller's function from it.
+ """
+
use Pleroma.Web, :controller
require Logger
+ plug(:skip_plug, Pleroma.Plugs.OAuthScopesPlug when action in [:empty_array, :empty_object])
+
+ plug(Pleroma.Plugs.EnsurePublicOrAuthenticatedPlug)
+
action_fallback(Pleroma.Web.MastodonAPI.FallbackController)
- # Stubs for unimplemented mastodon api
- #
def empty_array(conn, _) do
- Logger.debug("Unimplemented, returning an empty array")
+ Logger.debug("Unimplemented, returning an empty array (list)")
json(conn, [])
end
def empty_object(conn, _) do
- Logger.debug("Unimplemented, returning an empty object")
+ Logger.debug("Unimplemented, returning an empty object (map)")
json(conn, %{})
end
end
diff --git a/lib/pleroma/web/mastodon_api/controllers/media_controller.ex b/lib/pleroma/web/mastodon_api/controllers/media_controller.ex
index ed4c08d99..2b6f00952 100644
--- a/lib/pleroma/web/mastodon_api/controllers/media_controller.ex
+++ b/lib/pleroma/web/mastodon_api/controllers/media_controller.ex
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.MastodonAPI.MediaController do
diff --git a/lib/pleroma/web/mastodon_api/controllers/notification_controller.ex b/lib/pleroma/web/mastodon_api/controllers/notification_controller.ex
index 0c9218454..7fb536b09 100644
--- a/lib/pleroma/web/mastodon_api/controllers/notification_controller.ex
+++ b/lib/pleroma/web/mastodon_api/controllers/notification_controller.ex
@@ -5,7 +5,7 @@
defmodule Pleroma.Web.MastodonAPI.NotificationController do
use Pleroma.Web, :controller
- import Pleroma.Web.ControllerHelper, only: [add_link_headers: 2]
+ import Pleroma.Web.ControllerHelper, only: [add_link_headers: 2, skip_relationships?: 1]
alias Pleroma.Notification
alias Pleroma.Plugs.OAuthScopesPlug
@@ -45,7 +45,11 @@ defmodule Pleroma.Web.MastodonAPI.NotificationController do
conn
|> add_link_headers(notifications)
- |> render("index.json", notifications: notifications, for: user)
+ |> render("index.json",
+ notifications: notifications,
+ for: user,
+ skip_relationships: skip_relationships?(params)
+ )
end
# GET /api/v1/notifications/:id
@@ -66,7 +70,8 @@ defmodule Pleroma.Web.MastodonAPI.NotificationController do
json(conn, %{})
end
- # POST /api/v1/notifications/dismiss
+ # POST /api/v1/notifications/:id/dismiss
+ # POST /api/v1/notifications/dismiss (deprecated)
def dismiss(%{assigns: %{user: user}} = conn, %{"id" => id} = _params) do
with {:ok, _notif} <- Notification.dismiss(user, id) do
json(conn, %{})
diff --git a/lib/pleroma/web/mastodon_api/controllers/poll_controller.ex b/lib/pleroma/web/mastodon_api/controllers/poll_controller.ex
index d129f8672..d9f894118 100644
--- a/lib/pleroma/web/mastodon_api/controllers/poll_controller.ex
+++ b/lib/pleroma/web/mastodon_api/controllers/poll_controller.ex
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.MastodonAPI.PollController do
diff --git a/lib/pleroma/web/mastodon_api/controllers/report_controller.ex b/lib/pleroma/web/mastodon_api/controllers/report_controller.ex
index 263c2180f..f5782be13 100644
--- a/lib/pleroma/web/mastodon_api/controllers/report_controller.ex
+++ b/lib/pleroma/web/mastodon_api/controllers/report_controller.ex
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.MastodonAPI.ReportController do
diff --git a/lib/pleroma/web/mastodon_api/controllers/scheduled_activity_controller.ex b/lib/pleroma/web/mastodon_api/controllers/scheduled_activity_controller.ex
index ff9276541..e1e6bd89b 100644
--- a/lib/pleroma/web/mastodon_api/controllers/scheduled_activity_controller.ex
+++ b/lib/pleroma/web/mastodon_api/controllers/scheduled_activity_controller.ex
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.MastodonAPI.ScheduledActivityController do
diff --git a/lib/pleroma/web/mastodon_api/controllers/search_controller.ex b/lib/pleroma/web/mastodon_api/controllers/search_controller.ex
index fcab4ef63..c258742dd 100644
--- a/lib/pleroma/web/mastodon_api/controllers/search_controller.ex
+++ b/lib/pleroma/web/mastodon_api/controllers/search_controller.ex
@@ -5,13 +5,14 @@
defmodule Pleroma.Web.MastodonAPI.SearchController do
use Pleroma.Web, :controller
+ import Pleroma.Web.ControllerHelper, only: [fetch_integer_param: 2, skip_relationships?: 1]
+
alias Pleroma.Activity
alias Pleroma.Plugs.OAuthScopesPlug
alias Pleroma.Plugs.RateLimiter
alias Pleroma.Repo
alias Pleroma.User
alias Pleroma.Web
- alias Pleroma.Web.ControllerHelper
alias Pleroma.Web.MastodonAPI.AccountView
alias Pleroma.Web.MastodonAPI.StatusView
@@ -66,10 +67,11 @@ defmodule Pleroma.Web.MastodonAPI.SearchController do
defp search_options(params, user) do
[
+ skip_relationships: skip_relationships?(params),
resolve: params["resolve"] == "true",
following: params["following"] == "true",
- limit: ControllerHelper.fetch_integer_param(params, "limit"),
- offset: ControllerHelper.fetch_integer_param(params, "offset"),
+ limit: fetch_integer_param(params, "limit"),
+ offset: fetch_integer_param(params, "offset"),
type: params["type"],
author: get_author(params),
for_user: user
@@ -79,12 +81,24 @@ defmodule Pleroma.Web.MastodonAPI.SearchController do
defp resource_search(_, "accounts", query, options) do
accounts = with_fallback(fn -> User.search(query, options) end)
- AccountView.render("index.json", users: accounts, for: options[:for_user], as: :user)
+
+ AccountView.render("index.json",
+ users: accounts,
+ for: options[:for_user],
+ as: :user,
+ skip_relationships: false
+ )
end
defp resource_search(_, "statuses", query, options) do
statuses = with_fallback(fn -> Activity.search(options[:for_user], query, options) end)
- StatusView.render("index.json", activities: statuses, for: options[:for_user], as: :activity)
+
+ StatusView.render("index.json",
+ activities: statuses,
+ for: options[:for_user],
+ as: :activity,
+ skip_relationships: options[:skip_relationships]
+ )
end
defp resource_search(:v2, "hashtags", query, _options) do
diff --git a/lib/pleroma/web/mastodon_api/controllers/status_controller.ex b/lib/pleroma/web/mastodon_api/controllers/status_controller.ex
index b0048102f..397dd10e3 100644
--- a/lib/pleroma/web/mastodon_api/controllers/status_controller.ex
+++ b/lib/pleroma/web/mastodon_api/controllers/status_controller.ex
@@ -5,7 +5,8 @@
defmodule Pleroma.Web.MastodonAPI.StatusController do
use Pleroma.Web, :controller
- import Pleroma.Web.ControllerHelper, only: [try_render: 3, add_link_headers: 2]
+ import Pleroma.Web.ControllerHelper,
+ only: [try_render: 3, add_link_headers: 2, skip_relationships?: 1]
require Ecto.Query
@@ -76,7 +77,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusController do
%{scopes: ["write:bookmarks"]} when action in [:bookmark, :unbookmark]
)
- plug(Pleroma.Plugs.EnsurePublicOrAuthenticatedPlug)
+ plug(Pleroma.Plugs.EnsurePublicOrAuthenticatedPlug when action not in [:index, :show])
@rate_limited_status_actions ~w(reblog unreblog favourite unfavourite create delete)a
@@ -101,7 +102,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusController do
`ids` query param is required
"""
- def index(%{assigns: %{user: user}} = conn, %{"ids" => ids}) do
+ def index(%{assigns: %{user: user}} = conn, %{"ids" => ids} = params) do
limit = 100
activities =
@@ -110,7 +111,12 @@ defmodule Pleroma.Web.MastodonAPI.StatusController do
|> Activity.all_by_ids_with_object()
|> Enum.filter(&Visibility.visible_for_user?(&1, user))
- render(conn, "index.json", activities: activities, for: user, as: :activity)
+ render(conn, "index.json",
+ activities: activities,
+ for: user,
+ as: :activity,
+ skip_relationships: skip_relationships?(params)
+ )
end
@doc """
@@ -175,6 +181,8 @@ defmodule Pleroma.Web.MastodonAPI.StatusController do
for: user,
with_direct_conversation_id: true
)
+ else
+ _ -> {:error, :not_found}
end
end
@@ -183,6 +191,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusController do
with {:ok, %Activity{}} <- CommonAPI.delete(id, user) do
json(conn, %{})
else
+ {:error, :not_found} = e -> e
_e -> render_error(conn, :forbidden, "Can't delete this post")
end
end
@@ -204,9 +213,9 @@ defmodule Pleroma.Web.MastodonAPI.StatusController do
end
@doc "POST /api/v1/statuses/:id/favourite"
- def favourite(%{assigns: %{user: user}} = conn, %{"id" => ap_id_or_id}) do
- with {:ok, _fav, %{data: %{"id" => id}}} <- CommonAPI.favorite(ap_id_or_id, user),
- %Activity{} = activity <- Activity.get_create_by_object_ap_id(id) do
+ def favourite(%{assigns: %{user: user}} = conn, %{"id" => activity_id}) do
+ with {:ok, _fav} <- CommonAPI.favorite(user, activity_id),
+ %Activity{} = activity <- Activity.get_by_id(activity_id) do
try_render(conn, "show.json", activity: activity, for: user, as: :activity)
end
end
@@ -357,7 +366,12 @@ defmodule Pleroma.Web.MastodonAPI.StatusController do
conn
|> add_link_headers(activities)
- |> render("index.json", activities: activities, for: user, as: :activity)
+ |> render("index.json",
+ activities: activities,
+ for: user,
+ as: :activity,
+ skip_relationships: skip_relationships?(params)
+ )
end
@doc "GET /api/v1/bookmarks"
@@ -375,6 +389,11 @@ defmodule Pleroma.Web.MastodonAPI.StatusController do
conn
|> add_link_headers(bookmarks)
- |> render("index.json", %{activities: activities, for: user, as: :activity})
+ |> render("index.json",
+ activities: activities,
+ for: user,
+ as: :activity,
+ skip_relationships: skip_relationships?(params)
+ )
end
end
diff --git a/lib/pleroma/web/mastodon_api/controllers/subscription_controller.ex b/lib/pleroma/web/mastodon_api/controllers/subscription_controller.ex
index 11df6fc4a..4647c1f96 100644
--- a/lib/pleroma/web/mastodon_api/controllers/subscription_controller.ex
+++ b/lib/pleroma/web/mastodon_api/controllers/subscription_controller.ex
@@ -6,25 +6,22 @@ defmodule Pleroma.Web.MastodonAPI.SubscriptionController do
@moduledoc "The module represents functions to manage user subscriptions."
use Pleroma.Web, :controller
- alias Pleroma.Web.MastodonAPI.PushSubscriptionView, as: View
alias Pleroma.Web.Push
alias Pleroma.Web.Push.Subscription
action_fallback(:errors)
plug(Pleroma.Plugs.OAuthScopesPlug, %{scopes: ["push"]})
-
plug(Pleroma.Plugs.EnsurePublicOrAuthenticatedPlug)
+ plug(:restrict_push_enabled)
# Creates PushSubscription
# POST /api/v1/push/subscription
#
def create(%{assigns: %{user: user, token: token}} = conn, params) do
- with true <- Push.enabled(),
- {:ok, _} <- Subscription.delete_if_exists(user, token),
+ with {:ok, _} <- Subscription.delete_if_exists(user, token),
{:ok, subscription} <- Subscription.create(user, token, params) do
- view = View.render("push_subscription.json", subscription: subscription)
- json(conn, view)
+ render(conn, "show.json", subscription: subscription)
end
end
@@ -32,10 +29,8 @@ defmodule Pleroma.Web.MastodonAPI.SubscriptionController do
# GET /api/v1/push/subscription
#
def get(%{assigns: %{user: user, token: token}} = conn, _params) do
- with true <- Push.enabled(),
- {:ok, subscription} <- Subscription.get(user, token) do
- view = View.render("push_subscription.json", subscription: subscription)
- json(conn, view)
+ with {:ok, subscription} <- Subscription.get(user, token) do
+ render(conn, "show.json", subscription: subscription)
end
end
@@ -43,10 +38,8 @@ defmodule Pleroma.Web.MastodonAPI.SubscriptionController do
# PUT /api/v1/push/subscription
#
def update(%{assigns: %{user: user, token: token}} = conn, params) do
- with true <- Push.enabled(),
- {:ok, subscription} <- Subscription.update(user, token, params) do
- view = View.render("push_subscription.json", subscription: subscription)
- json(conn, view)
+ with {:ok, subscription} <- Subscription.update(user, token, params) do
+ render(conn, "show.json", subscription: subscription)
end
end
@@ -54,11 +47,20 @@ defmodule Pleroma.Web.MastodonAPI.SubscriptionController do
# DELETE /api/v1/push/subscription
#
def delete(%{assigns: %{user: user, token: token}} = conn, _params) do
- with true <- Push.enabled(),
- {:ok, _response} <- Subscription.delete(user, token),
+ with {:ok, _response} <- Subscription.delete(user, token),
do: json(conn, %{})
end
+ defp restrict_push_enabled(conn, _) do
+ if Push.enabled() do
+ conn
+ else
+ conn
+ |> render_error(:forbidden, "Web push subscription is disabled on this Pleroma instance")
+ |> halt()
+ end
+ end
+
# fallback action
#
def errors(conn, {:error, :not_found}) do
diff --git a/lib/pleroma/web/mastodon_api/controllers/suggestion_controller.ex b/lib/pleroma/web/mastodon_api/controllers/suggestion_controller.ex
index 0cdc7bd8d..c93a43969 100644
--- a/lib/pleroma/web/mastodon_api/controllers/suggestion_controller.ex
+++ b/lib/pleroma/web/mastodon_api/controllers/suggestion_controller.ex
@@ -5,10 +5,13 @@
defmodule Pleroma.Web.MastodonAPI.SuggestionController do
use Pleroma.Web, :controller
+ alias Pleroma.Plugs.OAuthScopesPlug
+
require Logger
+ plug(OAuthScopesPlug, %{scopes: ["read"]} when action == :index)
+
@doc "GET /api/v1/suggestions"
- def index(conn, _) do
- json(conn, [])
- end
+ def index(conn, params),
+ do: Pleroma.Web.MastodonAPI.MastodonAPIController.empty_array(conn, params)
end
diff --git a/lib/pleroma/web/mastodon_api/controllers/timeline_controller.ex b/lib/pleroma/web/mastodon_api/controllers/timeline_controller.ex
index 09e08271b..b3c58005e 100644
--- a/lib/pleroma/web/mastodon_api/controllers/timeline_controller.ex
+++ b/lib/pleroma/web/mastodon_api/controllers/timeline_controller.ex
@@ -6,7 +6,7 @@ defmodule Pleroma.Web.MastodonAPI.TimelineController do
use Pleroma.Web, :controller
import Pleroma.Web.ControllerHelper,
- only: [add_link_headers: 2, add_link_headers: 3, truthy_param?: 1]
+ only: [add_link_headers: 2, add_link_headers: 3, truthy_param?: 1, skip_relationships?: 1]
alias Pleroma.Pagination
alias Pleroma.Plugs.OAuthScopesPlug
@@ -14,9 +14,8 @@ defmodule Pleroma.Web.MastodonAPI.TimelineController do
alias Pleroma.User
alias Pleroma.Web.ActivityPub.ActivityPub
- # TODO: Replace with a macro when there is a Phoenix release with
+ # TODO: Replace with a macro when there is a Phoenix release with the following commit in it:
# https://github.com/phoenixframework/phoenix/commit/2e8c63c01fec4dde5467dbbbf9705ff9e780735e
- # in it
plug(RateLimiter, [name: :timeline, bucket_name: :direct_timeline] when action == :direct)
plug(RateLimiter, [name: :timeline, bucket_name: :public_timeline] when action == :public)
@@ -27,7 +26,7 @@ defmodule Pleroma.Web.MastodonAPI.TimelineController do
plug(OAuthScopesPlug, %{scopes: ["read:statuses"]} when action in [:home, :direct])
plug(OAuthScopesPlug, %{scopes: ["read:lists"]} when action == :list)
- plug(Pleroma.Plugs.EnsurePublicOrAuthenticatedPlug)
+ plug(Pleroma.Plugs.EnsurePublicOrAuthenticatedPlug when action != :public)
plug(:put_view, Pleroma.Web.MastodonAPI.StatusView)
@@ -49,7 +48,12 @@ defmodule Pleroma.Web.MastodonAPI.TimelineController do
conn
|> add_link_headers(activities)
- |> render("index.json", activities: activities, for: user, as: :activity)
+ |> render("index.json",
+ activities: activities,
+ for: user,
+ as: :activity,
+ skip_relationships: skip_relationships?(params)
+ )
end
# GET /api/v1/timelines/direct
@@ -68,24 +72,47 @@ defmodule Pleroma.Web.MastodonAPI.TimelineController do
conn
|> add_link_headers(activities)
- |> render("index.json", activities: activities, for: user, as: :activity)
+ |> render("index.json",
+ activities: activities,
+ for: user,
+ as: :activity,
+ skip_relationships: skip_relationships?(params)
+ )
end
# GET /api/v1/timelines/public
def public(%{assigns: %{user: user}} = conn, params) do
local_only = truthy_param?(params["local"])
- activities =
- params
- |> Map.put("type", ["Create", "Announce"])
- |> Map.put("local_only", local_only)
- |> Map.put("blocking_user", user)
- |> Map.put("muting_user", user)
- |> ActivityPub.fetch_public_activities()
+ cfg_key =
+ if local_only do
+ :local
+ else
+ :federated
+ end
- conn
- |> add_link_headers(activities, %{"local" => local_only})
- |> render("index.json", activities: activities, for: user, as: :activity)
+ restrict? = Pleroma.Config.get([:restrict_unauthenticated, :timelines, cfg_key])
+
+ if not (restrict? and is_nil(user)) do
+ activities =
+ params
+ |> Map.put("type", ["Create", "Announce"])
+ |> Map.put("local_only", local_only)
+ |> Map.put("blocking_user", user)
+ |> Map.put("muting_user", user)
+ |> ActivityPub.fetch_public_activities()
+
+ conn
+ |> add_link_headers(activities, %{"local" => local_only})
+ |> render("index.json",
+ activities: activities,
+ for: user,
+ as: :activity,
+ skip_relationships: skip_relationships?(params)
+ )
+ else
+ render_error(conn, :unauthorized, "authorization required for timeline view")
+ end
end
def hashtag_fetching(params, user, local_only) do
@@ -127,7 +154,12 @@ defmodule Pleroma.Web.MastodonAPI.TimelineController do
conn
|> add_link_headers(activities, %{"local" => local_only})
- |> render("index.json", activities: activities, for: user, as: :activity)
+ |> render("index.json",
+ activities: activities,
+ for: user,
+ as: :activity,
+ skip_relationships: skip_relationships?(params)
+ )
end
# GET /api/v1/timelines/list/:list_id
@@ -151,7 +183,12 @@ defmodule Pleroma.Web.MastodonAPI.TimelineController do
|> ActivityPub.fetch_activities_bounded(following, params)
|> Enum.reverse()
- render(conn, "index.json", activities: activities, for: user, as: :activity)
+ render(conn, "index.json",
+ activities: activities,
+ for: user,
+ as: :activity,
+ skip_relationships: skip_relationships?(params)
+ )
else
_e -> render_error(conn, :forbidden, "Error.")
end
diff --git a/lib/pleroma/web/mastodon_api/mastodon_api.ex b/lib/pleroma/web/mastodon_api/mastodon_api.ex
index 3fe2be521..70da64a7a 100644
--- a/lib/pleroma/web/mastodon_api/mastodon_api.ex
+++ b/lib/pleroma/web/mastodon_api/mastodon_api.ex
@@ -55,6 +55,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPI do
user
|> Notification.for_user_query(options)
+ |> restrict(:include_types, options)
|> restrict(:exclude_types, options)
|> restrict(:account_ap_id, options)
|> Pagination.fetch_paginated(params)
@@ -69,10 +70,10 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPI do
defp cast_params(params) do
param_types = %{
exclude_types: {:array, :string},
+ include_types: {:array, :string},
exclude_visibilities: {:array, :string},
reblogs: :boolean,
with_muted: :boolean,
- with_move: :boolean,
account_ap_id: :string
}
@@ -80,14 +81,16 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPI do
changeset.changes
end
+ defp restrict(query, :include_types, %{include_types: mastodon_types = [_ | _]}) do
+ ap_types = convert_and_filter_mastodon_types(mastodon_types)
+
+ where(query, [q, a], fragment("? @> ARRAY[?->>'type']::varchar[]", ^ap_types, a.data))
+ end
+
defp restrict(query, :exclude_types, %{exclude_types: mastodon_types = [_ | _]}) do
- ap_types =
- mastodon_types
- |> Enum.map(&Activity.from_mastodon_notification_type/1)
- |> Enum.filter(& &1)
+ ap_types = convert_and_filter_mastodon_types(mastodon_types)
- query
- |> where([q, a], not fragment("? @> ARRAY[?->>'type']::varchar[]", ^ap_types, a.data))
+ where(query, [q, a], not fragment("? @> ARRAY[?->>'type']::varchar[]", ^ap_types, a.data))
end
defp restrict(query, :account_ap_id, %{account_ap_id: account_ap_id}) do
@@ -95,4 +98,10 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPI do
end
defp restrict(query, _, _), do: query
+
+ defp convert_and_filter_mastodon_types(types) do
+ types
+ |> Enum.map(&Activity.from_mastodon_notification_type/1)
+ |> Enum.filter(& &1)
+ end
end
diff --git a/lib/pleroma/web/mastodon_api/views/account_view.ex b/lib/pleroma/web/mastodon_api/views/account_view.ex
index 6dc191250..b4b61e74c 100644
--- a/lib/pleroma/web/mastodon_api/views/account_view.ex
+++ b/lib/pleroma/web/mastodon_api/views/account_view.ex
@@ -5,13 +5,31 @@
defmodule Pleroma.Web.MastodonAPI.AccountView do
use Pleroma.Web, :view
- alias Pleroma.HTML
+ alias Pleroma.FollowingRelationship
alias Pleroma.User
+ alias Pleroma.UserRelationship
alias Pleroma.Web.CommonAPI.Utils
alias Pleroma.Web.MastodonAPI.AccountView
alias Pleroma.Web.MediaProxy
def render("index.json", %{users: users} = opts) do
+ reading_user = opts[:for]
+
+ # Note: :skip_relationships option is currently intentionally not supported for accounts
+ relationships_opt =
+ cond do
+ Map.has_key?(opts, :relationships) ->
+ opts[:relationships]
+
+ is_nil(reading_user) ->
+ UserRelationship.view_relationships_option(nil, [])
+
+ true ->
+ UserRelationship.view_relationships_option(reading_user, users)
+ end
+
+ opts = Map.put(opts, :relationships, relationships_opt)
+
users
|> render_many(AccountView, "show.json", opts)
|> Enum.filter(&Enum.any?/1)
@@ -28,7 +46,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountView do
id: to_string(user.id),
acct: user.nickname,
username: username_from_nickname(user.nickname),
- url: User.profile_url(user)
+ url: user.uri || user.ap_id
}
end
@@ -36,37 +54,111 @@ defmodule Pleroma.Web.MastodonAPI.AccountView do
%{}
end
- def render("relationship.json", %{user: %User{} = user, target: %User{} = target}) do
- follow_state = User.get_cached_follow_state(user, target)
+ def render(
+ "relationship.json",
+ %{user: %User{} = reading_user, target: %User{} = target} = opts
+ ) do
+ user_relationships = get_in(opts, [:relationships, :user_relationships])
+ following_relationships = get_in(opts, [:relationships, :following_relationships])
+
+ follow_state =
+ if following_relationships do
+ user_to_target_following_relation =
+ FollowingRelationship.find(following_relationships, reading_user, target)
+
+ User.get_follow_state(reading_user, target, user_to_target_following_relation)
+ else
+ User.get_follow_state(reading_user, target)
+ end
- requested =
- if follow_state && !User.following?(user, target) do
- follow_state == "pending"
+ followed_by =
+ if following_relationships do
+ case FollowingRelationship.find(following_relationships, target, reading_user) do
+ %{state: :follow_accept} -> true
+ _ -> false
+ end
else
- false
+ User.following?(target, reading_user)
end
+ # NOTE: adjust UserRelationship.view_relationships_option/2 on new relation-related flags
%{
id: to_string(target.id),
- following: User.following?(user, target),
- followed_by: User.following?(target, user),
- blocking: User.blocks_user?(user, target),
- blocked_by: User.blocks_user?(target, user),
- muting: User.mutes?(user, target),
- muting_notifications: User.muted_notifications?(user, target),
- subscribing: User.subscribed_to?(user, target),
- requested: requested,
- domain_blocking: User.blocks_domain?(user, target),
- showing_reblogs: User.showing_reblogs?(user, target),
+ following: follow_state == :follow_accept,
+ followed_by: followed_by,
+ blocking:
+ UserRelationship.exists?(
+ user_relationships,
+ :block,
+ reading_user,
+ target,
+ &User.blocks_user?(&1, &2)
+ ),
+ blocked_by:
+ UserRelationship.exists?(
+ user_relationships,
+ :block,
+ target,
+ reading_user,
+ &User.blocks_user?(&1, &2)
+ ),
+ muting:
+ UserRelationship.exists?(
+ user_relationships,
+ :mute,
+ reading_user,
+ target,
+ &User.mutes?(&1, &2)
+ ),
+ muting_notifications:
+ UserRelationship.exists?(
+ user_relationships,
+ :notification_mute,
+ reading_user,
+ target,
+ &User.muted_notifications?(&1, &2)
+ ),
+ subscribing:
+ UserRelationship.exists?(
+ user_relationships,
+ :inverse_subscription,
+ target,
+ reading_user,
+ &User.subscribed_to?(&2, &1)
+ ),
+ requested: follow_state == :follow_pending,
+ domain_blocking: User.blocks_domain?(reading_user, target),
+ showing_reblogs:
+ not UserRelationship.exists?(
+ user_relationships,
+ :reblog_mute,
+ reading_user,
+ target,
+ &User.muting_reblogs?(&1, &2)
+ ),
endorsed: false
}
end
- def render("relationships.json", %{user: user, targets: targets}) do
- render_many(targets, AccountView, "relationship.json", user: user, as: :target)
+ def render("relationships.json", %{user: user, targets: targets} = opts) do
+ relationships_opt =
+ cond do
+ Map.has_key?(opts, :relationships) ->
+ opts[:relationships]
+
+ is_nil(user) ->
+ UserRelationship.view_relationships_option(nil, [])
+
+ true ->
+ UserRelationship.view_relationships_option(user, targets)
+ end
+
+ render_opts = %{as: :target, user: user, relationships: relationships_opt}
+ render_many(targets, AccountView, "relationship.json", render_opts)
end
defp do_render("show.json", %{user: user} = opts) do
+ user = User.sanitize_html(user, User.html_filter_policy(opts[:for]))
display_name = user.name || user.nickname
image = User.avatar_url(user) |> MediaProxy.url()
@@ -89,29 +181,25 @@ defmodule Pleroma.Web.MastodonAPI.AccountView do
bot = user.actor_type in ["Application", "Service"]
emojis =
- (user.source_data["tag"] || [])
- |> Enum.filter(fn %{"type" => t} -> t == "Emoji" end)
- |> Enum.map(fn %{"icon" => %{"url" => url}, "name" => name} ->
+ Enum.map(user.emoji, fn {shortcode, url} ->
%{
- "shortcode" => String.trim(name, ":"),
- "url" => MediaProxy.url(url),
- "static_url" => MediaProxy.url(url),
+ "shortcode" => shortcode,
+ "url" => url,
+ "static_url" => url,
"visible_in_picker" => false
}
end)
- fields =
- user
- |> User.fields()
- |> Enum.map(fn %{"name" => name, "value" => value} ->
- %{
- "name" => name,
- "value" => Pleroma.HTML.filter_tags(value, Pleroma.HTML.Scrubber.LinksOnly)
- }
- end)
-
- bio = HTML.filter_tags(user.bio, User.html_filter_policy(opts[:for]))
- relationship = render("relationship.json", %{user: opts[:for], target: user})
+ relationship =
+ if opts[:skip_relationships] do
+ %{}
+ else
+ render("relationship.json", %{
+ user: opts[:for],
+ target: user,
+ relationships: opts[:relationships]
+ })
+ end
%{
id: to_string(user.id),
@@ -123,17 +211,17 @@ defmodule Pleroma.Web.MastodonAPI.AccountView do
followers_count: followers_count,
following_count: following_count,
statuses_count: user.note_count,
- note: bio || "",
- url: User.profile_url(user),
+ note: user.bio || "",
+ url: user.uri || user.ap_id,
avatar: image,
avatar_static: image,
header: header,
header_static: header,
emojis: emojis,
- fields: fields,
+ fields: user.fields,
bot: bot,
source: %{
- note: HTML.strip_tags((user.bio || "") |> String.replace("<br>", "\n")),
+ note: (user.bio || "") |> String.replace(~r(<br */?>), "\n") |> Pleroma.HTML.strip_tags(),
sensitive: false,
fields: user.raw_fields,
pleroma: %{
diff --git a/lib/pleroma/web/mastodon_api/views/app_view.ex b/lib/pleroma/web/mastodon_api/views/app_view.ex
index d934e2107..36071cd25 100644
--- a/lib/pleroma/web/mastodon_api/views/app_view.ex
+++ b/lib/pleroma/web/mastodon_api/views/app_view.ex
@@ -7,6 +7,21 @@ defmodule Pleroma.Web.MastodonAPI.AppView do
alias Pleroma.Web.OAuth.App
+ def render("index.json", %{apps: apps, count: count, page_size: page_size, admin: true}) do
+ %{
+ apps: render_many(apps, Pleroma.Web.MastodonAPI.AppView, "show.json", %{admin: true}),
+ count: count,
+ page_size: page_size
+ }
+ end
+
+ def render("show.json", %{admin: true, app: %App{} = app} = assigns) do
+ "show.json"
+ |> render(Map.delete(assigns, :admin))
+ |> Map.put(:trusted, app.trusted)
+ |> Map.put(:id, app.id)
+ end
+
def render("show.json", %{app: %App{} = app}) do
%{
id: app.id |> to_string,
diff --git a/lib/pleroma/web/mastodon_api/views/conversation_view.ex b/lib/pleroma/web/mastodon_api/views/conversation_view.ex
index 2220fbcb1..2b6f84c72 100644
--- a/lib/pleroma/web/mastodon_api/views/conversation_view.ex
+++ b/lib/pleroma/web/mastodon_api/views/conversation_view.ex
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.MastodonAPI.ConversationView do
diff --git a/lib/pleroma/web/mastodon_api/views/custom_emoji_view.ex b/lib/pleroma/web/mastodon_api/views/custom_emoji_view.ex
index cb8688941..47a242b8e 100644
--- a/lib/pleroma/web/mastodon_api/views/custom_emoji_view.ex
+++ b/lib/pleroma/web/mastodon_api/views/custom_emoji_view.ex
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.MastodonAPI.CustomEmojiView do
diff --git a/lib/pleroma/web/mastodon_api/views/filter_view.ex b/lib/pleroma/web/mastodon_api/views/filter_view.ex
index a685bc7b6..97fd1e83f 100644
--- a/lib/pleroma/web/mastodon_api/views/filter_view.ex
+++ b/lib/pleroma/web/mastodon_api/views/filter_view.ex
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.MastodonAPI.FilterView do
diff --git a/lib/pleroma/web/mastodon_api/views/instance_view.ex b/lib/pleroma/web/mastodon_api/views/instance_view.ex
index c4866e510..67214dbea 100644
--- a/lib/pleroma/web/mastodon_api/views/instance_view.ex
+++ b/lib/pleroma/web/mastodon_api/views/instance_view.ex
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.MastodonAPI.InstanceView do
diff --git a/lib/pleroma/web/mastodon_api/views/list_view.ex b/lib/pleroma/web/mastodon_api/views/list_view.ex
index bfda6f5b3..580596b64 100644
--- a/lib/pleroma/web/mastodon_api/views/list_view.ex
+++ b/lib/pleroma/web/mastodon_api/views/list_view.ex
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.MastodonAPI.ListView do
diff --git a/lib/pleroma/web/mastodon_api/views/marker_view.ex b/lib/pleroma/web/mastodon_api/views/marker_view.ex
index 38fbeed5f..985368fe5 100644
--- a/lib/pleroma/web/mastodon_api/views/marker_view.ex
+++ b/lib/pleroma/web/mastodon_api/views/marker_view.ex
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.MastodonAPI.MarkerView do
diff --git a/lib/pleroma/web/mastodon_api/views/notification_view.ex b/lib/pleroma/web/mastodon_api/views/notification_view.ex
index 33145c484..4da1ab67f 100644
--- a/lib/pleroma/web/mastodon_api/views/notification_view.ex
+++ b/lib/pleroma/web/mastodon_api/views/notification_view.ex
@@ -8,24 +8,91 @@ defmodule Pleroma.Web.MastodonAPI.NotificationView do
alias Pleroma.Activity
alias Pleroma.Notification
alias Pleroma.User
+ alias Pleroma.UserRelationship
alias Pleroma.Web.CommonAPI
alias Pleroma.Web.MastodonAPI.AccountView
alias Pleroma.Web.MastodonAPI.NotificationView
alias Pleroma.Web.MastodonAPI.StatusView
- def render("index.json", %{notifications: notifications, for: user}) do
- safe_render_many(notifications, NotificationView, "show.json", %{for: user})
+ def render("index.json", %{notifications: notifications, for: reading_user} = opts) do
+ activities = Enum.map(notifications, & &1.activity)
+
+ parent_activities =
+ activities
+ |> Enum.filter(
+ &(Activity.mastodon_notification_type(&1) in [
+ "favourite",
+ "reblog",
+ "pleroma:emoji_reaction"
+ ])
+ )
+ |> Enum.map(& &1.data["object"])
+ |> Activity.create_by_object_ap_id()
+ |> Activity.with_preloaded_object(:left)
+ |> Pleroma.Repo.all()
+
+ relationships_opt =
+ cond do
+ Map.has_key?(opts, :relationships) ->
+ opts[:relationships]
+
+ is_nil(reading_user) ->
+ UserRelationship.view_relationships_option(nil, [])
+
+ true ->
+ move_activities_targets =
+ activities
+ |> Enum.filter(&(Activity.mastodon_notification_type(&1) == "move"))
+ |> Enum.map(&User.get_cached_by_ap_id(&1.data["target"]))
+
+ actors =
+ activities
+ |> Enum.map(fn a -> User.get_cached_by_ap_id(a.data["actor"]) end)
+ |> Enum.filter(& &1)
+ |> Kernel.++(move_activities_targets)
+
+ UserRelationship.view_relationships_option(reading_user, actors,
+ source_mutes_only: opts[:skip_relationships]
+ )
+ end
+
+ opts =
+ opts
+ |> Map.put(:parent_activities, parent_activities)
+ |> Map.put(:relationships, relationships_opt)
+
+ safe_render_many(notifications, NotificationView, "show.json", opts)
end
- def render("show.json", %{
- notification: %Notification{activity: activity} = notification,
- for: user
- }) do
+ def render(
+ "show.json",
+ %{
+ notification: %Notification{activity: activity} = notification,
+ for: reading_user
+ } = opts
+ ) do
actor = User.get_cached_by_ap_id(activity.data["actor"])
- parent_activity = Activity.get_create_by_object_ap_id(activity.data["object"])
+
+ parent_activity_fn = fn ->
+ if opts[:parent_activities] do
+ Activity.Queries.find_by_object_ap_id(opts[:parent_activities], activity.data["object"])
+ else
+ Activity.get_create_by_object_ap_id(activity.data["object"])
+ end
+ end
+
mastodon_type = Activity.mastodon_notification_type(activity)
- with %{id: _} = account <- AccountView.render("show.json", %{user: actor, for: user}) do
+ render_opts = %{
+ relationships: opts[:relationships],
+ skip_relationships: opts[:skip_relationships]
+ }
+
+ with %{id: _} = account <-
+ AccountView.render(
+ "show.json",
+ Map.merge(render_opts, %{user: actor, for: reading_user})
+ ) do
response = %{
id: to_string(notification.id),
type: mastodon_type,
@@ -38,22 +105,25 @@ defmodule Pleroma.Web.MastodonAPI.NotificationView do
case mastodon_type do
"mention" ->
- put_status(response, activity, user)
+ put_status(response, activity, reading_user, render_opts)
"favourite" ->
- put_status(response, parent_activity, user)
+ put_status(response, parent_activity_fn.(), reading_user, render_opts)
"reblog" ->
- put_status(response, parent_activity, user)
+ put_status(response, parent_activity_fn.(), reading_user, render_opts)
"move" ->
- put_target(response, activity, user)
+ # Note: :skip_relationships option being applied to _account_ rendering (here)
+ put_target(response, activity, reading_user, render_opts)
- "follow" ->
+ "pleroma:emoji_reaction" ->
response
+ |> put_status(parent_activity_fn.(), reading_user, render_opts)
+ |> put_emoji(activity)
- "pleroma:emoji_reaction" ->
- put_status(response, parent_activity, user) |> put_emoji(activity)
+ type when type in ["follow", "follow_request"] ->
+ response
_ ->
nil
@@ -64,16 +134,21 @@ defmodule Pleroma.Web.MastodonAPI.NotificationView do
end
defp put_emoji(response, activity) do
- response
- |> Map.put(:emoji, activity.data["content"])
+ Map.put(response, :emoji, activity.data["content"])
end
- defp put_status(response, activity, user) do
- Map.put(response, :status, StatusView.render("show.json", %{activity: activity, for: user}))
+ defp put_status(response, activity, reading_user, opts) do
+ status_render_opts = Map.merge(opts, %{activity: activity, for: reading_user})
+ status_render = StatusView.render("show.json", status_render_opts)
+
+ Map.put(response, :status, status_render)
end
- defp put_target(response, activity, user) do
- target = User.get_cached_by_ap_id(activity.data["target"])
- Map.put(response, :target, AccountView.render("show.json", %{user: target, for: user}))
+ defp put_target(response, activity, reading_user, opts) do
+ target_user = User.get_cached_by_ap_id(activity.data["target"])
+ target_render_opts = Map.merge(opts, %{user: target_user, for: reading_user})
+ target_render = AccountView.render("show.json", target_render_opts)
+
+ Map.put(response, :target, target_render)
end
end
diff --git a/lib/pleroma/web/mastodon_api/views/report_view.ex b/lib/pleroma/web/mastodon_api/views/report_view.ex
index 9da2dd740..98cb581ef 100644
--- a/lib/pleroma/web/mastodon_api/views/report_view.ex
+++ b/lib/pleroma/web/mastodon_api/views/report_view.ex
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.MastodonAPI.ReportView do
diff --git a/lib/pleroma/web/mastodon_api/views/scheduled_activity_view.ex b/lib/pleroma/web/mastodon_api/views/scheduled_activity_view.ex
index fc042a276..458f6bc78 100644
--- a/lib/pleroma/web/mastodon_api/views/scheduled_activity_view.ex
+++ b/lib/pleroma/web/mastodon_api/views/scheduled_activity_view.ex
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.MastodonAPI.ScheduledActivityView do
diff --git a/lib/pleroma/web/mastodon_api/views/status_view.ex b/lib/pleroma/web/mastodon_api/views/status_view.ex
index f7469cdff..b5850e1ae 100644
--- a/lib/pleroma/web/mastodon_api/views/status_view.ex
+++ b/lib/pleroma/web/mastodon_api/views/status_view.ex
@@ -13,6 +13,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do
alias Pleroma.Object
alias Pleroma.Repo
alias Pleroma.User
+ alias Pleroma.UserRelationship
alias Pleroma.Web.CommonAPI
alias Pleroma.Web.CommonAPI.Utils
alias Pleroma.Web.MastodonAPI.AccountView
@@ -71,10 +72,45 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do
end
def render("index.json", opts) do
- replied_to_activities = get_replied_to_activities(opts.activities)
- opts = Map.put(opts, :replied_to_activities, replied_to_activities)
+ reading_user = opts[:for]
- safe_render_many(opts.activities, StatusView, "show.json", opts)
+ # To do: check AdminAPIControllerTest on the reasons behind nil activities in the list
+ activities = Enum.filter(opts.activities, & &1)
+ replied_to_activities = get_replied_to_activities(activities)
+
+ parent_activities =
+ activities
+ |> Enum.filter(&(&1.data["type"] == "Announce" && &1.data["object"]))
+ |> Enum.map(&Object.normalize(&1).data["id"])
+ |> Activity.create_by_object_ap_id()
+ |> Activity.with_preloaded_object(:left)
+ |> Activity.with_preloaded_bookmark(reading_user)
+ |> Activity.with_set_thread_muted_field(reading_user)
+ |> Repo.all()
+
+ relationships_opt =
+ cond do
+ Map.has_key?(opts, :relationships) ->
+ opts[:relationships]
+
+ is_nil(reading_user) ->
+ UserRelationship.view_relationships_option(nil, [])
+
+ true ->
+ actors = Enum.map(activities ++ parent_activities, &get_user(&1.data["actor"]))
+
+ UserRelationship.view_relationships_option(reading_user, actors,
+ source_mutes_only: opts[:skip_relationships]
+ )
+ end
+
+ opts =
+ opts
+ |> Map.put(:replied_to_activities, replied_to_activities)
+ |> Map.put(:parent_activities, parent_activities)
+ |> Map.put(:relationships, relationships_opt)
+
+ safe_render_many(activities, StatusView, "show.json", opts)
end
def render(
@@ -85,17 +121,25 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do
created_at = Utils.to_masto_date(activity.data["published"])
activity_object = Object.normalize(activity)
- reblogged_activity =
- Activity.create_by_object_ap_id(activity_object.data["id"])
- |> Activity.with_preloaded_bookmark(opts[:for])
- |> Activity.with_set_thread_muted_field(opts[:for])
- |> Repo.one()
+ reblogged_parent_activity =
+ if opts[:parent_activities] do
+ Activity.Queries.find_by_object_ap_id(
+ opts[:parent_activities],
+ activity_object.data["id"]
+ )
+ else
+ Activity.create_by_object_ap_id(activity_object.data["id"])
+ |> Activity.with_preloaded_bookmark(opts[:for])
+ |> Activity.with_set_thread_muted_field(opts[:for])
+ |> Repo.one()
+ end
- reblogged = render("show.json", Map.put(opts, :activity, reblogged_activity))
+ reblog_rendering_opts = Map.put(opts, :activity, reblogged_parent_activity)
+ reblogged = render("show.json", reblog_rendering_opts)
favorited = opts[:for] && opts[:for].ap_id in (activity_object.data["likes"] || [])
- bookmarked = Activity.get_bookmark(reblogged_activity, opts[:for]) != nil
+ bookmarked = Activity.get_bookmark(reblogged_parent_activity, opts[:for]) != nil
mentions =
activity.recipients
@@ -107,7 +151,13 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do
id: to_string(activity.id),
uri: activity_object.data["id"],
url: activity_object.data["id"],
- account: AccountView.render("show.json", %{user: user, for: opts[:for]}),
+ account:
+ AccountView.render("show.json", %{
+ user: user,
+ for: opts[:for],
+ relationships: opts[:relationships],
+ skip_relationships: opts[:skip_relationships]
+ }),
in_reply_to_id: nil,
in_reply_to_account_id: nil,
reblog: reblogged,
@@ -116,7 +166,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do
reblogs_count: 0,
replies_count: 0,
favourites_count: 0,
- reblogged: reblogged?(reblogged_activity, opts[:for]),
+ reblogged: reblogged?(reblogged_parent_activity, opts[:for]),
favourited: present?(favorited),
bookmarked: present?(bookmarked),
muted: false,
@@ -183,9 +233,10 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do
end
thread_muted? =
- case activity.thread_muted? do
- thread_muted? when is_boolean(thread_muted?) -> thread_muted?
- nil -> (opts[:for] && CommonAPI.thread_muted?(opts[:for], activity)) || false
+ cond do
+ is_nil(opts[:for]) -> false
+ is_boolean(activity.thread_muted?) -> activity.thread_muted?
+ true -> CommonAPI.thread_muted?(opts[:for], activity)
end
attachment_data = object.data["attachment"] || []
@@ -253,11 +304,28 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do
_ -> []
end
+ # Status muted state (would do 1 request per status unless user mutes are preloaded)
+ muted =
+ thread_muted? ||
+ UserRelationship.exists?(
+ get_in(opts, [:relationships, :user_relationships]),
+ :mute,
+ opts[:for],
+ user,
+ fn for_user, user -> User.mutes?(for_user, user) end
+ )
+
%{
id: to_string(activity.id),
uri: object.data["id"],
url: url,
- account: AccountView.render("show.json", %{user: user, for: opts[:for]}),
+ account:
+ AccountView.render("show.json", %{
+ user: user,
+ for: opts[:for],
+ relationships: opts[:relationships],
+ skip_relationships: opts[:skip_relationships]
+ }),
in_reply_to_id: reply_to && to_string(reply_to.id),
in_reply_to_account_id: reply_to_user && to_string(reply_to_user.id),
reblog: nil,
@@ -270,7 +338,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do
reblogged: reblogged?(activity, opts[:for]),
favourited: present?(favorited),
bookmarked: present?(bookmarked),
- muted: thread_muted? || User.mutes?(opts[:for], user),
+ muted: muted,
pinned: pinned?(activity, user),
sensitive: sensitive,
spoiler_text: summary,
@@ -421,7 +489,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do
end
def render_content(%{data: %{"type" => object_type}} = object)
- when object_type in ["Video", "Event"] do
+ when object_type in ["Video", "Event", "Audio"] do
with name when not is_nil(name) and name != "" <- object.data["name"] do
"<p><a href=\"#{object.data["id"]}\">#{name}</a></p>#{object.data["content"]}"
else
diff --git a/lib/pleroma/web/mastodon_api/views/push_subscription_view.ex b/lib/pleroma/web/mastodon_api/views/subscription_view.ex
index 021489711..7c67cc924 100644
--- a/lib/pleroma/web/mastodon_api/views/push_subscription_view.ex
+++ b/lib/pleroma/web/mastodon_api/views/subscription_view.ex
@@ -1,12 +1,12 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
-defmodule Pleroma.Web.MastodonAPI.PushSubscriptionView do
+defmodule Pleroma.Web.MastodonAPI.SubscriptionView do
use Pleroma.Web, :view
alias Pleroma.Web.Push
- def render("push_subscription.json", %{subscription: subscription}) do
+ def render("show.json", %{subscription: subscription}) do
%{
id: to_string(subscription.id),
endpoint: subscription.endpoint,
diff --git a/lib/pleroma/web/mastodon_api/websocket_handler.ex b/lib/pleroma/web/mastodon_api/websocket_handler.ex
index a400d1c8d..5652a37c1 100644
--- a/lib/pleroma/web/mastodon_api/websocket_handler.ex
+++ b/lib/pleroma/web/mastodon_api/websocket_handler.ex
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.MastodonAPI.WebsocketHandler do
diff --git a/lib/pleroma/web/media_proxy/media_proxy.ex b/lib/pleroma/web/media_proxy/media_proxy.ex
index 1725ab071..b2b524524 100644
--- a/lib/pleroma/web/media_proxy/media_proxy.ex
+++ b/lib/pleroma/web/media_proxy/media_proxy.ex
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.MediaProxy do
diff --git a/lib/pleroma/web/media_proxy/media_proxy_controller.ex b/lib/pleroma/web/media_proxy/media_proxy_controller.ex
index 8403850ff..1a09ac62a 100644
--- a/lib/pleroma/web/media_proxy/media_proxy_controller.ex
+++ b/lib/pleroma/web/media_proxy/media_proxy_controller.ex
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.MediaProxy.MediaProxyController do
diff --git a/lib/pleroma/web/metadata.ex b/lib/pleroma/web/metadata.ex
index 8761260f2..a9f70c43e 100644
--- a/lib/pleroma/web/metadata.ex
+++ b/lib/pleroma/web/metadata.ex
@@ -1,12 +1,17 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.Metadata do
alias Phoenix.HTML
def build_tags(params) do
- Enum.reduce(Pleroma.Config.get([__MODULE__, :providers], []), "", fn parser, acc ->
+ providers = [
+ Pleroma.Web.Metadata.Providers.RestrictIndexing
+ | Pleroma.Config.get([__MODULE__, :providers], [])
+ ]
+
+ Enum.reduce(providers, "", fn parser, acc ->
rendered_html =
params
|> parser.build_tags()
diff --git a/lib/pleroma/web/metadata/opengraph.ex b/lib/pleroma/web/metadata/opengraph.ex
index e7fa7f408..68c871e71 100644
--- a/lib/pleroma/web/metadata/opengraph.ex
+++ b/lib/pleroma/web/metadata/opengraph.ex
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.Metadata.Providers.OpenGraph do
@@ -68,7 +68,7 @@ defmodule Pleroma.Web.Metadata.Providers.OpenGraph do
property: "og:title",
content: Utils.user_name_string(user)
], []},
- {:meta, [property: "og:url", content: User.profile_url(user)], []},
+ {:meta, [property: "og:url", content: user.uri || user.ap_id], []},
{:meta, [property: "og:description", content: truncated_bio], []},
{:meta, [property: "og:type", content: "website"], []},
{:meta, [property: "og:image", content: Utils.attachment_url(User.avatar_url(user))], []},
diff --git a/lib/pleroma/web/metadata/player_view.ex b/lib/pleroma/web/metadata/player_view.ex
index 4289ebdbd..5a918532a 100644
--- a/lib/pleroma/web/metadata/player_view.ex
+++ b/lib/pleroma/web/metadata/player_view.ex
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.Metadata.PlayerView do
diff --git a/lib/pleroma/web/metadata/provider.ex b/lib/pleroma/web/metadata/provider.ex
index 197fb2a77..767288f9c 100644
--- a/lib/pleroma/web/metadata/provider.ex
+++ b/lib/pleroma/web/metadata/provider.ex
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.Metadata.Providers.Provider do
diff --git a/lib/pleroma/web/metadata/restrict_indexing.ex b/lib/pleroma/web/metadata/restrict_indexing.ex
new file mode 100644
index 000000000..f15607896
--- /dev/null
+++ b/lib/pleroma/web/metadata/restrict_indexing.ex
@@ -0,0 +1,25 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Web.Metadata.Providers.RestrictIndexing do
+ @behaviour Pleroma.Web.Metadata.Providers.Provider
+
+ @moduledoc """
+ Restricts indexing of remote users.
+ """
+
+ @impl true
+ def build_tags(%{user: %{local: false}}) do
+ [
+ {:meta,
+ [
+ name: "robots",
+ content: "noindex, noarchive"
+ ], []}
+ ]
+ end
+
+ @impl true
+ def build_tags(%{user: %{local: true}}), do: []
+end
diff --git a/lib/pleroma/web/metadata/twitter_card.ex b/lib/pleroma/web/metadata/twitter_card.ex
index 67419a666..5d08ce422 100644
--- a/lib/pleroma/web/metadata/twitter_card.ex
+++ b/lib/pleroma/web/metadata/twitter_card.ex
@@ -1,6 +1,6 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.Metadata.Providers.TwitterCard do
diff --git a/lib/pleroma/web/mongooseim/mongoose_im_controller.ex b/lib/pleroma/web/mongooseim/mongoose_im_controller.ex
index 358600e7d..04d823b36 100644
--- a/lib/pleroma/web/mongooseim/mongoose_im_controller.ex
+++ b/lib/pleroma/web/mongooseim/mongoose_im_controller.ex
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.MongooseIM.MongooseIMController do
diff --git a/lib/pleroma/web/nodeinfo/nodeinfo_controller.ex b/lib/pleroma/web/nodeinfo/nodeinfo_controller.ex
index 18eb41333..f9a5ddcc0 100644
--- a/lib/pleroma/web/nodeinfo/nodeinfo_controller.ex
+++ b/lib/pleroma/web/nodeinfo/nodeinfo_controller.ex
@@ -60,6 +60,7 @@ defmodule Pleroma.Web.Nodeinfo.NodeinfoController do
"pleroma_explicit_addressing",
"shareable_emoji_packs",
"multifetch",
+ "pleroma:api/v1/notifications:include_types_filter",
if Config.get([:media_proxy, :enabled]) do
"media_proxy"
end,
@@ -74,7 +75,8 @@ defmodule Pleroma.Web.Nodeinfo.NodeinfoController do
end,
if Config.get([:instance, :safe_dm_mentions]) do
"safe_dm_mentions"
- end
+ end,
+ "pleroma_emoji_reactions"
]
|> Enum.filter(& &1)
diff --git a/lib/pleroma/web/oauth.ex b/lib/pleroma/web/oauth.ex
index 280cf28c0..2f1b8708d 100644
--- a/lib/pleroma/web/oauth.ex
+++ b/lib/pleroma/web/oauth.ex
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.OAuth do
diff --git a/lib/pleroma/web/oauth/app.ex b/lib/pleroma/web/oauth/app.ex
index cc3fb1ce5..6a6d5f2e2 100644
--- a/lib/pleroma/web/oauth/app.ex
+++ b/lib/pleroma/web/oauth/app.ex
@@ -1,10 +1,11 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.OAuth.App do
use Ecto.Schema
import Ecto.Changeset
+ import Ecto.Query
alias Pleroma.Repo
@type t :: %__MODULE__{}
@@ -16,14 +17,24 @@ defmodule Pleroma.Web.OAuth.App do
field(:website, :string)
field(:client_id, :string)
field(:client_secret, :string)
+ field(:trusted, :boolean, default: false)
+
+ has_many(:oauth_authorizations, Pleroma.Web.OAuth.Authorization, on_delete: :delete_all)
+ has_many(:oauth_tokens, Pleroma.Web.OAuth.Token, on_delete: :delete_all)
timestamps()
end
+ @spec changeset(App.t(), map()) :: Ecto.Changeset.t()
+ def changeset(struct, params) do
+ cast(struct, params, [:client_name, :redirect_uris, :scopes, :website, :trusted])
+ end
+
+ @spec register_changeset(App.t(), map()) :: Ecto.Changeset.t()
def register_changeset(struct, params \\ %{}) do
changeset =
struct
- |> cast(params, [:client_name, :redirect_uris, :scopes, :website])
+ |> changeset(params)
|> validate_required([:client_name, :redirect_uris, :scopes])
if changeset.valid? do
@@ -41,6 +52,21 @@ defmodule Pleroma.Web.OAuth.App do
end
end
+ @spec create(map()) :: {:ok, App.t()} | {:error, Ecto.Changeset.t()}
+ def create(params) do
+ with changeset <- __MODULE__.register_changeset(%__MODULE__{}, params) do
+ Repo.insert(changeset)
+ end
+ end
+
+ @spec update(map()) :: {:ok, App.t()} | {:error, Ecto.Changeset.t()}
+ def update(params) do
+ with %__MODULE__{} = app <- Repo.get(__MODULE__, params["id"]),
+ changeset <- changeset(app, params) do
+ Repo.update(changeset)
+ end
+ end
+
@doc """
Gets app by attrs or create new with attrs.
And updates the scopes if need.
@@ -65,4 +91,58 @@ defmodule Pleroma.Web.OAuth.App do
|> change(%{scopes: scopes})
|> Repo.update()
end
+
+ @spec search(map()) :: {:ok, [App.t()], non_neg_integer()}
+ def search(params) do
+ query = from(a in __MODULE__)
+
+ query =
+ if params[:client_name] do
+ from(a in query, where: a.client_name == ^params[:client_name])
+ else
+ query
+ end
+
+ query =
+ if params[:client_id] do
+ from(a in query, where: a.client_id == ^params[:client_id])
+ else
+ query
+ end
+
+ query =
+ if Map.has_key?(params, :trusted) do
+ from(a in query, where: a.trusted == ^params[:trusted])
+ else
+ query
+ end
+
+ query =
+ from(u in query,
+ limit: ^params[:page_size],
+ offset: ^((params[:page] - 1) * params[:page_size])
+ )
+
+ count = Repo.aggregate(__MODULE__, :count, :id)
+
+ {:ok, Repo.all(query), count}
+ end
+
+ @spec destroy(pos_integer()) :: {:ok, App.t()} | {:error, Ecto.Changeset.t()}
+ def destroy(id) do
+ with %__MODULE__{} = app <- Repo.get(__MODULE__, id) do
+ Repo.delete(app)
+ end
+ end
+
+ @spec errors(Ecto.Changeset.t()) :: map()
+ def errors(changeset) do
+ Enum.reduce(changeset.errors, %{}, fn
+ {:client_name, {error, _}}, acc ->
+ Map.put(acc, :name, error)
+
+ {key, {error, _}}, acc ->
+ Map.put(acc, key, error)
+ end)
+ end
end
diff --git a/lib/pleroma/web/oauth/authorization.ex b/lib/pleroma/web/oauth/authorization.ex
index ed42a34f3..268ee5b63 100644
--- a/lib/pleroma/web/oauth/authorization.ex
+++ b/lib/pleroma/web/oauth/authorization.ex
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.OAuth.Authorization do
diff --git a/lib/pleroma/web/oauth/fallback_controller.ex b/lib/pleroma/web/oauth/fallback_controller.ex
index dd7f08bf1..a89ced886 100644
--- a/lib/pleroma/web/oauth/fallback_controller.ex
+++ b/lib/pleroma/web/oauth/fallback_controller.ex
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.OAuth.FallbackController do
diff --git a/lib/pleroma/web/oauth/oauth_controller.ex b/lib/pleroma/web/oauth/oauth_controller.ex
index 46688db7e..0121cd661 100644
--- a/lib/pleroma/web/oauth/oauth_controller.ex
+++ b/lib/pleroma/web/oauth/oauth_controller.ex
@@ -27,6 +27,8 @@ defmodule Pleroma.Web.OAuth.OAuthController do
plug(:fetch_flash)
plug(RateLimiter, [name: :authentication] when action == :create_authorization)
+ plug(:skip_plug, Pleroma.Plugs.OAuthScopesPlug)
+
action_fallback(Pleroma.Web.OAuth.FallbackController)
@oob_token_redirect_uri "urn:ietf:wg:oauth:2.0:oob"
diff --git a/lib/pleroma/web/oauth/oauth_view.ex b/lib/pleroma/web/oauth/oauth_view.ex
index 9b37a91c5..94ddaf913 100644
--- a/lib/pleroma/web/oauth/oauth_view.ex
+++ b/lib/pleroma/web/oauth/oauth_view.ex
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.OAuth.OAuthView do
diff --git a/lib/pleroma/web/oauth/scopes.ex b/lib/pleroma/web/oauth/scopes.ex
index 8ecf901f3..1023f16d4 100644
--- a/lib/pleroma/web/oauth/scopes.ex
+++ b/lib/pleroma/web/oauth/scopes.ex
@@ -15,7 +15,12 @@ defmodule Pleroma.Web.OAuth.Scopes do
Note: `scopes` is used by Mastodon — supporting it but sticking to
OAuth's standard `scope` wherever we control it
"""
- @spec fetch_scopes(map(), list()) :: list()
+ @spec fetch_scopes(map() | struct(), list()) :: list()
+
+ def fetch_scopes(%Pleroma.Web.ApiSpec.Schemas.AppCreateRequest{scopes: scopes}, default) do
+ parse_scopes(scopes, default)
+ end
+
def fetch_scopes(params, default) do
parse_scopes(params["scope"] || params["scopes"], default)
end
diff --git a/lib/pleroma/web/oauth/token.ex b/lib/pleroma/web/oauth/token.ex
index 8ea373805..08bb7326d 100644
--- a/lib/pleroma/web/oauth/token.ex
+++ b/lib/pleroma/web/oauth/token.ex
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.OAuth.Token do
diff --git a/lib/pleroma/web/oauth/token/query.ex b/lib/pleroma/web/oauth/token/query.ex
index 9642103e6..93d6e26ed 100644
--- a/lib/pleroma/web/oauth/token/query.ex
+++ b/lib/pleroma/web/oauth/token/query.ex
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.OAuth.Token.Query do
diff --git a/lib/pleroma/web/oauth/token/response.ex b/lib/pleroma/web/oauth/token/response.ex
index 266110814..6f4713dee 100644
--- a/lib/pleroma/web/oauth/token/response.ex
+++ b/lib/pleroma/web/oauth/token/response.ex
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.OAuth.Token.Response do
diff --git a/lib/pleroma/web/oauth/token/strategy/refresh_token.ex b/lib/pleroma/web/oauth/token/strategy/refresh_token.ex
index c620050c8..debc29b0b 100644
--- a/lib/pleroma/web/oauth/token/strategy/refresh_token.ex
+++ b/lib/pleroma/web/oauth/token/strategy/refresh_token.ex
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.OAuth.Token.Strategy.RefreshToken do
diff --git a/lib/pleroma/web/oauth/token/strategy/revoke.ex b/lib/pleroma/web/oauth/token/strategy/revoke.ex
index 983f095b4..069c1ee21 100644
--- a/lib/pleroma/web/oauth/token/strategy/revoke.ex
+++ b/lib/pleroma/web/oauth/token/strategy/revoke.ex
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.OAuth.Token.Strategy.Revoke do
diff --git a/lib/pleroma/web/oauth/token/utils.ex b/lib/pleroma/web/oauth/token/utils.ex
index 1e8765e93..43aeab6b0 100644
--- a/lib/pleroma/web/oauth/token/utils.ex
+++ b/lib/pleroma/web/oauth/token/utils.ex
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.OAuth.Token.Utils do
diff --git a/lib/pleroma/web/ostatus/ostatus_controller.ex b/lib/pleroma/web/ostatus/ostatus_controller.ex
index 01ec7941e..6fd3cfce5 100644
--- a/lib/pleroma/web/ostatus/ostatus_controller.ex
+++ b/lib/pleroma/web/ostatus/ostatus_controller.ex
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.OStatus.OStatusController do
@@ -16,6 +16,10 @@ defmodule Pleroma.Web.OStatus.OStatusController do
alias Pleroma.Web.Metadata.PlayerView
alias Pleroma.Web.Router
+ plug(Pleroma.Plugs.EnsureAuthenticatedPlug,
+ unless_func: &Pleroma.Web.FederatingPlug.federating?/0
+ )
+
plug(
RateLimiter,
[name: :ap_routes, params: ["uuid"]] when action in [:object, :activity]
@@ -135,13 +139,13 @@ defmodule Pleroma.Web.OStatus.OStatusController do
end
end
- def errors(conn, {:error, :not_found}) do
+ defp errors(conn, {:error, :not_found}) do
render_error(conn, :not_found, "Not found")
end
- def errors(conn, {:fetch_user, nil}), do: errors(conn, {:error, :not_found})
+ defp errors(conn, {:fetch_user, nil}), do: errors(conn, {:error, :not_found})
- def errors(conn, _) do
+ defp errors(conn, _) do
render_error(conn, :internal_server_error, "Something went wrong")
end
end
diff --git a/lib/pleroma/web/pleroma_api/controllers/account_controller.ex b/lib/pleroma/web/pleroma_api/controllers/account_controller.ex
index 773cd9a97..60405fbff 100644
--- a/lib/pleroma/web/pleroma_api/controllers/account_controller.ex
+++ b/lib/pleroma/web/pleroma_api/controllers/account_controller.ex
@@ -1,19 +1,18 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.PleromaAPI.AccountController do
use Pleroma.Web, :controller
import Pleroma.Web.ControllerHelper,
- only: [json_response: 3, add_link_headers: 2, assign_account_by_id: 2]
+ only: [json_response: 3, add_link_headers: 2, assign_account_by_id: 2, skip_relationships?: 1]
alias Ecto.Changeset
alias Pleroma.Plugs.OAuthScopesPlug
alias Pleroma.Plugs.RateLimiter
alias Pleroma.User
alias Pleroma.Web.ActivityPub.ActivityPub
- alias Pleroma.Web.CommonAPI
alias Pleroma.Web.MastodonAPI.StatusView
require Pleroma.Constants
@@ -58,38 +57,32 @@ defmodule Pleroma.Web.PleromaAPI.AccountController do
@doc "PATCH /api/v1/pleroma/accounts/update_avatar"
def update_avatar(%{assigns: %{user: user}} = conn, %{"img" => ""}) do
- {:ok, user} =
+ {:ok, _user} =
user
|> Changeset.change(%{avatar: nil})
|> User.update_and_set_cache()
- CommonAPI.update(user)
-
json(conn, %{url: nil})
end
def update_avatar(%{assigns: %{user: user}} = conn, params) do
{:ok, %{data: data}} = ActivityPub.upload(params, type: :avatar)
- {:ok, user} = user |> Changeset.change(%{avatar: data}) |> User.update_and_set_cache()
+ {:ok, _user} = user |> Changeset.change(%{avatar: data}) |> User.update_and_set_cache()
%{"url" => [%{"href" => href} | _]} = data
- CommonAPI.update(user)
-
json(conn, %{url: href})
end
@doc "PATCH /api/v1/pleroma/accounts/update_banner"
def update_banner(%{assigns: %{user: user}} = conn, %{"banner" => ""}) do
- with {:ok, user} <- User.update_banner(user, %{}) do
- CommonAPI.update(user)
+ with {:ok, _user} <- User.update_banner(user, %{}) do
json(conn, %{url: nil})
end
end
def update_banner(%{assigns: %{user: user}} = conn, params) do
with {:ok, object} <- ActivityPub.upload(%{"img" => params["banner"]}, type: :banner),
- {:ok, user} <- User.update_banner(user, object.data) do
- CommonAPI.update(user)
+ {:ok, _user} <- User.update_banner(user, object.data) do
%{"url" => [%{"href" => href} | _]} = object.data
json(conn, %{url: href})
@@ -139,7 +132,12 @@ defmodule Pleroma.Web.PleromaAPI.AccountController do
conn
|> add_link_headers(activities)
|> put_view(StatusView)
- |> render("index.json", activities: activities, for: for_user, as: :activity)
+ |> render("index.json",
+ activities: activities,
+ for: for_user,
+ as: :activity,
+ skip_relationships: skip_relationships?(params)
+ )
end
@doc "POST /api/v1/pleroma/accounts/:id/subscribe"
diff --git a/lib/pleroma/web/pleroma_api/controllers/mascot_controller.ex b/lib/pleroma/web/pleroma_api/controllers/mascot_controller.ex
index 8cf552b7e..d9c1c8636 100644
--- a/lib/pleroma/web/pleroma_api/controllers/mascot_controller.ex
+++ b/lib/pleroma/web/pleroma_api/controllers/mascot_controller.ex
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.PleromaAPI.MascotController do
diff --git a/lib/pleroma/web/pleroma_api/controllers/pleroma_api_controller.ex b/lib/pleroma/web/pleroma_api/controllers/pleroma_api_controller.ex
index 0e160bbfc..fe1b97a20 100644
--- a/lib/pleroma/web/pleroma_api/controllers/pleroma_api_controller.ex
+++ b/lib/pleroma/web/pleroma_api/controllers/pleroma_api_controller.ex
@@ -5,7 +5,7 @@
defmodule Pleroma.Web.PleromaAPI.PleromaAPIController do
use Pleroma.Web, :controller
- import Pleroma.Web.ControllerHelper, only: [add_link_headers: 2]
+ import Pleroma.Web.ControllerHelper, only: [add_link_headers: 2, skip_relationships?: 1]
alias Pleroma.Activity
alias Pleroma.Conversation.Participation
@@ -34,7 +34,7 @@ defmodule Pleroma.Web.PleromaAPI.PleromaAPIController do
plug(
OAuthScopesPlug,
- %{scopes: ["write:conversations"]} when action == :update_conversation
+ %{scopes: ["write:conversations"]} when action in [:update_conversation, :read_conversations]
)
plug(OAuthScopesPlug, %{scopes: ["write:notifications"]} when action == :read_notification)
@@ -101,16 +101,20 @@ defmodule Pleroma.Web.PleromaAPI.PleromaAPIController do
conn
|> put_view(ConversationView)
|> render("participation.json", %{participation: participation, for: user})
+ else
+ _error ->
+ conn
+ |> put_status(404)
+ |> json(%{"error" => "Unknown conversation id"})
end
end
def conversation_statuses(
- %{assigns: %{user: user}} = conn,
+ %{assigns: %{user: %{id: user_id} = user}} = conn,
%{"id" => participation_id} = params
) do
- participation = Participation.get(participation_id, preload: [:conversation])
-
- if user.id == participation.user_id do
+ with %Participation{user_id: ^user_id} = participation <-
+ Participation.get(participation_id, preload: [:conversation]) do
params =
params
|> Map.put("blocking_user", user)
@@ -119,13 +123,24 @@ defmodule Pleroma.Web.PleromaAPI.PleromaAPIController do
activities =
participation.conversation.ap_id
- |> ActivityPub.fetch_activities_for_context(params)
+ |> ActivityPub.fetch_activities_for_context_query(params)
+ |> Pleroma.Pagination.fetch_paginated(Map.put(params, "total", false))
|> Enum.reverse()
conn
|> add_link_headers(activities)
|> put_view(StatusView)
- |> render("index.json", %{activities: activities, for: user, as: :activity})
+ |> render("index.json",
+ activities: activities,
+ for: user,
+ as: :activity,
+ skip_relationships: skip_relationships?(params)
+ )
+ else
+ _error ->
+ conn
+ |> put_status(404)
+ |> json(%{"error" => "Unknown conversation id"})
end
end
@@ -133,15 +148,22 @@ defmodule Pleroma.Web.PleromaAPI.PleromaAPIController do
%{assigns: %{user: user}} = conn,
%{"id" => participation_id, "recipients" => recipients}
) do
- participation =
- participation_id
- |> Participation.get()
-
- with true <- user.id == participation.user_id,
+ with %Participation{} = participation <- Participation.get(participation_id),
+ true <- user.id == participation.user_id,
{:ok, participation} <- Participation.set_recipients(participation, recipients) do
conn
|> put_view(ConversationView)
|> render("participation.json", %{participation: participation, for: user})
+ else
+ {:error, message} ->
+ conn
+ |> put_status(:bad_request)
+ |> json(%{"error" => message})
+
+ _error ->
+ conn
+ |> put_status(404)
+ |> json(%{"error" => "Unknown conversation id"})
end
end
@@ -167,13 +189,17 @@ defmodule Pleroma.Web.PleromaAPI.PleromaAPIController do
end
end
- def read_notification(%{assigns: %{user: user}} = conn, %{"max_id" => max_id}) do
+ def read_notification(%{assigns: %{user: user}} = conn, %{"max_id" => max_id} = params) do
with notifications <- Notification.set_read_up_to(user, max_id) do
notifications = Enum.take(notifications, 80)
conn
|> put_view(NotificationView)
- |> render("index.json", %{notifications: notifications, for: user})
+ |> render("index.json",
+ notifications: notifications,
+ for: user,
+ skip_relationships: skip_relationships?(params)
+ )
end
end
end
diff --git a/lib/pleroma/web/pleroma_api/controllers/scrobble_controller.ex b/lib/pleroma/web/pleroma_api/controllers/scrobble_controller.ex
index b74b3debc..4463ec477 100644
--- a/lib/pleroma/web/pleroma_api/controllers/scrobble_controller.ex
+++ b/lib/pleroma/web/pleroma_api/controllers/scrobble_controller.ex
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.PleromaAPI.ScrobbleController do
diff --git a/lib/pleroma/web/push/impl.ex b/lib/pleroma/web/push/impl.ex
index 34ec1d8d9..f1740a6e0 100644
--- a/lib/pleroma/web/push/impl.ex
+++ b/lib/pleroma/web/push/impl.ex
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.Push.Impl do
@@ -16,6 +16,8 @@ defmodule Pleroma.Web.Push.Impl do
require Logger
import Ecto.Query
+ defdelegate mastodon_notification_type(activity), to: Activity
+
@types ["Create", "Follow", "Announce", "Like", "Move"]
@doc "Performs sending notifications for user subscriptions"
@@ -24,32 +26,32 @@ defmodule Pleroma.Web.Push.Impl do
%{
activity: %{data: %{"type" => activity_type}} = activity,
user: %User{id: user_id}
- } = notif
+ } = notification
)
when activity_type in @types do
- actor = User.get_cached_by_ap_id(notif.activity.data["actor"])
+ actor = User.get_cached_by_ap_id(notification.activity.data["actor"])
- type = Activity.mastodon_notification_type(notif.activity)
+ mastodon_type = mastodon_notification_type(notification.activity)
gcm_api_key = Application.get_env(:web_push_encryption, :gcm_api_key)
avatar_url = User.avatar_url(actor)
object = Object.normalize(activity)
user = User.get_cached_by_id(user_id)
direct_conversation_id = Activity.direct_conversation_id(activity, user)
- for subscription <- fetch_subsriptions(user_id),
- get_in(subscription.data, ["alerts", type]) do
+ for subscription <- fetch_subscriptions(user_id),
+ Subscription.enabled?(subscription, mastodon_type) do
%{
access_token: subscription.token.token,
- notification_id: notif.id,
- notification_type: type,
+ notification_id: notification.id,
+ notification_type: mastodon_type,
icon: avatar_url,
preferred_locale: "en",
pleroma: %{
- activity_id: notif.activity.id,
+ activity_id: notification.activity.id,
direct_conversation_id: direct_conversation_id
}
}
- |> Map.merge(build_content(notif, actor, object))
+ |> Map.merge(build_content(notification, actor, object, mastodon_type))
|> Jason.encode!()
|> push_message(build_sub(subscription), gcm_api_key, subscription)
end
@@ -82,7 +84,7 @@ defmodule Pleroma.Web.Push.Impl do
end
@doc "Gets user subscriptions"
- def fetch_subsriptions(user_id) do
+ def fetch_subscriptions(user_id) do
Subscription
|> where(user_id: ^user_id)
|> preload(:token)
@@ -99,28 +101,36 @@ defmodule Pleroma.Web.Push.Impl do
}
end
+ def build_content(notification, actor, object, mastodon_type \\ nil)
+
def build_content(
%{
activity: %{data: %{"directMessage" => true}},
user: %{notification_settings: %{privacy_option: true}}
},
actor,
- _
+ _object,
+ _mastodon_type
) do
%{title: "New Direct Message", body: "@#{actor.nickname}"}
end
- def build_content(notif, actor, object) do
+ def build_content(notification, actor, object, mastodon_type) do
+ mastodon_type = mastodon_type || mastodon_notification_type(notification.activity)
+
%{
- title: format_title(notif),
- body: format_body(notif, actor, object)
+ title: format_title(notification, mastodon_type),
+ body: format_body(notification, actor, object, mastodon_type)
}
end
+ def format_body(activity, actor, object, mastodon_type \\ nil)
+
def format_body(
%{activity: %{data: %{"type" => "Create"}}},
actor,
- %{data: %{"content" => content}}
+ %{data: %{"content" => content}},
+ _mastodon_type
) do
"@#{actor.nickname}: #{Utils.scrub_html_and_truncate(content, 80)}"
end
@@ -128,33 +138,44 @@ defmodule Pleroma.Web.Push.Impl do
def format_body(
%{activity: %{data: %{"type" => "Announce"}}},
actor,
- %{data: %{"content" => content}}
+ %{data: %{"content" => content}},
+ _mastodon_type
) do
"@#{actor.nickname} repeated: #{Utils.scrub_html_and_truncate(content, 80)}"
end
def format_body(
- %{activity: %{data: %{"type" => type}}},
+ %{activity: %{data: %{"type" => type}}} = notification,
actor,
- _object
+ _object,
+ mastodon_type
)
when type in ["Follow", "Like"] do
- case type do
- "Follow" -> "@#{actor.nickname} has followed you"
- "Like" -> "@#{actor.nickname} has favorited your post"
+ mastodon_type = mastodon_type || mastodon_notification_type(notification.activity)
+
+ case mastodon_type do
+ "follow" -> "@#{actor.nickname} has followed you"
+ "follow_request" -> "@#{actor.nickname} has requested to follow you"
+ "favourite" -> "@#{actor.nickname} has favorited your post"
end
end
- def format_title(%{activity: %{data: %{"directMessage" => true}}}) do
+ def format_title(activity, mastodon_type \\ nil)
+
+ def format_title(%{activity: %{data: %{"directMessage" => true}}}, _mastodon_type) do
"New Direct Message"
end
- def format_title(%{activity: %{data: %{"type" => type}}}) do
- case type do
- "Create" -> "New Mention"
- "Follow" -> "New Follower"
- "Announce" -> "New Repeat"
- "Like" -> "New Favorite"
+ def format_title(%{activity: activity}, mastodon_type) do
+ mastodon_type = mastodon_type || mastodon_notification_type(activity)
+
+ case mastodon_type do
+ "mention" -> "New Mention"
+ "follow" -> "New Follower"
+ "follow_request" -> "New Follow Request"
+ "reblog" -> "New Repeat"
+ "favourite" -> "New Favorite"
+ type -> "New #{String.capitalize(type || "event")}"
end
end
end
diff --git a/lib/pleroma/web/push/push.ex b/lib/pleroma/web/push/push.ex
index 7ef1532ac..b80a6438d 100644
--- a/lib/pleroma/web/push/push.ex
+++ b/lib/pleroma/web/push/push.ex
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.Push do
diff --git a/lib/pleroma/web/push/subscription.ex b/lib/pleroma/web/push/subscription.ex
index 988fabaeb..b99b0c5fb 100644
--- a/lib/pleroma/web/push/subscription.ex
+++ b/lib/pleroma/web/push/subscription.ex
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.Push.Subscription do
@@ -32,6 +32,14 @@ defmodule Pleroma.Web.Push.Subscription do
%{"alerts" => alerts}
end
+ def enabled?(subscription, "follow_request") do
+ enabled?(subscription, "follow")
+ end
+
+ def enabled?(subscription, alert_type) do
+ get_in(subscription.data, ["alerts", alert_type])
+ end
+
def create(
%User{} = user,
%Token{} = token,
diff --git a/lib/pleroma/web/rel_me.ex b/lib/pleroma/web/rel_me.ex
index e97c398dc..8e2b51508 100644
--- a/lib/pleroma/web/rel_me.ex
+++ b/lib/pleroma/web/rel_me.ex
@@ -3,11 +3,9 @@
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.RelMe do
- @hackney_options [
+ @options [
pool: :media,
- recv_timeout: 2_000,
- max_body: 2_000_000,
- with_body: true
+ max_body: 2_000_000
]
if Pleroma.Config.get(:env) == :test do
@@ -25,8 +23,18 @@ defmodule Pleroma.Web.RelMe do
def parse(_), do: {:error, "No URL provided"}
defp parse_url(url) do
+ opts =
+ if Application.get_env(:tesla, :adapter) == Tesla.Adapter.Hackney do
+ Keyword.merge(@options,
+ recv_timeout: 2_000,
+ with_body: true
+ )
+ else
+ @options
+ end
+
with {:ok, %Tesla.Env{body: html, status: status}} when status in 200..299 <-
- Pleroma.HTTP.get(url, [], adapter: @hackney_options),
+ Pleroma.HTTP.get(url, [], adapter: opts),
{:ok, html_tree} <- Floki.parse_document(html),
data <-
Floki.attribute(html_tree, "link[rel~=me]", "href") ++
diff --git a/lib/pleroma/web/rich_media/helpers.ex b/lib/pleroma/web/rich_media/helpers.ex
index 6506de46c..9d3d7f978 100644
--- a/lib/pleroma/web/rich_media/helpers.ex
+++ b/lib/pleroma/web/rich_media/helpers.ex
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright _ 2017-2019 Pleroma Authors <https://pleroma.social/>
+# Copyright _ 2017-2020 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.RichMedia.Helpers do
@@ -64,5 +64,8 @@ defmodule Pleroma.Web.RichMedia.Helpers do
def fetch_data_for_activity(_), do: %{}
- def perform(:fetch, %Activity{} = activity), do: fetch_data_for_activity(activity)
+ def perform(:fetch, %Activity{} = activity) do
+ fetch_data_for_activity(activity)
+ :ok
+ end
end
diff --git a/lib/pleroma/web/rich_media/parser.ex b/lib/pleroma/web/rich_media/parser.ex
index 0779065ee..40980def8 100644
--- a/lib/pleroma/web/rich_media/parser.ex
+++ b/lib/pleroma/web/rich_media/parser.ex
@@ -3,11 +3,9 @@
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.RichMedia.Parser do
- @hackney_options [
+ @options [
pool: :media,
- recv_timeout: 2_000,
- max_body: 2_000_000,
- with_body: true
+ max_body: 2_000_000
]
defp parsers do
@@ -77,8 +75,18 @@ defmodule Pleroma.Web.RichMedia.Parser do
end
defp parse_url(url) do
+ opts =
+ if Application.get_env(:tesla, :adapter) == Tesla.Adapter.Hackney do
+ Keyword.merge(@options,
+ recv_timeout: 2_000,
+ with_body: true
+ )
+ else
+ @options
+ end
+
try do
- {:ok, %Tesla.Env{body: html}} = Pleroma.HTTP.get(url, [], adapter: @hackney_options)
+ {:ok, %Tesla.Env{body: html}} = Pleroma.HTTP.get(url, [], adapter: opts)
html
|> parse_html()
diff --git a/lib/pleroma/web/rich_media/parsers/oembed_parser.ex b/lib/pleroma/web/rich_media/parsers/oembed_parser.ex
index 875637c4d..8f32bf91b 100644
--- a/lib/pleroma/web/rich_media/parsers/oembed_parser.ex
+++ b/lib/pleroma/web/rich_media/parsers/oembed_parser.ex
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.RichMedia.Parsers.OEmbed do
diff --git a/lib/pleroma/web/rich_media/parsers/ogp.ex b/lib/pleroma/web/rich_media/parsers/ogp.ex
index d40fa009f..3e9012588 100644
--- a/lib/pleroma/web/rich_media/parsers/ogp.ex
+++ b/lib/pleroma/web/rich_media/parsers/ogp.ex
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.RichMedia.Parsers.OGP do
diff --git a/lib/pleroma/web/rich_media/parsers/twitter_card.ex b/lib/pleroma/web/rich_media/parsers/twitter_card.ex
index afaa98f3d..09d4b526e 100644
--- a/lib/pleroma/web/rich_media/parsers/twitter_card.ex
+++ b/lib/pleroma/web/rich_media/parsers/twitter_card.ex
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.RichMedia.Parsers.TwitterCard do
diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex
index 980242c68..153802a43 100644
--- a/lib/pleroma/web/router.ex
+++ b/lib/pleroma/web/router.ex
@@ -16,75 +16,60 @@ defmodule Pleroma.Web.Router do
plug(Pleroma.Plugs.UserEnabledPlug)
end
- pipeline :api do
- plug(:accepts, ["json"])
- plug(:fetch_session)
+ pipeline :authenticate do
plug(Pleroma.Plugs.OAuthPlug)
plug(Pleroma.Plugs.BasicAuthDecoderPlug)
plug(Pleroma.Plugs.UserFetcherPlug)
plug(Pleroma.Plugs.SessionAuthenticationPlug)
plug(Pleroma.Plugs.LegacyAuthenticationPlug)
plug(Pleroma.Plugs.AuthenticationPlug)
+ end
+
+ pipeline :after_auth do
plug(Pleroma.Plugs.UserEnabledPlug)
plug(Pleroma.Plugs.SetUserSessionIdPlug)
plug(Pleroma.Plugs.EnsureUserKeyPlug)
- plug(Pleroma.Plugs.IdempotencyPlug)
end
- pipeline :authenticated_api do
+ pipeline :base_api do
plug(:accepts, ["json"])
plug(:fetch_session)
- plug(Pleroma.Plugs.OAuthPlug)
- plug(Pleroma.Plugs.BasicAuthDecoderPlug)
- plug(Pleroma.Plugs.UserFetcherPlug)
- plug(Pleroma.Plugs.SessionAuthenticationPlug)
- plug(Pleroma.Plugs.LegacyAuthenticationPlug)
- plug(Pleroma.Plugs.AuthenticationPlug)
- plug(Pleroma.Plugs.UserEnabledPlug)
- plug(Pleroma.Plugs.SetUserSessionIdPlug)
+ plug(:authenticate)
+ plug(OpenApiSpex.Plug.PutApiSpec, module: Pleroma.Web.ApiSpec)
+ end
+
+ pipeline :api do
+ plug(:base_api)
+ plug(:after_auth)
+ plug(Pleroma.Plugs.IdempotencyPlug)
+ end
+
+ pipeline :authenticated_api do
+ plug(:base_api)
+ plug(Pleroma.Plugs.AuthExpectedPlug)
+ plug(:after_auth)
plug(Pleroma.Plugs.EnsureAuthenticatedPlug)
plug(Pleroma.Plugs.IdempotencyPlug)
end
pipeline :admin_api do
- plug(:accepts, ["json"])
- plug(:fetch_session)
- plug(Pleroma.Plugs.OAuthPlug)
- plug(Pleroma.Plugs.BasicAuthDecoderPlug)
- plug(Pleroma.Plugs.UserFetcherPlug)
- plug(Pleroma.Plugs.SessionAuthenticationPlug)
- plug(Pleroma.Plugs.LegacyAuthenticationPlug)
- plug(Pleroma.Plugs.AuthenticationPlug)
+ plug(:base_api)
plug(Pleroma.Plugs.AdminSecretAuthenticationPlug)
- plug(Pleroma.Plugs.UserEnabledPlug)
- plug(Pleroma.Plugs.SetUserSessionIdPlug)
+ plug(:after_auth)
plug(Pleroma.Plugs.EnsureAuthenticatedPlug)
plug(Pleroma.Plugs.UserIsAdminPlug)
plug(Pleroma.Plugs.IdempotencyPlug)
end
pipeline :mastodon_html do
- plug(:accepts, ["html"])
- plug(:fetch_session)
- plug(Pleroma.Plugs.OAuthPlug)
- plug(Pleroma.Plugs.BasicAuthDecoderPlug)
- plug(Pleroma.Plugs.UserFetcherPlug)
- plug(Pleroma.Plugs.SessionAuthenticationPlug)
- plug(Pleroma.Plugs.LegacyAuthenticationPlug)
- plug(Pleroma.Plugs.AuthenticationPlug)
- plug(Pleroma.Plugs.UserEnabledPlug)
- plug(Pleroma.Plugs.SetUserSessionIdPlug)
- plug(Pleroma.Plugs.EnsureUserKeyPlug)
+ plug(:browser)
+ plug(:authenticate)
+ plug(:after_auth)
end
pipeline :pleroma_html do
- plug(:accepts, ["html"])
- plug(:fetch_session)
- plug(Pleroma.Plugs.OAuthPlug)
- plug(Pleroma.Plugs.BasicAuthDecoderPlug)
- plug(Pleroma.Plugs.UserFetcherPlug)
- plug(Pleroma.Plugs.SessionAuthenticationPlug)
- plug(Pleroma.Plugs.AuthenticationPlug)
+ plug(:browser)
+ plug(:authenticate)
plug(Pleroma.Plugs.EnsureUserKeyPlug)
end
@@ -94,10 +79,12 @@ defmodule Pleroma.Web.Router do
pipeline :config do
plug(:accepts, ["json", "xml"])
+ plug(OpenApiSpex.Plug.PutApiSpec, module: Pleroma.Web.ApiSpec)
end
pipeline :pleroma_api do
plug(:accepts, ["html", "json"])
+ plug(OpenApiSpex.Plug.PutApiSpec, module: Pleroma.Web.ApiSpec)
end
pipeline :mailbox_preview do
@@ -173,6 +160,8 @@ defmodule Pleroma.Web.Router do
get("/users/:nickname/password_reset", AdminAPIController, :get_password_reset)
patch("/users/force_password_reset", AdminAPIController, :force_password_reset)
+ get("/users/:nickname/credentials", AdminAPIController, :show_user_credentials)
+ patch("/users/:nickname/credentials", AdminAPIController, :update_user_credentials)
get("/users", AdminAPIController, :list_users)
get("/users/:nickname", AdminAPIController, :user_show)
@@ -184,7 +173,6 @@ defmodule Pleroma.Web.Router do
patch("/users/resend_confirmation_email", AdminAPIController, :resend_confirmation_email)
get("/reports", AdminAPIController, :list_reports)
- get("/grouped_reports", AdminAPIController, :list_grouped_reports)
get("/reports/:id", AdminAPIController, :report_show)
patch("/reports", AdminAPIController, :reports_update)
post("/reports/:id/notes", AdminAPIController, :report_notes_create)
@@ -197,12 +185,18 @@ defmodule Pleroma.Web.Router do
get("/config", AdminAPIController, :config_show)
post("/config", AdminAPIController, :config_update)
get("/config/descriptions", AdminAPIController, :config_descriptions)
+ get("/need_reboot", AdminAPIController, :need_reboot)
get("/restart", AdminAPIController, :restart)
get("/moderation_log", AdminAPIController, :list_log)
post("/reload_emoji", AdminAPIController, :reload_emoji)
get("/stats", AdminAPIController, :stats)
+
+ get("/oauth_app", AdminAPIController, :oauth_app_list)
+ post("/oauth_app", AdminAPIController, :oauth_app_create)
+ patch("/oauth_app/:id", AdminAPIController, :oauth_app_update)
+ delete("/oauth_app/:id", AdminAPIController, :oauth_app_delete)
end
scope "/api/pleroma/emoji", Pleroma.Web.PleromaAPI do
@@ -332,7 +326,7 @@ defmodule Pleroma.Web.Router do
get("/accounts/relationships", AccountController, :relationships)
get("/accounts/:id/lists", AccountController, :lists)
- get("/accounts/:id/identity_proofs", MastodonAPIController, :empty_array)
+ get("/accounts/:id/identity_proofs", AccountController, :identity_proofs)
get("/follow_requests", FollowRequestController, :index)
get("/blocks", AccountController, :blocks)
@@ -346,9 +340,11 @@ defmodule Pleroma.Web.Router do
get("/notifications", NotificationController, :index)
get("/notifications/:id", NotificationController, :show)
+ post("/notifications/:id/dismiss", NotificationController, :dismiss)
post("/notifications/clear", NotificationController, :clear)
- post("/notifications/dismiss", NotificationController, :dismiss)
delete("/notifications/destroy_multiple", NotificationController, :destroy_multiple)
+ # Deprecated: was removed in Mastodon v3, use `/notifications/:id/dismiss` instead
+ post("/notifications/dismiss", NotificationController, :dismiss)
get("/scheduled_statuses", ScheduledActivityController, :index)
get("/scheduled_statuses/:id", ScheduledActivityController, :show)
@@ -499,6 +495,12 @@ defmodule Pleroma.Web.Router do
)
end
+ scope "/api" do
+ pipe_through(:base_api)
+
+ get("/openapi", OpenApiSpex.Plug.RenderSpec, [])
+ end
+
scope "/api", Pleroma.Web, as: :authenticated_twitter_api do
pipe_through(:authenticated_api)
@@ -508,12 +510,8 @@ defmodule Pleroma.Web.Router do
post("/qvitter/statuses/notifications/read", TwitterAPI.Controller, :notifications_read)
end
- pipeline :ap_service_actor do
- plug(:accepts, ["activity+json", "json"])
- end
-
pipeline :ostatus do
- plug(:accepts, ["html", "xml", "atom", "activity+json", "json"])
+ plug(:accepts, ["html", "xml", "rss", "atom", "activity+json", "json"])
plug(Pleroma.Plugs.StaticFEPlug)
end
@@ -522,8 +520,7 @@ defmodule Pleroma.Web.Router do
end
scope "/", Pleroma.Web do
- pipe_through(:ostatus)
- pipe_through(:http_signature)
+ pipe_through([:ostatus, :http_signature])
get("/objects/:uuid", OStatus.OStatusController, :object)
get("/activities/:uuid", OStatus.OStatusController, :activity)
@@ -541,12 +538,6 @@ defmodule Pleroma.Web.Router do
get("/mailer/unsubscribe/:token", Mailer.SubscriptionController, :unsubscribe)
end
- pipeline :activitypub do
- plug(:accepts, ["activity+json", "json"])
- plug(Pleroma.Web.Plugs.HTTPSignaturePlug)
- plug(Pleroma.Web.Plugs.MappedSignatureToIdentityPlug)
- end
-
scope "/", Pleroma.Web.ActivityPub do
# XXX: not really ostatus
pipe_through(:ostatus)
@@ -554,18 +545,22 @@ defmodule Pleroma.Web.Router do
get("/users/:nickname/outbox", ActivityPubController, :outbox)
end
- pipeline :activitypub_client do
+ pipeline :ap_service_actor do
plug(:accepts, ["activity+json", "json"])
+ end
+
+ # Server to Server (S2S) AP interactions
+ pipeline :activitypub do
+ plug(:ap_service_actor)
+ plug(:http_signature)
+ end
+
+ # Client to Server (C2S) AP interactions
+ pipeline :activitypub_client do
+ plug(:ap_service_actor)
plug(:fetch_session)
- plug(Pleroma.Plugs.OAuthPlug)
- plug(Pleroma.Plugs.BasicAuthDecoderPlug)
- plug(Pleroma.Plugs.UserFetcherPlug)
- plug(Pleroma.Plugs.SessionAuthenticationPlug)
- plug(Pleroma.Plugs.LegacyAuthenticationPlug)
- plug(Pleroma.Plugs.AuthenticationPlug)
- plug(Pleroma.Plugs.UserEnabledPlug)
- plug(Pleroma.Plugs.SetUserSessionIdPlug)
- plug(Pleroma.Plugs.EnsureUserKeyPlug)
+ plug(:authenticate)
+ plug(:after_auth)
end
scope "/", Pleroma.Web.ActivityPub do
@@ -597,8 +592,8 @@ defmodule Pleroma.Web.Router do
post("/inbox", ActivityPubController, :inbox)
end
- get("/following", ActivityPubController, :following, assigns: %{relay: true})
- get("/followers", ActivityPubController, :followers, assigns: %{relay: true})
+ get("/following", ActivityPubController, :relay_following)
+ get("/followers", ActivityPubController, :relay_followers)
end
scope "/internal/fetch", Pleroma.Web.ActivityPub do
@@ -637,12 +632,7 @@ defmodule Pleroma.Web.Router do
get("/web/*path", MastoFEController, :index)
end
- pipeline :remote_media do
- end
-
scope "/proxy/", Pleroma.Web.MediaProxy do
- pipe_through(:remote_media)
-
get("/:sig/:url", MediaProxyController, :remote)
get("/:sig/:url/:filename", MediaProxyController, :remote)
end
@@ -655,6 +645,17 @@ defmodule Pleroma.Web.Router do
end
end
+ # Test-only routes needed to test action dispatching and plug chain execution
+ if Pleroma.Config.get(:env) == :test do
+ scope "/test/authenticated_api", Pleroma.Tests do
+ pipe_through(:authenticated_api)
+
+ for action <- [:skipped_oauth, :performed_oauth, :missed_oauth] do
+ get("/#{action}", OAuthTestController, action)
+ end
+ end
+ end
+
scope "/", Pleroma.Web.MongooseIM do
get("/user_exists", MongooseIMController, :user_exists)
get("/check_password", MongooseIMController, :check_password)
diff --git a/lib/pleroma/web/static_fe/static_fe_controller.ex b/lib/pleroma/web/static_fe/static_fe_controller.ex
index 8ccf15f4b..7a35238d7 100644
--- a/lib/pleroma/web/static_fe/static_fe_controller.ex
+++ b/lib/pleroma/web/static_fe/static_fe_controller.ex
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.StaticFE.StaticFEController do
@@ -17,6 +17,10 @@ defmodule Pleroma.Web.StaticFE.StaticFEController do
plug(:put_view, Pleroma.Web.StaticFE.StaticFEView)
plug(:assign_id)
+ plug(Pleroma.Plugs.EnsureAuthenticatedPlug,
+ unless_func: &Pleroma.Web.FederatingPlug.federating?/0
+ )
+
@page_keys ["max_id", "min_id", "limit", "since_id", "order"]
defp get_title(%Object{data: %{"name" => name}}) when is_binary(name),
@@ -33,7 +37,7 @@ defmodule Pleroma.Web.StaticFE.StaticFEController do
|> render("error.html", %{message: message, meta: ""})
end
- def get_counts(%Activity{} = activity) do
+ defp get_counts(%Activity{} = activity) do
%Object{data: data} = Object.normalize(activity)
%{
@@ -43,9 +47,9 @@ defmodule Pleroma.Web.StaticFE.StaticFEController do
}
end
- def represent(%Activity{} = activity), do: represent(activity, false)
+ defp represent(%Activity{} = activity), do: represent(activity, false)
- def represent(%Activity{object: %Object{data: data}} = activity, selected) do
+ defp represent(%Activity{object: %Object{data: data}} = activity, selected) do
{:ok, user} = User.get_or_fetch(activity.object.data["actor"])
link =
@@ -54,10 +58,19 @@ defmodule Pleroma.Web.StaticFE.StaticFEController do
_ -> data["url"] || data["external_url"] || data["id"]
end
+ content =
+ if data["content"] do
+ data["content"]
+ |> Pleroma.HTML.filter_tags()
+ |> Pleroma.Emoji.Formatter.emojify(Map.get(data, "emoji", %{}))
+ else
+ nil
+ end
+
%{
- user: user,
+ user: User.sanitize_html(user),
title: get_title(activity.object),
- content: data["content"] || nil,
+ content: content,
attachment: data["attachment"],
link: link,
published: data["published"],
@@ -109,7 +122,7 @@ defmodule Pleroma.Web.StaticFE.StaticFEController do
next_page_id = List.last(timeline) && List.last(timeline).id
render(conn, "profile.html", %{
- user: user,
+ user: User.sanitize_html(user),
timeline: timeline,
prev_page_id: prev_page_id,
next_page_id: next_page_id,
@@ -147,17 +160,17 @@ defmodule Pleroma.Web.StaticFE.StaticFEController do
end
end
- def assign_id(%{path_info: ["notice", notice_id]} = conn, _opts),
+ defp assign_id(%{path_info: ["notice", notice_id]} = conn, _opts),
do: assign(conn, :notice_id, notice_id)
- def assign_id(%{path_info: ["users", user_id]} = conn, _opts),
+ defp assign_id(%{path_info: ["users", user_id]} = conn, _opts),
do: assign(conn, :username_or_id, user_id)
- def assign_id(%{path_info: ["objects", object_id]} = conn, _opts),
+ defp assign_id(%{path_info: ["objects", object_id]} = conn, _opts),
do: assign(conn, :object_id, object_id)
- def assign_id(%{path_info: ["activities", activity_id]} = conn, _opts),
+ defp assign_id(%{path_info: ["activities", activity_id]} = conn, _opts),
do: assign(conn, :activity_id, activity_id)
- def assign_id(conn, _opts), do: conn
+ defp assign_id(conn, _opts), do: conn
end
diff --git a/lib/pleroma/web/static_fe/static_fe_view.ex b/lib/pleroma/web/static_fe/static_fe_view.ex
index 821ece9a9..b3d1d1ec8 100644
--- a/lib/pleroma/web/static_fe/static_fe_view.ex
+++ b/lib/pleroma/web/static_fe/static_fe_view.ex
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.StaticFE.StaticFEView do
@@ -18,15 +18,6 @@ defmodule Pleroma.Web.StaticFE.StaticFEView do
@media_types ["image", "audio", "video"]
- def emoji_for_user(%User{} = user) do
- user.source_data
- |> Map.get("tag", [])
- |> Enum.filter(fn %{"type" => t} -> t == "Emoji" end)
- |> Enum.map(fn %{"icon" => %{"url" => url}, "name" => name} ->
- {String.trim(name, ":"), url}
- end)
- end
-
def fetch_media_type(%{"mediaType" => mediaType}) do
Utils.fetch_media_type(@media_types, mediaType)
end
diff --git a/lib/pleroma/web/streamer/ping.ex b/lib/pleroma/web/streamer/ping.ex
index db3e68abe..7a08202a9 100644
--- a/lib/pleroma/web/streamer/ping.ex
+++ b/lib/pleroma/web/streamer/ping.ex
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.Streamer.Ping do
diff --git a/lib/pleroma/web/streamer/state.ex b/lib/pleroma/web/streamer/state.ex
index 5ce3ebb8a..999550b88 100644
--- a/lib/pleroma/web/streamer/state.ex
+++ b/lib/pleroma/web/streamer/state.ex
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.Streamer.State do
diff --git a/lib/pleroma/web/streamer/streamer.ex b/lib/pleroma/web/streamer/streamer.ex
index 2fc7ac8cf..814d5a729 100644
--- a/lib/pleroma/web/streamer/streamer.ex
+++ b/lib/pleroma/web/streamer/streamer.ex
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.Streamer do
diff --git a/lib/pleroma/web/streamer/streamer_socket.ex b/lib/pleroma/web/streamer/streamer_socket.ex
index cf0fa3077..7d5dcd34e 100644
--- a/lib/pleroma/web/streamer/streamer_socket.ex
+++ b/lib/pleroma/web/streamer/streamer_socket.ex
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.Streamer.StreamerSocket do
diff --git a/lib/pleroma/web/streamer/supervisor.ex b/lib/pleroma/web/streamer/supervisor.ex
index ec5985085..bd9029bc0 100644
--- a/lib/pleroma/web/streamer/supervisor.ex
+++ b/lib/pleroma/web/streamer/supervisor.ex
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.Streamer.Supervisor do
diff --git a/lib/pleroma/web/streamer/worker.ex b/lib/pleroma/web/streamer/worker.ex
index 29f992a67..abfed21c8 100644
--- a/lib/pleroma/web/streamer/worker.ex
+++ b/lib/pleroma/web/streamer/worker.ex
@@ -130,7 +130,7 @@ defmodule Pleroma.Web.Streamer.Worker do
defp should_send?(%User{} = user, %Activity{} = item) do
%{block: blocked_ap_ids, mute: muted_ap_ids, reblog_mute: reblog_muted_ap_ids} =
- User.outgoing_relations_ap_ids(user, [:block, :mute, :reblog_mute])
+ User.outgoing_relationships_ap_ids(user, [:block, :mute, :reblog_mute])
recipient_blocks = MapSet.new(blocked_ap_ids ++ muted_ap_ids)
recipients = MapSet.new(item.recipients)
diff --git a/lib/pleroma/web/templates/feed/feed/_activity.xml.eex b/lib/pleroma/web/templates/feed/feed/_activity.atom.eex
index ac8a75009..78350f2aa 100644
--- a/lib/pleroma/web/templates/feed/feed/_activity.xml.eex
+++ b/lib/pleroma/web/templates/feed/feed/_activity.atom.eex
@@ -2,10 +2,10 @@
<activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type>
<activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb>
<id><%= @data["id"] %></id>
- <title><%= activity_title(@object, Keyword.get(@feed_config, :post_title, %{})) %></title>
- <content type="html"><%= activity_content(@object) %></content>
- <published><%= @data["published"] %></published>
- <updated><%= @data["published"] %></updated>
+ <title><%= activity_title(@data, Keyword.get(@feed_config, :post_title, %{})) %></title>
+ <content type="html"><%= activity_content(@data) %></content>
+ <published><%= @activity.data["published"] %></published>
+ <updated><%= @activity.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
new file mode 100644
index 000000000..a304a16af
--- /dev/null
+++ b/lib/pleroma/web/templates/feed/feed/_activity.rss.eex
@@ -0,0 +1,49 @@
+<item>
+ <activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type>
+ <activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb>
+ <guid><%= @data["id"] %></guid>
+ <title><%= activity_title(@data, Keyword.get(@feed_config, :post_title, %{})) %></title>
+ <description><%= activity_content(@data) %></description>
+ <pubDate><%= @activity.data["published"] %></pubDate>
+ <updated><%= @activity.data["published"] %></updated>
+ <ostatus:conversation ref="<%= activity_context(@activity) %>">
+ <%= activity_context(@activity) %>
+ </ostatus:conversation>
+ <link rel="ostatus:conversation"><%= activity_context(@activity) %></link>
+
+ <%= if @data["summary"] do %>
+ <description><%= @data["summary"] %></description>
+ <% end %>
+
+ <%= if @activity.local do %>
+ <link><%= @data["id"] %></link>
+ <% else %>
+ <link><%= @data["external_url"] %></link>
+ <% end %>
+
+ <%= for tag <- @data["tag"] || [] do %>
+ <category term="<%= tag %>"></category>
+ <% end %>
+
+ <%= for attachment <- @data["attachment"] || [] do %>
+ <link type="<%= attachment_type(attachment) %>"><%= attachment_href(attachment) %></link>
+ <% end %>
+
+ <%= if @data["inReplyTo"] do %>
+ <thr:in-reply-to ref='<%= @data["inReplyTo"] %>' href='<%= get_href(@data["inReplyTo"]) %>'/>
+ <% end %>
+
+ <%= for id <- @activity.recipients do %>
+ <%= if id == Pleroma.Constants.as_public() do %>
+ <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/collection">http://activityschema.org/collection/public</link>
+ <% else %>
+ <%= unless Regex.match?(~r/^#{Pleroma.Web.base_url()}.+followers$/, id) do %>
+ <link rel="mentioned" ostatus:object-type="http://activitystrea.ms/schema/1.0/person"><%= id %></link>
+ <% end %>
+ <% end %>
+ <% end %>
+
+ <%= for {emoji, file} <- @data["emoji"] || %{} do %>
+ <link name="<%= emoji %>" rel="emoji"><%= file %></link>
+ <% end %>
+</item>
diff --git a/lib/pleroma/web/templates/feed/feed/_author.xml.eex b/lib/pleroma/web/templates/feed/feed/_author.atom.eex
index 25cbffada..25cbffada 100644
--- a/lib/pleroma/web/templates/feed/feed/_author.xml.eex
+++ b/lib/pleroma/web/templates/feed/feed/_author.atom.eex
diff --git a/lib/pleroma/web/templates/feed/feed/_author.rss.eex b/lib/pleroma/web/templates/feed/feed/_author.rss.eex
new file mode 100644
index 000000000..526aeddcf
--- /dev/null
+++ b/lib/pleroma/web/templates/feed/feed/_author.rss.eex
@@ -0,0 +1,17 @@
+<managingEditor>
+ <guid><%= @user.ap_id %></guid>
+ <activity:object>http://activitystrea.ms/schema/1.0/person</activity:object>
+ <uri><%= @user.ap_id %></uri>
+ <poco:preferredUsername><%= @user.nickname %></poco:preferredUsername>
+ <poco:displayName><%= @user.name %></poco:displayName>
+ <poco:note><%= escape(@user.bio) %></poco:note>
+ <description><%= escape(@user.bio) %></description>
+ <name><%= @user.nickname %></name>
+ <link rel="avatar"><%= User.avatar_url(@user) %></link>
+ <%= if User.banner_url(@user) do %>
+ <link rel="header"><%= User.banner_url(@user) %></link>
+ <% end %>
+ <%= if @user.local do %>
+ <ap_enabled>true</ap_enabled>
+ <% end %>
+</managingEditor>
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 da4fa6d6c..cf5874a91 100644
--- a/lib/pleroma/web/templates/feed/feed/_tag_activity.atom.eex
+++ b/lib/pleroma/web/templates/feed/feed/_tag_activity.atom.eex
@@ -1,12 +1,12 @@
<entry>
<activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type>
<activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb>
-
+
<%= render @view_module, "_tag_author.atom", assigns %>
-
+
<id><%= @data["id"] %></id>
- <title><%= activity_title(@object, Keyword.get(@feed_config, :post_title, %{})) %></title>
- <content type="html"><%= activity_content(@object) %></content>
+ <title><%= activity_title(@data, Keyword.get(@feed_config, :post_title, %{})) %></title>
+ <content type="html"><%= activity_content(@data) %></content>
<%= if @activity.local do %>
<link type="application/atom+xml" href='<%= @data["id"] %>' rel="self"/>
@@ -15,8 +15,8 @@
<link type="text/html" href='<%= @data["external_url"] %>' rel="alternate"/>
<% end %>
- <published><%= @data["published"] %></published>
- <updated><%= @data["published"] %></updated>
+ <published><%= @activity.data["published"] %></published>
+ <updated><%= @activity.data["published"] %></updated>
<ostatus:conversation ref="<%= activity_context(@activity) %>">
<%= activity_context(@activity) %>
@@ -26,7 +26,7 @@
<%= if @data["summary"] do %>
<summary><%= @data["summary"] %></summary>
<% end %>
-
+
<%= for id <- @activity.recipients do %>
<%= if id == Pleroma.Constants.as_public() do %>
<link rel="mentioned"
@@ -40,7 +40,7 @@
<% end %>
<% end %>
<% end %>
-
+
<%= for tag <- @data["tag"] || [] do %>
<category term="<%= tag %>"></category>
<% end %>
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 295574df1..2334e24a2 100644
--- a/lib/pleroma/web/templates/feed/feed/_tag_activity.xml.eex
+++ b/lib/pleroma/web/templates/feed/feed/_tag_activity.xml.eex
@@ -1,15 +1,14 @@
<item>
- <title><%= activity_title(@object, Keyword.get(@feed_config, :post_title, %{})) %></title>
-
-
+ <title><%= activity_title(@data, Keyword.get(@feed_config, :post_title, %{})) %></title>
+
+
<guid isPermalink="true"><%= activity_context(@activity) %></guid>
<link><%= activity_context(@activity) %></link>
- <pubDate><%= pub_date(@data["published"]) %></pubDate>
-
- <description><%= activity_content(@object) %></description>
+ <pubDate><%= pub_date(@activity.data["published"]) %></pubDate>
+
+ <description><%= activity_content(@data) %></description>
<%= for attachment <- @data["attachment"] || [] do %>
<enclosure url="<%= attachment_href(attachment) %>" type="<%= attachment_type(attachment) %>"/>
<% end %>
-
-</item>
+</item>
diff --git a/lib/pleroma/web/templates/feed/feed/user.xml.eex b/lib/pleroma/web/templates/feed/feed/user.atom.eex
index d274c08ae..c6acd848f 100644
--- a/lib/pleroma/web/templates/feed/feed/user.xml.eex
+++ b/lib/pleroma/web/templates/feed/feed/user.atom.eex
@@ -12,13 +12,13 @@
<logo><%= logo(@user) %></logo>
<link rel="self" href="<%= '#{user_feed_url(@conn, :feed, @user.nickname)}.atom' %>" type="application/atom+xml"/>
- <%= render @view_module, "_author.xml", assigns %>
+ <%= render @view_module, "_author.atom", assigns %>
<%= if last_activity(@activities) do %>
<link rel="next" href="<%= '#{user_feed_url(@conn, :feed, @user.nickname)}.atom?max_id=#{last_activity(@activities).id}' %>" type="application/atom+xml"/>
<% end %>
<%= for activity <- @activities do %>
- <%= render @view_module, "_activity.xml", Map.merge(assigns, prepare_activity(activity)) %>
+ <%= render @view_module, "_activity.atom", Map.merge(assigns, prepare_activity(activity)) %>
<% end %>
</feed>
diff --git a/lib/pleroma/web/templates/feed/feed/user.rss.eex b/lib/pleroma/web/templates/feed/feed/user.rss.eex
new file mode 100644
index 000000000..d69120480
--- /dev/null
+++ b/lib/pleroma/web/templates/feed/feed/user.rss.eex
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<rss version="2.0">
+ <channel>
+ <guid><%= user_feed_url(@conn, :feed, @user.nickname) <> ".rss" %></guid>
+ <title><%= @user.nickname <> "'s timeline" %></title>
+ <updated><%= most_recent_update(@activities, @user) %></updated>
+ <image><%= logo(@user) %></image>
+ <link><%= '#{user_feed_url(@conn, :feed, @user.nickname)}.rss' %></link>
+
+ <%= render @view_module, "_author.rss", assigns %>
+
+ <%= if last_activity(@activities) do %>
+ <link rel="next"><%= '#{user_feed_url(@conn, :feed, @user.nickname)}.rss?max_id=#{last_activity(@activities).id}' %></link>
+ <% end %>
+
+ <%= for activity <- @activities do %>
+ <%= render @view_module, "_activity.rss", Map.merge(assigns, prepare_activity(activity)) %>
+ <% end %>
+ </channel>
+</rss>
diff --git a/lib/pleroma/web/templates/static_fe/static_fe/_user_card.html.eex b/lib/pleroma/web/templates/static_fe/static_fe/_user_card.html.eex
index c7789f9ac..56f3a1524 100644
--- a/lib/pleroma/web/templates/static_fe/static_fe/_user_card.html.eex
+++ b/lib/pleroma/web/templates/static_fe/static_fe/_user_card.html.eex
@@ -1,10 +1,10 @@
<div class="p-author h-card">
- <a class="u-url" rel="author noopener" href="<%= User.profile_url(@user) %>">
+ <a class="u-url" rel="author noopener" href="<%= (@user.uri || @user.ap_id) %>">
<div class="avatar">
<img src="<%= User.avatar_url(@user) |> MediaProxy.url %>" width="48" height="48" alt="">
</div>
<span class="display-name">
- <bdi><%= raw (@user.name |> Formatter.emojify(emoji_for_user(@user))) %></bdi>
+ <bdi><%= raw Formatter.emojify(@user.name, @user.emoji) %></bdi>
<span class="nickname"><%= @user.nickname %></span>
</span>
</a>
diff --git a/lib/pleroma/web/templates/static_fe/static_fe/profile.html.eex b/lib/pleroma/web/templates/static_fe/static_fe/profile.html.eex
index 94063c92d..3191bf450 100644
--- a/lib/pleroma/web/templates/static_fe/static_fe/profile.html.eex
+++ b/lib/pleroma/web/templates/static_fe/static_fe/profile.html.eex
@@ -7,8 +7,8 @@
<input type="hidden" name="profile" value="">
<button type="submit" class="collapse">Remote follow</button>
</form>
- <%= raw Formatter.emojify(@user.name, emoji_for_user(@user)) %> |
- <%= link "@#{@user.nickname}@#{Endpoint.host()}", to: User.profile_url(@user) %>
+ <%= raw Formatter.emojify(@user.name, @user.emoji) %> |
+ <%= link "@#{@user.nickname}@#{Endpoint.host()}", to: (@user.uri || @user.ap_id) %>
</h3>
<p><%= raw @user.bio %></p>
</header>
diff --git a/lib/pleroma/web/translation_helpers.ex b/lib/pleroma/web/translation_helpers.ex
index a104ea6b8..7f78ce1b9 100644
--- a/lib/pleroma/web/translation_helpers.ex
+++ b/lib/pleroma/web/translation_helpers.ex
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.TranslationHelpers do
diff --git a/lib/pleroma/web/twitter_api/controllers/password_controller.ex b/lib/pleroma/web/twitter_api/controllers/password_controller.ex
index 1941e6143..800ab8954 100644
--- a/lib/pleroma/web/twitter_api/controllers/password_controller.ex
+++ b/lib/pleroma/web/twitter_api/controllers/password_controller.ex
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.TwitterAPI.PasswordController do
diff --git a/lib/pleroma/web/twitter_api/controllers/remote_follow_controller.ex b/lib/pleroma/web/twitter_api/controllers/remote_follow_controller.ex
index fbf31c7eb..89da760da 100644
--- a/lib/pleroma/web/twitter_api/controllers/remote_follow_controller.ex
+++ b/lib/pleroma/web/twitter_api/controllers/remote_follow_controller.ex
@@ -16,6 +16,8 @@ defmodule Pleroma.Web.TwitterAPI.RemoteFollowController do
@status_types ["Article", "Event", "Note", "Video", "Page", "Question"]
+ plug(Pleroma.Web.FederatingPlug)
+
# Note: follower can submit the form (with password auth) not being signed in (having no token)
plug(
OAuthScopesPlug,
diff --git a/lib/pleroma/web/twitter_api/controllers/util_controller.ex b/lib/pleroma/web/twitter_api/controllers/util_controller.ex
index bca0e26eb..537f9f778 100644
--- a/lib/pleroma/web/twitter_api/controllers/util_controller.ex
+++ b/lib/pleroma/web/twitter_api/controllers/util_controller.ex
@@ -17,6 +17,8 @@ defmodule Pleroma.Web.TwitterAPI.UtilController do
alias Pleroma.Web.CommonAPI
alias Pleroma.Web.WebFinger
+ plug(Pleroma.Web.FederatingPlug when action == :remote_subscribe)
+
plug(
OAuthScopesPlug,
%{scopes: ["follow", "write:follows"]}
diff --git a/lib/pleroma/web/twitter_api/twitter_api.ex b/lib/pleroma/web/twitter_api/twitter_api.ex
index bfd838902..7a1ba6936 100644
--- a/lib/pleroma/web/twitter_api/twitter_api.ex
+++ b/lib/pleroma/web/twitter_api/twitter_api.ex
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.TwitterAPI.TwitterAPI do
@@ -13,6 +13,7 @@ defmodule Pleroma.Web.TwitterAPI.TwitterAPI do
def register_user(params, opts \\ []) do
token = params["token"]
+ trusted_app? = params["trusted_app"]
params = %{
nickname: params["nickname"],
@@ -29,7 +30,7 @@ defmodule Pleroma.Web.TwitterAPI.TwitterAPI do
captcha_enabled = Pleroma.Config.get([Pleroma.Captcha, :enabled])
# true if captcha is disabled or enabled and valid, false otherwise
captcha_ok =
- if not captcha_enabled do
+ if trusted_app? || not captcha_enabled do
:ok
else
Pleroma.Captcha.validate(
@@ -99,7 +100,8 @@ defmodule Pleroma.Web.TwitterAPI.TwitterAPI do
def password_reset(nickname_or_email) do
with true <- is_binary(nickname_or_email),
- %User{local: true} = user <- User.get_by_nickname_or_email(nickname_or_email),
+ %User{local: true, email: email} = user when not is_nil(email) <-
+ User.get_by_nickname_or_email(nickname_or_email),
{:ok, token_record} <- Pleroma.PasswordResetToken.create_token(user) do
user
|> UserEmail.password_reset_email(token_record.token)
@@ -110,6 +112,9 @@ defmodule Pleroma.Web.TwitterAPI.TwitterAPI do
false ->
{:error, "bad user identifier"}
+ %User{local: true, email: nil} ->
+ {:ok, :noop}
+
%User{local: false} ->
{:error, "remote user"}
diff --git a/lib/pleroma/web/twitter_api/twitter_api_controller.ex b/lib/pleroma/web/twitter_api/twitter_api_controller.ex
index 39f10c49f..31adc2817 100644
--- a/lib/pleroma/web/twitter_api/twitter_api_controller.ex
+++ b/lib/pleroma/web/twitter_api/twitter_api_controller.ex
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.TwitterAPI.Controller do
@@ -15,6 +15,8 @@ defmodule Pleroma.Web.TwitterAPI.Controller do
plug(OAuthScopesPlug, %{scopes: ["write:notifications"]} when action == :notifications_read)
+ plug(:skip_plug, OAuthScopesPlug when action in [:oauth_tokens, :revoke_token])
+
plug(Pleroma.Plugs.EnsurePublicOrAuthenticatedPlug)
action_fallback(:errors)
diff --git a/lib/pleroma/web/twitter_api/views/password_view.ex b/lib/pleroma/web/twitter_api/views/password_view.ex
index b166b925d..41462e4af 100644
--- a/lib/pleroma/web/twitter_api/views/password_view.ex
+++ b/lib/pleroma/web/twitter_api/views/password_view.ex
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.TwitterAPI.PasswordView do
diff --git a/lib/pleroma/web/twitter_api/views/token_view.ex b/lib/pleroma/web/twitter_api/views/token_view.ex
index 3ff314913..c36303625 100644
--- a/lib/pleroma/web/twitter_api/views/token_view.ex
+++ b/lib/pleroma/web/twitter_api/views/token_view.ex
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.TwitterAPI.TokenView do
diff --git a/lib/pleroma/web/twitter_api/views/util_view.ex b/lib/pleroma/web/twitter_api/views/util_view.ex
index f4050650e..52054e020 100644
--- a/lib/pleroma/web/twitter_api/views/util_view.ex
+++ b/lib/pleroma/web/twitter_api/views/util_view.ex
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.TwitterAPI.UtilView do
diff --git a/lib/pleroma/web/uploader_controller.ex b/lib/pleroma/web/uploader_controller.ex
index 0cc172698..6533f1c0e 100644
--- a/lib/pleroma/web/uploader_controller.ex
+++ b/lib/pleroma/web/uploader_controller.ex
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.UploaderController do
diff --git a/lib/pleroma/web/views/error_helpers.ex b/lib/pleroma/web/views/error_helpers.ex
index bc08e60e4..df657a343 100644
--- a/lib/pleroma/web/views/error_helpers.ex
+++ b/lib/pleroma/web/views/error_helpers.ex
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.ErrorHelpers do
diff --git a/lib/pleroma/web/views/error_view.ex b/lib/pleroma/web/views/error_view.ex
index 5cb8669fe..e68d55e08 100644
--- a/lib/pleroma/web/views/error_view.ex
+++ b/lib/pleroma/web/views/error_view.ex
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.ErrorView do
diff --git a/lib/pleroma/web/views/layout_view.ex b/lib/pleroma/web/views/layout_view.ex
index e5183701d..3e49c6549 100644
--- a/lib/pleroma/web/views/layout_view.ex
+++ b/lib/pleroma/web/views/layout_view.ex
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.LayoutView do
diff --git a/lib/pleroma/web/views/masto_fe_view.ex b/lib/pleroma/web/views/masto_fe_view.ex
index c39b7f095..c3096006e 100644
--- a/lib/pleroma/web/views/masto_fe_view.ex
+++ b/lib/pleroma/web/views/masto_fe_view.ex
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.MastoFEView do
diff --git a/lib/pleroma/web/views/streamer_view.ex b/lib/pleroma/web/views/streamer_view.ex
index a9f14d09a..443868878 100644
--- a/lib/pleroma/web/views/streamer_view.ex
+++ b/lib/pleroma/web/views/streamer_view.ex
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.StreamerView do
diff --git a/lib/pleroma/web/web.ex b/lib/pleroma/web/web.ex
index 687346554..bf48ce26c 100644
--- a/lib/pleroma/web/web.ex
+++ b/lib/pleroma/web/web.ex
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web do
@@ -29,11 +29,45 @@ defmodule Pleroma.Web do
import Pleroma.Web.Router.Helpers
import Pleroma.Web.TranslationHelpers
+ alias Pleroma.Plugs.PlugHelper
+
plug(:set_put_layout)
defp set_put_layout(conn, _) do
put_layout(conn, Pleroma.Config.get(:app_layout, "app.html"))
end
+
+ # Marks a plug intentionally skipped and blocks its execution if it's present in plugs chain
+ defp skip_plug(conn, plug_module) do
+ try do
+ plug_module.skip_plug(conn)
+ rescue
+ UndefinedFunctionError ->
+ raise "#{plug_module} is not skippable. Append `use Pleroma.Web, :plug` to its code."
+ end
+ end
+
+ # Executed just before actual controller action, invokes before-action hooks (callbacks)
+ defp action(conn, params) do
+ with %Plug.Conn{halted: false} <- maybe_halt_on_missing_oauth_scopes_check(conn) do
+ super(conn, params)
+ end
+ end
+
+ # Halts if authenticated API action neither performs nor explicitly skips OAuth scopes check
+ defp maybe_halt_on_missing_oauth_scopes_check(conn) do
+ if Pleroma.Plugs.AuthExpectedPlug.auth_expected?(conn) &&
+ not PlugHelper.plug_called_or_skipped?(conn, Pleroma.Plugs.OAuthScopesPlug) do
+ conn
+ |> render_error(
+ :forbidden,
+ "Security violation: OAuth scopes check was neither handled nor explicitly skipped."
+ )
+ |> halt()
+ else
+ conn
+ end
+ end
end
end
@@ -96,6 +130,35 @@ defmodule Pleroma.Web do
end
end
+ def plug do
+ quote do
+ alias Pleroma.Plugs.PlugHelper
+
+ @doc """
+ Marks a plug intentionally skipped and blocks its execution if it's present in plugs chain.
+ """
+ def skip_plug(conn) do
+ PlugHelper.append_to_private_list(
+ conn,
+ PlugHelper.skipped_plugs_list_id(),
+ __MODULE__
+ )
+ end
+
+ @impl Plug
+ @doc "If marked as skipped, returns `conn`, and calls `perform/2` otherwise."
+ def call(%Plug.Conn{} = conn, options) do
+ if PlugHelper.plug_skipped?(conn, __MODULE__) do
+ conn
+ else
+ conn
+ |> PlugHelper.append_to_private_list(PlugHelper.called_plugs_list_id(), __MODULE__)
+ |> perform(options)
+ end
+ end
+ end
+ end
+
@doc """
When used, dispatch to the appropriate controller/view/etc.
"""
diff --git a/lib/pleroma/web/web_finger/web_finger.ex b/lib/pleroma/web/web_finger/web_finger.ex
index b4cc80179..7ffd0e51b 100644
--- a/lib/pleroma/web/web_finger/web_finger.ex
+++ b/lib/pleroma/web/web_finger/web_finger.ex
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.WebFinger do
@@ -173,7 +173,8 @@ defmodule Pleroma.Web.WebFinger do
get_template_from_xml(body)
else
_ ->
- with {:ok, %{body: body}} <- HTTP.get("https://#{domain}/.well-known/host-meta", []) do
+ with {:ok, %{body: body, status: status}} when status in 200..299 <-
+ HTTP.get("https://#{domain}/.well-known/host-meta", []) do
get_template_from_xml(body)
else
e -> {:error, "Can't find LRDD template: #{inspect(e)}"}
@@ -205,7 +206,7 @@ defmodule Pleroma.Web.WebFinger do
with response <-
HTTP.get(
address,
- Accept: "application/xrd+xml,application/jrd+json"
+ [{"accept", "application/xrd+xml,application/jrd+json"}]
),
{:ok, %{status: status, body: body}} when status in 200..299 <- response do
doc = XML.parse_document(body)
diff --git a/lib/pleroma/web/web_finger/web_finger_controller.ex b/lib/pleroma/web/web_finger/web_finger_controller.ex
index 896eb15f9..7077b20d2 100644
--- a/lib/pleroma/web/web_finger/web_finger_controller.ex
+++ b/lib/pleroma/web/web_finger/web_finger_controller.ex
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.WebFinger.WebFingerController do
diff --git a/lib/pleroma/web/xml/xml.ex b/lib/pleroma/web/xml/xml.ex
index df50aac9c..c69a86a1e 100644
--- a/lib/pleroma/web/xml/xml.ex
+++ b/lib/pleroma/web/xml/xml.ex
@@ -1,5 +1,5 @@
# Pleroma: A lightweight social networking server
-# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/>
+# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.XML do