diff options
Diffstat (limited to 'src/ejabberd_web_admin.erl')
-rw-r--r-- | src/ejabberd_web_admin.erl | 927 |
1 files changed, 44 insertions, 883 deletions
diff --git a/src/ejabberd_web_admin.erl b/src/ejabberd_web_admin.erl index a112eac35..5eaef7582 100644 --- a/src/ejabberd_web_admin.erl +++ b/src/ejabberd_web_admin.erl @@ -27,13 +27,11 @@ -module(ejabberd_web_admin). --behaviour(ejabberd_config). - -author('alexey@process-one.net'). -export([process/2, list_users/4, list_users_in_diapason/4, pretty_print_xml/1, - term_to_id/1, opt_type/1]). + term_to_id/1]). -include("logger.hrl"). @@ -132,7 +130,7 @@ is_allowed_path([<<"admin">> | Path], JID) -> is_allowed_path(Path, JID); is_allowed_path(Path, JID) -> {HostOfRule, AccessRule} = get_acl_rule(Path, 'GET'), - acl:any_rules_allowed(HostOfRule, AccessRule, JID). + any_rules_allowed(HostOfRule, AccessRule, JID). %% @spec(Path) -> URL %% where Path = [string()] @@ -186,8 +184,8 @@ process([<<"server">>, SHost | RPath] = Path, AJID = get_jid(Auth, HostHTTP, Method), process_admin(Host, Request#request{path = RPath, - auth = {auth_jid, Auth, AJID}, - us = {User, Server}}); + us = {User, Server}}, + AJID); {unauthorized, <<"no-auth-provided">>} -> {401, [{<<"WWW-Authenticate">>, @@ -218,8 +216,8 @@ process(RPath, AJID = get_jid(Auth, HostHTTP, Method), process_admin(global, Request#request{path = RPath, - auth = {auth_jid, Auth, AJID}, - us = {User, Server}}); + us = {User, Server}}, + AJID); {unauthorized, <<"no-auth-provided">>} -> {401, [{<<"WWW-Authenticate">>, @@ -262,8 +260,8 @@ get_auth_account(HostOfRule, AccessRule, User, Server, Pass) -> case ejabberd_auth:check_password(User, <<"">>, Server, Pass) of true -> - case acl:any_rules_allowed(HostOfRule, AccessRule, - jid:make(User, Server)) + case any_rules_allowed(HostOfRule, AccessRule, + jid:make(User, Server)) of false -> {unauthorized, <<"unprivileged-account">>}; true -> {ok, {User, Server}} @@ -342,7 +340,6 @@ make_xhtml(Els, Host, Node, Lang, JID) -> ?AC(<<"https://www.process-one.net/">>, <<"ProcessOne, leader in messaging and push solutions">>)] )])])])]}}. -direction(ltr) -> [{<<"dir">>, <<"ltr">>}]; direction(<<"he">>) -> [{<<"dir">>, <<"rtl">>}]; direction(_) -> []. @@ -395,9 +392,7 @@ logo_fill() -> %%%================================== %%%% process_admin -process_admin(global, - #request{path = [], auth = {_, _, AJID}, - lang = Lang}) -> +process_admin(global, #request{path = [], lang = Lang}, AJID) -> make_xhtml((?H1GL((?T(<<"Administration">>)), <<"">>, <<"Contents">>)) ++ @@ -406,290 +401,65 @@ process_admin(global, || {MIU, MIN} <- get_menu_items(global, cluster, Lang, AJID)])], global, Lang, AJID); -process_admin(Host, - #request{path = [], auth = {_, _Auth, AJID}, - lang = Lang}) -> +process_admin(Host, #request{path = [], lang = Lang}, AJID) -> make_xhtml([?XCT(<<"h1">>, <<"Administration">>), ?XE(<<"ul">>, [?LI([?ACT(MIU, MIN)]) || {MIU, MIN} <- get_menu_items(Host, cluster, Lang, AJID)])], Host, Lang, AJID); -process_admin(Host, - #request{path = [<<"style.css">>]}) -> +process_admin(Host, #request{path = [<<"style.css">>]}, _) -> {200, [{<<"Content-Type">>, <<"text/css">>}, last_modified(), cache_control_public()], css(Host)}; -process_admin(_Host, - #request{path = [<<"favicon.ico">>]}) -> +process_admin(_Host, #request{path = [<<"favicon.ico">>]}, _) -> {200, [{<<"Content-Type">>, <<"image/x-icon">>}, last_modified(), cache_control_public()], favicon()}; -process_admin(_Host, - #request{path = [<<"logo.png">>]}) -> +process_admin(_Host, #request{path = [<<"logo.png">>]}, _) -> {200, [{<<"Content-Type">>, <<"image/png">>}, last_modified(), cache_control_public()], logo()}; -process_admin(_Host, - #request{path = [<<"logo-fill.png">>]}) -> +process_admin(_Host, #request{path = [<<"logo-fill.png">>]}, _) -> {200, [{<<"Content-Type">>, <<"image/png">>}, last_modified(), cache_control_public()], logo_fill()}; -process_admin(_Host, - #request{path = [<<"additions.js">>]}) -> +process_admin(_Host, #request{path = [<<"additions.js">>]}, _) -> {200, [{<<"Content-Type">>, <<"text/javascript">>}, last_modified(), cache_control_public()], additions_js()}; -process_admin(Host, - #request{path = [<<"acls-raw">>], q = Query, - auth = {_, _Auth, AJID}, lang = Lang}) -> - Res = case lists:keysearch(<<"acls">>, 1, Query) of - {value, {_, String}} -> - case erl_scan:string(binary_to_list(String)) of - {ok, Tokens, _} -> - case erl_parse:parse_term(Tokens) of - {ok, NewACLs} -> - case catch acl:add_list(Host, NewACLs, true) of - ok -> ok; - _ -> error - end; - _ -> error - end; - _ -> error - end; - _ -> nothing - end, - ACLs = lists:keysort(2, - mnesia:dirty_select(acl, - [{{acl, {'$1', Host}, '$2'}, [], - [{{acl, '$1', '$2'}}]}])), - {NumLines, ACLsP} = term_to_paragraph(ACLs, 80), - make_xhtml((?H1GL((?T(<<"Access Control Lists">>)), - <<"acldefinition">>, <<"ACL Definition">>)) - ++ - case Res of - ok -> [?XREST(<<"Submitted">>)]; - error -> [?XREST(<<"Bad format">>)]; - nothing -> [] - end - ++ - [?XAE(<<"form">>, - [{<<"action">>, <<"">>}, {<<"method">>, <<"post">>}]++direction(ltr), - [?TEXTAREA(<<"acls">>, - (integer_to_binary(lists:max([16, - NumLines]))), - <<"80">>, <<(iolist_to_binary(ACLsP))/binary, ".">>), - ?BR, - ?INPUTT(<<"submit">>, <<"submit">>, <<"Submit">>)])], - Host, Lang, AJID); -process_admin(Host, - #request{method = Method, path = [<<"acls">>], - auth = {_, _Auth, AJID}, q = Query, lang = Lang}) -> - ?DEBUG("query: ~p", [Query]), - Res = case Method of - 'POST' -> - case catch acl_parse_query(Host, Query) of - {'EXIT', _} -> error; - NewACLs -> - ?INFO_MSG("NewACLs at ~s: ~p", [Host, NewACLs]), - case catch acl:add_list(Host, NewACLs, true) of - ok -> ok; - _ -> error - end - end; - _ -> nothing - end, - ACLs = lists:keysort(2, - mnesia:dirty_select(acl, - [{{acl, {'$1', Host}, '$2'}, [], - [{{acl, '$1', '$2'}}]}])), - make_xhtml((?H1GL((?T(<<"Access Control Lists">>)), - <<"acldefinition">>, <<"ACL Definition">>)) - ++ - case Res of - ok -> [?XREST(<<"Submitted">>)]; - error -> [?XREST(<<"Bad format">>)]; - nothing -> [] - end - ++ - [?XAE(<<"p">>, direction(ltr), [?ACT(<<"../acls-raw/">>, <<"Raw">>)])] ++ - [?XAE(<<"form">>, - [{<<"action">>, <<"">>}, {<<"method">>, <<"post">>}]++direction(ltr), - [acls_to_xhtml(ACLs), ?BR, - ?INPUTT(<<"submit">>, <<"delete">>, - <<"Delete Selected">>), - ?C(<<" ">>), - ?INPUTT(<<"submit">>, <<"submit">>, - <<"Submit">>)])], - Host, Lang, AJID); -process_admin(Host, - #request{path = [<<"access-raw">>], - auth = {_, _Auth, AJID}, q = Query, lang = Lang}) -> - SetAccess = fun (Rs) -> - mnesia:transaction(fun () -> - Os = mnesia:select(access, - [{{access, - {'$1', - Host}, - '$2'}, - [], - ['$_']}]), - lists:foreach(fun (O) -> - mnesia:delete_object(O) - end, - Os), - lists:foreach(fun ({access, - Name, - Rules}) -> - mnesia:write({access, - {Name, - Host}, - Rules}) - end, - Rs) - end) - end, - Res = case lists:keysearch(<<"access">>, 1, Query) of - {value, {_, String}} -> - case erl_scan:string(binary_to_list(String)) of - {ok, Tokens, _} -> - case erl_parse:parse_term(Tokens) of - {ok, Rs} -> - case SetAccess(Rs) of - {atomic, _} -> ok; - _ -> error - end; - _ -> error - end; - _ -> error - end; - _ -> nothing - end, - Access = mnesia:dirty_select(access, - [{{access, {'$1', Host}, '$2'}, [], - [{{access, '$1', '$2'}}]}]), - {NumLines, AccessP} = term_to_paragraph(lists:keysort(2,Access), 80), - make_xhtml((?H1GL((?T(<<"Access Rules">>)), - <<"accessrights">>, <<"Access Rights">>)) - ++ - case Res of - ok -> [?XREST(<<"Submitted">>)]; - error -> [?XREST(<<"Bad format">>)]; - nothing -> [] - end - ++ - [?XAE(<<"form">>, - [{<<"action">>, <<"">>}, {<<"method">>, <<"post">>}]++direction(ltr), - [?TEXTAREA(<<"access">>, - (integer_to_binary(lists:max([16, - NumLines]))), - <<"80">>, <<(iolist_to_binary(AccessP))/binary, ".">>), - ?BR, - ?INPUTT(<<"submit">>, <<"submit">>, <<"Submit">>)])], - Host, Lang, AJID); -process_admin(Host, - #request{method = Method, path = [<<"access">>], - q = Query, auth = {_, _Auth, AJID}, lang = Lang}) -> - ?DEBUG("query: ~p", [Query]), - Res = case Method of - 'POST' -> - case catch access_parse_query(Host, Query) of - {'EXIT', _} -> error; - ok -> ok - end; - _ -> nothing - end, - AccessRules = mnesia:dirty_select(access, - [{{access, {'$1', Host}, '$2'}, [], - [{{access, '$1', '$2'}}]}]), - make_xhtml((?H1GL((?T(<<"Access Rules">>)), - <<"accessrights">>, <<"Access Rights">>)) - ++ - case Res of - ok -> [?XREST(<<"Submitted">>)]; - error -> [?XREST(<<"Bad format">>)]; - nothing -> [] - end - ++ - [?XAE(<<"p">>, direction(ltr), [?ACT(<<"../access-raw/">>, <<"Raw">>)])] - ++ - [?XAE(<<"form">>, - [{<<"action">>, <<"">>}, {<<"method">>, <<"post">>}]++direction(ltr), - [access_rules_to_xhtml(AccessRules, Lang), ?BR, - ?INPUTT(<<"submit">>, <<"delete">>, - <<"Delete Selected">>)])], - Host, Lang, AJID); -process_admin(Host, - #request{path = [<<"access">>, SName], q = Query, - auth = {_, _Auth, AJID}, lang = Lang}) -> - ?DEBUG("query: ~p", [Query]), - Name = misc:binary_to_atom(SName), - Res = case lists:keysearch(<<"rules">>, 1, Query) of - {value, {_, String}} -> - case parse_access_rule(String) of - {ok, Rs} -> - ejabberd_config:add_option({access, Name, Host}, - Rs), - ok; - _ -> error - end; - _ -> nothing - end, - Rules = ejabberd_config:get_option({access, Name, Host}, []), - make_xhtml([?XC(<<"h1">>, - (str:format( - ?T(<<"~s access rule configuration">>), - [SName])))] - ++ - case Res of - ok -> [?XREST(<<"Submitted">>)]; - error -> [?XREST(<<"Bad format">>)]; - nothing -> [] - end - ++ - [?XAE(<<"form">>, - [{<<"action">>, <<"">>}, {<<"method">>, <<"post">>}], - [access_rule_to_xhtml(Rules), ?BR, - ?INPUTT(<<"submit">>, <<"submit">>, <<"Submit">>)])], - Host, Lang, AJID); -process_admin(global, - #request{path = [<<"vhosts">>], auth = {_, _Auth, AJID}, - lang = Lang}) -> +process_admin(global, #request{path = [<<"vhosts">>], lang = Lang}, AJID) -> Res = list_vhosts(Lang, AJID), make_xhtml((?H1GL((?T(<<"Virtual Hosts">>)), <<"virtualhosting">>, <<"Virtual Hosting">>)) ++ Res, global, Lang, AJID); -process_admin(Host, - #request{path = [<<"users">>], q = Query, - auth = {_, _Auth, AJID}, lang = Lang}) +process_admin(Host, #request{path = [<<"users">>], q = Query, + lang = Lang}, AJID) when is_binary(Host) -> Res = list_users(Host, Query, Lang, fun url_func/1), make_xhtml([?XCT(<<"h1">>, <<"Users">>)] ++ Res, Host, Lang, AJID); -process_admin(Host, - #request{path = [<<"users">>, Diap], - auth = {_, _Auth, AJID}, lang = Lang}) +process_admin(Host, #request{path = [<<"users">>, Diap], + lang = Lang}, AJID) when is_binary(Host) -> Res = list_users_in_diapason(Host, Diap, Lang, fun url_func/1), make_xhtml([?XCT(<<"h1">>, <<"Users">>)] ++ Res, Host, Lang, AJID); -process_admin(Host, - #request{path = [<<"online-users">>], - auth = {_, _Auth, AJID}, lang = Lang}) +process_admin(Host, #request{path = [<<"online-users">>], + lang = Lang}, AJID) when is_binary(Host) -> Res = list_online_users(Host, Lang), make_xhtml([?XCT(<<"h1">>, <<"Online Users">>)] ++ Res, Host, Lang, AJID); -process_admin(Host, - #request{path = [<<"last-activity">>], - auth = {_, _Auth, AJID}, q = Query, lang = Lang}) +process_admin(Host, #request{path = [<<"last-activity">>], + q = Query, lang = Lang}, AJID) when is_binary(Host) -> ?DEBUG("query: ~p", [Query]), Month = case lists:keysearch(<<"period">>, 1, Query) of @@ -730,15 +500,12 @@ process_admin(Host, <<"Show Integral Table">>)])] ++ Res, Host, Lang, AJID); -process_admin(Host, - #request{path = [<<"stats">>], auth = {_, _Auth, AJID}, - lang = Lang}) -> +process_admin(Host, #request{path = [<<"stats">>], lang = Lang}, AJID) -> Res = get_stats(Host, Lang), make_xhtml([?XCT(<<"h1">>, <<"Statistics">>)] ++ Res, Host, Lang, AJID); -process_admin(Host, - #request{path = [<<"user">>, U], - auth = {_, _Auth, AJID}, q = Query, lang = Lang}) -> +process_admin(Host, #request{path = [<<"user">>, U], + q = Query, lang = Lang}, AJID) -> case ejabberd_auth:user_exists(U, Host) of true -> Res = user_info(U, Host, Query, Lang), @@ -747,14 +514,11 @@ process_admin(Host, make_xhtml([?XCT(<<"h1">>, <<"Not Found">>)], Host, Lang, AJID) end; -process_admin(Host, - #request{path = [<<"nodes">>], auth = {_, _Auth, AJID}, - lang = Lang}) -> +process_admin(Host, #request{path = [<<"nodes">>], lang = Lang}, AJID) -> Res = get_nodes(Lang), make_xhtml(Res, Host, Lang, AJID); -process_admin(Host, - #request{path = [<<"node">>, SNode | NPath], - auth = {_, _Auth, AJID}, q = Query, lang = Lang}) -> +process_admin(Host, #request{path = [<<"node">>, SNode | NPath], + q = Query, lang = Lang}, AJID) -> case search_running_node(SNode) of false -> make_xhtml([?XCT(<<"h1">>, <<"Node not found">>)], Host, @@ -765,9 +529,7 @@ process_admin(Host, end; %%%================================== %%%% process_admin default case -process_admin(Host, - #request{lang = Lang, auth = {_, _Auth, AJID}} = - Request) -> +process_admin(Host, #request{lang = Lang} = Request, AJID) -> Res = case Host of global -> ejabberd_hooks:run_fold( @@ -785,286 +547,15 @@ process_admin(Host, _ -> make_xhtml(Res, Host, Lang, AJID) end. -%%%================================== -%%%% acl - -acls_to_xhtml(ACLs) -> - ?XAE(<<"table">>, [], - [?XE(<<"tbody">>, - (lists:map(fun ({acl, Name, Spec} = ACL) -> - SName = iolist_to_binary(atom_to_list(Name)), - ID = term_to_id(ACL), - ?XE(<<"tr">>, - ([?XE(<<"td">>, - [?INPUT(<<"checkbox">>, - <<"selected">>, ID)]), - ?XC(<<"td">>, SName)] - ++ acl_spec_to_xhtml(ID, Spec))) - end, - ACLs) - ++ - [?XE(<<"tr">>, - ([?X(<<"td">>), - ?XE(<<"td">>, - [?INPUT(<<"text">>, <<"namenew">>, <<"">>)])] - ++ acl_spec_to_xhtml(<<"new">>, {user, <<"">>})))]))]). - -acl_spec_to_text({user, {U, S}}) -> - {user, <<U/binary, "@", S/binary>>}; -acl_spec_to_text({user, U}) -> {user, U}; -acl_spec_to_text({server, S}) -> {server, S}; -acl_spec_to_text({user_regexp, {RU, S}}) -> - {user_regexp, <<RU/binary, "@", S/binary>>}; -acl_spec_to_text({user_regexp, RU}) -> - {user_regexp, RU}; -acl_spec_to_text({server_regexp, RS}) -> - {server_regexp, RS}; -acl_spec_to_text({node_regexp, {RU, RS}}) -> - {node_regexp, <<RU/binary, "@", RS/binary>>}; -acl_spec_to_text({user_glob, {RU, S}}) -> - {user_glob, <<RU/binary, "@", S/binary>>}; -acl_spec_to_text({user_glob, RU}) -> {user_glob, RU}; -acl_spec_to_text({server_glob, RS}) -> - {server_glob, RS}; -acl_spec_to_text({node_glob, {RU, RS}}) -> - {node_glob, <<RU/binary, "@", RS/binary>>}; -acl_spec_to_text(all) -> {all, <<"">>}; -acl_spec_to_text({ip, {IP, L}}) -> {ip, <<(misc:ip_to_list(IP))/binary, "/", - (integer_to_binary(L))/binary>>}; -acl_spec_to_text(Spec) -> {raw, term_to_string(Spec)}. - -acl_spec_to_xhtml(ID, Spec) -> - {Type, Str} = acl_spec_to_text(Spec), - [acl_spec_select(ID, Type), ?ACLINPUT(Str)]. - -acl_spec_select(ID, Opt) -> - ?XE(<<"td">>, - [?XAE(<<"select">>, - [{<<"name">>, <<"type", ID/binary>>}], - (lists:map(fun (O) -> - Sel = if O == Opt -> - [{<<"selected">>, - <<"selected">>}]; - true -> [] - end, - ?XAC(<<"option">>, - (Sel ++ - [{<<"value">>, - iolist_to_binary(atom_to_list(O))}]), - (iolist_to_binary(atom_to_list(O)))) - end, - [user, server, user_regexp, server_regexp, node_regexp, - user_glob, server_glob, node_glob, all, ip, raw])))]). - -%% @spec (T::any()) -> StringLine::string() -term_to_string(T) -> - StringParagraph = - (str:format("~1000000p", [T])), - ejabberd_regexp:greplace(StringParagraph, <<"\\n ">>, - <<"">>). - -%% @spec (T::any(), Cols::integer()) -> {NumLines::integer(), Paragraph::string()} -term_to_paragraph(T, Cols) -> - Paragraph = iolist_to_binary(io_lib:print(T, 1, Cols, -1)), - FieldList = ejabberd_regexp:split(Paragraph, <<"\n">>), - NumLines = length(FieldList), - {NumLines, Paragraph}. - term_to_id(T) -> base64:encode((term_to_binary(T))). -acl_parse_query(Host, Query) -> - ACLs = mnesia:dirty_select(acl, - [{{acl, {'$1', Host}, '$2'}, [], - [{{acl, '$1', '$2'}}]}]), - case lists:keysearch(<<"submit">>, 1, Query) of - {value, _} -> acl_parse_submit(ACLs, Query); - _ -> - case lists:keysearch(<<"delete">>, 1, Query) of - {value, _} -> acl_parse_delete(ACLs, Query) - end - end. - -acl_parse_submit(ACLs, Query) -> - NewACLs = lists:map(fun ({acl, Name, Spec} = ACL) -> - ID = term_to_id(ACL), - case {lists:keysearch(<<"type", ID/binary>>, 1, - Query), - lists:keysearch(<<"value", ID/binary>>, 1, - Query)} - of - {{value, {_, T}}, {value, {_, V}}} -> - {Type, Str} = acl_spec_to_text(Spec), - case - {iolist_to_binary(atom_to_list(Type)), - Str} - of - {T, V} -> ACL; - _ -> - NewSpec = string_to_spec(T, V), - {acl, Name, NewSpec} - end; - _ -> ACL - end - end, - ACLs), - NewACL = case {lists:keysearch(<<"namenew">>, 1, Query), - lists:keysearch(<<"typenew">>, 1, Query), - lists:keysearch(<<"valuenew">>, 1, Query)} - of - {{value, {_, <<"">>}}, _, _} -> []; - {{value, {_, N}}, {value, {_, T}}, {value, {_, V}}} -> - NewName = misc:binary_to_atom(N), - NewSpec = string_to_spec(T, V), - [{acl, NewName, NewSpec}]; - _ -> [] - end, - NewACLs ++ NewACL. - -string_to_spec(<<"user">>, Val) -> - string_to_spec2(user, Val); -string_to_spec(<<"server">>, Val) -> {server, Val}; -string_to_spec(<<"user_regexp">>, Val) -> - string_to_spec2(user_regexp, Val); -string_to_spec(<<"server_regexp">>, Val) -> - {server_regexp, Val}; -string_to_spec(<<"node_regexp">>, Val) -> - #jid{luser = U, lserver = S, resource = <<"">>} = - jid:decode(Val), - {node_regexp, U, S}; -string_to_spec(<<"user_glob">>, Val) -> - string_to_spec2(user_glob, Val); -string_to_spec(<<"server_glob">>, Val) -> - {server_glob, Val}; -string_to_spec(<<"node_glob">>, Val) -> - #jid{luser = U, lserver = S, resource = <<"">>} = - jid:decode(Val), - {node_glob, U, S}; -string_to_spec(<<"ip">>, Val) -> - [IPs, Ms] = str:tokens(Val, <<"/">>), - {ok, IP} = inet_parse:address(binary_to_list(IPs)), - {ip, {IP, binary_to_integer(Ms)}}; -string_to_spec(<<"all">>, _) -> all; -string_to_spec(<<"raw">>, Val) -> - {ok, Tokens, _} = erl_scan:string(binary_to_list(<<Val/binary, ".">>)), - {ok, NewSpec} = erl_parse:parse_term(Tokens), - NewSpec. - -string_to_spec2(ACLName, Val) -> - #jid{luser = U, lserver = S, resource = <<"">>} = - jid:decode(Val), - case U of - <<"">> -> {ACLName, S}; - _ -> {ACLName, {U, S}} - end. - -acl_parse_delete(ACLs, Query) -> - NewACLs = lists:filter(fun ({acl, _Name, _Spec} = - ACL) -> - ID = term_to_id(ACL), - not lists:member({<<"selected">>, ID}, Query) - end, - ACLs), - NewACLs. - -access_rules_to_xhtml(AccessRules, Lang) -> - ?XAE(<<"table">>, [], - [?XE(<<"tbody">>, - (lists:map(fun ({access, Name, Rules} = Access) -> - SName = iolist_to_binary(atom_to_list(Name)), - ID = term_to_id(Access), - ?XE(<<"tr">>, - [?XE(<<"td">>, - [?INPUT(<<"checkbox">>, - <<"selected">>, ID)]), - ?XE(<<"td">>, - [?AC(<<SName/binary, "/">>, SName)]), - ?XC(<<"td">>, (term_to_string(Rules)))]) - end, - lists:keysort(2,AccessRules)) - ++ - [?XE(<<"tr">>, - [?X(<<"td">>), - ?XE(<<"td">>, - [?INPUT(<<"text">>, <<"namenew">>, <<"">>)]), - ?XE(<<"td">>, - [?INPUTT(<<"submit">>, <<"addnew">>, - <<"Add New">>)])])]))]). - -access_parse_query(Host, Query) -> - AccessRules = mnesia:dirty_select(access, - [{{access, {'$1', Host}, '$2'}, [], - [{{access, '$1', '$2'}}]}]), - case lists:keysearch(<<"addnew">>, 1, Query) of - {value, _} -> - access_parse_addnew(AccessRules, Host, Query); - _ -> - case lists:keysearch(<<"delete">>, 1, Query) of - {value, _} -> - access_parse_delete(AccessRules, Host, Query) - end - end. - -access_parse_addnew(_AccessRules, Host, Query) -> - case lists:keysearch(<<"namenew">>, 1, Query) of - {value, {_, String}} when String /= <<"">> -> - Name = misc:binary_to_atom(String), - ejabberd_config:add_option({access, Name, Host}, - []), - ok - end. - -access_parse_delete(AccessRules, Host, Query) -> - lists:foreach(fun ({access, Name, _Rules} = - AccessRule) -> - ID = term_to_id(AccessRule), - case lists:member({<<"selected">>, ID}, Query) of - true -> - mnesia:transaction(fun () -> - mnesia:delete({access, - {Name, - Host}}) - end); - _ -> ok - end - end, - AccessRules), - ok. - -access_rule_to_xhtml(Rules) -> - Text = lists:flatmap(fun ({Access, ACL} = _Rule) -> - SAccess = element_to_list(Access), - SACL = atom_to_list(ACL), - [SAccess, " \t", SACL, "\n"] - end, - Rules), - ?XAC(<<"textarea">>, - [{<<"name">>, <<"rules">>}, {<<"rows">>, <<"16">>}, - {<<"cols">>, <<"80">>}], - list_to_binary(Text)). - -parse_access_rule(Text) -> - Strings = str:tokens(Text, <<"\r\n">>), - case catch lists:flatmap(fun (String) -> - case str:tokens(String, <<" \t">>) of - [Access, ACL] -> - [{list_to_element(Access), - misc:binary_to_atom(ACL)}]; - [] -> [] - end - end, - Strings) - of - {'EXIT', _Reason} -> error; - Rs -> {ok, Rs} - end. - %%%================================== %%%% list_vhosts list_vhosts(Lang, JID) -> - Hosts = ejabberd_config:get_myhosts(), + Hosts = ejabberd_option:hosts(), HostsAllowed = lists:filter(fun (Host) -> - acl:any_rules_allowed(Host, + any_rules_allowed(Host, [configure, webadmin_view], JID) end, @@ -1262,7 +753,7 @@ get_offlinemsg_module(Server) -> end. get_lastactivity_menuitem_list(Server) -> - case gen_mod:get_module_opt(Server, mod_last, db_type) of + case mod_last_opt:db_type(Server) of mnesia -> [{<<"last-activity">>, <<"Last Activity">>}]; _ -> [] end. @@ -1282,7 +773,7 @@ get_stats(global, Lang) -> ejabberd_auth:count_users(Host) + Total end, - 0, ejabberd_config:get_myhosts()), + 0, ejabberd_option:hosts()), OutS2SNumber = ejabberd_s2s:outgoing_s2s_number(), InS2SNumber = ejabberd_s2s:incoming_s2s_number(), [?XAE(<<"table">>, [], @@ -1579,8 +1070,6 @@ get_node(global, Node, [], Query, Lang) -> [?XE(<<"ul">>, ([?LI([?ACT(<<Base/binary, "db/">>, <<"Database">>)]), ?LI([?ACT(<<Base/binary, "backup/">>, <<"Backup">>)]), - ?LI([?ACT(<<Base/binary, "ports/">>, - <<"Listened Ports">>)]), ?LI([?ACT(<<Base/binary, "stats/">>, <<"Statistics">>)]), ?LI([?ACT(<<Base/binary, "update/">>, <<"Update">>)])] @@ -1594,10 +1083,7 @@ get_node(Host, Node, [], _Query, Lang) -> Base = get_base_path(Host, Node), MenuItems2 = make_menu_items(Host, Node, Base, Lang), [?XC(<<"h1">>, (str:format(?T(<<"Node ~p">>), [Node]))), - ?XE(<<"ul">>, - ([?LI([?ACT(<<Base/binary, "modules/">>, - <<"Modules">>)])] - ++ MenuItems2))]; + ?XE(<<"ul">>, MenuItems2)]; get_node(global, Node, [<<"db">>], Query, Lang) -> case ejabberd_cluster:call(Node, mnesia, system_info, [tables]) of {badrpc, _Reason} -> @@ -1830,68 +1316,6 @@ get_node(global, Node, [<<"backup">>], Query, Lang) -> ?XE(<<"td">>, [?INPUTT(<<"submit">>, <<"import_dir">>, <<"OK">>)])])])])])]; -get_node(global, Node, [<<"ports">>], Query, Lang) -> - Ports = ejabberd_cluster:call(Node, ejabberd_config, - get_local_option, [listen, - {ejabberd_listener, validate_cfg}, - []]), - Res = case catch node_ports_parse_query(Node, Ports, - Query) - of - submitted -> ok; - {'EXIT', _Reason} -> error; - {is_added, ok} -> ok; - {is_added, {error, Reason}} -> - {error, (str:format("~p", [Reason]))}; - _ -> nothing - end, - NewPorts = lists:sort(ejabberd_cluster:call(Node, ejabberd_config, - get_local_option, - [listen, - {ejabberd_listener, validate_cfg}, - []])), - H1String = <<(?T(<<"Listened Ports at ">>))/binary, - (iolist_to_binary(atom_to_list(Node)))/binary>>, - (?H1GL(H1String, <<"listeningports">>, <<"Listening Ports">>)) - ++ - case Res of - ok -> [?XREST(<<"Submitted">>)]; - error -> [?XREST(<<"Bad format">>)]; - {error, ReasonT} -> - [?XRES(<<(?T(<<"Error">>))/binary, ": ", - ReasonT/binary>>)]; - nothing -> [] - end - ++ - [?XAE(<<"form">>, - [{<<"action">>, <<"">>}, {<<"method">>, <<"post">>}], - [node_ports_to_xhtml(NewPorts, Lang)])]; -get_node(Host, Node, [<<"modules">>], Query, Lang) - when is_binary(Host) -> - Modules = ejabberd_cluster:call(Node, gen_mod, - loaded_modules_with_opts, [Host]), - Res = case catch node_modules_parse_query(Host, Node, - Modules, Query) - of - submitted -> ok; - {'EXIT', Reason} -> ?ERROR_MSG("~p~n", [Reason]), error; - _ -> nothing - end, - NewModules = lists:sort(ejabberd_cluster:call(Node, gen_mod, - loaded_modules_with_opts, [Host])), - H1String = (str:format(?T(<<"Modules at ~p">>), [Node])), - (?H1GL(H1String, <<"modulesoverview">>, - <<"Modules Overview">>)) - ++ - case Res of - ok -> [?XREST(<<"Submitted">>)]; - error -> [?XREST(<<"Bad format">>)]; - nothing -> [] - end - ++ - [?XAE(<<"form">>, - [{<<"action">>, <<"">>}, {<<"method">>, <<"post">>}], - [node_modules_to_xhtml(NewModules, Lang)])]; get_node(global, Node, [<<"stats">>], _Query, Lang) -> UpTime = ejabberd_cluster:call(Node, erlang, statistics, [wall_clock]), @@ -2170,252 +1594,6 @@ node_backup_parse_query(Node, Query) -> <<"import_piefxis_file">>, <<"export_piefxis_dir">>, <<"export_piefxis_host_dir">>, <<"export_sql_file">>]). -node_ports_to_xhtml(Ports, Lang) -> - ?XAE(<<"table">>, [{<<"class">>, <<"withtextareas">>}], - [?XE(<<"thead">>, - [?XE(<<"tr">>, - [?XCT(<<"td">>, <<"Port">>), ?XCT(<<"td">>, <<"IP">>), - ?XCT(<<"td">>, <<"Protocol">>), - ?XCT(<<"td">>, <<"Module">>), - ?XCT(<<"td">>, <<"Options">>)])]), - ?XE(<<"tbody">>, - (lists:map(fun ({PortIP, Module, Opts} = _E) -> - {_Port, SPort, _TIP, SIP, SSPort, NetProt, - OptsClean} = - get_port_data(PortIP, Opts), - SModule = - iolist_to_binary(atom_to_list(Module)), - {NumLines, SOptsClean} = - term_to_paragraph(OptsClean, 40), - ?XE(<<"tr">>, - [?XAE(<<"td">>, [{<<"size">>, <<"6">>}], - [?C(SPort)]), - ?XAE(<<"td">>, [{<<"size">>, <<"15">>}], - [?C(SIP)]), - ?XAE(<<"td">>, [{<<"size">>, <<"4">>}], - [?C((iolist_to_binary(atom_to_list(NetProt))))]), - ?XE(<<"td">>, - [?INPUTS(<<"text">>, - <<"module", SSPort/binary>>, - SModule, <<"15">>)]), - ?XAE(<<"td">>, direction(ltr), - [?TEXTAREA(<<"opts", SSPort/binary>>, - (integer_to_binary(NumLines)), - <<"35">>, SOptsClean)]), - ?XE(<<"td">>, - [?INPUTT(<<"submit">>, - <<"add", SSPort/binary>>, - <<"Restart">>)]), - ?XE(<<"td">>, - [?INPUTT(<<"submit">>, - <<"delete", SSPort/binary>>, - <<"Stop">>)])]) - end, - Ports) - ++ - [?XE(<<"tr">>, - [?XE(<<"td">>, - [?INPUTS(<<"text">>, <<"portnew">>, <<"">>, - <<"6">>)]), - ?XE(<<"td">>, - [?INPUTS(<<"text">>, <<"ipnew">>, <<"0.0.0.0">>, - <<"15">>)]), - ?XE(<<"td">>, [make_netprot_html(<<"tcp">>)]), - ?XE(<<"td">>, - [?INPUTS(<<"text">>, <<"modulenew">>, <<"">>, - <<"15">>)]), - ?XAE(<<"td">>, direction(ltr), - [?TEXTAREA(<<"optsnew">>, <<"2">>, <<"35">>, - <<"[]">>)]), - ?XAE(<<"td">>, [{<<"colspan">>, <<"2">>}], - [?INPUTT(<<"submit">>, <<"addnew">>, - <<"Start">>)])])]))]). - -make_netprot_html(NetProt) -> - ?XAE(<<"select">>, [{<<"name">>, <<"netprotnew">>}], - (lists:map(fun (O) -> - Sel = if O == NetProt -> - [{<<"selected">>, <<"selected">>}]; - true -> [] - end, - ?XAC(<<"option">>, (Sel ++ [{<<"value">>, O}]), O) - end, - [<<"tcp">>, <<"udp">>]))). - -get_port_data(PortIP, Opts) -> - {Port, IPT, _IPV, NetProt, OptsClean} = - ejabberd_listener:parse_listener_portip(PortIP, Opts), - IPS = misc:ip_to_list(IPT), - SPort = integer_to_binary(Port), - SSPort = list_to_binary( - lists:map(fun (N) -> - io_lib:format("~.16b", [N]) - end, - binary_to_list( - erlang:md5( - [SPort, IPS, atom_to_list(NetProt)])))), - {Port, SPort, IPT, IPS, SSPort, NetProt, OptsClean}. - -node_ports_parse_query(Node, Ports, Query) -> - lists:foreach(fun ({PortIpNetp, Module1, Opts1}) -> - {Port, _SPort, TIP, _SIP, SSPort, NetProt, - _OptsClean} = - get_port_data(PortIpNetp, Opts1), - case lists:keysearch(<<"add", SSPort/binary>>, 1, - Query) - of - {value, _} -> - PortIpNetp2 = {Port, TIP, NetProt}, - {{value, {_, SModule}}, {value, {_, SOpts}}} = - {lists:keysearch(<<"module", - SSPort/binary>>, - 1, Query), - lists:keysearch(<<"opts", SSPort/binary>>, - 1, Query)}, - Module = misc:binary_to_atom(SModule), - {ok, Tokens, _} = - erl_scan:string(binary_to_list(SOpts) ++ "."), - {ok, Opts} = erl_parse:parse_term(Tokens), - ejabberd_cluster:call(Node, ejabberd_listener, - delete_listener, - [PortIpNetp2, Module1]), - R = ejabberd_cluster:call(Node, ejabberd_listener, - add_listener, - [PortIpNetp2, Module, Opts]), - throw({is_added, R}); - _ -> - case lists:keysearch(<<"delete", - SSPort/binary>>, - 1, Query) - of - {value, _} -> - ejabberd_cluster:call(Node, ejabberd_listener, - delete_listener, - [PortIpNetp, Module1]), - throw(submitted); - _ -> ok - end - end - end, - Ports), - case lists:keysearch(<<"addnew">>, 1, Query) of - {value, _} -> - {{value, {_, SPort}}, {value, {_, STIP}}, - {value, {_, SNetProt}}, {value, {_, SModule}}, - {value, {_, SOpts}}} = - {lists:keysearch(<<"portnew">>, 1, Query), - lists:keysearch(<<"ipnew">>, 1, Query), - lists:keysearch(<<"netprotnew">>, 1, Query), - lists:keysearch(<<"modulenew">>, 1, Query), - lists:keysearch(<<"optsnew">>, 1, Query)}, - {ok, Toks, _} = erl_scan:string(binary_to_list(<<SPort/binary, ".">>)), - {ok, Port2} = erl_parse:parse_term(Toks), - {ok, ToksIP, _} = erl_scan:string(binary_to_list(<<STIP/binary, ".">>)), - STIP2 = case erl_parse:parse_term(ToksIP) of - {ok, IPTParsed} -> IPTParsed; - {error, _} -> STIP - end, - Module = misc:binary_to_atom(SModule), - NetProt2 = misc:binary_to_atom(SNetProt), - {ok, Tokens, _} = erl_scan:string(binary_to_list(<<SOpts/binary, ".">>)), - {ok, Opts} = erl_parse:parse_term(Tokens), - {Port2, _SPort, IP2, _SIP, _SSPort, NetProt2, - OptsClean} = - get_port_data({Port2, STIP2, NetProt2}, Opts), - R = ejabberd_cluster:call(Node, ejabberd_listener, add_listener, - [{Port2, IP2, NetProt2}, Module, OptsClean]), - throw({is_added, R}); - _ -> ok - end. - -node_modules_to_xhtml(Modules, Lang) -> - ?XAE(<<"table">>, [{<<"class">>, <<"withtextareas">>}], - [?XE(<<"thead">>, - [?XE(<<"tr">>, - [?XCT(<<"td">>, <<"Module">>), - ?XCT(<<"td">>, <<"Options">>)])]), - ?XE(<<"tbody">>, - (lists:map(fun ({Module, Opts} = _E) -> - SModule = - iolist_to_binary(atom_to_list(Module)), - {NumLines, SOpts} = term_to_paragraph(Opts, - 40), - ?XE(<<"tr">>, - [?XC(<<"td">>, SModule), - ?XAE(<<"td">>, direction(ltr), - [?TEXTAREA(<<"opts", SModule/binary>>, - (integer_to_binary(NumLines)), - <<"40">>, SOpts)]), - ?XE(<<"td">>, - [?INPUTT(<<"submit">>, - <<"restart", - SModule/binary>>, - <<"Restart">>)]), - ?XE(<<"td">>, - [?INPUTT(<<"submit">>, - <<"stop", SModule/binary>>, - <<"Stop">>)])]) - end, - Modules) - ++ - [?XE(<<"tr">>, - [?XE(<<"td">>, - [?INPUT(<<"text">>, <<"modulenew">>, <<"">>)]), - ?XAE(<<"td">>, direction(ltr), - [?TEXTAREA(<<"optsnew">>, <<"2">>, <<"40">>, - <<"[]">>)]), - ?XAE(<<"td">>, [{<<"colspan">>, <<"2">>}], - [?INPUTT(<<"submit">>, <<"start">>, - <<"Start">>)])])]))]). - -node_modules_parse_query(Host, Node, Modules, Query) -> - lists:foreach(fun ({Module, _Opts1}) -> - SModule = iolist_to_binary(atom_to_list(Module)), - case lists:keysearch(<<"restart", SModule/binary>>, 1, - Query) - of - {value, _} -> - {value, {_, SOpts}} = lists:keysearch(<<"opts", - SModule/binary>>, - 1, Query), - {ok, Tokens, _} = - erl_scan:string(binary_to_list(<<SOpts/binary, ".">>)), - {ok, Opts} = erl_parse:parse_term(Tokens), - NewMods = lists:keystore(Module, 1, ejabberd_config:get_option(modules), {Module, Opts}), - ejabberd_cluster:call(Node, gen_mod, stop_module, - [Host, Module]), - ejabberd_cluster:call(Node, ejabberd_config, add_option, - [modules, NewMods]), - ejabberd_cluster:call(Node, gen_mod, start_module, - [Host, Module]), - throw(submitted); - _ -> - case lists:keysearch(<<"stop", SModule/binary>>, - 1, Query) - of - {value, _} -> - ejabberd_cluster:call(Node, gen_mod, stop_module, - [Host, Module]), - throw(submitted); - _ -> ok - end - end - end, - Modules), - case lists:keysearch(<<"start">>, 1, Query) of - {value, _} -> - {{value, {_, SModule}}, {value, {_, SOpts}}} = - {lists:keysearch(<<"modulenew">>, 1, Query), - lists:keysearch(<<"optsnew">>, 1, Query)}, - Module = misc:binary_to_atom(SModule), - {ok, Tokens, _} = erl_scan:string(binary_to_list(<<SOpts/binary, ".">>)), - {ok, Opts} = erl_parse:parse_term(Tokens), - ejabberd_cluster:call(Node, gen_mod, start_module, - [Host, Module, Opts]), - throw(submitted); - _ -> ok - end. - node_update_parse_query(Node, Query) -> case lists:keysearch(<<"update">>, 1, Query) of {value, _} -> @@ -2495,16 +1673,6 @@ pretty_print_xml(#xmlel{name = Name, attrs = Attrs, end end]. -element_to_list(X) when is_atom(X) -> - iolist_to_binary(atom_to_list(X)); -element_to_list(X) when is_integer(X) -> - integer_to_binary(X). - -list_to_element(Bin) -> - {ok, Tokens, _} = erl_scan:string(binary_to_list(Bin)), - [{_, _, Element}] = Tokens, - Element. - url_func({user_diapason, From, To}) -> <<(integer_to_binary(From))/binary, "-", (integer_to_binary(To))/binary, "/">>; @@ -2576,8 +1744,7 @@ make_host_node_menu(_, cluster, _Lang, _JID) -> {<<"">>, <<"">>, []}; make_host_node_menu(Host, Node, Lang, JID) -> HostNodeBase = get_base_path(Host, Node), - HostNodeFixed = [{<<"modules/">>, <<"Modules">>}] ++ - get_menu_items_hook({hostnode, Host, Node}, Lang), + HostNodeFixed = get_menu_items_hook({hostnode, Host, Node}, Lang), HostNodeBasePath = url_to_path(HostNodeBase), HostNodeFixed2 = [Tuple || Tuple <- HostNodeFixed, @@ -2589,9 +1756,7 @@ make_host_menu(global, _HostNodeMenu, _Lang, _JID) -> {<<"">>, <<"">>, []}; make_host_menu(Host, HostNodeMenu, Lang, JID) -> HostBase = get_base_path(Host, cluster), - HostFixed = [{<<"acls">>, <<"Access Control Lists">>}, - {<<"access">>, <<"Access Rules">>}, - {<<"users">>, <<"Users">>}, + HostFixed = [{<<"users">>, <<"Users">>}, {<<"online-users">>, <<"Online Users">>}] ++ get_lastactivity_menuitem_list(Host) ++ @@ -2610,7 +1775,6 @@ make_node_menu(global, Node, Lang) -> NodeBase = get_base_path(global, Node), NodeFixed = [{<<"db/">>, <<"Database">>}, {<<"backup/">>, <<"Backup">>}, - {<<"ports/">>, <<"Listened Ports">>}, {<<"stats/">>, <<"Statistics">>}, {<<"update/">>, <<"Update">>}] ++ get_menu_items_hook({node, Node}, Lang), @@ -2621,9 +1785,7 @@ make_node_menu(_Host, _Node, _Lang) -> make_server_menu(HostMenu, NodeMenu, Lang, JID) -> Base = get_base_path(global, cluster), - Fixed = [{<<"acls">>, <<"Access Control Lists">>}, - {<<"access">>, <<"Access Rules">>}, - {<<"vhosts">>, <<"Virtual Hosts">>, HostMenu}, + Fixed = [{<<"vhosts">>, <<"Virtual Hosts">>, HostMenu}, {<<"nodes">>, <<"Nodes">>, NodeMenu}, {<<"stats">>, <<"Statistics">>}] ++ get_menu_items_hook(server, Lang), @@ -2696,11 +1858,10 @@ make_menu_item(item, 3, URI, Name, Lang) -> ?LI([?XAE(<<"div">>, [{<<"id">>, <<"navitemsubsub">>}], [?ACT(URI, Name)])]). -%%%================================== - - --spec opt_type(atom()) -> fun((any()) -> any()) | [atom()]. -opt_type(access_readonly) -> fun acl:access_rules_validator/1; -opt_type(_) -> [access_readonly]. +any_rules_allowed(Host, Access, Entity) -> + lists:any( + fun(Rule) -> + allow == acl:match_rule(Host, Rule, Entity) + end, Access). %%% vim: set foldmethod=marker foldmarker=%%%%,%%%=: |