ActivityPub: Send out Accept after Follow.
authorlain <lain@soykaf.club>
Sat, 17 Feb 2018 15:08:55 +0000 (16:08 +0100)
committerlain <lain@soykaf.club>
Sat, 17 Feb 2018 15:08:55 +0000 (16:08 +0100)
lib/pleroma/user.ex
lib/pleroma/web/activity_pub/activity_pub.ex
lib/pleroma/web/activity_pub/transmogrifier.ex
lib/pleroma/web/salmon/salmon.ex
lib/pleroma/web/websub/websub.ex
test/fixtures/mastodon-accept-activity.json [new file with mode: 0644]

index ddf66cee95ee4840d9823851921f362ed881e252..61bca3afd6084416937bbeb6ab39f39317a53979 100644 (file)
@@ -150,11 +150,12 @@ defmodule Pleroma.User do
 
   def follow(%User{} = follower, %User{info: info} = followed) do
     ap_followers = followed.follower_address
+
     if following?(follower, followed) or info["deactivated"] do
       {:error,
        "Could not follow user: #{followed.nickname} is already on your list."}
     else
-      if !followed.local && follower.local do
+      if !followed.local && follower.local && !ap_enabled?(followed) do
         Websub.subscribe(follower, followed)
       end
 
@@ -420,4 +421,6 @@ defmodule Pleroma.User do
     cs = User.remote_user_creation(data)
     Repo.insert(cs, on_conflict: :replace_all, conflict_target: :nickname)
   end
+
+  def ap_enabled?(%User{info: %{"ap_enabled" => ap}}), do: ap
 end
index 8e15fde4a810cf1373b92e255ceb271c1ee3103e..0c1b6cb280e01ce7631990f7ef22efd39be5d6ab 100644 (file)
@@ -49,6 +49,16 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
     end
   end
 
+  def accept(%{to: to, actor: actor, object: object} = params) do
+    local = !(params[:local] == false) # only accept false as false value
+
+    with data <- %{"to" => to, "type" => "Accept", "actor" => actor, "object" => object},
+         {:ok, activity} <- insert(data, local),
+         :ok <- maybe_federate(activity) do
+      {:ok, activity}
+    end
+  end
+
   # TODO: This is weird, maybe we shouldn't check here if we can make the activity.
   def like(%User{ap_id: ap_id} = user, %Object{data: %{"id" => _}} = object, activity_id \\ nil, local \\ true) do
     with nil <- get_existing_like(ap_id, object),
@@ -244,7 +254,11 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
   end
 
   def publish(actor, activity) do
-    remote_users = Pleroma.Web.Salmon.remote_users(activity)
+    {:ok, followers} = User.get_followers(actor)
+
+    remote_users = Pleroma.Web.Salmon.remote_users(activity) ++ followers
+    |> Enum.uniq
+
     {:ok, data} = Transmogrifier.prepare_outgoing(activity.data)
     Enum.each remote_users, fn(user) ->
       if user.info["ap_enabled"] do
index f4af3aed35b82570d30b39e813d47ded09892dd7..76f04e8a3f7b2d61f00be0df2d81e676dfd33ea4 100644 (file)
@@ -38,11 +38,11 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
     end
   end
 
-  def handle_incoming(%{"type" => "Follow", "object" => followed, "actor" => follower, "id" => id}) do
-    with %User{} = followed <- User.get_cached_by_ap_id(followed),
+  def handle_incoming(%{"type" => "Follow", "object" => followed, "actor" => follower, "id" => id} = data) 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
-      # TODO: Send an "Accept" activity.
+      ActivityPub.accept(%{to: [follower.ap_id], actor: followed.ap_id, object: data, local: true})
       User.follow(follower, followed)
       {:ok, activity}
     else
@@ -68,6 +68,13 @@ defmodule Pleroma.Web.ActivityPub.Transmogrifier do
     {:ok, data}
   end
 
+  def prepare_outgoing(%{"type" => type} = data) when type in ["Follow", "Accept"] do
+    data = data
+    |> Map.put("@context", "https://www.w3.org/ns/activitystreams")
+
+    {:ok, data}
+  end
+
   def add_mention_tags(object) do
     mentions = object["to"]
     |> Enum.map(fn (ap_id) -> User.get_cached_by_ap_id(ap_id) end)
