diff options
| -rw-r--r-- | CHANGELOG.md | 3 | ||||
| -rw-r--r-- | config/config.exs | 3 | ||||
| -rw-r--r-- | docs/config.md | 1 | ||||
| -rw-r--r-- | lib/pleroma/web/activity_pub/transmogrifier.ex | 34 | ||||
| -rw-r--r-- | lib/pleroma/web/media_proxy/media_proxy.ex | 50 | ||||
| -rw-r--r-- | test/media_proxy_test.exs | 9 | ||||
| -rw-r--r-- | test/web/activity_pub/transmogrifier_test.exs | 20 | 
7 files changed, 96 insertions, 24 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md index 0caeda978..8b07cdfa2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).  - Configuration: `link_name` option  - Configuration: `fetch_initial_posts` option  - Configuration: `notify_email` option +- Configuration: Media proxy `whitelist` option  - Pleroma API: User subscriptions  - Pleroma API: Healthcheck endpoint  - Admin API: Endpoints for listing/revoking invite tokens @@ -40,6 +41,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).  - Configuration: Dedupe enabled by default  - Configuration: Added `extra_cookie_attrs` for setting non-standard cookie attributes. Defaults to ["SameSite=Lax"] so that remote follows work.  - Pleroma API: Support for emoji tags in `/api/pleroma/emoji` resulting in a breaking API change +- Timelines: Messages involving people you have blocked will be excluded from the timeline in all cases instead of just repeats.  - Mastodon API: Support for `exclude_types`, `limit` and `min_id` in `/api/v1/notifications`  - Mastodon API: Add `languages` and `registrations` to `/api/v1/instance`  - Mastodon API: Provide plaintext versions of cw/content in the Status entity @@ -70,6 +72,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).  - Federation: Cope with missing or explicitly nulled address lists  - Federation: Explicitly ensure activities addressed to `as:Public` become addressed to the followers collection  - Federation: Better cope with actors which do not declare a followers collection and use `as:Public` with these semantics +- Federation: Follow requests from remote users who have been blocked will be automatically rejected if appropriate  - MediaProxy: Parse name from content disposition headers even for non-whitelisted types  - MediaProxy: S3 link encoding  - Rich Media: Reject any data which cannot be explicitly encoded into JSON 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 @@ config :pleroma, :media_proxy,        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/activity_pub/transmogrifier.ex b/lib/pleroma/web/activity_pub/transmogrifier.ex index 52666a409..b1e859d7c 100644 --- a/lib/pleroma/web/activity_pub/transmogrifier.ex +++ b/lib/pleroma/web/activity_pub/transmogrifier.ex @@ -438,20 +438,46 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do      with %User{local: true} = followed <- User.get_cached_by_ap_id(followed),           %User{} = follower <- User.get_or_fetch_by_ap_id(follower),           {:ok, activity} <- ActivityPub.follow(follower, followed, id, false) do -      if not User.locked?(followed) do +      with deny_follow_blocked <- Pleroma.Config.get([:user, :deny_follow_blocked]), +           {:user_blocked, false} <- +             {:user_blocked, User.blocks?(followed, follower) && deny_follow_blocked}, +           {:user_locked, false} <- {:user_locked, User.locked?(followed)}, +           {:follow, {:ok, follower}} <- {:follow, User.follow(follower, followed)} do          ActivityPub.accept(%{            to: [follower.ap_id],            actor: followed,            object: data,            local: true          }) - -        User.follow(follower, followed) +      else +        {:user_blocked, true} -> +          {:ok, _} = Utils.update_follow_state(activity, "reject") + +          ActivityPub.reject(%{ +            to: [follower.ap_id], +            actor: followed, +            object: data, +            local: true +          }) + +        {:follow, {:error, _}} -> +          {:ok, _} = Utils.update_follow_state(activity, "reject") + +          ActivityPub.reject(%{ +            to: [follower.ap_id], +            actor: followed, +            object: data, +            local: true +          }) + +        {:user_locked, true} -> +          :noop        end        {:ok, activity}      else -      _e -> :error +      _e -> +        :error      end    end 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 @@ defmodule Pleroma.Web.MediaProxy do    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 @@ defmodule Pleroma.MediaProxyTest 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 diff --git a/test/web/activity_pub/transmogrifier_test.exs b/test/web/activity_pub/transmogrifier_test.exs index 31e36a987..78429c7c6 100644 --- a/test/web/activity_pub/transmogrifier_test.exs +++ b/test/web/activity_pub/transmogrifier_test.exs @@ -215,6 +215,26 @@ defmodule Pleroma.Web.ActivityPub.TransmogrifierTest do        assert User.following?(User.get_cached_by_ap_id(data["actor"]), user)      end +    test "it rejects incoming follow requests from blocked users when deny_follow_blocked is enabled" do +      Pleroma.Config.put([:user, :deny_follow_blocked], true) + +      user = insert(:user) +      target = User.get_or_fetch("http://mastodon.example.org/users/admin") + +      {:ok, user} = User.block(user, target) + +      data = +        File.read!("test/fixtures/mastodon-follow-activity.json") +        |> Poison.decode!() +        |> Map.put("object", user.ap_id) + +      {:ok, %Activity{data: %{"id" => id}}} = Transmogrifier.handle_incoming(data) + +      %Activity{} = activity = Activity.get_by_ap_id(id) + +      assert activity.data["state"] == "reject" +    end +      test "it works for incoming follow requests from hubzilla" do        user = insert(:user)  | 
