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