From 24c3e2db2c6846073df80c124633dc851c20c107 Mon Sep 17 00:00:00 2001 From: Mark Felder Date: Thu, 25 Apr 2019 18:11:47 -0500 Subject: [PATCH] Add mediaproxy whitelist capability --- config/config.exs | 3 +- docs/config.md | 1 + lib/pleroma/web/media_proxy/media_proxy.ex | 50 ++++++++++++++-------- test/media_proxy_test.exs | 9 ++++ 4 files changed, 43 insertions(+), 20 deletions(-) diff --git a/config/config.exs b/config/config.exs index b11e4c680..a1cca06f8 100644 --- a/config/config.exs +++ b/config/config.exs @@ -326,7 +326,8 @@ follow_redirect: true, pool: :media ] - ] + ], + whitelist: [] config :pleroma, :chat, enabled: true diff --git a/docs/config.md b/docs/config.md index 7b6631f9b..7e31e6fb7 100644 --- a/docs/config.md +++ b/docs/config.md @@ -205,6 +205,7 @@ This section is used to configure Pleroma-FE, unless ``:managed_config`` in ``:i * `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 ## :gopher * `enabled`: Enables the gopher interface diff --git a/lib/pleroma/web/media_proxy/media_proxy.ex b/lib/pleroma/web/media_proxy/media_proxy.ex index 3bd2affe9..5762e767b 100644 --- a/lib/pleroma/web/media_proxy/media_proxy.ex +++ b/lib/pleroma/web/media_proxy/media_proxy.ex @@ -13,32 +13,44 @@ def url("/" <> _ = url), do: url def url(url) do config = Application.get_env(:pleroma, :media_proxy, []) + domain = URI.parse(url).host - if !Keyword.get(config, :enabled, false) or String.starts_with?(url, Pleroma.Web.base_url()) do - url - else - secret = Application.get_env(:pleroma, Pleroma.Web.Endpoint)[:secret_key_base] - - # Must preserve `%2F` for compatibility with S3 - # https://git.pleroma.social/pleroma/pleroma/issues/580 - replacement = get_replacement(url, ":2F:") - - # The URL is url-decoded and encoded again to ensure it is correctly encoded and not twice. - base64 = + cond do + !Keyword.get(config, :enabled, false) or String.starts_with?(url, Pleroma.Web.base_url()) -> url - |> String.replace("%2F", replacement) - |> URI.decode() - |> URI.encode() - |> String.replace(replacement, "%2F") - |> Base.url_encode64(@base64_opts) - sig = :crypto.hmac(:sha, secret, base64) - sig64 = sig |> Base.url_encode64(@base64_opts) + Enum.any?(Pleroma.Config.get([:media_proxy, :whitelist]), fn pattern -> + String.equivalent?(domain, pattern) + end) -> + url - build_url(sig64, base64, filename(url)) + true -> + encode_url(url) end end + def encode_url(url) do + secret = Application.get_env(:pleroma, Pleroma.Web.Endpoint)[:secret_key_base] + + # Must preserve `%2F` for compatibility with S3 + # https://git.pleroma.social/pleroma/pleroma/issues/580 + replacement = get_replacement(url, ":2F:") + + # The URL is url-decoded and encoded again to ensure it is correctly encoded and not twice. + base64 = + url + |> String.replace("%2F", replacement) + |> URI.decode() + |> URI.encode() + |> String.replace(replacement, "%2F") + |> Base.url_encode64(@base64_opts) + + sig = :crypto.hmac(:sha, secret, base64) + sig64 = sig |> Base.url_encode64(@base64_opts) + + build_url(sig64, base64, filename(url)) + end + def decode_url(sig, url) do secret = Application.get_env(:pleroma, Pleroma.Web.Endpoint)[:secret_key_base] sig = Base.url_decode64!(sig, @base64_opts) diff --git a/test/media_proxy_test.exs b/test/media_proxy_test.exs index ddbadfbf5..a4331478e 100644 --- a/test/media_proxy_test.exs +++ b/test/media_proxy_test.exs @@ -177,4 +177,13 @@ defp decode_result(encoded) do {:ok, decoded} = decode_url(sig, base64) decoded end + + test "mediaproxy whitelist" do + Pleroma.Config.put([:media_proxy, :enabled], true) + Pleroma.Config.put([:media_proxy, :whitelist], ["google.com", "feld.me"]) + url = "https://feld.me/foo.png" + + unencoded = url(url) + assert unencoded == url + end end