admin_api_controller_test.exs 30.5 KB
Newer Older
kaniini's avatar
kaniini committed
1
# Pleroma: A lightweight social networking server
2
# Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/>
kaniini's avatar
kaniini committed
3
4
# SPDX-License-Identifier: AGPL-3.0-only

5
6
defmodule Pleroma.Web.AdminAPI.AdminAPIControllerTest do
  use Pleroma.Web.ConnCase
7
  use Oban.Testing, repo: Pleroma.Repo
8

Alexander Strizhakov's avatar
Alexander Strizhakov committed
9
  import ExUnit.CaptureLog
10
  import Pleroma.Factory
11
  import Swoosh.TestAssertions
Alexander Strizhakov's avatar
Alexander Strizhakov committed
12

Sergey Suprunenko's avatar
Sergey Suprunenko committed
13
  alias Pleroma.Activity
14
  alias Pleroma.MFA
Maxim Filippov's avatar
Maxim Filippov committed
15
16
  alias Pleroma.ModerationLog
  alias Pleroma.Repo
17
  alias Pleroma.Tests.ObanHelpers
Haelwenn's avatar
Haelwenn committed
18
  alias Pleroma.User
Sergey Suprunenko's avatar
Sergey Suprunenko committed
19
  alias Pleroma.Web.CommonAPI
20

21
22
23
24
25
26
  setup_all do
    Tesla.Mock.mock_global(fn env -> apply(HttpRequestMock, :request, [env]) end)

    :ok
  end

27
28
29
30
31
32
33
34
35
36
  setup do
    admin = insert(:user, is_admin: true)
    token = insert(:oauth_admin_token, user: admin)

    conn =
      build_conn()
      |> assign(:user, admin)
      |> assign(:token, token)

    {:ok, %{admin: admin, token: token, conn: conn}}
37
38
  end

39
40
41
42
43
44
45
46
47
48
  test "with valid `admin_token` query parameter, skips OAuth scopes check" do
    clear_config([:admin_token], "password123")

    user = insert(:user)

    conn = get(build_conn(), "/api/pleroma/admin/users/#{user.nickname}?admin_token=password123")

    assert json_response(conn, 200)
  end

49
  describe "with [:auth, :enforce_oauth_admin_scope_usage]," do
50
    setup do: clear_config([:auth, :enforce_oauth_admin_scope_usage], true)
51

52
53
    test "GET /api/pleroma/admin/users/:nickname requires admin:read:accounts or broader scope",
         %{admin: admin} do
54
      user = insert(:user)
55
      url = "/api/pleroma/admin/users/#{user.nickname}"
56
57
58
59
60
61
62
63
64
65
66
67
68
69

      good_token1 = insert(:oauth_token, user: admin, scopes: ["admin"])
      good_token2 = insert(:oauth_token, user: admin, scopes: ["admin:read"])
      good_token3 = insert(:oauth_token, user: admin, scopes: ["admin:read:accounts"])

      bad_token1 = insert(:oauth_token, user: admin, scopes: ["read:accounts"])
      bad_token2 = insert(:oauth_token, user: admin, scopes: ["admin:read:accounts:partial"])
      bad_token3 = nil

      for good_token <- [good_token1, good_token2, good_token3] do
        conn =
          build_conn()
          |> assign(:user, admin)
          |> assign(:token, good_token)
70
          |> get(url)
71
72
73
74

        assert json_response(conn, 200)
      end

75
76
77
78
79
80
81
82
83
84
      for good_token <- [good_token1, good_token2, good_token3] do
        conn =
          build_conn()
          |> assign(:user, nil)
          |> assign(:token, good_token)
          |> get(url)

        assert json_response(conn, :forbidden)
      end

85
86
87
88
89
      for bad_token <- [bad_token1, bad_token2, bad_token3] do
        conn =
          build_conn()
          |> assign(:user, admin)
          |> assign(:token, bad_token)
90
          |> get(url)
91
92
93
94
95
96

        assert json_response(conn, :forbidden)
      end
    end
  end

97
  describe "unless [:auth, :enforce_oauth_admin_scope_usage]," do
