diff options
Diffstat (limited to 'lib')
| -rw-r--r-- | lib/pleroma/web/mastodon_api/views/account_view.ex | 5 | ||||
| -rw-r--r-- | lib/pleroma/web/mastodon_api/views/status_view.ex | 5 | ||||
| -rw-r--r-- | lib/pleroma/web/media_proxy/controller.ex | 59 | ||||
| -rw-r--r-- | lib/pleroma/web/media_proxy/media_proxy.ex | 30 | ||||
| -rw-r--r-- | lib/pleroma/web/router.ex | 8 | ||||
| -rw-r--r-- | lib/pleroma/web/twitter_api/representers/object_representer.ex | 2 | ||||
| -rw-r--r-- | lib/pleroma/web/twitter_api/views/user_view.ex | 7 | 
7 files changed, 108 insertions, 8 deletions
| diff --git a/lib/pleroma/web/mastodon_api/views/account_view.ex b/lib/pleroma/web/mastodon_api/views/account_view.ex index 02f1e60bb..1d5918988 100644 --- a/lib/pleroma/web/mastodon_api/views/account_view.ex +++ b/lib/pleroma/web/mastodon_api/views/account_view.ex @@ -3,6 +3,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountView do    alias Pleroma.User    alias Pleroma.Web.MastodonAPI.AccountView    alias Pleroma.Web.CommonAPI.Utils +  alias Pleroma.Web.MediaProxy    defp image_url(%{"url" => [ %{ "href" => href } | _ ]}), do: href    defp image_url(_), do: nil @@ -12,10 +13,10 @@ defmodule Pleroma.Web.MastodonAPI.AccountView do    end    def render("account.json", %{user: user}) do -    image = User.avatar_url(user) +    image = User.avatar_url(user) |> MediaProxy.url()      user_info = User.user_info(user) -    header = image_url(user.info["banner"]) || "https://placehold.it/700x335" +    header = (image_url(user.info["banner"]) || "https://placehold.it/700x335") |> MediaProxy.url()      %{        id: to_string(user.id), diff --git a/lib/pleroma/web/mastodon_api/views/status_view.ex b/lib/pleroma/web/mastodon_api/views/status_view.ex index 5585a5605..64f315597 100644 --- a/lib/pleroma/web/mastodon_api/views/status_view.ex +++ b/lib/pleroma/web/mastodon_api/views/status_view.ex @@ -3,6 +3,7 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do    alias Pleroma.Web.MastodonAPI.{AccountView, StatusView}    alias Pleroma.{User, Activity}    alias Pleroma.Web.CommonAPI.Utils +  alias Pleroma.Web.MediaProxy    def render("index.json", opts) do      render_many(opts.activities, StatusView, "status.json", opts) @@ -121,9 +122,9 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do      %{        id: to_string(attachment["id"] || hash_id), -      url: href, +      url: MediaProxy.url(href),        remote_url: href, -      preview_url: href, +      preview_url: MediaProxy.url(href),        text_url: href,        type: type      } diff --git a/lib/pleroma/web/media_proxy/controller.ex b/lib/pleroma/web/media_proxy/controller.ex new file mode 100644 index 000000000..dc122fc3a --- /dev/null +++ b/lib/pleroma/web/media_proxy/controller.ex @@ -0,0 +1,59 @@ +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 +    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 + +  defp proxy_request(link) do +    headers = [{"user-agent", "Pleroma/MediaProxy; #{Pleroma.Web.base_url()} <#{Application.get_env(:pleroma, :instance)[:email]}>"}] +    options = [:insecure, {:follow_redirect, true}] +    case :hackney.request(:get, link, headers, "", options) do +      {:ok, 200, headers, client} -> +        headers = Enum.into(headers, Map.new) +        {:ok, body} = :hackney.body(client) +        {:ok, headers["Content-Type"], body} +      {:ok, status, _, _} -> +        Logger.warn "MediaProxy: request failed, status #{status}, link: #{link}" +        {:error, {:http, :bad_status, link}} +      {:error, error} -> +        Logger.warn "MediaProxy: request failed, error #{inspect error}, link: #{link}" +        {:error, {:http, error, link}} +    end +  end + +  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 send_error(conn, code, body \\ "") do +    conn +    |> set_cache_header(:error) +    |> send_resp(code, body) +  end + +end diff --git a/lib/pleroma/web/media_proxy/media_proxy.ex b/lib/pleroma/web/media_proxy/media_proxy.ex new file mode 100644 index 000000000..21ebdfbbc --- /dev/null +++ b/lib/pleroma/web/media_proxy/media_proxy.ex @@ -0,0 +1,30 @@ +defmodule Pleroma.Web.MediaProxy do +  @base64_opts [padding: false] + +  def url(nil), do: nil + +  def url(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, secret, base64) +      sig64 = sig |> Base.url_encode64(@base64_opts) +      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, secret, url) +    if local_sig == sig do +      {:ok, Base.url_decode64!(url, @base64_opts)} +    else +      {:error, :invalid_signature} +    end +  end + +end diff --git a/lib/pleroma/web/router.ex b/lib/pleroma/web/router.ex index 6806e8a75..799021c24 100644 --- a/lib/pleroma/web/router.ex +++ b/lib/pleroma/web/router.ex @@ -233,6 +233,14 @@ defmodule Pleroma.Web.Router do      delete "/auth/sign_out", MastodonAPIController, :logout    end +  pipeline :remote_media do +    plug :accepts, ["html"] +  end +  scope "/proxy/", Pleroma.Web.MediaProxy do +    pipe_through :remote_media +    get "/:sig/:url", MediaProxyController, :remote +  end +    scope "/", Fallback do      get "/*path", RedirectController, :redirector    end diff --git a/lib/pleroma/web/twitter_api/representers/object_representer.ex b/lib/pleroma/web/twitter_api/representers/object_representer.ex index c39b60760..69eaeb36c 100644 --- a/lib/pleroma/web/twitter_api/representers/object_representer.ex +++ b/lib/pleroma/web/twitter_api/representers/object_representer.ex @@ -6,7 +6,7 @@ defmodule Pleroma.Web.TwitterAPI.Representers.ObjectRepresenter do      data = object.data      url = List.first(data["url"])      %{ -      url: url["href"], +      url: url["href"] |> Pleroma.Web.MediaProxy.url(),        mimetype: url["mediaType"],        id: data["uuid"],        oembed: false diff --git a/lib/pleroma/web/twitter_api/views/user_view.ex b/lib/pleroma/web/twitter_api/views/user_view.ex index d1c7e6fbd..cc6b450fb 100644 --- a/lib/pleroma/web/twitter_api/views/user_view.ex +++ b/lib/pleroma/web/twitter_api/views/user_view.ex @@ -2,6 +2,7 @@ defmodule Pleroma.Web.TwitterAPI.UserView do    use Pleroma.Web, :view    alias Pleroma.User    alias Pleroma.Web.CommonAPI.Utils +  alias Pleroma.Web.MediaProxy    def render("show.json", %{user: user = %User{}} = assigns) do      render_one(user, Pleroma.Web.TwitterAPI.UserView, "user.json", assigns) @@ -12,7 +13,7 @@ defmodule Pleroma.Web.TwitterAPI.UserView do    end    def render("user.json", %{user: user = %User{}} = assigns) do -    image = User.avatar_url(user) +    image = User.avatar_url(user) |> MediaProxy.url()      {following, follows_you, statusnet_blocking} = if assigns[:for] do        {          User.following?(assigns[:for], user), @@ -44,8 +45,8 @@ defmodule Pleroma.Web.TwitterAPI.UserView do        "screen_name" => user.nickname,        "statuses_count" => user_info[:note_count],        "statusnet_profile_url" => user.ap_id, -      "cover_photo" => image_url(user.info["banner"]), -      "background_image" => image_url(user.info["background"]) +      "cover_photo" => image_url(user.info["banner"]) |> MediaProxy.url(), +      "background_image" => image_url(user.info["background"]) |> MediaProxy.url(),      }      if assigns[:token] do | 
