-module(plume).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/plume.gleam").
-export([new/0, default/0, set_headers/2, middleware/2]).
-export_type([config/0]).
-if(?OTP_RELEASE >= 27).
-define(MODULEDOC(Str), -moduledoc(Str)).
-define(DOC(Str), -doc(Str)).
-else.
-define(MODULEDOC(Str), -compile([])).
-define(DOC(Str), -compile([])).
-endif.
?MODULEDOC(
" Sensible HTTP security headers for Gleam web servers, inspired by\n"
" [helmet](https://helmetjs.github.io/). Built on\n"
" [gleam_http](https://hexdocs.pm/gleam_http/), so it works with\n"
" [wisp](https://hexdocs.pm/wisp/), [mist](https://hexdocs.pm/mist/), or\n"
" any other compatible server.\n"
"\n"
" Build a `Config` describing which headers to set on outgoing responses,\n"
" then apply it. `default` ships a reasonable starter policy; `new`\n"
" starts with no headers set.\n"
"\n"
" As `use` middleware:\n"
"\n"
" ```gleam\n"
" use <- plume.middleware(plume.default())\n"
" response.new(200)\n"
" ```\n"
"\n"
" Or directly on a response:\n"
"\n"
" ```gleam\n"
" response.new(200)\n"
" |> plume.set_headers(plume.default())\n"
" ```\n"
).
-type config() :: {config,
gleam@option:option(plume@content_security_policy:content_security_policy()),
gleam@option:option(plume@content_type_options:content_type_options()),
gleam@option:option(plume@cross_origin_embedder_policy:cross_origin_embedder_policy()),
gleam@option:option(plume@cross_origin_opener_policy:cross_origin_opener_policy()),
gleam@option:option(plume@cross_origin_resource_policy:cross_origin_resource_policy()),
gleam@option:option(plume@dns_prefetch_control:dns_prefetch_control()),
gleam@option:option(plume@download_options:download_options()),
gleam@option:option(plume@frame_options:frame_options()),
gleam@option:option(plume@origin_agent_cluster:origin_agent_cluster()),
gleam@option:option(plume@permissions_policy:permissions_policy()),
gleam@option:option(plume@permitted_cross_domain_policies:permitted_cross_domain_policies()),
gleam@option:option(plume@referrer_policy:referrer_policy()),
gleam@option:option(plume@strict_transport_security:strict_transport_security()),
gleam@option:option(plume@xss_protection:xss_protection())}.
-file("src/plume.gleam", 67).
?DOC(
" A `Config` with no headers configured. Use this when you want to opt in\n"
" to each header individually rather than starting from `default`.\n"
).
-spec new() -> config().
new() ->
{config,
none,
none,
none,
none,
none,
none,
none,
none,
none,
none,
none,
none,
none,
none}.
-file("src/plume.gleam", 98).
?DOC(
" A `Config` with sensible defaults: a starter CSP, `nosniff`,\n"
" `SameOrigin` frame options, HSTS for one year on the host and its\n"
" subdomains, and other widely-recommended values.\n"
"\n"
" ## Examples\n"
"\n"
" Override individual fields with record update syntax:\n"
"\n"
" ```gleam\n"
" Config(..default(), frame_options: Some(frame_options.Deny))\n"
" ```\n"
).
-spec default() -> config().
default() ->
{config,
{some,
{policy,
[{default_src, [self]},
{base_uri, [self]},
{font_src,
[self,
{scheme, <<"https"/utf8>>},
{scheme, <<"data"/utf8>>}]},
{form_action, [self]},
{frame_ancestors, [self]},
{img_src, [self, {scheme, <<"data"/utf8>>}]},
{object_src, [none]},
{script_src, [self]},
{script_src_attr, [none]},
{style_src,
[self, {scheme, <<"https"/utf8>>}, unsafe_inline]},
upgrade_insecure_requests]}},
{some, no_sniff},
none,
{some, same_origin},
{some, same_origin},
{some, off},
{some, no_open},
{some, same_origin},
{some, enabled},
none,
{some, none},
{some, no_referrer},
{some, {include_sub_domains, 31536000}},
{some, disabled}}.
-file("src/plume.gleam", 204).
-spec set_header_if_some(
gleam@http@response:response(ERK),
gleam@option:option(ERM),
binary(),
fun((ERM) -> binary())
) -> gleam@http@response:response(ERK).
set_header_if_some(Resp, Value, Name, Render) ->
case Value of
{some, Value@1} ->
gleam@http@response:set_header(Resp, Name, Render(Value@1));
none ->
Resp
end.
-file("src/plume.gleam", 142).
?DOC(" Set the headers from `config` on an existing response.\n").
-spec set_headers(gleam@http@response:response(ERH), config()) -> gleam@http@response:response(ERH).
set_headers(Resp, Config) ->
_pipe = Resp,
_pipe@1 = set_header_if_some(
_pipe,
erlang:element(2, Config),
<<"content-security-policy"/utf8>>,
fun plume@content_security_policy:to_string/1
),
_pipe@2 = set_header_if_some(
_pipe@1,
erlang:element(3, Config),
<<"x-content-type-options"/utf8>>,
fun plume@content_type_options:to_string/1
),
_pipe@3 = set_header_if_some(
_pipe@2,
erlang:element(4, Config),
<<"cross-origin-embedder-policy"/utf8>>,
fun plume@cross_origin_embedder_policy:to_string/1
),
_pipe@4 = set_header_if_some(
_pipe@3,
erlang:element(5, Config),
<<"cross-origin-opener-policy"/utf8>>,
fun plume@cross_origin_opener_policy:to_string/1
),
_pipe@5 = set_header_if_some(
_pipe@4,
erlang:element(6, Config),
<<"cross-origin-resource-policy"/utf8>>,
fun plume@cross_origin_resource_policy:to_string/1
),
_pipe@6 = set_header_if_some(
_pipe@5,
erlang:element(7, Config),
<<"x-dns-prefetch-control"/utf8>>,
fun plume@dns_prefetch_control:to_string/1
),
_pipe@7 = set_header_if_some(
_pipe@6,
erlang:element(8, Config),
<<"x-download-options"/utf8>>,
fun plume@download_options:to_string/1
),
_pipe@8 = set_header_if_some(
_pipe@7,
erlang:element(9, Config),
<<"x-frame-options"/utf8>>,
fun plume@frame_options:to_string/1
),
_pipe@9 = set_header_if_some(
_pipe@8,
erlang:element(10, Config),
<<"origin-agent-cluster"/utf8>>,
fun plume@origin_agent_cluster:to_string/1
),
_pipe@10 = set_header_if_some(
_pipe@9,
erlang:element(11, Config),
<<"permissions-policy"/utf8>>,
fun plume@permissions_policy:to_string/1
),
_pipe@11 = set_header_if_some(
_pipe@10,
erlang:element(12, Config),
<<"x-permitted-cross-domain-policies"/utf8>>,
fun plume@permitted_cross_domain_policies:to_string/1
),
_pipe@12 = set_header_if_some(
_pipe@11,
erlang:element(13, Config),
<<"referrer-policy"/utf8>>,
fun plume@referrer_policy:to_string/1
),
_pipe@13 = set_header_if_some(
_pipe@12,
erlang:element(14, Config),
<<"strict-transport-security"/utf8>>,
fun plume@strict_transport_security:to_string/1
),
set_header_if_some(
_pipe@13,
erlang:element(15, Config),
<<"x-xss-protection"/utf8>>,
fun plume@xss_protection:to_string/1
).
-file("src/plume.gleam", 133).
?DOC(" Run `handler` and set the headers from `config` on the resulting response.\n").
-spec middleware(config(), fun(() -> gleam@http@response:response(ERE))) -> gleam@http@response:response(ERE).
middleware(Config, Handler) ->
_pipe = Handler(),
set_headers(_pipe, Config).