Merge remote-tracking branch 'remotes/origin/develop' into 2168-media-preview-proxy
authorIvan Tashkinov <ivantashkinov@gmail.com>
Sun, 19 Jul 2020 17:05:37 +0000 (20:05 +0300)
committerIvan Tashkinov <ivantashkinov@gmail.com>
Sun, 19 Jul 2020 17:05:37 +0000 (20:05 +0300)
# Conflicts:
# config/config.exs
# lib/pleroma/web/media_proxy/media_proxy.ex
# mix.lock
# test/web/media_proxy/media_proxy_test.exs

1  2 
.gitlab-ci.yml
config/config.exs
lib/pleroma/reverse_proxy/reverse_proxy.ex
lib/pleroma/web/mastodon_api/views/status_view.ex
lib/pleroma/web/media_proxy/media_proxy.ex
lib/pleroma/web/router.ex
mix.exs
mix.lock
test/web/media_proxy/media_proxy_test.exs

diff --combined .gitlab-ci.yml
index 5c12647a00f2b6afce42f9a5f0456f7fd962637a,c9ab848926f21debe460cee18509380aefdc3ffb..ab2bc9f98c1f8bc5faab4464c49812139305b474
@@@ -6,8 -6,6 +6,8 @@@ variables: &global_variable
    POSTGRES_PASSWORD: postgres
    DB_HOST: postgres
    MIX_ENV: test
 +  SHELL: /bin/sh
 +  USER: root
  
  cache: &global_cache_policy
    key: ${CI_COMMIT_REF_SLUG}
@@@ -60,26 -58,25 +60,25 @@@ unit-testing
      alias: postgres
      command: ["postgres", "-c", "fsync=off", "-c", "synchronous_commit=off", "-c", "full_page_writes=off"]
    script:
+     - apt-get update && apt-get install -y libimage-exiftool-perl
      - mix deps.get
      - mix ecto.create
      - mix ecto.migrate
      - mix coveralls --preload-modules
  
- # Removed to fix CI issue. In this early state it wasn't adding much value anyway.
- # TODO Fix and reinstate federated testing
- # federated-testing:
- #   stage: test
- #   cache: *testing_cache_policy
- #   services:
- #   - name: minibikini/postgres-with-rum:12
- #     alias: postgres
- #     command: ["postgres", "-c", "fsync=off", "-c", "synchronous_commit=off", "-c", "full_page_writes=off"]
- #   script:
- #     - mix deps.get
- #     - mix ecto.create
- #     - mix ecto.migrate
- #     - epmd -daemon
- #     - mix test --trace --only federated
+ federated-testing:
+   stage: test
+   cache: *testing_cache_policy
+   services:
+   - name: minibikini/postgres-with-rum:12
+     alias: postgres
+     command: ["postgres", "-c", "fsync=off", "-c", "synchronous_commit=off", "-c", "full_page_writes=off"]
+   script:
+     - mix deps.get
+     - mix ecto.create
+     - mix ecto.migrate
+     - epmd -daemon
+     - mix test --trace --only federated
  
  unit-testing-rum:
    stage: test
@@@ -93,6 -90,7 +92,7 @@@
      <<: *global_variables
      RUM_ENABLED: "true"
    script:
+     - apt-get update && apt-get install -y libimage-exiftool-perl
      - mix deps.get
      - mix ecto.create
      - mix ecto.migrate
diff --combined config/config.exs
index c8b6c7fad0ffe581ccaed93cb770f99e9bc59904,2d3f35e70253cc3cf654ad4e792a8fecbb0f07c8..9d8d43c54107399060905e8e9f5ad24a4d7cb7b3
@@@ -97,6 -97,7 +97,7 @@@ config :pleroma, :uri_schemes
      "dat",
      "dweb",
      "gopher",
+     "hyper",
      "ipfs",
      "ipns",
      "irc",
@@@ -171,7 -172,7 +172,7 @@@ config :mime, :types, %
    "application/ld+json" => ["activity+json"]
  }
  
- config :tesla, adapter: Tesla.Adapter.Hackney
+ config :tesla, adapter: Tesla.Adapter.Gun
  
  # Configures http settings, upstream proxy etc.
  config :pleroma, :http,
@@@ -188,6 -189,7 +189,7 @@@ config :pleroma, :instance
    background_image: "/images/city.jpg",
    instance_thumbnail: "/instance/thumbnail.jpeg",
    limit: 5_000,
+   description_limit: 5_000,
    chat_limit: 5_000,
    remote_limit: 100_000,
    upload_limit: 16_000_000,