98
    setup do: clear_config([:auth, :enforce_oauth_admin_scope_usage], false)
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149

    test "GET /api/pleroma/admin/users/:nickname requires " <>
           "read:accounts or admin:read:accounts or broader scope",
         %{admin: admin} do
      user = insert(:user)
      url = "/api/pleroma/admin/users/#{user.nickname}"

      good_token1 = insert(:oauth_token, user: admin, scopes: ["admin"])
      good_token2 = insert(:oauth_token, user: admin, scopes: ["admin:read"])
      good_token3 = insert(:oauth_token, user: admin, scopes: ["admin:read:accounts"])
      good_token4 = insert(:oauth_token, user: admin, scopes: ["read:accounts"])
      good_token5 = insert(:oauth_token, user: admin, scopes: ["read"])

      good_tokens = [good_token1, good_token2, good_token3, good_token4, good_token5]

      bad_token1 = insert(:oauth_token, user: admin, scopes: ["read:accounts:partial"])
      bad_token2 = insert(:oauth_token, user: admin, scopes: ["admin:read:accounts:partial"])
      bad_token3 = nil

      for good_token <- good_tokens do
        conn =
          build_conn()
          |> assign(:user, admin)
          |> assign(:token, good_token)
          |> get(url)

        assert json_response(conn, 200)
      end

      for good_token <- good_tokens do
        conn =
          build_conn()
          |> assign(:user, nil)
          |> assign(:token, good_token)
          |> get(url)

        assert json_response(conn, :forbidden)
      end

      for bad_token <- [bad_token1, bad_token2, bad_token3] do
        conn =
          build_conn()
          |> assign(:user, admin)
          |> assign(:token, bad_token)
          |> get(url)

        assert json_response(conn, :forbidden)
      end
    end
  end

150
  describe "PUT /api/pleroma/admin/users/tag" do
151
    setup %{conn: conn} do
152
153
154
155
156
      user1 = insert(:user, %{tags: ["x"]})
      user2 = insert(:user, %{tags: ["y"]})
      user3 = insert(:user, %{tags: ["unchanged"]})

      conn =
157
        conn
158
        |> put_req_header("accept", "application/json")
Ivan Tashkinov's avatar
Ivan Tashkinov committed
159
        |> put(
160
161
          "/api/pleroma/admin/users/tag?nicknames[]=#{user1.nickname}&nicknames[]=" <>
            "#{user2.nickname}&tags[]=foo&tags[]=bar"
Ivan Tashkinov's avatar
Ivan Tashkinov committed
162
        )
163

164
      %{conn: conn, user1: user1, user2: user2, user3: user3}
165
166
    end

Ivan Tashkinov's avatar
Ivan Tashkinov committed
167
168
    test "it appends specified tags to users with specified nicknames", %{
      conn: conn,
Maxim Filippov's avatar
Maxim Filippov committed
169
      admin: admin,
Ivan Tashkinov's avatar
Ivan Tashkinov committed
170
171
172
      user1: user1,
      user2: user2
    } do
173
      assert empty_json_response(conn)
minibikini's avatar
minibikini committed
174
175
      assert User.get_cached_by_id(user1.id).tags == ["x", "foo", "bar"]
      assert User.get_cached_by_id(user2.id).tags == ["y", "foo", "bar"]
Maxim Filippov's avatar
Maxim Filippov committed
176
177
178
179
180
181
182
183
184
185
186
187

      log_entry = Repo.one(ModerationLog)

      users =
        [user1.nickname, user2.nickname]
        |> Enum.map(&"@#{&1}")
        |> Enum.join(", ")

      tags = ["foo", "bar"] |> Enum.join(", ")

      assert ModerationLog.get_log_entry_message(log_entry) ==
               "@#{admin.nickname} added tags: #{tags} to users: #{users}"
188
189
190
    end

    test "it does not modify tags of not specified users", %{conn: conn, user3: user3} do
191
      assert empty_json_response(conn)
minibikini's avatar
minibikini committed
192
      assert User.get_cached_by_id(user3.id).tags == ["unchanged"]
193
194
195
    end
  end

196
  describe "DELETE /api/pleroma/admin/users/tag" do
197
    setup %{conn: conn} do
198
199
200
201
202
      user1 = insert(:user, %{tags: ["x"]})
      user2 = insert(:user, %{tags: ["y", "z"]})
      user3 = insert(:user, %{tags: ["unchanged"]})

      conn =
203
        conn
204
        |> put_req_header("accept", "application/json")
205
        |> delete(
206
207
          "/api/pleroma/admin/users/tag?nicknames[]=#{user1.nickname}&nicknames[]=" <>
            "#{user2.nickname}&tags[]=x&tags[]=z"
Ivan Tashkinov's avatar
Ivan Tashkinov committed
208
        )
209

210
      %{conn: conn, user1: user1, user2: user2, user3: user3}
211
212
    end

Ivan Tashkinov's avatar
Ivan Tashkinov committed
213
214
    test "it removes specified tags from users with specified nicknames", %{
      conn: conn,
Maxim Filippov's avatar
Maxim Filippov committed
215
      admin: admin,
Ivan Tashkinov's avatar
Ivan Tashkinov committed
216
217
218
      user1: user1,
      user2: user2
    } do
219
      assert empty_json_response(conn)
