refactor(emqx_license): simplify parser errors

prior to this change, badmatch exception may cause the license key
to be dumped in logs
This commit is contained in:
Zaiming (Stone) Shi 2022-02-08 17:57:37 +01:00
parent 774c0a3d7f
commit cd3565d357
5 changed files with 30 additions and 20 deletions

View File

@ -129,6 +129,7 @@ do_update({key, Content}, _Conf) when is_binary(Content); is_list(Content) ->
{ok, _License} -> {ok, _License} ->
#{<<"key">> => Content}; #{<<"key">> => Content};
{error, Reason} -> {error, Reason} ->
?SLOG(error, #{msg => "failed_to_parse_license", reason => Reason}),
error(Reason) error(Reason)
end. end.

View File

@ -98,7 +98,7 @@ max_connections(#{module := Module, data := LicenseData}) ->
%%-------------------------------------------------------------------- %%--------------------------------------------------------------------
do_parse(_Content, _Key, [], Errors) -> do_parse(_Content, _Key, [], Errors) ->
{error, {unknown_format, lists:reverse(Errors)}}; {error, lists:reverse(Errors)};
do_parse(Content, Key, [Module | Modules], Errors) -> do_parse(Content, Key, [Module | Modules], Errors) ->
try Module:parse(Content, Key) of try Module:parse(Content, Key) of
@ -107,7 +107,7 @@ do_parse(Content, Key, [Module | Modules], Errors) ->
{error, Error} -> {error, Error} ->
do_parse(Content, Key, Modules, [{Module, Error} | Errors]) do_parse(Content, Key, Modules, [{Module, Error} | Errors])
catch catch
_Class:Error:_Stk -> _Class : Error ->
do_parse(Content, Key, Modules, [{Module, Error} | Errors]) do_parse(Content, Key, Modules, [{Module, Error} | Errors])
end. end.

View File

@ -24,12 +24,14 @@
%%------------------------------------------------------------------------------ %%------------------------------------------------------------------------------
parse(Content, Key) -> parse(Content, Key) ->
[EncodedPayload, EncodedSignature] = binary:split(Content, <<".">>), case do_parse(Content) of
Payload = base64:decode(EncodedPayload), {ok, {Payload, Signature}} ->
Signature = base64:decode(EncodedSignature),
case verify_signature(Payload, Signature, Key) of case verify_signature(Payload, Signature, Key) of
true -> parse_payload(Payload); true -> parse_payload(Payload);
false -> {error, invalid_signature} false -> {error, invalid_signature}
end;
{error, Reason} ->
{error, Reason}
end. end.
dump(#{type := Type, dump(#{type := Type,
@ -67,6 +69,17 @@ max_connections(#{max_connections := MaxConns}) ->
%% Private functions %% Private functions
%%------------------------------------------------------------------------------ %%------------------------------------------------------------------------------
do_parse(Content) ->
try
[EncodedPayload, EncodedSignature] = binary:split(Content, <<".">>),
Payload = base64:decode(EncodedPayload),
Signature = base64:decode(EncodedSignature),
{ok, {Payload, Signature}}
catch
_ : _ ->
{error, bad_license_format}
end.
verify_signature(Payload, Signature, Key) -> verify_signature(Payload, Signature, Key) ->
RSAPublicKey = public_key:der_decode('RSAPublicKey', Key), RSAPublicKey = public_key:der_decode('RSAPublicKey', Key),
public_key:verify(Payload, ?DIGEST_TYPE, Signature, RSAPublicKey). public_key:verify(Payload, ?DIGEST_TYPE, Signature, RSAPublicKey).

View File

@ -68,7 +68,7 @@ t_update_file(_Config) ->
ok = file:write_file("license_with_invalid_content.lic", <<"bad license">>), ok = file:write_file("license_with_invalid_content.lic", <<"bad license">>),
?assertMatch( ?assertMatch(
{error, {unknown_format, _}}, {error, [_ | _]},
emqx_license:update_file("license_with_invalid_content.lic")), emqx_license:update_file("license_with_invalid_content.lic")),
?assertMatch( ?assertMatch(
@ -77,7 +77,7 @@ t_update_file(_Config) ->
t_update_value(_Config) -> t_update_value(_Config) ->
?assertMatch( ?assertMatch(
{error, {unknown_format, _}}, {error, [_ | _]},
emqx_license:update_key("invalid.license")), emqx_license:update_key("invalid.license")),
{ok, LicenseValue} = file:read_file(emqx_license_test_lib:default_license()), {ok, LicenseValue} = file:read_file(emqx_license_test_lib:default_license()),

View File

@ -45,8 +45,7 @@ t_parse(_Config) ->
%% invalid version %% invalid version
?assertMatch( ?assertMatch(
{error, {error,
{unknown_format, [{emqx_license_parser_v20220101,invalid_version}]},
[{emqx_license_parser_v20220101,invalid_version}]}},
emqx_license_parser:parse( emqx_license_parser:parse(
emqx_license_test_lib:make_license( emqx_license_test_lib:make_license(
["220101", ["220101",
@ -63,8 +62,7 @@ t_parse(_Config) ->
%% invalid field number %% invalid field number
?assertMatch( ?assertMatch(
{error, {error,
{unknown_format, [{emqx_license_parser_v20220101,invalid_field_number}]},
[{emqx_license_parser_v20220101,invalid_field_number}]}},
emqx_license_parser:parse( emqx_license_parser:parse(
emqx_license_test_lib:make_license( emqx_license_test_lib:make_license(
["220111", ["220111",
@ -80,12 +78,11 @@ t_parse(_Config) ->
?assertMatch( ?assertMatch(
{error, {error,
{unknown_format,
[{emqx_license_parser_v20220101, [{emqx_license_parser_v20220101,
[{type,invalid_license_type}, [{type,invalid_license_type},
{customer_type,invalid_customer_type}, {customer_type,invalid_customer_type},
{date_start,invalid_date}, {date_start,invalid_date},
{days,invalid_int_value}]}]}}, {days,invalid_int_value}]}]},
emqx_license_parser:parse( emqx_license_parser:parse(
emqx_license_test_lib:make_license( emqx_license_test_lib:make_license(
["220111", ["220111",
@ -125,21 +122,20 @@ t_parse(_Config) ->
?assertMatch( ?assertMatch(
{error, {error,
{unknown_format, [{emqx_license_parser_v20220101,invalid_signature}]},
[{emqx_license_parser_v20220101,invalid_signature}]}},
emqx_license_parser:parse( emqx_license_parser:parse(
iolist_to_binary([LicensePart, <<".">>, SignaturePart]), iolist_to_binary([LicensePart, <<".">>, SignaturePart]),
public_key_encoded())), public_key_encoded())),
%% totally invalid strings as license %% totally invalid strings as license
?assertMatch( ?assertMatch(
{error, {unknown_format, _}}, {error, [_ | _]},
emqx_license_parser:parse( emqx_license_parser:parse(
<<"badlicense">>, <<"badlicense">>,
public_key_encoded())), public_key_encoded())),
?assertMatch( ?assertMatch(
{error, {unknown_format, _}}, {error, [_ | _]},
emqx_license_parser:parse( emqx_license_parser:parse(
<<"bad.license">>, <<"bad.license">>,
public_key_encoded())). public_key_encoded())).