From 185381b1bf8013e1a8c94c16f9976569fb7c01c6 Mon Sep 17 00:00:00 2001 From: Michael Uvarov Date: Mon, 30 Apr 2018 12:21:15 +0200 Subject: [PATCH 1/3] Fix broken lager_console_backend backend Log message: Lager fatally failed to install handler lager_console_backend into lager_event, NOT retrying: {bad_console_config, info} --- rel/files/app.config | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rel/files/app.config b/rel/files/app.config index 158d50fc9bd..0f7e1bdb765 100644 --- a/rel/files/app.config +++ b/rel/files/app.config @@ -6,7 +6,7 @@ {log_root, "{{mongooseim_log_dir}}"}, {crash_log, "crash.log"}, {handlers, [ - {lager_console_backend, [info, {lager_default_formatter,[{eol, "\r\n"}]}]}, + {lager_console_backend, [{level, info}]}, %% use below line to add syslog backend for Lager % {lager_syslog_backend, [ "mongooseim", local0, info]}, {lager_file_backend, [{file, "ejabberd.log"}, {level, info}, {size, 2097152}, {date, "$D0"}, {count, 5}]} From 19fb5c61a57a5ce8a5684e48f90451e7a1a51e1d Mon Sep 17 00:00:00 2001 From: Arkadiusz Gil Date: Tue, 2 Jan 2018 13:00:43 +0100 Subject: [PATCH 2/3] Allow JIDs from all MUC light domains in HTTP room API --- big_tests/tests/rest_client_SUITE.erl | 87 +++++++++++++++++++++--- doc/rest-api/Client-frontend_swagger.yml | 2 +- src/ejabberd_router.erl | 10 +++ src/mongoose_client_api_rooms.erl | 33 ++++++--- 4 files changed, 112 insertions(+), 20 deletions(-) diff --git a/big_tests/tests/rest_client_SUITE.erl b/big_tests/tests/rest_client_SUITE.erl index 84ffeff2eca..51da650ba8c 100644 --- a/big_tests/tests/rest_client_SUITE.erl +++ b/big_tests/tests/rest_client_SUITE.erl @@ -64,7 +64,12 @@ muc_test_cases() -> room_is_not_created_with_jid_not_matching_hostname, room_can_be_fetched_by_jid, messages_can_be_sent_and_fetched_by_room_jid, - user_can_be_added_and_removed_by_room_jid + user_can_be_added_and_removed_by_room_jid, + room_cant_be_created_given_jid_in_a_non_muc_light_domain, + user_cant_be_invited_given_room_jid_in_a_non_muc_light_domain, + user_cant_be_removed_given_room_jid_in_a_non_muc_light_domain, + message_cant_be_sent_given_room_jid_in_a_non_muc_light_domain, + messages_cant_be_read_given_room_jid_in_a_non_muc_light_domain ]. roster_test_cases() -> @@ -83,7 +88,9 @@ init_per_suite(C) -> dynamic_modules:start(Host, mod_muc_light, [{host, binary_to_list(MUCLightHost)}, {rooms_in_rosters, true}]), - [{muc_light_host, MUCLightHost} | escalus:init_per_suite(C1)]. + NonMUCLightHost = <<"nonmuclight.", Host/binary>>, % register! + [{muc_light_host, MUCLightHost}, + {non_muc_light_host, NonMUCLightHost} | escalus:init_per_suite(C1)]. end_per_suite(Config) -> escalus_fresh:clean(), @@ -387,6 +394,63 @@ user_can_be_added_and_removed_by_room_jid(Config) -> ?assertEqual(<<"204">>, Status) end). +room_cant_be_created_given_jid_in_a_non_muc_light_domain(Config) -> + escalus:fresh_story(Config, [{alice, 1}], fun(Alice) -> + RoomID = <<"some_id">>, + RoomJID = <>, + Creds = credentials({alice, Alice}), + + {{Status, _}, _} = create_room_with_id_request(Creds, + <<"some_name">>, + <<"some subject">>, + RoomJID), + ?assertEqual(<<"400">>, Status) + end). + +user_cant_be_invited_given_room_jid_in_a_non_muc_light_domain(Config) -> + escalus:fresh_story(Config, [{alice, 1}], fun(Alice) -> + RoomID = given_new_room({alice, Alice}), + RoomJID = <>, + Creds = credentials({alice, Alice}), + + {{Status, _}, _} = invite_to_room({alice, Alice}, RoomJID, <<"auser@domain.com">>), + + ?assertEqual(<<"400">>, Status) + end). + +user_cant_be_removed_given_room_jid_in_a_non_muc_light_domain(Config) -> + escalus:fresh_story(Config, [{alice, 1}, {bob, 1}], fun(Alice, Bob) -> + RoomID = given_new_room({alice, Alice}), + RoomJID = <>, + Creds = credentials({alice, Alice}), + + {{Status, _}, _} = remove_user_from_a_room({alice, Alice}, RoomJID, Bob), + + ?assertEqual(<<"400">>, Status) + end). + +message_cant_be_sent_given_room_jid_in_a_non_muc_light_domain(Config) -> + escalus:fresh_story(Config, [{alice, 1}, {bob, 1}], fun(Alice, Bob) -> + RoomID = given_new_room({alice, Alice}), + RoomJID = <>, + Creds = credentials({alice, Alice}), + + {{Status, _}, _} = send_message_to_room({alice, Alice}, RoomJID), + + ?assertEqual(<<"400">>, Status) + end). + +messages_cant_be_read_given_room_jid_in_a_non_muc_light_domain(Config) -> + escalus:fresh_story(Config, [{alice, 1}, {bob, 1}], fun(Alice, Bob) -> + RoomID = given_new_room({alice, Alice}), + RoomJID = <>, + Creds = credentials({alice, Alice}), + + {{Status, _}, _} = get_room_messages({alice, Alice}, RoomJID), + + ?assertEqual(<<"400">>, Status) + end). + assert_room_messages(RecvMsg, {_ID, _GenFrom, GenMsg}) -> escalus:assert(is_chat_message, [maps:get(body, RecvMsg)], GenMsg), ok. @@ -413,15 +477,12 @@ wait_for_room_msg(Msg, User) -> Stanza = escalus:wait_for_stanza(User), escalus:assert(is_groupchat_message, [maps:get(body, Msg)], Stanza). -given_message_sent_to_room(RoomID, Sender) -> - {UserJID, _} = Creds = credentials(Sender), - Path = <<"/rooms/", RoomID/binary, "/messages">>, - Body = #{body => <<"Hi all!">>}, - {{<<"200">>, <<"OK">>}, {Result}} = rest_helper:post(client, Path, Body, Creds), +given_message_sent_to_room(RoomID, {_, ClientOrSpec} = Sender) -> + Body = <<"Hi all!">>, + {{<<"200">>, <<"OK">>}, {Result}} = send_message_to_room(Sender, RoomID, Body), MsgId = proplists:get_value(<<"id">>, Result), true = is_binary(MsgId), - - Body#{id => MsgId, from => UserJID}. + #{body => Body, id => MsgId, from => user_jid(ClientOrSpec)}. given_new_room_with_users(Owner, Users) -> RoomID = given_new_room(Owner), @@ -501,6 +562,14 @@ get_messages(MeCreds, Other, Before, Count) -> "&limit=", integer_to_list(Count)]), get_messages(GetPath, MeCreds). +send_message_to_room(Client, RoomID) -> + send_message_to_room(Client, RoomID, <<"Hi all!">>). + +send_message_to_room(Client, RoomID, Body) -> + {UserJID, _} = Creds = credentials(Client), + Path = <<"/rooms/", RoomID/binary, "/messages">>, + Payload = #{body => Body}, + rest_helper:post(client, Path, Payload, Creds). get_room_messages(Client, RoomID, Count) -> get_room_messages(Client, RoomID, Count, undefined). diff --git a/doc/rest-api/Client-frontend_swagger.yml b/doc/rest-api/Client-frontend_swagger.yml index c929f4f754b..2a92628400a 100644 --- a/doc/rest-api/Client-frontend_swagger.yml +++ b/doc/rest-api/Client-frontend_swagger.yml @@ -10,7 +10,7 @@ info: This is to ensure integration between the **REST API** users and regular **XMPP** users. * All requests requiring a room ID (i.e. most of the requests fired at `/room` endpoint) accept either a bare room ID (e.g. `656c6f656c6f`) or a room JID (e.g. `656c6f656c6f@muclight.somedomain.com`). - The host part of the room JID must be the host name of a MUC light service running in user's domain. + The host part of the room JID must be the host name of a registered MUC light service. * All requests require authentication. This is to make sure the server can identify who sent the request and if it comes from an authorized user. Currently the only supported method is **Basic Auth**. diff --git a/src/ejabberd_router.erl b/src/ejabberd_router.erl index 406c3535628..9ea4c4221d6 100644 --- a/src/ejabberd_router.erl +++ b/src/ejabberd_router.erl @@ -41,6 +41,7 @@ dirty_get_all_domains/0, dirty_get_all_routes/1, dirty_get_all_domains/1, + dirty_get_route_handler_module/1, register_components/2, register_components/3, register_components/4, @@ -374,6 +375,15 @@ all_routes(only_public) -> ++ mnesia:dirty_select(external_component_global, [MatchNonHidden]). +-spec dirty_get_route_handler_module(Domain :: binary()) -> {ok, module()} | error. +dirty_get_route_handler_module(Domain) -> + Routes = mnesia:dirty_match_object(#route{domain = Domain, handler = '_'}), + case Routes of + [#route{handler = {packet_handler, Module, _}}] -> + {ok, Module}; + _ -> + error + end. %%==================================================================== %% gen_server callbacks diff --git a/src/mongoose_client_api_rooms.erl b/src/mongoose_client_api_rooms.erl index 98a67041a52..2f285b0c754 100644 --- a/src/mongoose_client_api_rooms.erl +++ b/src/mongoose_client_api_rooms.erl @@ -41,7 +41,6 @@ allowed_methods(Req, State) -> resource_exists(Req, #{jid := #jid{lserver = Server}} = State) -> {RoomIDOrJID, Req2} = cowboy_req:binding(id, Req), - MUCLightDomain = muc_light_domain(Server), case RoomIDOrJID of undefined -> {Method, Req3} = cowboy_req:method(Req2), @@ -53,8 +52,8 @@ resource_exists(Req, #{jid := #jid{lserver = Server}} = State) -> end; _ -> case validate_room_id(RoomIDOrJID, Server) of - {ok, RoomID} -> - does_room_exist(RoomID, MUCLightDomain, Req2, State); + {ok, RoomID, RoomHost} -> + does_room_exist(RoomID, RoomHost, Req2, State); _ -> bad_request(Req2, State) end @@ -150,15 +149,29 @@ determine_role(US, Users) -> Role end. --spec validate_room_id(RoomIDOrJID :: binary(), Server :: binary()) -> - {ok, RoomID :: binary()} | error. -validate_room_id(RoomIDOrJID, Server) -> - MUCLightDomain = muc_light_domain(Server), +-spec validate_room_id(RoomIDOrJID :: binary() | term(), Server :: binary()) -> + {ok, RoomID :: binary(), RoomHost :: binary()} | error. +validate_room_id(RoomIDOrJID, Server) when is_binary(RoomIDOrJID) -> case jid:from_binary(RoomIDOrJID) of #jid{luser = <<>>, lserver = RoomID, lresource = <<>>} -> - {ok, RoomID}; - #jid{luser = RoomID, lserver = MUCLightDomain, lresource = <<>>} -> - {ok, RoomID}; + DefaultMucLightDomain = muc_light_domain(Server), + {ok, RoomID, DefaultMucLightDomain}; + #jid{luser = RoomID, lserver = RoomHost, lresource = <<>>} -> + case validate_room_host(RoomHost) of + ok -> + {ok, RoomID, RoomHost}; + error -> + error + end; + _ -> + error + end. + +-spec validate_room_host(binary()) -> ok | error. +validate_room_host(RoomHost) -> + case ejabberd_router:dirty_get_route_handler_module(RoomHost) of + {ok, mod_muc_light} -> + ok; _ -> error end. From 1d40acd6ccd369ad7705038b547795ac63f937f5 Mon Sep 17 00:00:00 2001 From: Arkadiusz Gil Date: Tue, 8 May 2018 13:07:11 +0200 Subject: [PATCH 3/3] Ensure that rooms can be created in a secondary MUC light domain --- big_tests/tests/rest_client_SUITE.erl | 29 +++++++++++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/big_tests/tests/rest_client_SUITE.erl b/big_tests/tests/rest_client_SUITE.erl index 51da650ba8c..6767434e1fa 100644 --- a/big_tests/tests/rest_client_SUITE.erl +++ b/big_tests/tests/rest_client_SUITE.erl @@ -69,7 +69,8 @@ muc_test_cases() -> user_cant_be_invited_given_room_jid_in_a_non_muc_light_domain, user_cant_be_removed_given_room_jid_in_a_non_muc_light_domain, message_cant_be_sent_given_room_jid_in_a_non_muc_light_domain, - messages_cant_be_read_given_room_jid_in_a_non_muc_light_domain + messages_cant_be_read_given_room_jid_in_a_non_muc_light_domain, + room_can_be_created_in_a_secondary_muc_light_domain ]. roster_test_cases() -> @@ -88,8 +89,11 @@ init_per_suite(C) -> dynamic_modules:start(Host, mod_muc_light, [{host, binary_to_list(MUCLightHost)}, {rooms_in_rosters, true}]), - NonMUCLightHost = <<"nonmuclight.", Host/binary>>, % register! + SecondaryMUCLightHost = <<"othermuclight.", Host/binary>>, + register_secondary_muc_light_service(SecondaryMUCLightHost), + NonMUCLightHost = <<"notamuclight.", Host/binary>>, % register! [{muc_light_host, MUCLightHost}, + {secondary_muc_light_host, SecondaryMUCLightHost}, {non_muc_light_host, NonMUCLightHost} | escalus:init_per_suite(C1)]. end_per_suite(Config) -> @@ -97,9 +101,17 @@ end_per_suite(Config) -> Host = ct:get_config({hosts, mim, domain}), rest_helper:maybe_disable_mam(mam_helper:backend(), Host), dynamic_modules:stop(Host, mod_muc_light), + unregister_secondary_muc_light_service(?config(secondary_muc_light_host, Config)), application:stop(shotgun), escalus:end_per_suite(Config). +register_secondary_muc_light_service(MUCLightHost) -> + PacketHandler = escalus_ejabberd:rpc(mongoose_packet_handler, new, [mod_muc_light]), + escalus_ejabberd:rpc(ejabberd_router, register_route, [MUCLightHost, PacketHandler]). + +unregister_secondary_muc_light_service(MUCLightHost) -> + escalus_ejabberd:rpc(ejabberd_router, unregister_route, [MUCLightHost]). + init_per_group(_GN, C) -> C. @@ -451,6 +463,19 @@ messages_cant_be_read_given_room_jid_in_a_non_muc_light_domain(Config) -> ?assertEqual(<<"400">>, Status) end). +room_can_be_created_in_a_secondary_muc_light_domain(Config) -> + escalus:fresh_story(Config, [{alice, 1}], fun(Alice) -> + RoomID = <<"some_id_but_different_domain">>, + RoomJID = <>, + Creds = credentials({alice, Alice}), + + {{Status, _}, _} = create_room_with_id_request(Creds, + <<"some_name">>, + <<"some subject">>, + RoomJID), + ?assertEqual(<<"201">>, Status) + end). + assert_room_messages(RecvMsg, {_ID, _GenFrom, GenMsg}) -> escalus:assert(is_chat_message, [maps:get(body, RecvMsg)], GenMsg), ok.