minibikini's avatar
minibikini committed
220
221
      assert User.get_cached_by_id(user1.id).tags == []
      assert User.get_cached_by_id(user2.id).tags == ["y"]
Maxim Filippov's avatar
Maxim Filippov committed
222
223
224
225
226
227
228
229
230
231
232
233

      log_entry = Repo.one(ModerationLog)

      users =
        [user1.nickname, user2.nickname]
        |> Enum.map(&"@#{&1}")
        |> Enum.join(", ")

      tags = ["x", "z"] |> Enum.join(", ")

      assert ModerationLog.get_log_entry_message(log_entry) ==
               "@#{admin.nickname} removed tags: #{tags} from users: #{users}"
234
235
236
    end

    test "it does not modify tags of not specified users", %{conn: conn, user3: user3} do
237
      assert empty_json_response(conn)
minibikini's avatar
minibikini committed
238
      assert User.get_cached_by_id(user3.id).tags == ["unchanged"]
239
240
241
    end
  end

Sachin Joshi's avatar
Sachin Joshi committed
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")
Sachin Joshi's avatar
Sachin Joshi committed
247
        |> get("/api/pleroma/admin/users/#{admin.nickname}/permission_group/")
248

lain's avatar
lain committed
249
250
251
252
      assert json_response(conn, 200) == %{
               "is_admin" => true,
               "is_moderator" => false
             }
253
254
    end

255
    test "/:right POST, can add to a permission group", %{admin: admin, conn: conn} do
256
257
258
      user = insert(:user)

      conn =
259
        conn
260
        |> put_req_header("accept", "application/json")
Sachin Joshi's avatar
Sachin Joshi committed
261
        |> post("/api/pleroma/admin/users/#{user.nickname}/permission_group/admin")
262

lain's avatar
lain committed
263
264
265
      assert json_response(conn, 200) == %{
               "is_admin" => true
             }
Maxim Filippov's avatar
Maxim Filippov committed
266
267
268
269
270

      log_entry = Repo.one(ModerationLog)

      assert ModerationLog.get_log_entry_message(log_entry) ==
               "@#{admin.nickname} made @#{user.nickname} admin"
271
272
    end

273
    test "/:right POST, can add to a permission group (multiple)", %{admin: admin, conn: conn} do
274
275
      user_one = insert(:user)
      user_two = insert(:user)
276
277

      conn =
278
        conn
279
        |> put_req_header("accept", "application/json")
280
281
282
        |> post("/api/pleroma/admin/users/permission_group/admin", %{
          nicknames: [user_one.nickname, user_two.nickname]
        })
283

284
      assert json_response(conn, 200) == %{"is_admin" => true}
Maxim Filippov's avatar
Maxim Filippov committed
285
286
287
288

      log_entry = Repo.one(ModerationLog)

      assert ModerationLog.get_log_entry_message(log_entry) ==
289
               "@#{admin.nickname} made @#{user_one.nickname}, @#{user_two.nickname} admin"
290
291
    end

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")
Maxim Filippov's avatar
Maxim Filippov committed
298
        |> delete("/api/pleroma/admin/users/#{user.nickname}/permission_group/admin")
299

300
      assert json_response(conn, 200) == %{"is_admin" => false}
Maxim Filippov's avatar
Maxim Filippov committed
301
302
303
304

      log_entry = Repo.one(ModerationLog)

      assert ModerationLog.get_log_entry_message(log_entry) ==
Maxim Filippov's avatar
Maxim Filippov committed
305
               "@#{admin.nickname} revoked admin role from @#{user.nickname}"
306
307
    end

308
309
310
311
    test "/:right DELETE, can remove from a permission group (multiple)", %{
      admin: admin,
      conn: conn
    } do
312
313
      user_one = insert(:user, is_admin: true)
      user_two = insert(:user, is_admin: true)
314
315

      conn =
316
        conn
317
        |> put_req_header("accept", "application/json")
318
319
320
        |> delete("/api/pleroma/admin/users/permission_group/admin", %{
          nicknames: [user_one.nickname, user_two.nickname]
        })
321

322
      assert json_response(conn, 200) == %{"is_admin" => false}
Maxim Filippov's avatar
Maxim Filippov committed
323
324
325
326

      log_entry = Repo.one(ModerationLog)

      assert ModerationLog.get_log_entry_message(log_entry) ==
327
328
329
               "@#{admin.nickname} revoked admin role from @#{user_one.nickname}, @#{
                 user_two.nickname
               }"
330
331
332
    end
  end

333
  test "/api/pleroma/admin/users/:nickname/password_reset", %{conn: conn} do
lain's avatar
lain committed
334
    user = insert(:user)
335
336

    conn =
337
      conn
