Resolve follow activity from accept/reject without ID (#328)
[akkoma] / test / pleroma / web / activity_pub / transmogrifier / follow_handling_test.exs
1 # Pleroma: A lightweight social networking server
2 # Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
3 # SPDX-License-Identifier: AGPL-3.0-only
4
5 defmodule Pleroma.Web.ActivityPub.Transmogrifier.FollowHandlingTest do
6 use Pleroma.DataCase
7 alias Pleroma.Activity
8 alias Pleroma.Notification
9 alias Pleroma.Repo
10 alias Pleroma.User
11 alias Pleroma.Web.ActivityPub.Transmogrifier
12 alias Pleroma.Web.ActivityPub.Utils
13
14 import Pleroma.Factory
15 import Ecto.Query
16 import Mock
17
18 setup_all do
19 Tesla.Mock.mock_global(fn env -> apply(HttpRequestMock, :request, [env]) end)
20 :ok
21 end
22
23 describe "handle_incoming" do
24 setup do: clear_config([:user, :deny_follow_blocked])
25
26 test "it works for osada follow request" do
27 user = insert(:user)
28
29 data =
30 File.read!("test/fixtures/osada-follow-activity.json")
31 |> Jason.decode!()
32 |> Map.put("object", user.ap_id)
33
34 {:ok, %Activity{data: data, local: false} = activity} = Transmogrifier.handle_incoming(data)
35
36 assert data["actor"] == "https://apfed.club/channel/indio"
37 assert data["type"] == "Follow"
38 assert data["id"] == "https://apfed.club/follow/9"
39
40 activity = Repo.get(Activity, activity.id)
41 assert activity.data["state"] == "accept"
42 assert User.following?(User.get_cached_by_ap_id(data["actor"]), user)
43 end
44
45 test "it works for incoming follow requests" do
46 user = insert(:user)
47
48 data =
49 File.read!("test/fixtures/mastodon-follow-activity.json")
50 |> Jason.decode!()
51 |> Map.put("object", user.ap_id)
52
53 {:ok, %Activity{data: data, local: false} = activity} = Transmogrifier.handle_incoming(data)
54
55 assert data["actor"] == "http://mastodon.example.org/users/admin"
56 assert data["type"] == "Follow"
57 assert data["id"] == "http://mastodon.example.org/users/admin#follows/2"
58
59 activity = Repo.get(Activity, activity.id)
60 assert activity.data["state"] == "accept"
61 assert User.following?(User.get_cached_by_ap_id(data["actor"]), user)
62
63 [notification] = Notification.for_user(user)
64 assert notification.type == "follow"
65 end
66
67 test "with locked accounts, it does create a Follow, but not an Accept" do
68 user = insert(:user, is_locked: true)
69
70 data =
71 File.read!("test/fixtures/mastodon-follow-activity.json")
72 |> Jason.decode!()
73 |> Map.put("object", user.ap_id)
74
75 {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
76
77 assert data["state"] == "pending"
78
79 refute User.following?(User.get_cached_by_ap_id(data["actor"]), user)
80
81 accepts =
82 from(
83 a in Activity,
84 where: fragment("?->>'type' = ?", a.data, "Accept")
85 )
86 |> Repo.all()
87
88 assert Enum.empty?(accepts)
89
90 [notification] = Notification.for_user(user)
91 assert notification.type == "follow_request"
92 end
93
94 test "it works for follow requests when you are already followed, creating a new accept activity" do
95 # This is important because the remote might have the wrong idea about the
96 # current follow status. This can lead to instance A thinking that x@A is
97 # followed by y@B, but B thinks they are not. In this case, the follow can
98 # never go through again because it will never get an Accept.
99 user = insert(:user)
100
101 data =
102 File.read!("test/fixtures/mastodon-follow-activity.json")
103 |> Jason.decode!()
104 |> Map.put("object", user.ap_id)
105
106 {:ok, %Activity{local: false}} = Transmogrifier.handle_incoming(data)
107
108 accepts =
109 from(
110 a in Activity,
111 where: fragment("?->>'type' = ?", a.data, "Accept")
112 )
113 |> Repo.all()
114
115 assert length(accepts) == 1
116
117 data =
118 File.read!("test/fixtures/mastodon-follow-activity.json")
119 |> Jason.decode!()
120 |> Map.put("id", String.replace(data["id"], "2", "3"))
121 |> Map.put("object", user.ap_id)
122
123 {:ok, %Activity{local: false}} = Transmogrifier.handle_incoming(data)
124
125 accepts =
126 from(
127 a in Activity,
128 where: fragment("?->>'type' = ?", a.data, "Accept")
129 )
130 |> Repo.all()
131
132 assert length(accepts) == 2
133 end
134
135 test "it rejects incoming follow requests from blocked users when deny_follow_blocked is enabled" do
136 clear_config([:user, :deny_follow_blocked], true)
137
138 user = insert(:user)
139 {:ok, target} = User.get_or_fetch("http://mastodon.example.org/users/admin")
140
141 {:ok, _user_relationship} = User.block(user, target)
142
143 data =
144 File.read!("test/fixtures/mastodon-follow-activity.json")
145 |> Jason.decode!()
146 |> Map.put("object", user.ap_id)
147
148 {:ok, %Activity{data: %{"id" => id}}} = Transmogrifier.handle_incoming(data)
149
150 %Activity{} = activity = Activity.get_by_ap_id(id)
151
152 assert activity.data["state"] == "reject"
153 end
154
155 test "it rejects incoming follow requests if the following errors for some reason" do
156 user = insert(:user)
157
158 data =
159 File.read!("test/fixtures/mastodon-follow-activity.json")
160 |> Jason.decode!()
161 |> Map.put("object", user.ap_id)
162
163 with_mock Pleroma.User, [:passthrough], follow: fn _, _, _ -> {:error, :testing} end do
164 {:ok, %Activity{data: %{"id" => id}}} = Transmogrifier.handle_incoming(data)
165
166 %Activity{} = activity = Activity.get_by_ap_id(id)
167
168 assert activity.data["state"] == "reject"
169 end
170 end
171
172 test "it works for incoming follow requests from hubzilla" do
173 user = insert(:user)
174
175 data =
176 File.read!("test/fixtures/hubzilla-follow-activity.json")
177 |> Jason.decode!()
178 |> Map.put("object", user.ap_id)
179 |> Utils.normalize_params()
180
181 {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
182
183 assert data["actor"] == "https://hubzilla.example.org/channel/kaniini"
184 assert data["type"] == "Follow"
185 assert data["id"] == "https://hubzilla.example.org/channel/kaniini#follows/2"
186 assert User.following?(User.get_cached_by_ap_id(data["actor"]), user)
187 end
188
189 test "it works for incoming follows to locked account" do
190 pending_follower = insert(:user, ap_id: "http://mastodon.example.org/users/admin")
191 user = insert(:user, is_locked: true)
192
193 data =
194 File.read!("test/fixtures/mastodon-follow-activity.json")
195 |> Jason.decode!()
196 |> Map.put("object", user.ap_id)
197
198 {:ok, %Activity{data: data, local: false}} = Transmogrifier.handle_incoming(data)
199
200 assert data["type"] == "Follow"
201 assert data["object"] == user.ap_id
202 assert data["state"] == "pending"
203 assert data["actor"] == "http://mastodon.example.org/users/admin"
204
205 assert [^pending_follower] = User.get_follow_requests(user)
206 end
207 end
208 end