chore: dashboard format code

This commit is contained in:
DDDHuang 2022-04-26 16:54:14 +08:00
parent 2ea66ebcee
commit 07444e3da5
19 changed files with 363 additions and 276 deletions

View File

@ -20,17 +20,18 @@
pwdhash :: binary(),
description :: binary(),
role = undefined :: atom(),
extra = [] :: term() %% not used so far, for future extension
%% not used so far, for future extension
extra = [] :: term()
}).
-define(ADMIN_JWT, emqx_admin_jwt).
-record(?ADMIN_JWT, {
token :: binary(),
username :: binary(),
exptime :: integer(),
extra = [] :: term() %% not used so far, fur future extension
%% not used so far, fur future extension
extra = [] :: term()
}).
-define(TAB_COLLECT, emqx_collect).
@ -49,18 +50,18 @@
-define(RPC_TIMEOUT, 5000).
-endif.
-define(DELTA_SAMPLER_LIST,
[ received
-define(DELTA_SAMPLER_LIST, [
received,
%, received_bytes
, sent
sent,
%, sent_bytes
, dropped
dropped
]).
-define(GAUGE_SAMPLER_LIST,
[ subscriptions
, topics
, connections
-define(GAUGE_SAMPLER_LIST, [
subscriptions,
topics,
connections
]).
-define(SAMPLER_LIST, ?GAUGE_SAMPLER_LIST ++ ?DELTA_SAMPLER_LIST).

View File

@ -3,16 +3,25 @@
{deps, [{emqx, {path, "../emqx"}}]}.
{edoc_opts, [{preprocess, true}]}.
{erl_opts, [warn_unused_vars,
{erl_opts, [
warn_unused_vars,
warn_shadow_vars,
warn_unused_import,
warn_obsolete_guard,
debug_info,
{d, 'APPLICATION', emqx}]}.
{xref_checks, [undefined_function_calls, undefined_functions,
locals_not_used, deprecated_function_calls,
warnings_as_errors, deprecated_functions]}.
{d, 'APPLICATION', emqx}
]}.
{xref_checks, [
undefined_function_calls,
undefined_functions,
locals_not_used,
deprecated_function_calls,
warnings_as_errors,
deprecated_functions
]}.
{cover_enabled, true}.
{cover_opts, [verbose]}.
{cover_export_enabled, true}.
{eunit_first_files, ["test/emqx_swagger_remote_schema.erl"]}.
{project_plugins, [erlfmt]}.

View File

@ -1,7 +1,8 @@
%% -*- mode: erlang -*-
{application, emqx_dashboard,
[{description, "EMQX Web Dashboard"},
{vsn, "5.0.0"}, % strict semver, bump manually!
{application, emqx_dashboard, [
{description, "EMQX Web Dashboard"},
% strict semver, bump manually!
{vsn, "5.0.0"},
{modules, []},
{registered, [emqx_dashboard_sup]},
{applications, [kernel, stdlib, mnesia, minirest, emqx]},
@ -9,7 +10,8 @@
{env, []},
{licenses, ["Apache-2.0"]},
{maintainers, ["EMQX Team <contact@emqx.io>"]},
{links, [{"Homepage", "https://emqx.io/"},
{links, [
{"Homepage", "https://emqx.io/"},
{"Github", "https://github.com/emqx/emqx-dashboard"}
]}
]}.

View File

@ -26,27 +26,31 @@
%% Mnesia bootstrap
-export([mnesia/1]).
-export([ add_user/3
, force_add_user/3
, remove_user/1
, update_user/2
, lookup_user/1
, change_password/2
, change_password/3
, all_users/0
, check/2
-export([
add_user/3,
force_add_user/3,
remove_user/1,
update_user/2,
lookup_user/1,
change_password/2,
change_password/3,
all_users/0,
check/2
]).
-export([ sign_token/2
, verify_token/1
, destroy_token_by_username/2
-export([
sign_token/2,
verify_token/1,
destroy_token_by_username/2
]).
-export([ hash/1
, verify_hash/2
-export([
hash/1,
verify_hash/2
]).
-export([ add_default_user/0
, default_username/0
-export([
add_default_user/0,
default_username/0
]).
-type emqx_admin() :: #?ADMIN{}.
@ -62,36 +66,46 @@ mnesia(boot) ->
{storage, disc_copies},
{record_name, ?ADMIN},
{attributes, record_info(fields, ?ADMIN)},
{storage_properties, [{ets, [{read_concurrency, true},
{write_concurrency, true}]}]}]).
{storage_properties, [
{ets, [
{read_concurrency, true},
{write_concurrency, true}
]}
]}
]).
%%--------------------------------------------------------------------
%% API
%%--------------------------------------------------------------------
-spec(add_user(binary(), binary(), binary()) -> {ok, map()} | {error, any()}).
add_user(Username, Password, Desc)
when is_binary(Username), is_binary(Password) ->
-spec add_user(binary(), binary(), binary()) -> {ok, map()} | {error, any()}.
add_user(Username, Password, Desc) when
is_binary(Username), is_binary(Password)
->
case legal_username(Username) of
true ->
return(
mria:transaction(?DASHBOARD_SHARD, fun add_user_/3, [Username, Password, Desc]));
mria:transaction(?DASHBOARD_SHARD, fun add_user_/3, [Username, Password, Desc])
);
false ->
{error, <<"Bad Username."
" Only upper and lower case letters, numbers and underscores are supported">>}
{error, <<
"Bad Username."
" Only upper and lower case letters, numbers and underscores are supported"
>>}
end.
%% 0 - 9 or A -Z or a - z or $_
legal_username(<<>>) -> false;
legal_username(UserName) ->
nomatch /= re:run(UserName, "^[_a-zA-Z0-9]*$").
legal_username(UserName) -> nomatch /= re:run(UserName, "^[_a-zA-Z0-9]*$").
%% black-magic: force overwrite a user
force_add_user(Username, Password, Desc) ->
AddFun = fun() ->
mnesia:write(#?ADMIN{username = Username,
mnesia:write(#?ADMIN{
username = Username,
pwdhash = hash(Password),
description = Desc})
description = Desc
})
end,
case mria:transaction(?DASHBOARD_SHARD, AddFun) of
{atomic, ok} -> ok;
@ -109,7 +123,7 @@ add_user_(Username, Password, Desc) ->
mnesia:abort(<<"username_already_exist">>)
end.
-spec(remove_user(binary()) -> {ok, any()} | {error, any()}).
-spec remove_user(binary()) -> {ok, any()} | {error, any()}.
remove_user(Username) when is_binary(Username) ->
Trans = fun() ->
case lookup_user(Username) of
@ -125,7 +139,7 @@ remove_user(Username) when is_binary(Username) ->
{error, Reason}
end.
-spec(update_user(binary(), binary()) -> {ok, map()} | {error, term()}).
-spec update_user(binary(), binary()) -> {ok, map()} | {error, term()}.
update_user(Username, Desc) when is_binary(Username) ->
return(mria:transaction(?DASHBOARD_SHARD, fun update_user_/2, [Username, Desc])).
@ -140,7 +154,8 @@ verify_hash(Origin, SaltHash) ->
true -> ok;
false -> error
end;
_ -> error
_ ->
error
end.
sha256(SaltBin, Password) ->
@ -174,7 +189,8 @@ change_password_hash(Username, PasswordHash) ->
{ok, Result} ->
_ = emqx_dashboard_token:destroy_by_username(Username),
{ok, Result};
{error, Reason} -> {error, Reason}
{error, Reason} ->
{error, Reason}
end.
update_pwd(Username, Fun) ->
@ -183,30 +199,35 @@ update_pwd(Username, Fun) ->
User =
case lookup_user(Username) of
[Admin] -> Admin;
[] ->
mnesia:abort(<<"username_not_found">>)
[] -> mnesia:abort(<<"username_not_found">>)
end,
mnesia:write(Fun(User))
end,
return(mria:transaction(?DASHBOARD_SHARD, Trans)).
-spec(lookup_user(binary()) -> [emqx_admin()]).
-spec lookup_user(binary()) -> [emqx_admin()].
lookup_user(Username) when is_binary(Username) ->
Fun = fun() -> mnesia:read(?ADMIN, Username) end,
{atomic, User} = mria:ro_transaction(?DASHBOARD_SHARD, Fun),
User.
-spec(all_users() -> [map()]).
-spec all_users() -> [map()].
all_users() ->
lists:map(fun(#?ADMIN{username = Username,
lists:map(
fun(
#?ADMIN{
username = Username,
description = Desc
}) ->
#{username => Username,
}
) ->
#{
username => Username,
description => Desc
}
end, ets:tab2list(?ADMIN)).
-spec(return({atomic | aborted, term()}) -> {ok, term()} | {error, Reason :: binary()}).
end,
ets:tab2list(?ADMIN)
).
-spec return({atomic | aborted, term()}) -> {ok, term()} | {error, Reason :: binary()}.
return({atomic, Result}) ->
{ok, Result};
return({aborted, Reason}) ->
@ -252,7 +273,7 @@ destroy_token_by_username(Username, Token) ->
%% Internal functions
%%--------------------------------------------------------------------
-spec(add_default_user() -> {ok, map() | empty | default_user_exists } | {error, any()}).
-spec add_default_user() -> {ok, map() | empty | default_user_exists} | {error, any()}.
add_default_user() ->
add_default_user(binenv(default_username), binenv(default_password)).
@ -264,7 +285,6 @@ binenv(Key) ->
add_default_user(Username, Password) when ?EMPTY_KEY(Username) orelse ?EMPTY_KEY(Password) ->
{ok, empty};
add_default_user(Username, Password) ->
case lookup_user(Username) of
[] -> add_user(Username, Password, <<"administrator">>);

View File

@ -60,11 +60,13 @@ api_spec() ->
emqx_dashboard_swagger:spec(?MODULE, #{check_schema => true, translate_body => true}).
paths() ->
[ "/login"
, "/logout"
, "/users"
, "/users/:username"
, "/users/:username/change_pwd"].
[
"/login",
"/logout",
"/users",
"/users/:username",
"/users/:username/change_pwd"
].
schema("/login") ->
#{
@ -101,8 +103,10 @@ schema("/users") ->
tags => [<<"dashboard">>],
desc => ?DESC(list_users_api),
responses => #{
200 => mk(array(hoconsc:ref(user)),
#{desc => ?DESC(list_users_api)})
200 => mk(
array(hoconsc:ref(user)),
#{desc => ?DESC(list_users_api)}
)
}
},
post => #{
@ -114,7 +118,6 @@ schema("/users") ->
}
}
};
schema("/users/:username") ->
#{
'operationId' => user,
@ -135,7 +138,8 @@ schema("/users/:username") ->
responses => #{
204 => <<"Delete User successfully">>,
400 => emqx_dashboard_swagger:error_codes(
[?BAD_REQUEST, ?NOT_ALLOWED], ?DESC(login_failed_response400)),
[?BAD_REQUEST, ?NOT_ALLOWED], ?DESC(login_failed_response400)
),
404 => response_schema(404)
}
}
@ -151,10 +155,12 @@ schema("/users/:username/change_pwd") ->
responses => #{
204 => <<"Update user password successfully">>,
401 => emqx_dashboard_swagger:error_codes(
[?WRONG_USERNAME_OR_PWD, ?ERROR_PWD_NOT_MATCH], ?DESC(login_failed401)),
[?WRONG_USERNAME_OR_PWD, ?ERROR_PWD_NOT_MATCH], ?DESC(login_failed401)
),
404 => response_schema(404),
400 => emqx_dashboard_swagger:error_codes(
[?BAD_REQUEST], ?DESC(login_failed_response400))
[?BAD_REQUEST], ?DESC(login_failed_response400)
)
}
}
}.
@ -174,26 +180,32 @@ field(username) ->
mk(binary(), #{desc => ?DESC(username), 'maxLength' => 100, example => <<"admin">>})};
field(username_in_path) ->
{username,
mk(binary(), #{desc => ?DESC(username), 'maxLength' => 100, example => <<"admin">>,
in => path, required => true})};
mk(binary(), #{
desc => ?DESC(username),
'maxLength' => 100,
example => <<"admin">>,
in => path,
required => true
})};
field(password) ->
{password,
mk(binary(), #{desc => ?DESC(password), 'maxLength' => 100, example => <<"public">>})};
field(description) ->
{description,
mk(binary(), #{desc => ?DESC(user_description), example => <<"administrator">>})};
{description, mk(binary(), #{desc => ?DESC(user_description), example => <<"administrator">>})};
field(token) ->
{token, mk(binary(), #{desc => ?DESC(token)})};
field(license) ->
{license, [
{edition, mk(enum([community, enterprise]),
#{desc => ?DESC(license), example => community})}]};
{edition,
mk(
enum([community, enterprise]),
#{desc => ?DESC(license), example => community}
)}
]};
field(version) ->
{version, mk(string(), #{desc => ?DESC(version), example => <<"5.0.0">>})};
field(old_pwd) ->
{old_pwd, mk(binary(), #{desc => ?DESC(old_pwd)})};
field(new_pwd) ->
{new_pwd, mk(binary(), #{desc => ?DESC(new_pwd)})}.
@ -207,7 +219,8 @@ login(post, #{body := Params}) ->
{ok, Token} ->
?SLOG(info, #{msg => "Dashboard login successfully", username => Username}),
Version = iolist_to_binary(proplists:get_value(version, emqx_sys:info())),
{200, #{token => Token,
{200, #{
token => Token,
version => Version,
license => #{edition => emqx_release:edition()}
}};
@ -216,8 +229,10 @@ login(post, #{body := Params}) ->
{401, ?WRONG_USERNAME_OR_PWD, <<"Auth filed">>}
end.
logout(_, #{body := #{<<"username">> := Username},
headers := #{<<"authorization">> := <<"Bearer ", Token/binary>>}}) ->
logout(_, #{
body := #{<<"username">> := Username},
headers := #{<<"authorization">> := <<"Bearer ", Token/binary>>}
}) ->
case emqx_dashboard_admin:destroy_token_by_username(Username, Token) of
ok ->
?SLOG(info, #{msg => "Dashboard logout successfully", username => Username}),
@ -229,7 +244,6 @@ logout(_, #{body := #{<<"username">> := Username},
users(get, _Request) ->
{200, emqx_dashboard_admin:all_users()};
users(post, #{body := Params}) ->
Desc = maps:get(<<"description">>, Params, <<"">>),
Username = maps:get(<<"username">>, Params),
@ -243,8 +257,11 @@ users(post, #{body := Params}) ->
?SLOG(info, #{msg => "Create dashboard success", username => Username}),
{200, Result};
{error, Reason} ->
?SLOG(info, #{msg => "Create dashboard failed",
username => Username, reason => Reason}),
?SLOG(info, #{
msg => "Create dashboard failed",
username => Username,
reason => Reason
}),
{400, ?BAD_REQUEST, Reason}
end
end.
@ -257,7 +274,6 @@ user(put, #{bindings := #{username := Username}, body := Params}) ->
{error, Reason} ->
{404, ?USER_NOT_FOUND, Reason}
end;
user(delete, #{bindings := #{username := Username}}) ->
case Username == emqx_dashboard_admin:default_username() of
true ->

View File

@ -18,8 +18,9 @@
-behaviour(application).
-export([ start/2
, stop/1
-export([
start/2,
stop/1
]).
-include("emqx_dashboard.hrl").
@ -33,7 +34,8 @@ start(_StartType, _StartArgs) ->
{ok, _Result} = emqx_dashboard_admin:add_default_user(),
ok = emqx_dashboard_config:add_handler(),
{ok, Sup};
{error, Reason} -> {error, Reason}
{error, Reason} ->
{error, Reason}
end.
stop(_State) ->

View File

@ -22,8 +22,10 @@
init(Req0, State) ->
?SLOG(warning, #{msg => "unexpected_api_access", request => Req0}),
Req = cowboy_req:reply(404,
Req = cowboy_req:reply(
404,
#{<<"content-type">> => <<"application/json">>},
<<"{\"code\": \"API_NOT_EXIST\", \"message\": \"Request Path Not Found\"}">>,
Req0),
Req0
),
{ok, Req, State}.

View File

@ -16,9 +16,10 @@
-module(emqx_dashboard_cli).
-export([ load/0
, admins/1
, unload/0
-export([
load/0,
admins/1,
unload/0
]).
load() ->
@ -26,7 +27,6 @@ load() ->
admins(["add", Username, Password]) ->
admins(["add", Username, Password, ""]);
admins(["add", Username, Password, Desc]) ->
case emqx_dashboard_admin:add_user(bin(Username), bin(Password), bin(Desc)) of
{ok, _} ->
@ -34,20 +34,20 @@ admins(["add", Username, Password, Desc]) ->
{error, Reason} ->
emqx_ctl:print("Error: ~p~n", [Reason])
end;
admins(["passwd", Username, Password]) ->
Status = emqx_dashboard_admin:change_password(bin(Username), bin(Password)),
emqx_ctl:print("~p~n", [Status]);
admins(["del", Username]) ->
Status = emqx_dashboard_admin:remove_user(bin(Username)),
emqx_ctl:print("~p~n", [Status]);
admins(_) ->
emqx_ctl:usage(
[{"admins add <Username> <Password> <Description>", "Add dashboard user"},
[
{"admins add <Username> <Password> <Description>", "Add dashboard user"},
{"admins passwd <Username> <Password>", "Reset dashboard user password"},
{"admins del <Username>", "Delete dashboard user" }]).
{"admins del <Username>", "Delete dashboard user"}
]
).
unload() ->
emqx_ctl:unregister_command(admins).

View File

@ -18,11 +18,12 @@
-include_lib("emqx/include/http_api.hrl").
-export([ all/0
, list/0
, look_up/1
, description/1
, format/1
-export([
all/0,
list/0,
look_up/1,
description/1,
format/1
]).
all() ->

View File

@ -21,15 +21,17 @@
-include("emqx_dashboard.hrl").
-include_lib("typerefl/include/types.hrl").
-export([ api_spec/0
, fields/1
, paths/0
, schema/1
, namespace/0
-export([
api_spec/0,
fields/1,
paths/0,
schema/1,
namespace/0
]).
-export([ error_codes/2
, error_code/2
-export([
error_codes/2,
error_code/2
]).
namespace() -> "dashboard".
@ -38,8 +40,9 @@ api_spec() ->
emqx_dashboard_swagger:spec(?MODULE, #{check_schema => true, translate_body => true}).
paths() ->
[ "/error_codes"
, "/error_codes/:code"
[
"/error_codes",
"/error_codes/:code"
].
schema("/error_codes") ->
@ -60,10 +63,12 @@ schema("/error_codes/:code") ->
security => [],
description => <<"API Error Codes">>,
parameters => [
{code, hoconsc:mk(hoconsc:enum(emqx_dashboard_error_code:all()), #{
{code,
hoconsc:mk(hoconsc:enum(emqx_dashboard_error_code:all()), #{
desc => <<"API Error Codes">>,
in => path,
example => hd(emqx_dashboard_error_code:all())})}
example => hd(emqx_dashboard_error_code:all())
})}
],
responses => #{
200 => hoconsc:ref(?MODULE, error_code)
@ -77,7 +82,6 @@ fields(error_code) ->
{description, hoconsc:mk(string(), #{desc => <<"Description">>})}
].
error_codes(_, _) ->
{200, emqx_dashboard_error_code:list()}.

View File

@ -11,23 +11,26 @@
-export([api_spec/0]).
-export([ paths/0
, schema/1
, fields/1
-export([
paths/0,
schema/1,
fields/1
]).
-export([ monitor/2
, monitor_current/2
-export([
monitor/2,
monitor_current/2
]).
api_spec() ->
emqx_dashboard_swagger:spec(?MODULE, #{check_schema => true, translate_body => true}).
paths() ->
[ "/monitor"
, "/monitor/nodes/:node"
, "/monitor_current"
, "/monitor_current/nodes/:node"
[
"/monitor",
"/monitor/nodes/:node",
"/monitor_current",
"/monitor_current/nodes/:node"
].
schema("/monitor") ->
@ -43,7 +46,6 @@ schema("/monitor") ->
}
}
};
schema("/monitor/nodes/:node") ->
#{
'operationId' => monitor,
@ -57,7 +59,6 @@ schema("/monitor/nodes/:node") ->
}
}
};
schema("/monitor_current") ->
#{
'operationId' => monitor_current,
@ -69,7 +70,6 @@ schema("/monitor_current") ->
}
}
};
schema("/monitor_current/nodes/:node") ->
#{
'operationId' => monitor_current,
@ -102,17 +102,19 @@ parameter_node() ->
},
{node, hoconsc:mk(binary(), Info)}.
fields(sampler) ->
Samplers =
[{SamplerName, hoconsc:mk(integer(), #{desc => swagger_desc(SamplerName)})}
|| SamplerName <- ?SAMPLER_LIST],
[
{SamplerName, hoconsc:mk(integer(), #{desc => swagger_desc(SamplerName)})}
|| SamplerName <- ?SAMPLER_LIST
],
[{time_stamp, hoconsc:mk(non_neg_integer(), #{desc => <<"Timestamp">>})} | Samplers];
fields(sampler_current) ->
Names = maps:values(?DELTA_SAMPLER_RATE_MAP) ++ ?GAUGE_SAMPLER_LIST,
[{SamplerName, hoconsc:mk(integer(), #{desc => swagger_desc(SamplerName)})}
|| SamplerName <- Names].
[
{SamplerName, hoconsc:mk(integer(), #{desc => swagger_desc(SamplerName)})}
|| SamplerName <- Names
].
%% -------------------------------------------------------------------------------------------------
%% API
@ -141,26 +143,39 @@ monitor_current(get, #{bindings := Bindings}) ->
%% -------------------------------------------------------------------------------------------------
%% Internal
swagger_desc(received) -> swagger_desc_format("Received messages ");
swagger_desc(received_bytes) -> swagger_desc_format("Received bytes ");
swagger_desc(sent) -> swagger_desc_format("Sent messages ");
swagger_desc(sent_bytes) -> swagger_desc_format("Sent bytes ");
swagger_desc(dropped) -> swagger_desc_format("Dropped messages ");
swagger_desc(received) ->
swagger_desc_format("Received messages ");
swagger_desc(received_bytes) ->
swagger_desc_format("Received bytes ");
swagger_desc(sent) ->
swagger_desc_format("Sent messages ");
swagger_desc(sent_bytes) ->
swagger_desc_format("Sent bytes ");
swagger_desc(dropped) ->
swagger_desc_format("Dropped messages ");
swagger_desc(subscriptions) ->
<<"Subscriptions at the time of sampling."
" Can only represent the approximate state">>;
<<
"Subscriptions at the time of sampling."
" Can only represent the approximate state"
>>;
swagger_desc(topics) ->
<<"Count topics at the time of sampling."
" Can only represent the approximate state">>;
<<
"Count topics at the time of sampling."
" Can only represent the approximate state"
>>;
swagger_desc(connections) ->
<<"Connections at the time of sampling."
" Can only represent the approximate state">>;
swagger_desc(received_msg_rate) -> swagger_desc_format("Dropped messages ", per);
<<
"Connections at the time of sampling."
" Can only represent the approximate state"
>>;
swagger_desc(received_msg_rate) ->
swagger_desc_format("Dropped messages ", per);
%swagger_desc(received_bytes_rate) -> swagger_desc_format("Received bytes ", per);
swagger_desc(sent_msg_rate) -> swagger_desc_format("Sent messages ", per);
swagger_desc(sent_msg_rate) ->
swagger_desc_format("Sent messages ", per);
%swagger_desc(sent_bytes_rate) -> swagger_desc_format("Sent bytes ", per);
swagger_desc(dropped_msg_rate) -> swagger_desc_format("Dropped messages ", per).
swagger_desc(dropped_msg_rate) ->
swagger_desc_format("Dropped messages ", per).
swagger_desc_format(Format) ->
swagger_desc_format(Format, last).

View File

@ -28,8 +28,8 @@ start_link() ->
supervisor:start_link({local, ?MODULE}, ?MODULE, []).
init([]) ->
{ok, {{one_for_one, 10, 100},
[
{ok,
{{one_for_one, 10, 100}, [
?CHILD(emqx_dashboard_token),
?CHILD(emqx_dashboard_monitor),
?CHILD(emqx_dashboard_config)

View File

@ -407,7 +407,8 @@ trans_description(Spec, Hocon) ->
Struct -> to_bin(Struct)
end,
case Desc of
undefined -> Spec;
undefined ->
Spec;
Desc ->
Desc1 = binary:replace(Desc, [<<"</br>\n">>, <<"\n">>], <<"</br>">>, [global]),
Spec#{description => Desc1}

View File

@ -18,11 +18,12 @@
-include("emqx_dashboard.hrl").
-export([ sign/2
, verify/1
, lookup/1
, destroy/1
, destroy_by_username/1
-export([
sign/2,
verify/1,
lookup/1,
destroy/1,
destroy_by_username/1
]).
-boot_mnesia({mnesia, [boot]}).
@ -42,26 +43,27 @@
-export([start_link/0, salt/0]).
-export([ init/1
, handle_call/3
, handle_cast/2
, handle_info/2
, terminate/2
, code_change/3
-export([
init/1,
handle_call/3,
handle_cast/2,
handle_info/2,
terminate/2,
code_change/3
]).
%%--------------------------------------------------------------------
%% jwt function
-spec(sign(Username :: binary(), Password :: binary()) ->
{ok, Token :: binary()} | {error, Reason :: term()}).
-spec sign(Username :: binary(), Password :: binary()) ->
{ok, Token :: binary()} | {error, Reason :: term()}.
sign(Username, Password) ->
do_sign(Username, Password).
-spec(verify(Token :: binary()) -> Result :: ok | {error, token_timeout | not_found}).
-spec verify(Token :: binary()) -> Result :: ok | {error, token_timeout | not_found}.
verify(Token) ->
do_verify(Token).
-spec(destroy(KeyOrKeys :: list() | binary() | #?ADMIN_JWT{}) -> ok).
-spec destroy(KeyOrKeys :: list() | binary() | #?ADMIN_JWT{}) -> ok.
destroy([]) ->
ok;
destroy(JWTorTokenList) when is_list(JWTorTokenList) ->
@ -71,12 +73,12 @@ destroy(#?ADMIN_JWT{token = Token}) ->
destroy(Token) when is_binary(Token) ->
do_destroy(Token).
-spec(destroy_by_username(Username :: binary()) -> ok).
-spec destroy_by_username(Username :: binary()) -> ok.
destroy_by_username(Username) ->
do_destroy_by_username(Username).
%% @doc create 4 bytes salt.
-spec(salt() -> binary()).
-spec salt() -> binary().
salt() ->
<<X:16/big-unsigned-integer>> = crypto:strong_rand_bytes(2),
iolist_to_binary(io_lib:format("~4.16.0b", [X])).
@ -88,8 +90,13 @@ mnesia(boot) ->
{storage, disc_copies},
{record_name, ?ADMIN_JWT},
{attributes, record_info(fields, ?ADMIN_JWT)},
{storage_properties, [{ets, [{read_concurrency, true},
{write_concurrency, true}]}]}]).
{storage_properties, [
{ets, [
{read_concurrency, true},
{write_concurrency, true}
]}
]}
]).
%%--------------------------------------------------------------------
%% jwt apply
@ -116,9 +123,11 @@ do_verify(Token)->
case ExpTime > erlang:system_time(millisecond) of
true ->
NewJWT = JWT#?ADMIN_JWT{exptime = jwt_expiration_time()},
{atomic, Res} = mria:transaction(?DASHBOARD_SHARD,
{atomic, Res} = mria:transaction(
?DASHBOARD_SHARD,
fun mnesia:write/1,
[NewJWT]),
[NewJWT]
),
Res;
_ ->
{error, token_timeout}
@ -137,7 +146,7 @@ do_destroy_by_username(Username) ->
%%--------------------------------------------------------------------
%% jwt internal util function
-spec(lookup(Token :: binary()) -> {ok, #?ADMIN_JWT{}} | {error, not_found}).
-spec lookup(Token :: binary()) -> {ok, #?ADMIN_JWT{}} | {error, not_found}.
lookup(Token) ->
Fun = fun() -> mnesia:read(?TAB, Token) end,
case mria:ro_transaction(?DASHBOARD_SHARD, Fun) of
@ -210,8 +219,9 @@ timer_clean(Pid) ->
-dialyzer({nowarn_function, clean_expired_jwt/1}).
clean_expired_jwt(Now) ->
Spec = [{#?ADMIN_JWT{exptime = '$1', token = '$2', _ = '_'},
[{'<', '$1', Now}], ['$2']}],
{atomic, JWTList} = mria:ro_transaction(?DASHBOARD_SHARD,
fun() -> mnesia:select(?TAB, Spec) end),
Spec = [{#?ADMIN_JWT{exptime = '$1', token = '$2', _ = '_'}, [{'<', '$1', Now}], ['$2']}],
{atomic, JWTList} = mria:ro_transaction(
?DASHBOARD_SHARD,
fun() -> mnesia:select(?TAB, Spec) end
),
ok = destroy(JWTList).

View File

@ -18,9 +18,10 @@
-behaviour(emqx_bpapi).
-export([ introduced_in/0
, do_sample/2
, current_rate/1
-export([
introduced_in/0,
do_sample/2,
current_rate/1
]).
-include("emqx_dashboard.hrl").

View File

@ -185,4 +185,3 @@ t_clean_token(_) ->
timer:sleep(5),
{error, not_found} = emqx_dashboard_admin:verify_token(Token2),
ok.

View File

@ -158,7 +158,8 @@ banned(post, #{body := Body}) ->
{400, 'BAD_REQUEST', list_to_binary(Reason)};
Ban ->
case emqx_banned:create(Ban) of
{ok, Banned} -> {200, format(Banned)};
{ok, Banned} ->
{200, format(Banned)};
{error, {already_exist, Old}} ->
OldBannedFormat = emqx_json:encode(format(Old)),
{400, 'ALREADY_EXISTS', OldBannedFormat}

View File

@ -33,3 +33,5 @@ b168102615e574df15ec6a91304747b4637a9171
b4451823350ec46126c49ca915b4b169dd4cf49e
# reformat apps/emqx_auto_subscribe and apps/emqx_conf
a4feb3e6e95c18cb531416112e57520c5ba00d40
# reformat apps/emqx_dashboard
fda246814b38ced2d229c42307c447970b09f3ab

View File

@ -17,6 +17,7 @@ APPS+=( 'apps/emqx_management')
APPS+=( 'apps/emqx_psk')
APPS+=( 'apps/emqx_plugin_libs' 'apps/emqx_machine' 'apps/emqx_statsd' )
APPS+=( 'apps/emqx_auto_subscribe' 'apps/emqx_conf')
APPS+=( 'apps/emqx_dashboard')
for app in "${APPS[@]}"; do
echo "$app ..."