Merge remote-tracking branch 'origin/develop' into feature/account-export
[akkoma] / test / pleroma / web / admin_api / controllers / admin_api_controller_test.exs
1 # Pleroma: A lightweight social networking server
2 # Copyright © 2017-2020 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 a limit", %{conn: conn, user: user} do
426 conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}/statuses?page_size=2")
427
428 assert json_response(conn, 200) |> length() == 2
429 end
430
431 test "doesn't return private statuses by default", %{conn: conn, user: user} do
432 {:ok, _private_status} = CommonAPI.post(user, %{status: "private", visibility: "private"})
433
434 {:ok, _public_status} = CommonAPI.post(user, %{status: "public", visibility: "public"})
435
436 conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}/statuses")
437
438 assert json_response(conn, 200) |> length() == 4
439 end
440
441 test "returns private statuses with godmode on", %{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?godmode=true")
447
448 assert json_response(conn, 200) |> length() == 5
449 end
450
451 test "excludes reblogs by default", %{conn: conn, user: user} do
452 other_user = insert(:user)
453 {:ok, activity} = CommonAPI.post(user, %{status: "."})
454 {:ok, %Activity{}} = CommonAPI.repeat(activity.id, other_user)
455
456 conn_res = get(conn, "/api/pleroma/admin/users/#{other_user.nickname}/statuses")
457 assert json_response(conn_res, 200) |> length() == 0
458
459 conn_res =
460 get(conn, "/api/pleroma/admin/users/#{other_user.nickname}/statuses?with_reblogs=true")
461
462 assert json_response(conn_res, 200) |> length() == 1
463 end
464 end
465
466 describe "GET /api/pleroma/admin/users/:nickname/chats" do
467 setup do
468 user = insert(:user)
469 recipients = insert_list(3, :user)
470
471 Enum.each(recipients, fn recipient ->
472 CommonAPI.post_chat_message(user, recipient, "yo")
473 end)
474
475 %{user: user}
476 end
477
478 test "renders user's chats", %{conn: conn, user: user} do
479 conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}/chats")
480
481 assert json_response(conn, 200) |> length() == 3
482 end
483 end
484
485 describe "GET /api/pleroma/admin/users/:nickname/chats unauthorized" do
486 setup do
487 user = insert(:user)
488 recipient = insert(:user)
489 CommonAPI.post_chat_message(user, recipient, "yo")
490 %{conn: conn} = oauth_access(["read:chats"])
491 %{conn: conn, user: user}
492 end
493
494 test "returns 403", %{conn: conn, user: user} do
495 conn
496 |> get("/api/pleroma/admin/users/#{user.nickname}/chats")
497 |> json_response(403)
498 end
499 end
500
501 describe "GET /api/pleroma/admin/users/:nickname/chats unauthenticated" do
502 setup do
503 user = insert(:user)
504 recipient = insert(:user)
505 CommonAPI.post_chat_message(user, recipient, "yo")
506 %{conn: build_conn(), user: user}
507 end
508
509 test "returns 403", %{conn: conn, user: user} do
510 conn
511 |> get("/api/pleroma/admin/users/#{user.nickname}/chats")
512 |> json_response(403)
513 end
514 end
515
516 describe "GET /api/pleroma/admin/moderation_log" do
517 setup do
518 moderator = insert(:user, is_moderator: true)
519
520 %{moderator: moderator}
521 end
522
523 test "returns the log", %{conn: conn, admin: admin} do
524 Repo.insert(%ModerationLog{
525 data: %{
526 actor: %{
527 "id" => admin.id,
528 "nickname" => admin.nickname,
529 "type" => "user"
530 },
531 action: "relay_follow",
532 target: "https://example.org/relay"
533 },
534 inserted_at: NaiveDateTime.truncate(~N[2017-08-15 15:47:06.597036], :second)
535 })
536
537 Repo.insert(%ModerationLog{
538 data: %{
539 actor: %{
540 "id" => admin.id,
541 "nickname" => admin.nickname,
542 "type" => "user"
543 },
544 action: "relay_unfollow",
545 target: "https://example.org/relay"
546 },
547 inserted_at: NaiveDateTime.truncate(~N[2017-08-16 15:47:06.597036], :second)
548 })
549
550 conn = get(conn, "/api/pleroma/admin/moderation_log")
551
552 response = json_response(conn, 200)
553 [first_entry, second_entry] = response["items"]
554
555 assert response["total"] == 2
556 assert first_entry["data"]["action"] == "relay_unfollow"
557
558 assert first_entry["message"] ==
559 "@#{admin.nickname} unfollowed relay: https://example.org/relay"
560
561 assert second_entry["data"]["action"] == "relay_follow"
562
563 assert second_entry["message"] ==
564 "@#{admin.nickname} followed relay: https://example.org/relay"
565 end
566
567 test "returns the log with pagination", %{conn: conn, admin: admin} do
568 Repo.insert(%ModerationLog{
569 data: %{
570 actor: %{
571 "id" => admin.id,
572 "nickname" => admin.nickname,
573 "type" => "user"
574 },
575 action: "relay_follow",
576 target: "https://example.org/relay"
577 },
578 inserted_at: NaiveDateTime.truncate(~N[2017-08-15 15:47:06.597036], :second)
579 })
580
581 Repo.insert(%ModerationLog{
582 data: %{
583 actor: %{
584 "id" => admin.id,
585 "nickname" => admin.nickname,
586 "type" => "user"
587 },
588 action: "relay_unfollow",
589 target: "https://example.org/relay"
590 },
591 inserted_at: NaiveDateTime.truncate(~N[2017-08-16 15:47:06.597036], :second)
592 })
593
594 conn1 = get(conn, "/api/pleroma/admin/moderation_log?page_size=1&page=1")
595
596 response1 = json_response(conn1, 200)
597 [first_entry] = response1["items"]
598
599 assert response1["total"] == 2
600 assert response1["items"] |> length() == 1
601 assert first_entry["data"]["action"] == "relay_unfollow"
602
603 assert first_entry["message"] ==
604 "@#{admin.nickname} unfollowed relay: https://example.org/relay"
605
606 conn2 = get(conn, "/api/pleroma/admin/moderation_log?page_size=1&page=2")
607
608 response2 = json_response(conn2, 200)
609 [second_entry] = response2["items"]
610
611 assert response2["total"] == 2
612 assert response2["items"] |> length() == 1
613 assert second_entry["data"]["action"] == "relay_follow"
614
615 assert second_entry["message"] ==
616 "@#{admin.nickname} followed relay: https://example.org/relay"
617 end
618
619 test "filters log by date", %{conn: conn, admin: admin} do
620 first_date = "2017-08-15T15:47:06Z"
621 second_date = "2017-08-20T15:47:06Z"
622
623 Repo.insert(%ModerationLog{
624 data: %{
625 actor: %{
626 "id" => admin.id,
627 "nickname" => admin.nickname,
628 "type" => "user"
629 },
630 action: "relay_follow",
631 target: "https://example.org/relay"
632 },
633 inserted_at: NaiveDateTime.from_iso8601!(first_date)
634 })
635
636 Repo.insert(%ModerationLog{
637 data: %{
638 actor: %{
639 "id" => admin.id,
640 "nickname" => admin.nickname,
641 "type" => "user"
642 },
643 action: "relay_unfollow",
644 target: "https://example.org/relay"
645 },
646 inserted_at: NaiveDateTime.from_iso8601!(second_date)
647 })
648
649 conn1 =
650 get(
651 conn,
652 "/api/pleroma/admin/moderation_log?start_date=#{second_date}"
653 )
654
655 response1 = json_response(conn1, 200)
656 [first_entry] = response1["items"]
657
658 assert response1["total"] == 1
659 assert first_entry["data"]["action"] == "relay_unfollow"
660
661 assert first_entry["message"] ==
662 "@#{admin.nickname} unfollowed relay: https://example.org/relay"
663 end
664
665 test "returns log filtered by user", %{conn: conn, admin: admin, moderator: moderator} do
666 Repo.insert(%ModerationLog{
667 data: %{
668 actor: %{
669 "id" => admin.id,
670 "nickname" => admin.nickname,
671 "type" => "user"
672 },
673 action: "relay_follow",
674 target: "https://example.org/relay"
675 }
676 })
677
678 Repo.insert(%ModerationLog{
679 data: %{
680 actor: %{
681 "id" => moderator.id,
682 "nickname" => moderator.nickname,
683 "type" => "user"
684 },
685 action: "relay_unfollow",
686 target: "https://example.org/relay"
687 }
688 })
689
690 conn1 = get(conn, "/api/pleroma/admin/moderation_log?user_id=#{moderator.id}")
691
692 response1 = json_response(conn1, 200)
693 [first_entry] = response1["items"]
694
695 assert response1["total"] == 1
696 assert get_in(first_entry, ["data", "actor", "id"]) == moderator.id
697 end
698
699 test "returns log filtered by search", %{conn: conn, moderator: moderator} do
700 ModerationLog.insert_log(%{
701 actor: moderator,
702 action: "relay_follow",
703 target: "https://example.org/relay"
704 })
705
706 ModerationLog.insert_log(%{
707 actor: moderator,
708 action: "relay_unfollow",
709 target: "https://example.org/relay"
710 })
711
712 conn1 = get(conn, "/api/pleroma/admin/moderation_log?search=unfo")
713
714 response1 = json_response(conn1, 200)
715 [first_entry] = response1["items"]
716
717 assert response1["total"] == 1
718
719 assert get_in(first_entry, ["data", "message"]) ==
720 "@#{moderator.nickname} unfollowed relay: https://example.org/relay"
721 end
722 end
723
724 test "gets a remote users when [:instance, :limit_to_local_content] is set to :unauthenticated",
725 %{conn: conn} do
726 clear_config(Pleroma.Config.get([:instance, :limit_to_local_content]), :unauthenticated)
727 user = insert(:user, %{local: false, nickname: "u@peer1.com"})
728 conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}/credentials")
729
730 assert json_response(conn, 200)
731 end
732
733 describe "GET /users/:nickname/credentials" do
734 test "gets the user credentials", %{conn: conn} do
735 user = insert(:user)
736 conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}/credentials")
737
738 response = assert json_response(conn, 200)
739 assert response["email"] == user.email
740 end
741
742 test "returns 403 if requested by a non-admin" do
743 user = insert(:user)
744
745 conn =
746 build_conn()
747 |> assign(:user, user)
748 |> get("/api/pleroma/admin/users/#{user.nickname}/credentials")
749
750 assert json_response(conn, :forbidden)
751 end
752 end
753
754 describe "PATCH /users/:nickname/credentials" do
755 setup do
756 user = insert(:user)
757 [user: user]
758 end
759
760 test "changes password and email", %{conn: conn, admin: admin, user: user} do
761 assert user.password_reset_pending == false
762
763 conn =
764 patch(conn, "/api/pleroma/admin/users/#{user.nickname}/credentials", %{
765 "password" => "new_password",
766 "email" => "new_email@example.com",
767 "name" => "new_name"
768 })
769
770 assert json_response(conn, 200) == %{"status" => "success"}
771
772 ObanHelpers.perform_all()
773
774 updated_user = User.get_by_id(user.id)
775
776 assert updated_user.email == "new_email@example.com"
777 assert updated_user.name == "new_name"
778 assert updated_user.password_hash != user.password_hash
779 assert updated_user.password_reset_pending == true
780
781 [log_entry2, log_entry1] = ModerationLog |> Repo.all() |> Enum.sort()
782
783 assert ModerationLog.get_log_entry_message(log_entry1) ==
784 "@#{admin.nickname} updated users: @#{user.nickname}"
785
786 assert ModerationLog.get_log_entry_message(log_entry2) ==
787 "@#{admin.nickname} forced password reset for users: @#{user.nickname}"
788 end
789
790 test "returns 403 if requested by a non-admin", %{user: user} do
791 conn =
792 build_conn()
793 |> assign(:user, user)
794 |> patch("/api/pleroma/admin/users/#{user.nickname}/credentials", %{
795 "password" => "new_password",
796 "email" => "new_email@example.com",
797 "name" => "new_name"
798 })
799
800 assert json_response(conn, :forbidden)
801 end
802
803 test "changes actor type from permitted list", %{conn: conn, user: user} do
804 assert user.actor_type == "Person"
805
806 assert patch(conn, "/api/pleroma/admin/users/#{user.nickname}/credentials", %{
807 "actor_type" => "Service"
808 })
809 |> json_response(200) == %{"status" => "success"}
810
811 updated_user = User.get_by_id(user.id)
812
813 assert updated_user.actor_type == "Service"
814
815 assert patch(conn, "/api/pleroma/admin/users/#{user.nickname}/credentials", %{
816 "actor_type" => "Application"
817 })
818 |> json_response(400) == %{"errors" => %{"actor_type" => "is invalid"}}
819 end
820
821 test "update non existing user", %{conn: conn} do
822 assert patch(conn, "/api/pleroma/admin/users/non-existing/credentials", %{
823 "password" => "new_password"
824 })
825 |> json_response(404) == %{"error" => "Not found"}
826 end
827 end
828
829 describe "PATCH /users/:nickname/force_password_reset" do
830 test "sets password_reset_pending to true", %{conn: conn} do
831 user = insert(:user)
832 assert user.password_reset_pending == false
833
834 conn =
835 patch(conn, "/api/pleroma/admin/users/force_password_reset", %{nicknames: [user.nickname]})
836
837 assert empty_json_response(conn) == ""
838
839 ObanHelpers.perform_all()
840
841 assert User.get_by_id(user.id).password_reset_pending == true
842 end
843 end
844
845 describe "instances" do
846 test "GET /instances/:instance/statuses", %{conn: conn} do
847 user = insert(:user, local: false, nickname: "archaeme@archae.me")
848 user2 = insert(:user, local: false, nickname: "test@test.com")
849 insert_pair(:note_activity, user: user)
850 activity = insert(:note_activity, user: user2)
851
852 ret_conn = get(conn, "/api/pleroma/admin/instances/archae.me/statuses")
853
854 response = json_response(ret_conn, 200)
855
856 assert length(response) == 2
857
858 ret_conn = get(conn, "/api/pleroma/admin/instances/test.com/statuses")
859
860 response = json_response(ret_conn, 200)
861
862 assert length(response) == 1
863
864 ret_conn = get(conn, "/api/pleroma/admin/instances/nonexistent.com/statuses")
865
866 response = json_response(ret_conn, 200)
867
868 assert Enum.empty?(response)
869
870 CommonAPI.repeat(activity.id, user)
871
872 ret_conn = get(conn, "/api/pleroma/admin/instances/archae.me/statuses")
873 response = json_response(ret_conn, 200)
874 assert length(response) == 2
875
876 ret_conn = get(conn, "/api/pleroma/admin/instances/archae.me/statuses?with_reblogs=true")
877 response = json_response(ret_conn, 200)
878 assert length(response) == 3
879 end
880 end
881
882 describe "PATCH /confirm_email" do
883 test "it confirms emails of two users", %{conn: conn, admin: admin} do
884 [first_user, second_user] = insert_pair(:user, confirmation_pending: true)
885
886 assert first_user.confirmation_pending == true
887 assert second_user.confirmation_pending == true
888
889 ret_conn =
890 patch(conn, "/api/pleroma/admin/users/confirm_email", %{
891 nicknames: [
892 first_user.nickname,
893 second_user.nickname
894 ]
895 })
896
897 assert ret_conn.status == 200
898
899 assert first_user.confirmation_pending == true
900 assert second_user.confirmation_pending == true
901
902 log_entry = Repo.one(ModerationLog)
903
904 assert ModerationLog.get_log_entry_message(log_entry) ==
905 "@#{admin.nickname} confirmed email for users: @#{first_user.nickname}, @#{
906 second_user.nickname
907 }"
908 end
909 end
910
911 describe "PATCH /resend_confirmation_email" do
912 test "it resend emails for two users", %{conn: conn, admin: admin} do
913 [first_user, second_user] = insert_pair(:user, confirmation_pending: true)
914
915 ret_conn =
916 patch(conn, "/api/pleroma/admin/users/resend_confirmation_email", %{
917 nicknames: [
918 first_user.nickname,
919 second_user.nickname
920 ]
921 })
922
923 assert ret_conn.status == 200
924
925 log_entry = Repo.one(ModerationLog)
926
927 assert ModerationLog.get_log_entry_message(log_entry) ==
928 "@#{admin.nickname} re-sent confirmation email for users: @#{first_user.nickname}, @#{
929 second_user.nickname
930 }"
931
932 ObanHelpers.perform_all()
933
934 Pleroma.Emails.UserEmail.account_confirmation_email(first_user)
935 # temporary hackney fix until hackney max_connections bug is fixed
936 # https://git.pleroma.social/pleroma/pleroma/-/issues/2101
937 |> Swoosh.Email.put_private(:hackney_options, ssl_options: [versions: [:"tlsv1.2"]])
938 |> assert_email_sent()
939 end
940 end
941
942 describe "/api/pleroma/admin/stats" do
943 test "status visibility count", %{conn: conn} do
944 admin = insert(:user, is_admin: true)
945 user = insert(:user)
946 CommonAPI.post(user, %{visibility: "public", status: "hey"})
947 CommonAPI.post(user, %{visibility: "unlisted", status: "hey"})
948 CommonAPI.post(user, %{visibility: "unlisted", status: "hey"})
949
950 response =
951 conn
952 |> assign(:user, admin)
953 |> get("/api/pleroma/admin/stats")
954 |> json_response(200)
955
956 assert %{"direct" => 0, "private" => 0, "public" => 1, "unlisted" => 2} =
957 response["status_visibility"]
958 end
959
960 test "by instance", %{conn: conn} do
961 admin = insert(:user, is_admin: true)
962 user1 = insert(:user)
963 instance2 = "instance2.tld"
964 user2 = insert(:user, %{ap_id: "https://#{instance2}/@actor"})
965
966 CommonAPI.post(user1, %{visibility: "public", status: "hey"})
967 CommonAPI.post(user2, %{visibility: "unlisted", status: "hey"})
968 CommonAPI.post(user2, %{visibility: "private", status: "hey"})
969
970 response =
971 conn
972 |> assign(:user, admin)
973 |> get("/api/pleroma/admin/stats", instance: instance2)
974 |> json_response(200)
975
976 assert %{"direct" => 0, "private" => 1, "public" => 0, "unlisted" => 1} =
977 response["status_visibility"]
978 end
979 end
980
981 describe "/api/pleroma/backups" do
982 test "it creates a backup", %{conn: conn} do
983 admin = %{id: admin_id, nickname: admin_nickname} = insert(:user, is_admin: true)
984 token = insert(:oauth_admin_token, user: admin)
985 user = %{id: user_id, nickname: user_nickname} = insert(:user)
986
987 assert "" ==
988 conn
989 |> assign(:user, admin)
990 |> assign(:token, token)
991 |> post("/api/pleroma/admin/backups", %{nickname: user.nickname})
992 |> json_response(200)
993
994 assert [backup] = Repo.all(Pleroma.User.Backup)
995
996 ObanHelpers.perform_all()
997
998 email = Pleroma.Emails.UserEmail.backup_is_ready_email(backup, admin.id)
999
1000 assert String.contains?(email.html_body, "Admin @#{admin.nickname} requested a full backup")
1001 assert_email_sent(to: {user.name, user.email}, html_body: email.html_body)
1002
1003 log_message = "@#{admin_nickname} requested account backup for @#{user_nickname}"
1004
1005 assert [
1006 %{
1007 data: %{
1008 "action" => "create_backup",
1009 "actor" => %{
1010 "id" => ^admin_id,
1011 "nickname" => ^admin_nickname
1012 },
1013 "message" => ^log_message,
1014 "subject" => %{
1015 "id" => ^user_id,
1016 "nickname" => ^user_nickname
1017 }
1018 }
1019 }
1020 ] = Pleroma.ModerationLog |> Repo.all()
1021 end
1022
1023 test "it doesn't limit admins", %{conn: conn} do
1024 admin = insert(:user, is_admin: true)
1025 token = insert(:oauth_admin_token, user: admin)
1026 user = insert(:user)
1027
1028 assert "" ==
1029 conn
1030 |> assign(:user, admin)
1031 |> assign(:token, token)
1032 |> post("/api/pleroma/admin/backups", %{nickname: user.nickname})
1033 |> json_response(200)
1034
1035 assert [_backup] = Repo.all(Pleroma.User.Backup)
1036
1037 assert "" ==
1038 conn
1039 |> assign(:user, admin)
1040 |> assign(:token, token)
1041 |> post("/api/pleroma/admin/backups", %{nickname: user.nickname})
1042 |> json_response(200)
1043
1044 assert Repo.aggregate(Pleroma.User.Backup, :count) == 2
1045 end
1046 end
1047 end
1048
1049 # Needed for testing
1050 defmodule Pleroma.Web.Endpoint.NotReal do
1051 end
1052
1053 defmodule Pleroma.Captcha.NotReal do
1054 end