From e3adc0684f0d3a5280ef529ca2b8a0f117f00c5a Mon Sep 17 00:00:00 2001 From: Thomas Citharel Date: Wed, 6 Apr 2022 16:53:20 +0200 Subject: [PATCH] Make FrontEndAnalytics provide CSP configuration Signed-off-by: Thomas Citharel --- lib/service/front_end_analytics/analytics.ex | 22 ++++++++++++++++++-- lib/service/front_end_analytics/matomo.ex | 12 ++++++++++- lib/service/front_end_analytics/plausible.ex | 12 ++++++++++- lib/service/front_end_analytics/sentry.ex | 12 ++++++++++- lib/web/plugs/http_security_plug.ex | 8 ++++--- test/web/plugs/http_security_plug_test.exs | 2 +- 6 files changed, 59 insertions(+), 9 deletions(-) diff --git a/lib/service/front_end_analytics/analytics.ex b/lib/service/front_end_analytics/analytics.ex index cb5b22b0b..f58c6823c 100644 --- a/lib/service/front_end_analytics/analytics.ex +++ b/lib/service/front_end_analytics/analytics.ex @@ -13,7 +13,12 @@ defmodule Mobilizon.Service.FrontEndAnalytics do @doc """ The configuration for the service """ - @callback configuration() :: map() + @callback configuration() :: keyword() + + @doc """ + The CSP configuration to add for the service to work + """ + @callback csp() :: keyword() @spec providers :: list(module()) def providers do @@ -27,7 +32,14 @@ defmodule Mobilizon.Service.FrontEndAnalytics do Enum.reduce(providers(), [], &load_config/2) end - @spec load_config(module(), map()) :: map() + @spec csp :: keyword() + def csp do + providers() + |> Enum.map(& &1.csp()) + |> Enum.reduce([], &merge_csp_config/2) + end + + @spec load_config(module(), list(map())) :: list(map()) defp load_config(provider, acc) do acc ++ [ @@ -50,4 +62,10 @@ defmodule Mobilizon.Service.FrontEndAnalytics do defp type(val) when is_float(val), do: :float defp type(val) when is_boolean(val), do: :boolean defp type(val) when is_binary(val), do: :string + + defp merge_csp_config(config, global_config) do + Keyword.merge(global_config, config, fn _key, global, config -> + "#{global} #{config}" + end) + end end diff --git a/lib/service/front_end_analytics/matomo.ex b/lib/service/front_end_analytics/matomo.ex index 34da3dd8f..f004030c9 100644 --- a/lib/service/front_end_analytics/matomo.ex +++ b/lib/service/front_end_analytics/matomo.ex @@ -25,6 +25,16 @@ defmodule Mobilizon.Service.FrontEndAnalytics.Matomo do def configuration do :mobilizon |> Application.get_env(__MODULE__, []) - |> Keyword.drop([:enabled]) + |> Keyword.drop([:enabled, :csp]) + end + + @doc """ + The CSP configuration to add for the service to work + """ + @impl FrontEndAnalytics + def csp do + :mobilizon + |> Application.get_env(__MODULE__, []) + |> Keyword.get(:csp, []) end end diff --git a/lib/service/front_end_analytics/plausible.ex b/lib/service/front_end_analytics/plausible.ex index 41c8cb895..d17f8b6fb 100644 --- a/lib/service/front_end_analytics/plausible.ex +++ b/lib/service/front_end_analytics/plausible.ex @@ -26,6 +26,16 @@ defmodule Mobilizon.Service.FrontEndAnalytics.Plausible do def configuration do :mobilizon |> Application.get_env(__MODULE__, []) - |> Keyword.drop([:enabled]) + |> Keyword.drop([:enabled, :csp]) + end + + @doc """ + The CSP configuration to add for the service to work + """ + @impl FrontEndAnalytics + def csp do + :mobilizon + |> Application.get_env(__MODULE__, []) + |> Keyword.get(:csp, []) end end diff --git a/lib/service/front_end_analytics/sentry.ex b/lib/service/front_end_analytics/sentry.ex index 0aa94dcbf..fd804bc73 100644 --- a/lib/service/front_end_analytics/sentry.ex +++ b/lib/service/front_end_analytics/sentry.ex @@ -26,6 +26,16 @@ defmodule Mobilizon.Service.FrontEndAnalytics.Sentry do def configuration do :mobilizon |> Application.get_env(__MODULE__, []) - |> Keyword.drop([:enabled]) + |> Keyword.drop([:enabled, :csp]) + end + + @doc """ + The CSP configuration to add for the service to work + """ + @impl FrontEndAnalytics + def csp do + :mobilizon + |> Application.get_env(__MODULE__, []) + |> Keyword.get(:csp, []) end end diff --git a/lib/web/plugs/http_security_plug.ex b/lib/web/plugs/http_security_plug.ex index 468dd89e3..9345d8bc4 100644 --- a/lib/web/plugs/http_security_plug.ex +++ b/lib/web/plugs/http_security_plug.ex @@ -9,6 +9,7 @@ defmodule Mobilizon.Web.Plugs.HTTPSecurityPlug do """ alias Mobilizon.Config + alias Mobilizon.Service.FrontEndAnalytics import Plug.Conn require Logger @@ -136,8 +137,9 @@ defmodule Mobilizon.Web.Plugs.HTTPSecurityPlug do @spec get_csp_config(atom(), Keyword.t()) :: iodata() defp get_csp_config(type, options) do - options - |> Keyword.get(type, Config.get([:http_security, :csp_policy, type])) - |> Enum.join(" ") + config_policy = Keyword.get(options, type, Config.get([:http_security, :csp_policy, type])) + front_end_analytics_policy = [Keyword.get(FrontEndAnalytics.csp(), type, [])] + + Enum.join(config_policy ++ front_end_analytics_policy, " ") end end diff --git a/test/web/plugs/http_security_plug_test.exs b/test/web/plugs/http_security_plug_test.exs index a7d533a50..9889f1dd7 100644 --- a/test/web/plugs/http_security_plug_test.exs +++ b/test/web/plugs/http_security_plug_test.exs @@ -73,7 +73,7 @@ defmodule Mobilizon.Web.Plugs.HTTPSecurityPlugTest do [csp] = Conn.get_resp_header(conn, "content-security-policy") assert csp =~ - ~r/script-src 'self' 'unsafe-eval' 'sha256-[\w+\/=]*' example.com matomo.example.com;/ + ~r/script-src 'self' 'unsafe-eval' 'sha256-[\w+\/=]*' example.com matomo.example.com ;/ end end