c54402e52c5ee89a8541d307e063c55f6ebe8979
[akkoma] / test / pleroma / web / admin_api / controllers / admin_api_controller_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.AdminAPI.AdminAPIControllerTest do
6 use Pleroma.Web.ConnCase
7 use Oban.Testing, repo: Pleroma.Repo
8
9 import ExUnit.CaptureLog
10 import Pleroma.Factory
11 import Swoosh.TestAssertions
12
13 alias Pleroma.Activity
14 alias Pleroma.MFA
15 alias Pleroma.ModerationLog
16 alias Pleroma.Repo
17 alias Pleroma.Tests.ObanHelpers
18 alias Pleroma.User
19 alias Pleroma.Web.CommonAPI
20
21 setup_all do
22 Tesla.Mock.mock_global(fn env -> apply(HttpRequestMock, :request, [env]) end)
23
24 :ok
25 end
26
27 setup do
28 admin = insert(:user, is_admin: true)
29 token = insert(:oauth_admin_token, user: admin)
30
31 conn =
32 build_conn()
33 |> assign(:user, admin)
34 |> assign(:token, token)
35
36 {:ok, %{admin: admin, token: token, conn: conn}}
37 end
38
39 test "with valid `admin_token` query parameter, skips OAuth scopes check" do
40 clear_config([:admin_token], "password123")
41
42 user = insert(:user)
43
44 conn = get(build_conn(), "/api/pleroma/admin/users/#{user.nickname}?admin_token=password123")
45
46 assert json_response(conn, 200)
47 end
48
49 describe "with [:auth, :enforce_oauth_admin_scope_usage]," do
50 setup do: clear_config([:auth, :enforce_oauth_admin_scope_usage], true)
51
52 test "GET /api/pleroma/admin/users/:nickname requires admin:read:accounts or broader scope",
53 %{admin: admin} do
54 user = insert(:user)
55 url = "/api/pleroma/admin/users/#{user.nickname}"
56
57 good_token1 = insert(:oauth_token, user: admin, scopes: ["admin"])
58 good_token2 = insert(:oauth_token, user: admin, scopes: ["admin:read"])
59 good_token3 = insert(:oauth_token, user: admin, scopes: ["admin:read:accounts"])
60
61 bad_token1 = insert(:oauth_token, user: admin, scopes: ["read:accounts"])
62 bad_token2 = insert(:oauth_token, user: admin, scopes: ["admin:read:accounts:partial"])
63 bad_token3 = nil
64
65 for good_token <- [good_token1, good_token2, good_token3] do
66 conn =
67 build_conn()
68 |> assign(:user, admin)
69 |> assign(:token, good_token)
70 |> get(url)
71
72 assert json_response(conn, 200)
73 end
74
75 for good_token <- [good_token1, good_token2, good_token3] do
76 conn =
77 build_conn()
78 |> assign(:user, nil)
79 |> assign(:token, good_token)
80 |> get(url)
81
82 assert json_response(conn, :forbidden)
83 end
84
85 for bad_token <- [bad_token1, bad_token2, bad_token3] do
86 conn =
87 build_conn()
88 |> assign(:user, admin)
89 |> assign(:token, bad_token)
90 |> get(url)
91
92 assert json_response(conn, :forbidden)
93 end
94 end
95 end
96
97 describe "unless [:auth, :enforce_oauth_admin_scope_usage]," do
98 setup do: clear_config([:auth, :enforce_oauth_admin_scope_usage], false)
99
100 test "GET /api/pleroma/admin/users/:nickname requires " <>
101 "read:accounts or admin:read:accounts or broader scope",
102 %{admin: admin} do
103 user = insert(:user)
104 url = "/api/pleroma/admin/users/#{user.nickname}"
105
106 good_token1 = insert(:oauth_token, user: admin, scopes: ["admin"])
107 good_token2 = insert(:oauth_token, user: admin, scopes: ["admin:read"])
108 good_token3 = insert(:oauth_token, user: admin, scopes: ["admin:read:accounts"])
109 good_token4 = insert(:oauth_token, user: admin, scopes: ["read:accounts"])
110 good_token5 = insert(:oauth_token, user: admin, scopes: ["read"])
111
112 good_tokens = [good_token1, good_token2, good_token3, good_token4, good_token5]
113
114 bad_token1 = insert(:oauth_token, user: admin, scopes: ["read:accounts:partial"])
115 bad_token2 = insert(:oauth_token, user: admin, scopes: ["admin:read:accounts:partial"])
116 bad_token3 = nil
117
118 for good_token <- good_tokens do
119 conn =
120 build_conn()
121 |> assign(:user, admin)
122 |> assign(:token, good_token)
123 |> get(url)
124
125 assert json_response(conn, 200)
126 end
127
128 for good_token <- good_tokens do
129 conn =
130 build_conn()
131 |> assign(:user, nil)
132 |> assign(:token, good_token)
133 |> get(url)
134
135 assert json_response(conn, :forbidden)
136 end
137
138 for bad_token <- [bad_token1, bad_token2, bad_token3] do
139 conn =
140 build_conn()
141 |> assign(:user, admin)
142 |> assign(:token, bad_token)
143 |> get(url)
144
145 assert json_response(conn, :forbidden)
146 end
147 end
148 end
149
150 describe "PUT /api/pleroma/admin/users/tag" do
151 setup %{conn: conn} do
152 user1 = insert(:user, %{tags: ["x"]})
153 user2 = insert(:user, %{tags: ["y"]})
154 user3 = insert(:user, %{tags: ["unchanged"]})
155
156 conn =
157 conn
158 |> put_req_header("accept", "application/json")
159 |> put(
160 "/api/pleroma/admin/users/tag?nicknames[]=#{user1.nickname}&nicknames[]=" <>
161 "#{user2.nickname}&tags[]=foo&tags[]=bar"
162 )
163
164 %{conn: conn, user1: user1, user2: user2, user3: user3}
165 end
166
167 test "it appends specified tags to users with specified nicknames", %{
168 conn: conn,
169 admin: admin,
170 user1: user1,
171 user2: user2
172 } do
173 assert empty_json_response(conn)
174 assert User.get_cached_by_id(user1.id).tags == ["x", "foo", "bar"]
175 assert User.get_cached_by_id(user2.id).tags == ["y", "foo", "bar"]
176
177 log_entry = Repo.one(ModerationLog)
178
179 users =
180 [user1.nickname, user2.nickname]
181 |> Enum.map(&"@#{&1}")
182 |> Enum.join(", ")
183
184 tags = ["foo", "bar"] |> Enum.join(", ")
185
186 assert ModerationLog.get_log_entry_message(log_entry) ==
187 "@#{admin.nickname} added tags: #{tags} to users: #{users}"
188 end
189
190 test "it does not modify tags of not specified users", %{conn: conn, user3: user3} do
191 assert empty_json_response(conn)
192 assert User.get_cached_by_id(user3.id).tags == ["unchanged"]
193 end
194 end
195
196 describe "DELETE /api/pleroma/admin/users/tag" do
197 setup %{conn: conn} do
198 user1 = insert(:user, %{tags: ["x"]})
199 user2 = insert(:user, %{tags: ["y", "z"]})
200 user3 = insert(:user, %{tags: ["unchanged"]})
201
202 conn =
203 conn
204 |> put_req_header("accept", "application/json")
205 |> delete(
206 "/api/pleroma/admin/users/tag?nicknames[]=#{user1.nickname}&nicknames[]=" <>
207 "#{user2.nickname}&tags[]=x&tags[]=z"
208 )
209
210 %{conn: conn, user1: user1, user2: user2, user3: user3}
211 end
212
213 test "it removes specified tags from users with specified nicknames", %{
214 conn: conn,
215 admin: admin,
216 user1: user1,
217 user2: user2
218 } do
219 assert empty_json_response(conn)
220 assert User.get_cached_by_id(user1.id).tags == []
221 assert User.get_cached_by_id(user2.id).tags == ["y"]
222
223 log_entry = Repo.one(ModerationLog)
224
225 users =
226 [user1.nickname, user2.nickname]
227 |> Enum.map(&"@#{&1}")
228 |> Enum.join(", ")
229
230 tags = ["x", "z"] |> Enum.join(", ")
231
232 assert ModerationLog.get_log_entry_message(log_entry) ==
233 "@#{admin.nickname} removed tags: #{tags} from users: #{users}"
234 end
235
236 test "it does not modify tags of not specified users", %{conn: conn, user3: user3} do
237 assert empty_json_response(conn)
238 assert User.get_cached_by_id(user3.id).tags == ["unchanged"]
239 end
240 end
241
242 describe "/api/pleroma/admin/users/:nickname/permission_group" do
243 test "GET is giving user_info", %{admin: admin, conn: conn} do
244 conn =
245 conn
246 |> put_req_header("accept", "application/json")
247 |> get("/api/pleroma/admin/users/#{admin.nickname}/permission_group/")
248
249 assert json_response(conn, 200) == %{
250 "is_admin" => true,
251 "is_moderator" => false
252 }
253 end
254
255 test "/:right POST, can add to a permission group", %{admin: admin, conn: conn} do
256 user = insert(:user)
257
258 conn =
259 conn
260 |> put_req_header("accept", "application/json")
261 |> post("/api/pleroma/admin/users/#{user.nickname}/permission_group/admin")
262
263 assert json_response(conn, 200) == %{
264 "is_admin" => true
265 }
266
267 log_entry = Repo.one(ModerationLog)
268
269 assert ModerationLog.get_log_entry_message(log_entry) ==
270 "@#{admin.nickname} made @#{user.nickname} admin"
271 end
272
273 test "/:right POST, can add to a permission group (multiple)", %{admin: admin, conn: conn} do
274 user_one = insert(:user)
275 user_two = insert(:user)
276
277 conn =
278 conn
279 |> put_req_header("accept", "application/json")
280 |> post("/api/pleroma/admin/users/permission_group/admin", %{
281 nicknames: [user_one.nickname, user_two.nickname]
282 })
283
284 assert json_response(conn, 200) == %{"is_admin" => true}
285
286 log_entry = Repo.one(ModerationLog)
287
288 assert ModerationLog.get_log_entry_message(log_entry) ==
289 "@#{admin.nickname} made @#{user_one.nickname}, @#{user_two.nickname} admin"
290 end
291
292 test "/:right DELETE, can remove from a permission group", %{admin: admin, conn: conn} do
293 user = insert(:user, is_admin: true)
294
295 conn =
296 conn
297 |> put_req_header("accept", "application/json")
298 |> delete("/api/pleroma/admin/users/#{user.nickname}/permission_group/admin")
299
300 assert json_response(conn, 200) == %{"is_admin" => false}
301
302 log_entry = Repo.one(ModerationLog)
303
304 assert ModerationLog.get_log_entry_message(log_entry) ==
305 "@#{admin.nickname} revoked admin role from @#{user.nickname}"
306 end
307
308 test "/:right DELETE, can remove from a permission group (multiple)", %{
309 admin: admin,
310 conn: conn
311 } do
312 user_one = insert(:user, is_admin: true)
313 user_two = insert(:user, is_admin: true)
314
315 conn =
316 conn
317 |> put_req_header("accept", "application/json")
318 |> delete("/api/pleroma/admin/users/permission_group/admin", %{
319 nicknames: [user_one.nickname, user_two.nickname]
320 })
321
322 assert json_response(conn, 200) == %{"is_admin" => false}
323
324 log_entry = Repo.one(ModerationLog)
325
326 assert ModerationLog.get_log_entry_message(log_entry) ==
327 "@#{admin.nickname} revoked admin role from @#{user_one.nickname}, @#{
328 user_two.nickname
329 }"
330 end
331 end
332
333 test "/api/pleroma/admin/users/:nickname/password_reset", %{conn: conn} do
334 user = insert(:user)
335
336 conn =
337 conn
338 |> put_req_header("accept", "application/json")
339 |> get("/api/pleroma/admin/users/#{user.nickname}/password_reset")
340
341 resp = json_response(conn, 200)
342
343 assert Regex.match?(~r/(http:\/\/|https:\/\/)/, resp["link"])
344 end
345
346 describe "PUT disable_mfa" do
347 test "returns 200 and disable 2fa", %{conn: conn} do
348 user =
349 insert(:user,
350 multi_factor_authentication_settings: %MFA.Settings{
351 enabled: true,
352 totp: %MFA.Settings.TOTP{secret: "otp_secret", confirmed: true}
353 }
354 )
355
356 response =
357 conn
358 |> put("/api/pleroma/admin/users/disable_mfa", %{nickname: user.nickname})
359 |> json_response(200)
360
361 assert response == user.nickname
362 mfa_settings = refresh_record(user).multi_factor_authentication_settings
363
364 refute mfa_settings.enabled
365 refute mfa_settings.totp.confirmed
366 end
367
368 test "returns 404 if user not found", %{conn: conn} do
369 response =
370 conn
371 |> put("/api/pleroma/admin/users/disable_mfa", %{nickname: "nickname"})
372 |> json_response(404)
373
374 assert response == %{"error" => "Not found"}
375 end
376 end
377
378 describe "GET /api/pleroma/admin/restart" do
379 setup do: clear_config(:configurable_from_database, true)
380
381 test "pleroma restarts", %{conn: conn} do
382 capture_log(fn ->
383 assert conn |> get("/api/pleroma/admin/restart") |> json_response(200) == %{}
384 end) =~ "pleroma restarted"
385
386 refute Restarter.Pleroma.need_reboot?()
387 end
388 end
389
390 test "need_reboot flag", %{conn: conn} do
391 assert conn
392 |> get("/api/pleroma/admin/need_reboot")
393 |> json_response(200) == %{"need_reboot" => false}
394
395 Restarter.Pleroma.need_reboot()
396
397 assert conn
398 |> get("/api/pleroma/admin/need_reboot")
399 |> json_response(200) == %{"need_reboot" => true}
400
401 on_exit(fn -> Restarter.Pleroma.refresh() end)
402 end
403
404 describe "GET /api/pleroma/admin/users/:nickname/statuses" do
405 setup do
406 user = insert(:user)
407
408 date1 = (DateTime.to_unix(DateTime.utc_now()) + 2000) |> DateTime.from_unix!()
409 date2 = (DateTime.to_unix(DateTime.utc_now()) + 1000) |> DateTime.from_unix!()
410 date3 = (DateTime.to_unix(DateTime.utc_now()) + 3000) |> DateTime.from_unix!()
411
412 insert(:note_activity, user: user, published: date1)
413 insert(:note_activity, user: user, published: date2)
414 insert(:note_activity, user: user, published: date3)
415
416 %{user: user}
417 end
418
419 test "renders user's statuses", %{conn: conn, user: user} do
420 conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}/statuses")
421
422 assert json_response(conn, 200) |> length() == 3
423 end
424
425 test "renders user's statuses with pagination", %{conn: conn, user: user} do
426 conn1 = get(conn, "/api/pleroma/admin/users/#{user.nickname}/statuses?page_size=1&page=1")
427
428 response1 = json_response(conn1, 200)
429
430 assert response1 |> length() == 1
431
432 conn2 = get(conn, "/api/pleroma/admin/users/#{user.nickname}/statuses?page_size=1&page=2")
433
434 response2 = json_response(conn2, 200)
435
436 assert response2 |> length() == 1
437
438 refute response1 == response2
439 end
440
441 test "doesn't return private statuses by default", %{conn: conn, user: user} do
442 {:ok, _private_status} = CommonAPI.post(user, %{status: "private", visibility: "private"})
443
444 {:ok, _public_status} = CommonAPI.post(user, %{status: "public", visibility: "public"})
445
446 conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}/statuses")
447
448 assert json_response(conn, 200) |> length() == 4
449 end
450
451 test "returns private statuses with godmode on", %{conn: conn, user: user} do
452 {:ok, _private_status} = CommonAPI.post(user, %{status: "private", visibility: "private"})
453
454 {:ok, _public_status} = CommonAPI.post(user, %{status: "public", visibility: "public"})
455
456 conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}/statuses?godmode=true")
457
458 assert json_response(conn, 200) |> length() == 5
459 end
460
461 test "excludes reblogs by default", %{conn: conn, user: user} do
462 other_user = insert(:user)
463 {:ok, activity} = CommonAPI.post(user, %{status: "."})
464 {:ok, %Activity{}} = CommonAPI.repeat(activity.id, other_user)
465
466 conn_res = get(conn, "/api/pleroma/admin/users/#{other_user.nickname}/statuses")
467 assert json_response(conn_res, 200) |> length() == 0
468
469 conn_res =
470 get(conn, "/api/pleroma/admin/users/#{other_user.nickname}/statuses?with_reblogs=true")
471
472 assert json_response(conn_res, 200) |> length() == 1
473 end
474 end
475
476 describe "GET /api/pleroma/admin/users/:nickname/chats" do
477 setup do
478 user = insert(:user)
479 recipients = insert_list(3, :user)
480
481 Enum.each(recipients, fn recipient ->
482 CommonAPI.post_chat_message(user, recipient, "yo")
483 end)
484
485 %{user: user}
486 end
487
488 test "renders user's chats", %{conn: conn, user: user} do
489 conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}/chats")
490
491 assert json_response(conn, 200) |> length() == 3
492 end
493 end
494
495 describe "GET /api/pleroma/admin/users/:nickname/chats unauthorized" do
496 setup do
497 user = insert(:user)
498 recipient = insert(:user)
499 CommonAPI.post_chat_message(user, recipient, "yo")
500 %{conn: conn} = oauth_access(["read:chats"])
501 %{conn: conn, user: user}
502 end
503
504 test "returns 403", %{conn: conn, user: user} do
505 conn
506 |> get("/api/pleroma/admin/users/#{user.nickname}/chats")
507 |> json_response(403)
508 end
509 end
510
511 describe "GET /api/pleroma/admin/users/:nickname/chats unauthenticated" do
512 setup do
513 user = insert(:user)
514 recipient = insert(:user)
515 CommonAPI.post_chat_message(user, recipient, "yo")
516 %{conn: build_conn(), user: user}
517 end
518
519 test "returns 403", %{conn: conn, user: user} do
520 conn
521 |> get("/api/pleroma/admin/users/#{user.nickname}/chats")
522 |> json_response(403)
523 end
524 end
525
526 describe "GET /api/pleroma/admin/moderation_log" do
527 setup do
528 moderator = insert(:user, is_moderator: true)
529
530 %{moderator: moderator}
531 end
532
533 test "returns the log", %{conn: conn, admin: admin} do
534 Repo.insert(%ModerationLog{
535 data: %{
536 actor: %{
537 "id" => admin.id,
538 "nickname" => admin.nickname,
539 "type" => "user"
540 },
541 action: "relay_follow",
542 target: "https://example.org/relay"
543 },
544 inserted_at: NaiveDateTime.truncate(~N[2017-08-15 15:47:06.597036], :second)
545 })
546
547 Repo.insert(%ModerationLog{
548 data: %{
549 actor: %{
550 "id" => admin.id,
551 "nickname" => admin.nickname,
552 "type" => "user"
553 },
554 action: "relay_unfollow",
555 target: "https://example.org/relay"
556 },
557 inserted_at: NaiveDateTime.truncate(~N[2017-08-16 15:47:06.597036], :second)
558 })
559
560 conn = get(conn, "/api/pleroma/admin/moderation_log")
561
562 response = json_response(conn, 200)
563 [first_entry, second_entry] = response["items"]
564
565 assert response["total"] == 2
566 assert first_entry["data"]["action"] == "relay_unfollow"
567
568 assert first_entry["message"] ==
569 "@#{admin.nickname} unfollowed relay: https://example.org/relay"
570
571 assert second_entry["data"]["action"] == "relay_follow"
572
573 assert second_entry["message"] ==
574 "@#{admin.nickname} followed relay: https://example.org/relay"
575 end
576
577 test "returns the log with pagination", %{conn: conn, admin: admin} do
578 Repo.insert(%ModerationLog{
579 data: %{
580 actor: %{
581 "id" => admin.id,
582 "nickname" => admin.nickname,
583 "type" => "user"
584 },
585 action: "relay_follow",
586 target: "https://example.org/relay"
587 },
588 inserted_at: NaiveDateTime.truncate(~N[2017-08-15 15:47:06.597036], :second)
589 })
590
591 Repo.insert(%ModerationLog{
592 data: %{
593 actor: %{
594 "id" => admin.id,
595 "nickname" => admin.nickname,
596 "type" => "user"
597 },
598 action: "relay_unfollow",
599 target: "https://example.org/relay"
600 },
601 inserted_at: NaiveDateTime.truncate(~N[2017-08-16 15:47:06.597036], :second)
602 })
603
604 conn1 = get(conn, "/api/pleroma/admin/moderation_log?page_size=1&page=1")
605
606 response1 = json_response(conn1, 200)
607 [first_entry] = response1["items"]
608
609 assert response1["total"] == 2
610 assert response1["items"] |> length() == 1
611 assert first_entry["data"]["action"] == "relay_unfollow"
612
613 assert first_entry["message"] ==
614 "@#{admin.nickname} unfollowed relay: https://example.org/relay"
615
616 conn2 = get(conn, "/api/pleroma/admin/moderation_log?page_size=1&page=2")
617
618 response2 = json_response(conn2, 200)
619 [second_entry] = response2["items"]
620
621 assert response2["total"] == 2
622 assert response2["items"] |> length() == 1
623 assert second_entry["data"]["action"] == "relay_follow"
624
625 assert second_entry["message"] ==
626 "@#{admin.nickname} followed relay: https://example.org/relay"
627 end
628
629 test "filters log by date", %{conn: conn, admin: admin} do
630 first_date = "2017-08-15T15:47:06Z"
631 second_date = "2017-08-20T15:47:06Z"
632
633 Repo.insert(%ModerationLog{
634 data: %{
635 actor: %{
636 "id" => admin.id,
637 "nickname" => admin.nickname,
638 "type" => "user"
639 },
640 action: "relay_follow",
641 target: "https://example.org/relay"
642 },
643 inserted_at: NaiveDateTime.from_iso8601!(first_date)
644 })
645
646 Repo.insert(%ModerationLog{
647 data: %{
648 actor: %{
649 "id" => admin.id,
650 "nickname" => admin.nickname,
651 "type" => "user"
652 },
653 action: "relay_unfollow",
654 target: "https://example.org/relay"
655 },
656 inserted_at: NaiveDateTime.from_iso8601!(second_date)
657 })
658
659 conn1 =
660 get(
661 conn,
662 "/api/pleroma/admin/moderation_log?start_date=#{second_date}"
663 )
664
665 response1 = json_response(conn1, 200)
666 [first_entry] = response1["items"]
667
668 assert response1["total"] == 1
669 assert first_entry["data"]["action"] == "relay_unfollow"
670
671 assert first_entry["message"] ==
672 "@#{admin.nickname} unfollowed relay: https://example.org/relay"
673 end
674
675 test "returns log filtered by user", %{conn: conn, admin: admin, moderator: moderator} do
676 Repo.insert(%ModerationLog{
677 data: %{
678 actor: %{
679 "id" => admin.id,
680 "nickname" => admin.nickname,
681 "type" => "user"
682 },
683 action: "relay_follow",
684 target: "https://example.org/relay"
685 }
686 })
687
688 Repo.insert(%ModerationLog{
689 data: %{
690 actor: %{
691 "id" => moderator.id,
692 "nickname" => moderator.nickname,
693 "type" => "user"
694 },
695 action: "relay_unfollow",
696 target: "https://example.org/relay"
697 }
698 })
699
700 conn1 = get(conn, "/api/pleroma/admin/moderation_log?user_id=#{moderator.id}")
701
702 response1 = json_response(conn1, 200)
703 [first_entry] = response1["items"]
704
705 assert response1["total"] == 1
706 assert get_in(first_entry, ["data", "actor", "id"]) == moderator.id
707 end
708
709 test "returns log filtered by search", %{conn: conn, moderator: moderator} do
710 ModerationLog.insert_log(%{
711 actor: moderator,
712 action: "relay_follow",
713 target: "https://example.org/relay"
714 })
715
716 ModerationLog.insert_log(%{
717 actor: moderator,
718 action: "relay_unfollow",
719 target: "https://example.org/relay"
720 })
721
722 conn1 = get(conn, "/api/pleroma/admin/moderation_log?search=unfo")
723
724 response1 = json_response(conn1, 200)
725 [first_entry] = response1["items"]
726
727 assert response1["total"] == 1
728
729 assert get_in(first_entry, ["data", "message"]) ==
730 "@#{moderator.nickname} unfollowed relay: https://example.org/relay"
731 end
732 end
733
734 test "gets a remote users when [:instance, :limit_to_local_content] is set to :unauthenticated",
735 %{conn: conn} do
736 clear_config(Pleroma.Config.get([:instance, :limit_to_local_content]), :unauthenticated)
737 user = insert(:user, %{local: false, nickname: "u@peer1.com"})
738 conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}/credentials")
739
740 assert json_response(conn, 200)
741 end
742
743 describe "GET /users/:nickname/credentials" do
744 test "gets the user credentials", %{conn: conn} do
745 user = insert(:user)
746 conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}/credentials")
747
748 response = assert json_response(conn, 200)
749 assert response["email"] == user.email
750 end
751
752 test "returns 403 if requested by a non-admin" do
753 user = insert(:user)
754
755 conn =
756 build_conn()
757 |> assign(:user, user)
758 |> get("/api/pleroma/admin/users/#{user.nickname}/credentials")
759
760 assert json_response(conn, :forbidden)
761 end
762 end
763
764 describe "PATCH /users/:nickname/credentials" do
765 setup do
766 user = insert(:user)
767 [user: user]
768 end
769
770 test "changes password and email", %{conn: conn, admin: admin, user: user} do
771 assert user.password_reset_pending == false
772
773 conn =
774 patch(conn, "/api/pleroma/admin/users/#{user.nickname}/credentials", %{
775 "password" => "new_password",
776 "email" => "new_email@example.com",
777 "name" => "new_name"
778 })
779
780 assert json_response(conn, 200) == %{"status" => "success"}
781
782 ObanHelpers.perform_all()
783
784 updated_user = User.get_by_id(user.id)
785
786 assert updated_user.email == "new_email@example.com"
787 assert updated_user.name == "new_name"
788 assert updated_user.password_hash != user.password_hash
789 assert updated_user.password_reset_pending == true
790
791 [log_entry2, log_entry1] = ModerationLog |> Repo.all() |> Enum.sort()
792
793 assert ModerationLog.get_log_entry_message(log_entry1) ==
794 "@#{admin.nickname} updated users: @#{user.nickname}"
795
796 assert ModerationLog.get_log_entry_message(log_entry2) ==
797 "@#{admin.nickname} forced password reset for users: @#{user.nickname}"
798 end
799
800 test "returns 403 if requested by a non-admin", %{user: user} do
801 conn =
802 build_conn()
803 |> assign(:user, user)
804 |> patch("/api/pleroma/admin/users/#{user.nickname}/credentials", %{
805 "password" => "new_password",
806 "email" => "new_email@example.com",
807 "name" => "new_name"
808 })
809
810 assert json_response(conn, :forbidden)
811 end
812
813 test "changes actor type from permitted list", %{conn: conn, user: user} do
814 assert user.actor_type == "Person"
815
816 assert patch(conn, "/api/pleroma/admin/users/#{user.nickname}/credentials", %{
817 "actor_type" => "Service"
818 })
819 |> json_response(200) == %{"status" => "success"}
820
821 updated_user = User.get_by_id(user.id)
822
823 assert updated_user.actor_type == "Service"
824
825 assert patch(conn, "/api/pleroma/admin/users/#{user.nickname}/credentials", %{
826 "actor_type" => "Application"
827 })
828 |> json_response(400) == %{"errors" => %{"actor_type" => "is invalid"}}
829 end
830
831 test "update non existing user", %{conn: conn} do
832 assert patch(conn, "/api/pleroma/admin/users/non-existing/credentials", %{
833 "password" => "new_password"
834 })
835 |> json_response(404) == %{"error" => "Not found"}
836 end
837 end
838
839 describe "PATCH /users/:nickname/force_password_reset" do
840 test "sets password_reset_pending to true", %{conn: conn} do
841 user = insert(:user)
842 assert user.password_reset_pending == false
843
844 conn =
845 patch(conn, "/api/pleroma/admin/users/force_password_reset", %{nicknames: [user.nickname]})
846
847 assert empty_json_response(conn) == ""
848
849 ObanHelpers.perform_all()
850
851 assert User.get_by_id(user.id).password_reset_pending == true
852 end
853 end
854
855 describe "instances" do
856 test "GET /instances/:instance/statuses", %{conn: conn} do
857 user = insert(:user, local: false, ap_id: "https://archae.me/users/archaeme")
858 user2 = insert(:user, local: false, ap_id: "https://test.com/users/test")
859 insert_pair(:note_activity, user: user)
860 activity = insert(:note_activity, user: user2)
861
862 ret_conn = get(conn, "/api/pleroma/admin/instances/archae.me/statuses")
863
864 response = json_response(ret_conn, 200)
865
866 assert length(response) == 2
867
868 ret_conn = get(conn, "/api/pleroma/admin/instances/test.com/statuses")
869
870 response = json_response(ret_conn, 200)
871
872 assert length(response) == 1
873
874 ret_conn = get(conn, "/api/pleroma/admin/instances/nonexistent.com/statuses")
875
876 response = json_response(ret_conn, 200)
877
878 assert Enum.empty?(response)
879
880 CommonAPI.repeat(activity.id, user)
881
882 ret_conn = get(conn, "/api/pleroma/admin/instances/archae.me/statuses")
883 response = json_response(ret_conn, 200)
884 assert length(response) == 2
885
886 ret_conn = get(conn, "/api/pleroma/admin/instances/archae.me/statuses?with_reblogs=true")
887 response = json_response(ret_conn, 200)
888 assert length(response) == 3
889 end
890 end
891
892 describe "PATCH /confirm_email" do
893 test "it confirms emails of two users", %{conn: conn, admin: admin} do
894 [first_user, second_user] = insert_pair(:user, confirmation_pending: true)
895
896 assert first_user.confirmation_pending == true
897 assert second_user.confirmation_pending == true
898
899 ret_conn =
900 patch(conn, "/api/pleroma/admin/users/confirm_email", %{
901 nicknames: [
902 first_user.nickname,
903 second_user.nickname
904 ]
905 })
906
907 assert ret_conn.status == 200
908
909 assert first_user.confirmation_pending == true
910 assert second_user.confirmation_pending == true
911
912 log_entry = Repo.one(ModerationLog)
913
914 assert ModerationLog.get_log_entry_message(log_entry) ==
915 "@#{admin.nickname} confirmed email for users: @#{first_user.nickname}, @#{
916 second_user.nickname
917 }"
918 end
919 end
920
921 describe "PATCH /resend_confirmation_email" do
922 test "it resend emails for two users", %{conn: conn, admin: admin} do
923 [first_user, second_user] = insert_pair(:user, confirmation_pending: true)
924
925 ret_conn =
926 patch(conn, "/api/pleroma/admin/users/resend_confirmation_email", %{
927 nicknames: [
928 first_user.nickname,
929 second_user.nickname
930 ]
931 })
932
933 assert ret_conn.status == 200
934
935 log_entry = Repo.one(ModerationLog)
936
937 assert ModerationLog.get_log_entry_message(log_entry) ==
938 "@#{admin.nickname} re-sent confirmation email for users: @#{first_user.nickname}, @#{
939 second_user.nickname
940 }"
941
942 ObanHelpers.perform_all()
943
944 Pleroma.Emails.UserEmail.account_confirmation_email(first_user)
945 # temporary hackney fix until hackney max_connections bug is fixed
946 # https://git.pleroma.social/pleroma/pleroma/-/issues/2101
947 |> Swoosh.Email.put_private(:hackney_options, ssl_options: [versions: [:"tlsv1.2"]])
948 |> assert_email_sent()
949 end
950 end
951
952 describe "/api/pleroma/admin/stats" do
953 test "status visibility count", %{conn: conn} do
954 user = insert(:user)
955 CommonAPI.post(user, %{visibility: "public", status: "hey"})
956 CommonAPI.post(user, %{visibility: "unlisted", status: "hey"})
957 CommonAPI.post(user, %{visibility: "unlisted", status: "hey"})
958
959 response =
960 conn
961 |> get("/api/pleroma/admin/stats")
962 |> json_response(200)
963
964 assert %{"direct" => 0, "private" => 0, "public" => 1, "unlisted" => 2} =
965 response["status_visibility"]
966 end
967
968 test "by instance", %{conn: conn} do
969 user1 = insert(:user)
970 instance2 = "instance2.tld"
971 user2 = insert(:user, %{ap_id: "https://#{instance2}/@actor"})
972
973 CommonAPI.post(user1, %{visibility: "public", status: "hey"})
974 CommonAPI.post(user2, %{visibility: "unlisted", status: "hey"})
975 CommonAPI.post(user2, %{visibility: "private", status: "hey"})
976
977 response =
978 conn
979 |> get("/api/pleroma/admin/stats", instance: instance2)
980 |> json_response(200)
981
982 assert %{"direct" => 0, "private" => 1, "public" => 0, "unlisted" => 1} =
983 response["status_visibility"]
984 end
985 end
986
987 describe "/api/pleroma/backups" do
988 test "it creates a backup", %{conn: conn} do
989 admin = %{id: admin_id, nickname: admin_nickname} = insert(:user, is_admin: true)
990 token = insert(:oauth_admin_token, user: admin)
991 user = %{id: user_id, nickname: user_nickname} = insert(:user)
992
993 assert "" ==
994 conn
995 |> assign(:user, admin)
996 |> assign(:token, token)
997 |> post("/api/pleroma/admin/backups", %{nickname: user.nickname})
998 |> json_response(200)
999
1000 assert [backup] = Repo.all(Pleroma.User.Backup)
1001
1002 ObanHelpers.perform_all()
1003
1004 email = Pleroma.Emails.UserEmail.backup_is_ready_email(backup, admin.id)
1005
1006 assert String.contains?(email.html_body, "Admin @#{admin.nickname} requested a full backup")
1007 assert_email_sent(to: {user.name, user.email}, html_body: email.html_body)
1008
1009 log_message = "@#{admin_nickname} requested account backup for @#{user_nickname}"
1010
1011 assert [
1012 %{
1013 data: %{
1014 "action" => "create_backup",
1015 "actor" => %{
1016 "id" => ^admin_id,
1017 "nickname" => ^admin_nickname
1018 },
1019 "message" => ^log_message,
1020 "subject" => %{
1021 "id" => ^user_id,
1022 "nickname" => ^user_nickname
1023 }
1024 }
1025 }
1026 ] = Pleroma.ModerationLog |> Repo.all()
1027 end
1028
1029 test "it doesn't limit admins", %{conn: conn} do
1030 admin = insert(:user, is_admin: true)
1031 token = insert(:oauth_admin_token, user: admin)
1032 user = insert(:user)
1033
1034 assert "" ==
1035 conn
1036 |> assign(:user, admin)
1037 |> assign(:token, token)
1038 |> post("/api/pleroma/admin/backups", %{nickname: user.nickname})
1039 |> json_response(200)
1040
1041 assert [_backup] = Repo.all(Pleroma.User.Backup)
1042
1043 assert "" ==
1044 conn
1045 |> assign(:user, admin)
1046 |> assign(:token, token)
1047 |> post("/api/pleroma/admin/backups", %{nickname: user.nickname})
1048 |> json_response(200)
1049
1050 assert Repo.aggregate(Pleroma.User.Backup, :count) == 2
1051 end
1052 end
1053 end
1054
1055 # Needed for testing
1056 defmodule Pleroma.Web.Endpoint.NotReal do
1057 end
1058
1059 defmodule Pleroma.Captcha.NotReal do
1060 end