Packages
oidcc
3.8.0-beta.1
3.8.0
3.8.0-beta.1
3.7.2
3.7.1
3.7.0
3.6.0
3.5.2
3.5.1
3.5.0
retired
3.4.0
3.3.0
3.2.6
3.2.5
3.2.4
3.2.3
3.2.2
3.2.1
3.2.0
3.2.0-beta.3
3.2.0-beta.2
retired
3.2.0-beta.1
retired
3.1.2
3.1.2-beta.1
retired
3.1.1
retired
3.1.0
retired
3.1.0-beta.2
retired
3.1.0-beta.1
retired
3.0.2
3.0.1
retired
3.0.0
retired
3.0.0-rc.6
retired
3.0.0-rc.5
retired
3.0.0-rc.4
retired
3.0.0-rc.3
retired
3.0.0-rc.2
retired
3.0.0-rc.1
retired
3.0.0-alpha.5
retired
3.0.0-alpha.4
retired
3.0.0-alpha.3
retired
3.0.0-alpha.2
retired
3.0.0-alpha.1
retired
2.0.0-alpha.2
retired
2.0.0-alpha.1
retired
1.8.1
retired
1.8.0
retired
1.7.0
retired
1.6.0
retired
1.5.1
retired
1.5.0
retired
1.4.0
retired
1.3.0
retired
1.2.1
retired
1.2.0
retired
1.1.0
retired
1.0.1
retired
1.0.0
retired
OpenID Connect client library for the BEAM.
Current section
Files
Jump to
Current section
Files
src/oidcc_decode_util.erl
%% SPDX-FileCopyrightText: 2023 Erlang Ecosystem Foundation
%% SPDX-License-Identifier: Apache-2.0
-module(oidcc_decode_util).
-moduledoc "Response Decoding Utils".
-moduledoc #{since => <<"3.0.0">>}.
-export([extract/3]).
-export([parse_setting_binary/2]).
-export([parse_setting_binary_list/2]).
-export([parse_setting_boolean/2]).
-export([parse_setting_list_enum/3]).
-export([parse_setting_number/2]).
-export([parse_setting_uri/2]).
-export([parse_setting_uri_https/2]).
-export([parse_setting_uri_map/2]).
-export([parse_setting_uri_https_map/2]).
-export_type([error/0]).
-doc #{since => <<"3.0.0">>}.
-type error() ::
{missing_config_property, Key :: atom()}
| {invalid_config_property, {
Type ::
uri
| uri_https
| binary
| number
| list_of_binaries
| boolean
| scopes_including_openid
| enum
| alg_no_none,
Field :: atom()
}}.
-doc false.
-spec extract(
Map :: #{binary() => term()},
Keys :: [{required, Key, ParseFn} | {optional, Key, Default, ParseFn}],
Acc :: #{atom() => term()}
) ->
{ok, {Matched, Rest}} | {error, error()}
when
Key :: atom(),
Default :: term(),
ParseFn :: fun((Setting :: term(), Key) -> {ok, term()} | {error, error()}),
Matched :: #{Key => Default | undefined | term()},
Rest :: #{binary() => term()}.
extract(Map1, [{required, Key, ParseFn} | RestKeys], Acc) ->
case maps:take(atom_to_binary(Key), Map1) of
{Value, Map2} ->
case ParseFn(Value, Key) of
{ok, Parsed} ->
extract(Map2, RestKeys, maps:put(Key, Parsed, Acc));
{error, Reason} ->
{error, Reason}
end;
error ->
{error, {missing_config_property, Key}}
end;
extract(Map1, [{optional, Key, Default, ParseFn} | RestKeys], Acc) ->
case maps:take(atom_to_binary(Key), Map1) of
{undefined, Map2} ->
extract(Map2, RestKeys, maps:put(Key, Default, Acc));
{Value, Map2} ->
case ParseFn(Value, Key) of
{ok, Parsed} ->
extract(Map2, RestKeys, maps:put(Key, Parsed, Acc));
{error, Reason} ->
{error, Reason}
end;
error ->
extract(Map1, RestKeys, maps:put(Key, Default, Acc))
end;
extract(Map, [], Acc) ->
{ok, {Acc, Map}}.
-doc false.
-spec parse_setting_uri(Setting :: term(), Field :: atom()) ->
{ok, uri_string:uri_string()} | {error, error()}.
parse_setting_uri(Setting, _Field) when is_binary(Setting) ->
{ok, Setting};
parse_setting_uri(_Setting, Field) ->
{error, {invalid_config_property, {uri, Field}}}.
-doc false.
-spec parse_setting_uri_https(Setting :: term(), Field :: atom()) ->
{ok, uri_string:uri_string()} | {error, error()}.
parse_setting_uri_https(Setting, Field) when is_binary(Setting) ->
case uri_string:parse(Setting) of
#{scheme := <<"https">>} ->
{ok, Setting};
#{scheme := _Scheme} ->
{error, {invalid_config_property, {uri_https, Field}}}
end;
parse_setting_uri_https(_Setting, Field) ->
{error, {invalid_config_property, {uri_https, Field}}}.
-doc false.
-spec parse_setting_uri_map(Setting :: term(), Field :: atom()) ->
{ok, #{binary() => uri_string:uri_string()}} | {error, error()}.
parse_setting_uri_map(Setting, Field) ->
do_parse_setting_uri_map(Setting, Field, fun parse_setting_uri/2).
-doc false.
-spec parse_setting_uri_https_map(Setting :: term(), Field :: atom()) ->
{ok, #{binary() => uri_string:uri_string()}} | {error, error()}.
parse_setting_uri_https_map(Setting, Field) ->
do_parse_setting_uri_map(Setting, Field, fun parse_setting_uri_https/2).
do_parse_setting_uri_map(#{} = Setting, Field, Parser) ->
SettingList = maps:to_list(Setting),
case
lists:foldl(
fun
(_Elem, {error, Reason}) ->
{error, Reason};
({BinKey, Value}, {ok, Acc}) when is_binary(BinKey) ->
case Parser(Value, Field) of
{ok, SettingValue} ->
{ok, [{BinKey, SettingValue} | Acc]};
{error, Reason} ->
{error, Reason}
end;
(_, _) ->
{error, {invalid_config_property, {uri_map, Field}}}
end,
{ok, []},
SettingList
)
of
{ok, ParsedList} ->
{ok, maps:from_list(ParsedList)};
{error, Reason} ->
{error, Reason}
end;
do_parse_setting_uri_map(_Setting, Field, _Parser) ->
{error, {invalid_config_property, {uri_map, Field}}}.
-doc false.
-spec parse_setting_binary(Setting :: term(), Field :: atom()) ->
{ok, binary()} | {error, error()}.
parse_setting_binary(Setting, _Field) when is_binary(Setting) ->
{ok, Setting};
parse_setting_binary(_Setting, Field) ->
{error, {invalid_config_property, {binary, Field}}}.
-doc false.
-spec parse_setting_binary_list(Setting :: term(), Field :: atom()) ->
{ok, [binary()]} | {error, error()}.
parse_setting_binary_list(Setting, Field) when is_list(Setting) ->
case lists:all(fun is_binary/1, Setting) of
true ->
{ok, Setting};
false ->
{error, {invalid_config_property, {list_of_binaries, Field}}}
end;
parse_setting_binary_list(_Setting, Field) ->
{error, {invalid_config_property, {list_of_binaries, Field}}}.
-doc false.
-spec parse_setting_number(Setting :: term(), Field :: atom()) ->
{ok, integer()} | {error, error()}.
parse_setting_number(Setting, _Field) when is_integer(Setting) ->
{ok, Setting};
parse_setting_number(_Setting, Field) ->
{error, {invalid_config_property, {number, Field}}}.
-doc false.
-spec parse_setting_boolean(Setting :: term(), Field :: atom()) ->
{ok, boolean()} | {error, error()}.
parse_setting_boolean(Setting, _Field) when is_boolean(Setting) ->
{ok, Setting};
parse_setting_boolean(_Setting, Field) ->
{error, {invalid_config_property, {boolean, Field}}}.
-doc false.
-spec parse_setting_list_enum(
Setting :: term(),
Field :: atom(),
Parse :: fun((binary()) -> {ok, Value} | error)
) ->
{ok, [Value]} | {error, error()}
when
Value :: term().
parse_setting_list_enum(Setting, Field, Parse) ->
case parse_setting_binary_list(Setting, Field) of
{ok, Values} ->
Parsed =
lists:map(
fun(Value) ->
case Parse(Value) of
{ok, ParsedValue} ->
{ok, ParsedValue};
error ->
{error, Value}
end
end,
Values
),
case
lists:filter(
fun
({ok, _Value}) ->
false;
({error, _Value}) ->
true
end,
Parsed
)
of
[] ->
{ok, lists:map(fun({ok, Value}) -> Value end, Parsed)};
[{error, _InvalidValue} | _Rest] ->
{error, {invalid_config_property, {enum, Field}}}
end;
{error, Reason} ->
{error, Reason}
end.