diff options
Diffstat (limited to 'lib')
21 files changed, 360 insertions, 182 deletions
diff --git a/lib/mix/tasks/pleroma/config.ex b/lib/mix/tasks/pleroma/config.ex index 11e4fde43..0e21408b2 100644 --- a/lib/mix/tasks/pleroma/config.ex +++ b/lib/mix/tasks/pleroma/config.ex @@ -45,7 +45,7 @@ defmodule Mix.Tasks.Pleroma.Config do if Pleroma.Config.get([:instance, :dynamic_configuration]) do config_path = "config/#{env}.exported_from_db.secret.exs" - {:ok, file} = File.open(config_path, [:write]) + {:ok, file} = File.open(config_path, [:write, :utf8]) IO.write(file, "use Mix.Config\r\n") Repo.all(Config) diff --git a/lib/pleroma/application.ex b/lib/pleroma/application.ex index d681eecc8..2b6a55f98 100644 --- a/lib/pleroma/application.ex +++ b/lib/pleroma/application.ex @@ -36,7 +36,8 @@ defmodule Pleroma.Application do Pleroma.Emoji, Pleroma.Captcha, Pleroma.Daemons.ScheduledActivityDaemon, - Pleroma.Daemons.ActivityExpirationDaemon + Pleroma.Daemons.ActivityExpirationDaemon, + Pleroma.Plugs.RateLimiter.Supervisor ] ++ cachex_children() ++ hackney_pool_children() ++ diff --git a/lib/pleroma/docs/json.ex b/lib/pleroma/docs/json.ex index 18ba01d58..f2a56d845 100644 --- a/lib/pleroma/docs/json.ex +++ b/lib/pleroma/docs/json.ex @@ -5,7 +5,7 @@ defmodule Pleroma.Docs.JSON do def process(descriptions) do config_path = "docs/generate_config.json" - with {:ok, file} <- File.open(config_path, [:write]), + with {:ok, file} <- File.open(config_path, [:write, :utf8]), json <- generate_json(descriptions), :ok <- IO.write(file, json), :ok <- File.close(file) do diff --git a/lib/pleroma/plugs/rate_limiter.ex b/lib/pleroma/plugs/rate_limiter.ex deleted file mode 100644 index 31388f574..000000000 --- a/lib/pleroma/plugs/rate_limiter.ex +++ /dev/null @@ -1,131 +0,0 @@ -# Pleroma: A lightweight social networking server -# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/> -# SPDX-License-Identifier: AGPL-3.0-only - -defmodule Pleroma.Plugs.RateLimiter do - @moduledoc """ - - ## Configuration - - A keyword list of rate limiters where a key is a limiter name and value is the limiter configuration. The basic configuration is a tuple where: - - * The first element: `scale` (Integer). The time scale in milliseconds. - * The second element: `limit` (Integer). How many requests to limit in the time scale provided. - - It is also possible to have different limits for unauthenticated and authenticated users: the keyword value must be a list of two tuples where the first one is a config for unauthenticated users and the second one is for authenticated. - - To disable a limiter set its value to `nil`. - - ### Example - - config :pleroma, :rate_limit, - one: {1000, 10}, - two: [{10_000, 10}, {10_000, 50}], - foobar: nil - - Here we have three limiters: - - * `one` which is not over 10req/1s - * `two` which has two limits: 10req/10s for unauthenticated users and 50req/10s for authenticated users - * `foobar` which is disabled - - ## Usage - - AllowedSyntax: - - plug(Pleroma.Plugs.RateLimiter, :limiter_name) - plug(Pleroma.Plugs.RateLimiter, {:limiter_name, options}) - - Allowed options: - - * `bucket_name` overrides bucket name (e.g. to have a separate limit for a set of actions) - * `params` appends values of specified request params (e.g. ["id"]) to bucket name - - Inside a controller: - - plug(Pleroma.Plugs.RateLimiter, :one when action == :one) - plug(Pleroma.Plugs.RateLimiter, :two when action in [:two, :three]) - - plug( - Pleroma.Plugs.RateLimiter, - {:status_id_action, bucket_name: "status_id_action:fav_unfav", params: ["id"]} - when action in ~w(fav_status unfav_status)a - ) - - or inside a router pipeline: - - pipeline :api do - ... - plug(Pleroma.Plugs.RateLimiter, :one) - ... - end - """ - import Pleroma.Web.TranslationHelpers - import Plug.Conn - - alias Pleroma.User - - def init(limiter_name) when is_atom(limiter_name) do - init({limiter_name, []}) - end - - def init({limiter_name, opts}) do - case Pleroma.Config.get([:rate_limit, limiter_name]) do - nil -> nil - config -> {limiter_name, config, opts} - end - end - - # Do not limit if there is no limiter configuration - def call(conn, nil), do: conn - - def call(conn, settings) do - case check_rate(conn, settings) do - {:ok, _count} -> - conn - - {:error, _count} -> - render_throttled_error(conn) - end - end - - defp bucket_name(conn, limiter_name, opts) do - bucket_name = opts[:bucket_name] || limiter_name - - if params_names = opts[:params] do - params_values = for p <- Enum.sort(params_names), do: conn.params[p] - Enum.join([bucket_name] ++ params_values, ":") - else - bucket_name - end - end - - defp check_rate( - %{assigns: %{user: %User{id: user_id}}} = conn, - {limiter_name, [_, {scale, limit}], opts} - ) do - bucket_name = bucket_name(conn, limiter_name, opts) - ExRated.check_rate("#{bucket_name}:#{user_id}", scale, limit) - end - - defp check_rate(conn, {limiter_name, [{scale, limit} | _], opts}) do - bucket_name = bucket_name(conn, limiter_name, opts) - ExRated.check_rate("#{bucket_name}:#{ip(conn)}", scale, limit) - end - - defp check_rate(conn, {limiter_name, {scale, limit}, opts}) do - check_rate(conn, {limiter_name, [{scale, limit}, {scale, limit}], opts}) - end - - def ip(%{remote_ip: remote_ip}) do - remote_ip - |> Tuple.to_list() - |> Enum.join(".") - end - - defp render_throttled_error(conn) do - conn - |> render_error(:too_many_requests, "Throttled") - |> halt() - end -end diff --git a/lib/pleroma/plugs/rate_limiter/limiter_supervisor.ex b/lib/pleroma/plugs/rate_limiter/limiter_supervisor.ex new file mode 100644 index 000000000..187582ede --- /dev/null +++ b/lib/pleroma/plugs/rate_limiter/limiter_supervisor.ex @@ -0,0 +1,44 @@ +defmodule Pleroma.Plugs.RateLimiter.LimiterSupervisor do + use DynamicSupervisor + + import Cachex.Spec + + def start_link(init_arg) do + DynamicSupervisor.start_link(__MODULE__, init_arg, name: __MODULE__) + end + + def add_limiter(limiter_name, expiration) do + {:ok, _pid} = + DynamicSupervisor.start_child( + __MODULE__, + %{ + id: String.to_atom("rl_#{limiter_name}"), + start: + {Cachex, :start_link, + [ + limiter_name, + [ + expiration: + expiration( + default: expiration, + interval: check_interval(expiration), + lazy: true + ) + ] + ]} + } + ) + end + + @impl true + def init(_init_arg) do + DynamicSupervisor.init(strategy: :one_for_one) + end + + defp check_interval(exp) do + (exp / 2) + |> Kernel.trunc() + |> Kernel.min(5000) + |> Kernel.max(1) + end +end diff --git a/lib/pleroma/plugs/rate_limiter/rate_limiter.ex b/lib/pleroma/plugs/rate_limiter/rate_limiter.ex new file mode 100644 index 000000000..d720508c8 --- /dev/null +++ b/lib/pleroma/plugs/rate_limiter/rate_limiter.ex @@ -0,0 +1,227 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Plugs.RateLimiter do + @moduledoc """ + + ## Configuration + + A keyword list of rate limiters where a key is a limiter name and value is the limiter configuration. The basic configuration is a tuple where: + + * The first element: `scale` (Integer). The time scale in milliseconds. + * The second element: `limit` (Integer). How many requests to limit in the time scale provided. + + It is also possible to have different limits for unauthenticated and authenticated users: the keyword value must be a list of two tuples where the first one is a config for unauthenticated users and the second one is for authenticated. + + To disable a limiter set its value to `nil`. + + ### Example + + config :pleroma, :rate_limit, + one: {1000, 10}, + two: [{10_000, 10}, {10_000, 50}], + foobar: nil + + Here we have three limiters: + + * `one` which is not over 10req/1s + * `two` which has two limits: 10req/10s for unauthenticated users and 50req/10s for authenticated users + * `foobar` which is disabled + + ## Usage + + AllowedSyntax: + + plug(Pleroma.Plugs.RateLimiter, name: :limiter_name) + plug(Pleroma.Plugs.RateLimiter, options) # :name is a required option + + Allowed options: + + * `name` required, always used to fetch the limit values from the config + * `bucket_name` overrides name for counting purposes (e.g. to have a separate limit for a set of actions) + * `params` appends values of specified request params (e.g. ["id"]) to bucket name + + Inside a controller: + + plug(Pleroma.Plugs.RateLimiter, [name: :one] when action == :one) + plug(Pleroma.Plugs.RateLimiter, [name: :two] when action in [:two, :three]) + + plug( + Pleroma.Plugs.RateLimiter, + [name: :status_id_action, bucket_name: "status_id_action:fav_unfav", params: ["id"]] + when action in ~w(fav_status unfav_status)a + ) + + or inside a router pipeline: + + pipeline :api do + ... + plug(Pleroma.Plugs.RateLimiter, name: :one) + ... + end + """ + import Pleroma.Web.TranslationHelpers + import Plug.Conn + + alias Pleroma.Plugs.RateLimiter.LimiterSupervisor + alias Pleroma.User + + def init(opts) do + limiter_name = Keyword.get(opts, :name) + + case Pleroma.Config.get([:rate_limit, limiter_name]) do + nil -> + nil + + config -> + name_root = Keyword.get(opts, :bucket_name, limiter_name) + + %{ + name: name_root, + limits: config, + opts: opts + } + end + end + + # Do not limit if there is no limiter configuration + def call(conn, nil), do: conn + + def call(conn, settings) do + settings + |> incorporate_conn_info(conn) + |> check_rate() + |> case do + {:ok, _count} -> + conn + + {:error, _count} -> + render_throttled_error(conn) + end + end + + def inspect_bucket(conn, name_root, settings) do + settings = + settings + |> incorporate_conn_info(conn) + + bucket_name = make_bucket_name(%{settings | name: name_root}) + key_name = make_key_name(settings) + limit = get_limits(settings) + + case Cachex.get(bucket_name, key_name) do + {:error, :no_cache} -> + {:err, :not_found} + + {:ok, nil} -> + {0, limit} + + {:ok, value} -> + {value, limit - value} + end + end + + defp check_rate(settings) do + bucket_name = make_bucket_name(settings) + key_name = make_key_name(settings) + limit = get_limits(settings) + + case Cachex.get_and_update(bucket_name, key_name, &increment_value(&1, limit)) do + {:commit, value} -> + {:ok, value} + + {:ignore, value} -> + {:error, value} + + {:error, :no_cache} -> + initialize_buckets(settings) + check_rate(settings) + end + end + + defp increment_value(nil, _limit), do: {:commit, 1} + + defp increment_value(val, limit) when val >= limit, do: {:ignore, val} + + defp increment_value(val, _limit), do: {:commit, val + 1} + + defp incorporate_conn_info(settings, %{assigns: %{user: %User{id: user_id}}, params: params}) do + Map.merge(settings, %{ + mode: :user, + conn_params: params, + conn_info: "#{user_id}" + }) + end + + defp incorporate_conn_info(settings, %{params: params} = conn) do + Map.merge(settings, %{ + mode: :anon, + conn_params: params, + conn_info: "#{ip(conn)}" + }) + end + + defp ip(%{remote_ip: remote_ip}) do + remote_ip + |> Tuple.to_list() + |> Enum.join(".") + end + + defp render_throttled_error(conn) do + conn + |> render_error(:too_many_requests, "Throttled") + |> halt() + end + + defp make_key_name(settings) do + "" + |> attach_params(settings) + |> attach_identity(settings) + end + + defp get_scale(_, {scale, _}), do: scale + + defp get_scale(:anon, [{scale, _}, {_, _}]), do: scale + + defp get_scale(:user, [{_, _}, {scale, _}]), do: scale + + defp get_limits(%{limits: {_scale, limit}}), do: limit + + defp get_limits(%{mode: :user, limits: [_, {_, limit}]}), do: limit + + defp get_limits(%{limits: [{_, limit}, _]}), do: limit + + defp make_bucket_name(%{mode: :user, name: name_root}), + do: user_bucket_name(name_root) + + defp make_bucket_name(%{mode: :anon, name: name_root}), + do: anon_bucket_name(name_root) + + defp attach_params(input, %{conn_params: conn_params, opts: opts}) do + param_string = + opts + |> Keyword.get(:params, []) + |> Enum.sort() + |> Enum.map(&Map.get(conn_params, &1, "")) + |> Enum.join(":") + + "#{input}#{param_string}" + end + + defp initialize_buckets(%{name: _name, limits: nil}), do: :ok + + defp initialize_buckets(%{name: name, limits: limits}) do + LimiterSupervisor.add_limiter(anon_bucket_name(name), get_scale(:anon, limits)) + LimiterSupervisor.add_limiter(user_bucket_name(name), get_scale(:user, limits)) + end + + defp attach_identity(base, %{mode: :user, conn_info: conn_info}), + do: "user:#{base}:#{conn_info}" + + defp attach_identity(base, %{mode: :anon, conn_info: conn_info}), + do: "ip:#{base}:#{conn_info}" + + defp user_bucket_name(name_root), do: "user:#{name_root}" |> String.to_atom() + defp anon_bucket_name(name_root), do: "anon:#{name_root}" |> String.to_atom() +end diff --git a/lib/pleroma/plugs/rate_limiter/supervisor.ex b/lib/pleroma/plugs/rate_limiter/supervisor.ex new file mode 100644 index 000000000..9672f7876 --- /dev/null +++ b/lib/pleroma/plugs/rate_limiter/supervisor.ex @@ -0,0 +1,16 @@ +defmodule Pleroma.Plugs.RateLimiter.Supervisor do + use Supervisor + + def start_link(opts) do + Supervisor.start_link(__MODULE__, opts, name: __MODULE__) + end + + def init(_args) do + children = [ + Pleroma.Plugs.RateLimiter.LimiterSupervisor + ] + + opts = [strategy: :one_for_one, name: Pleroma.Web.Streamer.Supervisor] + Supervisor.init(children, opts) + end +end diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex index 51a9c6169..65dd251f3 100644 --- a/lib/pleroma/web/activity_pub/activity_pub.ex +++ b/lib/pleroma/web/activity_pub/activity_pub.ex @@ -568,7 +568,6 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do |> fetch_activities_query(opts) |> restrict_unlisted() |> Pagination.fetch_paginated(opts, pagination) - |> Enum.reverse() end @valid_visibilities ~w[direct unlisted public private] diff --git a/lib/pleroma/web/feed/feed_controller.ex b/lib/pleroma/web/feed/feed_controller.ex index d91ecef9c..d0e23007d 100644 --- a/lib/pleroma/web/feed/feed_controller.ex +++ b/lib/pleroma/web/feed/feed_controller.ex @@ -33,21 +33,22 @@ defmodule Pleroma.Web.Feed.FeedController do def feed(conn, %{"nickname" => nickname} = params) do with {_, %User{} = user} <- {:fetch_user, User.get_cached_by_nickname(nickname)} do - query_params = - params - |> Map.take(["max_id"]) - |> Map.put("type", ["Create"]) - |> Map.put("whole_db", true) - |> Map.put("actor_id", user.ap_id) - activities = - query_params + %{ + "type" => ["Create"], + "whole_db" => true, + "actor_id" => user.ap_id + } + |> Map.merge(Map.take(params, ["max_id"])) |> ActivityPub.fetch_public_activities() - |> Enum.reverse() conn |> put_resp_content_type("application/atom+xml") - |> render("feed.xml", user: user, activities: activities) + |> render("feed.xml", + user: user, + activities: activities, + feed_config: Pleroma.Config.get([:feed]) + ) end end diff --git a/lib/pleroma/web/feed/feed_view.ex b/lib/pleroma/web/feed/feed_view.ex index 5eef1e757..bb1332fd3 100644 --- a/lib/pleroma/web/feed/feed_view.ex +++ b/lib/pleroma/web/feed/feed_view.ex @@ -6,12 +6,23 @@ defmodule Pleroma.Web.Feed.FeedView do use Phoenix.HTML use Pleroma.Web, :view + alias Pleroma.Formatter alias Pleroma.Object alias Pleroma.User alias Pleroma.Web.MediaProxy require Pleroma.Constants + def prepare_activity(activity) do + object = activity_object(activity) + + %{ + activity: activity, + data: Map.get(object, :data), + object: object + } + end + def most_recent_update(activities, user) do (List.first(activities) || user).updated_at |> NaiveDateTime.to_iso8601() @@ -23,31 +34,23 @@ defmodule Pleroma.Web.Feed.FeedView do |> MediaProxy.url() end - def last_activity(activities) do - List.last(activities) - end + def last_activity(activities), do: List.last(activities) - def activity_object(activity) do - Object.normalize(activity) - end + def activity_object(activity), do: Object.normalize(activity) - def activity_object_data(activity) do - activity - |> activity_object() - |> Map.get(:data) + def activity_title(%{data: %{"content" => content}}, opts \\ %{}) do + content + |> Formatter.truncate(opts[:max_length], opts[:omission]) + |> escape() end - def activity_content(activity) do - content = activity_object_data(activity)["content"] - + def activity_content(%{data: %{"content" => content}}) do content |> String.replace(~r/[\n\r]/, "") |> escape() end - def activity_context(activity) do - activity.data["context"] - end + def activity_context(activity), do: activity.data["context"] def attachment_href(attachment) do attachment["url"] diff --git a/lib/pleroma/web/mastodon_api/controllers/account_controller.ex b/lib/pleroma/web/mastodon_api/controllers/account_controller.ex index 73fad519e..5b01b964b 100644 --- a/lib/pleroma/web/mastodon_api/controllers/account_controller.ex +++ b/lib/pleroma/web/mastodon_api/controllers/account_controller.ex @@ -66,9 +66,9 @@ defmodule Pleroma.Web.MastodonAPI.AccountController do @relations [:follow, :unfollow] @needs_account ~W(followers following lists follow unfollow mute unmute block unblock)a - plug(RateLimiter, {:relations_id_action, params: ["id", "uri"]} when action in @relations) - plug(RateLimiter, :relations_actions when action in @relations) - plug(RateLimiter, :app_account_creation when action == :create) + 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: :app_account_creation] when action == :create) plug(:assign_account_by_id when action in @needs_account) action_fallback(Pleroma.Web.MastodonAPI.FallbackController) diff --git a/lib/pleroma/web/mastodon_api/controllers/auth_controller.ex b/lib/pleroma/web/mastodon_api/controllers/auth_controller.ex index bfd5120ba..d9e51de7f 100644 --- a/lib/pleroma/web/mastodon_api/controllers/auth_controller.ex +++ b/lib/pleroma/web/mastodon_api/controllers/auth_controller.ex @@ -15,7 +15,7 @@ defmodule Pleroma.Web.MastodonAPI.AuthController do @local_mastodon_name "Mastodon-Local" - plug(Pleroma.Plugs.RateLimiter, :password_reset when action == :password_reset) + plug(Pleroma.Plugs.RateLimiter, [name: :password_reset] when action == :password_reset) @doc "GET /web/login" def login(%{assigns: %{user: %User{}}} = conn, _params) do diff --git a/lib/pleroma/web/mastodon_api/controllers/search_controller.ex b/lib/pleroma/web/mastodon_api/controllers/search_controller.ex index 6cfd68a84..0a929f55b 100644 --- a/lib/pleroma/web/mastodon_api/controllers/search_controller.ex +++ b/lib/pleroma/web/mastodon_api/controllers/search_controller.ex @@ -22,7 +22,7 @@ defmodule Pleroma.Web.MastodonAPI.SearchController do plug(Pleroma.Plugs.EnsurePublicOrAuthenticatedPlug) - plug(RateLimiter, :search when action in [:search, :search2, :account_search]) + plug(RateLimiter, [name: :search] when action in [:search, :search2, :account_search]) def account_search(%{assigns: %{user: user}} = conn, %{"q" => query} = params) do accounts = User.search(query, search_options(params, user)) diff --git a/lib/pleroma/web/mastodon_api/controllers/status_controller.ex b/lib/pleroma/web/mastodon_api/controllers/status_controller.ex index e5d016f63..74b223cf4 100644 --- a/lib/pleroma/web/mastodon_api/controllers/status_controller.ex +++ b/lib/pleroma/web/mastodon_api/controllers/status_controller.ex @@ -82,17 +82,17 @@ defmodule Pleroma.Web.MastodonAPI.StatusController do plug( RateLimiter, - {:status_id_action, bucket_name: "status_id_action:reblog_unreblog", params: ["id"]} + [name: :status_id_action, bucket_name: "status_id_action:reblog_unreblog", params: ["id"]] when action in ~w(reblog unreblog)a ) plug( RateLimiter, - {:status_id_action, bucket_name: "status_id_action:fav_unfav", params: ["id"]} + [name: :status_id_action, bucket_name: "status_id_action:fav_unfav", params: ["id"]] when action in ~w(favourite unfavourite)a ) - plug(RateLimiter, :statuses_actions when action in @rate_limited_status_actions) + plug(RateLimiter, [name: :statuses_actions] when action in @rate_limited_status_actions) action_fallback(Pleroma.Web.MastodonAPI.FallbackController) diff --git a/lib/pleroma/web/mastodon_api/controllers/timeline_controller.ex b/lib/pleroma/web/mastodon_api/controllers/timeline_controller.ex index f2d2d3ccb..384159336 100644 --- a/lib/pleroma/web/mastodon_api/controllers/timeline_controller.ex +++ b/lib/pleroma/web/mastodon_api/controllers/timeline_controller.ex @@ -71,7 +71,6 @@ defmodule Pleroma.Web.MastodonAPI.TimelineController do |> Map.put("blocking_user", user) |> Map.put("muting_user", user) |> ActivityPub.fetch_public_activities() - |> Enum.reverse() conn |> add_link_headers(activities, %{"local" => local_only}) @@ -110,7 +109,6 @@ defmodule Pleroma.Web.MastodonAPI.TimelineController do |> Map.put("tag_all", tag_all) |> Map.put("tag_reject", tag_reject) |> ActivityPub.fetch_public_activities() - |> Enum.reverse() conn |> add_link_headers(activities, %{"local" => local_only}) diff --git a/lib/pleroma/web/mongooseim/mongoose_im_controller.ex b/lib/pleroma/web/mongooseim/mongoose_im_controller.ex index 6ed181cff..358600e7d 100644 --- a/lib/pleroma/web/mongooseim/mongoose_im_controller.ex +++ b/lib/pleroma/web/mongooseim/mongoose_im_controller.ex @@ -10,8 +10,8 @@ defmodule Pleroma.Web.MongooseIM.MongooseIMController do alias Pleroma.Repo alias Pleroma.User - plug(RateLimiter, :authentication when action in [:user_exists, :check_password]) - plug(RateLimiter, {:authentication, params: ["user"]} when action == :check_password) + plug(RateLimiter, [name: :authentication] when action in [:user_exists, :check_password]) + plug(RateLimiter, [name: :authentication, params: ["user"]] when action == :check_password) def user_exists(conn, %{"user" => username}) do with %User{} <- Repo.get_by(User, nickname: username, local: true) do diff --git a/lib/pleroma/web/oauth/oauth_controller.ex b/lib/pleroma/web/oauth/oauth_controller.ex index fe71aca8c..2aee8cab2 100644 --- a/lib/pleroma/web/oauth/oauth_controller.ex +++ b/lib/pleroma/web/oauth/oauth_controller.ex @@ -6,6 +6,7 @@ defmodule Pleroma.Web.OAuth.OAuthController do use Pleroma.Web, :controller alias Pleroma.Helpers.UriHelper + alias Pleroma.Plugs.RateLimiter alias Pleroma.Registration alias Pleroma.Repo alias Pleroma.User @@ -24,7 +25,7 @@ defmodule Pleroma.Web.OAuth.OAuthController do plug(:fetch_session) plug(:fetch_flash) - plug(Pleroma.Plugs.RateLimiter, :authentication when action == :create_authorization) + plug(RateLimiter, [name: :authentication] when action == :create_authorization) action_fallback(Pleroma.Web.OAuth.FallbackController) @@ -36,7 +37,7 @@ defmodule Pleroma.Web.OAuth.OAuthController do authorize(conn, Map.merge(params, auth_attrs)) end - def authorize(%Plug.Conn{assigns: %{token: %Token{}}} = conn, params) do + def authorize(%Plug.Conn{assigns: %{token: %Token{}}} = conn, %{"force_login" => _} = params) do if ControllerHelper.truthy_param?(params["force_login"]) do do_authorize(conn, params) else @@ -44,6 +45,22 @@ defmodule Pleroma.Web.OAuth.OAuthController do end end + # Note: the token is set in oauth_plug, but the token and client do not always go together. + # For example, MastodonFE's token is set if user requests with another client, + # after user already authorized to MastodonFE. + # So we have to check client and token. + def authorize( + %Plug.Conn{assigns: %{token: %Token{} = token}} = conn, + %{"client_id" => client_id} = params + ) do + with %Token{} = t <- Repo.get_by(Token, token: token.token) |> Repo.preload(:app), + ^client_id <- t.app.client_id do + handle_existing_authorization(conn, params) + else + _ -> do_authorize(conn, params) + end + end + def authorize(%Plug.Conn{} = conn, params), do: do_authorize(conn, params) defp do_authorize(%Plug.Conn{} = conn, params) do diff --git a/lib/pleroma/web/ostatus/ostatus_controller.ex b/lib/pleroma/web/ostatus/ostatus_controller.ex index 6958519de..12a7c2365 100644 --- a/lib/pleroma/web/ostatus/ostatus_controller.ex +++ b/lib/pleroma/web/ostatus/ostatus_controller.ex @@ -8,6 +8,7 @@ defmodule Pleroma.Web.OStatus.OStatusController do alias Fallback.RedirectController alias Pleroma.Activity alias Pleroma.Object + alias Pleroma.Plugs.RateLimiter alias Pleroma.User alias Pleroma.Web.ActivityPub.ActivityPubController alias Pleroma.Web.ActivityPub.ObjectView @@ -17,8 +18,8 @@ defmodule Pleroma.Web.OStatus.OStatusController do alias Pleroma.Web.Router plug( - Pleroma.Plugs.RateLimiter, - {:ap_routes, params: ["uuid"]} when action in [:object, :activity] + RateLimiter, + [name: :ap_routes, params: ["uuid"]] when action in [:object, :activity] ) plug( diff --git a/lib/pleroma/web/pleroma_api/controllers/account_controller.ex b/lib/pleroma/web/pleroma_api/controllers/account_controller.ex index db6faac83..bc2f1017c 100644 --- a/lib/pleroma/web/pleroma_api/controllers/account_controller.ex +++ b/lib/pleroma/web/pleroma_api/controllers/account_controller.ex @@ -42,7 +42,7 @@ defmodule Pleroma.Web.PleromaAPI.AccountController do when action != :confirmation_resend ) - plug(RateLimiter, :account_confirmation_resend when action == :confirmation_resend) + plug(RateLimiter, [name: :account_confirmation_resend] when action == :confirmation_resend) plug(:assign_account_by_id when action in [:favourites, :subscribe, :unsubscribe]) plug(:put_view, Pleroma.Web.MastodonAPI.AccountView) diff --git a/lib/pleroma/web/templates/feed/feed/_activity.xml.eex b/lib/pleroma/web/templates/feed/feed/_activity.xml.eex index d1f5e903c..514eacaed 100644 --- a/lib/pleroma/web/templates/feed/feed/_activity.xml.eex +++ b/lib/pleroma/web/templates/feed/feed/_activity.xml.eex @@ -2,11 +2,13 @@ <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><%= "New note by #{@user.nickname}" %></title> - <content type="html"><%= activity_content(@activity) %></content> + <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> - <ostatus:conversation ref="<%= activity_context(@activity) %>"><%= activity_context(@activity) %></ostatus:conversation> + <ostatus:conversation ref="<%= activity_context(@activity) %>"> + <%= activity_context(@activity) %> + </ostatus:conversation> <link ref="<%= activity_context(@activity) %>" rel="ostatus:conversation"/> <%= if @data["summary"] do %> diff --git a/lib/pleroma/web/templates/feed/feed/feed.xml.eex b/lib/pleroma/web/templates/feed/feed/feed.xml.eex index 45df9dc09..5ae36d345 100644 --- a/lib/pleroma/web/templates/feed/feed/feed.xml.eex +++ b/lib/pleroma/web/templates/feed/feed/feed.xml.eex @@ -19,6 +19,6 @@ <% end %> <%= for activity <- @activities do %> - <%= render @view_module, "_activity.xml", Map.merge(assigns, %{activity: activity, data: activity_object_data(activity)}) %> + <%= render @view_module, "_activity.xml", Map.merge(assigns, prepare_activity(activity)) %> <% end %> </feed> |