Fork of Pleroma with site-specific changes and feature branches https://git.pleroma.social/pleroma/pleroma
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

119 line
3.0KB

  1. # Pleroma: A lightweight social networking server
  2. # Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
  3. # SPDX-License-Identifier: AGPL-3.0-only
  4. defmodule Pleroma.Web.MediaProxy do
  5. alias Pleroma.Config
  6. alias Pleroma.Upload
  7. alias Pleroma.Web
  8. alias Pleroma.Web.MediaProxy.Invalidation
  9. @base64_opts [padding: false]
  10. @spec in_deleted_urls(String.t()) :: boolean()
  11. def in_deleted_urls(url), do: elem(Cachex.exists?(:deleted_urls_cache, url(url)), 1)
  12. def remove_from_deleted_urls(urls) when is_list(urls) do
  13. Cachex.execute!(:deleted_urls_cache, fn cache ->
  14. Enum.each(Invalidation.prepare_urls(urls), &Cachex.del(cache, &1))
  15. end)
  16. end
  17. def remove_from_deleted_urls(url) when is_binary(url) do
  18. Cachex.del(:deleted_urls_cache, url(url))
  19. end
  20. def put_in_deleted_urls(urls) when is_list(urls) do
  21. Cachex.execute!(:deleted_urls_cache, fn cache ->
  22. Enum.each(Invalidation.prepare_urls(urls), &Cachex.put(cache, &1, true))
  23. end)
  24. end
  25. def put_in_deleted_urls(url) when is_binary(url) do
  26. Cachex.put(:deleted_urls_cache, url(url), true)
  27. end
  28. def url(url) when is_nil(url) or url == "", do: nil
  29. def url("/" <> _ = url), do: url
  30. def url(url) do
  31. if disabled?() or not is_url_proxiable?(url) do
  32. url
  33. else
  34. encode_url(url)
  35. end
  36. end
  37. @spec is_url_proxiable?(String.t()) :: boolean()
  38. def is_url_proxiable?(url) do
  39. if local?(url) or whitelisted?(url) do
  40. false
  41. else
  42. true
  43. end
  44. end
  45. defp disabled?, do: !Config.get([:media_proxy, :enabled], false)
  46. defp local?(url), do: String.starts_with?(url, Pleroma.Web.base_url())
  47. defp whitelisted?(url) do
  48. %{host: domain} = URI.parse(url)
  49. mediaproxy_whitelist = Config.get([:media_proxy, :whitelist])
  50. upload_base_url_domain =
  51. if !is_nil(Config.get([Upload, :base_url])) do
  52. [URI.parse(Config.get([Upload, :base_url])).host]
  53. else
  54. []
  55. end
  56. whitelist = mediaproxy_whitelist ++ upload_base_url_domain
  57. Enum.any?(whitelist, fn pattern ->
  58. String.equivalent?(domain, pattern)
  59. end)
  60. end
  61. def encode_url(url) do
  62. base64 = Base.url_encode64(url, @base64_opts)
  63. sig64 =
  64. base64
  65. |> signed_url
  66. |> Base.url_encode64(@base64_opts)
  67. build_url(sig64, base64, filename(url))
  68. end
  69. def decode_url(sig, url) do
  70. with {:ok, sig} <- Base.url_decode64(sig, @base64_opts),
  71. signature when signature == sig <- signed_url(url) do
  72. {:ok, Base.url_decode64!(url, @base64_opts)}
  73. else
  74. _ -> {:error, :invalid_signature}
  75. end
  76. end
  77. defp signed_url(url) do
  78. :crypto.hmac(:sha, Config.get([Web.Endpoint, :secret_key_base]), url)
  79. end
  80. def filename(url_or_path) do
  81. if path = URI.parse(url_or_path).path, do: Path.basename(path)
  82. end
  83. def build_url(sig_base64, url_base64, filename \\ nil) do
  84. [
  85. Pleroma.Config.get([:media_proxy, :base_url], Web.base_url()),
  86. "proxy",
  87. sig_base64,
  88. url_base64,
  89. filename
  90. ]
  91. |> Enum.filter(& &1)
  92. |> Path.join()
  93. end
  94. end