Improve error handling, add configuration
authorhref <href@random.sh>
Tue, 28 Nov 2017 20:44:25 +0000 (21:44 +0100)
committerhref <href@random.sh>
Tue, 28 Nov 2017 20:44:25 +0000 (21:44 +0100)
config/config.exs
lib/pleroma/web/media_proxy/controller.ex
lib/pleroma/web/media_proxy/media_proxy.ex

index c4f89c40c5433399e1fd971a6d379666e60a342c..503ce8d64be86757ab9dd586f14a720bb22dbb84 100644 (file)
@@ -47,6 +47,11 @@ config :pleroma, :instance,
   limit: 5000,
   registrations_open: true
 
+config :pleroma, :media_proxy,
+  enabled: false,
+  redirect_on_failure: true
+  #base_url: "https://cache.pleroma.social"
+
 # 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 fece7cf45c10a13c6869004933cc9b26ef8bf431..dc122fc3a4d5d31da3191c67961f7ad23a747291 100644 (file)
@@ -2,19 +2,27 @@ defmodule Pleroma.Web.MediaProxy.MediaProxyController do
   use Pleroma.Web, :controller
   require Logger
 
+  @cache_control %{
+    default: "public, max-age=1209600",
+    error:   "public, must-revalidate, max-age=160",
+  }
+
   def remote(conn, %{"sig" => sig, "url" => url}) do
-    {:ok, url} = Pleroma.Web.MediaProxy.decode_url(sig, url)
-    url = url |> URI.encode()
-    case proxy_request(url) do
-      {:ok, content_type, body} ->
-        conn
-        |> put_resp_content_type(content_type)
-        |> set_cache_header(:default)
-        |> send_resp(200, body)
-      other ->
-        conn
-        |> set_cache_header(:error)
-        |> redirect(external: url)
+    config = Application.get_env(:pleroma, :media_proxy, [])
+    with \
+      true <- Keyword.get(config, :enabled, false),
+      {:ok, url} <- Pleroma.Web.MediaProxy.decode_url(sig, url),
+      url = URI.encode(url),
+      {:ok, content_type, body} <- proxy_request(url)
+    do
+      conn
+      |> put_resp_content_type(content_type)
+      |> set_cache_header(:default)
+      |> send_resp(200, body)
+    else
+      false -> send_error(conn, 404)
+      {:error, :invalid_signature} -> send_error(conn, 403)
+      {:error, {:http, _, url}} -> redirect_or_error(conn, url, Keyword.get(config, :redirect_on_failure, true))
     end
   end
 
@@ -28,21 +36,24 @@ defmodule Pleroma.Web.MediaProxy.MediaProxyController do
         {:ok, headers["Content-Type"], body}
       {:ok, status, _, _} ->
         Logger.warn "MediaProxy: request failed, status #{status}, link: #{link}"
-        {:error, :bad_status}
+        {:error, {:http, :bad_status, link}}
       {:error, error} ->
         Logger.warn "MediaProxy: request failed, error #{inspect error}, link: #{link}"
-        {:error, error}
+        {:error, {:http, error, link}}
     end
   end
 
-  @cache_control %{
-    default: "public, max-age=1209600",
-    error:   "public, must-revalidate, max-age=160",
-  }
+  defp set_cache_header(conn, key) do
+    Plug.Conn.put_resp_header(conn, "cache-control", @cache_control[key])
+  end
+
+  defp redirect_or_error(conn, url, true), do: redirect(conn, external: url)
+  defp redirect_or_error(conn, url, _), do: send_error(conn, 502, "Media proxy error: " <> url)
 
-  defp set_cache_header(conn, true), do: set_cache_header(conn, :default)
-  defp set_cache_header(conn, false), do: set_cache_header(conn, :error)
-  defp set_cache_header(conn, key) when is_atom(key), do: set_cache_header(conn, @cache_control[key])
-  defp set_cache_header(conn, value) when is_binary(value), do: Plug.Conn.put_resp_header(conn, "cache-control", value)
+  defp send_error(conn, code, body \\ "") do
+    conn
+    |> set_cache_header(:error)
+    |> send_resp(code, body)
+  end
 
 end
index 9c1d717481d2ec7dde07ad50d3e87e515a878673..21ebdfbbc13fcb2a51c3c05deed89714891b6fbc 100644 (file)
@@ -1,23 +1,25 @@
 defmodule Pleroma.Web.MediaProxy do
   @base64_opts [padding: false]
-  @base64_key Application.get_env(:pleroma, Pleroma.Web.Endpoint)[:secret_key_base]
 
   def url(nil), do: nil
 
   def url(url) do
-    if String.starts_with?(url, Pleroma.Web.base_url) do
+    config = Application.get_env(:pleroma, :media_proxy, [])
+    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]
       base64 = Base.url_encode64(url, @base64_opts)
-      sig = :crypto.hmac(:sha, @base64_key, base64)
+      sig = :crypto.hmac(:sha, secret, base64)
       sig64 = sig |> Base.url_encode64(@base64_opts)
-      cache_url("#{sig64}/#{base64}")
+      Keyword.get(config, :base_url, Pleroma.Web.base_url) <> "/proxy/#{sig64}/#{base64}"
     end
   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)
-    local_sig = :crypto.hmac(:sha, @base64_key, url)
+    local_sig = :crypto.hmac(:sha, secret, url)
     if local_sig == sig do
       {:ok, Base.url_decode64!(url, @base64_opts)}
     else
@@ -25,9 +27,4 @@ defmodule Pleroma.Web.MediaProxy do
     end
   end
 
-  defp cache_url(path) do
-    "/proxy/" <> path
-  end
-
-
 end