338
      |> put_req_header("accept", "application/json")
Sachin Joshi's avatar
Sachin Joshi committed
339
      |> get("/api/pleroma/admin/users/#{user.nickname}/password_reset")
340

341
342
343
    resp = json_response(conn, 200)

    assert Regex.match?(~r/(http:\/\/|https:\/\/)/, resp["link"])
344
  end
Maxim Filippov's avatar
Maxim Filippov committed
345

346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
  describe "PUT disable_mfa" do
    test "returns 200 and disable 2fa", %{conn: conn} do
      user =
        insert(:user,
          multi_factor_authentication_settings: %MFA.Settings{
            enabled: true,
            totp: %MFA.Settings.TOTP{secret: "otp_secret", confirmed: true}
          }
        )

      response =
        conn
        |> put("/api/pleroma/admin/users/disable_mfa", %{nickname: user.nickname})
        |> json_response(200)

      assert response == user.nickname
      mfa_settings = refresh_record(user).multi_factor_authentication_settings

      refute mfa_settings.enabled
      refute mfa_settings.totp.confirmed
    end

    test "returns 404 if user not found", %{conn: conn} do
      response =
        conn
        |> put("/api/pleroma/admin/users/disable_mfa", %{nickname: "nickname"})
        |> json_response(404)

374
      assert response == %{"error" => "Not found"}
375
376
377
    end
  end

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
Alexander Strizhakov's avatar
Alexander Strizhakov committed
382
      capture_log(fn ->
383
384
        assert conn |> get("/api/pleroma/admin/restart") |> json_response(200) == %{}
      end) =~ "pleroma restarted"
Alexander Strizhakov's avatar
Alexander Strizhakov committed
385
386

      refute Restarter.Pleroma.need_reboot?()
387
388
389
    end
  end

390
391
392
393
394
395
396
397
398
399
400
401
402
403
  test "need_reboot flag", %{conn: conn} do
    assert conn
           |> get("/api/pleroma/admin/need_reboot")
           |> json_response(200) == %{"need_reboot" => false}

    Restarter.Pleroma.need_reboot()

    assert conn
           |> get("/api/pleroma/admin/need_reboot")
           |> json_response(200) == %{"need_reboot" => true}

    on_exit(fn -> Restarter.Pleroma.refresh() end)
  end

404
405
406
407
408
409
410
411
412
413
414
415
  describe "GET /api/pleroma/admin/users/:nickname/statuses" do
    setup do
      user = insert(:user)

      date1 = (DateTime.to_unix(DateTime.utc_now()) + 2000) |> DateTime.from_unix!()
      date2 = (DateTime.to_unix(DateTime.utc_now()) + 1000) |> DateTime.from_unix!()
      date3 = (DateTime.to_unix(DateTime.utc_now()) + 3000) |> DateTime.from_unix!()

      insert(:note_activity, user: user, published: date1)
      insert(:note_activity, user: user, published: date2)
      insert(:note_activity, user: user, published: date3)

416
      %{user: user}
417
418
419
420
421
422
423
424
425
426
427
428
429
    end

    test "renders user's statuses", %{conn: conn, user: user} do
      conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}/statuses")

      assert json_response(conn, 200) |> length() == 3
    end

    test "renders user's statuses with a limit", %{conn: conn, user: user} do
      conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}/statuses?page_size=2")

      assert json_response(conn, 200) |> length() == 2
    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
437
438
439
440
441

      conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}/statuses")

      assert json_response(conn, 200) |> length() == 4
    end

    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
447
448
449

      conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}/statuses?godmode=true")

      assert json_response(conn, 200) |> length() == 5
    end
450
451
452

    test "excludes reblogs by default", %{conn: conn, user: user} do
      other_user = insert(:user)
453
      {:ok, activity} = CommonAPI.post(user, %{status: "."})
lain's avatar
lain committed
454
      {:ok, %Activity{}} = CommonAPI.repeat(activity.id, other_user)
455
456
457
458
459
460
461
462
463

      conn_res = get(conn, "/api/pleroma/admin/users/#{other_user.nickname}/statuses")
      assert json_response(conn_res, 200) |> length() == 0

      conn_res =
        get(conn, "/api/pleroma/admin/users/#{other_user.nickname}/statuses?with_reblogs=true")

      assert json_response(conn_res, 200) |> length() == 1
    end
464
  end
Maxim Filippov's avatar
Maxim Filippov committed
465

Alex Gleason's avatar
Alex Gleason committed
466
467
468
  describe "GET /api/pleroma/admin/users/:nickname/chats" do
    setup do
      user = insert(:user)
lain's avatar
lain committed
469
      recipients = insert_list(3, :user)
Alex Gleason's avatar
Alex Gleason committed
470

