logo

pleroma

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

admin_api_controller.ex (11826B)


  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.AdminAPIController do
  5. use Pleroma.Web, :controller
  6. import Pleroma.Web.ControllerHelper,
  7. only: [json_response: 3, fetch_integer_param: 3]
  8. alias Pleroma.Config
  9. alias Pleroma.MFA
  10. alias Pleroma.ModerationLog
  11. alias Pleroma.Stats
  12. alias Pleroma.User
  13. alias Pleroma.Web.ActivityPub.ActivityPub
  14. alias Pleroma.Web.AdminAPI
  15. alias Pleroma.Web.AdminAPI.AccountView
  16. alias Pleroma.Web.AdminAPI.ModerationLogView
  17. alias Pleroma.Web.Endpoint
  18. alias Pleroma.Web.Plugs.OAuthScopesPlug
  19. alias Pleroma.Web.Router
  20. @users_page_size 50
  21. plug(
  22. OAuthScopesPlug,
  23. %{scopes: ["admin:read:accounts"]}
  24. when action in [:right_get, :show_user_credentials, :create_backup]
  25. )
  26. plug(
  27. OAuthScopesPlug,
  28. %{scopes: ["admin:write:accounts"]}
  29. when action in [
  30. :get_password_reset,
  31. :force_password_reset,
  32. :tag_users,
  33. :untag_users,
  34. :right_add,
  35. :right_add_multiple,
  36. :right_delete,
  37. :disable_mfa,
  38. :right_delete_multiple,
  39. :update_user_credentials
  40. ]
  41. )
  42. plug(
  43. OAuthScopesPlug,
  44. %{scopes: ["admin:read:statuses"]}
  45. when action in [:list_user_statuses]
  46. )
  47. plug(
  48. OAuthScopesPlug,
  49. %{scopes: ["admin:read:chats"]}
  50. when action in [:list_user_chats]
  51. )
  52. plug(
  53. OAuthScopesPlug,
  54. %{scopes: ["admin:read"]}
  55. when action in [
  56. :list_log,
  57. :stats,
  58. :need_reboot
  59. ]
  60. )
  61. plug(
  62. OAuthScopesPlug,
  63. %{scopes: ["admin:write"]}
  64. when action in [
  65. :restart,
  66. :resend_confirmation_email,
  67. :confirm_email,
  68. :reload_emoji
  69. ]
  70. )
  71. action_fallback(AdminAPI.FallbackController)
  72. def list_user_statuses(%{assigns: %{user: admin}} = conn, %{"nickname" => nickname} = params) do
  73. with_reblogs = params["with_reblogs"] == "true" || params["with_reblogs"] == true
  74. godmode = params["godmode"] == "true" || params["godmode"] == true
  75. with %User{} = user <- User.get_cached_by_nickname_or_id(nickname, for: admin) do
  76. {page, page_size} = page_params(params)
  77. result =
  78. ActivityPub.fetch_user_activities(user, nil, %{
  79. limit: page_size,
  80. offset: (page - 1) * page_size,
  81. godmode: godmode,
  82. exclude_reblogs: not with_reblogs,
  83. pagination_type: :offset,
  84. total: true
  85. })
  86. conn
  87. |> put_view(AdminAPI.StatusView)
  88. |> render("index.json", %{total: result[:total], activities: result[:items], as: :activity})
  89. else
  90. _ -> {:error, :not_found}
  91. end
  92. end
  93. def list_user_chats(%{assigns: %{user: admin}} = conn, %{"nickname" => nickname} = _params) do
  94. with %User{id: user_id} <- User.get_cached_by_nickname_or_id(nickname, for: admin) do
  95. chats =
  96. Pleroma.Chat.for_user_query(user_id)
  97. |> Pleroma.Repo.all()
  98. conn
  99. |> put_view(AdminAPI.ChatView)
  100. |> render("index.json", chats: chats)
  101. else
  102. _ -> {:error, :not_found}
  103. end
  104. end
  105. def tag_users(%{assigns: %{user: admin}} = conn, %{"nicknames" => nicknames, "tags" => tags}) do
  106. with {:ok, _} <- User.tag(nicknames, tags) do
  107. ModerationLog.insert_log(%{
  108. actor: admin,
  109. nicknames: nicknames,
  110. tags: tags,
  111. action: "tag"
  112. })
  113. json_response(conn, :no_content, "")
  114. end
  115. end
  116. def untag_users(%{assigns: %{user: admin}} = conn, %{"nicknames" => nicknames, "tags" => tags}) do
  117. with {:ok, _} <- User.untag(nicknames, tags) do
  118. ModerationLog.insert_log(%{
  119. actor: admin,
  120. nicknames: nicknames,
  121. tags: tags,
  122. action: "untag"
  123. })
  124. json_response(conn, :no_content, "")
  125. end
  126. end
  127. def right_add_multiple(%{assigns: %{user: admin}} = conn, %{
  128. "permission_group" => permission_group,
  129. "nicknames" => nicknames
  130. })
  131. when permission_group in ["moderator", "admin"] do
  132. update = %{:"is_#{permission_group}" => true}
  133. users = nicknames |> Enum.map(&User.get_cached_by_nickname/1)
  134. for u <- users, do: User.admin_api_update(u, update)
  135. ModerationLog.insert_log(%{
  136. action: "grant",
  137. actor: admin,
  138. subject: users,
  139. permission: permission_group
  140. })
  141. json(conn, update)
  142. end
  143. def right_add_multiple(conn, _) do
  144. render_error(conn, :not_found, "No such permission_group")
  145. end
  146. def right_add(%{assigns: %{user: admin}} = conn, %{
  147. "permission_group" => permission_group,
  148. "nickname" => nickname
  149. })
  150. when permission_group in ["moderator", "admin"] do
  151. fields = %{:"is_#{permission_group}" => true}
  152. {:ok, user} =
  153. nickname
  154. |> User.get_cached_by_nickname()
  155. |> User.admin_api_update(fields)
  156. ModerationLog.insert_log(%{
  157. action: "grant",
  158. actor: admin,
  159. subject: [user],
  160. permission: permission_group
  161. })
  162. json(conn, fields)
  163. end
  164. def right_add(conn, _) do
  165. render_error(conn, :not_found, "No such permission_group")
  166. end
  167. def right_get(conn, %{"nickname" => nickname}) do
  168. user = User.get_cached_by_nickname(nickname)
  169. conn
  170. |> json(%{
  171. is_moderator: user.is_moderator,
  172. is_admin: user.is_admin
  173. })
  174. end
  175. def right_delete_multiple(
  176. %{assigns: %{user: %{nickname: admin_nickname} = admin}} = conn,
  177. %{
  178. "permission_group" => permission_group,
  179. "nicknames" => nicknames
  180. }
  181. )
  182. when permission_group in ["moderator", "admin"] do
  183. with false <- Enum.member?(nicknames, admin_nickname) do
  184. update = %{:"is_#{permission_group}" => false}
  185. users = nicknames |> Enum.map(&User.get_cached_by_nickname/1)
  186. for u <- users, do: User.admin_api_update(u, update)
  187. ModerationLog.insert_log(%{
  188. action: "revoke",
  189. actor: admin,
  190. subject: users,
  191. permission: permission_group
  192. })
  193. json(conn, update)
  194. else
  195. _ -> render_error(conn, :forbidden, "You can't revoke your own admin/moderator status.")
  196. end
  197. end
  198. def right_delete_multiple(conn, _) do
  199. render_error(conn, :not_found, "No such permission_group")
  200. end
  201. def right_delete(
  202. %{assigns: %{user: admin}} = conn,
  203. %{
  204. "permission_group" => permission_group,
  205. "nickname" => nickname
  206. }
  207. )
  208. when permission_group in ["moderator", "admin"] do
  209. fields = %{:"is_#{permission_group}" => false}
  210. {:ok, user} =
  211. nickname
  212. |> User.get_cached_by_nickname()
  213. |> User.admin_api_update(fields)
  214. ModerationLog.insert_log(%{
  215. action: "revoke",
  216. actor: admin,
  217. subject: [user],
  218. permission: permission_group
  219. })
  220. json(conn, fields)
  221. end
  222. def right_delete(%{assigns: %{user: %{nickname: nickname}}} = conn, %{"nickname" => nickname}) do
  223. render_error(conn, :forbidden, "You can't revoke your own admin status.")
  224. end
  225. @doc "Get a password reset token (base64 string) for given nickname"
  226. def get_password_reset(conn, %{"nickname" => nickname}) do
  227. (%User{local: true} = user) = User.get_cached_by_nickname(nickname)
  228. {:ok, token} = Pleroma.PasswordResetToken.create_token(user)
  229. conn
  230. |> json(%{
  231. token: token.token,
  232. link: Router.Helpers.reset_password_url(Endpoint, :reset, token.token)
  233. })
  234. end
  235. @doc "Force password reset for a given user"
  236. def force_password_reset(%{assigns: %{user: admin}} = conn, %{"nicknames" => nicknames}) do
  237. users = nicknames |> Enum.map(&User.get_cached_by_nickname/1)
  238. Enum.each(users, &User.force_password_reset_async/1)
  239. ModerationLog.insert_log(%{
  240. actor: admin,
  241. subject: users,
  242. action: "force_password_reset"
  243. })
  244. json_response(conn, :no_content, "")
  245. end
  246. @doc "Disable mfa for user's account."
  247. def disable_mfa(conn, %{"nickname" => nickname}) do
  248. case User.get_by_nickname(nickname) do
  249. %User{} = user ->
  250. MFA.disable(user)
  251. json(conn, nickname)
  252. _ ->
  253. {:error, :not_found}
  254. end
  255. end
  256. @doc "Show a given user's credentials"
  257. def show_user_credentials(%{assigns: %{user: admin}} = conn, %{"nickname" => nickname}) do
  258. with %User{} = user <- User.get_cached_by_nickname_or_id(nickname, for: admin) do
  259. conn
  260. |> put_view(AccountView)
  261. |> render("credentials.json", %{user: user, for: admin})
  262. else
  263. _ -> {:error, :not_found}
  264. end
  265. end
  266. @doc "Updates a given user"
  267. def update_user_credentials(
  268. %{assigns: %{user: admin}} = conn,
  269. %{"nickname" => nickname} = params
  270. ) do
  271. with {_, %User{} = user} <- {:user, User.get_cached_by_nickname(nickname)},
  272. {:ok, _user} <-
  273. User.update_as_admin(user, params) do
  274. ModerationLog.insert_log(%{
  275. actor: admin,
  276. subject: [user],
  277. action: "updated_users"
  278. })
  279. if params["password"] do
  280. User.force_password_reset_async(user)
  281. end
  282. ModerationLog.insert_log(%{
  283. actor: admin,
  284. subject: [user],
  285. action: "force_password_reset"
  286. })
  287. json(conn, %{status: "success"})
  288. else
  289. {:error, changeset} ->
  290. errors = Map.new(changeset.errors, fn {key, {error, _}} -> {key, error} end)
  291. {:errors, errors}
  292. _ ->
  293. {:error, :not_found}
  294. end
  295. end
  296. def list_log(conn, params) do
  297. {page, page_size} = page_params(params)
  298. log =
  299. ModerationLog.get_all(%{
  300. page: page,
  301. page_size: page_size,
  302. start_date: params["start_date"],
  303. end_date: params["end_date"],
  304. user_id: params["user_id"],
  305. search: params["search"]
  306. })
  307. conn
  308. |> put_view(ModerationLogView)
  309. |> render("index.json", %{log: log})
  310. end
  311. def restart(conn, _params) do
  312. with :ok <- configurable_from_database() do
  313. Restarter.Pleroma.restart(Config.get(:env), 50)
  314. json(conn, %{})
  315. end
  316. end
  317. def need_reboot(conn, _params) do
  318. json(conn, %{need_reboot: Restarter.Pleroma.need_reboot?()})
  319. end
  320. defp configurable_from_database do
  321. if Config.get(:configurable_from_database) do
  322. :ok
  323. else
  324. {:error, "You must enable configurable_from_database in your config file."}
  325. end
  326. end
  327. def reload_emoji(conn, _params) do
  328. Pleroma.Emoji.reload()
  329. json(conn, "ok")
  330. end
  331. def confirm_email(%{assigns: %{user: admin}} = conn, %{"nicknames" => nicknames}) do
  332. users = Enum.map(nicknames, &User.get_cached_by_nickname/1)
  333. User.confirm(users)
  334. ModerationLog.insert_log(%{actor: admin, subject: users, action: "confirm_email"})
  335. json(conn, "")
  336. end
  337. def resend_confirmation_email(%{assigns: %{user: admin}} = conn, %{"nicknames" => nicknames}) do
  338. users =
  339. Enum.map(nicknames, fn nickname ->
  340. nickname
  341. |> User.get_cached_by_nickname()
  342. |> User.send_confirmation_email()
  343. end)
  344. ModerationLog.insert_log(%{actor: admin, subject: users, action: "resend_confirmation_email"})
  345. json(conn, "")
  346. end
  347. def stats(conn, params) do
  348. counters = Stats.get_status_visibility_count(params["instance"])
  349. json(conn, %{"status_visibility" => counters})
  350. end
  351. def create_backup(%{assigns: %{user: admin}} = conn, %{"nickname" => nickname}) do
  352. with %User{} = user <- User.get_by_nickname(nickname),
  353. {:ok, _} <- Pleroma.User.Backup.create(user, admin.id) do
  354. ModerationLog.insert_log(%{actor: admin, subject: user, action: "create_backup"})
  355. json(conn, "")
  356. end
  357. end
  358. defp page_params(params) do
  359. {
  360. fetch_integer_param(params, "page", 1),
  361. fetch_integer_param(params, "page_size", @users_page_size)
  362. }
  363. end
  364. end