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