lain's avatar
lain committed
471
472
473
      Enum.each(recipients, fn recipient ->
        CommonAPI.post_chat_message(user, recipient, "yo")
      end)
Alex Gleason's avatar
Alex Gleason committed
474
475
476
477

      %{user: user}
    end

lain's avatar
lain committed
478
    test "renders user's chats", %{conn: conn, user: user} do
Alex Gleason's avatar
Alex Gleason committed
479
480
481
482
483
484
      conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}/chats")

      assert json_response(conn, 200) |> length() == 3
    end
  end

485
486
487
  describe "GET /api/pleroma/admin/users/:nickname/chats unauthorized" do
    setup do
      user = insert(:user)
lain's avatar
lain committed
488
489
      recipient = insert(:user)
      CommonAPI.post_chat_message(user, recipient, "yo")
490
491
492
493
494
495
496
497
498
499
500
501
502
503
      %{conn: conn} = oauth_access(["read:chats"])
      %{conn: conn, user: user}
    end

    test "returns 403", %{conn: conn, user: user} do
      conn
      |> get("/api/pleroma/admin/users/#{user.nickname}/chats")
      |> json_response(403)
    end
  end

  describe "GET /api/pleroma/admin/users/:nickname/chats unauthenticated" do
    setup do
      user = insert(:user)
lain's avatar
lain committed
504
505
      recipient = insert(:user)
      CommonAPI.post_chat_message(user, recipient, "yo")
506
507
508
509
510
511
512
513
514
515
      %{conn: build_conn(), user: user}
    end

    test "returns 403", %{conn: conn, user: user} do
      conn
      |> get("/api/pleroma/admin/users/#{user.nickname}/chats")
      |> json_response(403)
    end
  end

Maxim Filippov's avatar
Maxim Filippov committed
516
  describe "GET /api/pleroma/admin/moderation_log" do
517
    setup do
518
      moderator = insert(:user, is_moderator: true)
Maxim Filippov's avatar
Maxim Filippov committed
519

520
      %{moderator: moderator}
Maxim Filippov's avatar
Maxim Filippov committed
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
    end

    test "returns the log", %{conn: conn, admin: admin} do
      Repo.insert(%ModerationLog{
        data: %{
          actor: %{
            "id" => admin.id,
            "nickname" => admin.nickname,
            "type" => "user"
          },
          action: "relay_follow",
          target: "https://example.org/relay"
        },
        inserted_at: NaiveDateTime.truncate(~N[2017-08-15 15:47:06.597036], :second)
      })

      Repo.insert(%ModerationLog{
        data: %{
          actor: %{
            "id" => admin.id,
            "nickname" => admin.nickname,
            "type" => "user"
          },
          action: "relay_unfollow",
          target: "https://example.org/relay"
        },
        inserted_at: NaiveDateTime.truncate(~N[2017-08-16 15:47:06.597036], :second)
      })

      conn = get(conn, "/api/pleroma/admin/moderation_log")

      response = json_response(conn, 200)
Maxim Filippov's avatar
Maxim Filippov committed
553
      [first_entry, second_entry] = response["items"]
Maxim Filippov's avatar
Maxim Filippov committed
554

Maxim Filippov's avatar
Maxim Filippov committed
555
      assert response["total"] == 2
Maxim Filippov's avatar
Maxim Filippov committed
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
      assert first_entry["data"]["action"] == "relay_unfollow"

      assert first_entry["message"] ==
               "@#{admin.nickname} unfollowed relay: https://example.org/relay"

      assert second_entry["data"]["action"] == "relay_follow"

      assert second_entry["message"] ==
               "@#{admin.nickname} followed relay: https://example.org/relay"
    end

    test "returns the log with pagination", %{conn: conn, admin: admin} do
      Repo.insert(%ModerationLog{
        data: %{
          actor: %{
            "id" => admin.id,
            "nickname" => admin.nickname,
            "type" => "user"
          },
          action: "relay_follow",
          target: "https://example.org/relay"
        },
        inserted_at: NaiveDateTime.truncate(~N[2017-08-15 15:47:06.597036], :second)
      })

      Repo.insert(%ModerationLog{
        data: %{
          actor: %{
            "id" => admin.id,
            "nickname" => admin.nickname,
            "type" => "user"
          },
          action: "relay_unfollow",
          target: "https://example.org/relay"
        },
        inserted_at: NaiveDateTime.truncate(~N[2017-08-16 15:47:06.597036], :second)
      })

      conn1 = get(conn, "/api/pleroma/admin/moderation_log?page_size=1&page=1")

      response1 = json_response(conn1, 200)
Maxim Filippov's avatar
Maxim Filippov committed
597
      [first_entry] = response1["items"]
