-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).