Skip to content

Commit 0f2b78f

Browse files
authored
Merge pull request #4548 from esl/blocking-for-groupchats
Implement support for blocking a user for any groupchat
2 parents f31e9d1 + 7412c32 commit 0f2b78f

File tree

3 files changed

+107
-5
lines changed

3 files changed

+107
-5
lines changed

big_tests/tests/mod_blocking_SUITE.erl

Lines changed: 88 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
-module(mod_blocking_SUITE).
1818
-compile([export_all, nowarn_export_all]).
1919

20+
-include_lib("common_test/include/ct.hrl").
2021
-include_lib("exml/include/exml.hrl").
2122
-include_lib("eunit/include/eunit.hrl").
2223
-include_lib("escalus/include/escalus_xmlns.hrl").
@@ -33,7 +34,9 @@ all() ->
3334
{group, effect},
3435
{group, offline},
3536
{group, errors},
36-
{group, pushes}
37+
{group, pushes},
38+
{group, muc},
39+
{group, muc_light}
3740
].
3841

3942
groups() ->
@@ -43,7 +46,9 @@ groups() ->
4346
{offline, [sequence], offline_test_cases()},
4447
{errors, [parallel], error_test_cases()},
4548
{pushes, [parallel], push_test_cases()},
46-
{notify, [parallel], notify_test_cases()}
49+
{notify, [parallel], notify_test_cases()},
50+
{muc, [parallel], muc_test_cases()},
51+
{muc_light, [parallel], muc_light_test_cases()}
4752
].
4853

4954
manage_test_cases() ->
@@ -81,12 +86,19 @@ offline_test_cases() ->
8186

8287
error_test_cases() ->
8388
[blocker_cant_send_to_blockee].
89+
8490
push_test_cases() ->
8591
[block_push_sent].
8692

8793
notify_test_cases() ->
8894
[notify_blockee].
8995

96+
muc_test_cases() ->
97+
[messages_from_blocked_user_dont_arrive_muc].
98+
99+
muc_light_test_cases() ->
100+
[messages_from_blocked_user_dont_arrive_muc_light].
101+
90102
suite() ->
91103
escalus:suite().
92104

@@ -108,9 +120,28 @@ end_per_suite(Config) ->
108120
escalus:end_per_suite(Config),
109121
instrument_helper:stop().
110122