Maxim Filippov's avatar
Maxim Filippov committed
598

Maxim Filippov's avatar
Maxim Filippov committed
599
600
      assert response1["total"] == 2
      assert response1["items"] |> length() == 1
Maxim Filippov's avatar
Maxim Filippov committed
601
602
603
604
605
606
607
608
      assert first_entry["data"]["action"] == "relay_unfollow"

      assert first_entry["message"] ==
               "@#{admin.nickname} unfollowed relay: https://example.org/relay"

      conn2 = get(conn, "/api/pleroma/admin/moderation_log?page_size=1&page=2")

      response2 = json_response(conn2, 200)
Maxim Filippov's avatar
Maxim Filippov committed
609
      [second_entry] = response2["items"]
Maxim Filippov's avatar
Maxim Filippov committed
610

Maxim Filippov's avatar
Maxim Filippov committed
611
612
      assert response2["total"] == 2
      assert response2["items"] |> length() == 1
Maxim Filippov's avatar
Maxim Filippov committed
613
614
615
616
617
      assert second_entry["data"]["action"] == "relay_follow"

      assert second_entry["message"] ==
               "@#{admin.nickname} followed relay: https://example.org/relay"
    end
Maxim Filippov's avatar
Maxim Filippov committed
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655

    test "filters log by date", %{conn: conn, admin: admin} do
      first_date = "2017-08-15T15:47:06Z"
      second_date = "2017-08-20T15:47:06Z"

      Repo.insert(%ModerationLog{
        data: %{
          actor: %{
            "id" => admin.id,
            "nickname" => admin.nickname,
            "type" => "user"
          },
          action: "relay_follow",
          target: "https://example.org/relay"
        },
        inserted_at: NaiveDateTime.from_iso8601!(first_date)
      })

      Repo.insert(%ModerationLog{
        data: %{
          actor: %{
            "id" => admin.id,
            "nickname" => admin.nickname,
            "type" => "user"
          },
          action: "relay_unfollow",
          target: "https://example.org/relay"
        },
        inserted_at: NaiveDateTime.from_iso8601!(second_date)
      })

      conn1 =
        get(
          conn,
          "/api/pleroma/admin/moderation_log?start_date=#{second_date}"
        )

      response1 = json_response(conn1, 200)
Maxim Filippov's avatar
Maxim Filippov committed
656
      [first_entry] = response1["items"]
Maxim Filippov's avatar
Maxim Filippov committed
657

Maxim Filippov's avatar
Maxim Filippov committed
658
      assert response1["total"] == 1
Maxim Filippov's avatar
Maxim Filippov committed
659
660
661
662
663
      assert first_entry["data"]["action"] == "relay_unfollow"

      assert first_entry["message"] ==
               "@#{admin.nickname} unfollowed relay: https://example.org/relay"
    end
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692

    test "returns log filtered by user", %{conn: conn, admin: admin, moderator: moderator} do
      Repo.insert(%ModerationLog{
        data: %{
          actor: %{
            "id" => admin.id,
            "nickname" => admin.nickname,
            "type" => "user"
          },
          action: "relay_follow",
          target: "https://example.org/relay"
        }
      })

      Repo.insert(%ModerationLog{
        data: %{
          actor: %{
            "id" => moderator.id,
            "nickname" => moderator.nickname,
            "type" => "user"
          },
          action: "relay_unfollow",
          target: "https://example.org/relay"
        }
      })

      conn1 = get(conn, "/api/pleroma/admin/moderation_log?user_id=#{moderator.id}")

      response1 = json_response(conn1, 200)
Maxim Filippov's avatar
Maxim Filippov committed
693
      [first_entry] = response1["items"]
694

Maxim Filippov's avatar
Maxim Filippov committed
695
      assert response1["total"] == 1
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
      assert get_in(first_entry, ["data", "actor", "id"]) == moderator.id
    end

    test "returns log filtered by search", %{conn: conn, moderator: moderator} do
      ModerationLog.insert_log(%{
        actor: moderator,
        action: "relay_follow",
        target: "https://example.org/relay"
      })

      ModerationLog.insert_log(%{
        actor: moderator,
        action: "relay_unfollow",
        target: "https://example.org/relay"
      })

      conn1 = get(conn, "/api/pleroma/admin/moderation_log?search=unfo")

      response1 = json_response(conn1, 200)
Maxim Filippov's avatar
Maxim Filippov committed
715
      [first_entry] = response1["items"]
716

Maxim Filippov's avatar
Maxim Filippov committed
717
      assert response1["total"] == 1
718
719
720
721

      assert get_in(first_entry, ["data", "message"]) ==
               "@#{moderator.nickname} unfollowed relay: https://example.org/relay"
    end