@@@ -398,8 -400,6 +400,8 @@@ config :pleroma, :media_proxy
    proxy_opts: [
      redirect_on_failure: false,
      max_body_length: 25 * 1_048_576,
 +    # Note: max_read_duration defaults to Pleroma.ReverseProxy.max_read_duration_default/1
 +    max_read_duration: 30_000,
      http: [
        follow_redirect: true,
        pool: :media
@@@ -414,16 -414,6 +416,16 @@@ config :pleroma, Pleroma.Web.MediaProxy
  
  config :pleroma, Pleroma.Web.MediaProxy.Invalidation.Script, script_path: nil
  
 +# Note: media preview proxy depends on media proxy to be enabled
 +config :pleroma, :media_preview_proxy,
 +  enabled: false,
 +  thumbnail_max_width: 400,
 +  thumbnail_max_height: 200,
 +  proxy_opts: [
 +    head_request_max_read_duration: 5_000,
 +    max_read_duration: 10_000
 +  ]
 +
  config :pleroma, :chat, enabled: true
  
  config :phoenix, :format_encoders, json: Jason
@@@ -448,8 -438,7 +450,7 @@@ config :pleroma, Pleroma.Web.Metadata
  
  config :pleroma, Pleroma.Web.Preload,
    providers: [
-     Pleroma.Web.Preload.Providers.Instance,
-     Pleroma.Web.Preload.Providers.StatusNet
+     Pleroma.Web.Preload.Providers.Instance
    ]
  
  config :pleroma, :http_security,
@@@ -509,8 -498,7 +510,7 @@@ config :pleroma, Pleroma.User
  
  config :pleroma, Oban,
    repo: Pleroma.Repo,
-   verbose: false,
-   prune: {:maxlen, 1500},
+   log: false,
    queues: [
      activity_expiration: 10,
      federator_incoming: 50,
      attachments_cleanup: 5,
      new_users_digest: 1
    ],
+   plugins: [Oban.Plugins.Pruner],
    crontab: [
      {"0 0 * * *", Pleroma.Workers.Cron.ClearOauthTokenWorker},
      {"0 * * * *", Pleroma.Workers.Cron.StatsWorker},
@@@ -659,32 -648,30 +660,30 @@@ config :pleroma, Pleroma.Repo
    prepare: :unnamed
  
  config :pleroma, :connections_pool,
-   checkin_timeout: 250,
+   reclaim_multiplier: 0.1,
+   connection_acquisition_wait: 250,
+   connection_acquisition_retries: 5,
    max_connections: 250,
-   retry: 1,
-   retry_timeout: 1000,
+   max_idle_time: 30_000,
+   retry0,
    await_up_timeout: 5_000
  
  config :pleroma, :pools,
    federation: [
      size: 50,
-     max_overflow: 10,
-     timeout: 150_000
+     max_waiting: 10
    ],
    media: [
      size: 50,
-     max_overflow: 10,
-     timeout: 150_000
+     max_waiting: 10
    ],
    upload: [
      size: 25,
-     max_overflow: 5,
-     timeout: 300_000
+     max_waiting: 5
    ],
    default: [
      size: 10,
-     max_overflow: 2,
-     timeout: 10_000
+     max_waiting: 2
    ]
  
  config :pleroma, :hackney_pools,
@@@ -717,10 -704,8 +716,12 @@@ config :tzdata, :http_client, Pleroma.H
  
  config :ex_aws, http_client: Pleroma.HTTP.ExAws
  
+ config :pleroma, :instances_favicons, enabled: false
 +config :pleroma, :exexec,
 +  root_mode: false,
 +  options: %{}
 +
  # Import environment specific config. This must remain at the bottom
  # of this file so it overrides the configuration defined above.
  import_config "#{Mix.env()}.exs"
index aeaf9bd399dd055d82e82d794b8b2a898ae51b01,28ad4c8460a92a7690b55ac3c92db6b66df6bff3..613edf5658933c33688ac3c81b703f2f805245b3
@@@ -3,12 -3,13 +3,13 @@@
  # SPDX-License-Identifier: AGPL-3.0-only
  
  defmodule Pleroma.ReverseProxy do
+   @range_headers ~w(range if-range)
    @keep_req_headers ~w(accept user-agent accept-encoding cache-control if-modified-since) ++
-                       ~w(if-unmodified-since if-none-match if-range range)
+                       ~w(if-unmodified-since if-none-match) ++ @range_headers
    @resp_cache_headers ~w(etag date last-modified)
    @keep_resp_headers @resp_cache_headers ++
-                        ~w(content-type content-disposition content-encoding content-range) ++
-                        ~w(accept-ranges vary)
+                        ~w(content-length content-type content-disposition content-encoding) ++
+                        ~w(content-range accept-ranges vary)
    @default_cache_control_header "public, max-age=1209600"
    @valid_resp_codes [200, 206, 304]
    @max_read_duration :timer.seconds(30)
@@@ -16,8 -17,6 +17,8 @@@
    @failed_request_ttl :timer.seconds(60)
    @methods ~w(GET HEAD)
  
 +  def max_read_duration_default, do: @max_read_duration
 +
    @moduledoc """
    A reverse proxy.
  
    end
  
    defp response(conn, client, url, status, headers, opts) do
+     Logger.debug("#{__MODULE__} #{status} #{url} #{inspect(headers)}")
      result =
        conn
        |> put_resp_headers(build_resp_headers(headers, opts))
      end
    end
  
-   defp head_response(conn, _url, code, headers, opts) do
+   defp head_response(conn, url, code, headers, opts) do
+     Logger.debug("#{__MODULE__} #{code} #{url} #{inspect(headers)}")
      conn
      |> put_resp_headers(build_resp_headers(headers, opts))
      |> send_resp(code, "")
      headers
      |> downcase_headers()
      |> Enum.filter(fn {k, _} -> k in @keep_req_headers end)
-     |> (fn headers ->
-           headers = headers ++ Keyword.get(opts, :req_headers, [])
-           if Keyword.get(opts, :keep_user_agent, false) do
-             List.keystore(
-               headers,
-               "user-agent",
-               0,
-               {"user-agent", Pleroma.Application.user_agent()}
-             )
-           else
-             headers
-           end
-         end).()
+     |> build_req_range_or_encoding_header(opts)
+     |> build_req_user_agent_header(opts)
+     |> Keyword.merge(Keyword.get(opts, :req_headers, []))
+   end
+   # Disable content-encoding if any @range_headers are requested (see #1823).
+   defp build_req_range_or_encoding_header(headers, _opts) do
+     range? = Enum.any?(headers, fn {header, _} -> Enum.member?(@range_headers, header) end)
+     if range? && List.keymember?(headers, "accept-encoding", 0) do
+       List.keydelete(headers, "accept-encoding", 0)
+     else
+       headers
+     end
+   end
+   defp build_req_user_agent_header(headers, opts) do
+     if Keyword.get(opts, :keep_user_agent, false) do
+       List.keystore(
+         headers,
+         "user-agent",
+         0,
+         {"user-agent", Pleroma.Application.user_agent()}
+       )
+     else
+       headers
+     end
    end
  
    defp build_resp_headers(headers, opts) do
      |> Enum.filter(fn {k, _} -> k in @keep_resp_headers end)
      |> build_resp_cache_headers(opts)
      |> build_resp_content_disposition_header(opts)
-     |> (fn headers -> headers ++ Keyword.get(opts, :resp_headers, []) end).()
+     |> Keyword.merge(Keyword.get(opts, :resp_headers, []))
    end
  
    defp build_resp_cache_headers(headers, _opts) do
  
    defp body_size_constraint(_, _), do: :ok
  
 +  defp check_read_duration(nil = _duration, max), do: check_read_duration(@max_read_duration, max)
 +
    defp check_read_duration(duration, max)
         when is_integer(duration) and is_integer(max) and max > 0 do
      if duration > max do
index 00d45bcd410afff54449318984e7d78789ba9ce6,fa9d695f306912fb176aa62087604b034a3d2804..bdb3bf359f8c0c6a2557c53bb51629f452e19e6e
@@@ -333,6 -333,7 +333,7 @@@ defmodule Pleroma.Web.MastodonAPI.Statu
        reblog: nil,
        card: card,
        content: content_html,
+       text: opts[:with_source] && object.data["source"],
        created_at: created_at,
        reblogs_count: announcement_count,
        replies_count: object.data["repliesCount"] || 0,
      [attachment_url | _] = attachment["url"]
      media_type = attachment_url["mediaType"] || attachment_url["mimeType"] || "image"
      href = attachment_url["href"] |> MediaProxy.url()
 +    href_preview = attachment_url["href"] |> MediaProxy.preview_url()
  
      type =
        cond do
        id: to_string(attachment["id"] || hash_id),
        url: href,
        remote_url: href,
 -      preview_url: href,
 +      preview_url: href_preview,
        text_url: href,
        type: type,
        description: attachment["name"],
index 1b6242cb4d0fa9fad178216094956d9f088145a9,dfbfcea6bc74620504e9a0b339d8ca315b43e066..217c3f92263c65fa76be6b51e1536f6ed081aa3c
@@@ -37,7 -37,7 +37,7 @@@ defmodule Pleroma.Web.MediaProxy d
    def url("/" <> _ = url), do: url
  
    def url(url) do
 -    if disabled?() or not url_proxiable?(url) do
 +    if not enabled?() or not url_proxiable?(url) do
        url
      else
        encode_url(url)
      end
    end
  
 -  defp disabled?, do: !Config.get([:media_proxy, :enabled], false)
 +  # Note: routing all URLs to preview handler (even local and whitelisted).
 +  #   Preview handler will call url/1 on decoded URLs, and applicable ones will detour media proxy.
 +  def preview_url(url) do
 +    if preview_enabled?() do
 +      encode_preview_url(url)
 +    else
 +      url
 +    end
 +  end
  
 -  defp local?(url), do: String.starts_with?(url, Pleroma.Web.base_url())
 +  def enabled?, do: Config.get([:media_proxy, :enabled], false)
  
 -  defp whitelisted?(url) do
 +  # Note: media proxy must be enabled for media preview proxy in order to load all
 +  #   non-local non-whitelisted URLs through it and be sure that body size constraint is preserved.
 +  def preview_enabled?, do: enabled?() and Config.get([:media_preview_proxy, :enabled], false)
 +
 +  def local?(url), do: String.starts_with?(url, Pleroma.Web.base_url())
 +
 +  def 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
  
 -  def encode_url(url) do
+   defp maybe_get_domain_from_url(domain), do: domain
 +  defp base64_sig64(url) do
      base64 = Base.url_encode64(url, @base64_opts)
  
      sig64 =
        base64
 -      |> signed_url
 +      |> signed_url()
        |> Base.url_encode64(@base64_opts)
  
 +    {base64, sig64}
 +  end
 +
 +  def encode_url(url) do
 +    {base64, sig64} = base64_sig64(url)
 +
      build_url(sig64, base64, filename(url))
    end
  
 +  def encode_preview_url(url) do
 +    {base64, sig64} = base64_sig64(url)
 +
 +    build_preview_url(sig64, base64, filename(url))
 +  end
 +
    def decode_url(sig, url) do
      with {:ok, sig} <- Base.url_decode64(sig, @base64_opts),
           signature when signature == sig <- signed_url(url) do
      if path = URI.parse(url_or_path).path, do: Path.basename(path)
    end
  
 -  def build_url(sig_base64, url_base64, filename \\ nil) do
 +  defp proxy_url(path, sig_base64, url_base64, filename) do
      [
-       Pleroma.Config.get([:media_proxy, :base_url], Web.base_url()),
+       Config.get([:media_proxy, :base_url], Web.base_url()),
 -      "proxy",
 +      path,
        sig_base64,
        url_base64,
        filename
      |> Enum.filter(& &1)
      |> Path.join()
    end
 +
 +  def build_url(sig_base64, url_base64, filename \\ nil) do
 +    proxy_url("proxy", sig_base64, url_base64, filename)
 +  end
 +
 +  def build_preview_url(sig_base64, url_base64, filename \\ nil) do
 +    proxy_url("proxy/preview", sig_base64, url_base64, filename)
 +  end
 +
 +  def verify_request_path_and_url(
 +        %Plug.Conn{params: %{"filename" => _}, request_path: request_path},
 +        url
 +      ) do
 +    verify_request_path_and_url(request_path, url)
 +  end
 +
 +  def verify_request_path_and_url(request_path, url) when is_binary(request_path) do
 +    filename = filename(url)
 +
 +    if filename && not basename_matches?(request_path, filename) do
 +      {:wrong_filename, filename}
 +    else
 +      :ok
 +    end
 +  end
 +
 +  def verify_request_path_and_url(_, _), do: :ok
 +
 +  defp basename_matches?(path, filename) do
 +    basename = Path.basename(path)
 +    basename == filename or URI.decode(basename) == filename or URI.encode(basename) == filename
 +  end
  end
index 94f77378b29f3f513857f507cb518d1be6ec3250,386308362b6baaf295b70932e3270846cfce2b2f..ba10da1156540400144c51a49828677fb7cf5a69
@@@ -328,10 -328,6 +328,6 @@@ defmodule Pleroma.Web.Router d
        delete("/statuses/:id/reactions/:emoji", EmojiReactionController, :delete)
        post("/notifications/read", NotificationController, :mark_as_read)
  
-       patch("/accounts/update_avatar", AccountController, :update_avatar)
-       patch("/accounts/update_banner", AccountController, :update_banner)
-       patch("/accounts/update_background", AccountController, :update_background)
        get("/mascot", MascotController, :show)
        put("/mascot", MascotController, :update)
  
    scope "/api", Pleroma.Web do
      pipe_through(:config)
  
-     get("/help/test", TwitterAPI.UtilController, :help_test)
-     post("/help/test", TwitterAPI.UtilController, :help_test)
-     get("/statusnet/config", TwitterAPI.UtilController, :config)
-     get("/statusnet/version", TwitterAPI.UtilController, :version)
      get("/pleroma/frontend_configurations", TwitterAPI.UtilController, :frontend_configurations)
    end
  
    end
  
    scope "/proxy/", Pleroma.Web.MediaProxy do
 +    get("/preview/:sig/:url", MediaProxyController, :preview)
 +    get("/preview/:sig/:url/:filename", MediaProxyController, :preview)
      get("/:sig/:url", MediaProxyController, :remote)
      get("/:sig/:url/:filename", MediaProxyController, :remote)
    end
diff --combined mix.exs
index dc25741cf0c078b2a87c656b89f6c4515ae4cd81,52b4cf26840b460fb387ec2670f0a02c7dbfad0c..db13403f6d128edbf4186c2cc7a60dcf00abcf36
+++ b/mix.exs
@@@ -90,8 -90,6 +90,6 @@@ defmodule Pleroma.Mixfile d
    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.
        {:phoenix_pubsub, "~> 1.1"},
        {:phoenix_ecto, "~> 4.0"},
        {:ecto_enum, "~> 1.4"},
-       {:ecto_sql, "~> 3.3.2"},
+       {:ecto_sql, "~> 3.4.4"},
        {:postgrex, ">= 0.13.5"},
-       {:oban, "~> 1.2"},
+       {:oban, "~> 2.0.0"},
        {:gettext, "~> 0.15"},
        {:pbkdf2_elixir, "~> 1.0"},
        {:bcrypt_elixir, "~> 2.0"},
        {:poison, "~> 3.0", override: true},
        # {:tesla, "~> 1.3", override: true},
        {:tesla,
-        git: "https://git.pleroma.social/pleroma/elixir-libraries/tesla.git",
-        ref: "61b7503cef33f00834f78ddfafe0d5d9dec2270b",
-        override: true},
+        github: "teamon/tesla", ref: "af3707078b10793f6a534938e56b963aff82fe3c", override: true},
        {:castore, "~> 0.1"},
        {:cowlib, "~> 2.8", override: true},
        {:gun,
-        github: "ninenines/gun", ref: "e1a69b36b180a574c0ac314ced9613fdd52312cc", override: true},
+        github: "ninenines/gun", ref: "921c47146b2d9567eac7e9a4d2ccc60fffd4f327", override: true},
        {:jason, "~> 1.0"},
        {:mogrify, "~> 0.6.1"},
        {:ex_aws, "~> 2.1"},
         ref: "293d77bb6f4a67ac8bde1428735c3b42f22cbb30"},
        {:telemetry, "~> 0.3"},
        {:poolboy, "~> 1.5"},
+       {:prometheus, "~> 4.6"},
        {:prometheus_ex, "~> 3.0"},
        {:prometheus_plugs, "~> 1.1"},
        {:prometheus_phoenix, "~> 1.3"},
        {:plug_static_index_html, "~> 1.0.0"},
        {:excoveralls, "~> 0.12.1", only: :test},
        {:flake_id, "~> 0.1.0"},
+       {:concurrent_limiter,
+        git: "https://git.pleroma.social/pleroma/elixir-libraries/concurrent_limiter",
+        ref: "8eee96c6ba39b9286ec44c51c52d9f2758951365"},
        {:remote_ip,
         git: "https://git.pleroma.social/pleroma/remote_ip.git",
         ref: "b647d0deecaa3acb140854fe4bda5b7e1dc6d1c8"},
         ref: "e0f16822d578866e186a0974d65ad58cddc1e2ab"},
        {:mox, "~> 0.5", only: :test},
        {:restarter, path: "./restarter"},
 +      # Note: `runtime: true` for :exexec makes CI fail due to `root` user (see Pleroma.Exec)
 +      {:exexec, "~> 0.2", runtime: false},
        {:open_api_spex,
         git: "https://git.pleroma.social/pleroma/elixir-libraries/open_api_spex.git",
         ref: "f296ac0924ba3cf79c7a588c4c252889df4c2edd"}
diff --combined mix.lock
index a1d0bf0d294e11182dec6ed900dcae5cc841b193,8dd37a40fc5deb77a483ba0d98b5d2def8929e92..d26afef7ad975551d580cbfc955ba86b214a5372
+++ b/mix.lock
@@@ -15,6 -15,7 +15,7 @@@
    "certifi": {:hex, :certifi, "2.5.2", "b7cfeae9d2ed395695dd8201c57a2d019c0c43ecaf8b8bcb9320b40d6662f340", [:rebar3], [{:parse_trans, "~>3.3", [hex: :parse_trans, repo: "hexpm", optional: false]}], "hexpm", "3b3b5f36493004ac3455966991eaf6e768ce9884693d9968055aeeeb1e575040"},
    "combine": {:hex, :combine, "0.10.0", "eff8224eeb56498a2af13011d142c5e7997a80c8f5b97c499f84c841032e429f", [:mix], [], "hexpm", "1b1dbc1790073076580d0d1d64e42eae2366583e7aecd455d1215b0d16f2451b"},
    "comeonin": {:hex, :comeonin, "5.3.1", "7fe612b739c78c9c1a75186ef2d322ce4d25032d119823269d0aa1e2f1e20025", [:mix], [], "hexpm", "d6222483060c17f0977fad1b7401ef0c5863c985a64352755f366aee3799c245"},
+   "concurrent_limiter": {:git, "https://git.pleroma.social/pleroma/elixir-libraries/concurrent_limiter", "8eee96c6ba39b9286ec44c51c52d9f2758951365", [ref: "8eee96c6ba39b9286ec44c51c52d9f2758951365"]},
    "connection": {:hex, :connection, "1.0.4", "a1cae72211f0eef17705aaededacac3eb30e6625b04a6117c1b2db6ace7d5976", [:mix], [], "hexpm", "4a0850c9be22a43af9920a71ab17c051f5f7d45c209e40269a1938832510e4d9"},
    "cors_plug": {:hex, :cors_plug, "1.5.2", "72df63c87e4f94112f458ce9d25800900cc88608c1078f0e4faddf20933eda6e", [:mix], [{:plug, "~> 1.3 or ~> 1.4 or ~> 1.5", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "9af027d20dc12dd0c4345a6b87247e0c62965871feea0bfecf9764648b02cc69"},
    "cowboy": {:hex, :cowboy, "2.7.0", "91ed100138a764355f43316b1d23d7ff6bdb0de4ea618cb5d8677c93a7a2f115", [:rebar3], [{:cowlib, "~> 2.8.0", [hex: :cowlib, repo: "hexpm", optional: false]}, {:ranch, "~> 1.7.1", [hex: :ranch, repo: "hexpm", optional: false]}], "hexpm", "04fd8c6a39edc6aaa9c26123009200fc61f92a3a94f3178c527b70b767c6e605"},
    "crontab": {:hex, :crontab, "1.1.8", "2ce0e74777dfcadb28a1debbea707e58b879e6aa0ffbf9c9bb540887bce43617", [:mix], [{:ecto, "~> 1.0 or ~> 2.0 or ~> 3.0", [hex: :ecto, repo: "hexpm", optional: true]}], "hexpm"},
    "crypt": {:git, "https://github.com/msantos/crypt", "f63a705f92c26955977ee62a313012e309a4d77a", [ref: "f63a705f92c26955977ee62a313012e309a4d77a"]},
    "custom_base": {:hex, :custom_base, "0.2.1", "4a832a42ea0552299d81652aa0b1f775d462175293e99dfbe4d7dbaab785a706", [:mix], [], "hexpm", "8df019facc5ec9603e94f7270f1ac73ddf339f56ade76a721eaa57c1493ba463"},
-   "db_connection": {:hex, :db_connection, "2.2.1", "caee17725495f5129cb7faebde001dc4406796f12a62b8949f4ac69315080566", [:mix], [{:connection, "~> 1.0.2", [hex: :connection, repo: "hexpm", optional: false]}], "hexpm", "2b02ece62d9f983fcd40954e443b7d9e6589664380e5546b2b9b523cd0fb59e1"},
+   "db_connection": {:hex, :db_connection, "2.2.2", "3bbca41b199e1598245b716248964926303b5d4609ff065125ce98bcd368939e", [:mix], [{:connection, "~> 1.0.2", [hex: :connection, repo: "hexpm", optional: false]}], "hexpm", "642af240d8a8affb93b4ba5a6fcd2bbcbdc327e1a524b825d383711536f8070c"},
    "decimal": {:hex, :decimal, "1.8.1", "a4ef3f5f3428bdbc0d35374029ffcf4ede8533536fa79896dd450168d9acdf3c", [:mix], [], "hexpm", "3cb154b00225ac687f6cbd4acc4b7960027c757a5152b369923ead9ddbca7aec"},
    "deep_merge": {:hex, :deep_merge, "1.0.0", "b4aa1a0d1acac393bdf38b2291af38cb1d4a52806cf7a4906f718e1feb5ee961", [:mix], [], "hexpm", "ce708e5f094b9cd4e8f2be4f00d2f4250c4095be93f8cd6d018c753894885430"},
    "earmark": {:hex, :earmark, "1.4.3", "364ca2e9710f6bff494117dbbd53880d84bebb692dafc3a78eb50aa3183f2bfd", [:mix], [], "hexpm", "8cf8a291ebf1c7b9539e3cddb19e9cef066c2441b1640f13c34c1d3cfc825fec"},
-   "ecto": {:hex, :ecto, "3.4.4", "a2c881e80dc756d648197ae0d936216c0308370332c5e77a2325a10293eef845", [:mix], [{:decimal, "~> 1.6 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "cc4bd3ad62abc3b21fb629f0f7a3dab23a192fca837d257dd08449fba7373561"},
+   "ecto": {:hex, :ecto, "3.4.5", "2bcd262f57b2c888b0bd7f7a28c8a48aa11dc1a2c6a858e45dd8f8426d504265", [:mix], [{:decimal, "~> 1.6 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "8c6d1d4d524559e9b7a062f0498e2c206122552d63eacff0a6567ffe7a8e8691"},
    "ecto_enum": {:hex, :ecto_enum, "1.4.0", "d14b00e04b974afc69c251632d1e49594d899067ee2b376277efd8233027aec8", [:mix], [{:ecto, ">= 3.0.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:ecto_sql, "> 3.0.0", [hex: :ecto_sql, repo: "hexpm", optional: false]}, {:mariaex, ">= 0.0.0", [hex: :mariaex, repo: "hexpm", optional: true]}, {:postgrex, ">= 0.0.0", [hex: :postgrex, repo: "hexpm", optional: true]}], "hexpm", "8fb55c087181c2b15eee406519dc22578fa60dd82c088be376d0010172764ee4"},
-   "ecto_sql": {:hex, :ecto_sql, "3.3.4", "aa18af12eb875fbcda2f75e608b3bd534ebf020fc4f6448e4672fcdcbb081244", [:mix], [{:db_connection, "~> 2.2", [hex: :db_connection, repo: "hexpm", optional: false]}, {:ecto, "~> 3.4 or ~> 3.3.3", [hex: :ecto, repo: "hexpm", optional: false]}, {:myxql, "~> 0.3.0", [hex: :myxql, repo: "hexpm", optional: true]}, {:postgrex, "~> 0.15.0", [hex: :postgrex, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "5eccbdbf92e3c6f213007a82d5dbba4cd9bb659d1a21331f89f408e4c0efd7a8"},
+   "ecto_sql": {:hex, :ecto_sql, "3.4.5", "30161f81b167d561a9a2df4329c10ae05ff36eca7ccc84628f2c8b9fa1e43323", [:mix], [{:db_connection, "~> 2.2", [hex: :db_connection, repo: "hexpm", optional: false]}, {:ecto, "~> 3.4.3", [hex: :ecto, repo: "hexpm", optional: false]}, {:myxql, "~> 0.3.0 or ~> 0.4.0", [hex: :myxql, repo: "hexpm", optional: true]}, {:postgrex, "~> 0.15.0", [hex: :postgrex, repo: "hexpm", optional: true]}, {:tds, "~> 2.1.0", [hex: :tds, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "31990c6a3579b36a3c0841d34a94c275e727de8b84f58509da5f1b2032c98ac2"},
 +  "eimp": {:hex, :eimp, "1.0.14", "fc297f0c7e2700457a95a60c7010a5f1dcb768a083b6d53f49cd94ab95a28f22", [:rebar3], [{:p1_utils, "1.0.18", [hex: :p1_utils, repo: "hexpm", optional: false]}], "hexpm", "501133f3112079b92d9e22da8b88bf4f0e13d4d67ae9c15c42c30bd25ceb83b6"},
    "elixir_make": {:hex, :elixir_make, "0.6.0", "38349f3e29aff4864352084fc736fa7fa0f2995a819a737554f7ebd28b85aaab", [:mix], [], "hexpm", "d522695b93b7f0b4c0fcb2dfe73a6b905b1c301226a5a55cb42e5b14d509e050"},
 +  "erlexec": {:hex, :erlexec, "1.10.9", "3cbb3476f942bfb8b68b85721c21c1835061cf6dd35f5285c2362e85b100ddc7", [:rebar3], [], "hexpm", "271e5b5f2d91cdb9887efe74d89026c199bfc69f074cade0d08dab60993fa14e"},
    "esshd": {:hex, :esshd, "0.1.1", "d4dd4c46698093a40a56afecce8a46e246eb35463c457c246dacba2e056f31b5", [:mix], [], "hexpm", "d73e341e3009d390aa36387dc8862860bf9f874c94d9fd92ade2926376f49981"},
    "eternal": {:hex, :eternal, "1.2.1", "d5b6b2499ba876c57be2581b5b999ee9bdf861c647401066d3eeed111d096bc4", [:mix], [], "hexpm", "b14f1dc204321429479c569cfbe8fb287541184ed040956c8862cb7a677b8406"},
    "ex2ms": {:hex, :ex2ms, "1.5.0", "19e27f9212be9a96093fed8cdfbef0a2b56c21237196d26760f11dfcfae58e97", [:mix], [], "hexpm"},
@@@ -43,7 -42,6 +44,7 @@@
    "ex_machina": {:hex, :ex_machina, "2.3.0", "92a5ad0a8b10ea6314b876a99c8c9e3f25f4dde71a2a835845b136b9adaf199a", [:mix], [{:ecto, "~> 2.2 or ~> 3.0", [hex: :ecto, repo: "hexpm", optional: true]}, {:ecto_sql, "~> 3.0", [hex: :ecto_sql, repo: "hexpm", optional: true]}], "hexpm", "b84f6af156264530b312a8ab98ac6088f6b77ae5fe2058305c81434aa01fbaf9"},
    "ex_syslogger": {:hex, :ex_syslogger, "1.5.2", "72b6aa2d47a236e999171f2e1ec18698740f40af0bd02c8c650bf5f1fd1bac79", [:mix], [{:poison, ">= 1.5.0", [hex: :poison, repo: "hexpm", optional: true]}, {:syslog, "~> 1.1.0", [hex: :syslog, repo: "hexpm", optional: false]}], "hexpm", "ab9fab4136dbc62651ec6f16fa4842f10cf02ab4433fa3d0976c01be99398399"},
    "excoveralls": {:hex, :excoveralls, "0.12.2", "a513defac45c59e310ac42fcf2b8ae96f1f85746410f30b1ff2b710a4b6cd44b", [:mix], [{:hackney, "~> 1.0", [hex: :hackney, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "151c476331d49b45601ffc45f43cb3a8beb396b02a34e3777fea0ad34ae57d89"},
 +  "exexec": {:hex, :exexec, "0.2.0", "a6ffc48cba3ac9420891b847e4dc7120692fb8c08c9e82220ebddc0bb8d96103", [:mix], [{:erlexec, "~> 1.10", [hex: :erlexec, repo: "hexpm", optional: false]}], "hexpm", "312cd1c9befba9e078e57f3541e4f4257eabda6eb9c348154fe899d6ac633299"},
    "fast_html": {:hex, :fast_html, "1.0.3", "2cc0d4b68496266a1530e0c852cafeaede0bd10cfdee26fda50dc696c203162f", [:make, :mix], [], "hexpm", "ab3d782b639d3c4655fbaec0f9d032c91f8cab8dd791ac7469c2381bc7c32f85"},
    "fast_sanitize": {:hex, :fast_sanitize, "0.1.7", "2a7cd8734c88a2de6de55022104f8a3b87f1fdbe8bbf131d9049764b53d50d0d", [:mix], [{:fast_html, "~> 1.0", [hex: :fast_html, repo: "hexpm", optional: false]}, {:plug, "~> 1.8", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "f39fe8ea08fbac17487c30bf09b7d9f3e12472e51fb07a88ffeb8fd17da8ab67"},
    "flake_id": {:hex, :flake_id, "0.1.0", "7716b086d2e405d09b647121a166498a0d93d1a623bead243e1f74216079ccb3", [:mix], [{:base62, "~> 1.2", [hex: :base62, repo: "hexpm", optional: false]}, {:ecto, ">= 2.0.0", [hex: :ecto, repo: "hexpm", optional: true]}], "hexpm", "31fc8090fde1acd267c07c36ea7365b8604055f897d3a53dd967658c691bd827"},
@@@ -52,7 -50,7 +53,7 @@@
    "gen_stage": {:hex, :gen_stage, "0.14.3", "d0c66f1c87faa301c1a85a809a3ee9097a4264b2edf7644bf5c123237ef732bf", [:mix], [], "hexpm"},
    "gen_state_machine": {:hex, :gen_state_machine, "2.0.5", "9ac15ec6e66acac994cc442dcc2c6f9796cf380ec4b08267223014be1c728a95", [:mix], [], "hexpm"},
    "gettext": {:hex, :gettext, "0.17.4", "f13088e1ec10ce01665cf25f5ff779e7df3f2dc71b37084976cf89d1aa124d5c", [:mix], [], "hexpm", "3c75b5ea8288e2ee7ea503ff9e30dfe4d07ad3c054576a6e60040e79a801e14d"},
-   "gun": {:git, "https://github.com/ninenines/gun.git", "e1a69b36b180a574c0ac314ced9613fdd52312cc", [ref: "e1a69b36b180a574c0ac314ced9613fdd52312cc"]},
+   "gun": {:git, "https://github.com/ninenines/gun.git", "921c47146b2d9567eac7e9a4d2ccc60fffd4f327", [ref: "921c47146b2d9567eac7e9a4d2ccc60fffd4f327"]},
    "hackney": {:hex, :hackney, "1.16.0", "5096ac8e823e3a441477b2d187e30dd3fff1a82991a806b2003845ce72ce2d84", [:rebar3], [{:certifi, "2.5.2", [hex: :certifi, repo: "hexpm", optional: false]}, {:idna, "6.0.1", [hex: :idna, repo: "hexpm", optional: false]}, {:metrics, "1.0.1", [hex: :metrics, repo: "hexpm", optional: false]}, {:mimerl, "~>1.1", [hex: :mimerl, repo: "hexpm", optional: false]}, {:parse_trans, "3.3.0", [hex: :parse_trans, repo: "hexpm", optional: false]}, {:ssl_verify_fun, "1.1.6", [hex: :ssl_verify_fun, repo: "hexpm", optional: false]}], "hexpm", "3bf0bebbd5d3092a3543b783bf065165fa5d3ad4b899b836810e513064134e18"},
    "html_entities": {:hex, :html_entities, "0.5.1", "1c9715058b42c35a2ab65edc5b36d0ea66dd083767bef6e3edb57870ef556549", [:mix], [], "hexpm", "30efab070904eb897ff05cd52fa61c1025d7f8ef3a9ca250bc4e6513d16c32de"},
    "html_sanitize_ex": {:hex, :html_sanitize_ex, "1.3.0", "f005ad692b717691203f940c686208aa3d8ffd9dd4bb3699240096a51fa9564e", [:mix], [{:mochiweb, "~> 2.15", [hex: :mochiweb, repo: "hexpm", optional: false]}], "hexpm"},
@@@ -78,9 -76,8 +79,9 @@@
    "myhtmlex": {:git, "https://git.pleroma.social/pleroma/myhtmlex.git", "ad0097e2f61d4953bfef20fb6abddf23b87111e6", [ref: "ad0097e2f61d4953bfef20fb6abddf23b87111e6", submodules: true]},
    "nimble_parsec": {:hex, :nimble_parsec, "0.5.3", "def21c10a9ed70ce22754fdeea0810dafd53c2db3219a0cd54cf5526377af1c6", [:mix], [], "hexpm", "589b5af56f4afca65217a1f3eb3fee7e79b09c40c742fddc1c312b3ac0b3399f"},
    "nodex": {:git, "https://git.pleroma.social/pleroma/nodex", "cb6730f943cfc6aad674c92161be23a8411f15d1", [ref: "cb6730f943cfc6aad674c92161be23a8411f15d1"]},
-   "oban": {:hex, :oban, "1.2.0", "7cca94d341be43d220571e28f69131c4afc21095b25257397f50973d3fc59b07", [:mix], [{:ecto_sql, "~> 3.1", [hex: :ecto_sql, repo: "hexpm", optional: false]}, {:jason, "~> 1.1", [hex: :jason, repo: "hexpm", optional: false]}, {:postgrex, "~> 0.14", [hex: :postgrex, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "ba5f8b3f7d76967b3e23cf8014f6a13e4ccb33431e4808f036709a7f822362ee"},
+   "oban": {:hex, :oban, "2.0.0", "e6ce70d94dd46815ec0882a1ffb7356df9a9d5b8a40a64ce5c2536617a447379", [:mix], [{:ecto_sql, ">= 3.4.3", [hex: :ecto_sql, repo: "hexpm", optional: false]}, {:jason, "~> 1.1", [hex: :jason, repo: "hexpm", optional: false]}, {:postgrex, "~> 0.14", [hex: :postgrex, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "cf574813bd048b98a698aa587c21367d2e06842d4e1b1993dcd6a696e9e633bd"},
    "open_api_spex": {:git, "https://git.pleroma.social/pleroma/elixir-libraries/open_api_spex.git", "f296ac0924ba3cf79c7a588c4c252889df4c2edd", [ref: "f296ac0924ba3cf79c7a588c4c252889df4c2edd"]},
 +  "p1_utils": {:hex, :p1_utils, "1.0.18", "3fe224de5b2e190d730a3c5da9d6e8540c96484cf4b4692921d1e28f0c32b01c", [:rebar3], [], "hexpm", "1fc8773a71a15553b179c986b22fbeead19b28fe486c332d4929700ffeb71f88"},
    "parse_trans": {:hex, :parse_trans, "3.3.0", "09765507a3c7590a784615cfd421d101aec25098d50b89d7aa1d66646bc571c1", [:rebar3], [], "hexpm", "17ef63abde837ad30680ea7f857dd9e7ced9476cdd7b0394432af4bfc241b960"},
    "pbkdf2_elixir": {:hex, :pbkdf2_elixir, "1.2.1", "9cbe354b58121075bd20eb83076900a3832324b7dd171a6895fab57b6bb2752c", [:mix], [{:comeonin, "~> 5.3", [hex: :comeonin, repo: "hexpm", optional: false]}], "hexpm", "d3b40a4a4630f0b442f19eca891fcfeeee4c40871936fed2f68e1c4faa30481f"},
    "phoenix": {:hex, :phoenix, "1.4.13", "67271ad69b51f3719354604f4a3f968f83aa61c19199343656c9caee057ff3b8", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix_pubsub, "~> 1.1", [hex: :phoenix_pubsub, repo: "hexpm", optional: false]}, {:plug, "~> 1.8.1 or ~> 1.9", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 1.0 or ~> 2.0", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "ab765a0feddb81fc62e2116c827b5f068df85159c162bee760745276ad7ddc1b"},
@@@ -94,9 -91,9 +95,9 @@@
    "plug_static_index_html": {:hex, :plug_static_index_html, "1.0.0", "840123d4d3975585133485ea86af73cb2600afd7f2a976f9f5fd8b3808e636a0", [:mix], [{:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "79fd4fcf34d110605c26560cbae8f23c603ec4158c08298bd4360fdea90bb5cf"},
    "poison": {:hex, :poison, "3.1.0", "d9eb636610e096f86f25d9a46f35a9facac35609a7591b3be3326e99a0484665", [:mix], [], "hexpm", "fec8660eb7733ee4117b85f55799fd3833eb769a6df71ccf8903e8dc5447cfce"},
    "poolboy": {:hex, :poolboy, "1.5.2", "392b007a1693a64540cead79830443abf5762f5d30cf50bc95cb2c1aaafa006b", [:rebar3], [], "hexpm", "dad79704ce5440f3d5a3681c8590b9dc25d1a561e8f5a9c995281012860901e3"},
-   "postgrex": {:hex, :postgrex, "0.15.3", "5806baa8a19a68c4d07c7a624ccdb9b57e89cbc573f1b98099e3741214746ae4", [:mix], [{:connection, "~> 1.0", [hex: :connection, repo: "hexpm", optional: false]}, {:db_connection, "~> 2.1", [hex: :db_connection, repo: "hexpm", optional: false]}, {:decimal, "~> 1.5", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}], "hexpm", "4737ce62a31747b4c63c12b20c62307e51bb4fcd730ca0c32c280991e0606c90"},
+   "postgrex": {:hex, :postgrex, "0.15.5", "aec40306a622d459b01bff890fa42f1430dac61593b122754144ad9033a2152f", [:mix], [{:connection, "~> 1.0", [hex: :connection, repo: "hexpm", optional: false]}, {:db_connection, "~> 2.1", [hex: :db_connection, repo: "hexpm", optional: false]}, {:decimal, "~> 1.5", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}], "hexpm", "ed90c81e1525f65a2ba2279dbcebf030d6d13328daa2f8088b9661eb9143af7f"},
    "pot": {:hex, :pot, "0.10.2", "9895c83bcff8cd22d9f5bc79dfc88a188176b261b618ad70d93faf5c5ca36e67", [:rebar3], [], "hexpm", "ac589a8e296b7802681e93cd0a436faec117ea63e9916709c628df31e17e91e2"},
-   "prometheus": {:hex, :prometheus, "4.5.0", "8f4a2246fe0beb50af0f77c5e0a5bb78fe575c34a9655d7f8bc743aad1c6bf76", [:mix, :rebar3], [], "hexpm", "679b5215480fff612b8351f45c839d995a07ce403e42ff02f1c6b20960d41a4e"},
+   "prometheus": {:hex, :prometheus, "4.6.0", "20510f381db1ccab818b4cf2fac5fa6ab5cc91bc364a154399901c001465f46f", [:mix, :rebar3], [], "hexpm", "4905fd2992f8038eccd7aa0cd22f40637ed618c0bed1f75c05aacec15b7545de"},
    "prometheus_ecto": {:hex, :prometheus_ecto, "1.4.3", "3dd4da1812b8e0dbee81ea58bb3b62ed7588f2eae0c9e97e434c46807ff82311", [:mix], [{:ecto, "~> 2.0 or ~> 3.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:prometheus_ex, "~> 1.1 or ~> 2.0 or ~> 3.0", [hex: :prometheus_ex, repo: "hexpm", optional: false]}], "hexpm", "8d66289f77f913b37eda81fd287340c17e61a447549deb28efc254532b2bed82"},
    "prometheus_ex": {:hex, :prometheus_ex, "3.0.5", "fa58cfd983487fc5ead331e9a3e0aa622c67232b3ec71710ced122c4c453a02f", [:mix], [{:prometheus, "~> 4.0", [hex: :prometheus, repo: "hexpm", optional: false]}], "hexpm", "9fd13404a48437e044b288b41f76e64acd9735fb8b0e3809f494811dfa66d0fb"},
    "prometheus_phoenix": {:hex, :prometheus_phoenix, "1.3.0", "c4b527e0b3a9ef1af26bdcfbfad3998f37795b9185d475ca610fe4388fdd3bb5", [:mix], [{:phoenix, "~> 1.4", [hex: :phoenix, repo: "hexpm", optional: false]}, {:prometheus_ex, "~> 1.3 or ~> 2.0 or ~> 3.0", [hex: :prometheus_ex, repo: "hexpm", optional: false]}], "hexpm", "c4d1404ac4e9d3d963da601db2a7d8ea31194f0017057fabf0cfb9bf5a6c8c75"},
    "swoosh": {:git, "https://github.com/swoosh/swoosh", "c96e0ca8a00d8f211ec1f042a4626b09f249caa5", [ref: "c96e0ca8a00d8f211ec1f042a4626b09f249caa5"]},
    "syslog": {:hex, :syslog, "1.1.0", "6419a232bea84f07b56dc575225007ffe34d9fdc91abe6f1b2f254fd71d8efc2", [:rebar3], [], "hexpm", "4c6a41373c7e20587be33ef841d3de6f3beba08519809329ecc4d27b15b659e1"},
    "telemetry": {:hex, :telemetry, "0.4.2", "2808c992455e08d6177322f14d3bdb6b625fbcfd233a73505870d8738a2f4599", [:rebar3], [], "hexpm", "2d1419bd9dda6a206d7b5852179511722e2b18812310d304620c7bd92a13fcef"},
-   "tesla": {:git, "https://git.pleroma.social/pleroma/elixir-libraries/tesla.git", "61b7503cef33f00834f78ddfafe0d5d9dec2270b", [ref: "61b7503cef33f00834f78ddfafe0d5d9dec2270b"]},
+   "tesla": {:git, "https://github.com/teamon/tesla.git", "af3707078b10793f6a534938e56b963aff82fe3c", [ref: "af3707078b10793f6a534938e56b963aff82fe3c"]},
    "timex": {:hex, :timex, "3.6.1", "efdf56d0e67a6b956cc57774353b0329c8ab7726766a11547e529357ffdc1d56", [:mix], [{:combine, "~> 0.10", [hex: :combine, repo: "hexpm", optional: false]}, {:gettext, "~> 0.10", [hex: :gettext, repo: "hexpm", optional: false]}, {:tzdata, "~> 0.1.8 or ~> 0.5 or ~> 1.0.0", [hex: :tzdata, repo: "hexpm", optional: false]}], "hexpm", "f354efb2400dd7a80fd9eb6c8419068c4f632da4ac47f3d8822d6e33f08bc852"},
    "trailing_format_plug": {:hex, :trailing_format_plug, "0.0.7", "64b877f912cf7273bed03379936df39894149e35137ac9509117e59866e10e45", [:mix], [{:plug, "> 0.12.0", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "bd4fde4c15f3e993a999e019d64347489b91b7a9096af68b2bdadd192afa693f"},
    "tzdata": {:hex, :tzdata, "1.0.3", "73470ad29dde46e350c60a66e6b360d3b99d2d18b74c4c349dbebbc27a09a3eb", [:mix], [{:hackney, "~> 1.0", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm", "a6e1ee7003c4d04ecbd21dd3ec690d4c6662db5d3bbdd7262d53cdf5e7c746c1"},
index ac5d8fd32a60f8f82e4be9c28487eb4d73962f17,72885cfdd09f0bb081f2e61a9625d830f48e6737..06990464ff2dc1cac0bcb4c9ca36f37f48da7efe
@@@ -6,16 -6,9 +6,16 @@@ defmodule Pleroma.Web.MediaProxyTest d
    use ExUnit.Case
    use Pleroma.Tests.Helpers
  
 +  alias Pleroma.Config
    alias Pleroma.Web.Endpoint
    alias Pleroma.Web.MediaProxy
  
 +  defp decode_result(encoded) do
 +    [_, "proxy", sig, base64 | _] = URI.parse(encoded).path |> String.split("/")
 +    {:ok, decoded} = MediaProxy.decode_url(sig, base64)
 +    decoded
 +  end
 +
    describe "when enabled" do
      setup do: clear_config([:media_proxy, :enabled], true)
  
@@@ -42,7 -35,7 +42,7 @@@
  
        assert String.starts_with?(
                 encoded,
 -               Pleroma.Config.get([:media_proxy, :base_url], Pleroma.Web.base_url())
 +               Config.get([:media_proxy, :base_url], Pleroma.Web.base_url())
               )
  
        assert String.ends_with?(encoded, "/logo.png")
      end
  
      test "validates signature" do
-       secret_key_base = Config.get([Endpoint, :secret_key_base])
-       clear_config([Endpoint, :secret_key_base], secret_key_base)
        encoded = MediaProxy.url("https://pleroma.social")
  
-       Config.put(
+       clear_config(
          [Endpoint, :secret_key_base],
          "00000000000000000000000000000000000000000000000"
        )
        assert MediaProxy.decode_url(sig, base64) == {:error, :invalid_signature}
      end
  
 +    def test_verify_request_path_and_url(request_path, url, expected_result) do
 +      assert MediaProxy.verify_request_path_and_url(request_path, url) == expected_result
 +
 +      assert MediaProxy.verify_request_path_and_url(
 +               %Plug.Conn{
 +                 params: %{"filename" => Path.basename(request_path)},
 +                 request_path: request_path
 +               },
 +               url
 +             ) == expected_result
 +    end
 +
 +    test "if first arg of `verify_request_path_and_url/2` is a Plug.Conn without \"filename\" " <>
 +           "parameter, `verify_request_path_and_url/2` returns :ok " do
 +      assert MediaProxy.verify_request_path_and_url(
 +               %Plug.Conn{params: %{}, request_path: "/some/path"},
 +               "https://instance.com/file.jpg"
 +             ) == :ok
 +
 +      assert MediaProxy.verify_request_path_and_url(
 +               %Plug.Conn{params: %{}, request_path: "/path/to/file.jpg"},
 +               "https://instance.com/file.jpg"
 +             ) == :ok
 +    end
 +
 +    test "`verify_request_path_and_url/2` preserves the encoded or decoded path" do
 +      test_verify_request_path_and_url(
 +        "/Hello world.jpg",
 +        "http://pleroma.social/Hello world.jpg",
 +        :ok
 +      )
 +
 +      test_verify_request_path_and_url(
 +        "/Hello%20world.jpg",
 +        "http://pleroma.social/Hello%20world.jpg",
 +        :ok
 +      )
 +
 +      test_verify_request_path_and_url(
 +        "/my%2Flong%2Furl%2F2019%2F07%2FS.jpg",
 +        "http://pleroma.social/my%2Flong%2Furl%2F2019%2F07%2FS.jpg",
 +        :ok
 +      )
 +
 +      test_verify_request_path_and_url(
 +        "/my%2Flong%2Furl%2F2019%2F07%2FS",
 +        "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 MediaProxy.verify_request_path_and_url(
 +               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 = MediaProxy.url(url)
  
-       assert String.starts_with?(encoded, 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
      end
    end
  
+   defp decode_result(encoded) do
+     [_, "proxy", sig, base64 | _] = URI.parse(encoded).path |> String.split("/")
+     {:ok, decoded} = MediaProxy.decode_url(sig, base64)
+     decoded
+   end
    describe "whitelist" do
      setup do: clear_config([:media_proxy, :enabled], true)
  
      test "mediaproxy whitelist" do
+       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"