aboutsummaryrefslogtreecommitdiff
path: root/lib/pleroma/config/converter.ex
diff options
context:
space:
mode:
Diffstat (limited to 'lib/pleroma/config/converter.ex')
-rw-r--r--lib/pleroma/config/converter.ex195
1 files changed, 195 insertions, 0 deletions
diff --git a/lib/pleroma/config/converter.ex b/lib/pleroma/config/converter.ex
new file mode 100644
index 000000000..86d7ea8e2
--- /dev/null
+++ b/lib/pleroma/config/converter.ex
@@ -0,0 +1,195 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.Config.Converter do
+ @moduledoc """
+ Converts json structures into elixir structures and types and vice versa.
+ """
+ @spec to_elixir_types(boolean() | String.t() | map() | list()) :: term()
+ def to_elixir_types(%{"tuple" => [":args", args]}) when is_list(args) do
+ arguments =
+ Enum.map(args, fn arg ->
+ if String.contains?(arg, ["{", "}"]) do
+ {elem, []} = Code.eval_string(arg)
+ elem
+ else
+ to_elixir_types(arg)
+ end
+ end)
+
+ {:args, arguments}
+ end
+
+ def to_elixir_types(%{"tuple" => [":proxy_url", %{"tuple" => [type, host, port]}]}) do
+ {:proxy_url, {string_to_elixir_types!(type), parse_host(host), port}}
+ end
+
+ def to_elixir_types(%{"tuple" => [":partial_chain", entity]}) do
+ {partial_chain, []} =
+ entity
+ |> String.replace(~r/[^\w|^{:,[|^,|^[|^\]^}|^\/|^\.|^"]^\s/, "")
+ |> Code.eval_string()
+
+ {:partial_chain, partial_chain}
+ end
+
+ def to_elixir_types(%{"tuple" => entity}) do
+ Enum.reduce(entity, {}, &Tuple.append(&2, to_elixir_types(&1)))
+ end
+
+ def to_elixir_types(entity) when is_map(entity) do
+ Map.new(entity, fn {k, v} -> {to_elixir_types(k), to_elixir_types(v)} end)
+ end
+
+ def to_elixir_types(entity) when is_list(entity) do
+ Enum.map(entity, &to_elixir_types/1)
+ end
+
+ def to_elixir_types(entity) when is_binary(entity) do
+ entity
+ |> String.trim()
+ |> string_to_elixir_types!()
+ end
+
+ def to_elixir_types(entity), do: entity
+
+ defp parse_host("localhost"), do: :localhost
+
+ defp parse_host(host) do
+ charlist = to_charlist(host)
+
+ case :inet.parse_address(charlist) do
+ {:error, :einval} ->
+ charlist
+
+ {:ok, ip} ->
+ ip
+ end
+ end
+
+ @spec string_to_elixir_types!(String.t()) ::
+ atom() | Regex.t() | module() | String.t() | no_return()
+ def string_to_elixir_types!("~r" <> _pattern = regex) do
+ pattern =
+ ~r/^~r(?'delimiter'[\/|"'([{<]{1})(?'pattern'.+)[\/|"')\]}>]{1}(?'modifier'[uismxfU]*)/u
+
+ delimiters = ["/", "|", "\"", "'", {"(", ")"}, {"[", "]"}, {"{", "}"}, {"<", ">"}]
+
+ with %{"modifier" => modifier, "pattern" => pattern, "delimiter" => regex_delimiter} <-
+ Regex.named_captures(pattern, regex),
+ {:ok, {leading, closing}} <- find_valid_delimiter(delimiters, pattern, regex_delimiter),
+ {result, _} <- Code.eval_string("~r#{leading}#{pattern}#{closing}#{modifier}") do
+ result
+ end
+ end
+
+ def string_to_elixir_types!(":" <> atom), do: String.to_atom(atom)
+
+ def string_to_elixir_types!(value) do
+ if module_name?(value) do
+ String.to_existing_atom("Elixir." <> value)
+ else
+ value
+ end
+ end
+
+ defp find_valid_delimiter([], _string, _) do
+ raise(ArgumentError, message: "valid delimiter for Regex expression not found")
+ end
+
+ defp find_valid_delimiter([{leading, closing} = delimiter | others], pattern, regex_delimiter)
+ when is_tuple(delimiter) do
+ if String.contains?(pattern, closing) do
+ find_valid_delimiter(others, pattern, regex_delimiter)
+ else
+ {:ok, {leading, closing}}
+ end
+ end
+
+ defp find_valid_delimiter([delimiter | others], pattern, regex_delimiter) do
+ if String.contains?(pattern, delimiter) do
+ find_valid_delimiter(others, pattern, regex_delimiter)
+ else
+ {:ok, {delimiter, delimiter}}
+ end
+ end
+
+ @spec module_name?(String.t()) :: boolean()
+ def module_name?(string) do
+ Regex.match?(~r/^(Pleroma|Phoenix|Tesla|Quack|Ueberauth|Swoosh)\./, string) or
+ string in ["Oban", "Ueberauth", "ExSyslogger", "ConcurrentLimiter"]
+ end
+
+ @spec to_json_types(term()) :: map() | list() | boolean() | String.t() | integer()
+ def to_json_types(entity) when is_list(entity) do
+ Enum.map(entity, &to_json_types/1)
+ end
+
+ def to_json_types(%Regex{} = entity), do: inspect(entity)
+
+ def to_json_types(entity) when is_map(entity) do
+ Map.new(entity, fn {k, v} -> {to_json_types(k), to_json_types(v)} end)
+ end
+
+ def to_json_types({:args, args}) when is_list(args) do
+ arguments =
+ Enum.map(args, fn
+ arg when is_tuple(arg) -> inspect(arg)
+ arg -> to_json_types(arg)
+ end)
+
+ %{"tuple" => [":args", arguments]}
+ end
+
+ def to_json_types({:proxy_url, {type, :localhost, port}}) do
+ %{"tuple" => [":proxy_url", %{"tuple" => [to_json_types(type), "localhost", port]}]}
+ end
+
+ def to_json_types({:proxy_url, {type, host, port}}) when is_tuple(host) do
+ ip =
+ host
+ |> :inet_parse.ntoa()
+ |> to_string()
+
+ %{
+ "tuple" => [
+ ":proxy_url",
+ %{"tuple" => [to_json_types(type), ip, port]}
+ ]
+ }
+ end
+
+ def to_json_types({:proxy_url, {type, host, port}}) do
+ %{
+ "tuple" => [
+ ":proxy_url",
+ %{"tuple" => [to_json_types(type), to_string(host), port]}
+ ]
+ }
+ end
+
+ def to_json_types({:partial_chain, entity}),
+ do: %{"tuple" => [":partial_chain", inspect(entity)]}
+
+ def to_json_types(entity) when is_tuple(entity) do
+ value =
+ entity
+ |> Tuple.to_list()
+ |> to_json_types()
+
+ %{"tuple" => value}
+ end
+
+ def to_json_types(entity) when is_binary(entity), do: entity
+
+ def to_json_types(entity) when is_boolean(entity) or is_number(entity) or is_nil(entity) do
+ entity
+ end
+
+ def to_json_types(entity) when entity in [:"tlsv1.1", :"tlsv1.2", :"tlsv1.3"] do
+ ":#{entity}"
+ end
+
+ def to_json_types(entity) when is_atom(entity), do: inspect(entity)
+end