CommonAPI: Refactor visibility, forbid public to private replies.
authorlain <lain@soykaf.club>
Wed, 15 May 2019 14:30:08 +0000 (16:30 +0200)
committerlain <lain@soykaf.club>
Wed, 15 May 2019 14:30:08 +0000 (16:30 +0200)
lib/pleroma/web/activity_pub/visibility.ex
lib/pleroma/web/common_api/common_api.ex
lib/pleroma/web/mastodon_api/views/status_view.ex
lib/pleroma/web/twitter_api/views/activity_view.ex
test/web/activity_pub/visibilty_test.exs
test/web/common_api/common_api_test.exs

index 6dee61dd61b02bf9dc337d86becb7faa807b711f..b38ee0442db93daf83f47c7be7cd2d9f7900335a 100644 (file)
@@ -58,4 +58,28 @@ defmodule Pleroma.Web.ActivityPub.Visibility do
         visible_for_user?(tail, user)
     end
   end
+
+  def get_visibility(object) do
+    public = "https://www.w3.org/ns/activitystreams#Public"
+    to = object.data["to"] || []
+    cc = object.data["cc"] || []
+
+    cond do
+      public in to ->
+        "public"
+
+      public in cc ->
+        "unlisted"
+
+      # this should use the sql for the object's activity
+      Enum.any?(to, &String.contains?(&1, "/followers")) ->
+        "private"
+
+      length(cc) > 0 ->
+        "private"
+
+      true ->
+        "direct"
+    end
+  end
 end
index b53869c7582899eebfbad8bc188a4f2bcb47a730..c31e56d4c2dc822fa04474c78400d1ac0205e9ec 100644 (file)
@@ -126,22 +126,30 @@ defmodule Pleroma.Web.CommonAPI do
         "public"
 
       in_reply_to ->
-        # XXX: these heuristics should be moved out of MastodonAPI.
-        with %Object{} = object <- Object.normalize(in_reply_to) do
-          Pleroma.Web.MastodonAPI.StatusView.get_visibility(object)
-        end
+        get_replied_to_visibility(in_reply_to)
     end
   end
 
   def get_visibility(_), do: "public"
 
+  def get_replied_to_visibility(nil), do: nil
+
+  def get_replied_to_visibility(activity) do
+    with %Object{} = object <- Object.normalize(activity) do
+      Pleroma.Web.ActivityPub.Visibility.get_visibility(object)
+    end
+  end
+
   def post(user, %{"status" => status} = data) do
-    visibility = get_visibility(data)
     limit = Pleroma.Config.get([:instance, :limit])
 
     with status <- String.trim(status),
          attachments <- attachments_from_ids(data),
+         visibility <- get_visibility(data),
          in_reply_to <- get_replied_to_activity(data["in_reply_to_status_id"]),
+         in_reply_to_visibility <- get_replied_to_visibility(in_reply_to),
+         {_, false} <-
+           {:private_to_public, in_reply_to_visibility == "direct" && visibility != "direct"},
          {content_html, mentions, tags} <-
            make_content_html(
              status,
@@ -185,6 +193,8 @@ defmodule Pleroma.Web.CommonAPI do
         )
 
       res
+    else
+      e -> {:error, e}
     end
   end
 
index bd23729441c846bb17254e2c8fc2fd1bd97cd936..c93d915e5aa851e8fa27084fec1e682a58137d9d 100644 (file)
@@ -16,6 +16,8 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do
   alias Pleroma.Web.MastodonAPI.StatusView
   alias Pleroma.Web.MediaProxy
 
+  import Pleroma.Web.ActivityPub.Visibility, only: [get_visibility: 1]
+
   # TODO: Add cached version.
   defp get_replied_to_activities(activities) do
     activities
@@ -340,30 +342,6 @@ defmodule Pleroma.Web.MastodonAPI.StatusView do
     end
   end
 
-  def get_visibility(object) do
-    public = "https://www.w3.org/ns/activitystreams#Public"
-    to = object.data["to"] || []
-    cc = object.data["cc"] || []
-
-    cond do
-      public in to ->
-        "public"
-
-      public in cc ->
-        "unlisted"
-
-      # this should use the sql for the object's activity
-      Enum.any?(to, &String.contains?(&1, "/followers")) ->
-        "private"
-
-      length(cc) > 0 ->
-        "private"
-
-      true ->
-        "direct"
-    end
-  end
-
   def render_content(%{data: %{"type" => "Video"}} = object) do
     with name when not is_nil(name) and name != "" <- object.data["name"] do
       "<p><a href=\"#{object.data["id"]}\">#{name}</a></p>#{object.data["content"]}"
index d084ad7344778199a0968e374573f7c76da857e0..44bcafe0e2e35f98d5017ae6706a10abccfa9082 100644 (file)
@@ -310,7 +310,7 @@ defmodule Pleroma.Web.TwitterAPI.ActivityView do
       "tags" => tags,
       "activity_type" => "post",
       "possibly_sensitive" => possibly_sensitive,
-      "visibility" => StatusView.get_visibility(object),
+      "visibility" => Pleroma.Web.ActivityPub.Visibility.get_visibility(object),
       "summary" => summary,
       "summary_html" => summary |> Formatter.emojify(object.data["emoji"]),
       "card" => card,
index 24b96c4aa7429925694ea5e0bda3b86dc810dc81..9c03c8be2ecf0c43ae89a0856282bda591cfe571 100644 (file)
@@ -95,4 +95,16 @@ defmodule Pleroma.Web.ActivityPub.VisibilityTest do
     refute Visibility.visible_for_user?(private, unrelated)
     refute Visibility.visible_for_user?(direct, unrelated)
   end
+
+  test "get_visibility", %{
+    public: public,
+    private: private,
+    direct: direct,
+    unlisted: unlisted
+  } do
+    assert Visibility.get_visibility(public) == "public"
+    assert Visibility.get_visibility(private) == "private"
+    assert Visibility.get_visibility(direct) == "direct"
+    assert Visibility.get_visibility(unlisted) == "unlisted"
+  end
 end
index a5b07c4469f89d8fc2938bf7829bc2428a3b19f2..8d4f401eec8a0303cac3c8d17243af9590589ade 100644 (file)
@@ -87,6 +87,28 @@ defmodule Pleroma.Web.CommonAPITest do
 
       assert object.data["content"] == "<p><b>2hu</b></p>alert('xss')"
     end
+
+    test "it does not allow replies to direct messages that are not direct messages themselves" do
+      user = insert(:user)
+
+      {:ok, activity} = CommonAPI.post(user, %{"status" => "suya..", "visibility" => "direct"})
+
+      assert {:ok, _} =
+               CommonAPI.post(user, %{
+                 "status" => "suya..",
+                 "visibility" => "direct",
+                 "in_reply_to_status_id" => activity.id
+               })
+
+      Enum.each(["public", "private", "unlisted"], fn visibility ->
+        assert {:error, {:private_to_public, _}} =
+                 CommonAPI.post(user, %{
+                   "status" => "suya..",
+                   "visibility" => visibility,
+                   "in_reply_to_status_id" => activity.id
+                 })
+      end)
+    end
   end
 
   describe "reactions" do