logo

pleroma

My custom branche(s) on git.pleroma.social/pleroma/pleroma git clone https://hacktivis.me/git/pleroma.git

admin_api_controller_test.exs (37334B)


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