123+
init_per_group(muc, Config) ->
124+
muc_helper:load_muc(),
125+
mongoose_helper:ensure_muc_clean(),
126+
init_per_group(generic, Config);
127+
init_per_group(muc_light, Config0) ->
128+
HostType = domain_helper:host_type(),
129+
Config1 = dynamic_modules:save_modules(HostType, Config0),
130+
Backend = mongoose_helper:mnesia_or_rdbms_backend(),
131+
MucLightConfig = config_parser_helper:mod_config(mod_muc_light, #{backend => Backend}),
132+
dynamic_modules:ensure_modules(HostType, [{mod_muc_light, MucLightConfig}]),
133+
init_per_group(generic, Config1);
111134
init_per_group(_GroupName, Config) ->
112135
escalus_fresh:create_users(Config, escalus:get_users([alice, bob, kate, mike, john])).
113136

137+
end_per_group(muc, Config) ->
138+
mongoose_helper:ensure_muc_clean(),
139+
muc_helper:unload_muc(),
140+
Config;
141+
end_per_group(muc_light, Config) ->
142+
muc_light_helper:clear_db(domain_helper:host_type()),
143+
dynamic_modules:restore_modules(Config),
144+
Config;
114145
end_per_group(_GroupName, Config) ->
115146
Config.
116147

@@ -240,6 +271,47 @@ messages_from_blocked_user_dont_arrive(Config) ->
240271
privacy_helper:assert_privacy_check_packet_event(User1, #{dir => in, blocked_count => 1}, TS)
241272
end).
242273

274+
messages_from_blocked_user_dont_arrive_muc(ConfigIn) ->
275+
muc_helper:story_with_room(ConfigIn, [], [{alice, 1}, {bob, 1}], fun(Config, Alice, Bob) ->
276+
RoomJid = ?config(room, Config),
277+
BobNick = escalus_utils:get_username(Bob),
278+
escalus:send(Bob, muc_helper:stanza_muc_enter_room(RoomJid, BobNick)),
279+
escalus:wait_for_stanzas(Bob, 2),
280+
AliceNick = escalus_utils:get_username(Alice),
281+
escalus:send(Alice, muc_helper:stanza_muc_enter_room(RoomJid, AliceNick)),
282+
escalus:wait_for_stanza(Bob),
283+
escalus:wait_for_stanzas(Alice, 3),
284+
285+
user_blocks(Alice, [Bob], muc),
286+
TS = instrument_helper:timestamp(),
287+
Stanza = escalus_stanza:groupchat_to(muc_helper:room_address(?config(room, Config)), <<"Hello">>),
288+
escalus:send(Bob, Stanza),
289+
ct:sleep(100),
290+
% We don't expect Bob to get an error from Alice as this would lead to
291+
% her being kicked out of the room
292+
escalus_assert:has_no_stanzas(Alice),
293+
privacy_helper:assert_privacy_check_packet_event(Bob, #{dir => out}, TS),
294+
privacy_helper:assert_privacy_check_packet_event(Alice, #{dir => in, blocked_count => 1}, TS)
295+
end).
296+
297+
messages_from_blocked_user_dont_arrive_muc_light(Config) ->
298+
escalus:fresh_story(Config, [{alice, 1}, {bob, 1}], fun(Alice, Bob) ->
299+
RoomName = <<"blocking-testroom">>,
300+
muc_light_helper:create_room(RoomName, muc_light_helper:muc_host(),
301+
Alice, [Bob], Config, muc_light_helper:ver(1)),
302+
303+
user_blocks(Alice, [Bob], muc_light),
304+
TS = instrument_helper:timestamp(),
305+
Stanza = escalus_stanza:groupchat_to(muc_light_helper:room_bin_jid(RoomName), <<"Hello">>),
306+
escalus:send(Bob, Stanza),
307+
ct:sleep(100),
308+
% We don't expect Bob to get an error from Alice as this would lead to
309+
% her being kicked out of the room
310+
escalus_assert:has_no_stanzas(Alice),
311+
privacy_helper:assert_privacy_check_packet_event(Bob, #{dir => out}, TS),
312+
privacy_helper:assert_privacy_check_packet_event(Alice, #{dir => in, blocked_count => 1}, TS)
313+
end).
314+
243315
messages_from_unblocked_user_arrive_again(Config) ->
244316
escalus:fresh_story(
245317
Config, [{alice, 1}, {bob, 1}],
@@ -594,9 +666,12 @@ get_blocklist_items(Items) ->
594666
maps:get(<<"jid">>, A)
595667
end, Items).
596668

597-
user_blocks(Blocker, Blockees) when is_list(Blockees) ->
669+
user_blocks(Blocker, Blockees) ->
670+
user_blocks(Blocker, Blockees, pm).
671+
672+
user_blocks(Blocker, Blockees, ChatType) when is_list(Blockees) ->
598673
TS = instrument_helper:timestamp(),
599-
BlockeeJIDs = [ escalus_utils:jid_to_lower(escalus_client:short_jid(B)) || B <- Blockees ],
674+
BlockeeJIDs = blockee_jids(Blockees, ChatType),
600675
AddStanza = block_users_stanza(BlockeeJIDs),
601676
escalus_client:send(Blocker, AddStanza),
602677
Res = escalus:wait_for_stanzas(Blocker, 2),
@@ -605,6 +680,15 @@ user_blocks(Blocker, Blockees) when is_list(Blockees) ->
605680
escalus:assert_many(Preds, Res),
606681
privacy_helper:assert_privacy_set_event(Blocker, #{}, TS).
607682

683+
blockee_jids(Blockees, pm) ->
684+
[escalus_utils:jid_to_lower(escalus_client:short_jid(B)) || B <- Blockees];
685+
blockee_jids(Blockees, muc) ->
686+
MucHost = muc_helper:muc_host(),
687+
[<<MucHost/binary, "/", (escalus_client:username(B))/binary>> || B <- Blockees];
688+
blockee_jids(Blockees, muc_light) ->
689+
MucHost = muc_light_helper:muc_host(),
690+
[<<MucHost/binary, "/", (escalus_client:short_jid(B))/binary>> || B <- Blockees].
691+
608692
blocklist_is_empty(BlockList) ->
609693
escalus:assert(is_iq_result, BlockList),
610694
escalus:assert(fun is_blocklist_result_empty/1, BlockList).

doc/modules/mod_blocking.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,3 +24,9 @@ If the user has other online resources which use privacy lists it may result in
2424
Similar to privacy lists, a blocked contact sees the user as offline no matter what their real status is.
2525

2626
If the contact being blocked is subscribed to the user's presence, they receive an "unavailable" presence; when unblocked, they receive the current status of the user.
27+
28+
The user can be blocked in the context of groupchat by using `domain/resource` format of the jid, see [JID Matching](https://xmpp.org/extensions/xep-0191.html#matching).
29+
The `domain` part should be then a configured `muc` or `muclight` domain, e.g. `conference.localhost` or `muclight.localhost`.
30+
The resource is then respectively user's nickname in case of `muc` or user's bare jid in case of `muclight`.
31+
32+
Note: When a blocked user sends a message to a room, the server does not respond with an error but silently ignores it, i.e. doesn't deliver it to the user that issued the blocking.

src/privacy/mod_privacy.erl

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,12 @@ handle_privacy_iq(Acc1, StateData, HostType, IQ) ->
166166
-spec user_receive_message(mongoose_acc:t(), mongoose_c2s_hooks:params(), gen_hook:extra()) ->
167167
mongoose_c2s_hooks:result().
168168
user_receive_message(Acc, #{c2s_data := StateData}, _Extra) ->
169-
do_privacy_check_receive(Acc, StateData, send).
169+
case mongoose_acc:stanza_type(Acc) of
170+
<<"groupchat">> ->
171+
do_privacy_check_receive(Acc, StateData, ignore);
172+
_ ->
173+
do_privacy_check_receive(Acc, StateData, send)
174+
end.
170175

171176
-spec user_receive_presence(mongoose_acc:t(), mongoose_c2s_hooks:params(), map()) ->
172177
mongoose_c2s_hooks:result().
@@ -677,6 +682,13 @@ is_type_match(jid, Value, JID, _Subscription, _Groups) ->
677682
_ ->
678683
false
679684
end;
685+
{<<>>, Server, Resource} ->
686+
case JID of
687+
{_, Server, Resource} ->
688+
true;
689+
_ ->
690+
false
691+
end;
680692
_ ->
681693
Value == JID
682694
end;

0 commit comments

Comments
 (0)