Fork of Pleroma with site-specific changes and feature branches https://git.pleroma.social/pleroma/pleroma
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1533 lines
49KB

  1. # Pleroma: A lightweight social networking server
  2. # Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
  3. # SPDX-License-Identifier: AGPL-3.0-only
  4. defmodule Pleroma.Web.AdminAPI.ConfigControllerTest do
  5. use Pleroma.Web.ConnCase
  6. import ExUnit.CaptureLog
  7. import Pleroma.Factory
  8. alias Pleroma.ConfigDB
  9. setup do
  10. admin = insert(:user, is_admin: true)
  11. token = insert(:oauth_admin_token, user: admin)
  12. conn =
  13. build_conn()
  14. |> assign(:user, admin)
  15. |> assign(:token, token)
  16. {:ok, %{admin: admin, token: token, conn: conn}}
  17. end
  18. describe "GET /api/pleroma/admin/config" do
  19. setup do: clear_config(:configurable_from_database, true)
  20. test "when configuration from database is off", %{conn: conn} do
  21. clear_config(:configurable_from_database, false)
  22. conn = get(conn, "/api/pleroma/admin/config")
  23. assert json_response_and_validate_schema(conn, 400) ==
  24. %{
  25. "error" => "You must enable configurable_from_database in your config file."
  26. }
  27. end
  28. test "with settings only in db", %{conn: conn} do
  29. config1 = insert(:config)
  30. config2 = insert(:config)
  31. conn = get(conn, "/api/pleroma/admin/config?only_db=true")
  32. %{
  33. "configs" => [
  34. %{
  35. "group" => ":pleroma",
  36. "key" => key1,
  37. "value" => _
  38. },
  39. %{
  40. "group" => ":pleroma",
  41. "key" => key2,
  42. "value" => _
  43. }
  44. ]
  45. } = json_response_and_validate_schema(conn, 200)
  46. assert key1 == inspect(config1.key)
  47. assert key2 == inspect(config2.key)
  48. end
  49. test "db is added to settings that are in db", %{conn: conn} do
  50. _config = insert(:config, key: ":instance", value: [name: "Some name"])
  51. %{"configs" => configs} =
  52. conn
  53. |> get("/api/pleroma/admin/config")
  54. |> json_response_and_validate_schema(200)
  55. [instance_config] =
  56. Enum.filter(configs, fn %{"group" => group, "key" => key} ->
  57. group == ":pleroma" and key == ":instance"
  58. end)
  59. assert instance_config["db"] == [":name"]
  60. end
  61. test "merged default setting with db settings", %{conn: conn} do
  62. config1 = insert(:config)
  63. config2 = insert(:config)
  64. config3 =
  65. insert(:config,
  66. value: [k1: :v1, k2: :v2]
  67. )
  68. %{"configs" => configs} =
  69. conn
  70. |> get("/api/pleroma/admin/config")
  71. |> json_response_and_validate_schema(200)
  72. assert length(configs) > 3
  73. saved_configs = [config1, config2, config3]
  74. keys = Enum.map(saved_configs, &inspect(&1.key))
  75. received_configs =
  76. Enum.filter(configs, fn %{"group" => group, "key" => key} ->
  77. group == ":pleroma" and key in keys
  78. end)
  79. assert length(received_configs) == 3
  80. db_keys =
  81. config3.value
  82. |> Keyword.keys()
  83. |> ConfigDB.to_json_types()
  84. keys = Enum.map(saved_configs -- [config3], &inspect(&1.key))
  85. values = Enum.map(saved_configs, &ConfigDB.to_json_types(&1.value))
  86. mapset_keys = MapSet.new(keys ++ db_keys)
  87. Enum.each(received_configs, fn %{"value" => value, "db" => db} ->
  88. db = MapSet.new(db)
  89. assert MapSet.subset?(db, mapset_keys)
  90. assert value in values
  91. end)
  92. end
  93. test "subkeys with full update right merge", %{conn: conn} do
  94. insert(:config,
  95. key: ":emoji",
  96. value: [groups: [a: 1, b: 2], key: [a: 1]]
  97. )
  98. insert(:config,
  99. key: ":assets",
  100. value: [mascots: [a: 1, b: 2], key: [a: 1]]
  101. )
  102. %{"configs" => configs} =
  103. conn
  104. |> get("/api/pleroma/admin/config")
  105. |> json_response_and_validate_schema(200)
  106. vals =
  107. Enum.filter(configs, fn %{"group" => group, "key" => key} ->
  108. group == ":pleroma" and key in [":emoji", ":assets"]
  109. end)
  110. emoji = Enum.find(vals, fn %{"key" => key} -> key == ":emoji" end)
  111. assets = Enum.find(vals, fn %{"key" => key} -> key == ":assets" end)
  112. emoji_val = ConfigDB.to_elixir_types(emoji["value"])
  113. assets_val = ConfigDB.to_elixir_types(assets["value"])
  114. assert emoji_val[:groups] == [a: 1, b: 2]
  115. assert assets_val[:mascots] == [a: 1, b: 2]
  116. end
  117. test "with valid `admin_token` query parameter, skips OAuth scopes check" do
  118. clear_config([:admin_token], "password123")
  119. build_conn()
  120. |> get("/api/pleroma/admin/config?admin_token=password123")
  121. |> json_response_and_validate_schema(200)
  122. end
  123. end
  124. test "POST /api/pleroma/admin/config with configdb disabled", %{conn: conn} do
  125. clear_config(:configurable_from_database, false)
  126. conn =
  127. conn
  128. |> put_req_header("content-type", "application/json")
  129. |> post("/api/pleroma/admin/config", %{"configs" => []})
  130. assert json_response_and_validate_schema(conn, 400) ==
  131. %{"error" => "You must enable configurable_from_database in your config file."}
  132. end
  133. describe "POST /api/pleroma/admin/config" do
  134. setup do
  135. http = Application.get_env(:pleroma, :http)
  136. on_exit(fn ->
  137. Application.delete_env(:pleroma, :key1)
  138. Application.delete_env(:pleroma, :key2)
  139. Application.delete_env(:pleroma, :key3)
  140. Application.delete_env(:pleroma, :key4)
  141. Application.delete_env(:pleroma, :keyaa1)
  142. Application.delete_env(:pleroma, :keyaa2)
  143. Application.delete_env(:pleroma, Pleroma.Web.Endpoint.NotReal)
  144. Application.delete_env(:pleroma, Pleroma.Captcha.NotReal)
  145. Application.put_env(:pleroma, :http, http)
  146. Application.put_env(:tesla, :adapter, Tesla.Mock)
  147. Restarter.Pleroma.refresh()
  148. end)
  149. end
  150. setup do: clear_config(:configurable_from_database, true)
  151. @tag capture_log: true
  152. test "create new config setting in db", %{conn: conn} do
  153. ueberauth = Application.get_env(:ueberauth, Ueberauth)
  154. on_exit(fn -> Application.put_env(:ueberauth, Ueberauth, ueberauth) end)
  155. conn =
  156. conn
  157. |> put_req_header("content-type", "application/json")
  158. |> post("/api/pleroma/admin/config", %{
  159. configs: [
  160. %{group: ":pleroma", key: ":key1", value: "value1"},
  161. %{
  162. group: ":ueberauth",
  163. key: "Ueberauth",
  164. value: [%{"tuple" => [":consumer_secret", "aaaa"]}]
  165. },
  166. %{
  167. group: ":pleroma",
  168. key: ":key2",
  169. value: %{
  170. ":nested_1" => "nested_value1",
  171. ":nested_2" => [
  172. %{":nested_22" => "nested_value222"},
  173. %{":nested_33" => %{":nested_44" => "nested_444"}}
  174. ]
  175. }
  176. },
  177. %{
  178. group: ":pleroma",
  179. key: ":key3",
  180. value: [
  181. %{"nested_3" => ":nested_3", "nested_33" => "nested_33"},
  182. %{"nested_4" => true}
  183. ]
  184. },
  185. %{
  186. group: ":pleroma",
  187. key: ":key4",
  188. value: %{":nested_5" => ":upload", "endpoint" => "https://example.com"}
  189. },
  190. %{
  191. group: ":idna",
  192. key: ":key5",
  193. value: %{"tuple" => ["string", "Pleroma.Captcha.NotReal", []]}
  194. }
  195. ]
  196. })
  197. assert json_response_and_validate_schema(conn, 200) == %{
  198. "configs" => [
  199. %{
  200. "group" => ":pleroma",
  201. "key" => ":key1",
  202. "value" => "value1",
  203. "db" => [":key1"]
  204. },
  205. %{
  206. "group" => ":ueberauth",
  207. "key" => "Ueberauth",
  208. "value" => [%{"tuple" => [":consumer_secret", "aaaa"]}],
  209. "db" => [":consumer_secret"]
  210. },
  211. %{
  212. "group" => ":pleroma",
  213. "key" => ":key2",
  214. "value" => %{
  215. ":nested_1" => "nested_value1",
  216. ":nested_2" => [
  217. %{":nested_22" => "nested_value222"},
  218. %{":nested_33" => %{":nested_44" => "nested_444"}}
  219. ]
  220. },
  221. "db" => [":key2"]
  222. },
  223. %{
  224. "group" => ":pleroma",
  225. "key" => ":key3",
  226. "value" => [
  227. %{"nested_3" => ":nested_3", "nested_33" => "nested_33"},
  228. %{"nested_4" => true}
  229. ],
  230. "db" => [":key3"]
  231. },
  232. %{
  233. "group" => ":pleroma",
  234. "key" => ":key4",
  235. "value" => %{"endpoint" => "https://example.com", ":nested_5" => ":upload"},
  236. "db" => [":key4"]
  237. },
  238. %{
  239. "group" => ":idna",
  240. "key" => ":key5",
  241. "value" => %{"tuple" => ["string", "Pleroma.Captcha.NotReal", []]},
  242. "db" => [":key5"]
  243. }
  244. ],
  245. "need_reboot" => false
  246. }
  247. assert Application.get_env(:pleroma, :key1) == "value1"
  248. assert Application.get_env(:pleroma, :key2) == %{
  249. nested_1: "nested_value1",
  250. nested_2: [
  251. %{nested_22: "nested_value222"},
  252. %{nested_33: %{nested_44: "nested_444"}}
  253. ]
  254. }
  255. assert Application.get_env(:pleroma, :key3) == [
  256. %{"nested_3" => :nested_3, "nested_33" => "nested_33"},
  257. %{"nested_4" => true}
  258. ]
  259. assert Application.get_env(:pleroma, :key4) == %{
  260. "endpoint" => "https://example.com",
  261. nested_5: :upload
  262. }
  263. assert Application.get_env(:idna, :key5) == {"string", Pleroma.Captcha.NotReal, []}
  264. end
  265. test "save configs setting without explicit key", %{conn: conn} do
  266. level = Application.get_env(:quack, :level)
  267. meta = Application.get_env(:quack, :meta)
  268. webhook_url = Application.get_env(:quack, :webhook_url)
  269. on_exit(fn ->
  270. Application.put_env(:quack, :level, level)
  271. Application.put_env(:quack, :meta, meta)
  272. Application.put_env(:quack, :webhook_url, webhook_url)
  273. end)
  274. conn =
  275. conn
  276. |> put_req_header("content-type", "application/json")
  277. |> post("/api/pleroma/admin/config", %{
  278. configs: [
  279. %{
  280. group: ":quack",
  281. key: ":level",
  282. value: ":info"
  283. },
  284. %{
  285. group: ":quack",
  286. key: ":meta",
  287. value: [":none"]
  288. },
  289. %{
  290. group: ":quack",
  291. key: ":webhook_url",
  292. value: "https://hooks.slack.com/services/KEY"
  293. }
  294. ]
  295. })
  296. assert json_response_and_validate_schema(conn, 200) == %{
  297. "configs" => [
  298. %{
  299. "group" => ":quack",
  300. "key" => ":level",
  301. "value" => ":info",
  302. "db" => [":level"]
  303. },
  304. %{
  305. "group" => ":quack",
  306. "key" => ":meta",
  307. "value" => [":none"],
  308. "db" => [":meta"]
  309. },
  310. %{
  311. "group" => ":quack",
  312. "key" => ":webhook_url",
  313. "value" => "https://hooks.slack.com/services/KEY",
  314. "db" => [":webhook_url"]
  315. }
  316. ],
  317. "need_reboot" => false
  318. }
  319. assert Application.get_env(:quack, :level) == :info
  320. assert Application.get_env(:quack, :meta) == [:none]
  321. assert Application.get_env(:quack, :webhook_url) == "https://hooks.slack.com/services/KEY"
  322. end
  323. test "saving config with partial update", %{conn: conn} do
  324. insert(:config, key: ":key1", value: :erlang.term_to_binary(key1: 1, key2: 2))
  325. conn =
  326. conn
  327. |> put_req_header("content-type", "application/json")
  328. |> post("/api/pleroma/admin/config", %{
  329. configs: [
  330. %{group: ":pleroma", key: ":key1", value: [%{"tuple" => [":key3", 3]}]}
  331. ]
  332. })
  333. assert json_response_and_validate_schema(conn, 200) == %{
  334. "configs" => [
  335. %{
  336. "group" => ":pleroma",
  337. "key" => ":key1",
  338. "value" => [
  339. %{"tuple" => [":key1", 1]},
  340. %{"tuple" => [":key2", 2]},
  341. %{"tuple" => [":key3", 3]}
  342. ],
  343. "db" => [":key1", ":key2", ":key3"]
  344. }
  345. ],
  346. "need_reboot" => false
  347. }
  348. end
  349. test "saving config which need pleroma reboot", %{conn: conn} do
  350. clear_config([:shout, :enabled], true)
  351. assert conn
  352. |> put_req_header("content-type", "application/json")
  353. |> post(
  354. "/api/pleroma/admin/config",
  355. %{
  356. configs: [
  357. %{group: ":pleroma", key: ":shout", value: [%{"tuple" => [":enabled", true]}]}
  358. ]
  359. }
  360. )
  361. |> json_response_and_validate_schema(200) == %{
  362. "configs" => [
  363. %{
  364. "db" => [":enabled"],
  365. "group" => ":pleroma",
  366. "key" => ":shout",
  367. "value" => [%{"tuple" => [":enabled", true]}]
  368. }
  369. ],
  370. "need_reboot" => true
  371. }
  372. configs =
  373. conn
  374. |> get("/api/pleroma/admin/config")
  375. |> json_response_and_validate_schema(200)
  376. assert configs["need_reboot"]
  377. capture_log(fn ->
  378. assert conn |> get("/api/pleroma/admin/restart") |> json_response(200) ==
  379. %{}
  380. end) =~ "pleroma restarted"
  381. configs =
  382. conn
  383. |> get("/api/pleroma/admin/config")
  384. |> json_response_and_validate_schema(200)
  385. assert configs["need_reboot"] == false
  386. end
  387. test "update setting which need reboot, don't change reboot flag until reboot", %{conn: conn} do
  388. clear_config([:shout, :enabled], true)
  389. assert conn
  390. |> put_req_header("content-type", "application/json")
  391. |> post(
  392. "/api/pleroma/admin/config",
  393. %{
  394. configs: [
  395. %{group: ":pleroma", key: ":shout", value: [%{"tuple" => [":enabled", true]}]}
  396. ]
  397. }
  398. )
  399. |> json_response_and_validate_schema(200) == %{
  400. "configs" => [
  401. %{
  402. "db" => [":enabled"],
  403. "group" => ":pleroma",
  404. "key" => ":shout",
  405. "value" => [%{"tuple" => [":enabled", true]}]
  406. }
  407. ],
  408. "need_reboot" => true
  409. }
  410. assert conn
  411. |> put_req_header("content-type", "application/json")
  412. |> post("/api/pleroma/admin/config", %{
  413. configs: [
  414. %{group: ":pleroma", key: ":key1", value: [%{"tuple" => [":key3", 3]}]}
  415. ]
  416. })
  417. |> json_response_and_validate_schema(200) == %{
  418. "configs" => [
  419. %{
  420. "group" => ":pleroma",
  421. "key" => ":key1",
  422. "value" => [
  423. %{"tuple" => [":key3", 3]}
  424. ],
  425. "db" => [":key3"]
  426. }
  427. ],
  428. "need_reboot" => true
  429. }
  430. capture_log(fn ->
  431. assert conn |> get("/api/pleroma/admin/restart") |> json_response(200) ==
  432. %{}
  433. end) =~ "pleroma restarted"
  434. configs =
  435. conn
  436. |> get("/api/pleroma/admin/config")
  437. |> json_response_and_validate_schema(200)
  438. assert configs["need_reboot"] == false
  439. end
  440. test "saving config with nested merge", %{conn: conn} do
  441. insert(:config, key: :key1, value: [key1: 1, key2: [k1: 1, k2: 2]])
  442. conn =
  443. conn
  444. |> put_req_header("content-type", "application/json")
  445. |> post("/api/pleroma/admin/config", %{
  446. configs: [
  447. %{
  448. group: ":pleroma",
  449. key: ":key1",
  450. value: [
  451. %{"tuple" => [":key3", 3]},
  452. %{
  453. "tuple" => [
  454. ":key2",
  455. [
  456. %{"tuple" => [":k2", 1]},
  457. %{"tuple" => [":k3", 3]}
  458. ]
  459. ]
  460. }
  461. ]
  462. }
  463. ]
  464. })
  465. assert json_response_and_validate_schema(conn, 200) == %{
  466. "configs" => [
  467. %{
  468. "group" => ":pleroma",
  469. "key" => ":key1",
  470. "value" => [
  471. %{"tuple" => [":key1", 1]},
  472. %{"tuple" => [":key3", 3]},
  473. %{
  474. "tuple" => [
  475. ":key2",
  476. [
  477. %{"tuple" => [":k1", 1]},
  478. %{"tuple" => [":k2", 1]},
  479. %{"tuple" => [":k3", 3]}
  480. ]
  481. ]
  482. }
  483. ],
  484. "db" => [":key1", ":key3", ":key2"]
  485. }
  486. ],
  487. "need_reboot" => false
  488. }
  489. end
  490. test "saving special atoms", %{conn: conn} do
  491. conn =
  492. conn
  493. |> put_req_header("content-type", "application/json")
  494. |> post("/api/pleroma/admin/config", %{
  495. "configs" => [
  496. %{
  497. "group" => ":pleroma",
  498. "key" => ":key1",
  499. "value" => [
  500. %{
  501. "tuple" => [
  502. ":ssl_options",
  503. [%{"tuple" => [":versions", [":tlsv1", ":tlsv1.1", ":tlsv1.2"]]}]
  504. ]
  505. }
  506. ]
  507. }
  508. ]
  509. })
  510. assert json_response_and_validate_schema(conn, 200) == %{
  511. "configs" => [
  512. %{
  513. "group" => ":pleroma",
  514. "key" => ":key1",
  515. "value" => [
  516. %{
  517. "tuple" => [
  518. ":ssl_options",
  519. [%{"tuple" => [":versions", [":tlsv1", ":tlsv1.1", ":tlsv1.2"]]}]
  520. ]
  521. }
  522. ],
  523. "db" => [":ssl_options"]
  524. }
  525. ],
  526. "need_reboot" => false
  527. }
  528. assert Application.get_env(:pleroma, :key1) == [
  529. ssl_options: [versions: [:tlsv1, :"tlsv1.1", :"tlsv1.2"]]
  530. ]
  531. end
  532. test "saving full setting if value is in full_key_update list", %{conn: conn} do
  533. backends = Application.get_env(:logger, :backends)
  534. on_exit(fn -> Application.put_env(:logger, :backends, backends) end)
  535. insert(:config,
  536. group: :logger,
  537. key: :backends,
  538. value: []
  539. )
  540. Pleroma.Config.TransferTask.load_and_update_env([], false)
  541. assert Application.get_env(:logger, :backends) == []
  542. conn =
  543. conn
  544. |> put_req_header("content-type", "application/json")
  545. |> post("/api/pleroma/admin/config", %{
  546. configs: [
  547. %{
  548. group: ":logger",
  549. key: ":backends",
  550. value: [":console"]
  551. }
  552. ]
  553. })
  554. assert json_response_and_validate_schema(conn, 200) == %{
  555. "configs" => [
  556. %{
  557. "group" => ":logger",
  558. "key" => ":backends",
  559. "value" => [
  560. ":console"
  561. ],
  562. "db" => [":backends"]
  563. }
  564. ],
  565. "need_reboot" => false
  566. }
  567. assert Application.get_env(:logger, :backends) == [
  568. :console
  569. ]
  570. end
  571. test "saving full setting if value is not keyword", %{conn: conn} do
  572. insert(:config,
  573. group: :tesla,
  574. key: :adapter,
  575. value: Tesla.Adapter.Hackey
  576. )
  577. conn =
  578. conn
  579. |> put_req_header("content-type", "application/json")
  580. |> post("/api/pleroma/admin/config", %{
  581. configs: [
  582. %{group: ":tesla", key: ":adapter", value: "Tesla.Adapter.Httpc"}
  583. ]
  584. })
  585. assert json_response_and_validate_schema(conn, 200) == %{
  586. "configs" => [
  587. %{
  588. "group" => ":tesla",
  589. "key" => ":adapter",
  590. "value" => "Tesla.Adapter.Httpc",
  591. "db" => [":adapter"]
  592. }
  593. ],
  594. "need_reboot" => false
  595. }
  596. end
  597. test "update config setting & delete with fallback to default value", %{
  598. conn: conn,
  599. admin: admin,
  600. token: token
  601. } do
  602. ueberauth = Application.get_env(:ueberauth, Ueberauth)
  603. insert(:config, key: :keyaa1)
  604. insert(:config, key: :keyaa2)
  605. config3 =
  606. insert(:config,
  607. group: :ueberauth,
  608. key: Ueberauth
  609. )
  610. conn =
  611. conn
  612. |> put_req_header("content-type", "application/json")
  613. |> post("/api/pleroma/admin/config", %{
  614. configs: [
  615. %{group: ":pleroma", key: ":keyaa1", value: "another_value"},
  616. %{group: ":pleroma", key: ":keyaa2", value: "another_value"}
  617. ]
  618. })
  619. assert json_response_and_validate_schema(conn, 200) == %{
  620. "configs" => [
  621. %{
  622. "group" => ":pleroma",
  623. "key" => ":keyaa1",
  624. "value" => "another_value",
  625. "db" => [":keyaa1"]
  626. },
  627. %{
  628. "group" => ":pleroma",
  629. "key" => ":keyaa2",
  630. "value" => "another_value",
  631. "db" => [":keyaa2"]
  632. }
  633. ],
  634. "need_reboot" => false
  635. }
  636. assert Application.get_env(:pleroma, :keyaa1) == "another_value"
  637. assert Application.get_env(:pleroma, :keyaa2) == "another_value"
  638. assert Application.get_env(:ueberauth, Ueberauth) == config3.value
  639. conn =
  640. build_conn()
  641. |> assign(:user, admin)
  642. |> assign(:token, token)
  643. |> put_req_header("content-type", "application/json")
  644. |> post("/api/pleroma/admin/config", %{
  645. configs: [
  646. %{group: ":pleroma", key: ":keyaa2", delete: true},
  647. %{
  648. group: ":ueberauth",
  649. key: "Ueberauth",
  650. delete: true
  651. }
  652. ]
  653. })
  654. assert json_response_and_validate_schema(conn, 200) == %{
  655. "configs" => [],
  656. "need_reboot" => false
  657. }
  658. assert Application.get_env(:ueberauth, Ueberauth) == ueberauth
  659. refute Keyword.has_key?(Application.get_all_env(:pleroma), :keyaa2)
  660. end
  661. test "common config example", %{conn: conn} do
  662. conn =
  663. conn
  664. |> put_req_header("content-type", "application/json")
  665. |> post("/api/pleroma/admin/config", %{
  666. configs: [
  667. %{
  668. "group" => ":pleroma",
  669. "key" => "Pleroma.Captcha.NotReal",
  670. "value" => [
  671. %{"tuple" => [":enabled", false]},
  672. %{"tuple" => [":method", "Pleroma.Captcha.Kocaptcha"]},
  673. %{"tuple" => [":seconds_valid", 60]},
  674. %{"tuple" => [":path", ""]},
  675. %{"tuple" => [":key1", nil]},
  676. %{"tuple" => [":partial_chain", "&:hackney_connect.partial_chain/1"]},
  677. %{"tuple" => [":regex1", "~r/https:\/\/example.com/"]},
  678. %{"tuple" => [":regex2", "~r/https:\/\/example.com/u"]},
  679. %{"tuple" => [":regex3", "~r/https:\/\/example.com/i"]},
  680. %{"tuple" => [":regex4", "~r/https:\/\/example.com/s"]},
  681. %{"tuple" => [":name", "Pleroma"]}
  682. ]
  683. }
  684. ]
  685. })
  686. assert Config.get([Pleroma.Captcha.NotReal, :name]) == "Pleroma"
  687. assert json_response_and_validate_schema(conn, 200) == %{
  688. "configs" => [
  689. %{
  690. "group" => ":pleroma",
  691. "key" => "Pleroma.Captcha.NotReal",
  692. "value" => [
  693. %{"tuple" => [":enabled", false]},
  694. %{"tuple" => [":method", "Pleroma.Captcha.Kocaptcha"]},
  695. %{"tuple" => [":seconds_valid", 60]},
  696. %{"tuple" => [":path", ""]},
  697. %{"tuple" => [":key1", nil]},
  698. %{"tuple" => [":partial_chain", "&:hackney_connect.partial_chain/1"]},
  699. %{"tuple" => [":regex1", "~r/https:\\/\\/example.com/"]},
  700. %{"tuple" => [":regex2", "~r/https:\\/\\/example.com/u"]},
  701. %{"tuple" => [":regex3", "~r/https:\\/\\/example.com/i"]},
  702. %{"tuple" => [":regex4", "~r/https:\\/\\/example.com/s"]},
  703. %{"tuple" => [":name", "Pleroma"]}
  704. ],
  705. "db" => [
  706. ":enabled",
  707. ":method",
  708. ":seconds_valid",
  709. ":path",
  710. ":key1",
  711. ":partial_chain",
  712. ":regex1",
  713. ":regex2",
  714. ":regex3",
  715. ":regex4",
  716. ":name"
  717. ]
  718. }
  719. ],
  720. "need_reboot" => false
  721. }
  722. end
  723. test "tuples with more than two values", %{conn: conn} do
  724. conn =
  725. conn
  726. |> put_req_header("content-type", "application/json")
  727. |> post("/api/pleroma/admin/config", %{
  728. configs: [
  729. %{
  730. "group" => ":pleroma",
  731. "key" => "Pleroma.Web.Endpoint.NotReal",
  732. "value" => [
  733. %{
  734. "tuple" => [
  735. ":http",
  736. [
  737. %{
  738. "tuple" => [
  739. ":key2",
  740. [
  741. %{
  742. "tuple" => [
  743. ":_",
  744. [
  745. %{
  746. "tuple" => [
  747. "/api/v1/streaming",
  748. "Pleroma.Web.MastodonAPI.WebsocketHandler",
  749. []
  750. ]
  751. },
  752. %{
  753. "tuple" => [
  754. "/websocket",
  755. "Phoenix.Endpoint.CowboyWebSocket",
  756. %{
  757. "tuple" => [
  758. "Phoenix.Transports.WebSocket",
  759. %{
  760. "tuple" => [
  761. "Pleroma.Web.Endpoint",
  762. "Pleroma.Web.UserSocket",
  763. []
  764. ]
  765. }
  766. ]
  767. }
  768. ]
  769. },
  770. %{
  771. "tuple" => [
  772. ":_",
  773. "Phoenix.Endpoint.Cowboy2Handler",
  774. %{"tuple" => ["Pleroma.Web.Endpoint", []]}
  775. ]
  776. }
  777. ]
  778. ]
  779. }
  780. ]
  781. ]
  782. }
  783. ]
  784. ]
  785. }
  786. ]
  787. }
  788. ]
  789. })
  790. assert json_response_and_validate_schema(conn, 200) == %{
  791. "configs" => [
  792. %{
  793. "group" => ":pleroma",
  794. "key" => "Pleroma.Web.Endpoint.NotReal",
  795. "value" => [
  796. %{
  797. "tuple" => [
  798. ":http",
  799. [
  800. %{
  801. "tuple" => [
  802. ":key2",
  803. [
  804. %{
  805. "tuple" => [
  806. ":_",
  807. [
  808. %{
  809. "tuple" => [
  810. "/api/v1/streaming",
  811. "Pleroma.Web.MastodonAPI.WebsocketHandler",
  812. []
  813. ]
  814. },
  815. %{
  816. "tuple" => [
  817. "/websocket",
  818. "Phoenix.Endpoint.CowboyWebSocket",
  819. %{
  820. "tuple" => [
  821. "Phoenix.Transports.WebSocket",
  822. %{
  823. "tuple" => [
  824. "Pleroma.Web.Endpoint",
  825. "Pleroma.Web.UserSocket",
  826. []
  827. ]
  828. }
  829. ]
  830. }
  831. ]
  832. },
  833. %{
  834. "tuple" => [
  835. ":_",
  836. "Phoenix.Endpoint.Cowboy2Handler",
  837. %{"tuple" => ["Pleroma.Web.Endpoint", []]}
  838. ]
  839. }
  840. ]
  841. ]
  842. }
  843. ]
  844. ]
  845. }
  846. ]
  847. ]
  848. }
  849. ],
  850. "db" => [":http"]
  851. }
  852. ],
  853. "need_reboot" => false
  854. }
  855. end
  856. test "settings with nesting map", %{conn: conn} do
  857. conn =
  858. conn
  859. |> put_req_header("content-type", "application/json")
  860. |> post("/api/pleroma/admin/config", %{
  861. configs: [
  862. %{
  863. "group" => ":pleroma",
  864. "key" => ":key1",
  865. "value" => [
  866. %{"tuple" => [":key2", "some_val"]},
  867. %{
  868. "tuple" => [
  869. ":key3",
  870. %{
  871. ":max_options" => 20,
  872. ":max_option_chars" => 200,
  873. ":min_expiration" => 0,
  874. ":max_expiration" => 31_536_000,
  875. "nested" => %{
  876. ":max_options" => 20,
  877. ":max_option_chars" => 200,
  878. ":min_expiration" => 0,
  879. ":max_expiration" => 31_536_000
  880. }
  881. }
  882. ]
  883. }
  884. ]
  885. }
  886. ]
  887. })
  888. assert json_response_and_validate_schema(conn, 200) ==
  889. %{
  890. "configs" => [
  891. %{
  892. "group" => ":pleroma",
  893. "key" => ":key1",
  894. "value" => [
  895. %{"tuple" => [":key2", "some_val"]},
  896. %{
  897. "tuple" => [
  898. ":key3",
  899. %{
  900. ":max_expiration" => 31_536_000,
  901. ":max_option_chars" => 200,
  902. ":max_options" => 20,
  903. ":min_expiration" => 0,
  904. "nested" => %{
  905. ":max_expiration" => 31_536_000,
  906. ":max_option_chars" => 200,
  907. ":max_options" => 20,
  908. ":min_expiration" => 0
  909. }
  910. }
  911. ]
  912. }
  913. ],
  914. "db" => [":key2", ":key3"]
  915. }
  916. ],
  917. "need_reboot" => false
  918. }
  919. end
  920. test "value as map", %{conn: conn} do
  921. conn =
  922. conn
  923. |> put_req_header("content-type", "application/json")
  924. |> post("/api/pleroma/admin/config", %{
  925. configs: [
  926. %{
  927. "group" => ":pleroma",
  928. "key" => ":key1",
  929. "value" => %{"key" => "some_val"}
  930. }
  931. ]
  932. })
  933. assert json_response_and_validate_schema(conn, 200) ==
  934. %{
  935. "configs" => [
  936. %{
  937. "group" => ":pleroma",
  938. "key" => ":key1",
  939. "value" => %{"key" => "some_val"},
  940. "db" => [":key1"]
  941. }
  942. ],
  943. "need_reboot" => false
  944. }
  945. end
  946. test "queues key as atom", %{conn: conn} do
  947. conn =
  948. conn
  949. |> put_req_header("content-type", "application/json")
  950. |> post("/api/pleroma/admin/config", %{
  951. configs: [
  952. %{
  953. "group" => ":oban",
  954. "key" => ":queues",
  955. "value" => [
  956. %{"tuple" => [":federator_incoming", 50]},
  957. %{"tuple" => [":federator_outgoing", 50]},
  958. %{"tuple" => [":web_push", 50]},
  959. %{"tuple" => [":mailer", 10]},
  960. %{"tuple" => [":transmogrifier", 20]},
  961. %{"tuple" => [":scheduled_activities", 10]},
  962. %{"tuple" => [":background", 5]}
  963. ]
  964. }
  965. ]
  966. })
  967. assert json_response_and_validate_schema(conn, 200) == %{
  968. "configs" => [
  969. %{
  970. "group" => ":oban",
  971. "key" => ":queues",
  972. "value" => [
  973. %{"tuple" => [":federator_incoming", 50]},
  974. %{"tuple" => [":federator_outgoing", 50]},
  975. %{"tuple" => [":web_push", 50]},
  976. %{"tuple" => [":mailer", 10]},
  977. %{"tuple" => [":transmogrifier", 20]},
  978. %{"tuple" => [":scheduled_activities", 10]},
  979. %{"tuple" => [":background", 5]}
  980. ],
  981. "db" => [
  982. ":federator_incoming",
  983. ":federator_outgoing",
  984. ":web_push",
  985. ":mailer",
  986. ":transmogrifier",
  987. ":scheduled_activities",
  988. ":background"
  989. ]
  990. }
  991. ],
  992. "need_reboot" => false
  993. }
  994. end
  995. test "delete part of settings by atom subkeys", %{conn: conn} do
  996. insert(:config,
  997. key: :keyaa1,
  998. value: [subkey1: "val1", subkey2: "val2", subkey3: "val3"]
  999. )
  1000. conn =
  1001. conn
  1002. |> put_req_header("content-type", "application/json")
  1003. |> post("/api/pleroma/admin/config", %{
  1004. configs: [
  1005. %{
  1006. group: ":pleroma",
  1007. key: ":keyaa1",
  1008. subkeys: [":subkey1", ":subkey3"],
  1009. delete: true
  1010. }
  1011. ]
  1012. })
  1013. assert json_response_and_validate_schema(conn, 200) == %{
  1014. "configs" => [
  1015. %{
  1016. "group" => ":pleroma",
  1017. "key" => ":keyaa1",
  1018. "value" => [%{"tuple" => [":subkey2", "val2"]}],
  1019. "db" => [":subkey2"]
  1020. }
  1021. ],
  1022. "need_reboot" => false
  1023. }
  1024. end
  1025. test "proxy tuple localhost", %{conn: conn} do
  1026. conn =
  1027. conn
  1028. |> put_req_header("content-type", "application/json")
  1029. |> post("/api/pleroma/admin/config", %{
  1030. configs: [
  1031. %{
  1032. group: ":pleroma",
  1033. key: ":http",
  1034. value: [
  1035. %{"tuple" => [":proxy_url", %{"tuple" => [":socks5", "localhost", 1234]}]}
  1036. ]
  1037. }
  1038. ]
  1039. })
  1040. assert %{
  1041. "configs" => [
  1042. %{
  1043. "group" => ":pleroma",
  1044. "key" => ":http",
  1045. "value" => value,
  1046. "db" => db
  1047. }
  1048. ]
  1049. } = json_response_and_validate_schema(conn, 200)
  1050. assert %{"tuple" => [":proxy_url", %{"tuple" => [":socks5", "localhost", 1234]}]} in value
  1051. assert ":proxy_url" in db
  1052. end
  1053. test "proxy tuple domain", %{conn: conn} do
  1054. conn =
  1055. conn
  1056. |> put_req_header("content-type", "application/json")
  1057. |> post("/api/pleroma/admin/config", %{
  1058. configs: [
  1059. %{
  1060. group: ":pleroma",
  1061. key: ":http",
  1062. value: [
  1063. %{"tuple" => [":proxy_url", %{"tuple" => [":socks5", "domain.com", 1234]}]}
  1064. ]
  1065. }
  1066. ]
  1067. })
  1068. assert %{
  1069. "configs" => [
  1070. %{
  1071. "group" => ":pleroma",
  1072. "key" => ":http",
  1073. "value" => value,
  1074. "db" => db
  1075. }
  1076. ]
  1077. } = json_response_and_validate_schema(conn, 200)
  1078. assert %{"tuple" => [":proxy_url", %{"tuple" => [":socks5", "domain.com", 1234]}]} in value
  1079. assert ":proxy_url" in db
  1080. end
  1081. test "proxy tuple ip", %{conn: conn} do
  1082. conn =
  1083. conn
  1084. |> put_req_header("content-type", "application/json")
  1085. |> post("/api/pleroma/admin/config", %{
  1086. configs: [
  1087. %{
  1088. group: ":pleroma",
  1089. key: ":http",
  1090. value: [
  1091. %{"tuple" => [":proxy_url", %{"tuple" => [":socks5", "127.0.0.1", 1234]}]}
  1092. ]
  1093. }
  1094. ]
  1095. })
  1096. assert %{
  1097. "configs" => [
  1098. %{
  1099. "group" => ":pleroma",
  1100. "key" => ":http",
  1101. "value" => value,
  1102. "db" => db
  1103. }
  1104. ]
  1105. } = json_response_and_validate_schema(conn, 200)
  1106. assert %{"tuple" => [":proxy_url", %{"tuple" => [":socks5", "127.0.0.1", 1234]}]} in value
  1107. assert ":proxy_url" in db
  1108. end
  1109. @tag capture_log: true
  1110. test "doesn't set keys not in the whitelist", %{conn: conn} do
  1111. clear_config(:database_config_whitelist, [
  1112. {:pleroma, :key1},
  1113. {:pleroma, :key2},
  1114. {:pleroma, Pleroma.Captcha.NotReal},
  1115. {:not_real}
  1116. ])
  1117. conn
  1118. |> put_req_header("content-type", "application/json")
  1119. |> post("/api/pleroma/admin/config", %{
  1120. configs: [
  1121. %{group: ":pleroma", key: ":key1", value: "value1"},
  1122. %{group: ":pleroma", key: ":key2", value: "value2"},
  1123. %{group: ":pleroma", key: ":key3", value: "value3"},
  1124. %{group: ":pleroma", key: "Pleroma.Web.Endpoint.NotReal", value: "value4"},
  1125. %{group: ":pleroma", key: "Pleroma.Captcha.NotReal", value: "value5"},
  1126. %{group: ":not_real", key: ":anything", value: "value6"}
  1127. ]
  1128. })
  1129. assert Application.get_env(:pleroma, :key1) == "value1"
  1130. assert Application.get_env(:pleroma, :key2) == "value2"
  1131. assert Application.get_env(:pleroma, :key3) == nil
  1132. assert Application.get_env(:pleroma, Pleroma.Web.Endpoint.NotReal) == nil
  1133. assert Application.get_env(:pleroma, Pleroma.Captcha.NotReal) == "value5"
  1134. assert Application.get_env(:not_real, :anything) == "value6"
  1135. end
  1136. test "args for Pleroma.Upload.Filter.Mogrify with custom tuples", %{conn: conn} do
  1137. clear_config(Pleroma.Upload.Filter.Mogrify)
  1138. assert conn
  1139. |> put_req_header("content-type", "application/json")
  1140. |> post("/api/pleroma/admin/config", %{
  1141. configs: [
  1142. %{
  1143. group: ":pleroma",
  1144. key: "Pleroma.Upload.Filter.Mogrify",
  1145. value: [
  1146. %{"tuple" => [":args", ["auto-orient", "strip"]]}
  1147. ]
  1148. }
  1149. ]
  1150. })
  1151. |> json_response_and_validate_schema(200) == %{
  1152. "configs" => [
  1153. %{
  1154. "group" => ":pleroma",
  1155. "key" => "Pleroma.Upload.Filter.Mogrify",
  1156. "value" => [
  1157. %{"tuple" => [":args", ["auto-orient", "strip"]]}
  1158. ],
  1159. "db" => [":args"]
  1160. }
  1161. ],
  1162. "need_reboot" => false
  1163. }
  1164. assert Config.get(Pleroma.Upload.Filter.Mogrify) == [args: ["auto-orient", "strip"]]
  1165. assert conn
  1166. |> put_req_header("content-type", "application/json")
  1167. |> post("/api/pleroma/admin/config", %{
  1168. configs: [
  1169. %{
  1170. group: ":pleroma",
  1171. key: "Pleroma.Upload.Filter.Mogrify",
  1172. value: [
  1173. %{
  1174. "tuple" => [
  1175. ":args",
  1176. [
  1177. "auto-orient",
  1178. "strip",
  1179. "{\"implode\", \"1\"}",
  1180. "{\"resize\", \"3840x1080>\"}"
  1181. ]
  1182. ]
  1183. }
  1184. ]
  1185. }
  1186. ]
  1187. })
  1188. |> json_response(200) == %{
  1189. "configs" => [
  1190. %{
  1191. "group" => ":pleroma",
  1192. "key" => "Pleroma.Upload.Filter.Mogrify",
  1193. "value" => [
  1194. %{
  1195. "tuple" => [
  1196. ":args",
  1197. [
  1198. "auto-orient",
  1199. "strip",
  1200. "{\"implode\", \"1\"}",
  1201. "{\"resize\", \"3840x1080>\"}"
  1202. ]
  1203. ]
  1204. }
  1205. ],
  1206. "db" => [":args"]
  1207. }
  1208. ],
  1209. "need_reboot" => false
  1210. }
  1211. assert Config.get(Pleroma.Upload.Filter.Mogrify) == [
  1212. args: ["auto-orient", "strip", {"implode", "1"}, {"resize", "3840x1080>"}]
  1213. ]
  1214. end
  1215. test "enables the welcome messages", %{conn: conn} do
  1216. clear_config([:welcome])
  1217. params = %{
  1218. "group" => ":pleroma",
  1219. "key" => ":welcome",
  1220. "value" => [
  1221. %{
  1222. "tuple" => [
  1223. ":direct_message",
  1224. [
  1225. %{"tuple" => [":enabled", true]},
  1226. %{"tuple" => [":message", "Welcome to Pleroma!"]},
  1227. %{"tuple" => [":sender_nickname", "pleroma"]}
  1228. ]
  1229. ]
  1230. },
  1231. %{
  1232. "tuple" => [
  1233. ":chat_message",
  1234. [
  1235. %{"tuple" => [":enabled", true]},
  1236. %{"tuple" => [":message", "Welcome to Pleroma!"]},
  1237. %{"tuple" => [":sender_nickname", "pleroma"]}
  1238. ]
  1239. ]
  1240. },
  1241. %{
  1242. "tuple" => [
  1243. ":email",
  1244. [
  1245. %{"tuple" => [":enabled", true]},
  1246. %{"tuple" => [":sender", %{"tuple" => ["pleroma@dev.dev", "Pleroma"]}]},
  1247. %{"tuple" => [":subject", "Welcome to <%= instance_name %>!"]},
  1248. %{"tuple" => [":html", "Welcome to <%= instance_name %>!"]},
  1249. %{"tuple" => [":text", "Welcome to <%= instance_name %>!"]}
  1250. ]
  1251. ]
  1252. }
  1253. ]
  1254. }
  1255. refute Pleroma.User.WelcomeEmail.enabled?()
  1256. refute Pleroma.User.WelcomeMessage.enabled?()
  1257. refute Pleroma.User.WelcomeChatMessage.enabled?()
  1258. res =
  1259. assert conn
  1260. |> put_req_header("content-type", "application/json")
  1261. |> post("/api/pleroma/admin/config", %{"configs" => [params]})
  1262. |> json_response_and_validate_schema(200)
  1263. assert Pleroma.User.WelcomeEmail.enabled?()
  1264. assert Pleroma.User.WelcomeMessage.enabled?()
  1265. assert Pleroma.User.WelcomeChatMessage.enabled?()
  1266. assert res == %{
  1267. "configs" => [
  1268. %{
  1269. "db" => [":direct_message", ":chat_message", ":email"],
  1270. "group" => ":pleroma",
  1271. "key" => ":welcome",
  1272. "value" => params["value"]
  1273. }
  1274. ],
  1275. "need_reboot" => false
  1276. }
  1277. end
  1278. test "custom instance thumbnail", %{conn: conn} do
  1279. clear_config([:instance])
  1280. params = %{
  1281. "group" => ":pleroma",
  1282. "key" => ":instance",
  1283. "value" => [
  1284. %{
  1285. "tuple" => [
  1286. ":instance_thumbnail",
  1287. "https://example.com/media/new_thumbnail.jpg"
  1288. ]
  1289. }
  1290. ]
  1291. }
  1292. res =
  1293. assert conn
  1294. |> put_req_header("content-type", "application/json")
  1295. |> post("/api/pleroma/admin/config", %{"configs" => [params]})
  1296. |> json_response_and_validate_schema(200)
  1297. assert res == %{
  1298. "configs" => [
  1299. %{
  1300. "db" => [":instance_thumbnail"],
  1301. "group" => ":pleroma",
  1302. "key" => ":instance",
  1303. "value" => params["value"]
  1304. }
  1305. ],
  1306. "need_reboot" => false
  1307. }
  1308. _res =
  1309. assert conn
  1310. |> get("/api/v1/instance")
  1311. |> json_response_and_validate_schema(200)
  1312. assert res = %{"thumbnail" => "https://example.com/media/new_thumbnail.jpg"}
  1313. end
  1314. test "Concurrent Limiter", %{conn: conn} do
  1315. clear_config([ConcurrentLimiter])
  1316. params = %{
  1317. "group" => ":pleroma",
  1318. "key" => "ConcurrentLimiter",
  1319. "value" => [
  1320. %{
  1321. "tuple" => [
  1322. "Pleroma.Web.RichMedia.Helpers",
  1323. [
  1324. %{"tuple" => [":max_running", 6]},
  1325. %{"tuple" => [":max_waiting", 6]}
  1326. ]
  1327. ]
  1328. },
  1329. %{
  1330. "tuple" => [
  1331. "Pleroma.Web.ActivityPub.MRF.MediaProxyWarmingPolicy",
  1332. [
  1333. %{"tuple" => [":max_running", 7]},
  1334. %{"tuple" => [":max_waiting", 7]}
  1335. ]
  1336. ]
  1337. }
  1338. ]
  1339. }
  1340. assert conn
  1341. |> put_req_header("content-type", "application/json")
  1342. |> post("/api/pleroma/admin/config", %{"configs" => [params]})
  1343. |> json_response_and_validate_schema(200)
  1344. end
  1345. end
  1346. describe "GET /api/pleroma/admin/config/descriptions" do
  1347. test "structure", %{conn: conn} do
  1348. conn = get(conn, "/api/pleroma/admin/config/descriptions")
  1349. assert [child | _others] = json_response_and_validate_schema(conn, 200)
  1350. assert child["children"]
  1351. assert child["key"]
  1352. assert String.starts_with?(child["group"], ":")
  1353. assert child["description"]
  1354. end
  1355. test "filters by database configuration whitelist", %{conn: conn} do
  1356. clear_config(:database_config_whitelist, [
  1357. {:pleroma, :instance},
  1358. {:pleroma, :activitypub},
  1359. {:pleroma, Pleroma.Upload},
  1360. {:esshd}
  1361. ])
  1362. conn = get(conn, "/api/pleroma/admin/config/descriptions")
  1363. children = json_response_and_validate_schema(conn, 200)
  1364. assert length(children) == 4
  1365. assert Enum.count(children, fn c -> c["group"] == ":pleroma" end) == 3
  1366. instance = Enum.find(children, fn c -> c["key"] == ":instance" end)
  1367. assert instance["children"]
  1368. activitypub = Enum.find(children, fn c -> c["key"] == ":activitypub" end)
  1369. assert activitypub["children"]
  1370. web_endpoint = Enum.find(children, fn c -> c["key"] == "Pleroma.Upload" end)
  1371. assert web_endpoint["children"]
  1372. esshd = Enum.find(children, fn c -> c["group"] == ":esshd" end)
  1373. assert esshd["children"]
  1374. end
  1375. end
  1376. end