Packages

HTTP security headers with validatation for Phoenix/Plug

Current section

Files

Jump to
plug_secure_headers lib plug_secure_headers.ex~
Raw

lib/plug_secure_headers.ex~

defmodule PlugSecureHeaders do
use Pipe
import Plug.Conn, only: [halt: 1, delete_resp_header: 2, update_resp_header: 4]
@secure_config [
warn_only: false,
merge_config: false,
report_only: false,
use_secure_config: true,
config: [
content_security_policy: "default-src 'none'; script-src 'self'; connect-src 'self'; img-src 'self'; style-src 'self';",
http_public_key_pins: "",
strict_transport_security: "max-age=631138519",
x_content_type_options: "nosniff",
x_download_options: "noopen",
x_frame_options: "sameorigin",
x_permitted_cross_domain_policies: "none",
x_xss_protection: "1; mode=block"
]
]
defp get_config(options, boolean) do
if(boolean) do
get_in(options, [:plug_secure_headers, :config])
end
end
defp merge_config?(options) do
get_in(options, [:plug_secure_headers, :merge_config])
end
def init(options) do
options =
options
|> merge_config?
|> merge_config!
validate(options)
IO.puts "init:"
IO.inspect options
options
end
@doc "Callback implementation for Plug.call/2"
def call(conn, options) do
case Keyword.has_key?(options, :config) do
false -> halt(conn)
true -> set_headers(conn, options)
end
end
defp set_headers(conn, options) when options |> is_list do
conn
|> delete(options[:config])
|> set(options[:config])
end
defp set_headers(conn, _) do
conn
end
defp validate(options) do
pipe_matching x, {:ok, x},
options
|> PlugSecureHeaders.PlugSecureHeaders.validate
|> PlugSecureHeaders.ContentSecurityPolicy.validate
|> PlugSecureHeaders.HttpPublicKeyPins.validate
|> PlugSecureHeaders.StrictTrasportSecurity.validate
|> PlugSecureHeaders.XContentTypeOptions.validate
|> PlugSecureHeaders.XDownloadOptions.validate
|> PlugSecureHeaders.XFrameOptions.validate
|> PlugSecureHeaders.XPermittedCrossDomainPolicies.validate
|> PlugSecureHeaders.XXssProtection.validate
end
defp set(conn, nil), do: conn
defp set(conn, list) when list |> is_list do
List.foldl(list, conn, fn({key, value}, conn) -> set(conn, dasherize(key), value) end)
end
defp set(conn, _key, nil), do: conn
defp set(conn, key, value) when value |> is_bitstring do
update_resp_header(conn, key, value, fn(_) -> value end)
end
defp delete(conn, nil), do: conn
defp delete(conn, []), do: conn
defp delete(conn, [h|t]) when h |> is_bitstring do
conn
|> delete_resp_header(h)
|> delete(t)
end
defp delete(conn, list) when list |> is_list do
List.foldl(list, conn, fn({key, _}, conn) -> delete(conn, dasherize(key)) end)
end
defp delete(conn, key) when key |> is_bitstring, do: delete(conn, [key])
defp dasherize(data) when is_atom(data), do: dasherize(Atom.to_string(data))
defp dasherize(data), do: String.replace(data, "_", "-")
defp merge_config!(options) do
env_options = Application.get_env(:plug_secure_headers, PlugSecureHeaders)
env_config = get_config(env_options, true)
config = get_config(options, true)
merged_config = Keyword.merge(env_config, config)
# options = set_config(options, merged_config)
IO.inspect merged_config
IO.puts "merge_config!"
IO.inspect config
Keyword.merge(env_options, options)
end
end