57 lines
1.6 KiB
Elixir
57 lines
1.6 KiB
Elixir
defmodule WhoNeedHelpWeb.SecurityHeaders do
|
|
@moduledoc false
|
|
|
|
import Plug.Conn
|
|
|
|
def put_content_security_policy(conn, _opts) do
|
|
tile_origin =
|
|
:who_need_help
|
|
|> Application.fetch_env!(:map_tile_url)
|
|
|> origin()
|
|
|
|
websocket_origins =
|
|
[
|
|
origin(%URI{scheme: "ws", host: conn.host, port: conn.port}),
|
|
origin(%URI{scheme: "wss", host: conn.host, port: default_https_port(conn)})
|
|
]
|
|
|> Enum.reject(&is_nil/1)
|
|
|> Enum.uniq()
|
|
|
|
connect_sources = sources(["'self'", tile_origin | websocket_origins])
|
|
image_sources = sources(["'self'", "data:", "blob:", tile_origin])
|
|
|
|
policy =
|
|
[
|
|
"default-src 'self'",
|
|
"base-uri 'self'",
|
|
"frame-ancestors 'none'",
|
|
"object-src 'none'",
|
|
"script-src 'self'",
|
|
"style-src 'self' 'unsafe-inline'",
|
|
"img-src #{image_sources}",
|
|
"connect-src #{connect_sources}",
|
|
"worker-src 'self' blob:",
|
|
"manifest-src 'self'",
|
|
"form-action 'self'"
|
|
]
|
|
|> Enum.join("; ")
|
|
|
|
put_resp_header(conn, "content-security-policy", policy)
|
|
end
|
|
|
|
defp default_https_port(%Plug.Conn{port: 443}), do: 443
|
|
defp default_https_port(_conn), do: nil
|
|
|
|
defp sources(values),
|
|
do: values |> Enum.reject(&is_nil/1) |> Enum.uniq() |> Enum.join(" ")
|
|
|
|
defp origin(url) when is_binary(url), do: url |> URI.parse() |> origin()
|
|
|
|
defp origin(%URI{scheme: scheme, host: host} = uri)
|
|
when scheme in ["http", "https", "ws", "wss"] and is_binary(host) and host != "" do
|
|
URI.to_string(%URI{scheme: scheme, host: host, port: uri.port})
|
|
end
|
|
|
|
defp origin(_uri), do: nil
|
|
end
|