From 7f4c3a1e993a3827b58f9cb8049a8ee5f54a1bdf Mon Sep 17 00:00:00 2001
From: href <href@random.sh>
Date: Tue, 20 Nov 2018 17:46:54 +0100
Subject: [PATCH] mediaproxy: fix empty url & add some tests

---
 lib/pleroma/web/media_proxy/media_proxy.ex |   6 +-
 test/media_proxy_test.exs                  | 113 +++++++++++++++++++++
 2 files changed, 117 insertions(+), 2 deletions(-)
 create mode 100644 test/media_proxy_test.exs

diff --git a/lib/pleroma/web/media_proxy/media_proxy.ex b/lib/pleroma/web/media_proxy/media_proxy.ex
index 93c36b4ed..0fc0a07b2 100644
--- a/lib/pleroma/web/media_proxy/media_proxy.ex
+++ b/lib/pleroma/web/media_proxy/media_proxy.ex
@@ -3,6 +3,8 @@ defmodule Pleroma.Web.MediaProxy do
 
   def url(nil), do: nil
 
+  def url(""), do: nil
+
   def url(url = "/" <> _), do: url
 
   def url(url) do
@@ -15,10 +17,10 @@ def url(url) do
       base64 = Base.url_encode64(url, @base64_opts)
       sig = :crypto.hmac(:sha, secret, base64)
       sig64 = sig |> Base.url_encode64(@base64_opts)
-      filename = Path.basename(URI.parse(url).path)
+      filename = if path = URI.parse(url).path, do: "/" <> Path.basename(path), else: ""
 
       Keyword.get(config, :base_url, Pleroma.Web.base_url()) <>
-        "/proxy/#{sig64}/#{base64}/#{filename}"
+        "/proxy/#{sig64}/#{base64}#{filename}"
     end
   end
 
diff --git a/test/media_proxy_test.exs b/test/media_proxy_test.exs
new file mode 100644
index 000000000..c69ed7ea4
--- /dev/null
+++ b/test/media_proxy_test.exs
@@ -0,0 +1,113 @@
+defmodule Pleroma.MediaProxyTest do
+  use ExUnit.Case
+  import Pleroma.Web.MediaProxy
+
+  describe "when enabled" do
+    setup do
+      enabled = Pleroma.Config.get([:media_proxy, :enabled])
+
+      unless enabled do
+        Pleroma.Config.put([:media_proxy, :enabled], true)
+        on_exit(fn -> Pleroma.Config.put([:media_proxy, :enabled], enabled) end)
+      end
+
+      :ok
+    end
+
+    test "ignores invalid url" do
+      assert url(nil) == nil
+      assert url("") == nil
+    end
+
+    test "ignores relative url" do
+      assert url("/local") == "/local"
+      assert 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
+    end
+
+    test "encodes and decodes URL" do
+      url = "https://pleroma.soykaf.com/static/logo.png"
+      encoded = url(url)
+
+      assert String.starts_with?(
+               encoded,
+               Pleroma.Config.get([:media_proxy, :base_url], Pleroma.Web.base_url())
+             )
+
+      assert String.ends_with?(encoded, "/logo.png")
+
+      assert decode_result(encoded) == url
+    end
+
+    test "encodes and decodes URL without a path" do
+      url = "https://pleroma.soykaf.com"
+      encoded = 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)
+      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)
+      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")
+
+      Pleroma.Config.put(
+        [Pleroma.Web.Endpoint, :secret_key_base],
+        "00000000000000000000000000000000000000000000000"
+      )
+
+      [_, "proxy", sig, base64 | _] = URI.parse(encoded).path |> String.split("/")
+      assert decode_url(sig, base64) == {:error, :invalid_signature}
+    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
+
+    test "does not encode remote urls" do
+      assert 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)
+    decoded
+  end
+end