Packages

A module for parsing, mutating, and serializing Content-Security-Policy directives.

Current section

Files

Jump to
cosepo src cosepo.erl
Raw

src/cosepo.erl

-module(cosepo).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch]).
-export([serialize/1, merge/2, set/2, new_directive/2, parse/1]).
-export_type([content_security_policy/0, directive/0]).
-type content_security_policy() :: {content_security_policy, list(directive())}.
-opaque directive() :: {directive, binary(), list(binary())}.
-spec serialize(content_security_policy()) -> binary().
serialize(Content_security_policy) ->
_pipe = gleam@list:fold(
erlang:element(2, Content_security_policy),
<<""/utf8>>,
fun(Serialized_csp, Directive) ->
<<<<<<Serialized_csp/binary, (erlang:element(2, Directive))/binary>>/binary,
(gleam@list:fold(
erlang:element(3, Directive),
<<""/utf8>>,
fun(Serialized_directive, Value) ->
<<<<Serialized_directive/binary, " "/utf8>>/binary,
Value/binary>>
end
))/binary>>/binary,
"; "/utf8>>
end
),
gleam@string:trim(_pipe).
-spec find_directive_by_name(content_security_policy(), binary()) -> {ok,
directive()} |
{error, nil}.
find_directive_by_name(Content_security_policy, Name) ->
gleam@list:find(
erlang:element(2, Content_security_policy),
fun(Directive) -> erlang:element(2, Directive) =:= Name end
).
-spec merge(content_security_policy(), directive()) -> content_security_policy().
merge(Content_security_policy, Directive) ->
_pipe = case find_directive_by_name(
Content_security_policy,
erlang:element(2, Directive)
) of
{error, _} ->
lists:append(
erlang:element(2, Content_security_policy),
[Directive]
);
{ok, Existing_directive} ->
Value = lists:append(
erlang:element(3, Existing_directive),
erlang:element(3, Directive)
),
[erlang:setelement(3, Directive, Value)]
end,
{content_security_policy, _pipe}.
-spec set(content_security_policy(), directive()) -> content_security_policy().
set(Content_security_policy, Directive) ->
_pipe = case find_directive_by_name(
Content_security_policy,
erlang:element(2, Directive)
) of
{error, _} ->
lists:append(
erlang:element(2, Content_security_policy),
[Directive]
);
{ok, Existing_directive} ->
[erlang:setelement(
3,
Existing_directive,
erlang:element(3, Directive)
)]
end,
{content_security_policy, _pipe}.
-spec new_directive(binary(), list(binary())) -> {ok, directive()} |
{error, binary()}.
new_directive(Name, Value) ->
case gleam@list:find(
[<<"base-uri"/utf8>>,
<<"child-src"/utf8>>,
<<"connect-src"/utf8>>,
<<"default-src"/utf8>>,
<<"font-src"/utf8>>,
<<"form-action"/utf8>>,
<<"frame-ancestors"/utf8>>,
<<"frame-src"/utf8>>,
<<"img-src"/utf8>>,
<<"manifest-src"/utf8>>,
<<"media-src"/utf8>>,
<<"object-src"/utf8>>,
<<"script-src"/utf8>>,
<<"script-src-attr"/utf8>>,
<<"script-src-elem"/utf8>>,
<<"style-src"/utf8>>,
<<"style-src-attr"/utf8>>,
<<"style-src-elem"/utf8>>,
<<"upgrade-insecure-requests"/utf8>>,
<<"worker-src"/utf8>>],
fun(X) -> X =:= Name end
) of
{error, _} ->
{error, <<Name/binary, " is not a valid directive name"/utf8>>};
{ok, _} ->
case Name of
<<"upgrade-insecure-requests"/utf8>> ->
case Value of
[] ->
{ok, {directive, Name, Value}};
_ ->
{error,
<<"unexpected values for upgrade-insecure-requests directive"/utf8>>}
end;
_ ->
{ok, {directive, Name, Value}}
end
end.
-spec parse(binary()) -> {ok, content_security_policy()} | {error, binary()}.
parse(Serialized_csp) ->
Csp = {ok, {content_security_policy, []}},
gleam@list:fold(
gleam@string:split(Serialized_csp, <<";"/utf8>>),
Csp,
fun(Accumulator, Directive) -> case Accumulator of
{error, E} ->
{error, E};
{ok, Valid_csp} ->
Trimmed_directive = gleam@string:trim(Directive),
case gleam@string:split(Trimmed_directive, <<" "/utf8>>) of
[] ->
{error, <<"Nothing to parse!"/utf8>>};
[Name] ->
case Name of
<<"upgrade-insecure-requests"/utf8>> ->
{ok,
merge(
Valid_csp,
{directive,
<<"upgrade-insecure-requests"/utf8>>,
[]}
)};
<<""/utf8>> ->
{ok, Valid_csp};
_ ->
{error,
<<"missing directive values for "/utf8,
Trimmed_directive/binary>>}
end;
[Name@1 | Value] ->
case new_directive(
gleam@string:lowercase(Name@1),
Value
) of
{error, E@1} ->
{error, E@1};
{ok, New_directive} ->
{ok, merge(Valid_csp, New_directive)}
end
end
end end
).