index 81b86458258849137aea29ecc031f20157034c49..806f3c3c07066ca56de1758bc94821a4c1361eac 100644 (file)
@@ -154,8 +154,16 @@ defmodule Pleroma.Web.Salmon do
 
   defp send_to_user(_,_,_), do: nil
 
+  @supported_activities [
+    "Create",
+    "Follow",
+    "Like",
+    "Announce",
+    "Undo",
+    "Delete"
+  ]
   def publish(user, activity, poster \\ &@httpoison.post/4)
-  def publish(%{info: %{"keys" => keys}} = user, activity, poster) do
+  def publish(%{info: %{"keys" => keys}} = user, %{data: %{"type" => type}} = activity, poster) when type in @supported_activities do
     feed = ActivityRepresenter.to_simple_form(activity, user, true)
     |> ActivityRepresenter.wrap_with_entry
     |> :xmerl.export_simple(:xmerl_xml)
index db1577a9373a71044263266a0b9443254dad2d94..47a01849df74bc8b5bec01ff4b66954f9e8cb752 100644 (file)
@@ -38,7 +38,15 @@ defmodule Pleroma.Web.Websub do
     end
   end
 
-  def publish(topic, user, activity) do
+  @supported_activities [
+    "Create",
+    "Follow",
+    "Like",
+    "Announce",
+    "Undo",
+    "Delete"
+  ]
+  def publish(topic, user, %{data: %{"type" => type}} = activity) when type in @supported_activities do
     # TODO: Only send to still valid subscriptions.
     query = from sub in WebsubServerSubscription,
     where: sub.topic == ^topic and sub.state == "active"
@@ -58,6 +66,7 @@ defmodule Pleroma.Web.Websub do
       Pleroma.Web.Federator.enqueue(:publish_single_websub, data)
     end)
   end
+  def publish(_,_,_), do: ""
 
   def sign(secret, doc) do
     :crypto.hmac(:sha, secret, to_string(doc)) |> Base.encode16 |> String.downcase
diff --git a/test/fixtures/mastodon-accept-activity.json b/test/fixtures/mastodon-accept-activity.json
new file mode 100644 (file)
index 0000000..b661ed6
--- /dev/null
@@ -0,0 +1,34 @@
+{
+  "type": "Accept",
+  "signature": {
+    "type": "RsaSignature2017",
+    "signatureValue": "rBzK4Kqhd4g7HDS8WE5oRbWQb2R+HF/6awbUuMWhgru/xCODT0SJWSri0qWqEO4fPcpoUyz2d25cw6o+iy9wiozQb3hQNnu69AR+H5Mytc06+g10KCHexbGhbAEAw/7IzmeXELHUbaqeduaDIbdt1zw4RkwLXdqgQcGXTJ6ND1wM3WMHXQCK1m0flasIXFoBxpliPAGiElV8s0+Ltuh562GvflG3kB3WO+j+NaR0ZfG5G9N88xMj9UQlCKit5gpAE5p6syUsCU2WGBHywTumv73i3OVTIFfq+P9AdMsRuzw1r7zoKEsthW4aOzLQDi01ZjvdBz8zH6JnjDU7SMN/Ig==",
+    "creator": "http://mastodon.example.org/users/admin#main-key",
+    "created": "2018-02-17T14:36:41Z"
+  },
+  "object": {
+    "type": "Follow",
+    "object": "http://mastodon.example.org/users/admin",
+    "id": "http://localtesting.pleroma.lol/users/lain#follows/4",
+    "actor": "http://localtesting.pleroma.lol/users/lain"
+  },
+  "nickname": "lain",
+  "id": "http://mastodon.example.org/users/admin#accepts/follows/4",
+  "actor": "http://mastodon.example.org/users/admin",
+  "@context": [
+    "https://www.w3.org/ns/activitystreams",
+    "https://w3id.org/security/v1",
+    {
+      "toot": "http://joinmastodon.org/ns#",
+      "sensitive": "as:sensitive",
+      "ostatus": "http://ostatus.org#",
+      "movedTo": "as:movedTo",
+      "manuallyApprovesFollowers": "as:manuallyApprovesFollowers",
+      "inReplyToAtomUri": "ostatus:inReplyToAtomUri",
+      "conversation": "ostatus:conversation",
+      "atomUri": "ostatus:atomUri",
+      "Hashtag": "as:Hashtag",
+      "Emoji": "toot:Emoji"
+    }
+  ]
+}
\ No newline at end of file