feat(dashboard): Update the configuration file to hocon
This commit is contained in:
parent
3b1303340a
commit
569d54a4c0
|
@ -91,6 +91,7 @@ includes() ->
|
|||
, "emqx_bridge_mqtt"
|
||||
, "emqx_modules"
|
||||
, "emqx_management"
|
||||
, "emqx_dashboard"
|
||||
, "emqx_gateway"
|
||||
].
|
||||
-endif.
|
||||
|
|
|
@ -1,130 +1,41 @@
|
|||
##--------------------------------------------------------------------
|
||||
## EMQ X Dashboard
|
||||
## Dashboard for EMQ X
|
||||
##--------------------------------------------------------------------
|
||||
|
||||
## Default user's login name.
|
||||
##
|
||||
## Value: String
|
||||
dashboard.default_user.login = admin
|
||||
|
||||
## Default user's password.
|
||||
##
|
||||
## Value: String
|
||||
dashboard.default_user.password = public
|
||||
|
||||
##--------------------------------------------------------------------
|
||||
## HTTP Listener
|
||||
|
||||
## The port that the Dashboard HTTP listener will bind.
|
||||
##
|
||||
## Value: Port
|
||||
##
|
||||
## Examples: 18083
|
||||
dashboard.listener.http.port = 18083
|
||||
|
||||
## The acceptor pool for external Dashboard HTTP listener.
|
||||
##
|
||||
## Value: Number
|
||||
dashboard.listener.http.acceptors = 4
|
||||
|
||||
## Maximum number of concurrent Dashboard HTTP connections.
|
||||
##
|
||||
## Value: Number
|
||||
dashboard.listener.http.max_clients = 512
|
||||
|
||||
## Set up the socket for IPv6.
|
||||
##
|
||||
## Value: false | true
|
||||
dashboard.listener.http.inet6 = false
|
||||
|
||||
## Listen on IPv4 and IPv6 (false) or only on IPv6 (true). Use with inet6.
|
||||
##
|
||||
## Value: false | true
|
||||
dashboard.listener.http.ipv6_v6only = false
|
||||
|
||||
##--------------------------------------------------------------------
|
||||
## HTTPS Listener
|
||||
|
||||
## The port that the Dashboard HTTPS listener will bind.
|
||||
##
|
||||
## Value: Port
|
||||
##
|
||||
## Examples: 18084
|
||||
## dashboard.listener.https.port = 18084
|
||||
|
||||
## The acceptor pool for external Dashboard HTTPS listener.
|
||||
##
|
||||
## Value: Number
|
||||
## dashboard.listener.https.acceptors = 2
|
||||
|
||||
## Maximum number of concurrent Dashboard HTTPS connections.
|
||||
##
|
||||
## Value: Number
|
||||
## dashboard.listener.https.max_clients = 512
|
||||
|
||||
## Set up the socket for IPv6.
|
||||
##
|
||||
## Value: false | true
|
||||
## dashboard.listener.https.inet6 = false
|
||||
|
||||
## Listen on IPv4 and IPv6 (false) or only on IPv6 (true). Use with inet6.
|
||||
##
|
||||
## Value: false | true
|
||||
## dashboard.listener.https.ipv6_v6only = false
|
||||
|
||||
## Path to the file containing the user's private PEM-encoded key.
|
||||
##
|
||||
## Value: File
|
||||
## dashboard.listener.https.keyfile = "etc/certs/key.pem"
|
||||
|
||||
## Path to a file containing the user certificate.
|
||||
##
|
||||
## Value: File
|
||||
## dashboard.listener.https.certfile = "etc/certs/cert.pem"
|
||||
|
||||
## Path to the file containing PEM-encoded CA certificates.
|
||||
##
|
||||
## Value: File
|
||||
## dashboard.listener.https.cacertfile = "etc/certs/cacert.pem"
|
||||
|
||||
## See: 'listener.ssl.<name>.dhfile' in emq.conf
|
||||
##
|
||||
## Value: File
|
||||
## dashboard.listener.https.dhfile = "{{ platform_etc_dir }}/certs/dh-params.pem"
|
||||
|
||||
## See: 'listener.ssl.<name>.verify' in emq.conf
|
||||
##
|
||||
## Value: verify_peer | verify_none
|
||||
## dashboard.listener.https.verify = verify_peer
|
||||
|
||||
## See: 'listener.ssl.<name>.fail_if_no_peer_cert' in emq.conf
|
||||
##
|
||||
## Value: false | true
|
||||
## dashboard.listener.https.fail_if_no_peer_cert = true
|
||||
|
||||
## TLS versions only to protect from POODLE attack.
|
||||
##
|
||||
## Value: String, seperated by ','
|
||||
## NOTE: Do not use tlsv1.3 if emqx is running on OTP-22 or earlier
|
||||
## dashboard.listener.https.tls_versions = "tlsv1.3,tlsv1.2,tlsv1.1,tlsv1"
|
||||
|
||||
## See: 'listener.ssl.<name>.ciphers' in emq.conf
|
||||
##
|
||||
## Value: Ciphers
|
||||
## dashboard.listener.https.ciphers = "TLS_AES_256_GCM_SHA384,TLS_AES_128_GCM_SHA256,TLS_CHACHA20_POLY1305_SHA256,TLS_AES_128_CCM_SHA256,TLS_AES_128_CCM_8_SHA256,ECDHE-ECDSA-AES256-GCM-SHA384,ECDHE-RSA-AES256-GCM-SHA384,ECDHE-ECDSA-AES256-SHA384,ECDHE-RSA-AES256-SHA384,ECDHE-ECDSA-DES-CBC3-SHA,ECDH-ECDSA-AES256-GCM-SHA384,ECDH-RSA-AES256-GCM-SHA384,ECDH-ECDSA-AES256-SHA384,ECDH-RSA-AES256-SHA384,DHE-DSS-AES256-GCM-SHA384,DHE-DSS-AES256-SHA256,AES256-GCM-SHA384,AES256-SHA256,ECDHE-ECDSA-AES128-GCM-SHA256,ECDHE-RSA-AES128-GCM-SHA256,ECDHE-ECDSA-AES128-SHA256,ECDHE-RSA-AES128-SHA256,ECDH-ECDSA-AES128-GCM-SHA256,ECDH-RSA-AES128-GCM-SHA256,ECDH-ECDSA-AES128-SHA256,ECDH-RSA-AES128-SHA256,DHE-DSS-AES128-GCM-SHA256,DHE-DSS-AES128-SHA256,AES128-GCM-SHA256,AES128-SHA256,ECDHE-ECDSA-AES256-SHA,ECDHE-RSA-AES256-SHA,DHE-DSS-AES256-SHA,ECDH-ECDSA-AES256-SHA,ECDH-RSA-AES256-SHA,AES256-SHA,ECDHE-ECDSA-AES128-SHA,ECDHE-RSA-AES128-SHA,DHE-DSS-AES128-SHA,ECDH-ECDSA-AES128-SHA,ECDH-RSA-AES128-SHA,AES128-SHA"
|
||||
|
||||
## See: 'listener.ssl.<name>.secure_renegotiate' in emq.conf
|
||||
##
|
||||
## Value: on | off
|
||||
## dashboard.listener.https.secure_renegotiate = off
|
||||
|
||||
## See: 'listener.ssl.<name>.reuse_sessions' in emq.conf
|
||||
##
|
||||
## Value: on | off
|
||||
## dashboard.listener.https.reuse_sessions = on
|
||||
|
||||
## See: 'listener.ssl.<name>.honor_cipher_order' in emq.conf
|
||||
##
|
||||
## Value: on | off
|
||||
## dashboard.listener.https.honor_cipher_order = on
|
||||
|
||||
emqx_dashboard:{
|
||||
default_username: "admin"
|
||||
default_password: "public"
|
||||
listeners: [
|
||||
{
|
||||
num_acceptors: 4
|
||||
max_connections: 512
|
||||
protocol: http
|
||||
port: 18083
|
||||
backlog: 512
|
||||
send_timeout: 15s
|
||||
send_timeout_close: true
|
||||
inet6: false
|
||||
ipv6_v6only: false
|
||||
}
|
||||
## ,
|
||||
## {
|
||||
## protocol: https
|
||||
## port: 8081
|
||||
## acceptors: 2
|
||||
## backlog: 512
|
||||
## send_timeout: 15s
|
||||
## send_timeout_close: true
|
||||
## inet6: false
|
||||
## ipv6_v6only: false
|
||||
## certfile = "etc/certs/cert.pem"
|
||||
## keyfile = "etc/certs/key.pem"
|
||||
## cacertfile = "etc/certs/cacert.pem"
|
||||
## verify = verify_peer
|
||||
## tls_versions = "tlsv1.3,tlsv1.2,tlsv1.1,tlsv1"
|
||||
## ciphers = "TLS_AES_256_GCM_SHA384,TLS_AES_128_GCM_SHA256,TLS_CHACHA20_POLY1305_SHA256,TLS_AES_128_CCM_SHA256,TLS_AES_128_CCM_8_SHA256,ECDHE-ECDSA-AES256-GCM-SHA384,ECDHE-RSA-AES256-GCM-SHA384,ECDHE-ECDSA-AES256-SHA384,ECDHE-RSA-AES256-SHA384,ECDHE-ECDSA-DES-CBC3-SHA,ECDH-ECDSA-AES256-GCM-SHA384,ECDH-RSA-AES256-GCM-SHA384,ECDH-ECDSA-AES256-SHA384,ECDH-RSA-AES256-SHA384,DHE-DSS-AES256-GCM-SHA384,DHE-DSS-AES256-SHA256,AES256-GCM-SHA384,AES256-SHA256,ECDHE-ECDSA-AES128-GCM-SHA256,ECDHE-RSA-AES128-GCM-SHA256,ECDHE-ECDSA-AES128-SHA256,ECDHE-RSA-AES128-SHA256,ECDH-ECDSA-AES128-GCM-SHA256,ECDH-RSA-AES128-GCM-SHA256,ECDH-ECDSA-AES128-SHA256,ECDH-RSA-AES128-SHA256,DHE-DSS-AES128-GCM-SHA256,DHE-DSS-AES128-SHA256,AES128-GCM-SHA256,AES128-SHA256,ECDHE-ECDSA-AES256-SHA,ECDHE-RSA-AES256-SHA,DHE-DSS-AES256-SHA,ECDH-ECDSA-AES256-SHA,ECDH-RSA-AES256-SHA,AES256-SHA,ECDHE-ECDSA-AES128-SHA,ECDHE-RSA-AES128-SHA,DHE-DSS-AES128-SHA,ECDH-ECDSA-AES128-SHA,ECDH-RSA-AES128-SHA,AES128-SHA"
|
||||
## fail_if_no_peer_cert = true
|
||||
## inet6 = false
|
||||
## ipv6_v6only = false
|
||||
## }
|
||||
]
|
||||
}
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
%% limitations under the License.
|
||||
%%--------------------------------------------------------------------
|
||||
|
||||
-record(mqtt_admin, {username, password, tags}).
|
||||
-record(mqtt_admin, {username, password, tags, role = undefined}).
|
||||
|
||||
-type(mqtt_admin() :: #mqtt_admin{}).
|
||||
|
||||
|
|
|
@ -1,152 +0,0 @@
|
|||
%%-*- mode: erlang -*-
|
||||
%% emqx_dashboard config mapping
|
||||
|
||||
{mapping, "dashboard.default_user.login", "emqx_dashboard.default_user_username", [
|
||||
{datatype, string}
|
||||
]}.
|
||||
|
||||
{mapping, "dashboard.default_user.password", "emqx_dashboard.default_user_passwd", [
|
||||
{datatype, string},
|
||||
{override_env, "EMQX_ADMIN_PASSWORD"}
|
||||
]}.
|
||||
|
||||
{mapping, "dashboard.listener.http.port", "emqx_dashboard.listeners", [
|
||||
{datatype, integer}
|
||||
]}.
|
||||
|
||||
{mapping, "dashboard.listener.http.acceptors", "emqx_dashboard.listeners", [
|
||||
{default, 4},
|
||||
{datatype, integer}
|
||||
]}.
|
||||
|
||||
{mapping, "dashboard.listener.http.max_clients", "emqx_dashboard.listeners", [
|
||||
{default, 512},
|
||||
{datatype, integer}
|
||||
]}.
|
||||
|
||||
{mapping, "dashboard.listener.http.access.$id", "emqx_dashboard.listeners", [
|
||||
{datatype, string}
|
||||
]}.
|
||||
|
||||
{mapping, "dashboard.listener.http.inet6", "emqx_dashboard.listeners", [
|
||||
{default, false},
|
||||
{datatype, {enum, [true, false]}}
|
||||
]}.
|
||||
|
||||
{mapping, "dashboard.listener.http.ipv6_v6only", "emqx_dashboard.listeners", [
|
||||
{default, false},
|
||||
{datatype, {enum, [true, false]}}
|
||||
]}.
|
||||
|
||||
{mapping, "dashboard.listener.https.port", "emqx_dashboard.listeners", [
|
||||
{datatype, integer}
|
||||
]}.
|
||||
|
||||
{mapping, "dashboard.listener.https.acceptors", "emqx_dashboard.listeners", [
|
||||
{default, 8},
|
||||
{datatype, integer}
|
||||
]}.
|
||||
|
||||
{mapping, "dashboard.listener.https.max_clients", "emqx_dashboard.listeners", [
|
||||
{default, 64},
|
||||
{datatype, integer}
|
||||
]}.
|
||||
|
||||
{mapping, "dashboard.listener.https.inet6", "emqx_dashboard.listeners", [
|
||||
{default, false},
|
||||
{datatype, {enum, [true, false]}}
|
||||
]}.
|
||||
|
||||
{mapping, "dashboard.listener.https.ipv6_v6only", "emqx_dashboard.listeners", [
|
||||
{default, false},
|
||||
{datatype, {enum, [true, false]}}
|
||||
]}.
|
||||
|
||||
{mapping, "dashboard.listener.https.tls_versions", "emqx_dashboard.listeners", [
|
||||
{datatype, string}
|
||||
]}.
|
||||
|
||||
{mapping, "dashboard.listener.https.dhfile", "emqx_dashboard.listeners", [
|
||||
{datatype, string}
|
||||
]}.
|
||||
|
||||
{mapping, "dashboard.listener.https.keyfile", "emqx_dashboard.listeners", [
|
||||
{datatype, string}
|
||||
]}.
|
||||
|
||||
{mapping, "dashboard.listener.https.certfile", "emqx_dashboard.listeners", [
|
||||
{datatype, string}
|
||||
]}.
|
||||
|
||||
{mapping, "dashboard.listener.https.cacertfile", "emqx_dashboard.listeners", [
|
||||
{datatype, string}
|
||||
]}.
|
||||
|
||||
{mapping, "dashboard.listener.https.verify", "emqx_dashboard.listeners", [
|
||||
{datatype, string}
|
||||
]}.
|
||||
|
||||
{mapping, "dashboard.listener.https.fail_if_no_peer_cert", "emqx_dashboard.listeners", [
|
||||
{datatype, {enum, [true, false]}}
|
||||
]}.
|
||||
|
||||
{mapping, "dashboard.listener.https.ciphers", "emqx_dashboard.listeners", [
|
||||
{datatype, string}
|
||||
]}.
|
||||
|
||||
{mapping, "dashboard.listener.https.secure_renegotiate", "emqx_dashboard.listeners", [
|
||||
{datatype, flag}
|
||||
]}.
|
||||
|
||||
{mapping, "dashboard.listener.https.reuse_sessions", "emqx_dashboard.listeners", [
|
||||
{default, on},
|
||||
{datatype, flag}
|
||||
]}.
|
||||
|
||||
{mapping, "dashboard.listener.https.honor_cipher_order", "emqx_dashboard.listeners", [
|
||||
{datatype, flag}
|
||||
]}.
|
||||
|
||||
{translation, "emqx_dashboard.listeners", fun(Conf) ->
|
||||
Filter = fun(Opts) -> [{K, V} || {K, V} <- Opts, V =/= undefined] end,
|
||||
LisOpts = fun(Prefix) ->
|
||||
Filter([{num_acceptors, cuttlefish:conf_get(Prefix ++ ".acceptors", Conf)},
|
||||
{max_connections, cuttlefish:conf_get(Prefix ++ ".max_clients", Conf)},
|
||||
{inet6, cuttlefish:conf_get(Prefix ++ ".inet6", Conf)},
|
||||
{ipv6_v6only, cuttlefish:conf_get(Prefix ++ ".ipv6_v6only", Conf)}])
|
||||
end,
|
||||
|
||||
SplitFun = fun(undefined) -> undefined; (S) -> string:tokens(S, ",") end,
|
||||
|
||||
SslOpts = fun(Prefix) ->
|
||||
Versions = case SplitFun(cuttlefish:conf_get(Prefix ++ ".tls_versions", Conf, undefined)) of
|
||||
undefined -> undefined;
|
||||
L -> [list_to_atom(V) || V <- L]
|
||||
end,
|
||||
Filter([{versions, Versions},
|
||||
{ciphers, SplitFun(cuttlefish:conf_get(Prefix ++ ".ciphers", Conf, undefined))},
|
||||
{dhfile, cuttlefish:conf_get(Prefix ++ ".dhfile", Conf, undefined)},
|
||||
{keyfile, cuttlefish:conf_get(Prefix ++ ".keyfile", Conf, undefined)},
|
||||
{certfile, cuttlefish:conf_get(Prefix ++ ".certfile", Conf, undefined)},
|
||||
{cacertfile, cuttlefish:conf_get(Prefix ++ ".cacertfile", Conf, undefined)},
|
||||
{verify, cuttlefish:conf_get(Prefix ++ ".verify", Conf, undefined)},
|
||||
{fail_if_no_peer_cert, cuttlefish:conf_get(Prefix ++ ".fail_if_no_peer_cert", Conf, undefined)},
|
||||
{secure_renegotiate, cuttlefish:conf_get(Prefix ++ ".secure_renegotiate", Conf, undefined)},
|
||||
{reuse_sessions, cuttlefish:conf_get(Prefix ++ ".reuse_sessions", Conf, undefined)},
|
||||
{honor_cipher_order, cuttlefish:conf_get(Prefix ++ ".honor_cipher_order", Conf, undefined)}])
|
||||
end,
|
||||
lists:append(
|
||||
lists:map(
|
||||
fun(Proto) ->
|
||||
Prefix = "dashboard.listener." ++ atom_to_list(Proto),
|
||||
case cuttlefish:conf_get(Prefix ++ ".port", Conf, undefined) of
|
||||
undefined -> [];
|
||||
Port ->
|
||||
[{Proto, Port, case Proto of
|
||||
http -> LisOpts(Prefix);
|
||||
https -> LisOpts(Prefix) ++ SslOpts(Prefix)
|
||||
end}]
|
||||
end
|
||||
end, [http, https]))
|
||||
end}.
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
{application, emqx_dashboard,
|
||||
[{description, "EMQ X Web Dashboard"},
|
||||
{vsn, "4.4.0"}, % strict semver, bump manually!
|
||||
{vsn, "5.0.0"}, % strict semver, bump manually!
|
||||
{modules, []},
|
||||
{registered, [emqx_dashboard_sup]},
|
||||
{applications, [kernel,stdlib,mnesia,minirest]},
|
||||
|
|
|
@ -1,16 +0,0 @@
|
|||
%% -*- mode: erlang -*-
|
||||
{VSN,
|
||||
[ {"4.3.0",
|
||||
%% load all plugins
|
||||
%% NOTE: this depends on the fact that emqx_dashboard is always
|
||||
%% the last application gets upgraded
|
||||
[ {apply, {emqx_plugins, load, []}}
|
||||
]},
|
||||
{<<".*">>, []}
|
||||
],
|
||||
[ {"4.3.0",
|
||||
[ {apply, {emqx_plugins, load, []}}
|
||||
]},
|
||||
{<<".*">>, []}
|
||||
]
|
||||
}.
|
|
@ -16,114 +16,112 @@
|
|||
|
||||
-module(emqx_dashboard).
|
||||
|
||||
-include_lib("emqx/include/emqx.hrl").
|
||||
-include_lib("emqx/include/logger.hrl").
|
||||
-define(APP, ?MODULE).
|
||||
|
||||
%%-import(proplists, [get_value/3]).
|
||||
|
||||
-export([ start_listeners/0
|
||||
, stop_listeners/0
|
||||
, start_listener/1
|
||||
, stop_listener/1
|
||||
]).
|
||||
, stop_listener/1]).
|
||||
|
||||
%% for minirest
|
||||
-export([ filter/1
|
||||
, is_authorized/1
|
||||
]).
|
||||
%% Authorization
|
||||
-export([authorize_appid/1]).
|
||||
|
||||
-define(APP, ?MODULE).
|
||||
|
||||
-define(BASE_PATH, "/api/v5").
|
||||
|
||||
%%--------------------------------------------------------------------
|
||||
%% Start/Stop listeners.
|
||||
%% Start/Stop Listeners
|
||||
%%--------------------------------------------------------------------
|
||||
|
||||
start_listeners() ->
|
||||
lists:foreach(fun(Listener) -> start_listener(Listener) end, listeners()).
|
||||
|
||||
%% Start HTTP Listener
|
||||
start_listener(_) -> ok.
|
||||
%% TODO: V5 API
|
||||
%%start_listener({Proto, Port, Options}) when Proto == http ->
|
||||
%% Dispatch = [{"/", cowboy_static, {priv_file, emqx_dashboard, "www/index.html"}},
|
||||
%% {"/static/[...]", cowboy_static, {priv_dir, emqx_dashboard, "www/static"}},
|
||||
%% {"/api/v4/[...]", minirest, http_handlers()}],
|
||||
%% minirest:start_http(listener_name(Proto), ranch_opts(Port, Options), Dispatch);
|
||||
%%
|
||||
%%start_listener({Proto, Port, Options}) when Proto == https ->
|
||||
%% Dispatch = [{"/", cowboy_static, {priv_file, emqx_dashboard, "www/index.html"}},
|
||||
%% {"/static/[...]", cowboy_static, {priv_dir, emqx_dashboard, "www/static"}},
|
||||
%% {"/api/v4/[...]", minirest, http_handlers()}],
|
||||
%% minirest:start_https(listener_name(Proto), ranch_opts(Port, Options), Dispatch).
|
||||
%%
|
||||
%%ranch_opts(Port, Options0) ->
|
||||
%% NumAcceptors = get_value(num_acceptors, Options0, 4),
|
||||
%% MaxConnections = get_value(max_connections, Options0, 512),
|
||||
%% Options = lists:foldl(fun({K, _V}, Acc) when K =:= max_connections orelse K =:= num_acceptors ->
|
||||
%% Acc;
|
||||
%% ({inet6, true}, Acc) -> [inet6 | Acc];
|
||||
%% ({inet6, false}, Acc) -> Acc;
|
||||
%% ({ipv6_v6only, true}, Acc) -> [{ipv6_v6only, true} | Acc];
|
||||
%% ({ipv6_v6only, false}, Acc) -> Acc;
|
||||
%% ({K, V}, Acc)->
|
||||
%% [{K, V} | Acc]
|
||||
%% end, [], Options0),
|
||||
%% #{num_acceptors => NumAcceptors,
|
||||
%% max_connections => MaxConnections,
|
||||
%% socket_opts => [{port, Port} | Options]}.
|
||||
lists:foreach(fun start_listener/1, listeners()).
|
||||
|
||||
stop_listeners() ->
|
||||
lists:foreach(fun(Listener) -> stop_listener(Listener) end, listeners()).
|
||||
lists:foreach(fun stop_listener/1, listeners()).
|
||||
|
||||
stop_listener(_) ->
|
||||
ok.
|
||||
%% TODO: V5 API
|
||||
%%stop_listener({Proto, _Port, _}) ->
|
||||
%% minirest:stop_http(listener_name(Proto)).
|
||||
start_listener({Proto, Port, Options}) ->
|
||||
{ok, _} = application:ensure_all_started(minirest),
|
||||
Authorization = {?MODULE, authorize_appid},
|
||||
RanchOptions = ranch_opts(Port, Options),
|
||||
GlobalSpec = #{
|
||||
openapi => "3.0.0",
|
||||
info => #{title => "EMQ X Dashboard API", version => "5.0.0"},
|
||||
servers => [#{url => ?BASE_PATH}],
|
||||
components => #{
|
||||
schemas => #{},
|
||||
securitySchemes => #{
|
||||
application => #{
|
||||
type => apiKey,
|
||||
name => "authorization",
|
||||
in => header}}}},
|
||||
Dispatch = [{"/", cowboy_static, {priv_file, emqx_dashboard, "www/index.html"}},
|
||||
{"/static/[...]", cowboy_static, {priv_dir, emqx_dashboard, "www/static"}}],
|
||||
Minirest = #{
|
||||
protocol => Proto,
|
||||
base_path => ?BASE_PATH,
|
||||
apps => apps(),
|
||||
authorization => Authorization,
|
||||
security => [#{application => []}],
|
||||
swagger_global_spec => GlobalSpec,
|
||||
dispatch => Dispatch},
|
||||
MinirestOptions = maps:merge(Minirest, RanchOptions),
|
||||
{ok, _} = minirest:start(listener_name(Proto), MinirestOptions),
|
||||
io:format("Start ~p listener on ~p successfully.~n", [listener_name(Proto), Port]).
|
||||
|
||||
apps() ->
|
||||
[App || {App, _, _} <- application:loaded_applications(),
|
||||
case re:run(atom_to_list(App), "^emqx") of
|
||||
{match,[{0,4}]} -> true;
|
||||
_ -> false
|
||||
end].
|
||||
|
||||
ranch_opts(Port, Options0) ->
|
||||
Options = lists:foldl(
|
||||
fun
|
||||
({K, _V}, Acc) when K =:= max_connections orelse K =:= num_acceptors -> Acc;
|
||||
({inet6, true}, Acc) -> [inet6 | Acc];
|
||||
({inet6, false}, Acc) -> Acc;
|
||||
({ipv6_v6only, true}, Acc) -> [{ipv6_v6only, true} | Acc];
|
||||
({ipv6_v6only, false}, Acc) -> Acc;
|
||||
({K, V}, Acc)->
|
||||
[{K, V} | Acc]
|
||||
end, [], Options0),
|
||||
maps:from_list([{port, Port} | Options]).
|
||||
|
||||
stop_listener({Proto, Port, _}) ->
|
||||
io:format("Stop dashboard listener on ~s successfully.~n",[format(Port)]),
|
||||
minirest:stop(listener_name(Proto)).
|
||||
|
||||
listeners() ->
|
||||
application:get_env(?APP, listeners, []).
|
||||
[{Protocol, Port, maps:to_list(maps:without([protocol, port], Map))}
|
||||
|| Map = #{protocol := Protocol,port := Port}
|
||||
<- emqx_config:get([emqx_dashboard, listeners], [])].
|
||||
|
||||
%%listener_name(Proto) ->
|
||||
%% list_to_atom(atom_to_list(Proto) ++ ":dashboard").
|
||||
listener_name(Proto) ->
|
||||
list_to_atom(atom_to_list(Proto) ++ ":dashboard").
|
||||
|
||||
%%--------------------------------------------------------------------
|
||||
%% HTTP Handlers and Dispatcher
|
||||
%%--------------------------------------------------------------------
|
||||
|
||||
%%http_handlers() ->
|
||||
%% Plugins = lists:map(fun(Plugin) -> Plugin#plugin.name end, emqx_plugins:list()),
|
||||
%% [{"/api/v4/",
|
||||
%% minirest:handler(#{apps => Plugins ++ [emqx_modules],
|
||||
%% filter => fun ?MODULE:filter/1}),
|
||||
%% [{authorization, fun ?MODULE:is_authorized/1}]}].
|
||||
|
||||
%%--------------------------------------------------------------------
|
||||
%% Basic Authorization
|
||||
%%--------------------------------------------------------------------
|
||||
|
||||
is_authorized(Req) ->
|
||||
is_authorized(binary_to_list(cowboy_req:path(Req)), Req).
|
||||
|
||||
is_authorized("/api/v4/auth", _Req) ->
|
||||
true;
|
||||
is_authorized(_Path, Req) ->
|
||||
authorize_appid(Req) ->
|
||||
case cowboy_req:parse_header(<<"authorization">>, Req) of
|
||||
{basic, Username, Password} ->
|
||||
case emqx_dashboard_admin:check(iolist_to_binary(Username),
|
||||
iolist_to_binary(Password)) of
|
||||
ok -> true;
|
||||
{error, Reason} ->
|
||||
?LOG(error, "[Dashboard] Authorization Failure: username=~s, reason=~p",
|
||||
[Username, Reason]),
|
||||
false
|
||||
ok ->
|
||||
ok;
|
||||
{error, _} ->
|
||||
{401, #{<<"WWW-Authenticate">> =>
|
||||
<<"Basic Realm=\"minirest-server\"">>},
|
||||
<<"UNAUTHORIZED">>}
|
||||
end;
|
||||
_ -> false
|
||||
_ ->
|
||||
{401, #{<<"WWW-Authenticate">> =>
|
||||
<<"Basic Realm=\"minirest-server\"">>},
|
||||
<<"UNAUTHORIZED">>}
|
||||
end.
|
||||
|
||||
filter(#{app := emqx_modules}) -> true;
|
||||
filter(#{app := App}) ->
|
||||
case emqx_plugins:find_plugin(App) of
|
||||
false -> false;
|
||||
Plugin -> Plugin#plugin.active
|
||||
end.
|
||||
format(Port) when is_integer(Port) ->
|
||||
io_lib:format("0.0.0.0:~w", [Port]);
|
||||
format({Addr, Port}) when is_list(Addr) ->
|
||||
io_lib:format("~s:~w", [Addr, Port]);
|
||||
format({Addr, Port}) when is_tuple(Addr) ->
|
||||
io_lib:format("~s:~w", [inet:ntoa(Addr), Port]).
|
||||
|
|
|
@ -182,7 +182,7 @@ check(Username, Password) ->
|
|||
|
||||
init([]) ->
|
||||
%% Add default admin user
|
||||
_ = add_default_user(binenv(default_user_username), binenv(default_user_passwd)),
|
||||
_ = add_default_user(binenv(default_username), binenv(default_password)),
|
||||
{ok, state}.
|
||||
|
||||
handle_call(_Req, _From, State) ->
|
||||
|
@ -217,7 +217,7 @@ salt() ->
|
|||
<<Salt:32>>.
|
||||
|
||||
binenv(Key) ->
|
||||
iolist_to_binary(application:get_env(emqx_dashboard, Key, "")).
|
||||
iolist_to_binary(emqx_config:get([emqx_dashboard, Key], "")).
|
||||
|
||||
add_default_user(Username, Password) when ?EMPTY_KEY(Username) orelse ?EMPTY_KEY(Password) ->
|
||||
igonre;
|
||||
|
|
|
@ -0,0 +1,55 @@
|
|||
%%--------------------------------------------------------------------
|
||||
%% Copyright (c) 2020-2021 EMQ Technologies Co., Ltd. All Rights Reserved.
|
||||
%%
|
||||
%% Licensed under the Apache License, Version 2.0 (the "License");
|
||||
%% you may not use this file except in compliance with the License.
|
||||
%% You may obtain a copy of the License at
|
||||
%%
|
||||
%% http://www.apache.org/licenses/LICENSE-2.0
|
||||
%%
|
||||
%% Unless required by applicable law or agreed to in writing, software
|
||||
%% distributed under the License is distributed on an "AS IS" BASIS,
|
||||
%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
%% See the License for the specific language governing permissions and
|
||||
%% limitations under the License.
|
||||
%%--------------------------------------------------------------------
|
||||
-module(emqx_dashboard_schema).
|
||||
|
||||
-include_lib("typerefl/include/types.hrl").
|
||||
|
||||
-export([ structs/0
|
||||
, fields/1]).
|
||||
|
||||
structs() -> ["emqx_dashboard"].
|
||||
|
||||
fields("emqx_dashboard") ->
|
||||
[ {listeners, hoconsc:array(hoconsc:union([hoconsc:ref(?MODULE, "http"),
|
||||
hoconsc:ref(?MODULE, "https")]))}
|
||||
, {default_username, fun default_username/1}
|
||||
, {default_password, fun default_password/1}
|
||||
];
|
||||
|
||||
fields("http") ->
|
||||
[ {"protocol", hoconsc:enum([http, https])}
|
||||
, {"port", emqx_schema:t(integer(), undefined, 8081)}
|
||||
, {"num_acceptors", emqx_schema:t(integer(), undefined, 4)}
|
||||
, {"max_connections", emqx_schema:t(integer(), undefined, 512)}
|
||||
, {"backlog", emqx_schema:t(integer(), undefined, 1024)}
|
||||
, {"send_timeout", emqx_schema:t(emqx_schema:duration(), undefined, "15s")}
|
||||
, {"send_timeout_close", emqx_schema:t(boolean(), undefined, true)}
|
||||
, {"inet6", emqx_schema:t(boolean(), undefined, false)}
|
||||
, {"ipv6_v6only", emqx_schema:t(boolean(), undefined, false)}
|
||||
];
|
||||
|
||||
fields("https") ->
|
||||
emqx_schema:ssl(#{enable => true}) ++ fields("http").
|
||||
|
||||
default_username(type) -> string();
|
||||
default_username(default) -> "admin";
|
||||
default_username(nullable) -> false;
|
||||
default_username(_) -> undefined.
|
||||
|
||||
default_password(type) -> string();
|
||||
default_password(default) -> "public";
|
||||
default_password(nullable) -> false;
|
||||
default_password(_) -> undefined.
|
|
@ -63,7 +63,7 @@ start_listener({Proto, Port, Options}) ->
|
|||
swagger_global_spec => GlobalSpec},
|
||||
MinirestOptions = maps:merge(Minirest, RanchOptions),
|
||||
{ok, _} = minirest:start(listener_name(Proto), MinirestOptions),
|
||||
io:format("Start ~p listener on ~p successfully.", [listener_name(Proto), Port]).
|
||||
io:format("Start ~p listener on ~p successfully.~n", [listener_name(Proto), Port]).
|
||||
|
||||
apps() ->
|
||||
Apps = [App || {App, _, _} <- application:loaded_applications(),
|
||||
|
|
|
@ -269,6 +269,7 @@ relx_apps(ReleaseType) ->
|
|||
, emqx_bridge_mqtt
|
||||
, emqx_modules
|
||||
, emqx_management
|
||||
, emqx_dashboard
|
||||
, emqx_retainer
|
||||
, emqx_statsd
|
||||
]
|
||||
|
|
|
@ -15,15 +15,6 @@ main(_) ->
|
|||
{ok, Bin} = file:read_file(BaseConf),
|
||||
Apps = filelib:wildcard("emqx_*", "apps/"),
|
||||
Conf = lists:foldl(fun(App, Acc) ->
|
||||
case lists:member(App, ["emqx_exhook",
|
||||
"emqx_exproto",
|
||||
"emqx_lwm2m",
|
||||
"emqx_sn",
|
||||
"emqx_coap",
|
||||
"emqx_stomp",
|
||||
"emqx_dashboard"]) of
|
||||
true -> Acc;
|
||||
false ->
|
||||
Filename = filename:join([apps, App, "etc", App]) ++ ".conf",
|
||||
case filelib:is_regular(Filename) of
|
||||
true ->
|
||||
|
@ -31,6 +22,5 @@ main(_) ->
|
|||
[Acc, io_lib:nl(), Bin1];
|
||||
false -> Acc
|
||||
end
|
||||
end
|
||||
end, Bin, Apps),
|
||||
ok = file:write_file("apps/emqx/etc/emqx.conf.all", Conf).
|
||||
|
|
Loading…
Reference in New Issue