Merge branch 'feature/database-configuration-whitelist' into 'develop'

Database configuration whitelist

See merge request pleroma/pleroma!2522
This commit is contained in:
rinpatch 2020-05-14 16:07:37 +00:00
commit e455ca3f3e
5 changed files with 117 additions and 16 deletions

View file

@ -19,6 +19,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
- NodeInfo: `pleroma:api/v1/notifications:include_types_filter` to the `features` list. - NodeInfo: `pleroma:api/v1/notifications:include_types_filter` to the `features` list.
- NodeInfo: `pleroma_emoji_reactions` to the `features` list. - NodeInfo: `pleroma_emoji_reactions` to the `features` list.
- Configuration: `:restrict_unauthenticated` setting, restrict access for unauthenticated users to timelines (public and federate), user profiles and statuses. - Configuration: `:restrict_unauthenticated` setting, restrict access for unauthenticated users to timelines (public and federate), user profiles and statuses.
- Configuration: Add `:database_config_whitelist` setting to whitelist settings which can be configured from AdminFE.
- New HTTP adapter [gun](https://github.com/ninenines/gun). Gun adapter requires minimum OTP version of 22.2 otherwise Pleroma wont start. For hackney OTP update is not required. - New HTTP adapter [gun](https://github.com/ninenines/gun). Gun adapter requires minimum OTP version of 22.2 otherwise Pleroma wont start. For hackney OTP update is not required.
- Mix task to create trusted OAuth App. - Mix task to create trusted OAuth App.
- Notifications: Added `follow_request` notification type. - Notifications: Added `follow_request` notification type.

View file

@ -911,6 +911,21 @@ config :auto_linker,
Boolean, enables/disables in-database configuration. Read [Transfering the config to/from the database](../administration/CLI_tasks/config.md) for more information. Boolean, enables/disables in-database configuration. Read [Transfering the config to/from the database](../administration/CLI_tasks/config.md) for more information.
## :database_config_whitelist
List of valid configuration sections which are allowed to be configured from the
database. Settings stored in the database before the whitelist is configured are
still applied, so it is suggested to only use the whitelist on instances that
have not migrated the config to the database.
Example:
```elixir
config :pleroma, :database_config_whitelist, [
{:pleroma, :instance},
{:pleroma, Pleroma.Web.Metadata},
{:auto_linker}
]
```
### Multi-factor authentication - :two_factor_authentication ### Multi-factor authentication - :two_factor_authentication
* `totp` - a list containing TOTP configuration * `totp` - a list containing TOTP configuration

View file

@ -18,7 +18,6 @@ def compile do
with config <- Pleroma.Config.Loader.read("config/description.exs") do with config <- Pleroma.Config.Loader.read("config/description.exs") do
config[:pleroma][:config_description] config[:pleroma][:config_description]
|> Pleroma.Docs.Generator.convert_to_strings() |> Pleroma.Docs.Generator.convert_to_strings()
|> Jason.encode!()
end end
end end
end end

View file

@ -37,7 +37,7 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do
require Logger require Logger
@descriptions_json Pleroma.Docs.JSON.compile() @descriptions Pleroma.Docs.JSON.compile()
@users_page_size 50 @users_page_size 50
plug( plug(
@ -897,9 +897,9 @@ def list_log(conn, params) do
end end
def config_descriptions(conn, _params) do def config_descriptions(conn, _params) do
conn descriptions = Enum.filter(@descriptions, &whitelisted_config?/1)
|> Plug.Conn.put_resp_content_type("application/json")
|> Plug.Conn.send_resp(200, @descriptions_json) json(conn, descriptions)
end end
def config_show(conn, %{"only_db" => true}) do def config_show(conn, %{"only_db" => true}) do
@ -954,7 +954,9 @@ def config_show(conn, _params) do
def config_update(conn, %{"configs" => configs}) do def config_update(conn, %{"configs" => configs}) do
with :ok <- configurable_from_database(conn) do with :ok <- configurable_from_database(conn) do
{_errors, results} = {_errors, results} =
Enum.map(configs, fn configs
|> Enum.filter(&whitelisted_config?/1)
|> Enum.map(fn
%{"group" => group, "key" => key, "delete" => true} = params -> %{"group" => group, "key" => key, "delete" => true} = params ->
ConfigDB.delete(%{group: group, key: key, subkeys: params["subkeys"]}) ConfigDB.delete(%{group: group, key: key, subkeys: params["subkeys"]})
@ -1016,6 +1018,28 @@ defp configurable_from_database(conn) do
end end
end end
defp whitelisted_config?(group, key) do
if whitelisted_configs = Config.get(:database_config_whitelist) do
Enum.any?(whitelisted_configs, fn
{whitelisted_group} ->
group == inspect(whitelisted_group)
{whitelisted_group, whitelisted_key} ->
group == inspect(whitelisted_group) && key == inspect(whitelisted_key)
end)
else
true
end
end
defp whitelisted_config?(%{"group" => group, "key" => key}) do
whitelisted_config?(group, key)
end
defp whitelisted_config?(%{:group => group} = config) do
whitelisted_config?(group, config[:key])
end
def reload_emoji(conn, _params) do def reload_emoji(conn, _params) do
Pleroma.Emoji.reload() Pleroma.Emoji.reload()

View file

@ -2940,6 +2940,33 @@ test "proxy tuple ip", %{conn: conn} do
assert %{"tuple" => [":proxy_url", %{"tuple" => [":socks5", "127.0.0.1", 1234]}]} in value assert %{"tuple" => [":proxy_url", %{"tuple" => [":socks5", "127.0.0.1", 1234]}]} in value
assert ":proxy_url" in db assert ":proxy_url" in db
end end
test "doesn't set keys not in the whitelist", %{conn: conn} do
clear_config(:database_config_whitelist, [
{:pleroma, :key1},
{:pleroma, :key2},
{:pleroma, Pleroma.Captcha.NotReal},
{:not_real}
])
post(conn, "/api/pleroma/admin/config", %{
configs: [
%{group: ":pleroma", key: ":key1", value: "value1"},
%{group: ":pleroma", key: ":key2", value: "value2"},
%{group: ":pleroma", key: ":key3", value: "value3"},
%{group: ":pleroma", key: "Pleroma.Web.Endpoint.NotReal", value: "value4"},
%{group: ":pleroma", key: "Pleroma.Captcha.NotReal", value: "value5"},
%{group: ":not_real", key: ":anything", value: "value6"}
]
})
assert Application.get_env(:pleroma, :key1) == "value1"
assert Application.get_env(:pleroma, :key2) == "value2"
assert Application.get_env(:pleroma, :key3) == nil
assert Application.get_env(:pleroma, Pleroma.Web.Endpoint.NotReal) == nil
assert Application.get_env(:pleroma, Pleroma.Captcha.NotReal) == "value5"
assert Application.get_env(:not_real, :anything) == "value6"
end
end end
describe "GET /api/pleroma/admin/restart" do describe "GET /api/pleroma/admin/restart" do
@ -3571,7 +3598,8 @@ test "it deletes the note", %{conn: conn, report_id: report_id} do
end end
end end
test "GET /api/pleroma/admin/config/descriptions", %{conn: conn} do describe "GET /api/pleroma/admin/config/descriptions" do
test "structure", %{conn: conn} do
admin = insert(:user, is_admin: true) admin = insert(:user, is_admin: true)
conn = conn =
@ -3586,6 +3614,40 @@ test "GET /api/pleroma/admin/config/descriptions", %{conn: conn} do
assert child["description"] assert child["description"]
end end
test "filters by database configuration whitelist", %{conn: conn} do
clear_config(:database_config_whitelist, [
{:pleroma, :instance},
{:pleroma, :activitypub},
{:pleroma, Pleroma.Upload},
{:esshd}
])
admin = insert(:user, is_admin: true)
conn =
assign(conn, :user, admin)
|> get("/api/pleroma/admin/config/descriptions")
children = json_response(conn, 200)
assert length(children) == 4
assert Enum.count(children, fn c -> c["group"] == ":pleroma" end) == 3
instance = Enum.find(children, fn c -> c["key"] == ":instance" end)
assert instance["children"]
activitypub = Enum.find(children, fn c -> c["key"] == ":activitypub" end)
assert activitypub["children"]
web_endpoint = Enum.find(children, fn c -> c["key"] == "Pleroma.Upload" end)
assert web_endpoint["children"]
esshd = Enum.find(children, fn c -> c["group"] == ":esshd" end)
assert esshd["children"]
end
end
describe "/api/pleroma/admin/stats" do describe "/api/pleroma/admin/stats" do
test "status visibility count", %{conn: conn} do test "status visibility count", %{conn: conn} do
admin = insert(:user, is_admin: true) admin = insert(:user, is_admin: true)