Merge branch 'develop' into refactor/notification_settings
authorMark Felder <feld@FreeBSD.org>
Wed, 15 Jul 2020 14:30:23 +0000 (09:30 -0500)
committerMark Felder <feld@FreeBSD.org>
Wed, 15 Jul 2020 14:30:23 +0000 (09:30 -0500)
61 files changed:
CHANGELOG.md
config/config.exs
config/description.exs
config/test.exs
docs/configuration/cheatsheet.md
lib/pleroma/application.ex
lib/pleroma/config/deprecation_warnings.ex
lib/pleroma/plugs/admin_secret_authentication_plug.ex
lib/pleroma/plugs/http_security_plug.ex
lib/pleroma/plugs/user_is_admin_plug.ex
lib/pleroma/web/activity_pub/mrf/anti_followbot_policy.ex
lib/pleroma/web/activity_pub/mrf/anti_link_spam_policy.ex
lib/pleroma/web/activity_pub/mrf/hellthread_policy.ex
lib/pleroma/web/activity_pub/mrf/keyword_policy.ex
lib/pleroma/web/activity_pub/mrf/mention_policy.ex
lib/pleroma/web/activity_pub/mrf/object_age_policy.ex
lib/pleroma/web/activity_pub/mrf/reject_non_public.ex
lib/pleroma/web/activity_pub/mrf/simple_policy.ex
lib/pleroma/web/activity_pub/mrf/tag_policy.ex
lib/pleroma/web/activity_pub/mrf/user_allow_list_policy.ex
lib/pleroma/web/activity_pub/mrf/vocabulary_policy.ex
lib/pleroma/web/activity_pub/publisher.ex
lib/pleroma/web/activity_pub/transmogrifier.ex
lib/pleroma/web/api_spec/helpers.ex
lib/pleroma/web/api_spec/operations/admin/config_operation.ex
lib/pleroma/web/api_spec/operations/admin/invite_operation.ex
lib/pleroma/web/api_spec/operations/admin/media_proxy_cache_operation.ex
lib/pleroma/web/api_spec/operations/admin/oauth_app_operation.ex
lib/pleroma/web/api_spec/operations/admin/relay_operation.ex
lib/pleroma/web/api_spec/operations/admin/report_operation.ex
lib/pleroma/web/api_spec/operations/admin/status_operation.ex
lib/pleroma/web/mastodon_api/controllers/status_controller.ex
lib/pleroma/web/media_proxy/media_proxy.ex
mix.exs
priv/gettext/errors.pot
priv/gettext/it/LC_MESSAGES/errors.po
priv/gettext/nl/LC_MESSAGES/errors.po
priv/gettext/pl/LC_MESSAGES/errors.po
priv/repo/migrations/20200714081657_oban_2_0_config_changes.exs [new file with mode: 0644]
test/config/deprecation_warnings_test.exs
test/plugs/admin_secret_authentication_plug_test.exs
test/plugs/http_security_plug_test.exs
test/plugs/user_is_admin_plug_test.exs
test/web/activity_pub/activity_pub_controller_test.exs
test/web/activity_pub/mrf/anti_followbot_policy_test.exs
test/web/activity_pub/mrf/hellthread_policy_test.exs
test/web/activity_pub/mrf/keyword_policy_test.exs
test/web/activity_pub/mrf/mention_policy_test.exs
test/web/activity_pub/mrf/reject_non_public_test.exs
test/web/activity_pub/mrf/simple_policy_test.exs
test/web/activity_pub/mrf/tag_policy_test.exs
test/web/activity_pub/mrf/user_allowlist_policy_test.exs
test/web/activity_pub/mrf/vocabulary_policy_test.exs
test/web/activity_pub/publisher_test.exs
test/web/activity_pub/transmogrifier_test.exs
test/web/admin_api/controllers/admin_api_controller_test.exs
test/web/admin_api/controllers/config_controller_test.exs
test/web/admin_api/controllers/report_controller_test.exs
test/web/mastodon_api/controllers/status_controller_test.exs
test/web/media_proxy/media_proxy_controller_test.exs
test/web/media_proxy/media_proxy_test.exs

index 4af195f7dd2d1f73f9fe0181a19447a96817fbbf..a02f28241b202c394a79dd7d83b2a4b8534b7b7d 100644 (file)
@@ -12,6 +12,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
 - MFR policy to set global expiration for all local Create activities
 - OGP rich media parser merged with TwitterCard
 - Configuration: `:instance, rewrite_policy` moved to `:mrf, policies`, `:instance, :mrf_transparency` moved to `:mrf, :transparency`, `:instance, :mrf_transparency_exclusions` moved to `:mrf, :transparency_exclusions`. Old config namespace is deprecated.
+- Configuration: `:media_proxy, whitelist` format changed to host with scheme (e.g. `http://example.com` instead of `example.com`). Domain format is deprecated.
 
 <details>
   <summary>API Changes</summary>
index 6fc84efc2abae11b90bc31620b1f93b93435f185..daeefdca36517e7e59fe130e8972355102562f1e 100644 (file)
@@ -512,6 +512,7 @@ config :pleroma, Oban,
     attachments_cleanup: 5,
     new_users_digest: 1
   ],
+  plugins: [Oban.Plugins.Pruner],
   crontab: [
     {"0 0 * * *", Pleroma.Workers.Cron.ClearOauthTokenWorker},
     {"0 * * * *", Pleroma.Workers.Cron.StatsWorker},
index 84dcdb87e06840699c54931a7b45e6b528fb4af2..afc4dcd79b79301cfbe113468d081dd63f1cd4a7 100644 (file)
@@ -1768,8 +1768,8 @@ config :pleroma, :config_description, [
       %{
         key: :whitelist,
         type: {:list, :string},
-        description: "List of domains to bypass the mediaproxy",
-        suggestions: ["example.com"]
+        description: "List of hosts with scheme to bypass the mediaproxy",
+        suggestions: ["http://example.com"]
       }
     ]
   },
@@ -2008,13 +2008,15 @@ config :pleroma, :config_description, [
     label: "Pleroma Admin Token",
     type: :group,
     description:
-      "Allows to set a token that can be used to authenticate with the admin api without using an actual user by giving it as the `admin_token` parameter",
+      "Allows setting a token that can be used to authenticate requests with admin privileges without a normal user account token. Append the `admin_token` parameter to requests to utilize it. (Please reconsider using HTTP Basic Auth or OAuth-based authentication if possible)",
     children: [
       %{
         key: :admin_token,
         type: :string,
         description: "Admin token",
-        suggestions: ["We recommend a secure random string or UUID"]
+        suggestions: [
+          "Please use a high entropy string or UUID"
+        ]
       }
     ]
   },
index d45c36b7bcd8e1f9dd561ff32475f784a5b04e5c..abcf793e5934138b3384d615c6881dfd0429745b 100644 (file)
@@ -113,6 +113,11 @@ config :pleroma, Pleroma.Web.ApiSpec.CastAndValidate, strict: true
 
 config :pleroma, :instances_favicons, enabled: true
 
+config :pleroma, Pleroma.Uploaders.S3,
+  bucket: nil,
+  streaming_enabled: true,
+  public_endpoint: nil
+
 if File.exists?("./config/test.secret.exs") do
   import_config "test.secret.exs"
 else
index f796330f1080b10ee80fbaa3c9a9684ab5477ee5..ba62a721e1acdc07fbf9cd39668693b4ddf90506 100644 (file)
@@ -252,6 +252,7 @@ This section describe PWA manifest instance-specific values. Currently this opti
 * `background_color`: Describe the background color of the app. (Example: `"#191b22"`, `"aliceblue"`).
 
 ## :emoji
+
 * `shortcode_globs`: Location of custom emoji files. `*` can be used as a wildcard. Example `["/emoji/custom/**/*.png"]`
 * `pack_extensions`: A list of file extensions for emojis, when no emoji.txt for a pack is present. Example `[".png", ".gif"]`
 * `groups`: Emojis are ordered in groups (tags). This is an array of key-value pairs where the key is the groupname and the value the location or array of locations. `*` can be used as a wildcard. Example `[Custom: ["/emoji/*.png", "/emoji/custom/*.png"]]`
@@ -260,13 +261,14 @@ This section describe PWA manifest instance-specific values. Currently this opti
   memory for this amount of seconds multiplied by the number of files.
 
 ## :media_proxy
+
 * `enabled`: Enables proxying of remote media to the instance’s proxy
 * `base_url`: The base URL to access a user-uploaded file. Useful when you want to proxy the media files via another host/CDN fronts.
 * `proxy_opts`: All options defined in `Pleroma.ReverseProxy` documentation, defaults to `[max_body_length: (25*1_048_576)]`.
-* `whitelist`: List of domains to bypass the mediaproxy
+* `whitelist`: List of hosts with scheme to bypass the mediaproxy (e.g. `https://example.com`)
 * `invalidation`: options for remove media from cache after delete object:
-    * `enabled`: Enables purge cache
-    * `provider`: Which one of  the [purge cache strategy](#purge-cache-strategy) to use.
+  * `enabled`: Enables purge cache
+  * `provider`: Which one of  the [purge cache strategy](#purge-cache-strategy) to use.
 
 ### Purge cache strategy
 
@@ -278,6 +280,7 @@ Urls of attachments pass to script as arguments.
 * `script_path`: path to external script.
 
 Example:
+
 ```elixir
 config :pleroma, Pleroma.Web.MediaProxy.Invalidation.Script,
   script_path: "./installation/nginx-cache-purge.example"
@@ -629,8 +632,7 @@ Email notifications settings.
 Configuration options described in [Oban readme](https://github.com/sorentwo/oban#usage):
 
 * `repo` - app's Ecto repo (`Pleroma.Repo`)
-* `verbose` - logs verbosity
-* `prune` - non-retryable jobs [pruning settings](https://github.com/sorentwo/oban#pruning) (`:disabled` / `{:maxlen, value}` / `{:maxage, value}`)
+* `log` - logs verbosity
 * `queues` - job queues (see below)
 * `crontab` - periodic jobs, see [`Oban.Cron`](#obancron)
 
@@ -815,6 +817,8 @@ or
 curl -H "X-Admin-Token: somerandomtoken" "http://localhost:4000/api/pleroma/admin/users/invites"
 ```
 
+Warning: it's discouraged to use this feature because of the associated security risk: static / rarely changed instance-wide token is much weaker compared to email-password pair of a real admin user; consider using HTTP Basic Auth or OAuth-based authentication instead.
+
 ### :auth
 
 * `Pleroma.Web.Auth.PleromaAuthenticator`: default database authenticator.
index b68a373a448c7d2c3f96f051bd1b4744e03eff98..3282c6882104c9e14fafe004fa0a675b34959ddd 100644 (file)
@@ -35,6 +35,10 @@ defmodule Pleroma.Application do
   # See http://elixir-lang.org/docs/stable/elixir/Application.html
   # for more information on OTP Applications
   def start(_type, _args) do
+    # Scrubbers are compiled at runtime and therefore will cause a conflict
+    # every time the application is restarted, so we disable module
+    # conflicts at runtime
+    Code.compiler_options(ignore_module_conflict: true)
     Config.Holder.save_default()
     Pleroma.HTML.compile_scrubbers()
     Config.DeprecationWarnings.warn()
index 0a6c724fbd5090b8f36f6aabd4152869b6ca23e0..026871c4f11b943fdb6cf15e67153138f13be4b8 100644 (file)
@@ -54,6 +54,7 @@ defmodule Pleroma.Config.DeprecationWarnings do
     check_hellthread_threshold()
     mrf_user_allowlist()
     check_old_mrf_config()
+    check_media_proxy_whitelist_config()
   end
 
   def check_old_mrf_config do
@@ -65,7 +66,7 @@ defmodule Pleroma.Config.DeprecationWarnings do
     move_namespace_and_warn(@mrf_config_map, warning_preface)
   end
 
-  @spec move_namespace_and_warn([config_map()], String.t()) :: :ok
+  @spec move_namespace_and_warn([config_map()], String.t()) :: :ok | nil
   def move_namespace_and_warn(config_map, warning_preface) do
     warning =
       Enum.reduce(config_map, "", fn
@@ -84,4 +85,16 @@ defmodule Pleroma.Config.DeprecationWarnings do
       Logger.warn(warning_preface <> warning)
     end
   end
+
+  @spec check_media_proxy_whitelist_config() :: :ok | nil
+  def check_media_proxy_whitelist_config do
+    whitelist = Config.get([:media_proxy, :whitelist])
+
+    if Enum.any?(whitelist, &(not String.starts_with?(&1, "http"))) do
+      Logger.warn("""
+      !!!DEPRECATION WARNING!!!
+      Your config is using old format (only domain) for MediaProxy whitelist option. Setting should work for now, but you are advised to change format to scheme with port to prevent possible issues later.
+      """)
+    end
+  end
 end
index b4b47a31f2ffaff3d1095610f64e1f3499cb1454..2e54df47a386bb6e02eb402981e09c5567d08cdc 100644 (file)
@@ -4,6 +4,9 @@
 
 defmodule Pleroma.Plugs.AdminSecretAuthenticationPlug do
   import Plug.Conn
+
+  alias Pleroma.Plugs.OAuthScopesPlug
+  alias Pleroma.Plugs.RateLimiter
   alias Pleroma.User
 
   def init(options) do
@@ -11,7 +14,10 @@ defmodule Pleroma.Plugs.AdminSecretAuthenticationPlug do
   end
 
   def secret_token do
-    Pleroma.Config.get(:admin_token)
+    case Pleroma.Config.get(:admin_token) do
+      blank when blank in [nil, ""] -> nil
+      token -> token
+    end
   end
 
   def call(%{assigns: %{user: %User{}}} = conn, _), do: conn
@@ -26,9 +32,9 @@ defmodule Pleroma.Plugs.AdminSecretAuthenticationPlug do
 
   def authenticate(%{params: %{"admin_token" => admin_token}} = conn) do
     if admin_token == secret_token() do
-      assign(conn, :user, %User{is_admin: true})
+      assign_admin_user(conn)
     else
-      conn
+      handle_bad_token(conn)
     end
   end
 
@@ -36,8 +42,19 @@ defmodule Pleroma.Plugs.AdminSecretAuthenticationPlug do
     token = secret_token()
 
     case get_req_header(conn, "x-admin-token") do
-      [^token] -> assign(conn, :user, %User{is_admin: true})
-      _ -> conn
+      blank when blank in [[], [""]] -> conn
+      [^token] -> assign_admin_user(conn)
+      _ -> handle_bad_token(conn)
     end
   end
+
+  defp assign_admin_user(conn) do
+    conn
+    |> assign(:user, %User{is_admin: true})
+    |> OAuthScopesPlug.skip_plug()
+  end
+
+  defp handle_bad_token(conn) do
+    RateLimiter.call(conn, name: :authentication)
+  end
 end
index 7d65cf078605f9034bbdfb2fceae9be049c1c48e..c363b193b8573fc290000c4b4ebc47882506bf3d 100644 (file)
@@ -108,31 +108,48 @@ defmodule Pleroma.Plugs.HTTPSecurityPlug do
     |> :erlang.iolist_to_binary()
   end
 
-  defp build_csp_multimedia_source_list do
-    media_proxy_whitelist =
-      Enum.reduce(Config.get([:media_proxy, :whitelist]), [], fn host, acc ->
-        add_source(acc, host)
-      end)
+  defp build_csp_from_whitelist([], acc), do: acc
 
-    media_proxy_base_url = build_csp_param(Config.get([:media_proxy, :base_url]))
+  defp build_csp_from_whitelist([last], acc) do
+    [build_csp_param_from_whitelist(last) | acc]
+  end
 
-    upload_base_url = build_csp_param(Config.get([Pleroma.Upload, :base_url]))
+  defp build_csp_from_whitelist([head | tail], acc) do
+    build_csp_from_whitelist(tail, [[?\s, build_csp_param_from_whitelist(head)] | acc])
+  end
 
-    s3_endpoint = build_csp_param(Config.get([Pleroma.Uploaders.S3, :public_endpoint]))
+  # TODO: use `build_csp_param/1` after removing support bare domains for media proxy whitelist
+  defp build_csp_param_from_whitelist("http" <> _ = url) do
+    build_csp_param(url)
+  end
 
-    captcha_method = Config.get([Pleroma.Captcha, :method])
+  defp build_csp_param_from_whitelist(url), do: url
 
-    captcha_endpoint = build_csp_param(Config.get([captcha_method, :endpoint]))
+  defp build_csp_multimedia_source_list do
+    media_proxy_whitelist =
+      [:media_proxy, :whitelist]
+      |> Config.get()
+      |> build_csp_from_whitelist([])
 
-    []
-    |> add_source(media_proxy_base_url)
-    |> add_source(upload_base_url)
-    |> add_source(s3_endpoint)
+    captcha_method = Config.get([Pleroma.Captcha, :method])
+    captcha_endpoint = Config.get([captcha_method, :endpoint])
+
+    base_endpoints =
+      [
+        [:media_proxy, :base_url],
+        [Pleroma.Upload, :base_url],
+        [Pleroma.Uploaders.S3, :public_endpoint]
+      ]
+      |> Enum.map(&Config.get/1)
+
+    [captcha_endpoint | base_endpoints]
+    |> Enum.map(&build_csp_param/1)
+    |> Enum.reduce([], &add_source(&2, &1))
     |> add_source(media_proxy_whitelist)
-    |> add_source(captcha_endpoint)
   end
 
   defp add_source(iodata, nil), do: iodata
+  defp add_source(iodata, []), do: iodata
   defp add_source(iodata, source), do: [[?\s, source] | iodata]
 
   defp add_csp_param(csp_iodata, nil), do: csp_iodata
index 2748102dff6e90bcdc21e9a9c4051b2d79cbe965..488a61d1d4940304423694a94c8127a43a8ca139 100644 (file)
@@ -7,37 +7,18 @@ defmodule Pleroma.Plugs.UserIsAdminPlug do
   import Plug.Conn
 
   alias Pleroma.User
-  alias Pleroma.Web.OAuth
 
   def init(options) do
     options
   end
 
-  def call(%{assigns: %{user: %User{is_admin: true}} = assigns} = conn, _) do
-    token = assigns[:token]
-
-    cond do
-      not Pleroma.Config.enforce_oauth_admin_scope_usage?() ->
-        conn
-
-      token && OAuth.Scopes.contains_admin_scopes?(token.scopes) ->
-        # Note: checking for _any_ admin scope presence, not necessarily fitting requested action.
-        #   Thus, controller must explicitly invoke OAuthScopesPlug to verify scope requirements.
-        #   Admin might opt out of admin scope for some apps to block any admin actions from them.
-        conn
-
-      true ->
-        fail(conn)
-    end
+  def call(%{assigns: %{user: %User{is_admin: true}}} = conn, _) do
+    conn
   end
 
   def call(conn, _) do
-    fail(conn)
-  end
-
-  defp fail(conn) do
     conn
-    |> render_error(:forbidden, "User is not an admin or OAuth admin scope is not granted.")
+    |> render_error(:forbidden, "User is not an admin.")
     |> halt()
   end
 end
index 0270b96ae06c5cb8a8727cc0c76b0430022c90ae..b96388489170b4e5c385817f8473aaa4d0cc425c 100644 (file)
@@ -60,7 +60,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.AntiFollowbotPolicy do
     if score < 0.8 do
       {:ok, message}
     else
-      {:reject, nil}
+      {:reject, "[AntiFollowbotPolicy] Scored #{actor_id} as #{score}"}
     end
   end
 
index a7e187b5e4df03ab5c474df31194712b38362a8f..b224641114550e0f1d37240840ba34e20b0312c4 100644 (file)
@@ -39,14 +39,13 @@ defmodule Pleroma.Web.ActivityPub.MRF.AntiLinkSpamPolicy do
         {:ok, message}
 
       {:old_user, false} ->
-        {:reject, nil}
+        {:reject, "[AntiLinkSpamPolicy] User has no posts nor followers"}
 
       {:error, _} ->
-        {:reject, nil}
+        {:reject, "[AntiLinkSpamPolicy] Failed to get or fetch user by ap_id"}
 
       e ->
-        Logger.warn("[MRF anti-link-spam] WTF: unhandled error #{inspect(e)}")
-        {:reject, nil}
+        {:reject, "[AntiLinkSpamPolicy] Unhandled error #{inspect(e)}"}
     end
   end
 
index f6b2c44152ed3119defeb046327efbdb032fa78a..9ba07b4e38b73c4a1bffdfba131511aee90855f9 100644 (file)
@@ -43,7 +43,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.HellthreadPolicy do
   defp reject_message(message, threshold) when threshold > 0 do
     with {_, recipients} <- get_recipient_count(message) do
       if recipients > threshold do
-        {:reject, nil}
+        {:reject, "[HellthreadPolicy] #{recipients} recipients is over the limit of #{threshold}"}
       else
         {:ok, message}
       end
@@ -87,7 +87,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.HellthreadPolicy do
          {:ok, message} <- delist_message(message, delist_threshold) do
       {:ok, message}
     else
-      _e -> {:reject, nil}
+      e -> e
     end
   end
 
index 88b0d2b39e8e491062c80df406fba4c7a19ed08b..15e09dcf03abdbe3d11c8293ab0e5619aaddb832 100644 (file)
@@ -24,7 +24,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.KeywordPolicy do
     if Enum.any?(Pleroma.Config.get([:mrf_keyword, :reject]), fn pattern ->
          string_matches?(content, pattern) or string_matches?(summary, pattern)
        end) do
-      {:reject, nil}
+      {:reject, "[KeywordPolicy] Matches with rejected keyword"}
     else
       {:ok, message}
     end
@@ -89,8 +89,9 @@ defmodule Pleroma.Web.ActivityPub.MRF.KeywordPolicy do
          {:ok, message} <- check_replace(message) do
       {:ok, message}
     else
-      _e ->
-        {:reject, nil}
+      {:reject, nil} -> {:reject, "[KeywordPolicy] "}
+      {:reject, _} = e -> e
+      _e -> {:reject, "[KeywordPolicy] "}
     end
   end
 
index 06f003921a65de36f101d799ce9774bcf6b5fab4..7910ca131830d3b782a2f3d5040c13f2196caefd 100644 (file)
@@ -12,8 +12,9 @@ defmodule Pleroma.Web.ActivityPub.MRF.MentionPolicy do
     reject_actors = Pleroma.Config.get([:mrf_mention, :actors], [])
     recipients = (message["to"] || []) ++ (message["cc"] || [])
 
-    if Enum.any?(recipients, fn recipient -> Enum.member?(reject_actors, recipient) end) do
-      {:reject, nil}
+    if rejected_mention =
+         Enum.find(recipients, fn recipient -> Enum.member?(reject_actors, recipient) end) do
+      {:reject, "[MentionPolicy] Rejected for mention of #{rejected_mention}"}
     else
       {:ok, message}
     end
index a629141358a05abde41672100734e0e13135e715..5f111c72f552ccbf1265bb9230c4cd58a89fdcfb 100644 (file)
@@ -28,7 +28,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.ObjectAgePolicy do
 
   defp check_reject(message, actions) do
     if :reject in actions do
-      {:reject, nil}
+      {:reject, "[ObjectAgePolicy]"}
     else
       {:ok, message}
     end
@@ -47,9 +47,8 @@ defmodule Pleroma.Web.ActivityPub.MRF.ObjectAgePolicy do
 
         {:ok, message}
       else
-        # Unhandleable error: somebody is messing around, just drop the message.
         _e ->
-          {:reject, nil}
+          {:reject, "[ObjectAgePolicy] Unhandled error"}
       end
     else
       {:ok, message}
@@ -69,9 +68,8 @@ defmodule Pleroma.Web.ActivityPub.MRF.ObjectAgePolicy do
 
         {:ok, message}
       else
-        # Unhandleable error: somebody is messing around, just drop the message.
         _e ->
-          {:reject, nil}
+          {:reject, "[ObjectAgePolicy] Unhandled error"}
       end
     else
       {:ok, message}
index 4fd63106d25aff6b60daff650abca271c97af16d..0b9ed2224dc82a334f6a2efc7d4082a311651bd9 100644 (file)
@@ -38,7 +38,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.RejectNonPublic do
         {:ok, object}
 
       true ->
-        {:reject, nil}
+        {:reject, "[RejectNonPublic] visibility: #{visibility}"}
     end
   end
 
index 70a2ca05338ddd7d848ed70e23091712453ccfd8..b77b8c7b49eb2254d9fe3612d61d616f819bd214 100644 (file)
@@ -21,7 +21,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicy do
       accepts == [] -> {:ok, object}
       actor_host == Config.get([Pleroma.Web.Endpoint, :url, :host]) -> {:ok, object}
       MRF.subdomain_match?(accepts, actor_host) -> {:ok, object}
-      true -> {:reject, nil}
+      true -> {:reject, "[SimplePolicy] host not in accept list"}
     end
   end
 
@@ -31,7 +31,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicy do
       |> MRF.subdomains_regex()
 
     if MRF.subdomain_match?(rejects, actor_host) do
-      {:reject, nil}
+      {:reject, "[SimplePolicy] host in reject list"}
     else
       {:ok, object}
     end
@@ -114,7 +114,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicy do
       |> MRF.subdomains_regex()
 
     if MRF.subdomain_match?(report_removal, actor_host) do
-      {:reject, nil}
+      {:reject, "[SimplePolicy] host in report_removal list"}
     else
       {:ok, object}
     end
@@ -159,7 +159,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicy do
       |> MRF.subdomains_regex()
 
     if MRF.subdomain_match?(reject_deletes, actor_host) do
-      {:reject, nil}
+      {:reject, "[SimplePolicy] host in reject_deletes list"}
     else
       {:ok, object}
     end
@@ -177,7 +177,9 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicy do
          {:ok, object} <- check_report_removal(actor_info, object) do
       {:ok, object}
     else
-      _e -> {:reject, nil}
+      {:reject, nil} -> {:reject, "[SimplePolicy]"}
+      {:reject, _} = e -> e
+      _ -> {:reject, "[SimplePolicy]"}
     end
   end
 
@@ -191,7 +193,9 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicy do
          {:ok, object} <- check_banner_removal(actor_info, object) do
       {:ok, object}
     else
-      _e -> {:reject, nil}
+      {:reject, nil} -> {:reject, "[SimplePolicy]"}
+      {:reject, _} = e -> e
+      _ -> {:reject, "[SimplePolicy]"}
     end
   end
 
index c310462cba7fbe68baac41855f7bd7f1ad585a49..febabda082d12220e6938bc53cc76ba996c2e9dd 100644 (file)
@@ -134,12 +134,13 @@ defmodule Pleroma.Web.ActivityPub.MRF.TagPolicy do
     if user.local == true do
       {:ok, message}
     else
-      {:reject, nil}
+      {:reject,
+       "[TagPolicy] Follow from #{actor} tagged with mrf_tag:disable-remote-subscription"}
     end
   end
 
-  defp process_tag("mrf_tag:disable-any-subscription", %{"type" => "Follow"}),
-    do: {:reject, nil}
+  defp process_tag("mrf_tag:disable-any-subscription", %{"type" => "Follow", "actor" => actor}),
+    do: {:reject, "[TagPolicy] Follow from #{actor} tagged with mrf_tag:disable-any-subscription"}
 
   defp process_tag(_, message), do: {:ok, message}
 
index 651aed70f00b5ae3bb5c33daa4e7230b01d9165d..1a28f2ba21d118563324d36b9e602d6d87eb60a9 100644 (file)
@@ -14,7 +14,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.UserAllowListPolicy do
     if actor in allow_list do
       {:ok, object}
     else
-      {:reject, nil}
+      {:reject, "[UserAllowListPolicy] #{actor} not in the list"}
     end
   end
 
index 6167a74e209fcf7940cdfc4d0836c08d23a9f3f2..a6c5455702c27cdc733619e5ecc90a9f780962ca 100644 (file)
@@ -11,22 +11,26 @@ defmodule Pleroma.Web.ActivityPub.MRF.VocabularyPolicy do
     with {:ok, _} <- filter(child_message) do
       {:ok, message}
     else
-      {:reject, nil} ->
-        {:reject, nil}
+      {:reject, _} = e -> e
     end
   end
 
   def filter(%{"type" => message_type} = message) do
     with accepted_vocabulary <- Pleroma.Config.get([:mrf_vocabulary, :accept]),
          rejected_vocabulary <- Pleroma.Config.get([:mrf_vocabulary, :reject]),
-         true <-
-           Enum.empty?(accepted_vocabulary) || Enum.member?(accepted_vocabulary, message_type),
-         false <-
-           length(rejected_vocabulary) > 0 && Enum.member?(rejected_vocabulary, message_type),
+         {_, true} <-
+           {:accepted,
+            Enum.empty?(accepted_vocabulary) || Enum.member?(accepted_vocabulary, message_type)},
+         {_, false} <-
+           {:rejected,
+            length(rejected_vocabulary) > 0 && Enum.member?(rejected_vocabulary, message_type)},
          {:ok, _} <- filter(message["object"]) do
       {:ok, message}
     else
-      _ -> {:reject, nil}
+      {:reject, _} = e -> e
+      {:accepted, _} -> {:reject, "[VocabularyPolicy] #{message_type} not in accept list"}
+      {:rejected, _} -> {:reject, "[VocabularyPolicy] #{message_type} in reject list"}
+      _ -> {:reject, "[VocabularyPolicy]"}
     end
   end
 
index b70cbd04343b4d40ca899a6e63c331d861f3d3d4..d88f7f3ee57d40614d3c574293aad7423805773d 100644 (file)
@@ -49,7 +49,8 @@ defmodule Pleroma.Web.ActivityPub.Publisher do
   """
   def publish_one(%{inbox: inbox, json: json, actor: %User{} = actor, id: id} = params) do
     Logger.debug("Federating #{id} to #{inbox}")
-    %{host: host, path: path} = URI.parse(inbox)
+
+    uri = URI.parse(inbox)
 
     digest = "SHA-256=" <> (:crypto.hash(:sha256, json) |> Base.encode64())
 
@@ -57,8 +58,8 @@ defmodule Pleroma.Web.ActivityPub.Publisher do
 
     signature =
       Pleroma.Signature.sign(actor, %{
-        "(request-target)": "post #{path}",
-        host: host,
+        "(request-target)": "post #{uri.path}",
+        host: signature_host(uri),
         "content-length": byte_size(json),
         digest: digest,
         date: date
@@ -76,8 +77,9 @@ defmodule Pleroma.Web.ActivityPub.Publisher do
                  {"digest", digest}
                ]
              ) do
-      if !Map.has_key?(params, :unreachable_since) || params[:unreachable_since],
-        do: Instances.set_reachable(inbox)
+      if not Map.has_key?(params, :unreachable_since) || params[:unreachable_since] do
+        Instances.set_reachable(inbox)
+      end
 
       result
     else
@@ -96,6 +98,14 @@ defmodule Pleroma.Web.ActivityPub.Publisher do
     |> publish_one()
   end
 
+  defp signature_host(%URI{port: port, scheme: scheme, host: host}) do
+    if port == URI.default_port(scheme) do
+      host
+    else
+      "#{host}:#{port}"
+    end
+  end
+
   defp should_federate?(inbox, public) do
     if public do
       true
index 884646cebf98ce45e85a342523e16ac41e2c28f5..f37bcab3e752493f090c671ef2955ed3ae2159c3 100644 (file)
@@ -62,15 +62,17 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
   def fix_summary(object), do: Map.put(object, "summary", "")
 
   def fix_addressing_list(map, field) do
+    addrs = map[field]
+
     cond do
-      is_binary(map[field]) ->
-        Map.put(map, field, [map[field]])
+      is_list(addrs) ->
+        Map.put(map, field, Enum.filter(addrs, &is_binary/1))
 
-      is_nil(map[field]) ->
-        Map.put(map, field, [])
+      is_binary(addrs) ->
+        Map.put(map, field, [addrs])
 
       true ->
-        map
+        Map.put(map, field, [])
     end
   end
 
index a258e8421c6e6877145ba85e76bec2e0094bd629..2a7f1a706bc737d1ed829fb6bf7d1c3bf015acf1 100644 (file)
@@ -29,6 +29,10 @@ defmodule Pleroma.Web.ApiSpec.Helpers do
     }
   end
 
+  def admin_api_params do
+    [Operation.parameter(:admin_token, :query, :string, "Allows authorization via admin token.")]
+  end
+
   def pagination_params do
     [
       Operation.parameter(:max_id, :query, :string, "Return items older than this ID"),
index 7b38a2ef4e053da0310de366676fb0f8b3a79b86..3a8380797dd5373d58fa78834f522b9fa7d839bc 100644 (file)
@@ -26,6 +26,7 @@ defmodule Pleroma.Web.ApiSpec.Admin.ConfigOperation do
           %Schema{type: :boolean, default: false},
           "Get only saved in database settings"
         )
+        | admin_api_params()
       ],
       security: [%{"oAuth" => ["read"]}],
       responses: %{
@@ -41,6 +42,7 @@ defmodule Pleroma.Web.ApiSpec.Admin.ConfigOperation do
       summary: "Update config settings",
       operationId: "AdminAPI.ConfigController.update",
       security: [%{"oAuth" => ["write"]}],
+      parameters: admin_api_params(),
       requestBody:
         request_body("Parameters", %Schema{
           type: :object,
@@ -73,6 +75,7 @@ defmodule Pleroma.Web.ApiSpec.Admin.ConfigOperation do
       summary: "Get JSON with config descriptions.",
       operationId: "AdminAPI.ConfigController.descriptions",
       security: [%{"oAuth" => ["read"]}],
+      parameters: admin_api_params(),
       responses: %{
         200 =>
           Operation.response("Config Descriptions", "application/json", %Schema{
index d3af9db49213b712f65269efe5dd3626211b8651..801024d75f5eb63d823bb9f2f6af71c7d1c8fa23 100644 (file)
@@ -20,6 +20,7 @@ defmodule Pleroma.Web.ApiSpec.Admin.InviteOperation do
       summary: "Get a list of generated invites",
       operationId: "AdminAPI.InviteController.index",
       security: [%{"oAuth" => ["read:invites"]}],
+      parameters: admin_api_params(),
       responses: %{
         200 =>
           Operation.response("Invites", "application/json", %Schema{
@@ -51,6 +52,7 @@ defmodule Pleroma.Web.ApiSpec.Admin.InviteOperation do
       summary: "Create an account registration invite token",
       operationId: "AdminAPI.InviteController.create",
       security: [%{"oAuth" => ["write:invites"]}],
+      parameters: admin_api_params(),
       requestBody:
         request_body("Parameters", %Schema{
           type: :object,
@@ -71,6 +73,7 @@ defmodule Pleroma.Web.ApiSpec.Admin.InviteOperation do
       summary: "Revoke invite by token",
       operationId: "AdminAPI.InviteController.revoke",
       security: [%{"oAuth" => ["write:invites"]}],
+      parameters: admin_api_params(),
       requestBody:
         request_body(
           "Parameters",
@@ -97,6 +100,7 @@ defmodule Pleroma.Web.ApiSpec.Admin.InviteOperation do
       summary: "Sends registration invite via email",
       operationId: "AdminAPI.InviteController.email",
       security: [%{"oAuth" => ["write:invites"]}],
+      parameters: admin_api_params(),
       requestBody:
         request_body(
           "Parameters",
index 0358cfbad8ae095d5583eef03161987fbec4f2c7..20d033f66f9f88c4863c72af71d3c133e9f2a045 100644 (file)
@@ -33,6 +33,7 @@ defmodule Pleroma.Web.ApiSpec.Admin.MediaProxyCacheOperation do
           %Schema{type: :integer, default: 50},
           "Number of statuses to return"
         )
+        | admin_api_params()
       ],
       responses: %{
         200 => success_response()
@@ -46,6 +47,7 @@ defmodule Pleroma.Web.ApiSpec.Admin.MediaProxyCacheOperation do
       summary: "Remove a banned MediaProxy URL from Cachex",
       operationId: "AdminAPI.MediaProxyCacheController.delete",
       security: [%{"oAuth" => ["write:media_proxy_caches"]}],
+      parameters: admin_api_params(),
       requestBody:
         request_body(
           "Parameters",
@@ -71,6 +73,7 @@ defmodule Pleroma.Web.ApiSpec.Admin.MediaProxyCacheOperation do
       summary: "Purge and optionally ban a MediaProxy URL",
       operationId: "AdminAPI.MediaProxyCacheController.purge",
       security: [%{"oAuth" => ["write:media_proxy_caches"]}],
+      parameters: admin_api_params(),
       requestBody:
         request_body(
           "Parameters",
index fbc9f80d7809615847744f837e85ab11af6323bf..a75f3e6229442fd0023708ea8bad824103eb0903 100644 (file)
@@ -36,6 +36,7 @@ defmodule Pleroma.Web.ApiSpec.Admin.OAuthAppOperation do
           %Schema{type: :integer, default: 50},
           "Number of apps to return"
         )
+        | admin_api_params()
       ],
       responses: %{
         200 =>
@@ -72,6 +73,7 @@ defmodule Pleroma.Web.ApiSpec.Admin.OAuthAppOperation do
       summary: "Create OAuth App",
       operationId: "AdminAPI.OAuthAppController.create",
       requestBody: request_body("Parameters", create_request()),
+      parameters: admin_api_params(),
       security: [%{"oAuth" => ["write"]}],
       responses: %{
         200 => Operation.response("App", "application/json", oauth_app()),
@@ -85,7 +87,7 @@ defmodule Pleroma.Web.ApiSpec.Admin.OAuthAppOperation do
       tags: ["Admin", "oAuth Apps"],
       summary: "Update OAuth App",
       operationId: "AdminAPI.OAuthAppController.update",
-      parameters: [id_param()],
+      parameters: [id_param() | admin_api_params()],
       security: [%{"oAuth" => ["write"]}],
       requestBody: request_body("Parameters", update_request()),
       responses: %{
@@ -103,7 +105,7 @@ defmodule Pleroma.Web.ApiSpec.Admin.OAuthAppOperation do
       tags: ["Admin", "oAuth Apps"],
       summary: "Delete OAuth App",
       operationId: "AdminAPI.OAuthAppController.delete",
-      parameters: [id_param()],
+      parameters: [id_param() | admin_api_params()],
       security: [%{"oAuth" => ["write"]}],
       responses: %{
         204 => no_content_response(),
index 7672cb467a4d490cc1c1c173c8a87e567e647077..67ee5eee02900b0a0a7db09985b902c43653edd3 100644 (file)
@@ -19,6 +19,7 @@ defmodule Pleroma.Web.ApiSpec.Admin.RelayOperation do
       summary: "List Relays",
       operationId: "AdminAPI.RelayController.index",
       security: [%{"oAuth" => ["read"]}],
+      parameters: admin_api_params(),
       responses: %{
         200 =>
           Operation.response("Response", "application/json", %Schema{
@@ -41,6 +42,7 @@ defmodule Pleroma.Web.ApiSpec.Admin.RelayOperation do
       summary: "Follow a Relay",
       operationId: "AdminAPI.RelayController.follow",
       security: [%{"oAuth" => ["write:follows"]}],
+      parameters: admin_api_params(),
       requestBody:
         request_body("Parameters", %Schema{
           type: :object,
@@ -64,6 +66,7 @@ defmodule Pleroma.Web.ApiSpec.Admin.RelayOperation do
       summary: "Unfollow a Relay",
       operationId: "AdminAPI.RelayController.unfollow",
       security: [%{"oAuth" => ["write:follows"]}],
+      parameters: admin_api_params(),
       requestBody:
         request_body("Parameters", %Schema{
           type: :object,
index 15e78bfafe714c8ce6cd4b3048d50944ed7ab0c1..3bb7ec49ec7a28e7ad7d33a520cd3694d5e47ae8 100644 (file)
@@ -48,6 +48,7 @@ defmodule Pleroma.Web.ApiSpec.Admin.ReportOperation do
           %Schema{type: :integer, default: 50},
           "Number number of log entries per page"
         )
+        | admin_api_params()
       ],
       responses: %{
         200 =>
@@ -71,7 +72,7 @@ defmodule Pleroma.Web.ApiSpec.Admin.ReportOperation do
       tags: ["Admin", "Reports"],
       summary: "Get an individual report",
       operationId: "AdminAPI.ReportController.show",
-      parameters: [id_param()],
+      parameters: [id_param() | admin_api_params()],
       security: [%{"oAuth" => ["read:reports"]}],
       responses: %{
         200 => Operation.response("Report", "application/json", report()),
@@ -86,6 +87,7 @@ defmodule Pleroma.Web.ApiSpec.Admin.ReportOperation do
       summary: "Change the state of one or multiple reports",
       operationId: "AdminAPI.ReportController.update",
       security: [%{"oAuth" => ["write:reports"]}],
+      parameters: admin_api_params(),
       requestBody: request_body("Parameters", update_request(), required: true),
       responses: %{
         204 => no_content_response(),
@@ -100,7 +102,7 @@ defmodule Pleroma.Web.ApiSpec.Admin.ReportOperation do
       tags: ["Admin", "Reports"],
       summary: "Create report note",
       operationId: "AdminAPI.ReportController.notes_create",
-      parameters: [id_param()],
+      parameters: [id_param() | admin_api_params()],
       requestBody:
         request_body("Parameters", %Schema{
           type: :object,
@@ -124,6 +126,7 @@ defmodule Pleroma.Web.ApiSpec.Admin.ReportOperation do
       parameters: [
         Operation.parameter(:report_id, :path, :string, "Report ID"),
         Operation.parameter(:id, :path, :string, "Note ID")
+        | admin_api_params()
       ],
       security: [%{"oAuth" => ["write:reports"]}],
       responses: %{
index 745399b4b08bcda7472e9589f28e46b3c5038472..c105838a4ee41f5b7d038eb7d6f6d3a912733eba 100644 (file)
@@ -55,6 +55,7 @@ defmodule Pleroma.Web.ApiSpec.Admin.StatusOperation do
           %Schema{type: :integer, default: 50},
           "Number of statuses to return"
         )
+        | admin_api_params()
       ],
       responses: %{
         200 =>
@@ -71,7 +72,7 @@ defmodule Pleroma.Web.ApiSpec.Admin.StatusOperation do
       tags: ["Admin", "Statuses"],
       summary: "Show Status",
       operationId: "AdminAPI.StatusController.show",
-      parameters: [id_param()],
+      parameters: [id_param() | admin_api_params()],
       security: [%{"oAuth" => ["read:statuses"]}],
       responses: %{
         200 => Operation.response("Status", "application/json", status()),
@@ -85,7 +86,7 @@ defmodule Pleroma.Web.ApiSpec.Admin.StatusOperation do
       tags: ["Admin", "Statuses"],
       summary: "Change the scope of an individual reported status",
       operationId: "AdminAPI.StatusController.update",
-      parameters: [id_param()],
+      parameters: [id_param() | admin_api_params()],
       security: [%{"oAuth" => ["write:statuses"]}],
       requestBody: request_body("Parameters", update_request(), required: true),
       responses: %{
@@ -100,7 +101,7 @@ defmodule Pleroma.Web.ApiSpec.Admin.StatusOperation do
       tags: ["Admin", "Statuses"],
       summary: "Delete an individual reported status",
       operationId: "AdminAPI.StatusController.delete",
-      parameters: [id_param()],
+      parameters: [id_param() | admin_api_params()],
       security: [%{"oAuth" => ["write:statuses"]}],
       responses: %{
         200 => empty_object_response(),
index 12be530c999a94ff3b71ba4653dd4870dd93b489..9bb2ef117b414f15b40ca78fd3e729d5adf25029 100644 (file)
@@ -172,6 +172,11 @@ defmodule Pleroma.Web.MastodonAPI.StatusController do
         with_direct_conversation_id: true
       )
     else
+      {:error, {:reject, message}} ->
+        conn
+        |> put_status(:unprocessable_entity)
+        |> json(%{error: message})
+
       {:error, message} ->
         conn
         |> put_status(:unprocessable_entity)
index 6f35826da1caab4fa9f43a981967d950b1d697a2..dfbfcea6bc74620504e9a0b339d8ca315b43e066 100644 (file)
@@ -60,22 +60,28 @@ defmodule Pleroma.Web.MediaProxy do
   defp whitelisted?(url) do
     %{host: domain} = URI.parse(url)
 
-    mediaproxy_whitelist = Config.get([:media_proxy, :whitelist])
-
-    upload_base_url_domain =
-      if !is_nil(Config.get([Upload, :base_url])) do
-        [URI.parse(Config.get([Upload, :base_url])).host]
+    mediaproxy_whitelist_domains =
+      [:media_proxy, :whitelist]
+      |> Config.get()
+      |> Enum.map(&maybe_get_domain_from_url/1)
+
+    whitelist_domains =
+      if base_url = Config.get([Upload, :base_url]) do
+        %{host: base_domain} = URI.parse(base_url)
+        [base_domain | mediaproxy_whitelist_domains]
       else
-        []
+        mediaproxy_whitelist_domains
       end
 
-    whitelist = mediaproxy_whitelist ++ upload_base_url_domain
+    domain in whitelist_domains
+  end
 
-    Enum.any?(whitelist, fn pattern ->
-      String.equivalent?(domain, pattern)
-    end)
+  defp maybe_get_domain_from_url("http" <> _ = url) do
+    URI.parse(url).host
   end
 
+  defp maybe_get_domain_from_url(domain), do: domain
+
   def encode_url(url) do
     base64 = Base.url_encode64(url, @base64_opts)
 
diff --git a/mix.exs b/mix.exs
index d7992ee37181180cfbe687e92e70193df87e4364..741f917e68fd7b7e4b81ee365d9b166457d77b10 100644 (file)
--- a/mix.exs
+++ b/mix.exs
@@ -90,8 +90,6 @@ defmodule Pleroma.Mixfile do
   defp elixirc_paths(_), do: ["lib"]
 
   defp warnings_as_errors(:prod), do: false
-  # Uncomment this if you need testing configurable_from_database logic
-  # defp warnings_as_errors(:dev), do: false
   defp warnings_as_errors(_), do: true
 
   # Specifies OAuth dependencies.
index 0e1cf37ebde3a9a49b8c911d9092ec5334e39995..e337226a736c63c0e7d5d319c9b3ebc7f42b5ee9 100644 (file)
@@ -90,110 +90,100 @@ msgid "must be equal to %{number}"
 msgstr ""
 
 #, elixir-format
-#: lib/pleroma/web/common_api/common_api.ex:421
+#: lib/pleroma/web/common_api/common_api.ex:505
 msgid "Account not found"
 msgstr ""
 
 #, elixir-format
-#: lib/pleroma/web/common_api/common_api.ex:249
+#: lib/pleroma/web/common_api/common_api.ex:339
 msgid "Already voted"
 msgstr ""
 
 #, elixir-format
-#: lib/pleroma/web/oauth/oauth_controller.ex:360
+#: lib/pleroma/web/oauth/oauth_controller.ex:359
 msgid "Bad request"
 msgstr ""
 
 #, elixir-format
-#: lib/pleroma/web/activity_pub/activity_pub_controller.ex:425
+#: lib/pleroma/web/activity_pub/activity_pub_controller.ex:426
 msgid "Can't delete object"
 msgstr ""
 
 #, elixir-format
-#: lib/pleroma/web/mastodon_api/controllers/status_controller.ex:196
-msgid "Can't delete this post"
-msgstr ""
-
-#, elixir-format
-#: lib/pleroma/web/controller_helper.ex:95
-#: lib/pleroma/web/controller_helper.ex:101
+#: lib/pleroma/web/controller_helper.ex:105
+#: lib/pleroma/web/controller_helper.ex:111
 msgid "Can't display this activity"
 msgstr ""
 
 #, elixir-format
-#: lib/pleroma/web/mastodon_api/controllers/account_controller.ex:227
-#: lib/pleroma/web/mastodon_api/controllers/account_controller.ex:254
+#: lib/pleroma/web/mastodon_api/controllers/account_controller.ex:285
 msgid "Can't find user"
 msgstr ""
 
 #, elixir-format
-#: lib/pleroma/web/pleroma_api/controllers/account_controller.ex:114
+#: lib/pleroma/web/pleroma_api/controllers/account_controller.ex:61
 msgid "Can't get favorites"
 msgstr ""
 
 #, elixir-format
-#: lib/pleroma/web/activity_pub/activity_pub_controller.ex:437
+#: lib/pleroma/web/activity_pub/activity_pub_controller.ex:438
 msgid "Can't like object"
 msgstr ""
 
 #, elixir-format
-#: lib/pleroma/web/common_api/utils.ex:556
+#: lib/pleroma/web/common_api/utils.ex:563
 msgid "Cannot post an empty status without attachments"
 msgstr ""
 
 #, elixir-format
-#: lib/pleroma/web/common_api/utils.ex:504
+#: lib/pleroma/web/common_api/utils.ex:511
 msgid "Comment must be up to %{max_size} characters"
 msgstr ""
 
 #, elixir-format
-#: lib/pleroma/config/config_db.ex:222
+#: lib/pleroma/config/config_db.ex:191
 msgid "Config with params %{params} not found"
 msgstr ""
 
 #, elixir-format
-#: lib/pleroma/web/common_api/common_api.ex:95
+#: lib/pleroma/web/common_api/common_api.ex:181
+#: lib/pleroma/web/common_api/common_api.ex:185
 msgid "Could not delete"
 msgstr ""
 
 #, elixir-format
-#: lib/pleroma/web/common_api/common_api.ex:141
+#: lib/pleroma/web/common_api/common_api.ex:231
 msgid "Could not favorite"
 msgstr ""
 
 #, elixir-format
-#: lib/pleroma/web/common_api/common_api.ex:370
+#: lib/pleroma/web/common_api/common_api.ex:453
 msgid "Could not pin"
 msgstr ""
 
 #, elixir-format
-#: lib/pleroma/web/common_api/common_api.ex:112
-msgid "Could not repeat"
-msgstr ""
-
-#, elixir-format
-#: lib/pleroma/web/common_api/common_api.ex:188
+#: lib/pleroma/web/common_api/common_api.ex:278
 msgid "Could not unfavorite"
 msgstr ""
 
 #, elixir-format
-#: lib/pleroma/web/common_api/common_api.ex:380
+#: lib/pleroma/web/common_api/common_api.ex:463
 msgid "Could not unpin"
 msgstr ""
 
 #, elixir-format
-#: lib/pleroma/web/common_api/common_api.ex:126
+#: lib/pleroma/web/common_api/common_api.ex:216
 msgid "Could not unrepeat"
 msgstr ""
 
 #, elixir-format
-#: lib/pleroma/web/common_api/common_api.ex:428
-#: lib/pleroma/web/common_api/common_api.ex:437
+#: lib/pleroma/web/common_api/common_api.ex:512
+#: lib/pleroma/web/common_api/common_api.ex:521
 msgid "Could not update state"
 msgstr ""
 
 #, elixir-format
-#: lib/pleroma/web/mastodon_api/controllers/timeline_controller.ex:202
+#: lib/pleroma/web/mastodon_api/controllers/timeline_controller.ex:207
 msgid "Error."
 msgstr ""
 
@@ -203,8 +193,8 @@ msgid "Invalid CAPTCHA"
 msgstr ""
 
 #, elixir-format
-#: lib/pleroma/web/mastodon_api/controllers/account_controller.ex:117
-#: lib/pleroma/web/oauth/oauth_controller.ex:569
+#: lib/pleroma/web/mastodon_api/controllers/account_controller.ex:116
+#: lib/pleroma/web/oauth/oauth_controller.ex:568
 msgid "Invalid credentials"
 msgstr ""
 
@@ -214,22 +204,22 @@ msgid "Invalid credentials."
 msgstr ""
 
 #, elixir-format
-#: lib/pleroma/web/common_api/common_api.ex:265
+#: lib/pleroma/web/common_api/common_api.ex:355
 msgid "Invalid indices"
 msgstr ""
 
 #, elixir-format
-#: lib/pleroma/web/admin_api/admin_api_controller.ex:1147
+#: lib/pleroma/web/admin_api/controllers/fallback_controller.ex:29
 msgid "Invalid parameters"
 msgstr ""
 
 #, elixir-format
-#: lib/pleroma/web/common_api/utils.ex:411
+#: lib/pleroma/web/common_api/utils.ex:414
 msgid "Invalid password."
 msgstr ""
 
 #, elixir-format
-#: lib/pleroma/web/mastodon_api/controllers/account_controller.ex:187
+#: lib/pleroma/web/mastodon_api/controllers/account_controller.ex:220
 msgid "Invalid request"
 msgstr ""
 
@@ -239,44 +229,44 @@ msgid "Kocaptcha service unavailable"
 msgstr ""
 
 #, elixir-format
-#: lib/pleroma/web/mastodon_api/controllers/account_controller.ex:113
+#: lib/pleroma/web/mastodon_api/controllers/account_controller.ex:112
 msgid "Missing parameters"
 msgstr ""
 
 #, elixir-format
-#: lib/pleroma/web/common_api/utils.ex:540
+#: lib/pleroma/web/common_api/utils.ex:547
 msgid "No such conversation"
 msgstr ""
 
 #, elixir-format
-#: lib/pleroma/web/admin_api/admin_api_controller.ex:439
-#: lib/pleroma/web/admin_api/admin_api_controller.ex:465 lib/pleroma/web/admin_api/admin_api_controller.ex:507
+#: lib/pleroma/web/admin_api/controllers/admin_api_controller.ex:388
+#: lib/pleroma/web/admin_api/controllers/admin_api_controller.ex:414 lib/pleroma/web/admin_api/controllers/admin_api_controller.ex:456
 msgid "No such permission_group"
 msgstr ""
 
 #, elixir-format
-#: lib/pleroma/plugs/uploaded_media.ex:74
-#: lib/pleroma/web/activity_pub/activity_pub_controller.ex:485 lib/pleroma/web/admin_api/admin_api_controller.ex:1135
-#: lib/pleroma/web/feed/user_controller.ex:73 lib/pleroma/web/ostatus/ostatus_controller.ex:143
+#: lib/pleroma/plugs/uploaded_media.ex:84
+#: lib/pleroma/web/activity_pub/activity_pub_controller.ex:486 lib/pleroma/web/admin_api/controllers/fallback_controller.ex:11
+#: lib/pleroma/web/feed/user_controller.ex:71 lib/pleroma/web/ostatus/ostatus_controller.ex:143
 msgid "Not found"
 msgstr ""
 
 #, elixir-format
-#: lib/pleroma/web/common_api/common_api.ex:241
+#: lib/pleroma/web/common_api/common_api.ex:331
 msgid "Poll's author can't vote"
 msgstr ""
 
 #, elixir-format
 #: lib/pleroma/web/mastodon_api/controllers/fallback_controller.ex:20
 #: lib/pleroma/web/mastodon_api/controllers/poll_controller.ex:37 lib/pleroma/web/mastodon_api/controllers/poll_controller.ex:49
-#: lib/pleroma/web/mastodon_api/controllers/poll_controller.ex:50 lib/pleroma/web/mastodon_api/controllers/status_controller.ex:290
+#: lib/pleroma/web/mastodon_api/controllers/poll_controller.ex:50 lib/pleroma/web/mastodon_api/controllers/status_controller.ex:306
 #: lib/pleroma/web/mastodon_api/controllers/subscription_controller.ex:71
 msgid "Record not found"
 msgstr ""
 
 #, elixir-format
-#: lib/pleroma/web/admin_api/admin_api_controller.ex:1153
-#: lib/pleroma/web/feed/user_controller.ex:79 lib/pleroma/web/mastodon_api/controllers/fallback_controller.ex:32
+#: lib/pleroma/web/admin_api/controllers/fallback_controller.ex:35
+#: lib/pleroma/web/feed/user_controller.ex:77 lib/pleroma/web/mastodon_api/controllers/fallback_controller.ex:36
 #: lib/pleroma/web/ostatus/ostatus_controller.ex:149
 msgid "Something went wrong"
 msgstr ""
@@ -287,7 +277,7 @@ msgid "The message visibility must be direct"
 msgstr ""
 
 #, elixir-format
-#: lib/pleroma/web/common_api/utils.ex:566
+#: lib/pleroma/web/common_api/utils.ex:573
 msgid "The status is over the character limit"
 msgstr ""
 
@@ -302,65 +292,65 @@ msgid "Throttled"
 msgstr ""
 
 #, elixir-format
-#: lib/pleroma/web/common_api/common_api.ex:266
+#: lib/pleroma/web/common_api/common_api.ex:356
 msgid "Too many choices"
 msgstr ""
 
 #, elixir-format
-#: lib/pleroma/web/activity_pub/activity_pub_controller.ex:442
+#: lib/pleroma/web/activity_pub/activity_pub_controller.ex:443
 msgid "Unhandled activity type"
 msgstr ""
 
 #, elixir-format
-#: lib/pleroma/web/admin_api/admin_api_controller.ex:536
+#: lib/pleroma/web/admin_api/controllers/admin_api_controller.ex:485
 msgid "You can't revoke your own admin status."
 msgstr ""
 
 #, elixir-format
-#: lib/pleroma/web/oauth/oauth_controller.ex:218
-#: lib/pleroma/web/oauth/oauth_controller.ex:309
+#: lib/pleroma/web/oauth/oauth_controller.ex:221
+#: lib/pleroma/web/oauth/oauth_controller.ex:308
 msgid "Your account is currently disabled"
 msgstr ""
 
 #, elixir-format
-#: lib/pleroma/web/oauth/oauth_controller.ex:180
-#: lib/pleroma/web/oauth/oauth_controller.ex:332
+#: lib/pleroma/web/oauth/oauth_controller.ex:183
+#: lib/pleroma/web/oauth/oauth_controller.ex:331
 msgid "Your login is missing a confirmed e-mail address"
 msgstr ""
 
 #, elixir-format
-#: lib/pleroma/web/activity_pub/activity_pub_controller.ex:389
+#: lib/pleroma/web/activity_pub/activity_pub_controller.ex:390
 msgid "can't read inbox of %{nickname} as %{as_nickname}"
 msgstr ""
 
 #, elixir-format
-#: lib/pleroma/web/activity_pub/activity_pub_controller.ex:472
+#: lib/pleroma/web/activity_pub/activity_pub_controller.ex:473
 msgid "can't update outbox of %{nickname} as %{as_nickname}"
 msgstr ""
 
 #, elixir-format
-#: lib/pleroma/web/common_api/common_api.ex:388
+#: lib/pleroma/web/common_api/common_api.ex:471
 msgid "conversation is already muted"
 msgstr ""
 
 #, elixir-format
-#: lib/pleroma/web/activity_pub/activity_pub_controller.ex:316
-#: lib/pleroma/web/activity_pub/activity_pub_controller.ex:491
+#: lib/pleroma/web/activity_pub/activity_pub_controller.ex:314
+#: lib/pleroma/web/activity_pub/activity_pub_controller.ex:492
 msgid "error"
 msgstr ""
 
 #, elixir-format
-#: lib/pleroma/web/pleroma_api/controllers/mascot_controller.ex:29
+#: lib/pleroma/web/pleroma_api/controllers/mascot_controller.ex:32
 msgid "mascots can only be images"
 msgstr ""
 
 #, elixir-format
-#: lib/pleroma/web/activity_pub/activity_pub_controller.ex:60
+#: lib/pleroma/web/activity_pub/activity_pub_controller.ex:62
 msgid "not found"
 msgstr ""
 
 #, elixir-format
-#: lib/pleroma/web/oauth/oauth_controller.ex:395
+#: lib/pleroma/web/oauth/oauth_controller.ex:394
 msgid "Bad OAuth request."
 msgstr ""
 
@@ -375,17 +365,17 @@ msgid "CAPTCHA expired"
 msgstr ""
 
 #, elixir-format
-#: lib/pleroma/plugs/uploaded_media.ex:55
+#: lib/pleroma/plugs/uploaded_media.ex:57
 msgid "Failed"
 msgstr ""
 
 #, elixir-format
-#: lib/pleroma/web/oauth/oauth_controller.ex:411
+#: lib/pleroma/web/oauth/oauth_controller.ex:410
 msgid "Failed to authenticate: %{message}."
 msgstr ""
 
 #, elixir-format
-#: lib/pleroma/web/oauth/oauth_controller.ex:442
+#: lib/pleroma/web/oauth/oauth_controller.ex:441
 msgid "Failed to set up user account."
 msgstr ""
 
@@ -395,7 +385,7 @@ msgid "Insufficient permissions: %{permissions}."
 msgstr ""
 
 #, elixir-format
-#: lib/pleroma/plugs/uploaded_media.ex:94
+#: lib/pleroma/plugs/uploaded_media.ex:104
 msgid "Internal Error"
 msgstr ""
 
@@ -411,12 +401,12 @@ msgid "Invalid answer data"
 msgstr ""
 
 #, elixir-format
-#: lib/pleroma/web/nodeinfo/nodeinfo_controller.ex:128
+#: lib/pleroma/web/nodeinfo/nodeinfo_controller.ex:33
 msgid "Nodeinfo schema version not handled"
 msgstr ""
 
 #, elixir-format
-#: lib/pleroma/web/oauth/oauth_controller.ex:169
+#: lib/pleroma/web/oauth/oauth_controller.ex:172
 msgid "This action is outside the authorized scopes"
 msgstr ""
 
@@ -426,13 +416,13 @@ msgid "Unknown error, please check the details and try again."
 msgstr ""
 
 #, elixir-format
-#: lib/pleroma/web/oauth/oauth_controller.ex:116
-#: lib/pleroma/web/oauth/oauth_controller.ex:155
+#: lib/pleroma/web/oauth/oauth_controller.ex:119
+#: lib/pleroma/web/oauth/oauth_controller.ex:158
 msgid "Unlisted redirect_uri."
 msgstr ""
 
 #, elixir-format
-#: lib/pleroma/web/oauth/oauth_controller.ex:391
+#: lib/pleroma/web/oauth/oauth_controller.ex:390
 msgid "Unsupported OAuth provider: %{provider}."
 msgstr ""
 
@@ -452,12 +442,12 @@ msgid "CAPTCHA Error"
 msgstr ""
 
 #, elixir-format
-#: lib/pleroma/web/common_api/common_api.ex:200
+#: lib/pleroma/web/common_api/common_api.ex:290
 msgid "Could not add reaction emoji"
 msgstr ""
 
 #, elixir-format
-#: lib/pleroma/web/common_api/common_api.ex:211
+#: lib/pleroma/web/common_api/common_api.ex:301
 msgid "Could not remove reaction emoji"
 msgstr ""
 
@@ -472,39 +462,45 @@ msgid "List not found"
 msgstr ""
 
 #, elixir-format
-#: lib/pleroma/web/mastodon_api/controllers/account_controller.ex:124
+#: lib/pleroma/web/mastodon_api/controllers/account_controller.ex:123
 msgid "Missing parameter: %{name}"
 msgstr ""
 
 #, elixir-format
-#: lib/pleroma/web/oauth/oauth_controller.ex:207
-#: lib/pleroma/web/oauth/oauth_controller.ex:322
+#: lib/pleroma/web/oauth/oauth_controller.ex:210
+#: lib/pleroma/web/oauth/oauth_controller.ex:321
 msgid "Password reset is required"
 msgstr ""
 
 #, elixir-format
 #: lib/pleroma/tests/auth_test_controller.ex:9
-#: lib/pleroma/web/activity_pub/activity_pub_controller.ex:6 lib/pleroma/web/admin_api/admin_api_controller.ex:6
-#: lib/pleroma/web/controller_helper.ex:6 lib/pleroma/web/fallback_redirect_controller.ex:6
-#: lib/pleroma/web/feed/tag_controller.ex:6 lib/pleroma/web/feed/user_controller.ex:6
-#: lib/pleroma/web/mailer/subscription_controller.ex:2 lib/pleroma/web/masto_fe_controller.ex:6
-#: lib/pleroma/web/mastodon_api/controllers/account_controller.ex:6 lib/pleroma/web/mastodon_api/controllers/app_controller.ex:6
-#: lib/pleroma/web/mastodon_api/controllers/auth_controller.ex:6 lib/pleroma/web/mastodon_api/controllers/conversation_controller.ex:6
-#: lib/pleroma/web/mastodon_api/controllers/custom_emoji_controller.ex:6 lib/pleroma/web/mastodon_api/controllers/domain_block_controller.ex:6
-#: lib/pleroma/web/mastodon_api/controllers/fallback_controller.ex:6 lib/pleroma/web/mastodon_api/controllers/filter_controller.ex:6
-#: lib/pleroma/web/mastodon_api/controllers/follow_request_controller.ex:6 lib/pleroma/web/mastodon_api/controllers/instance_controller.ex:6
-#: lib/pleroma/web/mastodon_api/controllers/list_controller.ex:6 lib/pleroma/web/mastodon_api/controllers/marker_controller.ex:6
-#: lib/pleroma/web/mastodon_api/controllers/mastodon_api_controller.ex:14 lib/pleroma/web/mastodon_api/controllers/media_controller.ex:6
-#: lib/pleroma/web/mastodon_api/controllers/notification_controller.ex:6 lib/pleroma/web/mastodon_api/controllers/poll_controller.ex:6
-#: lib/pleroma/web/mastodon_api/controllers/report_controller.ex:8 lib/pleroma/web/mastodon_api/controllers/scheduled_activity_controller.ex:6
-#: lib/pleroma/web/mastodon_api/controllers/search_controller.ex:6 lib/pleroma/web/mastodon_api/controllers/status_controller.ex:6
-#: lib/pleroma/web/mastodon_api/controllers/subscription_controller.ex:7 lib/pleroma/web/mastodon_api/controllers/suggestion_controller.ex:6
-#: lib/pleroma/web/mastodon_api/controllers/timeline_controller.ex:6 lib/pleroma/web/media_proxy/media_proxy_controller.ex:6
-#: lib/pleroma/web/mongooseim/mongoose_im_controller.ex:6 lib/pleroma/web/nodeinfo/nodeinfo_controller.ex:6
-#: lib/pleroma/web/oauth/fallback_controller.ex:6 lib/pleroma/web/oauth/mfa_controller.ex:10
-#: lib/pleroma/web/oauth/oauth_controller.ex:6 lib/pleroma/web/ostatus/ostatus_controller.ex:6
-#: lib/pleroma/web/pleroma_api/controllers/account_controller.ex:6 lib/pleroma/web/pleroma_api/controllers/emoji_api_controller.ex:2
-#: lib/pleroma/web/pleroma_api/controllers/mascot_controller.ex:6 lib/pleroma/web/pleroma_api/controllers/pleroma_api_controller.ex:6
+#: lib/pleroma/web/activity_pub/activity_pub_controller.ex:6 lib/pleroma/web/admin_api/controllers/admin_api_controller.ex:6
+#: lib/pleroma/web/admin_api/controllers/config_controller.ex:6 lib/pleroma/web/admin_api/controllers/fallback_controller.ex:6
+#: lib/pleroma/web/admin_api/controllers/invite_controller.ex:6 lib/pleroma/web/admin_api/controllers/media_proxy_cache_controller.ex:6
+#: lib/pleroma/web/admin_api/controllers/oauth_app_controller.ex:6 lib/pleroma/web/admin_api/controllers/relay_controller.ex:6
+#: lib/pleroma/web/admin_api/controllers/report_controller.ex:6 lib/pleroma/web/admin_api/controllers/status_controller.ex:6
+#: lib/pleroma/web/controller_helper.ex:6 lib/pleroma/web/embed_controller.ex:6
+#: lib/pleroma/web/fallback_redirect_controller.ex:6 lib/pleroma/web/feed/tag_controller.ex:6
+#: lib/pleroma/web/feed/user_controller.ex:6 lib/pleroma/web/mailer/subscription_controller.ex:2
+#: lib/pleroma/web/masto_fe_controller.ex:6 lib/pleroma/web/mastodon_api/controllers/account_controller.ex:6
+#: lib/pleroma/web/mastodon_api/controllers/app_controller.ex:6 lib/pleroma/web/mastodon_api/controllers/auth_controller.ex:6
+#: lib/pleroma/web/mastodon_api/controllers/conversation_controller.ex:6 lib/pleroma/web/mastodon_api/controllers/custom_emoji_controller.ex:6
+#: lib/pleroma/web/mastodon_api/controllers/domain_block_controller.ex:6 lib/pleroma/web/mastodon_api/controllers/fallback_controller.ex:6
+#: lib/pleroma/web/mastodon_api/controllers/filter_controller.ex:6 lib/pleroma/web/mastodon_api/controllers/follow_request_controller.ex:6
+#: lib/pleroma/web/mastodon_api/controllers/instance_controller.ex:6 lib/pleroma/web/mastodon_api/controllers/list_controller.ex:6
+#: lib/pleroma/web/mastodon_api/controllers/marker_controller.ex:6 lib/pleroma/web/mastodon_api/controllers/mastodon_api_controller.ex:14
+#: lib/pleroma/web/mastodon_api/controllers/media_controller.ex:6 lib/pleroma/web/mastodon_api/controllers/notification_controller.ex:6
+#: lib/pleroma/web/mastodon_api/controllers/poll_controller.ex:6 lib/pleroma/web/mastodon_api/controllers/report_controller.ex:8
+#: lib/pleroma/web/mastodon_api/controllers/scheduled_activity_controller.ex:6 lib/pleroma/web/mastodon_api/controllers/search_controller.ex:6
+#: lib/pleroma/web/mastodon_api/controllers/status_controller.ex:6 lib/pleroma/web/mastodon_api/controllers/subscription_controller.ex:7
+#: lib/pleroma/web/mastodon_api/controllers/suggestion_controller.ex:6 lib/pleroma/web/mastodon_api/controllers/timeline_controller.ex:6
+#: lib/pleroma/web/media_proxy/media_proxy_controller.ex:6 lib/pleroma/web/mongooseim/mongoose_im_controller.ex:6
+#: lib/pleroma/web/nodeinfo/nodeinfo_controller.ex:6 lib/pleroma/web/oauth/fallback_controller.ex:6
+#: lib/pleroma/web/oauth/mfa_controller.ex:10 lib/pleroma/web/oauth/oauth_controller.ex:6
+#: lib/pleroma/web/ostatus/ostatus_controller.ex:6 lib/pleroma/web/pleroma_api/controllers/account_controller.ex:6
+#: lib/pleroma/web/pleroma_api/controllers/chat_controller.ex:5 lib/pleroma/web/pleroma_api/controllers/conversation_controller.ex:6
+#: lib/pleroma/web/pleroma_api/controllers/emoji_pack_controller.ex:2 lib/pleroma/web/pleroma_api/controllers/emoji_reaction_controller.ex:6
+#: lib/pleroma/web/pleroma_api/controllers/mascot_controller.ex:6 lib/pleroma/web/pleroma_api/controllers/notification_controller.ex:6
 #: lib/pleroma/web/pleroma_api/controllers/scrobble_controller.ex:6
 #: lib/pleroma/web/pleroma_api/controllers/two_factor_authentication_controller.ex:7 lib/pleroma/web/static_fe/static_fe_controller.ex:6
 #: lib/pleroma/web/twitter_api/controllers/password_controller.ex:10 lib/pleroma/web/twitter_api/controllers/remote_follow_controller.ex:6
@@ -519,46 +515,56 @@ msgid "Two-factor authentication enabled, you must use a access token."
 msgstr ""
 
 #, elixir-format
-#: lib/pleroma/web/pleroma_api/controllers/emoji_api_controller.ex:210
+#: lib/pleroma/web/pleroma_api/controllers/emoji_pack_controller.ex:210
 msgid "Unexpected error occurred while adding file to pack."
 msgstr ""
 
 #, elixir-format
-#: lib/pleroma/web/pleroma_api/controllers/emoji_api_controller.ex:138
+#: lib/pleroma/web/pleroma_api/controllers/emoji_pack_controller.ex:138
 msgid "Unexpected error occurred while creating pack."
 msgstr ""
 
 #, elixir-format
-#: lib/pleroma/web/pleroma_api/controllers/emoji_api_controller.ex:278
+#: lib/pleroma/web/pleroma_api/controllers/emoji_pack_controller.ex:278
 msgid "Unexpected error occurred while removing file from pack."
 msgstr ""
 
 #, elixir-format
-#: lib/pleroma/web/pleroma_api/controllers/emoji_api_controller.ex:250
+#: lib/pleroma/web/pleroma_api/controllers/emoji_pack_controller.ex:250
 msgid "Unexpected error occurred while updating file in pack."
 msgstr ""
 
 #, elixir-format
-#: lib/pleroma/web/pleroma_api/controllers/emoji_api_controller.ex:179
+#: lib/pleroma/web/pleroma_api/controllers/emoji_pack_controller.ex:179
 msgid "Unexpected error occurred while updating pack metadata."
 msgstr ""
 
-#, elixir-format
-#: lib/pleroma/plugs/user_is_admin_plug.ex:40
-msgid "User is not an admin or OAuth admin scope is not granted."
-msgstr ""
-
 #, elixir-format
 #: lib/pleroma/web/mastodon_api/controllers/subscription_controller.ex:61
 msgid "Web push subscription is disabled on this Pleroma instance"
 msgstr ""
 
 #, elixir-format
-#: lib/pleroma/web/admin_api/admin_api_controller.ex:502
+#: lib/pleroma/web/admin_api/controllers/admin_api_controller.ex:451
 msgid "You can't revoke your own admin/moderator status."
 msgstr ""
 
 #, elixir-format
-#: lib/pleroma/web/mastodon_api/controllers/timeline_controller.ex:105
+#: lib/pleroma/web/mastodon_api/controllers/timeline_controller.ex:126
 msgid "authorization required for timeline view"
 msgstr ""
+
+#, elixir-format
+#: lib/pleroma/web/mastodon_api/controllers/fallback_controller.ex:24
+msgid "Access denied"
+msgstr ""
+
+#, elixir-format
+#: lib/pleroma/web/mastodon_api/controllers/account_controller.ex:282
+msgid "This API requires an authenticated user"
+msgstr ""
+
+#, elixir-format
+#: lib/pleroma/plugs/user_is_admin_plug.ex:21
+msgid "User is not an admin."
+msgstr ""
index 406a297d1b1d1f8dc550c1fef1cc9151539c01dc..cd0cd6c658b1b7af72b2165374213ef9afe1bbdb 100644 (file)
@@ -562,11 +562,11 @@ msgstr "Errore inaspettato durante l'aggiornamento del file nel pacchetto."
 msgid "Unexpected error occurred while updating pack metadata."
 msgstr "Errore inaspettato durante l'aggiornamento dei metadati del pacchetto."
 
-#: lib/pleroma/plugs/user_is_admin_plug.ex:40
+#: lib/pleroma/plugs/user_is_admin_plug.ex:21
 #, elixir-format
-msgid "User is not an admin or OAuth admin scope is not granted."
+msgid "User is not an admin."
 msgstr ""
-"L'utente non è un amministratore o non ha ricevuto questa autorizzazione "
+"L'utente non è un amministratore."
 "OAuth."
 
 #: lib/pleroma/web/mastodon_api/controllers/subscription_controller.ex:61
index 3118f6b5d9eb749145d1c870954d8467be006459..cfcb05fe67a56dc508954f936db29cec6ec0dacf 100644 (file)
@@ -559,9 +559,9 @@ msgstr ""
 msgid "Unexpected error occurred while updating pack metadata."
 msgstr ""
 
-#: lib/pleroma/plugs/user_is_admin_plug.ex:40
+#: lib/pleroma/plugs/user_is_admin_plug.ex:21
 #, elixir-format
-msgid "User is not an admin or OAuth admin scope is not granted."
+msgid "User is not an admin."
 msgstr ""
 
 #: lib/pleroma/web/mastodon_api/controllers/subscription_controller.ex:61
index 7241d8a0a95b42300f5fd8ce13877557b1fd4257..653ea00a162077982760468a31587ba1826711f4 100644 (file)
@@ -566,9 +566,9 @@ msgstr "Nieoczekiwany błąd podczas zmieniania pliku w paczce."
 msgid "Unexpected error occurred while updating pack metadata."
 msgstr "Nieoczekiwany błąd podczas zmieniania metadanych paczki."
 
-#: lib/pleroma/plugs/user_is_admin_plug.ex:40
+#: lib/pleroma/plugs/user_is_admin_plug.ex:21
 #, elixir-format
-msgid "User is not an admin or OAuth admin scope is not granted."
+msgid "User is not an admin."
 msgstr ""
 
 #: lib/pleroma/web/mastodon_api/controllers/subscription_controller.ex:61
diff --git a/priv/repo/migrations/20200714081657_oban_2_0_config_changes.exs b/priv/repo/migrations/20200714081657_oban_2_0_config_changes.exs
new file mode 100644 (file)
index 0000000..c54bb25
--- /dev/null
@@ -0,0 +1,27 @@
+defmodule Elixir.Pleroma.Repo.Migrations.Oban20ConfigChanges do
+  use Ecto.Migration
+  import Ecto.Query
+  alias Pleroma.ConfigDB
+  alias Pleroma.Repo
+
+  def change do
+    config_entry =
+      from(c in ConfigDB, where: c.group == ^":pleroma" and c.key == ^"Oban")
+      |> select([c], struct(c, [:value, :id]))
+      |> Repo.one()
+
+    if config_entry do
+      %{value: value} = config_entry
+
+      value =
+        case Keyword.fetch(value, :verbose) do
+          {:ok, log} -> Keyword.put_new(value, :log, log)
+          _ -> value
+        end
+        |> Keyword.drop([:verbose, :prune])
+
+      Ecto.Changeset.change(config_entry, %{value: value})
+      |> Repo.update()
+    end
+  end
+end
index 548ee87b01b6ed784028562519bb5631c096bd6d..555661a715481539df6e333df6d60e33c0e80df5 100644 (file)
@@ -54,4 +54,12 @@ defmodule Pleroma.Config.DeprecationWarningsTest do
     assert Pleroma.Config.get(new_group2) == 2
     assert Pleroma.Config.get(new_group3) == 3
   end
+
+  test "check_media_proxy_whitelist_config/0" do
+    clear_config([:media_proxy, :whitelist], ["https://example.com", "example2.com"])
+
+    assert capture_log(fn ->
+             Pleroma.Config.DeprecationWarnings.check_media_proxy_whitelist_config()
+           end) =~ "Your config is using old format (only domain) for MediaProxy whitelist option"
+  end
 end
index 100016c62842461e987b0c04f82efa71fe6a45a2..89df03c4b719bd56c33fa11e44dd0060fd91f0e4 100644 (file)
@@ -4,9 +4,14 @@
 
 defmodule Pleroma.Plugs.AdminSecretAuthenticationPlugTest do
   use Pleroma.Web.ConnCase, async: true
+
+  import Mock
   import Pleroma.Factory
 
   alias Pleroma.Plugs.AdminSecretAuthenticationPlug
+  alias Pleroma.Plugs.OAuthScopesPlug
+  alias Pleroma.Plugs.PlugHelper
+  alias Pleroma.Plugs.RateLimiter
 
   test "does nothing if a user is assigned", %{conn: conn} do
     user = insert(:user)
@@ -25,6 +30,10 @@ defmodule Pleroma.Plugs.AdminSecretAuthenticationPlugTest do
   describe "when secret set it assigns an admin user" do
     setup do: clear_config([:admin_token])
 
+    setup_with_mocks([{RateLimiter, [:passthrough], []}]) do
+      :ok
+    end
+
     test "with `admin_token` query parameter", %{conn: conn} do
       Pleroma.Config.put(:admin_token, "password123")
 
@@ -33,12 +42,14 @@ defmodule Pleroma.Plugs.AdminSecretAuthenticationPlugTest do
         |> AdminSecretAuthenticationPlug.call(%{})
 
       refute conn.assigns[:user]
+      assert called(RateLimiter.call(conn, name: :authentication))
 
       conn =
         %{conn | params: %{"admin_token" => "password123"}}
         |> AdminSecretAuthenticationPlug.call(%{})
 
       assert conn.assigns[:user].is_admin
+      assert PlugHelper.plug_skipped?(conn, OAuthScopesPlug)
     end
 
     test "with `x-admin-token` HTTP header", %{conn: conn} do
@@ -50,6 +61,7 @@ defmodule Pleroma.Plugs.AdminSecretAuthenticationPlugTest do
         |> AdminSecretAuthenticationPlug.call(%{})
 
       refute conn.assigns[:user]
+      assert called(RateLimiter.call(conn, name: :authentication))
 
       conn =
         conn
@@ -57,6 +69,7 @@ defmodule Pleroma.Plugs.AdminSecretAuthenticationPlugTest do
         |> AdminSecretAuthenticationPlug.call(%{})
 
       assert conn.assigns[:user].is_admin
+      assert PlugHelper.plug_skipped?(conn, OAuthScopesPlug)
     end
   end
 end
index 63b4d3f31fefe5a0ec8edfd43fbac8ded7ebb73a..2297e3dac3d1106a83aa02844b14adf2b5193e73 100644 (file)
@@ -4,17 +4,12 @@
 
 defmodule Pleroma.Web.Plugs.HTTPSecurityPlugTest do
   use Pleroma.Web.ConnCase
+
   alias Pleroma.Config
   alias Plug.Conn
 
-  setup do: clear_config([:http_securiy, :enabled])
-  setup do: clear_config([:http_security, :sts])
-  setup do: clear_config([:http_security, :referrer_policy])
-
   describe "http security enabled" do
-    setup do
-      Config.put([:http_security, :enabled], true)
-    end
+    setup do: clear_config([:http_security, :enabled], true)
 
     test "it sends CSP headers when enabled", %{conn: conn} do
       conn = get(conn, "/api/v1/instance")
@@ -29,7 +24,7 @@ defmodule Pleroma.Web.Plugs.HTTPSecurityPlugTest do
     end
 
     test "it sends STS headers when enabled", %{conn: conn} do
-      Config.put([:http_security, :sts], true)
+      clear_config([:http_security, :sts], true)
 
       conn = get(conn, "/api/v1/instance")
 
@@ -38,7 +33,7 @@ defmodule Pleroma.Web.Plugs.HTTPSecurityPlugTest do
     end
 
     test "it does not send STS headers when disabled", %{conn: conn} do
-      Config.put([:http_security, :sts], false)
+      clear_config([:http_security, :sts], false)
 
       conn = get(conn, "/api/v1/instance")
 
@@ -47,23 +42,19 @@ defmodule Pleroma.Web.Plugs.HTTPSecurityPlugTest do
     end
 
     test "referrer-policy header reflects configured value", %{conn: conn} do
-      conn = get(conn, "/api/v1/instance")
+      resp = get(conn, "/api/v1/instance")
 
-      assert Conn.get_resp_header(conn, "referrer-policy") == ["same-origin"]
+      assert Conn.get_resp_header(resp, "referrer-policy") == ["same-origin"]
 
-      Config.put([:http_security, :referrer_policy], "no-referrer")
+      clear_config([:http_security, :referrer_policy], "no-referrer")
 
-      conn =
-        build_conn()
-        |> get("/api/v1/instance")
+      resp = get(conn, "/api/v1/instance")
 
-      assert Conn.get_resp_header(conn, "referrer-policy") == ["no-referrer"]
+      assert Conn.get_resp_header(resp, "referrer-policy") == ["no-referrer"]
     end
 
-    test "it sends `report-to` & `report-uri` CSP response headers" do
-      conn =
-        build_conn()
-        |> get("/api/v1/instance")
+    test "it sends `report-to` & `report-uri` CSP response headers", %{conn: conn} do
+      conn = get(conn, "/api/v1/instance")
 
       [csp] = Conn.get_resp_header(conn, "content-security-policy")
 
@@ -74,10 +65,67 @@ defmodule Pleroma.Web.Plugs.HTTPSecurityPlugTest do
       assert reply_to ==
                "{\"endpoints\":[{\"url\":\"https://endpoint.com\"}],\"group\":\"csp-endpoint\",\"max-age\":10886400}"
     end
+
+    test "default values for img-src and media-src with disabled media proxy", %{conn: conn} do
+      conn = get(conn, "/api/v1/instance")
+
+      [csp] = Conn.get_resp_header(conn, "content-security-policy")
+      assert csp =~ "media-src 'self' https:;"
+      assert csp =~ "img-src 'self' data: blob: https:;"
+    end
+  end
+
+  describe "img-src and media-src" do
+    setup do
+      clear_config([:http_security, :enabled], true)
+      clear_config([:media_proxy, :enabled], true)
+      clear_config([:media_proxy, :proxy_opts, :redirect_on_failure], false)
+    end
+
+    test "media_proxy with base_url", %{conn: conn} do
+      url = "https://example.com"
+      clear_config([:media_proxy, :base_url], url)
+      assert_media_img_src(conn, url)
+    end
+
+    test "upload with base url", %{conn: conn} do
+      url = "https://example2.com"
+      clear_config([Pleroma.Upload, :base_url], url)
+      assert_media_img_src(conn, url)
+    end
+
+    test "with S3 public endpoint", %{conn: conn} do
+      url = "https://example3.com"
+      clear_config([Pleroma.Uploaders.S3, :public_endpoint], url)
+      assert_media_img_src(conn, url)
+    end
+
+    test "with captcha endpoint", %{conn: conn} do
+      clear_config([Pleroma.Captcha.Mock, :endpoint], "https://captcha.com")
+      assert_media_img_src(conn, "https://captcha.com")
+    end
+
+    test "with media_proxy whitelist", %{conn: conn} do
+      clear_config([:media_proxy, :whitelist], ["https://example6.com", "https://example7.com"])
+      assert_media_img_src(conn, "https://example7.com https://example6.com")
+    end
+
+    # TODO: delete after removing support bare domains for media proxy whitelist
+    test "with media_proxy bare domains whitelist (deprecated)", %{conn: conn} do
+      clear_config([:media_proxy, :whitelist], ["example4.com", "example5.com"])
+      assert_media_img_src(conn, "example5.com example4.com")
+    end
+  end
+
+  defp assert_media_img_src(conn, url) do
+    conn = get(conn, "/api/v1/instance")
+    [csp] = Conn.get_resp_header(conn, "content-security-policy")
+    assert csp =~ "media-src 'self' #{url};"
+    assert csp =~ "img-src 'self' data: blob: #{url};"
   end
 
   test "it does not send CSP headers when disabled", %{conn: conn} do
-    Config.put([:http_security, :enabled], false)
+    clear_config([:http_security, :enabled], false)
 
     conn = get(conn, "/api/v1/instance")
 
index fd6a50e534e62079d33993470f000322fac93792..8bc00e44497a58dafcdb48600fe07ca88880955f 100644 (file)
@@ -8,112 +8,30 @@ defmodule Pleroma.Plugs.UserIsAdminPlugTest do
   alias Pleroma.Plugs.UserIsAdminPlug
   import Pleroma.Factory
 
-  describe "unless [:auth, :enforce_oauth_admin_scope_usage]," do
-    setup do: clear_config([:auth, :enforce_oauth_admin_scope_usage], false)
+  test "accepts a user that is an admin" do
+    user = insert(:user, is_admin: true)
 
-    test "accepts a user that is an admin" do
-      user = insert(:user, is_admin: true)
+    conn = assign(build_conn(), :user, user)
 
-      conn = assign(build_conn(), :user, user)
+    ret_conn = UserIsAdminPlug.call(conn, %{})
 
-      ret_conn = UserIsAdminPlug.call(conn, %{})
-
-      assert conn == ret_conn
-    end
-
-    test "denies a user that isn't an admin" do
-      user = insert(:user)
-
-      conn =
-        build_conn()
-        |> assign(:user, user)
-        |> UserIsAdminPlug.call(%{})
-
-      assert conn.status == 403
-    end
-
-    test "denies when a user isn't set" do
-      conn = UserIsAdminPlug.call(build_conn(), %{})
-
-      assert conn.status == 403
-    end
+    assert conn == ret_conn
   end
 
-  describe "with [:auth, :enforce_oauth_admin_scope_usage]," do
-    setup do: clear_config([:auth, :enforce_oauth_admin_scope_usage], true)
-
-    setup do
-      admin_user = insert(:user, is_admin: true)
-      non_admin_user = insert(:user, is_admin: false)
-      blank_user = nil
-
-      {:ok, %{users: [admin_user, non_admin_user, blank_user]}}
-    end
-
-    test "if token has any of admin scopes, accepts a user that is an admin", %{conn: conn} do
-      user = insert(:user, is_admin: true)
-      token = insert(:oauth_token, user: user, scopes: ["admin:something"])
-
-      conn =
-        conn
-        |> assign(:user, user)
-        |> assign(:token, token)
+  test "denies a user that isn't an admin" do
+    user = insert(:user)
 
-      ret_conn = UserIsAdminPlug.call(conn, %{})
+    conn =
+      build_conn()
+      |> assign(:user, user)
+      |> UserIsAdminPlug.call(%{})
 
-      assert conn == ret_conn
-    end
-
-    test "if token has any of admin scopes, denies a user that isn't an admin", %{conn: conn} do
-      user = insert(:user, is_admin: false)
-      token = insert(:oauth_token, user: user, scopes: ["admin:something"])
-
-      conn =
-        conn
-        |> assign(:user, user)
-        |> assign(:token, token)
-        |> UserIsAdminPlug.call(%{})
-
-      assert conn.status == 403
-    end
-
-    test "if token has any of admin scopes, denies when a user isn't set", %{conn: conn} do
-      token = insert(:oauth_token, scopes: ["admin:something"])
-
-      conn =
-        conn
-        |> assign(:user, nil)
-        |> assign(:token, token)
-        |> UserIsAdminPlug.call(%{})
-
-      assert conn.status == 403
-    end
-
-    test "if token lacks admin scopes, denies users regardless of is_admin flag",
-         %{users: users} do
-      for user <- users do
-        token = insert(:oauth_token, user: user)
-
-        conn =
-          build_conn()
-          |> assign(:user, user)
-          |> assign(:token, token)
-          |> UserIsAdminPlug.call(%{})
-
-        assert conn.status == 403
-      end
-    end
+    assert conn.status == 403
+  end
 
-    test "if token is missing, denies users regardless of is_admin flag", %{users: users} do
-      for user <- users do
-        conn =
-          build_conn()
-          |> assign(:user, user)
-          |> assign(:token, nil)
-          |> UserIsAdminPlug.call(%{})
+  test "denies when a user isn't set" do
+    conn = UserIsAdminPlug.call(build_conn(), %{})
 
-        assert conn.status == 403
-      end
-    end
+    assert conn.status == 403
   end
 end
index e722f7c04ee157c990365d5e741b7b6449b6c734..ed900d8f84e3261b2ce53a742f8cd99bbbe5440b 100644 (file)
@@ -1082,6 +1082,45 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do
       assert object = Object.get_by_ap_id(note_object.data["id"])
       assert object.data["like_count"] == 1
     end
+
+    test "it doesn't spreads faulty attributedTo or actor fields", %{
+      conn: conn,
+      activity: activity
+    } do
+      reimu = insert(:user, nickname: "reimu")
+      cirno = insert(:user, nickname: "cirno")
+
+      assert reimu.ap_id
+      assert cirno.ap_id
+
+      activity =
+        activity
+        |> put_in(["object", "actor"], reimu.ap_id)
+        |> put_in(["object", "attributedTo"], reimu.ap_id)
+        |> put_in(["actor"], reimu.ap_id)
+        |> put_in(["attributedTo"], reimu.ap_id)
+
+      _reimu_outbox =
+        conn
+        |> assign(:user, cirno)
+        |> put_req_header("content-type", "application/activity+json")
+        |> post("/users/#{reimu.nickname}/outbox", activity)
+        |> json_response(403)
+
+      cirno_outbox =
+        conn
+        |> assign(:user, cirno)
+        |> put_req_header("content-type", "application/activity+json")
+        |> post("/users/#{cirno.nickname}/outbox", activity)
+        |> json_response(201)
+
+      assert cirno_outbox["attributedTo"] == nil
+      assert cirno_outbox["actor"] == cirno.ap_id
+
+      assert cirno_object = Object.normalize(cirno_outbox["object"])
+      assert cirno_object.data["actor"] == cirno.ap_id
+      assert cirno_object.data["attributedTo"] == cirno.ap_id
+    end
   end
 
   describe "/relay/followers" do
index fca0de7c6f25cfed5d5ef4576705e7a0c704efb3..3c795f5ac407a35869d222857e9df41799f9ba2b 100644 (file)
@@ -21,7 +21,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.AntiFollowbotPolicyTest do
         "id" => "https://example.com/activities/1234"
       }
 
-      {:reject, nil} = AntiFollowbotPolicy.filter(message)
+      assert {:reject, "[AntiFollowbotPolicy]" <> _} = AntiFollowbotPolicy.filter(message)
     end
 
     test "matches followbots by display name" do
@@ -36,7 +36,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.AntiFollowbotPolicyTest do
         "id" => "https://example.com/activities/1234"
       }
 
-      {:reject, nil} = AntiFollowbotPolicy.filter(message)
+      assert {:reject, "[AntiFollowbotPolicy]" <> _} = AntiFollowbotPolicy.filter(message)
     end
   end
 
index 6e9daa7f97cbbe2ec6acfc80f6ebd6e0d244a108..26f5bcdaa83ac9d8ab7f4580677a88f9d5ebfcb0 100644 (file)
@@ -50,7 +50,8 @@ defmodule Pleroma.Web.ActivityPub.MRF.HellthreadPolicyTest do
     } do
       Pleroma.Config.put([:mrf_hellthread], %{delist_threshold: 0, reject_threshold: 2})
 
-      {:reject, nil} = filter(message)
+      assert {:reject, "[HellthreadPolicy] 3 recipients is over the limit of 2"} ==
+               filter(message)
     end
 
     test "does not reject the message if the recipient count is below reject_threshold", %{
index fd1f7aec804ef13ea635ed2ba9923741e1c48335..b3d0f3d90620b39b104cb0dbf8ff7c5bc6d41d89 100644 (file)
@@ -25,7 +25,8 @@ defmodule Pleroma.Web.ActivityPub.MRF.KeywordPolicyTest do
         }
       }
 
-      assert {:reject, nil} == KeywordPolicy.filter(message)
+      assert {:reject, "[KeywordPolicy] Matches with rejected keyword"} =
+               KeywordPolicy.filter(message)
     end
 
     test "rejects if string matches in summary" do
@@ -39,7 +40,8 @@ defmodule Pleroma.Web.ActivityPub.MRF.KeywordPolicyTest do
         }
       }
 
-      assert {:reject, nil} == KeywordPolicy.filter(message)
+      assert {:reject, "[KeywordPolicy] Matches with rejected keyword"} =
+               KeywordPolicy.filter(message)
     end
 
     test "rejects if regex matches in content" do
@@ -55,7 +57,8 @@ defmodule Pleroma.Web.ActivityPub.MRF.KeywordPolicyTest do
                    }
                  }
 
-                 {:reject, nil} == KeywordPolicy.filter(message)
+                 {:reject, "[KeywordPolicy] Matches with rejected keyword"} ==
+                   KeywordPolicy.filter(message)
                end)
     end
 
@@ -72,7 +75,8 @@ defmodule Pleroma.Web.ActivityPub.MRF.KeywordPolicyTest do
                    }
                  }
 
-                 {:reject, nil} == KeywordPolicy.filter(message)
+                 {:reject, "[KeywordPolicy] Matches with rejected keyword"} ==
+                   KeywordPolicy.filter(message)
                end)
     end
   end
index aa003bef5182d53b741f0468f26fb7c6f8ec4161..220309cc94c9484948c1e942bd330325064e2bc3 100644 (file)
@@ -76,7 +76,8 @@ defmodule Pleroma.Web.ActivityPub.MRF.MentionPolicyTest do
         "to" => ["https://example.com/blocked"]
       }
 
-      assert MentionPolicy.filter(message) == {:reject, nil}
+      assert MentionPolicy.filter(message) ==
+               {:reject, "[MentionPolicy] Rejected for mention of https://example.com/blocked"}
     end
 
     test "cc" do
@@ -88,7 +89,8 @@ defmodule Pleroma.Web.ActivityPub.MRF.MentionPolicyTest do
         "cc" => ["https://example.com/blocked"]
       }
 
-      assert MentionPolicy.filter(message) == {:reject, nil}
+      assert MentionPolicy.filter(message) ==
+               {:reject, "[MentionPolicy] Rejected for mention of https://example.com/blocked"}
     end
   end
 end
index f36299b861072768f02fe3f8f9af5aa848041cfc..58b46b9a2cf41d0d960236306d1c4b3db97ce156 100644 (file)
@@ -64,7 +64,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.RejectNonPublicTest do
       }
 
       Pleroma.Config.put([:mrf_rejectnonpublic, :allow_followersonly], false)
-      assert {:reject, nil} = RejectNonPublic.filter(message)
+      assert {:reject, _} = RejectNonPublic.filter(message)
     end
   end
 
@@ -94,7 +94,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.RejectNonPublicTest do
       }
 
       Pleroma.Config.put([:mrf_rejectnonpublic, :allow_direct], false)
-      assert {:reject, nil} = RejectNonPublic.filter(message)
+      assert {:reject, _} = RejectNonPublic.filter(message)
     end
   end
 end
index b7b9bc6a2f8907caa80684b50c6a0b37b6237c98..e842d8d8de023fb3d3cdfbae9b5bf6ab5a11d096 100644 (file)
@@ -124,7 +124,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicyTest do
       report_message = build_report_message()
       local_message = build_local_message()
 
-      assert SimplePolicy.filter(report_message) == {:reject, nil}
+      assert {:reject, _} = SimplePolicy.filter(report_message)
       assert SimplePolicy.filter(local_message) == {:ok, local_message}
     end
 
@@ -133,7 +133,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicyTest do
       report_message = build_report_message()
       local_message = build_local_message()
 
-      assert SimplePolicy.filter(report_message) == {:reject, nil}
+      assert {:reject, _} = SimplePolicy.filter(report_message)
       assert SimplePolicy.filter(local_message) == {:ok, local_message}
     end
   end
@@ -241,7 +241,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicyTest do
 
       remote_message = build_remote_message()
 
-      assert SimplePolicy.filter(remote_message) == {:reject, nil}
+      assert {:reject, _} = SimplePolicy.filter(remote_message)
     end
 
     test "activity matches with wildcard domain" do
@@ -249,7 +249,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicyTest do
 
       remote_message = build_remote_message()
 
-      assert SimplePolicy.filter(remote_message) == {:reject, nil}
+      assert {:reject, _} = SimplePolicy.filter(remote_message)
     end
 
     test "actor has a matching host" do
@@ -257,7 +257,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicyTest do
 
       remote_user = build_remote_user()
 
-      assert SimplePolicy.filter(remote_user) == {:reject, nil}
+      assert {:reject, _} = SimplePolicy.filter(remote_user)
     end
   end
 
@@ -279,7 +279,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicyTest do
       remote_message = build_remote_message()
 
       assert SimplePolicy.filter(local_message) == {:ok, local_message}
-      assert SimplePolicy.filter(remote_message) == {:reject, nil}
+      assert {:reject, _} = SimplePolicy.filter(remote_message)
     end
 
     test "activity has a matching host" do
@@ -429,7 +429,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicyTest do
     test "it rejects the deletion" do
       deletion_message = build_remote_deletion_message()
 
-      assert SimplePolicy.filter(deletion_message) == {:reject, nil}
+      assert {:reject, _} = SimplePolicy.filter(deletion_message)
     end
   end
 
@@ -439,7 +439,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.SimplePolicyTest do
     test "it rejects the deletion" do
       deletion_message = build_remote_deletion_message()
 
-      assert SimplePolicy.filter(deletion_message) == {:reject, nil}
+      assert {:reject, _} = SimplePolicy.filter(deletion_message)
     end
   end
 
index e7793641a458d50ea89851a08fd0d757e77efeed..6ff71d6408358fd1471b21674892a05986d95920 100644 (file)
@@ -12,8 +12,8 @@ defmodule Pleroma.Web.ActivityPub.MRF.TagPolicyTest do
   describe "mrf_tag:disable-any-subscription" do
     test "rejects message" do
       actor = insert(:user, tags: ["mrf_tag:disable-any-subscription"])
-      message = %{"object" => actor.ap_id, "type" => "Follow"}
-      assert {:reject, nil} = TagPolicy.filter(message)
+      message = %{"object" => actor.ap_id, "type" => "Follow", "actor" => actor.ap_id}
+      assert {:reject, _} = TagPolicy.filter(message)
     end
   end
 
@@ -22,7 +22,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.TagPolicyTest do
       actor = insert(:user, tags: ["mrf_tag:disable-remote-subscription"])
       follower = insert(:user, tags: ["mrf_tag:disable-remote-subscription"], local: false)
       message = %{"object" => actor.ap_id, "type" => "Follow", "actor" => follower.ap_id}
-      assert {:reject, nil} = TagPolicy.filter(message)
+      assert {:reject, _} = TagPolicy.filter(message)
     end
 
     test "allows non-local follow requests" do
index ba1b696588336be81b94f00d854a243dbbbdf866..8e1ad5bc83dadf07fd6e89e9dc5b687eef92b31a 100644 (file)
@@ -26,6 +26,6 @@ defmodule Pleroma.Web.ActivityPub.MRF.UserAllowListPolicyTest do
     actor = insert(:user)
     Pleroma.Config.put([:mrf_user_allowlist], %{"localhost" => ["test-ap-id"]})
     message = %{"actor" => actor.ap_id}
-    assert UserAllowListPolicy.filter(message) == {:reject, nil}
+    assert {:reject, _} = UserAllowListPolicy.filter(message)
   end
 end
index 69f22bb77cabcfe8ca36d8c5c877917900eb8134..2bceb67ee85f6768430c4a53389748b2899a4a32 100644 (file)
@@ -46,7 +46,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.VocabularyPolicyTest do
         }
       }
 
-      {:reject, nil} = VocabularyPolicy.filter(message)
+      {:reject, _} = VocabularyPolicy.filter(message)
     end
 
     test "it does not accept disallowed parent types" do
@@ -60,7 +60,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.VocabularyPolicyTest do
         }
       }
 
-      {:reject, nil} = VocabularyPolicy.filter(message)
+      {:reject, _} = VocabularyPolicy.filter(message)
     end
   end
 
@@ -75,7 +75,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.VocabularyPolicyTest do
         "object" => "whatever"
       }
 
-      {:reject, nil} = VocabularyPolicy.filter(message)
+      {:reject, _} = VocabularyPolicy.filter(message)
     end
 
     test "it rejects based on child object type" do
@@ -89,7 +89,7 @@ defmodule Pleroma.Web.ActivityPub.MRF.VocabularyPolicyTest do
         }
       }
 
-      {:reject, nil} = VocabularyPolicy.filter(message)
+      {:reject, _} = VocabularyPolicy.filter(message)
     end
 
     test "it passes through objects that aren't disallowed" do
index c2bc38d52508fdf896d2781484dfe742080d4919..b9388b966d5d3e067df18c325a54b8c146728a35 100644 (file)
@@ -123,6 +123,39 @@ defmodule Pleroma.Web.ActivityPub.PublisherTest do
   end
 
   describe "publish_one/1" do
+    test "publish to url with with different ports" do
+      inbox80 = "http://42.site/users/nick1/inbox"
+      inbox42 = "http://42.site:42/users/nick1/inbox"
+
+      mock(fn
+        %{method: :post, url: "http://42.site:42/users/nick1/inbox"} ->
+          {:ok, %Tesla.Env{status: 200, body: "port 42"}}
+
+        %{method: :post, url: "http://42.site/users/nick1/inbox"} ->
+          {:ok, %Tesla.Env{status: 200, body: "port 80"}}
+      end)
+
+      actor = insert(:user)
+
+      assert {:ok, %{body: "port 42"}} =
+               Publisher.publish_one(%{
+                 inbox: inbox42,
+                 json: "{}",
+                 actor: actor,
+                 id: 1,
+                 unreachable_since: true
+               })
+
+      assert {:ok, %{body: "port 80"}} =
+               Publisher.publish_one(%{
+                 inbox: inbox80,
+                 json: "{}",
+                 actor: actor,
+                 id: 1,
+                 unreachable_since: true
+               })
+    end
+
     test_with_mock "calls `Instances.set_reachable` on successful federation if `unreachable_since` is not specified",
                    Instances,
                    [:passthrough],
@@ -131,7 +164,6 @@ defmodule Pleroma.Web.ActivityPub.PublisherTest do
       inbox = "http://200.site/users/nick1/inbox"
 
       assert {:ok, _} = Publisher.publish_one(%{inbox: inbox, json: "{}", actor: actor, id: 1})
-
       assert called(Instances.set_reachable(inbox))
     end
 
index f7b7d1a9f2b89063495a584705ff0293da8a495e..248b410c641cebb290746f5279d932922102a3a3 100644 (file)
@@ -774,6 +774,29 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do
       assert [user.follower_address] == activity.data["to"]
     end
 
+    test "it correctly processes messages with weirdness in address fields" do
+      user = insert(:user)
+
+      message = %{
+        "@context" => "https://www.w3.org/ns/activitystreams",
+        "to" => [nil, user.follower_address],
+        "cc" => ["https://www.w3.org/ns/activitystreams#Public", ["¿"]],
+        "type" => "Create",
+        "object" => %{
+          "content" => "…",
+          "type" => "Note",
+          "attributedTo" => user.ap_id,
+          "inReplyTo" => nil
+        },
+        "actor" => user.ap_id
+      }
+
+      assert {:ok, activity} = Transmogrifier.handle_incoming(message)
+
+      assert ["https://www.w3.org/ns/activitystreams#Public"] == activity.data["cc"]
+      assert [user.follower_address] == activity.data["to"]
+    end
+
     test "it accepts Move activities" do
       old_user = insert(:user)
       new_user = insert(:user)
index c2433f23c1480a69d216b901cdec9b3cc3bd46f9..da91cd552afb8552695baa21f861c84d3c3d9666 100644 (file)
@@ -41,6 +41,16 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do
     {:ok, %{admin: admin, token: token, conn: conn}}
   end
 
+  test "with valid `admin_token` query parameter, skips OAuth scopes check" do
+    clear_config([:admin_token], "password123")
+
+    user = insert(:user)
+
+    conn = get(build_conn(), "/api/pleroma/admin/users/#{user.nickname}?admin_token=password123")
+
+    assert json_response(conn, 200)
+  end
+
   describe "with [:auth, :enforce_oauth_admin_scope_usage]," do
     setup do: clear_config([:auth, :enforce_oauth_admin_scope_usage], true)
 
index 064ef9bc7cb82224d6b4b5188602d5b2e9f21348..61bc9fd39093616ca0cd4db2361b7950cd03f87d 100644 (file)
@@ -152,6 +152,14 @@ defmodule Pleroma.Web.AdminAPI.ConfigControllerTest do
       assert emoji_val[:groups] == [a: 1, b: 2]
       assert assets_val[:mascots] == [a: 1, b: 2]
     end
+
+    test "with valid `admin_token` query parameter, skips OAuth scopes check" do
+      clear_config([:admin_token], "password123")
+
+      build_conn()
+      |> get("/api/pleroma/admin/config?admin_token=password123")
+      |> json_response_and_validate_schema(200)
+    end
   end
 
   test "POST /api/pleroma/admin/config error", %{conn: conn} do
index 940bce340d2f26082ecb343e24e0fb70f76063f6..f30dc895629835cd9569f98dc134f75beda67e00 100644 (file)
@@ -297,7 +297,7 @@ defmodule Pleroma.Web.AdminAPI.ReportControllerTest do
         |> get("/api/pleroma/admin/reports")
 
       assert json_response(conn, :forbidden) ==
-               %{"error" => "User is not an admin or OAuth admin scope is not granted."}
+               %{"error" => "User is not an admin."}
     end
 
     test "returns 403 when requested by anonymous" do
index fd2de8d808ff1da608691a9d91d10b53a2ecc7e3..d34f300da932246a02a5429c424ec25d039558ad 100644 (file)
@@ -22,6 +22,8 @@ defmodule Pleroma.Web.MastodonAPI.StatusControllerTest do
   setup do: clear_config([:instance, :federating])
   setup do: clear_config([:instance, :allow_relay])
   setup do: clear_config([:rich_media, :enabled])
+  setup do: clear_config([:mrf, :policies])
+  setup do: clear_config([:mrf_keyword, :reject])
 
   describe "posting statuses" do
     setup do: oauth_access(["write:statuses"])
@@ -157,6 +159,17 @@ defmodule Pleroma.Web.MastodonAPI.StatusControllerTest do
                |> json_response_and_validate_schema(422)
     end
 
+    test "Get MRF reason when posting a status is rejected by one", %{conn: conn} do
+      Pleroma.Config.put([:mrf_keyword, :reject], ["GNO"])
+      Pleroma.Config.put([:mrf, :policies], [Pleroma.Web.ActivityPub.MRF.KeywordPolicy])
+
+      assert %{"error" => "[KeywordPolicy] Matches with rejected keyword"} =
+               conn
+               |> put_req_header("content-type", "application/json")
+               |> post("api/v1/statuses", %{"status" => "GNO/Linux"})
+               |> json_response_and_validate_schema(422)
+    end
+
     test "posting an undefined status with an attachment", %{user: user, conn: conn} do
       file = %Plug.Upload{
         content_type: "image/jpg",
index d61cef83b409f006acfc5613aad81c211735d8c4..d4db44c6312c7248c988fd80fbb5ea69ec255ec8 100644 (file)
 
 defmodule Pleroma.Web.MediaProxy.MediaProxyControllerTest do
   use Pleroma.Web.ConnCase
+
   import Mock
-  alias Pleroma.Config
 
-  setup do: clear_config(:media_proxy)
-  setup do: clear_config([Pleroma.Web.Endpoint, :secret_key_base])
+  alias Pleroma.Web.MediaProxy
+  alias Pleroma.Web.MediaProxy.MediaProxyController
+  alias Plug.Conn
 
   setup do
     on_exit(fn -> Cachex.clear(:banned_urls_cache) end)
   end
 
   test "it returns 404 when MediaProxy disabled", %{conn: conn} do
-    Config.put([:media_proxy, :enabled], false)
+    clear_config([:media_proxy, :enabled], false)
 
-    assert %Plug.Conn{
+    assert %Conn{
              status: 404,
              resp_body: "Not Found"
            } = get(conn, "/proxy/hhgfh/eeeee")
 
-    assert %Plug.Conn{
+    assert %Conn{
              status: 404,
              resp_body: "Not Found"
            } = get(conn, "/proxy/hhgfh/eeee/fff")
   end
 
-  test "it returns 403 when signature invalidated", %{conn: conn} do
-    Config.put([:media_proxy, :enabled], true)
-    Config.put([Pleroma.Web.Endpoint, :secret_key_base], "00000000000")
-    path = URI.parse(Pleroma.Web.MediaProxy.encode_url("https://google.fn")).path
-    Config.put([Pleroma.Web.Endpoint, :secret_key_base], "000")
-
-    assert %Plug.Conn{
-             status: 403,
-             resp_body: "Forbidden"
-           } = get(conn, path)
-
-    assert %Plug.Conn{
-             status: 403,
-             resp_body: "Forbidden"
-           } = get(conn, "/proxy/hhgfh/eeee")
-
-    assert %Plug.Conn{
-             status: 403,
-             resp_body: "Forbidden"
-           } = get(conn, "/proxy/hhgfh/eeee/fff")
-  end
+  describe "" do
+    setup do
+      clear_config([:media_proxy, :enabled], true)
+      clear_config([Pleroma.Web.Endpoint, :secret_key_base], "00000000000")
+      [url: MediaProxy.encode_url("https://google.fn/test.png")]
+    end
 
-  test "redirects on valid url when filename invalidated", %{conn: conn} do
-    Config.put([:media_proxy, :enabled], true)
-    Config.put([Pleroma.Web.Endpoint, :secret_key_base], "00000000000")
-    url = Pleroma.Web.MediaProxy.encode_url("https://google.fn/test.png")
-    invalid_url = String.replace(url, "test.png", "test-file.png")
-    response = get(conn, invalid_url)
-    assert response.status == 302
-    assert redirected_to(response) == url
-  end
+    test "it returns 403 for invalid signature", %{conn: conn, url: url} do
+      Pleroma.Config.put([Pleroma.Web.Endpoint, :secret_key_base], "000")
+      %{path: path} = URI.parse(url)
+
+      assert %Conn{
+               status: 403,
+               resp_body: "Forbidden"
+             } = get(conn, path)
+
+      assert %Conn{
+               status: 403,
+               resp_body: "Forbidden"
+             } = get(conn, "/proxy/hhgfh/eeee")
+
+      assert %Conn{
+               status: 403,
+               resp_body: "Forbidden"
+             } = get(conn, "/proxy/hhgfh/eeee/fff")
+    end
 
-  test "it performs ReverseProxy.call when signature valid", %{conn: conn} do
-    Config.put([:media_proxy, :enabled], true)
-    Config.put([Pleroma.Web.Endpoint, :secret_key_base], "00000000000")
-    url = Pleroma.Web.MediaProxy.encode_url("https://google.fn/test.png")
+    test "redirects on valid url when filename is invalidated", %{conn: conn, url: url} do
+      invalid_url = String.replace(url, "test.png", "test-file.png")
+      response = get(conn, invalid_url)
+      assert response.status == 302
+      assert redirected_to(response) == url
+    end
 
-    with_mock Pleroma.ReverseProxy,
-      call: fn _conn, _url, _opts -> %Plug.Conn{status: :success} end do
-      assert %Plug.Conn{status: :success} = get(conn, url)
+    test "it performs ReverseProxy.call with valid signature", %{conn: conn, url: url} do
+      with_mock Pleroma.ReverseProxy,
+        call: fn _conn, _url, _opts -> %Conn{status: :success} end do
+        assert %Conn{status: :success} = get(conn, url)
+      end
+    end
+
+    test "it returns 404 when url is in banned_urls cache", %{conn: conn, url: url} do
+      MediaProxy.put_in_banned_urls("https://google.fn/test.png")
+
+      with_mock Pleroma.ReverseProxy,
+        call: fn _conn, _url, _opts -> %Conn{status: :success} end do
+        assert %Conn{status: 404, resp_body: "Not Found"} = get(conn, url)
+      end
     end
   end
 
-  test "it returns 404 when url contains in banned_urls cache", %{conn: conn} do
-    Config.put([:media_proxy, :enabled], true)
-    Config.put([Pleroma.Web.Endpoint, :secret_key_base], "00000000000")
-    url = Pleroma.Web.MediaProxy.encode_url("https://google.fn/test.png")
-    Pleroma.Web.MediaProxy.put_in_banned_urls("https://google.fn/test.png")
+  describe "filename_matches/3" do
+    test "preserves the encoded or decoded path" do
+      assert MediaProxyController.filename_matches(
+               %{"filename" => "/Hello world.jpg"},
+               "/Hello world.jpg",
+               "http://pleroma.social/Hello world.jpg"
+             ) == :ok
+
+      assert MediaProxyController.filename_matches(
+               %{"filename" => "/Hello%20world.jpg"},
+               "/Hello%20world.jpg",
+               "http://pleroma.social/Hello%20world.jpg"
+             ) == :ok
+
+      assert MediaProxyController.filename_matches(
+               %{"filename" => "/my%2Flong%2Furl%2F2019%2F07%2FS.jpg"},
+               "/my%2Flong%2Furl%2F2019%2F07%2FS.jpg",
+               "http://pleroma.social/my%2Flong%2Furl%2F2019%2F07%2FS.jpg"
+             ) == :ok
+
+      assert MediaProxyController.filename_matches(
+               %{"filename" => "/my%2Flong%2Furl%2F2019%2F07%2FS.jp"},
+               "/my%2Flong%2Furl%2F2019%2F07%2FS.jp",
+               "http://pleroma.social/my%2Flong%2Furl%2F2019%2F07%2FS.jpg"
+             ) == {:wrong_filename, "my%2Flong%2Furl%2F2019%2F07%2FS.jpg"}
+    end
+
+    test "encoded url are tried to match for proxy as `conn.request_path` encodes the url" do
+      # conn.request_path will return encoded url
+      request_path = "/ANALYSE-DAI-_-LE-STABLECOIN-100-D%C3%89CENTRALIS%C3%89-BQ.jpg"
 
-    with_mock Pleroma.ReverseProxy,
-      call: fn _conn, _url, _opts -> %Plug.Conn{status: :success} end do
-      assert %Plug.Conn{status: 404, resp_body: "Not Found"} = get(conn, url)
+      assert MediaProxyController.filename_matches(
+               true,
+               request_path,
+               "https://mydomain.com/uploads/2019/07/ANALYSE-DAI-_-LE-STABLECOIN-100-DÉCENTRALISÉ-BQ.jpg"
+             ) == :ok
     end
   end
 end
index 69d2a71a68d2e3a727a9b0e90c58dadb108c75be..72885cfdd09f0bb081f2e61a9625d830f48e6737 100644 (file)
@@ -5,38 +5,33 @@
 defmodule Pleroma.Web.MediaProxyTest do
   use ExUnit.Case
   use Pleroma.Tests.Helpers
-  import Pleroma.Web.MediaProxy
-  alias Pleroma.Web.MediaProxy.MediaProxyController
 
-  setup do: clear_config([:media_proxy, :enabled])
-  setup do: clear_config(Pleroma.Upload)
+  alias Pleroma.Web.Endpoint
+  alias Pleroma.Web.MediaProxy
 
   describe "when enabled" do
-    setup do
-      Pleroma.Config.put([:media_proxy, :enabled], true)
-      :ok
-    end
+    setup do: clear_config([:media_proxy, :enabled], true)
 
     test "ignores invalid url" do
-      assert url(nil) == nil
-      assert url("") == nil
+      assert MediaProxy.url(nil) == nil
+      assert MediaProxy.url("") == nil
     end
 
     test "ignores relative url" do
-      assert url("/local") == "/local"
-      assert url("/") == "/"
+      assert MediaProxy.url("/local") == "/local"
+      assert MediaProxy.url("/") == "/"
     end
 
     test "ignores local url" do
-      local_url = Pleroma.Web.Endpoint.url() <> "/hello"
-      local_root = Pleroma.Web.Endpoint.url()
-      assert url(local_url) == local_url
-      assert url(local_root) == local_root
+      local_url = Endpoint.url() <> "/hello"
+      local_root = Endpoint.url()
+      assert MediaProxy.url(local_url) == local_url
+      assert MediaProxy.url(local_root) == local_root
     end
 
     test "encodes and decodes URL" do
       url = "https://pleroma.soykaf.com/static/logo.png"
-      encoded = url(url)
+      encoded = MediaProxy.url(url)
 
       assert String.starts_with?(
                encoded,
@@ -50,86 +45,44 @@ defmodule Pleroma.Web.MediaProxyTest do
 
     test "encodes and decodes URL without a path" do
       url = "https://pleroma.soykaf.com"
-      encoded = url(url)
+      encoded = MediaProxy.url(url)
       assert decode_result(encoded) == url
     end
 
     test "encodes and decodes URL without an extension" do
       url = "https://pleroma.soykaf.com/path/"
-      encoded = url(url)
+      encoded = MediaProxy.url(url)
       assert String.ends_with?(encoded, "/path")
       assert decode_result(encoded) == url
     end
 
     test "encodes and decodes URL and ignores query params for the path" do
       url = "https://pleroma.soykaf.com/static/logo.png?93939393939&bunny=true"
-      encoded = url(url)
+      encoded = MediaProxy.url(url)
       assert String.ends_with?(encoded, "/logo.png")
       assert decode_result(encoded) == url
     end
 
     test "validates signature" do
-      secret_key_base = Pleroma.Config.get([Pleroma.Web.Endpoint, :secret_key_base])
-
-      on_exit(fn ->
-        Pleroma.Config.put([Pleroma.Web.Endpoint, :secret_key_base], secret_key_base)
-      end)
-
-      encoded = url("https://pleroma.social")
+      encoded = MediaProxy.url("https://pleroma.social")
 
-      Pleroma.Config.put(
-        [Pleroma.Web.Endpoint, :secret_key_base],
+      clear_config(
+        [Endpoint, :secret_key_base],
         "00000000000000000000000000000000000000000000000"
       )
 
       [_, "proxy", sig, base64 | _] = URI.parse(encoded).path |> String.split("/")
-      assert decode_url(sig, base64) == {:error, :invalid_signature}
-    end
-
-    test "filename_matches preserves the encoded or decoded path" do
-      assert MediaProxyController.filename_matches(
-               %{"filename" => "/Hello world.jpg"},
-               "/Hello world.jpg",
-               "http://pleroma.social/Hello world.jpg"
-             ) == :ok
-
-      assert MediaProxyController.filename_matches(
-               %{"filename" => "/Hello%20world.jpg"},
-               "/Hello%20world.jpg",
-               "http://pleroma.social/Hello%20world.jpg"
-             ) == :ok
-
-      assert MediaProxyController.filename_matches(
-               %{"filename" => "/my%2Flong%2Furl%2F2019%2F07%2FS.jpg"},
-               "/my%2Flong%2Furl%2F2019%2F07%2FS.jpg",
-               "http://pleroma.social/my%2Flong%2Furl%2F2019%2F07%2FS.jpg"
-             ) == :ok
-
-      assert MediaProxyController.filename_matches(
-               %{"filename" => "/my%2Flong%2Furl%2F2019%2F07%2FS.jp"},
-               "/my%2Flong%2Furl%2F2019%2F07%2FS.jp",
-               "http://pleroma.social/my%2Flong%2Furl%2F2019%2F07%2FS.jpg"
-             ) == {:wrong_filename, "my%2Flong%2Furl%2F2019%2F07%2FS.jpg"}
-    end
-
-    test "encoded url are tried to match for proxy as `conn.request_path` encodes the url" do
-      # conn.request_path will return encoded url
-      request_path = "/ANALYSE-DAI-_-LE-STABLECOIN-100-D%C3%89CENTRALIS%C3%89-BQ.jpg"
-
-      assert MediaProxyController.filename_matches(
-               true,
-               request_path,
-               "https://mydomain.com/uploads/2019/07/ANALYSE-DAI-_-LE-STABLECOIN-100-DÉCENTRALISÉ-BQ.jpg"
-             ) == :ok
+      assert MediaProxy.decode_url(sig, base64) == {:error, :invalid_signature}
     end
 
     test "uses the configured base_url" do
-      clear_config([:media_proxy, :base_url], "https://cache.pleroma.social")
+      base_url = "https://cache.pleroma.social"
+      clear_config([:media_proxy, :base_url], base_url)
 
       url = "https://pleroma.soykaf.com/static/logo.png"
-      encoded = url(url)
+      encoded = MediaProxy.url(url)
 
-      assert String.starts_with?(encoded, Pleroma.Config.get([:media_proxy, :base_url]))
+      assert String.starts_with?(encoded, base_url)
     end
 
     # Some sites expect ASCII encoded characters in the URL to be preserved even if
@@ -140,7 +93,7 @@ defmodule Pleroma.Web.MediaProxyTest do
       url =
         "https://pleroma.com/%20/%21/%22/%23/%24/%25/%26/%27/%28/%29/%2A/%2B/%2C/%2D/%2E/%2F/%30/%31/%32/%33/%34/%35/%36/%37/%38/%39/%3A/%3B/%3C/%3D/%3E/%3F/%40/%41/%42/%43/%44/%45/%46/%47/%48/%49/%4A/%4B/%4C/%4D/%4E/%4F/%50/%51/%52/%53/%54/%55/%56/%57/%58/%59/%5A/%5B/%5C/%5D/%5E/%5F/%60/%61/%62/%63/%64/%65/%66/%67/%68/%69/%6A/%6B/%6C/%6D/%6E/%6F/%70/%71/%72/%73/%74/%75/%76/%77/%78/%79/%7A/%7B/%7C/%7D/%7E/%7F/%80/%81/%82/%83/%84/%85/%86/%87/%88/%89/%8A/%8B/%8C/%8D/%8E/%8F/%90/%91/%92/%93/%94/%95/%96/%97/%98/%99/%9A/%9B/%9C/%9D/%9E/%9F/%C2%A0/%A1/%A2/%A3/%A4/%A5/%A6/%A7/%A8/%A9/%AA/%AB/%AC/%C2%AD/%AE/%AF/%B0/%B1/%B2/%B3/%B4/%B5/%B6/%B7/%B8/%B9/%BA/%BB/%BC/%BD/%BE/%BF/%C0/%C1/%C2/%C3/%C4/%C5/%C6/%C7/%C8/%C9/%CA/%CB/%CC/%CD/%CE/%CF/%D0/%D1/%D2/%D3/%D4/%D5/%D6/%D7/%D8/%D9/%DA/%DB/%DC/%DD/%DE/%DF/%E0/%E1/%E2/%E3/%E4/%E5/%E6/%E7/%E8/%E9/%EA/%EB/%EC/%ED/%EE/%EF/%F0/%F1/%F2/%F3/%F4/%F5/%F6/%F7/%F8/%F9/%FA/%FB/%FC/%FD/%FE/%FF"
 
-      encoded = url(url)
+      encoded = MediaProxy.url(url)
       assert decode_result(encoded) == url
     end
 
@@ -151,56 +104,49 @@ defmodule Pleroma.Web.MediaProxyTest do
       url =
         "https://pleroma.com/ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890-._~:/?#[]@!$&'()*+,;=|^`{}"
 
-      encoded = url(url)
+      encoded = MediaProxy.url(url)
       assert decode_result(encoded) == url
     end
 
     test "preserve unicode characters" do
       url = "https://ko.wikipedia.org/wiki/위키백과:대문"
 
-      encoded = url(url)
+      encoded = MediaProxy.url(url)
       assert decode_result(encoded) == url
     end
   end
 
   describe "when disabled" do
-    setup do
-      enabled = Pleroma.Config.get([:media_proxy, :enabled])
-
-      if enabled do
-        Pleroma.Config.put([:media_proxy, :enabled], false)
-
-        on_exit(fn ->
-          Pleroma.Config.put([:media_proxy, :enabled], enabled)
-          :ok
-        end)
-      end
-
-      :ok
-    end
+    setup do: clear_config([:media_proxy, :enabled], false)
 
     test "does not encode remote urls" do
-      assert url("https://google.fr") == "https://google.fr"
+      assert MediaProxy.url("https://google.fr") == "https://google.fr"
     end
   end
 
   defp decode_result(encoded) do
     [_, "proxy", sig, base64 | _] = URI.parse(encoded).path |> String.split("/")
-    {:ok, decoded} = decode_url(sig, base64)
+    {:ok, decoded} = MediaProxy.decode_url(sig, base64)
     decoded
   end
 
   describe "whitelist" do
-    setup do
-      Pleroma.Config.put([:media_proxy, :enabled], true)
-      :ok
-    end
+    setup do: clear_config([:media_proxy, :enabled], true)
 
     test "mediaproxy whitelist" do
-      Pleroma.Config.put([:media_proxy, :whitelist], ["google.com", "feld.me"])
+      clear_config([:media_proxy, :whitelist], ["https://google.com", "https://feld.me"])
+      url = "https://feld.me/foo.png"
+
+      unencoded = MediaProxy.url(url)
+      assert unencoded == url
+    end
+
+    # TODO: delete after removing support bare domains for media proxy whitelist
+    test "mediaproxy whitelist bare domains whitelist (deprecated)" do
+      clear_config([:media_proxy, :whitelist], ["google.com", "feld.me"])
       url = "https://feld.me/foo.png"
 
-      unencoded = url(url)
+      unencoded = MediaProxy.url(url)
       assert unencoded == url
     end
 
@@ -211,17 +157,17 @@ defmodule Pleroma.Web.MediaProxyTest do
       media_url = "https://mycdn.akamai.com"
 
       url = "#{media_url}/static/logo.png"
-      encoded = url(url)
+      encoded = MediaProxy.url(url)
 
       assert String.starts_with?(encoded, media_url)
     end
 
     test "ensure Pleroma.Upload base_url is always whitelisted" do
       media_url = "https://media.pleroma.social"
-      Pleroma.Config.put([Pleroma.Upload, :base_url], media_url)
+      clear_config([Pleroma.Upload, :base_url], media_url)
 
       url = "#{media_url}/static/logo.png"
-      encoded = url(url)
+      encoded = MediaProxy.url(url)
 
       assert String.starts_with?(encoded, media_url)
     end