Maxim Filippov's avatar
Maxim Filippov committed
722
  end
723

724
725
726
727
728
729
730
731
732
  test "gets a remote users when [:instance, :limit_to_local_content] is set to :unauthenticated",
       %{conn: conn} do
    clear_config(Pleroma.Config.get([:instance, :limit_to_local_content]), :unauthenticated)
    user = insert(:user, %{local: false, nickname: "u@peer1.com"})
    conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}/credentials")

    assert json_response(conn, 200)
  end

733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
  describe "GET /users/:nickname/credentials" do
    test "gets the user credentials", %{conn: conn} do
      user = insert(:user)
      conn = get(conn, "/api/pleroma/admin/users/#{user.nickname}/credentials")

      response = assert json_response(conn, 200)
      assert response["email"] == user.email
    end

    test "returns 403 if requested by a non-admin" do
      user = insert(:user)

      conn =
        build_conn()
        |> assign(:user, user)
        |> get("/api/pleroma/admin/users/#{user.nickname}/credentials")

      assert json_response(conn, :forbidden)
    end
  end

  describe "PATCH /users/:nickname/credentials" do
Alexander Strizhakov's avatar
Alexander Strizhakov committed
755
    setup do
756
      user = insert(:user)
Alexander Strizhakov's avatar
Alexander Strizhakov committed
757
758
759
760
      [user: user]
    end

    test "changes password and email", %{conn: conn, admin: admin, user: user} do
761
762
763
      assert user.password_reset_pending == false

      conn =
764
765
766
767
        patch(conn, "/api/pleroma/admin/users/#{user.nickname}/credentials", %{
          "password" => "new_password",
          "email" => "new_email@example.com",
          "name" => "new_name"
768
769
770
771
772
773
        })

      assert json_response(conn, 200) == %{"status" => "success"}

      ObanHelpers.perform_all()

774
      updated_user = User.get_by_id(user.id)
775

776
777
778
779
780
781
      assert updated_user.email == "new_email@example.com"
      assert updated_user.name == "new_name"
      assert updated_user.password_hash != user.password_hash
      assert updated_user.password_reset_pending == true

      [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
787
788

      assert ModerationLog.get_log_entry_message(log_entry2) ==
               "@#{admin.nickname} forced password reset for users: @#{user.nickname}"
    end
789

Alexander Strizhakov's avatar
Alexander Strizhakov committed
790
    test "returns 403 if requested by a non-admin", %{user: user} do
791
792
793
794
795
796
797
798
799
800
801
      conn =
        build_conn()
        |> assign(:user, user)
        |> patch("/api/pleroma/admin/users/#{user.nickname}/credentials", %{
          "password" => "new_password",
          "email" => "new_email@example.com",
          "name" => "new_name"
        })

      assert json_response(conn, :forbidden)
    end
Alexander Strizhakov's avatar
Alexander Strizhakov committed
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817

    test "changes actor type from permitted list", %{conn: conn, user: user} do
      assert user.actor_type == "Person"

      assert patch(conn, "/api/pleroma/admin/users/#{user.nickname}/credentials", %{
               "actor_type" => "Service"
             })
             |> json_response(200) == %{"status" => "success"}

      updated_user = User.get_by_id(user.id)

      assert updated_user.actor_type == "Service"

      assert patch(conn, "/api/pleroma/admin/users/#{user.nickname}/credentials", %{
               "actor_type" => "Application"
             })
818
             |> json_response(400) == %{"errors" => %{"actor_type" => "is invalid"}}
Alexander Strizhakov's avatar
Alexander Strizhakov committed
819
820
821
822
823
824
    end

    test "update non existing user", %{conn: conn} do
      assert patch(conn, "/api/pleroma/admin/users/non-existing/credentials", %{
               "password" => "new_password"
             })
825
             |> json_response(404) == %{"error" => "Not found"}
Alexander Strizhakov's avatar
Alexander Strizhakov committed
826
    end
827
828
  end

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
840

      ObanHelpers.perform_all()

841
      assert User.get_by_id(user.id).password_reset_pending == true
842
843
    end
  end
844

845
  describe "instances" do
846
    test "GET /instances/:instance/statuses", %{conn: conn} do
847
848
849
      user = insert(:user, local: false, nickname: "archaeme@archae.me")
      user2 = insert(:user, local: false, nickname: "test@test.com")
      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
857

      assert length(response) == 2

858
      ret_conn = get(conn, "/api/pleroma/admin/instances/test.com/statuses")
859

860
      response = json_response(ret_conn, 200)
861
862
863

      assert length(response) == 1

864
      ret_conn = get(conn, "/api/pleroma/admin/instances/nonexistent.com/statuses")
865

866
      response = json_response(ret_conn, 200)
867

Haelwenn's avatar
Haelwenn committed
868
      assert Enum.empty?(response)
869
870
871
872
873
874
875
876
877
878

      CommonAPI.repeat(activity.id, user)

      ret_conn = get(conn, "/api/pleroma/admin/instances/archae.me/statuses")
      response = json_response(ret_conn, 200)
      assert length(response) == 2

      ret_conn = get(conn, "/api/pleroma/admin/instances/archae.me/statuses?with_reblogs=true")
      response = json_response(ret_conn, 200)
      assert length(response) == 3
879
880
    end
  end
881

882
  describe "PATCH /confirm_email" do
883
    test "it confirms emails of two users", %{conn: conn, admin: admin} do
884
885
886
887
888
      [first_user, second_user] = insert_pair(:user, confirmation_pending: true)

      assert first_user.confirmation_pending == true
      assert second_user.confirmation_pending == true

889
890
891
892
893
894
895
896
897
      ret_conn =
        patch(conn, "/api/pleroma/admin/users/confirm_email", %{
          nicknames: [
            first_user.nickname,
            second_user.nickname
          ]
        })

      assert ret_conn.status == 200
898
899
900
901
902
903
904
905
906
907
908
909
910
911

      assert first_user.confirmation_pending == true
      assert second_user.confirmation_pending == true

      log_entry = Repo.one(ModerationLog)

      assert ModerationLog.get_log_entry_message(log_entry) ==
               "@#{admin.nickname} confirmed email for users: @#{first_user.nickname}, @#{
                 second_user.nickname
               }"
    end
  end

  describe "PATCH /resend_confirmation_email" do
