diff options
-rw-r--r-- | config/config.exs | 4 | ||||
-rw-r--r-- | config/description.exs | 19 | ||||
-rw-r--r-- | config/test.exs | 2 | ||||
-rw-r--r-- | docs/configuration/cheatsheet.md | 8 | ||||
-rw-r--r-- | lib/pleroma/plugs/rate_limiter/rate_limiter.ex | 27 | ||||
-rw-r--r-- | lib/pleroma/plugs/remote_ip.ex | 7 | ||||
-rw-r--r-- | lib/pleroma/user.ex | 32 | ||||
-rw-r--r-- | lib/pleroma/web/activity_pub/utils.ex | 39 | ||||
-rw-r--r-- | lib/pleroma/web/pleroma_api/controllers/pleroma_api_controller.ex | 33 | ||||
-rw-r--r-- | lib/pleroma/workers/background_worker.ex | 4 | ||||
-rw-r--r-- | priv/repo/migrations/20200314123607_config_remove_fetch_initial_posts.exs | 10 | ||||
-rw-r--r-- | priv/repo/migrations/20200315125756_delete_fetch_initial_posts_jobs.exs | 10 | ||||
-rw-r--r-- | test/plugs/rate_limiter_test.exs | 76 | ||||
-rw-r--r-- | test/web/activity_pub/utils_test.exs | 65 | ||||
-rw-r--r-- | test/web/mastodon_api/controllers/account_controller_test.exs | 4 |
15 files changed, 97 insertions, 243 deletions
diff --git a/config/config.exs b/config/config.exs index 2cd741213..3357e23e7 100644 --- a/config/config.exs +++ b/config/config.exs @@ -504,10 +504,6 @@ config :pleroma, :workers, federator_outgoing: 5 ] -config :pleroma, :fetch_initial_posts, - enabled: false, - pages: 5 - config :auto_linker, opts: [ extra: true, diff --git a/config/description.exs b/config/description.exs index 9fdcfcd96..c0e403b2e 100644 --- a/config/description.exs +++ b/config/description.exs @@ -2008,25 +2008,6 @@ config :pleroma, :config_description, [ ] }, %{ - group: :pleroma, - key: :fetch_initial_posts, - type: :group, - description: "Fetching initial posts settings", - children: [ - %{ - key: :enabled, - type: :boolean, - description: "Fetch posts when a new user is federated with" - }, - %{ - key: :pages, - type: :integer, - description: "The amount of pages to fetch", - suggestions: [5] - } - ] - }, - %{ group: :auto_linker, key: :opts, type: :group, diff --git a/config/test.exs b/config/test.exs index a17886265..b8ea63c94 100644 --- a/config/test.exs +++ b/config/test.exs @@ -92,6 +92,8 @@ config :pleroma, :modules, runtime_dir: "test/fixtures/modules" config :pleroma, Pleroma.Emails.NewUsersDigestEmail, enabled: true +config :pleroma, Pleroma.Plugs.RemoteIp, enabled: false + if File.exists?("./config/test.secret.exs") do import_config "test.secret.exs" else diff --git a/docs/configuration/cheatsheet.md b/docs/configuration/cheatsheet.md index 05fd6ceb1..2629385da 100644 --- a/docs/configuration/cheatsheet.md +++ b/docs/configuration/cheatsheet.md @@ -151,14 +151,6 @@ config :pleroma, :mrf_user_allowlist, * `sign_object_fetches`: Sign object fetches with HTTP signatures * `authorized_fetch_mode`: Require HTTP signatures for AP fetches -### :fetch_initial_posts - -!!! warning - Be careful with this setting, fetching posts may lead to new users being discovered whose posts will then also be fetched. This can lead to serious load on your instance and database. - -* `enabled`: If enabled, when a new user is discovered by your instance, fetch some of their latest posts. -* `pages`: The amount of pages to fetch - ## Pleroma.ScheduledActivity * `daily_user_limit`: the number of scheduled activities a user is allowed to create in a single day (Default: `25`) diff --git a/lib/pleroma/plugs/rate_limiter/rate_limiter.ex b/lib/pleroma/plugs/rate_limiter/rate_limiter.ex index c3f6351c8..1529da717 100644 --- a/lib/pleroma/plugs/rate_limiter/rate_limiter.ex +++ b/lib/pleroma/plugs/rate_limiter/rate_limiter.ex @@ -78,7 +78,7 @@ defmodule Pleroma.Plugs.RateLimiter do end def call(conn, plug_opts) do - if disabled?() do + if disabled?(conn) do handle_disabled(conn) else action_settings = action_settings(plug_opts) @@ -87,9 +87,9 @@ defmodule Pleroma.Plugs.RateLimiter do end defp handle_disabled(conn) do - if Config.get(:env) == :prod do - Logger.warn("Rate limiter is disabled for localhost/socket") - end + Logger.warn( + "Rate limiter disabled due to forwarded IP not being found. Please ensure your reverse proxy is providing the X-Forwarded-For header or disable the RemoteIP plug/rate limiter." + ) conn end @@ -109,16 +109,21 @@ defmodule Pleroma.Plugs.RateLimiter do end end - def disabled? do + def disabled?(conn) do localhost_or_socket = - Config.get([Pleroma.Web.Endpoint, :http, :ip]) - |> Tuple.to_list() - |> Enum.join(".") - |> String.match?(~r/^local|^127.0.0.1/) + case Config.get([Pleroma.Web.Endpoint, :http, :ip]) do + {127, 0, 0, 1} -> true + {0, 0, 0, 0, 0, 0, 0, 1} -> true + {:local, _} -> true + _ -> false + end - remote_ip_disabled = not Config.get([Pleroma.Plugs.RemoteIp, :enabled]) + remote_ip_not_found = + if Map.has_key?(conn.assigns, :remote_ip_found), + do: !conn.assigns.remote_ip_found, + else: false - localhost_or_socket and remote_ip_disabled + localhost_or_socket and remote_ip_not_found end @inspect_bucket_not_found {:error, :not_found} diff --git a/lib/pleroma/plugs/remote_ip.ex b/lib/pleroma/plugs/remote_ip.ex index 2eca4f8f6..0ac9050d0 100644 --- a/lib/pleroma/plugs/remote_ip.ex +++ b/lib/pleroma/plugs/remote_ip.ex @@ -7,6 +7,8 @@ defmodule Pleroma.Plugs.RemoteIp do This is a shim to call [`RemoteIp`](https://git.pleroma.social/pleroma/remote_ip) but with runtime configuration. """ + import Plug.Conn + @behaviour Plug @headers ~w[ @@ -26,11 +28,12 @@ defmodule Pleroma.Plugs.RemoteIp do def init(_), do: nil - def call(conn, _) do + def call(%{remote_ip: original_remote_ip} = conn, _) do config = Pleroma.Config.get(__MODULE__, []) if Keyword.get(config, :enabled, false) do - RemoteIp.call(conn, remote_ip_opts(config)) + %{remote_ip: new_remote_ip} = conn = RemoteIp.call(conn, remote_ip_opts(config)) + assign(conn, :remote_ip_found, original_remote_ip != new_remote_ip) else conn end diff --git a/lib/pleroma/user.ex b/lib/pleroma/user.ex index 7531757f5..db510d957 100644 --- a/lib/pleroma/user.ex +++ b/lib/pleroma/user.ex @@ -839,10 +839,6 @@ defmodule Pleroma.User do _e -> with [_nick, _domain] <- String.split(nickname, "@"), {:ok, user} <- fetch_by_nickname(nickname) do - if Pleroma.Config.get([:fetch_initial_posts, :enabled]) do - fetch_initial_posts(user) - end - {:ok, user} else _e -> {:error, "not found " <> nickname} @@ -850,11 +846,6 @@ defmodule Pleroma.User do end end - @doc "Fetch some posts when the user has just been federated with" - def fetch_initial_posts(user) do - BackgroundWorker.enqueue("fetch_initial_posts", %{"user_id" => user.id}) - end - @spec get_followers_query(User.t(), pos_integer() | nil) :: Ecto.Query.t() def get_followers_query(%User{} = user, nil) do User.Query.build(%{followers: user, deactivated: false}) @@ -1320,16 +1311,6 @@ defmodule Pleroma.User do Repo.delete(user) end - def perform(:fetch_initial_posts, %User{} = user) do - pages = Pleroma.Config.get!([:fetch_initial_posts, :pages]) - - # Insert all the posts in reverse order, so they're in the right order on the timeline - user.source_data["outbox"] - |> Utils.fetch_ordered_collection(pages) - |> Enum.reverse() - |> Enum.each(&Pleroma.Web.Federator.incoming_ap_doc/1) - end - def perform(:deactivate_async, user, status), do: deactivate(user, status) @spec perform(atom(), User.t(), list()) :: list() | {:error, any()} @@ -1458,18 +1439,7 @@ defmodule Pleroma.User do if !is_nil(user) and !needs_update?(user) do {:ok, user} else - # Whether to fetch initial posts for the user (if it's a new user & the fetching is enabled) - should_fetch_initial = is_nil(user) and Pleroma.Config.get([:fetch_initial_posts, :enabled]) - - resp = fetch_by_ap_id(ap_id) - - if should_fetch_initial do - with {:ok, %User{} = user} <- resp do - fetch_initial_posts(user) - end - end - - resp + fetch_by_ap_id(ap_id) end end diff --git a/lib/pleroma/web/activity_pub/utils.ex b/lib/pleroma/web/activity_pub/utils.ex index 2bc958670..15dd2ed45 100644 --- a/lib/pleroma/web/activity_pub/utils.ex +++ b/lib/pleroma/web/activity_pub/utils.ex @@ -784,45 +784,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 = 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..dae7f0f2f 100644 --- a/lib/pleroma/web/pleroma_api/controllers/pleroma_api_controller.ex +++ b/lib/pleroma/web/pleroma_api/controllers/pleroma_api_controller.ex @@ -101,6 +101,11 @@ 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 @@ -108,9 +113,9 @@ defmodule Pleroma.Web.PleromaAPI.PleromaAPIController do %{assigns: %{user: user}} = conn, %{"id" => participation_id} = params ) do - participation = Participation.get(participation_id, preload: [:conversation]) - - if user.id == participation.user_id do + with %Participation{} = participation <- + Participation.get(participation_id, preload: [:conversation]), + true <- user.id == participation.user_id do params = params |> Map.put("blocking_user", user) @@ -126,6 +131,11 @@ defmodule Pleroma.Web.PleromaAPI.PleromaAPIController do |> add_link_headers(activities) |> put_view(StatusView) |> render("index.json", %{activities: activities, for: user, as: :activity}) + else + _error -> + conn + |> put_status(404) + |> json(%{"error" => "Unknown conversation id"}) end end @@ -133,15 +143,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 diff --git a/lib/pleroma/workers/background_worker.ex b/lib/pleroma/workers/background_worker.ex index 598df6580..0f8ece2c4 100644 --- a/lib/pleroma/workers/background_worker.ex +++ b/lib/pleroma/workers/background_worker.ex @@ -10,10 +10,6 @@ defmodule Pleroma.Workers.BackgroundWorker do use Pleroma.Workers.WorkerHelper, queue: "background" @impl Oban.Worker - def perform(%{"op" => "fetch_initial_posts", "user_id" => user_id}, _job) do - user = User.get_cached_by_id(user_id) - User.perform(:fetch_initial_posts, user) - end def perform(%{"op" => "deactivate_user", "user_id" => user_id, "status" => status}, _job) do user = User.get_cached_by_id(user_id) diff --git a/priv/repo/migrations/20200314123607_config_remove_fetch_initial_posts.exs b/priv/repo/migrations/20200314123607_config_remove_fetch_initial_posts.exs new file mode 100644 index 000000000..392f531e8 --- /dev/null +++ b/priv/repo/migrations/20200314123607_config_remove_fetch_initial_posts.exs @@ -0,0 +1,10 @@ +defmodule Pleroma.Repo.Migrations.ConfigRemoveFetchInitialPosts do + use Ecto.Migration + + def change do + execute( + "delete from config where config.key = ':fetch_initial_posts' and config.group = ':pleroma';", + "" + ) + end +end diff --git a/priv/repo/migrations/20200315125756_delete_fetch_initial_posts_jobs.exs b/priv/repo/migrations/20200315125756_delete_fetch_initial_posts_jobs.exs new file mode 100644 index 000000000..5b8e3ab91 --- /dev/null +++ b/priv/repo/migrations/20200315125756_delete_fetch_initial_posts_jobs.exs @@ -0,0 +1,10 @@ +defmodule Pleroma.Repo.Migrations.DeleteFetchInitialPostsJobs do + use Ecto.Migration + + def change do + execute( + "delete from oban_jobs where worker = 'Pleroma.Workers.BackgroundWorker' and args->>'op' = 'fetch_initial_posts';", + "" + ) + end +end diff --git a/test/plugs/rate_limiter_test.exs b/test/plugs/rate_limiter_test.exs index 8023271e4..81e2009c8 100644 --- a/test/plugs/rate_limiter_test.exs +++ b/test/plugs/rate_limiter_test.exs @@ -3,8 +3,7 @@ # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.Plugs.RateLimiterTest do - use ExUnit.Case, async: true - use Plug.Test + use Pleroma.Web.ConnCase alias Pleroma.Config alias Pleroma.Plugs.RateLimiter @@ -36,63 +35,44 @@ defmodule Pleroma.Plugs.RateLimiterTest do |> RateLimiter.init() |> RateLimiter.action_settings() end + end - test "it is disabled for localhost" do - Config.put([:rate_limit, @limiter_name], {1, 1}) - Config.put([Pleroma.Web.Endpoint, :http, :ip], {127, 0, 0, 1}) - Config.put([Pleroma.Plugs.RemoteIp, :enabled], false) - - assert RateLimiter.disabled?() == true - end + test "it is disabled if it remote ip plug is enabled but no remote ip is found" do + Config.put([Pleroma.Web.Endpoint, :http, :ip], {127, 0, 0, 1}) + assert RateLimiter.disabled?(Plug.Conn.assign(build_conn(), :remote_ip_found, false)) + end - test "it is disabled for socket" do - Config.put([:rate_limit, @limiter_name], {1, 1}) - Config.put([Pleroma.Web.Endpoint, :http, :ip], {:local, "/path/to/pleroma.sock"}) - Config.put([Pleroma.Plugs.RemoteIp, :enabled], false) + test "it restricts based on config values" do + limiter_name = :test_plug_opts + scale = 80 + limit = 5 - assert RateLimiter.disabled?() == true - end + Config.put([Pleroma.Web.Endpoint, :http, :ip], {8, 8, 8, 8}) + Config.put([:rate_limit, limiter_name], {scale, limit}) - test "it is enabled for socket when remote ip is enabled" do - Config.put([:rate_limit, @limiter_name], {1, 1}) - Config.put([Pleroma.Web.Endpoint, :http, :ip], {:local, "/path/to/pleroma.sock"}) - Config.put([Pleroma.Plugs.RemoteIp, :enabled], true) + plug_opts = RateLimiter.init(name: limiter_name) + conn = conn(:get, "/") - assert RateLimiter.disabled?() == false + for i <- 1..5 do + conn = RateLimiter.call(conn, plug_opts) + assert {^i, _} = RateLimiter.inspect_bucket(conn, limiter_name, plug_opts) + Process.sleep(10) end - test "it restricts based on config values" do - limiter_name = :test_plug_opts - scale = 80 - limit = 5 - - Config.put([Pleroma.Web.Endpoint, :http, :ip], {8, 8, 8, 8}) - Config.put([:rate_limit, limiter_name], {scale, limit}) - - plug_opts = RateLimiter.init(name: limiter_name) - conn = conn(:get, "/") - - for i <- 1..5 do - conn = RateLimiter.call(conn, plug_opts) - assert {^i, _} = RateLimiter.inspect_bucket(conn, limiter_name, plug_opts) - Process.sleep(10) - end + conn = RateLimiter.call(conn, plug_opts) + assert %{"error" => "Throttled"} = Phoenix.ConnTest.json_response(conn, :too_many_requests) + assert conn.halted - conn = RateLimiter.call(conn, plug_opts) - assert %{"error" => "Throttled"} = Phoenix.ConnTest.json_response(conn, :too_many_requests) - assert conn.halted + Process.sleep(50) - Process.sleep(50) + conn = conn(:get, "/") - conn = conn(:get, "/") + conn = RateLimiter.call(conn, plug_opts) + assert {1, 4} = RateLimiter.inspect_bucket(conn, limiter_name, plug_opts) - conn = RateLimiter.call(conn, plug_opts) - assert {1, 4} = RateLimiter.inspect_bucket(conn, limiter_name, plug_opts) - - refute conn.status == Plug.Conn.Status.code(:too_many_requests) - refute conn.resp_body - refute conn.halted - end + refute conn.status == Plug.Conn.Status.code(:too_many_requests) + refute conn.resp_body + refute conn.halted end describe "options" do diff --git a/test/web/activity_pub/utils_test.exs b/test/web/activity_pub/utils_test.exs index e5ab54dd4..e913a5148 100644 --- a/test/web/activity_pub/utils_test.exs +++ b/test/web/activity_pub/utils_test.exs @@ -177,71 +177,6 @@ defmodule Pleroma.Web.ActivityPub.UtilsTest do end end - describe "fetch_ordered_collection" do - import Tesla.Mock - - test "fetches the first OrderedCollectionPage when an OrderedCollection is encountered" do - mock(fn - %{method: :get, url: "http://mastodon.com/outbox"} -> - json(%{"type" => "OrderedCollection", "first" => "http://mastodon.com/outbox?page=true"}) - - %{method: :get, url: "http://mastodon.com/outbox?page=true"} -> - json(%{"type" => "OrderedCollectionPage", "orderedItems" => ["ok"]}) - end) - - assert Utils.fetch_ordered_collection("http://mastodon.com/outbox", 1) == ["ok"] - end - - test "fetches several pages in the right order one after another, but only the specified amount" do - mock(fn - %{method: :get, url: "http://example.com/outbox"} -> - json(%{ - "type" => "OrderedCollectionPage", - "orderedItems" => [0], - "next" => "http://example.com/outbox?page=1" - }) - - %{method: :get, url: "http://example.com/outbox?page=1"} -> - json(%{ - "type" => "OrderedCollectionPage", - "orderedItems" => [1], - "next" => "http://example.com/outbox?page=2" - }) - - %{method: :get, url: "http://example.com/outbox?page=2"} -> - json(%{"type" => "OrderedCollectionPage", "orderedItems" => [2]}) - end) - - assert Utils.fetch_ordered_collection("http://example.com/outbox", 0) == [0] - assert Utils.fetch_ordered_collection("http://example.com/outbox", 1) == [0, 1] - end - - test "returns an error if the url doesn't have an OrderedCollection/Page" do - mock(fn - %{method: :get, url: "http://example.com/not-an-outbox"} -> - json(%{"type" => "NotAnOutbox"}) - end) - - assert {:error, _} = Utils.fetch_ordered_collection("http://example.com/not-an-outbox", 1) - end - - test "returns the what was collected if there are less pages than specified" do - mock(fn - %{method: :get, url: "http://example.com/outbox"} -> - json(%{ - "type" => "OrderedCollectionPage", - "orderedItems" => [0], - "next" => "http://example.com/outbox?page=1" - }) - - %{method: :get, url: "http://example.com/outbox?page=1"} -> - json(%{"type" => "OrderedCollectionPage", "orderedItems" => [1]}) - end) - - assert Utils.fetch_ordered_collection("http://example.com/outbox", 5) == [0, 1] - end - end - test "make_json_ld_header/0" do assert Utils.make_json_ld_header() == %{ "@context" => [ diff --git a/test/web/mastodon_api/controllers/account_controller_test.exs b/test/web/mastodon_api/controllers/account_controller_test.exs index 7f7d8cea3..7efccd9c4 100644 --- a/test/web/mastodon_api/controllers/account_controller_test.exs +++ b/test/web/mastodon_api/controllers/account_controller_test.exs @@ -756,10 +756,6 @@ defmodule Pleroma.Web.MastodonAPI.AccountControllerTest do end describe "create account by app / rate limit" do - clear_config([Pleroma.Plugs.RemoteIp, :enabled]) do - Pleroma.Config.put([Pleroma.Plugs.RemoteIp, :enabled], true) - end - clear_config([:rate_limit, :app_account_creation]) do Pleroma.Config.put([:rate_limit, :app_account_creation], {10_000, 2}) end |