diff options
Diffstat (limited to 'test/web/activity_pub/mrf')
9 files changed, 647 insertions, 0 deletions
diff --git a/test/web/activity_pub/mrf/anti_link_spam_policy_test.exs b/test/web/activity_pub/mrf/anti_link_spam_policy_test.exs new file mode 100644 index 000000000..03dc299ec --- /dev/null +++ b/test/web/activity_pub/mrf/anti_link_spam_policy_test.exs @@ -0,0 +1,145 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2019 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.ActivityPub.MRF.AntiLinkSpamPolicyTest do + use Pleroma.DataCase + import Pleroma.Factory + import ExUnit.CaptureLog + + alias Pleroma.Web.ActivityPub.MRF.AntiLinkSpamPolicy + + @linkless_message %{ + "type" => "Create", + "object" => %{ + "content" => "hi world!" + } + } + + @linkful_message %{ + "type" => "Create", + "object" => %{ + "content" => "<a href='https://example.com'>hi world!</a>" + } + } + + @response_message %{ + "type" => "Create", + "object" => %{ + "name" => "yes", + "type" => "Answer" + } + } + + describe "with new user" do + test "it allows posts without links" do + user = insert(:user) + + assert user.info.note_count == 0 + + message = + @linkless_message + |> Map.put("actor", user.ap_id) + + {:ok, _message} = AntiLinkSpamPolicy.filter(message) + end + + test "it disallows posts with links" do + user = insert(:user) + + assert user.info.note_count == 0 + + message = + @linkful_message + |> Map.put("actor", user.ap_id) + + {:reject, _} = AntiLinkSpamPolicy.filter(message) + end + end + + describe "with old user" do + test "it allows posts without links" do + user = insert(:user, info: %{note_count: 1}) + + assert user.info.note_count == 1 + + message = + @linkless_message + |> Map.put("actor", user.ap_id) + + {:ok, _message} = AntiLinkSpamPolicy.filter(message) + end + + test "it allows posts with links" do + user = insert(:user, info: %{note_count: 1}) + + assert user.info.note_count == 1 + + message = + @linkful_message + |> Map.put("actor", user.ap_id) + + {:ok, _message} = AntiLinkSpamPolicy.filter(message) + end + end + + describe "with followed new user" do + test "it allows posts without links" do + user = insert(:user, info: %{follower_count: 1}) + + assert user.info.follower_count == 1 + + message = + @linkless_message + |> Map.put("actor", user.ap_id) + + {:ok, _message} = AntiLinkSpamPolicy.filter(message) + end + + test "it allows posts with links" do + user = insert(:user, info: %{follower_count: 1}) + + assert user.info.follower_count == 1 + + message = + @linkful_message + |> Map.put("actor", user.ap_id) + + {:ok, _message} = AntiLinkSpamPolicy.filter(message) + end + end + + describe "with unknown actors" do + test "it rejects posts without links" do + message = + @linkless_message + |> Map.put("actor", "http://invalid.actor") + + assert capture_log(fn -> + {:reject, _} = AntiLinkSpamPolicy.filter(message) + end) =~ "[error] Could not decode user at fetch http://invalid.actor" + end + + test "it rejects posts with links" do + message = + @linkful_message + |> Map.put("actor", "http://invalid.actor") + + assert capture_log(fn -> + {:reject, _} = AntiLinkSpamPolicy.filter(message) + end) =~ "[error] Could not decode user at fetch http://invalid.actor" + end + end + + describe "with contentless-objects" do + test "it does not reject them or error out" do + user = insert(:user, info: %{note_count: 1}) + + message = + @response_message + |> Map.put("actor", user.ap_id) + + {:ok, _message} = AntiLinkSpamPolicy.filter(message) + end + end +end diff --git a/test/web/activity_pub/mrf/ensure_re_prepended_test.exs b/test/web/activity_pub/mrf/ensure_re_prepended_test.exs new file mode 100644 index 000000000..dbc8b9e80 --- /dev/null +++ b/test/web/activity_pub/mrf/ensure_re_prepended_test.exs @@ -0,0 +1,82 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2019 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.ActivityPub.MRF.EnsureRePrependedTest do + use Pleroma.DataCase + + alias Pleroma.Activity + alias Pleroma.Object + alias Pleroma.Web.ActivityPub.MRF.EnsureRePrepended + + describe "rewrites summary" do + test "it adds `re:` to summary object when child summary and parent summary equal" do + message = %{ + "type" => "Create", + "object" => %{ + "summary" => "object-summary", + "inReplyTo" => %Activity{object: %Object{data: %{"summary" => "object-summary"}}} + } + } + + assert {:ok, res} = EnsureRePrepended.filter(message) + assert res["object"]["summary"] == "re: object-summary" + end + + test "it adds `re:` to summary object when child summary containts re-subject of parent summary " do + message = %{ + "type" => "Create", + "object" => %{ + "summary" => "object-summary", + "inReplyTo" => %Activity{object: %Object{data: %{"summary" => "re: object-summary"}}} + } + } + + assert {:ok, res} = EnsureRePrepended.filter(message) + assert res["object"]["summary"] == "re: object-summary" + end + end + + describe "skip filter" do + test "it skip if type isn't 'Create'" do + message = %{ + "type" => "Annotation", + "object" => %{"summary" => "object-summary"} + } + + assert {:ok, res} = EnsureRePrepended.filter(message) + assert res == message + end + + test "it skip if summary is empty" do + message = %{ + "type" => "Create", + "object" => %{ + "inReplyTo" => %Activity{object: %Object{data: %{"summary" => "summary"}}} + } + } + + assert {:ok, res} = EnsureRePrepended.filter(message) + assert res == message + end + + test "it skip if inReplyTo is empty" do + message = %{"type" => "Create", "object" => %{"summary" => "summary"}} + assert {:ok, res} = EnsureRePrepended.filter(message) + assert res == message + end + + test "it skip if parent and child summary isn't equal" do + message = %{ + "type" => "Create", + "object" => %{ + "summary" => "object-summary", + "inReplyTo" => %Activity{object: %Object{data: %{"summary" => "summary"}}} + } + } + + assert {:ok, res} = EnsureRePrepended.filter(message) + assert res == message + end + end +end diff --git a/test/web/activity_pub/mrf/mediaproxy_warming_policy_test.exs b/test/web/activity_pub/mrf/mediaproxy_warming_policy_test.exs new file mode 100644 index 000000000..372e789be --- /dev/null +++ b/test/web/activity_pub/mrf/mediaproxy_warming_policy_test.exs @@ -0,0 +1,45 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.ActivityPub.MRF.MediaProxyWarmingPolicyTest do + use Pleroma.DataCase + + alias Pleroma.HTTP + alias Pleroma.Web.ActivityPub.MRF.MediaProxyWarmingPolicy + + import Mock + + @message %{ + "type" => "Create", + "object" => %{ + "type" => "Note", + "content" => "content", + "attachment" => [ + %{"url" => [%{"href" => "http://example.com/image.jpg"}]} + ] + } + } + + test "it prefetches media proxy URIs" do + with_mock HTTP, get: fn _, _, _ -> {:ok, []} end do + MediaProxyWarmingPolicy.filter(@message) + assert called(HTTP.get(:_, :_, :_)) + end + end + + test "it does nothing when no attachments are present" do + object = + @message["object"] + |> Map.delete("attachment") + + message = + @message + |> Map.put("object", object) + + with_mock HTTP, get: fn _, _, _ -> {:ok, []} end do + MediaProxyWarmingPolicy.filter(message) + refute called(HTTP.get(:_, :_, :_)) + end + end +end diff --git a/test/web/activity_pub/mrf/no_placeholder_text_policy_test.exs b/test/web/activity_pub/mrf/no_placeholder_text_policy_test.exs new file mode 100644 index 000000000..63ed71129 --- /dev/null +++ b/test/web/activity_pub/mrf/no_placeholder_text_policy_test.exs @@ -0,0 +1,37 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2019 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.ActivityPub.MRF.NoPlaceholderTextPolicyTest do + use Pleroma.DataCase + alias Pleroma.Web.ActivityPub.MRF.NoPlaceholderTextPolicy + + test "it clears content object" do + message = %{ + "type" => "Create", + "object" => %{"content" => ".", "attachment" => "image"} + } + + assert {:ok, res} = NoPlaceholderTextPolicy.filter(message) + assert res["object"]["content"] == "" + + message = put_in(message, ["object", "content"], "<p>.</p>") + assert {:ok, res} = NoPlaceholderTextPolicy.filter(message) + assert res["object"]["content"] == "" + end + + @messages [ + %{ + "type" => "Create", + "object" => %{"content" => "test", "attachment" => "image"} + }, + %{"type" => "Create", "object" => %{"content" => "."}}, + %{"type" => "Create", "object" => %{"content" => "<p>.</p>"}} + ] + test "it skips filter" do + Enum.each(@messages, fn message -> + assert {:ok, res} = NoPlaceholderTextPolicy.filter(message) + assert res == message + end) + end +end diff --git a/test/web/activity_pub/mrf/normalize_markup_test.exs b/test/web/activity_pub/mrf/normalize_markup_test.exs new file mode 100644 index 000000000..3916a1f35 --- /dev/null +++ b/test/web/activity_pub/mrf/normalize_markup_test.exs @@ -0,0 +1,42 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2019 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.ActivityPub.MRF.NormalizeMarkupTest do + use Pleroma.DataCase + alias Pleroma.Web.ActivityPub.MRF.NormalizeMarkup + + @html_sample """ + <b>this is in bold</b> + <p>this is a paragraph</p> + this is a linebreak<br /> + this is a link with allowed "rel" attribute: <a href="http://example.com/" rel="tag">example.com</a> + this is a link with not allowed "rel" attribute: <a href="http://example.com/" rel="tag noallowed">example.com</a> + this is an image: <img src="http://example.com/image.jpg"><br /> + <script>alert('hacked')</script> + """ + + test "it filter html tags" do + expected = """ + <b>this is in bold</b> + <p>this is a paragraph</p> + this is a linebreak<br /> + this is a link with allowed "rel" attribute: <a href="http://example.com/" rel="tag">example.com</a> + this is a link with not allowed "rel" attribute: <a href="http://example.com/">example.com</a> + this is an image: <img src="http://example.com/image.jpg" /><br /> + alert('hacked') + """ + + message = %{"type" => "Create", "object" => %{"content" => @html_sample}} + + assert {:ok, res} = NormalizeMarkup.filter(message) + assert res["object"]["content"] == expected + end + + test "it skips filter if type isn't `Create`" do + message = %{"type" => "Note", "object" => %{}} + + assert {:ok, res} = NormalizeMarkup.filter(message) + assert res == message + end +end diff --git a/test/web/activity_pub/mrf/reject_non_public_test.exs b/test/web/activity_pub/mrf/reject_non_public_test.exs new file mode 100644 index 000000000..fdf6b245e --- /dev/null +++ b/test/web/activity_pub/mrf/reject_non_public_test.exs @@ -0,0 +1,105 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2019 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.ActivityPub.MRF.RejectNonPublicTest do + use Pleroma.DataCase + import Pleroma.Factory + + alias Pleroma.Web.ActivityPub.MRF.RejectNonPublic + + setup do + policy = Pleroma.Config.get([:mrf_rejectnonpublic]) + on_exit(fn -> Pleroma.Config.put([:mrf_rejectnonpublic], policy) end) + + :ok + end + + describe "public message" do + test "it's allowed when address is public" do + actor = insert(:user, follower_address: "test-address") + + message = %{ + "actor" => actor.ap_id, + "to" => ["https://www.w3.org/ns/activitystreams#Public"], + "cc" => ["https://www.w3.org/ns/activitystreams#Publid"], + "type" => "Create" + } + + assert {:ok, message} = RejectNonPublic.filter(message) + end + + test "it's allowed when cc address contain public address" do + actor = insert(:user, follower_address: "test-address") + + message = %{ + "actor" => actor.ap_id, + "to" => ["https://www.w3.org/ns/activitystreams#Public"], + "cc" => ["https://www.w3.org/ns/activitystreams#Publid"], + "type" => "Create" + } + + assert {:ok, message} = RejectNonPublic.filter(message) + end + end + + describe "followers message" do + test "it's allowed when addrer of message in the follower addresses of user and it enabled in config" do + actor = insert(:user, follower_address: "test-address") + + message = %{ + "actor" => actor.ap_id, + "to" => ["test-address"], + "cc" => ["https://www.w3.org/ns/activitystreams#Publid"], + "type" => "Create" + } + + Pleroma.Config.put([:mrf_rejectnonpublic, :allow_followersonly], true) + assert {:ok, message} = RejectNonPublic.filter(message) + end + + test "it's rejected when addrer of message in the follower addresses of user and it disabled in config" do + actor = insert(:user, follower_address: "test-address") + + message = %{ + "actor" => actor.ap_id, + "to" => ["test-address"], + "cc" => ["https://www.w3.org/ns/activitystreams#Publid"], + "type" => "Create" + } + + Pleroma.Config.put([:mrf_rejectnonpublic, :allow_followersonly], false) + assert {:reject, nil} = RejectNonPublic.filter(message) + end + end + + describe "direct message" do + test "it's allows when direct messages are allow" do + actor = insert(:user) + + message = %{ + "actor" => actor.ap_id, + "to" => ["https://www.w3.org/ns/activitystreams#Publid"], + "cc" => ["https://www.w3.org/ns/activitystreams#Publid"], + "type" => "Create" + } + + Pleroma.Config.put([:mrf_rejectnonpublic, :allow_direct], true) + assert {:ok, message} = RejectNonPublic.filter(message) + end + + test "it's reject when direct messages aren't allow" do + actor = insert(:user) + + message = %{ + "actor" => actor.ap_id, + "to" => ["https://www.w3.org/ns/activitystreams#Publid~~~"], + "cc" => ["https://www.w3.org/ns/activitystreams#Publid"], + "type" => "Create" + } + + Pleroma.Config.put([:mrf_rejectnonpublic, :allow_direct], false) + assert {:reject, nil} = RejectNonPublic.filter(message) + end + end +end diff --git a/test/web/activity_pub/mrf/subchain_policy_test.exs b/test/web/activity_pub/mrf/subchain_policy_test.exs new file mode 100644 index 000000000..f7cbcad48 --- /dev/null +++ b/test/web/activity_pub/mrf/subchain_policy_test.exs @@ -0,0 +1,32 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.ActivityPub.MRF.SubchainPolicyTest do + use Pleroma.DataCase + + alias Pleroma.Web.ActivityPub.MRF.DropPolicy + alias Pleroma.Web.ActivityPub.MRF.SubchainPolicy + + @message %{ + "actor" => "https://banned.com", + "type" => "Create", + "object" => %{"content" => "hi"} + } + + test "it matches and processes subchains when the actor matches a configured target" do + Pleroma.Config.put([:mrf_subchain, :match_actor], %{ + ~r/^https:\/\/banned.com/s => [DropPolicy] + }) + + {:reject, _} = SubchainPolicy.filter(@message) + end + + test "it doesn't match and process subchains when the actor doesn't match a configured target" do + Pleroma.Config.put([:mrf_subchain, :match_actor], %{ + ~r/^https:\/\/borked.com/s => [DropPolicy] + }) + + {:ok, _message} = SubchainPolicy.filter(@message) + end +end diff --git a/test/web/activity_pub/mrf/tag_policy_test.exs b/test/web/activity_pub/mrf/tag_policy_test.exs new file mode 100644 index 000000000..4aa35311e --- /dev/null +++ b/test/web/activity_pub/mrf/tag_policy_test.exs @@ -0,0 +1,123 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Web.ActivityPub.MRF.TagPolicyTest do + use Pleroma.DataCase + import Pleroma.Factory + + alias Pleroma.Web.ActivityPub.MRF.TagPolicy + @public "https://www.w3.org/ns/activitystreams#Public" + + describe "mrf_tag:disable-any-subscription" do + test "rejects message" do + actor = insert(:user, tags: ["mrf_tag:disable-any-subscription"]) + message = %{"object" => actor.ap_id, "type" => "Follow"} + assert {:reject, nil} = TagPolicy.filter(message) + end + end + + describe "mrf_tag:disable-remote-subscription" do + test "rejects non-local follow requests" do + actor = insert(:user, tags: ["mrf_tag:disable-remote-subscription"]) + follower = insert(:user, tags: ["mrf_tag:disable-remote-subscription"], local: false) + message = %{"object" => actor.ap_id, "type" => "Follow", "actor" => follower.ap_id} + assert {:reject, nil} = TagPolicy.filter(message) + end + + test "allows non-local follow requests" do + actor = insert(:user, tags: ["mrf_tag:disable-remote-subscription"]) + follower = insert(:user, tags: ["mrf_tag:disable-remote-subscription"], local: true) + message = %{"object" => actor.ap_id, "type" => "Follow", "actor" => follower.ap_id} + assert {:ok, message} = TagPolicy.filter(message) + end + end + + describe "mrf_tag:sandbox" do + test "removes from public timelines" do + actor = insert(:user, tags: ["mrf_tag:sandbox"]) + + message = %{ + "actor" => actor.ap_id, + "type" => "Create", + "object" => %{}, + "to" => [@public, "f"], + "cc" => [@public, "d"] + } + + except_message = %{ + "actor" => actor.ap_id, + "type" => "Create", + "object" => %{"to" => ["f", actor.follower_address], "cc" => ["d"]}, + "to" => ["f", actor.follower_address], + "cc" => ["d"] + } + + assert TagPolicy.filter(message) == {:ok, except_message} + end + end + + describe "mrf_tag:force-unlisted" do + test "removes from the federated timeline" do + actor = insert(:user, tags: ["mrf_tag:force-unlisted"]) + + message = %{ + "actor" => actor.ap_id, + "type" => "Create", + "object" => %{}, + "to" => [@public, "f"], + "cc" => [actor.follower_address, "d"] + } + + except_message = %{ + "actor" => actor.ap_id, + "type" => "Create", + "object" => %{"to" => ["f", actor.follower_address], "cc" => ["d", @public]}, + "to" => ["f", actor.follower_address], + "cc" => ["d", @public] + } + + assert TagPolicy.filter(message) == {:ok, except_message} + end + end + + describe "mrf_tag:media-strip" do + test "removes attachments" do + actor = insert(:user, tags: ["mrf_tag:media-strip"]) + + message = %{ + "actor" => actor.ap_id, + "type" => "Create", + "object" => %{"attachment" => ["file1"]} + } + + except_message = %{ + "actor" => actor.ap_id, + "type" => "Create", + "object" => %{} + } + + assert TagPolicy.filter(message) == {:ok, except_message} + end + end + + describe "mrf_tag:media-force-nsfw" do + test "Mark as sensitive on presence of attachments" do + actor = insert(:user, tags: ["mrf_tag:media-force-nsfw"]) + + message = %{ + "actor" => actor.ap_id, + "type" => "Create", + "object" => %{"tag" => ["test"], "attachment" => ["file1"]} + } + + except_message = %{ + "actor" => actor.ap_id, + "type" => "Create", + "object" => %{"tag" => ["test", "nsfw"], "attachment" => ["file1"], "sensitive" => true} + } + + assert TagPolicy.filter(message) == {:ok, except_message} + end + end +end diff --git a/test/web/activity_pub/mrf/user_allowlist_policy_test.exs b/test/web/activity_pub/mrf/user_allowlist_policy_test.exs new file mode 100644 index 000000000..6519e2398 --- /dev/null +++ b/test/web/activity_pub/mrf/user_allowlist_policy_test.exs @@ -0,0 +1,36 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2019 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only +defmodule Pleroma.Web.ActivityPub.MRF.UserAllowListPolicyTest do + use Pleroma.DataCase + import Pleroma.Factory + + alias Pleroma.Web.ActivityPub.MRF.UserAllowListPolicy + + setup do + policy = Pleroma.Config.get([:mrf_user_allowlist]) || [] + on_exit(fn -> Pleroma.Config.put([:mrf_user_allowlist], policy) end) + + :ok + end + + test "pass filter if allow list is empty" do + actor = insert(:user) + message = %{"actor" => actor.ap_id} + assert UserAllowListPolicy.filter(message) == {:ok, message} + end + + test "pass filter if allow list isn't empty and user in allow list" do + actor = insert(:user) + Pleroma.Config.put([:mrf_user_allowlist, :localhost], [actor.ap_id, "test-ap-id"]) + message = %{"actor" => actor.ap_id} + assert UserAllowListPolicy.filter(message) == {:ok, message} + end + + test "rejected if allow list isn't empty and user not in allow list" do + actor = insert(:user) + Pleroma.Config.put([:mrf_user_allowlist, :localhost], ["test-ap-id"]) + message = %{"actor" => actor.ap_id} + assert UserAllowListPolicy.filter(message) == {:reject, nil} + end +end |