912
    test "it resend emails for two users", %{conn: conn, admin: admin} do
913
914
      [first_user, second_user] = insert_pair(:user, confirmation_pending: true)

915
916
917
918
919
920
921
922
923
      ret_conn =
        patch(conn, "/api/pleroma/admin/users/resend_confirmation_email", %{
          nicknames: [
            first_user.nickname,
            second_user.nickname
          ]
        })

      assert ret_conn.status == 200
924
925
926
927
928
929
930

      log_entry = Repo.one(ModerationLog)

      assert ModerationLog.get_log_entry_message(log_entry) ==
               "@#{admin.nickname} re-sent confirmation email for users: @#{first_user.nickname}, @#{
                 second_user.nickname
               }"
931
932

      ObanHelpers.perform_all()
933
934
935
936
937
938

      Pleroma.Emails.UserEmail.account_confirmation_email(first_user)
      # temporary hackney fix until hackney max_connections bug is fixed
      # https://git.pleroma.social/pleroma/pleroma/-/issues/2101
      |> Swoosh.Email.put_private(:hackney_options, ssl_options: [versions: [:"tlsv1.2"]])
      |> assert_email_sent()
939
940
    end
  end
Maxim Filippov's avatar
Maxim Filippov committed
941

942
943
944
945
  describe "/api/pleroma/admin/stats" do
    test "status visibility count", %{conn: conn} do
      admin = insert(:user, is_admin: true)
      user = insert(:user)
946
947
948
      CommonAPI.post(user, %{visibility: "public", status: "hey"})
      CommonAPI.post(user, %{visibility: "unlisted", status: "hey"})
      CommonAPI.post(user, %{visibility: "unlisted", status: "hey"})
949
950
951
952
953
954
955
956
957
958

      response =
        conn
        |> assign(:user, admin)
        |> get("/api/pleroma/admin/stats")
        |> json_response(200)

      assert %{"direct" => 0, "private" => 0, "public" => 1, "unlisted" => 2} =
               response["status_visibility"]
    end
Roman Chvanikov's avatar
Roman Chvanikov committed
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978

    test "by instance", %{conn: conn} do
      admin = insert(:user, is_admin: true)
      user1 = insert(:user)
      instance2 = "instance2.tld"
      user2 = insert(:user, %{ap_id: "https://#{instance2}/@actor"})

      CommonAPI.post(user1, %{visibility: "public", status: "hey"})
      CommonAPI.post(user2, %{visibility: "unlisted", status: "hey"})
      CommonAPI.post(user2, %{visibility: "private", status: "hey"})

      response =
        conn
        |> assign(:user, admin)
        |> get("/api/pleroma/admin/stats", instance: instance2)
        |> json_response(200)

      assert %{"direct" => 0, "private" => 1, "public" => 0, "unlisted" => 1} =
               response["status_visibility"]
    end
979
  end
980
end
981
982
983
984
985
986
987

# Needed for testing
defmodule Pleroma.Web.Endpoint.NotReal do
end

defmodule Pleroma.Captcha.NotReal do
end