Hey Guys,
I have a peculiar requirement, i.e. I want to use inline style or maybe a style directive, for styling source code.
I prefer using Chroma for source code highlighting as it has support for lots of languages & has lots of styling.
Here’s the demo: Chroma Playground (v2.8.0)
Now that I’m moving my blog to Elixir & Phoenix. How do I make the inline style work with CSP?
I’m unable to pass the style_nonce
to the blog live view!!
Here’s the CSP Header Plug:
defmodule DerpyToolsWeb.Plugs.CustomSecureBrowserHeaders do
def init(options), do: options
def call(conn, _opts) do
img_nonce = generate_nonce()
style_nonce = generate_nonce()
script_nonce = generate_nonce()
csp_headers =
csp_headers(
img_nonce,
script_nonce
)
conn
|> Plug.Conn.assign(:csp_img_nonce, img_nonce)
|> Plug.Conn.assign(:csp_style_nonce, style_nonce)
|> Plug.Conn.assign(:csp_script_nonce, script_nonce)
|> Phoenix.Controller.put_secure_browser_headers(csp_headers)
end
def csp_headers(img_nonce, script_nonce) do
csp_content =
case Application.fetch_env!(:derpy_tools, :env) do
# :prod -> connect-src wss://derpytools.com wss://www.derpytools.com;
# :stg -> connect-src wss://derpytools.site wss://www.derpytools.site;
:dev ->
"""
default-src 'self' data: https://*;
font-src 'self' data: https://*;
style-src 'self' data: https://* 'unsafe-inline';
img-src 'self' data: https://* 'nonce-#{img_nonce}';
script-src 'self' https://* 'nonce-#{script_nonce}';
connect-src wss://derpytools.com wss://www.derpytools.com wss://derpytools.site wss://www.derpytools.site wss://localhost:* ws://localhost:*;
"""
_ ->
nil
end
case csp_content do
nil -> %{}
csp_content -> %{"content-security-policy" => csp_content |> String.replace("\n", "")}
end
end
defp generate_nonce(size \\ 10),
do: size |> :crypto.strong_rand_bytes() |> Base.url_encode64(padding: false)
end
Here’s how I use it:
<script nonce={assigns[:csp_script_nonce]}>
localStorage.getItem("dark_mode") === "true" && document.documentElement.classList.add("dark");
</script>
I tried to pass it the way csrf_token is passed, using get_connect_params, but that doesn’t work as the value is available only when socket is connected.
Is there another way?
Or should I stick to global styling for code highlighting?