Merge branch 'activitypub-tombstone-fix' into 'develop'
[akkoma] / test / web / activity_pub / activity_pub_controller_test.exs
1 # Pleroma: A lightweight social networking server
2 # Copyright © 2017-2018 Pleroma Authors <https://pleroma.social/>
3 # SPDX-License-Identifier: AGPL-3.0-only
4
5 defmodule Pleroma.Web.ActivityPub.ActivityPubControllerTest do
6 use Pleroma.Web.ConnCase
7 import Pleroma.Factory
8 alias Pleroma.Web.ActivityPub.{UserView, ObjectView}
9 alias Pleroma.{Object, Repo, User}
10 alias Pleroma.Activity
11
12 setup_all do
13 Tesla.Mock.mock_global(fn env -> apply(HttpRequestMock, :request, [env]) end)
14 :ok
15 end
16
17 describe "/relay" do
18 test "with the relay active, it returns the relay user", %{conn: conn} do
19 res =
20 conn
21 |> get(activity_pub_path(conn, :relay))
22 |> json_response(200)
23
24 assert res["id"] =~ "/relay"
25 end
26
27 test "with the relay disabled, it returns 404", %{conn: conn} do
28 Pleroma.Config.put([:instance, :allow_relay], false)
29
30 conn
31 |> get(activity_pub_path(conn, :relay))
32 |> json_response(404)
33 |> assert
34
35 Pleroma.Config.put([:instance, :allow_relay], true)
36 end
37 end
38
39 describe "/users/:nickname" do
40 test "it returns a json representation of the user", %{conn: conn} do
41 user = insert(:user)
42
43 conn =
44 conn
45 |> put_req_header("accept", "application/activity+json")
46 |> get("/users/#{user.nickname}")
47
48 user = Repo.get(User, user.id)
49
50 assert json_response(conn, 200) == UserView.render("user.json", %{user: user})
51 end
52 end
53
54 describe "/object/:uuid" do
55 test "it returns a json representation of the object", %{conn: conn} do
56 note = insert(:note)
57 uuid = String.split(note.data["id"], "/") |> List.last()
58
59 conn =
60 conn
61 |> put_req_header("accept", "application/activity+json")
62 |> get("/objects/#{uuid}")
63
64 assert json_response(conn, 200) == ObjectView.render("object.json", %{object: note})
65 end
66
67 test "it returns 404 for non-public messages", %{conn: conn} do
68 note = insert(:direct_note)
69 uuid = String.split(note.data["id"], "/") |> List.last()
70
71 conn =
72 conn
73 |> put_req_header("accept", "application/activity+json")
74 |> get("/objects/#{uuid}")
75
76 assert json_response(conn, 404)
77 end
78
79 test "it returns 404 for tombstone objects", %{conn: conn} do
80 tombstone = insert(:tombstone)
81 uuid = String.split(tombstone.data["id"], "/") |> List.last()
82
83 conn =
84 conn
85 |> put_req_header("accept", "application/activity+json")
86 |> get("/objects/#{uuid}")
87
88 assert json_response(conn, 404)
89 end
90 end
91
92 describe "/inbox" do
93 test "it inserts an incoming activity into the database", %{conn: conn} do
94 data = File.read!("test/fixtures/mastodon-post-activity.json") |> Poison.decode!()
95
96 conn =
97 conn
98 |> assign(:valid_signature, true)
99 |> put_req_header("content-type", "application/activity+json")
100 |> post("/inbox", data)
101
102 assert "ok" == json_response(conn, 200)
103 :timer.sleep(500)
104 assert Activity.get_by_ap_id(data["id"])
105 end
106 end
107
108 describe "/users/:nickname/inbox" do
109 test "it inserts an incoming activity into the database", %{conn: conn} do
110 user = insert(:user)
111
112 data =
113 File.read!("test/fixtures/mastodon-post-activity.json")
114 |> Poison.decode!()
115 |> Map.put("bcc", [user.ap_id])
116
117 conn =
118 conn
119 |> assign(:valid_signature, true)
120 |> put_req_header("content-type", "application/activity+json")
121 |> post("/users/#{user.nickname}/inbox", data)
122
123 assert "ok" == json_response(conn, 200)
124 :timer.sleep(500)
125 assert Activity.get_by_ap_id(data["id"])
126 end
127
128 test "it rejects reads from other users", %{conn: conn} do
129 user = insert(:user)
130 otheruser = insert(:user)
131
132 conn =
133 conn
134 |> assign(:user, otheruser)
135 |> put_req_header("accept", "application/activity+json")
136 |> get("/users/#{user.nickname}/inbox")
137
138 assert json_response(conn, 403)
139 end
140
141 test "it returns a note activity in a collection", %{conn: conn} do
142 note_activity = insert(:direct_note_activity)
143 user = User.get_cached_by_ap_id(hd(note_activity.data["to"]))
144
145 conn =
146 conn
147 |> assign(:user, user)
148 |> put_req_header("accept", "application/activity+json")
149 |> get("/users/#{user.nickname}/inbox")
150
151 assert response(conn, 200) =~ note_activity.data["object"]["content"]
152 end
153 end
154
155 describe "/users/:nickname/outbox" do
156 test "it returns a note activity in a collection", %{conn: conn} do
157 note_activity = insert(:note_activity)
158 user = User.get_cached_by_ap_id(note_activity.data["actor"])
159
160 conn =
161 conn
162 |> put_req_header("accept", "application/activity+json")
163 |> get("/users/#{user.nickname}/outbox")
164
165 assert response(conn, 200) =~ note_activity.data["object"]["content"]
166 end
167
168 test "it returns an announce activity in a collection", %{conn: conn} do
169 announce_activity = insert(:announce_activity)
170 user = User.get_cached_by_ap_id(announce_activity.data["actor"])
171
172 conn =
173 conn
174 |> put_req_header("accept", "application/activity+json")
175 |> get("/users/#{user.nickname}/outbox")
176
177 assert response(conn, 200) =~ announce_activity.data["object"]
178 end
179
180 test "it rejects posts from other users", %{conn: conn} do
181 data = File.read!("test/fixtures/activitypub-client-post-activity.json") |> Poison.decode!()
182 user = insert(:user)
183 otheruser = insert(:user)
184
185 conn =
186 conn
187 |> assign(:user, otheruser)
188 |> put_req_header("content-type", "application/activity+json")
189 |> post("/users/#{user.nickname}/outbox", data)
190
191 assert json_response(conn, 403)
192 end
193
194 test "it inserts an incoming create activity into the database", %{conn: conn} do
195 data = File.read!("test/fixtures/activitypub-client-post-activity.json") |> Poison.decode!()
196 user = insert(:user)
197
198 conn =
199 conn
200 |> assign(:user, user)
201 |> put_req_header("content-type", "application/activity+json")
202 |> post("/users/#{user.nickname}/outbox", data)
203
204 result = json_response(conn, 201)
205 assert Activity.get_by_ap_id(result["id"])
206 end
207
208 test "it rejects an incoming activity with bogus type", %{conn: conn} do
209 data = File.read!("test/fixtures/activitypub-client-post-activity.json") |> Poison.decode!()
210 user = insert(:user)
211
212 data =
213 data
214 |> Map.put("type", "BadType")
215
216 conn =
217 conn
218 |> assign(:user, user)
219 |> put_req_header("content-type", "application/activity+json")
220 |> post("/users/#{user.nickname}/outbox", data)
221
222 assert json_response(conn, 400)
223 end
224
225 test "it erects a tombstone when receiving a delete activity", %{conn: conn} do
226 note_activity = insert(:note_activity)
227 user = User.get_cached_by_ap_id(note_activity.data["actor"])
228
229 data = %{
230 type: "Delete",
231 object: %{
232 id: note_activity.data["object"]["id"]
233 }
234 }
235
236 conn =
237 conn
238 |> assign(:user, user)
239 |> put_req_header("content-type", "application/activity+json")
240 |> post("/users/#{user.nickname}/outbox", data)
241
242 result = json_response(conn, 201)
243 assert Activity.get_by_ap_id(result["id"])
244
245 object = Object.get_by_ap_id(note_activity.data["object"]["id"])
246 assert object
247 assert object.data["type"] == "Tombstone"
248 end
249
250 test "it rejects delete activity of object from other actor", %{conn: conn} do
251 note_activity = insert(:note_activity)
252 user = insert(:user)
253
254 data = %{
255 type: "Delete",
256 object: %{
257 id: note_activity.data["object"]["id"]
258 }
259 }
260
261 conn =
262 conn
263 |> assign(:user, user)
264 |> put_req_header("content-type", "application/activity+json")
265 |> post("/users/#{user.nickname}/outbox", data)
266
267 assert json_response(conn, 400)
268 end
269 end
270
271 describe "/users/:nickname/followers" do
272 test "it returns the followers in a collection", %{conn: conn} do
273 user = insert(:user)
274 user_two = insert(:user)
275 User.follow(user, user_two)
276
277 result =
278 conn
279 |> get("/users/#{user_two.nickname}/followers")
280 |> json_response(200)
281
282 assert result["first"]["orderedItems"] == [user.ap_id]
283 end
284
285 test "it returns returns empty if the user has 'hide_network' set", %{conn: conn} do
286 user = insert(:user)
287 user_two = insert(:user, %{info: %{hide_network: true}})
288 User.follow(user, user_two)
289
290 result =
291 conn
292 |> get("/users/#{user_two.nickname}/followers")
293 |> json_response(200)
294
295 assert result["first"]["orderedItems"] == []
296 assert result["totalItems"] == 1
297 end
298
299 test "it works for more than 10 users", %{conn: conn} do
300 user = insert(:user)
301
302 Enum.each(1..15, fn _ ->
303 other_user = insert(:user)
304 User.follow(other_user, user)
305 end)
306
307 result =
308 conn
309 |> get("/users/#{user.nickname}/followers")
310 |> json_response(200)
311
312 assert length(result["first"]["orderedItems"]) == 10
313 assert result["first"]["totalItems"] == 15
314 assert result["totalItems"] == 15
315
316 result =
317 conn
318 |> get("/users/#{user.nickname}/followers?page=2")
319 |> json_response(200)
320
321 assert length(result["orderedItems"]) == 5
322 assert result["totalItems"] == 15
323 end
324 end
325
326 describe "/users/:nickname/following" do
327 test "it returns the following in a collection", %{conn: conn} do
328 user = insert(:user)
329 user_two = insert(:user)
330 User.follow(user, user_two)
331
332 result =
333 conn
334 |> get("/users/#{user.nickname}/following")
335 |> json_response(200)
336
337 assert result["first"]["orderedItems"] == [user_two.ap_id]
338 end
339
340 test "it returns returns empty if the user has 'hide_network' set", %{conn: conn} do
341 user = insert(:user, %{info: %{hide_network: true}})
342 user_two = insert(:user)
343 User.follow(user, user_two)
344
345 result =
346 conn
347 |> get("/users/#{user.nickname}/following")
348 |> json_response(200)
349
350 assert result["first"]["orderedItems"] == []
351 assert result["totalItems"] == 1
352 end
353
354 test "it works for more than 10 users", %{conn: conn} do
355 user = insert(:user)
356
357 Enum.each(1..15, fn _ ->
358 user = Repo.get(User, user.id)
359 other_user = insert(:user)
360 User.follow(user, other_user)
361 end)
362
363 result =
364 conn
365 |> get("/users/#{user.nickname}/following")
366 |> json_response(200)
367
368 assert length(result["first"]["orderedItems"]) == 10
369 assert result["first"]["totalItems"] == 15
370 assert result["totalItems"] == 15
371
372 result =
373 conn
374 |> get("/users/#{user.nickname}/following?page=2")
375 |> json_response(200)
376
377 assert length(result["orderedItems"]) == 5
378 assert result["totalItems"] == 15
379 end
380 end
381 end