chore: dashboard format code
This commit is contained in:
parent
2ea66ebcee
commit
07444e3da5
|
@ -20,17 +20,18 @@
|
||||||
pwdhash :: binary(),
|
pwdhash :: binary(),
|
||||||
description :: binary(),
|
description :: binary(),
|
||||||
role = undefined :: atom(),
|
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).
|
-define(ADMIN_JWT, emqx_admin_jwt).
|
||||||
|
|
||||||
-record(?ADMIN_JWT, {
|
-record(?ADMIN_JWT, {
|
||||||
token :: binary(),
|
token :: binary(),
|
||||||
username :: binary(),
|
username :: binary(),
|
||||||
exptime :: integer(),
|
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).
|
-define(TAB_COLLECT, emqx_collect).
|
||||||
|
@ -49,18 +50,18 @@
|
||||||
-define(RPC_TIMEOUT, 5000).
|
-define(RPC_TIMEOUT, 5000).
|
||||||
-endif.
|
-endif.
|
||||||
|
|
||||||
-define(DELTA_SAMPLER_LIST,
|
-define(DELTA_SAMPLER_LIST, [
|
||||||
[ received
|
received,
|
||||||
%, received_bytes
|
%, received_bytes
|
||||||
, sent
|
sent,
|
||||||
%, sent_bytes
|
%, sent_bytes
|
||||||
, dropped
|
dropped
|
||||||
]).
|
]).
|
||||||
|
|
||||||
-define(GAUGE_SAMPLER_LIST,
|
-define(GAUGE_SAMPLER_LIST, [
|
||||||
[ subscriptions
|
subscriptions,
|
||||||
, topics
|
topics,
|
||||||
, connections
|
connections
|
||||||
]).
|
]).
|
||||||
|
|
||||||
-define(SAMPLER_LIST, ?GAUGE_SAMPLER_LIST ++ ?DELTA_SAMPLER_LIST).
|
-define(SAMPLER_LIST, ?GAUGE_SAMPLER_LIST ++ ?DELTA_SAMPLER_LIST).
|
||||||
|
|
|
@ -3,16 +3,25 @@
|
||||||
{deps, [{emqx, {path, "../emqx"}}]}.
|
{deps, [{emqx, {path, "../emqx"}}]}.
|
||||||
|
|
||||||
{edoc_opts, [{preprocess, true}]}.
|
{edoc_opts, [{preprocess, true}]}.
|
||||||
{erl_opts, [warn_unused_vars,
|
{erl_opts, [
|
||||||
|
warn_unused_vars,
|
||||||
warn_shadow_vars,
|
warn_shadow_vars,
|
||||||
warn_unused_import,
|
warn_unused_import,
|
||||||
warn_obsolete_guard,
|
warn_obsolete_guard,
|
||||||
debug_info,
|
debug_info,
|
||||||
{d, 'APPLICATION', emqx}]}.
|
{d, 'APPLICATION', emqx}
|
||||||
{xref_checks, [undefined_function_calls, undefined_functions,
|
]}.
|
||||||
locals_not_used, deprecated_function_calls,
|
{xref_checks, [
|
||||||
warnings_as_errors, deprecated_functions]}.
|
undefined_function_calls,
|
||||||
|
undefined_functions,
|
||||||
|
locals_not_used,
|
||||||
|
deprecated_function_calls,
|
||||||
|
warnings_as_errors,
|
||||||
|
deprecated_functions
|
||||||
|
]}.
|
||||||
{cover_enabled, true}.
|
{cover_enabled, true}.
|
||||||
{cover_opts, [verbose]}.
|
{cover_opts, [verbose]}.
|
||||||
{cover_export_enabled, true}.
|
{cover_export_enabled, true}.
|
||||||
{eunit_first_files, ["test/emqx_swagger_remote_schema.erl"]}.
|
{eunit_first_files, ["test/emqx_swagger_remote_schema.erl"]}.
|
||||||
|
|
||||||
|
{project_plugins, [erlfmt]}.
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
%% -*- mode: erlang -*-
|
%% -*- mode: erlang -*-
|
||||||
{application, emqx_dashboard,
|
{application, emqx_dashboard, [
|
||||||
[{description, "EMQX Web Dashboard"},
|
{description, "EMQX Web Dashboard"},
|
||||||
{vsn, "5.0.0"}, % strict semver, bump manually!
|
% strict semver, bump manually!
|
||||||
|
{vsn, "5.0.0"},
|
||||||
{modules, []},
|
{modules, []},
|
||||||
{registered, [emqx_dashboard_sup]},
|
{registered, [emqx_dashboard_sup]},
|
||||||
{applications, [kernel, stdlib, mnesia, minirest, emqx]},
|
{applications, [kernel, stdlib, mnesia, minirest, emqx]},
|
||||||
|
@ -9,7 +10,8 @@
|
||||||
{env, []},
|
{env, []},
|
||||||
{licenses, ["Apache-2.0"]},
|
{licenses, ["Apache-2.0"]},
|
||||||
{maintainers, ["EMQX Team <contact@emqx.io>"]},
|
{maintainers, ["EMQX Team <contact@emqx.io>"]},
|
||||||
{links, [{"Homepage", "https://emqx.io/"},
|
{links, [
|
||||||
|
{"Homepage", "https://emqx.io/"},
|
||||||
{"Github", "https://github.com/emqx/emqx-dashboard"}
|
{"Github", "https://github.com/emqx/emqx-dashboard"}
|
||||||
]}
|
]}
|
||||||
]}.
|
]}.
|
||||||
|
|
|
@ -26,27 +26,31 @@
|
||||||
%% Mnesia bootstrap
|
%% Mnesia bootstrap
|
||||||
-export([mnesia/1]).
|
-export([mnesia/1]).
|
||||||
|
|
||||||
-export([ add_user/3
|
-export([
|
||||||
, force_add_user/3
|
add_user/3,
|
||||||
, remove_user/1
|
force_add_user/3,
|
||||||
, update_user/2
|
remove_user/1,
|
||||||
, lookup_user/1
|
update_user/2,
|
||||||
, change_password/2
|
lookup_user/1,
|
||||||
, change_password/3
|
change_password/2,
|
||||||
, all_users/0
|
change_password/3,
|
||||||
, check/2
|
all_users/0,
|
||||||
|
check/2
|
||||||
]).
|
]).
|
||||||
|
|
||||||
-export([ sign_token/2
|
-export([
|
||||||
, verify_token/1
|
sign_token/2,
|
||||||
, destroy_token_by_username/2
|
verify_token/1,
|
||||||
|
destroy_token_by_username/2
|
||||||
]).
|
]).
|
||||||
-export([ hash/1
|
-export([
|
||||||
, verify_hash/2
|
hash/1,
|
||||||
|
verify_hash/2
|
||||||
]).
|
]).
|
||||||
|
|
||||||
-export([ add_default_user/0
|
-export([
|
||||||
, default_username/0
|
add_default_user/0,
|
||||||
|
default_username/0
|
||||||
]).
|
]).
|
||||||
|
|
||||||
-type emqx_admin() :: #?ADMIN{}.
|
-type emqx_admin() :: #?ADMIN{}.
|
||||||
|
@ -62,36 +66,46 @@ mnesia(boot) ->
|
||||||
{storage, disc_copies},
|
{storage, disc_copies},
|
||||||
{record_name, ?ADMIN},
|
{record_name, ?ADMIN},
|
||||||
{attributes, record_info(fields, ?ADMIN)},
|
{attributes, record_info(fields, ?ADMIN)},
|
||||||
{storage_properties, [{ets, [{read_concurrency, true},
|
{storage_properties, [
|
||||||
{write_concurrency, true}]}]}]).
|
{ets, [
|
||||||
|
{read_concurrency, true},
|
||||||
|
{write_concurrency, true}
|
||||||
|
]}
|
||||||
|
]}
|
||||||
|
]).
|
||||||
|
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
%% API
|
%% API
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
|
|
||||||
-spec(add_user(binary(), binary(), binary()) -> {ok, map()} | {error, any()}).
|
-spec add_user(binary(), binary(), binary()) -> {ok, map()} | {error, any()}.
|
||||||
add_user(Username, Password, Desc)
|
add_user(Username, Password, Desc) when
|
||||||
when is_binary(Username), is_binary(Password) ->
|
is_binary(Username), is_binary(Password)
|
||||||
|
->
|
||||||
case legal_username(Username) of
|
case legal_username(Username) of
|
||||||
true ->
|
true ->
|
||||||
return(
|
return(
|
||||||
mria:transaction(?DASHBOARD_SHARD, fun add_user_/3, [Username, Password, Desc]));
|
mria:transaction(?DASHBOARD_SHARD, fun add_user_/3, [Username, Password, Desc])
|
||||||
|
);
|
||||||
false ->
|
false ->
|
||||||
{error, <<"Bad Username."
|
{error, <<
|
||||||
" Only upper and lower case letters, numbers and underscores are supported">>}
|
"Bad Username."
|
||||||
|
" Only upper and lower case letters, numbers and underscores are supported"
|
||||||
|
>>}
|
||||||
end.
|
end.
|
||||||
|
|
||||||
%% 0 - 9 or A -Z or a - z or $_
|
%% 0 - 9 or A -Z or a - z or $_
|
||||||
legal_username(<<>>) -> false;
|
legal_username(<<>>) -> false;
|
||||||
legal_username(UserName) ->
|
legal_username(UserName) -> nomatch /= re:run(UserName, "^[_a-zA-Z0-9]*$").
|
||||||
nomatch /= re:run(UserName, "^[_a-zA-Z0-9]*$").
|
|
||||||
|
|
||||||
%% black-magic: force overwrite a user
|
%% black-magic: force overwrite a user
|
||||||
force_add_user(Username, Password, Desc) ->
|
force_add_user(Username, Password, Desc) ->
|
||||||
AddFun = fun() ->
|
AddFun = fun() ->
|
||||||
mnesia:write(#?ADMIN{username = Username,
|
mnesia:write(#?ADMIN{
|
||||||
|
username = Username,
|
||||||
pwdhash = hash(Password),
|
pwdhash = hash(Password),
|
||||||
description = Desc})
|
description = Desc
|
||||||
|
})
|
||||||
end,
|
end,
|
||||||
case mria:transaction(?DASHBOARD_SHARD, AddFun) of
|
case mria:transaction(?DASHBOARD_SHARD, AddFun) of
|
||||||
{atomic, ok} -> ok;
|
{atomic, ok} -> ok;
|
||||||
|
@ -109,7 +123,7 @@ add_user_(Username, Password, Desc) ->
|
||||||
mnesia:abort(<<"username_already_exist">>)
|
mnesia:abort(<<"username_already_exist">>)
|
||||||
end.
|
end.
|
||||||
|
|
||||||
-spec(remove_user(binary()) -> {ok, any()} | {error, any()}).
|
-spec remove_user(binary()) -> {ok, any()} | {error, any()}.
|
||||||
remove_user(Username) when is_binary(Username) ->
|
remove_user(Username) when is_binary(Username) ->
|
||||||
Trans = fun() ->
|
Trans = fun() ->
|
||||||
case lookup_user(Username) of
|
case lookup_user(Username) of
|
||||||
|
@ -125,7 +139,7 @@ remove_user(Username) when is_binary(Username) ->
|
||||||
{error, Reason}
|
{error, Reason}
|
||||||
end.
|
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) ->
|
update_user(Username, Desc) when is_binary(Username) ->
|
||||||
return(mria:transaction(?DASHBOARD_SHARD, fun update_user_/2, [Username, Desc])).
|
return(mria:transaction(?DASHBOARD_SHARD, fun update_user_/2, [Username, Desc])).
|
||||||
|
|
||||||
|
@ -140,7 +154,8 @@ verify_hash(Origin, SaltHash) ->
|
||||||
true -> ok;
|
true -> ok;
|
||||||
false -> error
|
false -> error
|
||||||
end;
|
end;
|
||||||
_ -> error
|
_ ->
|
||||||
|
error
|
||||||
end.
|
end.
|
||||||
|
|
||||||
sha256(SaltBin, Password) ->
|
sha256(SaltBin, Password) ->
|
||||||
|
@ -174,7 +189,8 @@ change_password_hash(Username, PasswordHash) ->
|
||||||
{ok, Result} ->
|
{ok, Result} ->
|
||||||
_ = emqx_dashboard_token:destroy_by_username(Username),
|
_ = emqx_dashboard_token:destroy_by_username(Username),
|
||||||
{ok, Result};
|
{ok, Result};
|
||||||
{error, Reason} -> {error, Reason}
|
{error, Reason} ->
|
||||||
|
{error, Reason}
|
||||||
end.
|
end.
|
||||||
|
|
||||||
update_pwd(Username, Fun) ->
|
update_pwd(Username, Fun) ->
|
||||||
|
@ -183,30 +199,35 @@ update_pwd(Username, Fun) ->
|
||||||
User =
|
User =
|
||||||
case lookup_user(Username) of
|
case lookup_user(Username) of
|
||||||
[Admin] -> Admin;
|
[Admin] -> Admin;
|
||||||
[] ->
|
[] -> mnesia:abort(<<"username_not_found">>)
|
||||||
mnesia:abort(<<"username_not_found">>)
|
|
||||||
end,
|
end,
|
||||||
mnesia:write(Fun(User))
|
mnesia:write(Fun(User))
|
||||||
end,
|
end,
|
||||||
return(mria:transaction(?DASHBOARD_SHARD, Trans)).
|
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) ->
|
lookup_user(Username) when is_binary(Username) ->
|
||||||
Fun = fun() -> mnesia:read(?ADMIN, Username) end,
|
Fun = fun() -> mnesia:read(?ADMIN, Username) end,
|
||||||
{atomic, User} = mria:ro_transaction(?DASHBOARD_SHARD, Fun),
|
{atomic, User} = mria:ro_transaction(?DASHBOARD_SHARD, Fun),
|
||||||
User.
|
User.
|
||||||
|
|
||||||
-spec(all_users() -> [map()]).
|
-spec all_users() -> [map()].
|
||||||
all_users() ->
|
all_users() ->
|
||||||
lists:map(fun(#?ADMIN{username = Username,
|
lists:map(
|
||||||
|
fun(
|
||||||
|
#?ADMIN{
|
||||||
|
username = Username,
|
||||||
description = Desc
|
description = Desc
|
||||||
}) ->
|
}
|
||||||
#{username => Username,
|
) ->
|
||||||
|
#{
|
||||||
|
username => Username,
|
||||||
description => Desc
|
description => Desc
|
||||||
}
|
}
|
||||||
end, ets:tab2list(?ADMIN)).
|
end,
|
||||||
-spec(return({atomic | aborted, term()}) -> {ok, term()} | {error, Reason :: binary()}).
|
ets:tab2list(?ADMIN)
|
||||||
|
).
|
||||||
|
-spec return({atomic | aborted, term()}) -> {ok, term()} | {error, Reason :: binary()}.
|
||||||
return({atomic, Result}) ->
|
return({atomic, Result}) ->
|
||||||
{ok, Result};
|
{ok, Result};
|
||||||
return({aborted, Reason}) ->
|
return({aborted, Reason}) ->
|
||||||
|
@ -252,7 +273,7 @@ destroy_token_by_username(Username, Token) ->
|
||||||
%% Internal functions
|
%% 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() ->
|
||||||
add_default_user(binenv(default_username), binenv(default_password)).
|
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) ->
|
add_default_user(Username, Password) when ?EMPTY_KEY(Username) orelse ?EMPTY_KEY(Password) ->
|
||||||
{ok, empty};
|
{ok, empty};
|
||||||
|
|
||||||
add_default_user(Username, Password) ->
|
add_default_user(Username, Password) ->
|
||||||
case lookup_user(Username) of
|
case lookup_user(Username) of
|
||||||
[] -> add_user(Username, Password, <<"administrator">>);
|
[] -> add_user(Username, Password, <<"administrator">>);
|
||||||
|
|
|
@ -60,11 +60,13 @@ api_spec() ->
|
||||||
emqx_dashboard_swagger:spec(?MODULE, #{check_schema => true, translate_body => true}).
|
emqx_dashboard_swagger:spec(?MODULE, #{check_schema => true, translate_body => true}).
|
||||||
|
|
||||||
paths() ->
|
paths() ->
|
||||||
[ "/login"
|
[
|
||||||
, "/logout"
|
"/login",
|
||||||
, "/users"
|
"/logout",
|
||||||
, "/users/:username"
|
"/users",
|
||||||
, "/users/:username/change_pwd"].
|
"/users/:username",
|
||||||
|
"/users/:username/change_pwd"
|
||||||
|
].
|
||||||
|
|
||||||
schema("/login") ->
|
schema("/login") ->
|
||||||
#{
|
#{
|
||||||
|
@ -101,8 +103,10 @@ schema("/users") ->
|
||||||
tags => [<<"dashboard">>],
|
tags => [<<"dashboard">>],
|
||||||
desc => ?DESC(list_users_api),
|
desc => ?DESC(list_users_api),
|
||||||
responses => #{
|
responses => #{
|
||||||
200 => mk(array(hoconsc:ref(user)),
|
200 => mk(
|
||||||
#{desc => ?DESC(list_users_api)})
|
array(hoconsc:ref(user)),
|
||||||
|
#{desc => ?DESC(list_users_api)}
|
||||||
|
)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
post => #{
|
post => #{
|
||||||
|
@ -114,7 +118,6 @@ schema("/users") ->
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
schema("/users/:username") ->
|
schema("/users/:username") ->
|
||||||
#{
|
#{
|
||||||
'operationId' => user,
|
'operationId' => user,
|
||||||
|
@ -135,7 +138,8 @@ schema("/users/:username") ->
|
||||||
responses => #{
|
responses => #{
|
||||||
204 => <<"Delete User successfully">>,
|
204 => <<"Delete User successfully">>,
|
||||||
400 => emqx_dashboard_swagger:error_codes(
|
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)
|
404 => response_schema(404)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -151,10 +155,12 @@ schema("/users/:username/change_pwd") ->
|
||||||
responses => #{
|
responses => #{
|
||||||
204 => <<"Update user password successfully">>,
|
204 => <<"Update user password successfully">>,
|
||||||
401 => emqx_dashboard_swagger:error_codes(
|
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),
|
404 => response_schema(404),
|
||||||
400 => emqx_dashboard_swagger:error_codes(
|
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">>})};
|
mk(binary(), #{desc => ?DESC(username), 'maxLength' => 100, example => <<"admin">>})};
|
||||||
field(username_in_path) ->
|
field(username_in_path) ->
|
||||||
{username,
|
{username,
|
||||||
mk(binary(), #{desc => ?DESC(username), 'maxLength' => 100, example => <<"admin">>,
|
mk(binary(), #{
|
||||||
in => path, required => true})};
|
desc => ?DESC(username),
|
||||||
|
'maxLength' => 100,
|
||||||
|
example => <<"admin">>,
|
||||||
|
in => path,
|
||||||
|
required => true
|
||||||
|
})};
|
||||||
field(password) ->
|
field(password) ->
|
||||||
{password,
|
{password,
|
||||||
mk(binary(), #{desc => ?DESC(password), 'maxLength' => 100, example => <<"public">>})};
|
mk(binary(), #{desc => ?DESC(password), 'maxLength' => 100, example => <<"public">>})};
|
||||||
field(description) ->
|
field(description) ->
|
||||||
{description,
|
{description, mk(binary(), #{desc => ?DESC(user_description), example => <<"administrator">>})};
|
||||||
mk(binary(), #{desc => ?DESC(user_description), example => <<"administrator">>})};
|
|
||||||
field(token) ->
|
field(token) ->
|
||||||
{token, mk(binary(), #{desc => ?DESC(token)})};
|
{token, mk(binary(), #{desc => ?DESC(token)})};
|
||||||
field(license) ->
|
field(license) ->
|
||||||
{license, [
|
{license, [
|
||||||
{edition, mk(enum([community, enterprise]),
|
{edition,
|
||||||
#{desc => ?DESC(license), example => community})}]};
|
mk(
|
||||||
|
enum([community, enterprise]),
|
||||||
|
#{desc => ?DESC(license), example => community}
|
||||||
|
)}
|
||||||
|
]};
|
||||||
field(version) ->
|
field(version) ->
|
||||||
{version, mk(string(), #{desc => ?DESC(version), example => <<"5.0.0">>})};
|
{version, mk(string(), #{desc => ?DESC(version), example => <<"5.0.0">>})};
|
||||||
|
|
||||||
field(old_pwd) ->
|
field(old_pwd) ->
|
||||||
{old_pwd, mk(binary(), #{desc => ?DESC(old_pwd)})};
|
{old_pwd, mk(binary(), #{desc => ?DESC(old_pwd)})};
|
||||||
|
|
||||||
field(new_pwd) ->
|
field(new_pwd) ->
|
||||||
{new_pwd, mk(binary(), #{desc => ?DESC(new_pwd)})}.
|
{new_pwd, mk(binary(), #{desc => ?DESC(new_pwd)})}.
|
||||||
|
|
||||||
|
@ -207,7 +219,8 @@ login(post, #{body := Params}) ->
|
||||||
{ok, Token} ->
|
{ok, Token} ->
|
||||||
?SLOG(info, #{msg => "Dashboard login successfully", username => Username}),
|
?SLOG(info, #{msg => "Dashboard login successfully", username => Username}),
|
||||||
Version = iolist_to_binary(proplists:get_value(version, emqx_sys:info())),
|
Version = iolist_to_binary(proplists:get_value(version, emqx_sys:info())),
|
||||||
{200, #{token => Token,
|
{200, #{
|
||||||
|
token => Token,
|
||||||
version => Version,
|
version => Version,
|
||||||
license => #{edition => emqx_release:edition()}
|
license => #{edition => emqx_release:edition()}
|
||||||
}};
|
}};
|
||||||
|
@ -216,8 +229,10 @@ login(post, #{body := Params}) ->
|
||||||
{401, ?WRONG_USERNAME_OR_PWD, <<"Auth filed">>}
|
{401, ?WRONG_USERNAME_OR_PWD, <<"Auth filed">>}
|
||||||
end.
|
end.
|
||||||
|
|
||||||
logout(_, #{body := #{<<"username">> := Username},
|
logout(_, #{
|
||||||
headers := #{<<"authorization">> := <<"Bearer ", Token/binary>>}}) ->
|
body := #{<<"username">> := Username},
|
||||||
|
headers := #{<<"authorization">> := <<"Bearer ", Token/binary>>}
|
||||||
|
}) ->
|
||||||
case emqx_dashboard_admin:destroy_token_by_username(Username, Token) of
|
case emqx_dashboard_admin:destroy_token_by_username(Username, Token) of
|
||||||
ok ->
|
ok ->
|
||||||
?SLOG(info, #{msg => "Dashboard logout successfully", username => Username}),
|
?SLOG(info, #{msg => "Dashboard logout successfully", username => Username}),
|
||||||
|
@ -229,7 +244,6 @@ logout(_, #{body := #{<<"username">> := Username},
|
||||||
|
|
||||||
users(get, _Request) ->
|
users(get, _Request) ->
|
||||||
{200, emqx_dashboard_admin:all_users()};
|
{200, emqx_dashboard_admin:all_users()};
|
||||||
|
|
||||||
users(post, #{body := Params}) ->
|
users(post, #{body := Params}) ->
|
||||||
Desc = maps:get(<<"description">>, Params, <<"">>),
|
Desc = maps:get(<<"description">>, Params, <<"">>),
|
||||||
Username = maps:get(<<"username">>, Params),
|
Username = maps:get(<<"username">>, Params),
|
||||||
|
@ -243,8 +257,11 @@ users(post, #{body := Params}) ->
|
||||||
?SLOG(info, #{msg => "Create dashboard success", username => Username}),
|
?SLOG(info, #{msg => "Create dashboard success", username => Username}),
|
||||||
{200, Result};
|
{200, Result};
|
||||||
{error, Reason} ->
|
{error, Reason} ->
|
||||||
?SLOG(info, #{msg => "Create dashboard failed",
|
?SLOG(info, #{
|
||||||
username => Username, reason => Reason}),
|
msg => "Create dashboard failed",
|
||||||
|
username => Username,
|
||||||
|
reason => Reason
|
||||||
|
}),
|
||||||
{400, ?BAD_REQUEST, Reason}
|
{400, ?BAD_REQUEST, Reason}
|
||||||
end
|
end
|
||||||
end.
|
end.
|
||||||
|
@ -257,7 +274,6 @@ user(put, #{bindings := #{username := Username}, body := Params}) ->
|
||||||
{error, Reason} ->
|
{error, Reason} ->
|
||||||
{404, ?USER_NOT_FOUND, Reason}
|
{404, ?USER_NOT_FOUND, Reason}
|
||||||
end;
|
end;
|
||||||
|
|
||||||
user(delete, #{bindings := #{username := Username}}) ->
|
user(delete, #{bindings := #{username := Username}}) ->
|
||||||
case Username == emqx_dashboard_admin:default_username() of
|
case Username == emqx_dashboard_admin:default_username() of
|
||||||
true ->
|
true ->
|
||||||
|
|
|
@ -18,8 +18,9 @@
|
||||||
|
|
||||||
-behaviour(application).
|
-behaviour(application).
|
||||||
|
|
||||||
-export([ start/2
|
-export([
|
||||||
, stop/1
|
start/2,
|
||||||
|
stop/1
|
||||||
]).
|
]).
|
||||||
|
|
||||||
-include("emqx_dashboard.hrl").
|
-include("emqx_dashboard.hrl").
|
||||||
|
@ -33,7 +34,8 @@ start(_StartType, _StartArgs) ->
|
||||||
{ok, _Result} = emqx_dashboard_admin:add_default_user(),
|
{ok, _Result} = emqx_dashboard_admin:add_default_user(),
|
||||||
ok = emqx_dashboard_config:add_handler(),
|
ok = emqx_dashboard_config:add_handler(),
|
||||||
{ok, Sup};
|
{ok, Sup};
|
||||||
{error, Reason} -> {error, Reason}
|
{error, Reason} ->
|
||||||
|
{error, Reason}
|
||||||
end.
|
end.
|
||||||
|
|
||||||
stop(_State) ->
|
stop(_State) ->
|
||||||
|
|
|
@ -22,8 +22,10 @@
|
||||||
|
|
||||||
init(Req0, State) ->
|
init(Req0, State) ->
|
||||||
?SLOG(warning, #{msg => "unexpected_api_access", request => Req0}),
|
?SLOG(warning, #{msg => "unexpected_api_access", request => Req0}),
|
||||||
Req = cowboy_req:reply(404,
|
Req = cowboy_req:reply(
|
||||||
|
404,
|
||||||
#{<<"content-type">> => <<"application/json">>},
|
#{<<"content-type">> => <<"application/json">>},
|
||||||
<<"{\"code\": \"API_NOT_EXIST\", \"message\": \"Request Path Not Found\"}">>,
|
<<"{\"code\": \"API_NOT_EXIST\", \"message\": \"Request Path Not Found\"}">>,
|
||||||
Req0),
|
Req0
|
||||||
|
),
|
||||||
{ok, Req, State}.
|
{ok, Req, State}.
|
||||||
|
|
|
@ -16,9 +16,10 @@
|
||||||
|
|
||||||
-module(emqx_dashboard_cli).
|
-module(emqx_dashboard_cli).
|
||||||
|
|
||||||
-export([ load/0
|
-export([
|
||||||
, admins/1
|
load/0,
|
||||||
, unload/0
|
admins/1,
|
||||||
|
unload/0
|
||||||
]).
|
]).
|
||||||
|
|
||||||
load() ->
|
load() ->
|
||||||
|
@ -26,7 +27,6 @@ load() ->
|
||||||
|
|
||||||
admins(["add", Username, Password]) ->
|
admins(["add", Username, Password]) ->
|
||||||
admins(["add", Username, Password, ""]);
|
admins(["add", Username, Password, ""]);
|
||||||
|
|
||||||
admins(["add", Username, Password, Desc]) ->
|
admins(["add", Username, Password, Desc]) ->
|
||||||
case emqx_dashboard_admin:add_user(bin(Username), bin(Password), bin(Desc)) of
|
case emqx_dashboard_admin:add_user(bin(Username), bin(Password), bin(Desc)) of
|
||||||
{ok, _} ->
|
{ok, _} ->
|
||||||
|
@ -34,20 +34,20 @@ admins(["add", Username, Password, Desc]) ->
|
||||||
{error, Reason} ->
|
{error, Reason} ->
|
||||||
emqx_ctl:print("Error: ~p~n", [Reason])
|
emqx_ctl:print("Error: ~p~n", [Reason])
|
||||||
end;
|
end;
|
||||||
|
|
||||||
admins(["passwd", Username, Password]) ->
|
admins(["passwd", Username, Password]) ->
|
||||||
Status = emqx_dashboard_admin:change_password(bin(Username), bin(Password)),
|
Status = emqx_dashboard_admin:change_password(bin(Username), bin(Password)),
|
||||||
emqx_ctl:print("~p~n", [Status]);
|
emqx_ctl:print("~p~n", [Status]);
|
||||||
|
|
||||||
admins(["del", Username]) ->
|
admins(["del", Username]) ->
|
||||||
Status = emqx_dashboard_admin:remove_user(bin(Username)),
|
Status = emqx_dashboard_admin:remove_user(bin(Username)),
|
||||||
emqx_ctl:print("~p~n", [Status]);
|
emqx_ctl:print("~p~n", [Status]);
|
||||||
|
|
||||||
admins(_) ->
|
admins(_) ->
|
||||||
emqx_ctl:usage(
|
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 passwd <Username> <Password>", "Reset dashboard user password"},
|
||||||
{"admins del <Username>", "Delete dashboard user" }]).
|
{"admins del <Username>", "Delete dashboard user"}
|
||||||
|
]
|
||||||
|
).
|
||||||
|
|
||||||
unload() ->
|
unload() ->
|
||||||
emqx_ctl:unregister_command(admins).
|
emqx_ctl:unregister_command(admins).
|
||||||
|
|
|
@ -18,11 +18,12 @@
|
||||||
|
|
||||||
-include_lib("emqx/include/http_api.hrl").
|
-include_lib("emqx/include/http_api.hrl").
|
||||||
|
|
||||||
-export([ all/0
|
-export([
|
||||||
, list/0
|
all/0,
|
||||||
, look_up/1
|
list/0,
|
||||||
, description/1
|
look_up/1,
|
||||||
, format/1
|
description/1,
|
||||||
|
format/1
|
||||||
]).
|
]).
|
||||||
|
|
||||||
all() ->
|
all() ->
|
||||||
|
|
|
@ -21,15 +21,17 @@
|
||||||
-include("emqx_dashboard.hrl").
|
-include("emqx_dashboard.hrl").
|
||||||
-include_lib("typerefl/include/types.hrl").
|
-include_lib("typerefl/include/types.hrl").
|
||||||
|
|
||||||
-export([ api_spec/0
|
-export([
|
||||||
, fields/1
|
api_spec/0,
|
||||||
, paths/0
|
fields/1,
|
||||||
, schema/1
|
paths/0,
|
||||||
, namespace/0
|
schema/1,
|
||||||
|
namespace/0
|
||||||
]).
|
]).
|
||||||
|
|
||||||
-export([ error_codes/2
|
-export([
|
||||||
, error_code/2
|
error_codes/2,
|
||||||
|
error_code/2
|
||||||
]).
|
]).
|
||||||
|
|
||||||
namespace() -> "dashboard".
|
namespace() -> "dashboard".
|
||||||
|
@ -38,8 +40,9 @@ api_spec() ->
|
||||||
emqx_dashboard_swagger:spec(?MODULE, #{check_schema => true, translate_body => true}).
|
emqx_dashboard_swagger:spec(?MODULE, #{check_schema => true, translate_body => true}).
|
||||||
|
|
||||||
paths() ->
|
paths() ->
|
||||||
[ "/error_codes"
|
[
|
||||||
, "/error_codes/:code"
|
"/error_codes",
|
||||||
|
"/error_codes/:code"
|
||||||
].
|
].
|
||||||
|
|
||||||
schema("/error_codes") ->
|
schema("/error_codes") ->
|
||||||
|
@ -60,10 +63,12 @@ schema("/error_codes/:code") ->
|
||||||
security => [],
|
security => [],
|
||||||
description => <<"API Error Codes">>,
|
description => <<"API Error Codes">>,
|
||||||
parameters => [
|
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">>,
|
desc => <<"API Error Codes">>,
|
||||||
in => path,
|
in => path,
|
||||||
example => hd(emqx_dashboard_error_code:all())})}
|
example => hd(emqx_dashboard_error_code:all())
|
||||||
|
})}
|
||||||
],
|
],
|
||||||
responses => #{
|
responses => #{
|
||||||
200 => hoconsc:ref(?MODULE, error_code)
|
200 => hoconsc:ref(?MODULE, error_code)
|
||||||
|
@ -77,7 +82,6 @@ fields(error_code) ->
|
||||||
{description, hoconsc:mk(string(), #{desc => <<"Description">>})}
|
{description, hoconsc:mk(string(), #{desc => <<"Description">>})}
|
||||||
].
|
].
|
||||||
|
|
||||||
|
|
||||||
error_codes(_, _) ->
|
error_codes(_, _) ->
|
||||||
{200, emqx_dashboard_error_code:list()}.
|
{200, emqx_dashboard_error_code:list()}.
|
||||||
|
|
||||||
|
|
|
@ -11,23 +11,26 @@
|
||||||
|
|
||||||
-export([api_spec/0]).
|
-export([api_spec/0]).
|
||||||
|
|
||||||
-export([ paths/0
|
-export([
|
||||||
, schema/1
|
paths/0,
|
||||||
, fields/1
|
schema/1,
|
||||||
|
fields/1
|
||||||
]).
|
]).
|
||||||
|
|
||||||
-export([ monitor/2
|
-export([
|
||||||
, monitor_current/2
|
monitor/2,
|
||||||
|
monitor_current/2
|
||||||
]).
|
]).
|
||||||
|
|
||||||
api_spec() ->
|
api_spec() ->
|
||||||
emqx_dashboard_swagger:spec(?MODULE, #{check_schema => true, translate_body => true}).
|
emqx_dashboard_swagger:spec(?MODULE, #{check_schema => true, translate_body => true}).
|
||||||
|
|
||||||
paths() ->
|
paths() ->
|
||||||
[ "/monitor"
|
[
|
||||||
, "/monitor/nodes/:node"
|
"/monitor",
|
||||||
, "/monitor_current"
|
"/monitor/nodes/:node",
|
||||||
, "/monitor_current/nodes/:node"
|
"/monitor_current",
|
||||||
|
"/monitor_current/nodes/:node"
|
||||||
].
|
].
|
||||||
|
|
||||||
schema("/monitor") ->
|
schema("/monitor") ->
|
||||||
|
@ -43,7 +46,6 @@ schema("/monitor") ->
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
schema("/monitor/nodes/:node") ->
|
schema("/monitor/nodes/:node") ->
|
||||||
#{
|
#{
|
||||||
'operationId' => monitor,
|
'operationId' => monitor,
|
||||||
|
@ -57,7 +59,6 @@ schema("/monitor/nodes/:node") ->
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
schema("/monitor_current") ->
|
schema("/monitor_current") ->
|
||||||
#{
|
#{
|
||||||
'operationId' => monitor_current,
|
'operationId' => monitor_current,
|
||||||
|
@ -69,7 +70,6 @@ schema("/monitor_current") ->
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
schema("/monitor_current/nodes/:node") ->
|
schema("/monitor_current/nodes/:node") ->
|
||||||
#{
|
#{
|
||||||
'operationId' => monitor_current,
|
'operationId' => monitor_current,
|
||||||
|
@ -102,17 +102,19 @@ parameter_node() ->
|
||||||
},
|
},
|
||||||
{node, hoconsc:mk(binary(), Info)}.
|
{node, hoconsc:mk(binary(), Info)}.
|
||||||
|
|
||||||
|
|
||||||
fields(sampler) ->
|
fields(sampler) ->
|
||||||
Samplers =
|
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];
|
[{time_stamp, hoconsc:mk(non_neg_integer(), #{desc => <<"Timestamp">>})} | Samplers];
|
||||||
|
|
||||||
fields(sampler_current) ->
|
fields(sampler_current) ->
|
||||||
Names = maps:values(?DELTA_SAMPLER_RATE_MAP) ++ ?GAUGE_SAMPLER_LIST,
|
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
|
%% API
|
||||||
|
@ -141,26 +143,39 @@ monitor_current(get, #{bindings := Bindings}) ->
|
||||||
%% -------------------------------------------------------------------------------------------------
|
%% -------------------------------------------------------------------------------------------------
|
||||||
%% Internal
|
%% Internal
|
||||||
|
|
||||||
swagger_desc(received) -> swagger_desc_format("Received messages ");
|
swagger_desc(received) ->
|
||||||
swagger_desc(received_bytes) -> swagger_desc_format("Received bytes ");
|
swagger_desc_format("Received messages ");
|
||||||
swagger_desc(sent) -> swagger_desc_format("Sent messages ");
|
swagger_desc(received_bytes) ->
|
||||||
swagger_desc(sent_bytes) -> swagger_desc_format("Sent bytes ");
|
swagger_desc_format("Received bytes ");
|
||||||
swagger_desc(dropped) -> swagger_desc_format("Dropped messages ");
|
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) ->
|
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) ->
|
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) ->
|
swagger_desc(connections) ->
|
||||||
<<"Connections at the time of sampling."
|
<<
|
||||||
" Can only represent the approximate state">>;
|
"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_msg_rate) ->
|
||||||
|
swagger_desc_format("Dropped messages ", per);
|
||||||
%swagger_desc(received_bytes_rate) -> swagger_desc_format("Received bytes ", 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(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) ->
|
||||||
swagger_desc_format(Format, last).
|
swagger_desc_format(Format, last).
|
||||||
|
|
|
@ -28,8 +28,8 @@ start_link() ->
|
||||||
supervisor:start_link({local, ?MODULE}, ?MODULE, []).
|
supervisor:start_link({local, ?MODULE}, ?MODULE, []).
|
||||||
|
|
||||||
init([]) ->
|
init([]) ->
|
||||||
{ok, {{one_for_one, 10, 100},
|
{ok,
|
||||||
[
|
{{one_for_one, 10, 100}, [
|
||||||
?CHILD(emqx_dashboard_token),
|
?CHILD(emqx_dashboard_token),
|
||||||
?CHILD(emqx_dashboard_monitor),
|
?CHILD(emqx_dashboard_monitor),
|
||||||
?CHILD(emqx_dashboard_config)
|
?CHILD(emqx_dashboard_config)
|
||||||
|
|
|
@ -407,7 +407,8 @@ trans_description(Spec, Hocon) ->
|
||||||
Struct -> to_bin(Struct)
|
Struct -> to_bin(Struct)
|
||||||
end,
|
end,
|
||||||
case Desc of
|
case Desc of
|
||||||
undefined -> Spec;
|
undefined ->
|
||||||
|
Spec;
|
||||||
Desc ->
|
Desc ->
|
||||||
Desc1 = binary:replace(Desc, [<<"</br>\n">>, <<"\n">>], <<"</br>">>, [global]),
|
Desc1 = binary:replace(Desc, [<<"</br>\n">>, <<"\n">>], <<"</br>">>, [global]),
|
||||||
Spec#{description => Desc1}
|
Spec#{description => Desc1}
|
||||||
|
|
|
@ -18,11 +18,12 @@
|
||||||
|
|
||||||
-include("emqx_dashboard.hrl").
|
-include("emqx_dashboard.hrl").
|
||||||
|
|
||||||
-export([ sign/2
|
-export([
|
||||||
, verify/1
|
sign/2,
|
||||||
, lookup/1
|
verify/1,
|
||||||
, destroy/1
|
lookup/1,
|
||||||
, destroy_by_username/1
|
destroy/1,
|
||||||
|
destroy_by_username/1
|
||||||
]).
|
]).
|
||||||
|
|
||||||
-boot_mnesia({mnesia, [boot]}).
|
-boot_mnesia({mnesia, [boot]}).
|
||||||
|
@ -42,26 +43,27 @@
|
||||||
|
|
||||||
-export([start_link/0, salt/0]).
|
-export([start_link/0, salt/0]).
|
||||||
|
|
||||||
-export([ init/1
|
-export([
|
||||||
, handle_call/3
|
init/1,
|
||||||
, handle_cast/2
|
handle_call/3,
|
||||||
, handle_info/2
|
handle_cast/2,
|
||||||
, terminate/2
|
handle_info/2,
|
||||||
, code_change/3
|
terminate/2,
|
||||||
|
code_change/3
|
||||||
]).
|
]).
|
||||||
|
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
%% jwt function
|
%% jwt function
|
||||||
-spec(sign(Username :: binary(), Password :: binary()) ->
|
-spec sign(Username :: binary(), Password :: binary()) ->
|
||||||
{ok, Token :: binary()} | {error, Reason :: term()}).
|
{ok, Token :: binary()} | {error, Reason :: term()}.
|
||||||
sign(Username, Password) ->
|
sign(Username, Password) ->
|
||||||
do_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) ->
|
verify(Token) ->
|
||||||
do_verify(Token).
|
do_verify(Token).
|
||||||
|
|
||||||
-spec(destroy(KeyOrKeys :: list() | binary() | #?ADMIN_JWT{}) -> ok).
|
-spec destroy(KeyOrKeys :: list() | binary() | #?ADMIN_JWT{}) -> ok.
|
||||||
destroy([]) ->
|
destroy([]) ->
|
||||||
ok;
|
ok;
|
||||||
destroy(JWTorTokenList) when is_list(JWTorTokenList) ->
|
destroy(JWTorTokenList) when is_list(JWTorTokenList) ->
|
||||||
|
@ -71,12 +73,12 @@ destroy(#?ADMIN_JWT{token = Token}) ->
|
||||||
destroy(Token) when is_binary(Token) ->
|
destroy(Token) when is_binary(Token) ->
|
||||||
do_destroy(Token).
|
do_destroy(Token).
|
||||||
|
|
||||||
-spec(destroy_by_username(Username :: binary()) -> ok).
|
-spec destroy_by_username(Username :: binary()) -> ok.
|
||||||
destroy_by_username(Username) ->
|
destroy_by_username(Username) ->
|
||||||
do_destroy_by_username(Username).
|
do_destroy_by_username(Username).
|
||||||
|
|
||||||
%% @doc create 4 bytes salt.
|
%% @doc create 4 bytes salt.
|
||||||
-spec(salt() -> binary()).
|
-spec salt() -> binary().
|
||||||
salt() ->
|
salt() ->
|
||||||
<<X:16/big-unsigned-integer>> = crypto:strong_rand_bytes(2),
|
<<X:16/big-unsigned-integer>> = crypto:strong_rand_bytes(2),
|
||||||
iolist_to_binary(io_lib:format("~4.16.0b", [X])).
|
iolist_to_binary(io_lib:format("~4.16.0b", [X])).
|
||||||
|
@ -88,8 +90,13 @@ mnesia(boot) ->
|
||||||
{storage, disc_copies},
|
{storage, disc_copies},
|
||||||
{record_name, ?ADMIN_JWT},
|
{record_name, ?ADMIN_JWT},
|
||||||
{attributes, record_info(fields, ?ADMIN_JWT)},
|
{attributes, record_info(fields, ?ADMIN_JWT)},
|
||||||
{storage_properties, [{ets, [{read_concurrency, true},
|
{storage_properties, [
|
||||||
{write_concurrency, true}]}]}]).
|
{ets, [
|
||||||
|
{read_concurrency, true},
|
||||||
|
{write_concurrency, true}
|
||||||
|
]}
|
||||||
|
]}
|
||||||
|
]).
|
||||||
|
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
%% jwt apply
|
%% jwt apply
|
||||||
|
@ -116,9 +123,11 @@ do_verify(Token)->
|
||||||
case ExpTime > erlang:system_time(millisecond) of
|
case ExpTime > erlang:system_time(millisecond) of
|
||||||
true ->
|
true ->
|
||||||
NewJWT = JWT#?ADMIN_JWT{exptime = jwt_expiration_time()},
|
NewJWT = JWT#?ADMIN_JWT{exptime = jwt_expiration_time()},
|
||||||
{atomic, Res} = mria:transaction(?DASHBOARD_SHARD,
|
{atomic, Res} = mria:transaction(
|
||||||
|
?DASHBOARD_SHARD,
|
||||||
fun mnesia:write/1,
|
fun mnesia:write/1,
|
||||||
[NewJWT]),
|
[NewJWT]
|
||||||
|
),
|
||||||
Res;
|
Res;
|
||||||
_ ->
|
_ ->
|
||||||
{error, token_timeout}
|
{error, token_timeout}
|
||||||
|
@ -137,7 +146,7 @@ do_destroy_by_username(Username) ->
|
||||||
|
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
%% jwt internal util function
|
%% 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) ->
|
lookup(Token) ->
|
||||||
Fun = fun() -> mnesia:read(?TAB, Token) end,
|
Fun = fun() -> mnesia:read(?TAB, Token) end,
|
||||||
case mria:ro_transaction(?DASHBOARD_SHARD, Fun) of
|
case mria:ro_transaction(?DASHBOARD_SHARD, Fun) of
|
||||||
|
@ -210,8 +219,9 @@ timer_clean(Pid) ->
|
||||||
|
|
||||||
-dialyzer({nowarn_function, clean_expired_jwt/1}).
|
-dialyzer({nowarn_function, clean_expired_jwt/1}).
|
||||||
clean_expired_jwt(Now) ->
|
clean_expired_jwt(Now) ->
|
||||||
Spec = [{#?ADMIN_JWT{exptime = '$1', token = '$2', _ = '_'},
|
Spec = [{#?ADMIN_JWT{exptime = '$1', token = '$2', _ = '_'}, [{'<', '$1', Now}], ['$2']}],
|
||||||
[{'<', '$1', Now}], ['$2']}],
|
{atomic, JWTList} = mria:ro_transaction(
|
||||||
{atomic, JWTList} = mria:ro_transaction(?DASHBOARD_SHARD,
|
?DASHBOARD_SHARD,
|
||||||
fun() -> mnesia:select(?TAB, Spec) end),
|
fun() -> mnesia:select(?TAB, Spec) end
|
||||||
|
),
|
||||||
ok = destroy(JWTList).
|
ok = destroy(JWTList).
|
||||||
|
|
|
@ -18,9 +18,10 @@
|
||||||
|
|
||||||
-behaviour(emqx_bpapi).
|
-behaviour(emqx_bpapi).
|
||||||
|
|
||||||
-export([ introduced_in/0
|
-export([
|
||||||
, do_sample/2
|
introduced_in/0,
|
||||||
, current_rate/1
|
do_sample/2,
|
||||||
|
current_rate/1
|
||||||
]).
|
]).
|
||||||
|
|
||||||
-include("emqx_dashboard.hrl").
|
-include("emqx_dashboard.hrl").
|
||||||
|
|
|
@ -185,4 +185,3 @@ t_clean_token(_) ->
|
||||||
timer:sleep(5),
|
timer:sleep(5),
|
||||||
{error, not_found} = emqx_dashboard_admin:verify_token(Token2),
|
{error, not_found} = emqx_dashboard_admin:verify_token(Token2),
|
||||||
ok.
|
ok.
|
||||||
|
|
||||||
|
|
|
@ -158,7 +158,8 @@ banned(post, #{body := Body}) ->
|
||||||
{400, 'BAD_REQUEST', list_to_binary(Reason)};
|
{400, 'BAD_REQUEST', list_to_binary(Reason)};
|
||||||
Ban ->
|
Ban ->
|
||||||
case emqx_banned:create(Ban) of
|
case emqx_banned:create(Ban) of
|
||||||
{ok, Banned} -> {200, format(Banned)};
|
{ok, Banned} ->
|
||||||
|
{200, format(Banned)};
|
||||||
{error, {already_exist, Old}} ->
|
{error, {already_exist, Old}} ->
|
||||||
OldBannedFormat = emqx_json:encode(format(Old)),
|
OldBannedFormat = emqx_json:encode(format(Old)),
|
||||||
{400, 'ALREADY_EXISTS', OldBannedFormat}
|
{400, 'ALREADY_EXISTS', OldBannedFormat}
|
||||||
|
|
|
@ -33,3 +33,5 @@ b168102615e574df15ec6a91304747b4637a9171
|
||||||
b4451823350ec46126c49ca915b4b169dd4cf49e
|
b4451823350ec46126c49ca915b4b169dd4cf49e
|
||||||
# reformat apps/emqx_auto_subscribe and apps/emqx_conf
|
# reformat apps/emqx_auto_subscribe and apps/emqx_conf
|
||||||
a4feb3e6e95c18cb531416112e57520c5ba00d40
|
a4feb3e6e95c18cb531416112e57520c5ba00d40
|
||||||
|
# reformat apps/emqx_dashboard
|
||||||
|
fda246814b38ced2d229c42307c447970b09f3ab
|
||||||
|
|
|
@ -17,6 +17,7 @@ APPS+=( 'apps/emqx_management')
|
||||||
APPS+=( 'apps/emqx_psk')
|
APPS+=( 'apps/emqx_psk')
|
||||||
APPS+=( 'apps/emqx_plugin_libs' 'apps/emqx_machine' 'apps/emqx_statsd' )
|
APPS+=( 'apps/emqx_plugin_libs' 'apps/emqx_machine' 'apps/emqx_statsd' )
|
||||||
APPS+=( 'apps/emqx_auto_subscribe' 'apps/emqx_conf')
|
APPS+=( 'apps/emqx_auto_subscribe' 'apps/emqx_conf')
|
||||||
|
APPS+=( 'apps/emqx_dashboard')
|
||||||
|
|
||||||
for app in "${APPS[@]}"; do
|
for app in "${APPS[@]}"; do
|
||||||
echo "$app ..."
|
echo "$app ..."
|
||||||
|
|
Loading…
Reference in New Issue