1: %%==============================================================================
    2: %% Copyright 2010 Erlang Solutions Ltd.
    3: %%
    4: %% Licensed under the Apache License, Version 2.0 (the "License");
    5: %% you may not use this file except in compliance with the License.
    6: %% You may obtain a copy of the License at
    7: %%
    8: %% http://www.apache.org/licenses/LICENSE-2.0
    9: %%
   10: %% Unless required by applicable law or agreed to in writing, software
   11: %% distributed under the License is distributed on an "AS IS" BASIS,
   12: %% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   13: %% See the License for the specific language governing permissions and
   14: %% limitations under the License.
   15: %%==============================================================================
   16: 
   17: -module(privacy_SUITE).
   18: -compile([export_all, nowarn_export_all]).
   19: 
   20: -include_lib("exml/include/exml.hrl").
   21: -include_lib("escalus/include/escalus.hrl").
   22: -include_lib("common_test/include/ct.hrl").
   23: -include_lib("escalus/include/escalus_xmlns.hrl").
   24: 
   25: -define(SLEEP_TIME, 50).
   26: 
   27: %%--------------------------------------------------------------------
   28: %% Suite configuration
   29: %%--------------------------------------------------------------------
   30: 
   31: all() ->
   32:     [
   33:      {group, management},
   34:      {group, blocking},
   35:      {group, allowing}
   36:     ].
   37: 
   38: groups() ->
   39:     [
   40:      {management, [parallel], management_test_cases()},
   41:      {blocking, [parallel], blocking_test_cases()},
   42:      {allowing, [parallel], allowing_test_cases()}
   43:     ].
   44: 
   45: management_test_cases() ->
   46:     [
   47:      discover_support,
   48:      get_all_lists,
   49:      get_existing_list,
   50:      get_many_lists,
   51:      get_nonexistent_list,
   52:      set_list,
   53:      activate,
   54:      activate_nonexistent,
   55:      deactivate,
   56:      default,
   57:      %default_conflict,  % fails, as of bug #7073
   58:      default_nonexistent,
   59:      no_default,
   60:      remove_list,
   61:      get_all_lists_with_active,
   62:      get_all_lists_with_default
   63:     ].
   64: 
   65: blocking_test_cases() ->
   66:     [
   67:      block_jid_message,
   68:      block_group_message,
   69:      block_subscription_message,
   70:      block_all_message,
   71:      block_jid_presence_in,
   72:      block_jid_presence_out,
   73:      block_jid_iq,
   74:      block_jid_all,
   75:      block_jid_message_but_not_presence,
   76:      newly_blocked_presense_jid_by_new_list,
   77:      newly_blocked_presense_jid_by_list_change,
   78:      newly_blocked_presence_not_notify_self,
   79:      iq_reply_doesnt_crash_user_process
   80:     ].
   81: 
   82: allowing_test_cases() ->
   83:     [allow_subscription_to_from_message,
   84:      allow_subscription_both_message].
   85: 
   86: suite() ->
   87:     escalus:suite().
   88: 
   89: %%--------------------------------------------------------------------
   90: %% Init & teardown
   91: %%--------------------------------------------------------------------
   92: 
   93: init_per_suite(Config0) ->
   94:     HostType = domain_helper:host_type(),
   95:     Config1 = dynamic_modules:save_modules(HostType, Config0),
   96:     Backend = mongoose_helper:get_backend_mnesia_rdbms(HostType),
   97:     ModConfig = [{mod_privacy, set_opts(Backend)}],
   98:     dynamic_modules:ensure_modules(HostType, ModConfig),
   99:     [{escalus_no_stanzas_after_story, true},
  100:      {backend, Backend} |
  101:      escalus:init_per_suite(Config1)].
  102: 
  103: set_opts(Backend) ->
  104:     config_parser_helper:mod_config(mod_privacy, #{backend => Backend}).
  105: 
  106: end_per_suite(Config) ->
  107:     escalus_fresh:clean(),
  108:     dynamic_modules:restore_modules(Config),
  109:     escalus:end_per_suite(Config).
  110: 
  111: init_per_group(_GroupName, Config) ->
  112:     Config.
  113: 
  114: end_per_group(_GroupName, Config) ->
  115:     Config.
  116: 
  117: init_per_testcase(CaseName, Config) ->
  118:     escalus:init_per_testcase(CaseName, Config).
  119: 
  120: end_per_testcase(CaseName, Config) ->
  121:     escalus:end_per_testcase(CaseName, Config).
  122: 
  123: %%--------------------------------------------------------------------
  124: %% Tests
  125: %%--------------------------------------------------------------------
  126: 
  127: %% In terms of server response to blocked communication, we strive to implement the following
  128: %% as defined in XEP-0016:
  129: %% If someone I block tries to communicate with me, then the following rules apply:
  130: %%  * For presence stanzas (including notifications, subscriptions, and probes), the server MUST NOT respond and MUST NOT
  131: %%    return an error.
  132: %%  * For message stanzas, the server SHOULD return an error, which SHOULD be <service-unavailable/>.
  133: %%  * For IQ stanzas of type "get" or "set", the server MUST return an error, which SHOULD be <service-unavailable/>. IQ
  134: %%    stanzas of other types MUST be silently dropped by the server.
  135: %% If I want to communicate with someone I block, then:
  136: %%  * If the user attempts to send an outbound stanza to a contact and that stanza type is blocked, the user's server MUST
  137: %%    NOT route the stanza to the contact but instead MUST return a <not-acceptable/> error:
  138: 
  139: 
  140: %% TODO:
  141: %% x get all privacy lists
  142: %% x get single privacy list
  143: %%   x that exists
  144: %%   x that doesn't exist (ensure server returns item-not-found)
  145: %%   x request more than one at a time (ensure server returns bad-request)
  146: %% x set new/edit privacy list (ensure server pushes notifications
  147: %%   to all resources)
  148: %% - remove existing list
  149: %%   x remove existing list (ensure server push)
  150: %%   - remove, but check conflict case
  151: %% x manage active list(s)
  152: %%   x activate
  153: %%   x activate nonexistent (ensure item-not-found)
  154: %%   x deactivate by sending empty <active />
  155: %% - manage default list
  156: %%   x set default
  157: %%   - set default, but check the conflict case, i.e.:
  158: %%     "Client attempts to change the default list but that list is in use
  159: %%     by another resource",
  160: %%     !!! ejabberd doesn't support this, bug filed (#7073)
  161: %%   x set nonexistent default list
  162: %%   x use domain's routing, i.e. no default list -> send empty <default />
  163: %%   - set no default list, but check conflict case,
  164: %%     when a resource currently uses the default list
  165: %%
  166: %% TODO later:
  167: %% - big picture:
  168: %%   - blocking can be done on jids, roster groups,
  169: %%     subscription type or globally
  170: %%   - a blocking rule may block one or more of {message, presence-in,
  171: %%     presence-out, iqs} by specifying these as children to the list item
  172: %%     or block all of them, when the item has no children
  173: %% - blocking: messages, presence (in/out), iqs, all
  174: 
  175: discover_support(Config) ->
  176:     escalus:fresh_story(Config, [{alice, 1}], fun(Alice) ->
  177:         Server = escalus_client:server(Alice),
  178:         IqGet = escalus_stanza:disco_info(Server),
  179:         Result = escalus:send_iq_and_wait_for_result(Alice, IqGet),
  180:         escalus:assert(has_feature, [?NS_PRIVACY], Result)
  181:     end).
  182: 
  183: get_all_lists(Config) ->
  184:     escalus:fresh_story(Config, [{alice, 1}], fun(Alice) ->
  185: 
  186:         escalus:send(Alice, escalus_stanza:privacy_get_all()),
  187:         escalus:assert(is_privacy_result, escalus:wait_for_stanza(Alice))
  188: 
  189:         end).
  190: 
  191: get_all_lists_with_active(Config) ->
  192:     escalus:fresh_story(Config, [{alice, 1}, {bob, 1}], fun(Alice, Bob) ->
  193: 
  194:         privacy_helper:set_and_activate(Alice, {<<"deny_client">>, Bob}),
  195: 
  196:         escalus:send(Alice, escalus_stanza:privacy_get_all()),
  197:         escalus:assert(is_privacy_result_with_active, [<<"deny_client">>],
  198:                        escalus:wait_for_stanza(Alice))
  199: 
  200:         end).
  201: 
  202: get_all_lists_with_default(Config) ->
  203:     escalus:fresh_story(Config, [{alice, 1}, {bob, 1}], fun(Alice, Bob) ->
  204: 
  205:         privacy_helper:set_list(Alice, {<<"deny_client">>, Bob}),
  206:         privacy_helper:set_list(Alice, {<<"allow_client">>, Bob}),
  207:         privacy_helper:set_default_list(Alice, <<"allow_client">>),
  208: 
  209:         escalus:send(Alice, escalus_stanza:privacy_get_all()),
  210:         escalus:assert(is_privacy_result_with_default,
  211:                        escalus:wait_for_stanza(Alice))
  212: 
  213:         end).
  214: 
  215: get_nonexistent_list(Config) ->
  216:     escalus:fresh_story(Config, [{alice, 1}], fun(Alice) ->
  217: 
  218:         escalus_client:send(Alice,
  219:             escalus_stanza:privacy_get_lists([<<"public">>])),
  220:         escalus_assert:is_privacy_list_nonexistent_error(
  221:             escalus_client:wait_for_stanza(Alice))
  222: 
  223:         end).
  224: 
  225: get_many_lists(Config) ->
  226:     escalus:fresh_story(Config, [{alice, 1}], fun(Alice) ->
  227: 
  228:         Request = escalus_stanza:privacy_get_lists([<<"public">>, <<"private">>]),
  229:         escalus_client:send(Alice, Request),
  230:         Response = escalus_client:wait_for_stanza(Alice),
  231:         escalus_assert:is_error(Response, <<"modify">>, <<"bad-request">>)
  232: 
  233:         end).
  234: 
  235: get_existing_list(Config) ->
  236:     escalus:fresh_story(Config, [{alice, 1}, {bob, 1}], fun(Alice, Bob) ->
  237: 
  238:         privacy_helper:set_list(Alice, {<<"deny_client">>, Bob}),
  239: 
  240:         escalus:send(Alice, escalus_stanza:privacy_get_lists([<<"deny_client">>])),
  241:         Response = escalus:wait_for_stanza(Alice),
  242: 
  243:         <<"deny_client">> = exml_query:path(Response, [{element, <<"query">>},
  244:                                                        {element, <<"list">>},
  245:                                                        {attr, <<"name">>}])
  246: 
  247:         end).
  248: 
  249: activate(Config) ->
  250:     escalus:fresh_story(Config, [{alice, 1}, {bob, 1}], fun(Alice, Bob) ->
  251: 
  252:         privacy_helper:set_list(Alice, {<<"deny_client">>, Bob}),
  253: 
  254:         Request = escalus_stanza:privacy_activate(<<"deny_client">>),
  255:         escalus_client:send(Alice, Request),
  256: 
  257:         Response = escalus_client:wait_for_stanza(Alice),
  258:         escalus:assert(is_iq_result, Response)
  259: 
  260:         end).
  261: 
  262: activate_nonexistent(Config) ->
  263:     escalus:fresh_story(Config, [{alice, 1}], fun(Alice) ->
  264: 
  265:         Request = escalus_stanza:privacy_activate(<<"some_list">>),
  266:         escalus_client:send(Alice, Request),
  267: 
  268:         Response = escalus_client:wait_for_stanza(Alice),
  269:         escalus:assert(is_error, [<<"cancel">>, <<"item-not-found">>], Response)
  270: 
  271:         end).
  272: 
  273: deactivate(Config) ->
  274:     escalus:fresh_story(Config, [{alice, 1}], fun(Alice) ->
  275: 
  276:         Request = escalus_stanza:privacy_deactivate(),
  277:         escalus_client:send(Alice, Request),
  278: 
  279:         Response = escalus_client:wait_for_stanza(Alice),
  280:         escalus:assert(is_iq_result, Response)
  281: 
  282:         end).
  283: 
  284: default(Config) ->
  285:     escalus:fresh_story(Config, [{alice, 1}, {bob, 1}], fun(Alice, Bob) ->
  286: 
  287:         privacy_helper:set_list(Alice, {<<"deny_client">>, Bob}),
  288: 
  289:         Request = escalus_stanza:privacy_set_default(<<"deny_client">>),
  290:         escalus_client:send(Alice, Request),
  291: 
  292:         Response = escalus_client:wait_for_stanza(Alice),
  293:         escalus:assert(is_iq_result, Response)
  294: 
  295:         end).
  296: 
  297: default_conflict(Config) ->
  298:     escalus:fresh_story(Config, [{alice, 2}, {bob, 1}], fun(Alice, Alice2, Bob) ->
  299: 
  300:         %% testcase setup
  301:         %% setup list on server
  302:         privacy_helper:send_set_list(Alice, {<<"deny_client">>, Bob}),
  303:         privacy_helper:send_set_list(Alice, {<<"allow_client">>, Bob}),
  304:         %% skip responses
  305:         escalus_client:wait_for_stanzas(Alice, 4),
  306:         %% make a default list for Alice2
  307:         R1 = escalus_stanza:privacy_set_default(Alice2, <<"deny_client">>),
  308:         escalus_client:send(Alice2, R1),
  309:         escalus:assert_many([is_privacy_set, is_privacy_set, is_iq_result],
  310:                             escalus_client:wait_for_stanzas(Alice2, 3)),
  311:         %% setup done
  312: 
  313:         Request = escalus_stanza:privacy_set_default(<<"allow_client">>),
  314:         escalus_client:send(Alice, Request),
  315: 
  316:         Response = escalus_client:wait_for_stanza(Alice),
  317:         %% TODO: should fail on this (result) and receive error
  318:         %%       this is a bug and was filed to the esl redmine as Bug #7073
  319:         %true = exmpp_iq:is_result(Response),
  320:         %% but this should pass just fine
  321:         escalus:assert(is_error, [<<"cancel">>, <<"conflict">>], Response)
  322: 
  323:         end).
  324: 
  325: default_nonexistent(Config) ->
  326:     escalus:fresh_story(Config, [{alice, 1}], fun(Alice) ->
  327: 
  328:         Request = escalus_stanza:privacy_set_default(<<"some_list">>),
  329:         escalus_client:send(Alice, Request),
  330: 
  331:         Response = escalus_client:wait_for_stanza(Alice),
  332:         escalus_assert:is_error(Response, <<"cancel">>, <<"item-not-found">>)
  333: 
  334:         end).
  335: 
  336: no_default(Config) ->
  337:     escalus:fresh_story(Config, [{alice, 1}], fun(Alice) ->
  338: 
  339:         Request = escalus_stanza:privacy_no_default(),
  340:         escalus_client:send(Alice, Request),
  341: 
  342:         Response = escalus_client:wait_for_stanza(Alice),
  343:         escalus:assert(is_iq_result, Response)
  344: 
  345:         end).
  346: 
  347: set_list(Config) ->
  348:     escalus:fresh_story(Config, [{alice, 3}, {bob, 1}], fun(Alice, Alice2, Alice3, Bob) ->
  349: 
  350:         privacy_helper:send_set_list(Alice, {<<"deny_client">>, Bob}),
  351: 
  352:         %% Verify that original Alice gets iq result and notification.
  353:         %% It's a bit quirky as these come in undefined order
  354:         %% (actually, they always came with 'push' first and then 'result',
  355:         %% but I suppose it's not mandatory).
  356:         AliceResponses = escalus_client:wait_for_stanzas(Alice, 2),
  357:         escalus:assert_many([
  358:             fun escalus_pred:is_iq_result/1,
  359:             fun privacy_helper:is_privacy_list_push/1
  360:         ], AliceResponses),
  361: 
  362:         %% Verify that other resources also get the push.
  363:         escalus:assert(fun privacy_helper:is_privacy_list_push/1,
  364:                        escalus:wait_for_stanza(Alice2)),
  365:         escalus:assert(fun privacy_helper:is_privacy_list_push/1,
  366:                        escalus:wait_for_stanza(Alice3))
  367: 
  368:         %% All in all, the spec requires the resources to reply
  369:         %% (as to every iq), but it's omitted here.
  370: 
  371:         end).
  372: 
  373: remove_list(Config) ->
  374:     escalus:fresh_story(Config, [{alice, 1}, {bob, 1}], fun(Alice, Bob) ->
  375: 
  376:         privacy_helper:send_set_list(Alice, {<<"deny_client">>, Bob}),
  377: 
  378:         %% These are the pushed notification and iq result.
  379:         escalus_client:wait_for_stanzas(Alice, 2),
  380: 
  381:         %% Request list deletion by sending an empty list.
  382:         RemoveRequest = escalus_stanza:privacy_set_list(
  383:                           escalus_stanza:privacy_list(<<"someList">>, [])),
  384:         escalus_client:send(Alice, RemoveRequest),
  385: 
  386:         %% These too are the pushed notification and iq result.
  387:         escalus:assert_many([
  388:             fun privacy_helper:is_privacy_list_push/1,
  389:             is_iq_result
  390:         ], escalus_client:wait_for_stanzas(Alice, 2)),
  391: 
  392:         escalus_client:send(Alice,
  393:             escalus_stanza:privacy_get_lists([<<"someList">>])),
  394: 
  395:         %% Finally ensure that the list doesn't exist anymore.
  396:         escalus_assert:is_privacy_list_nonexistent_error(
  397:             escalus_client:wait_for_stanza(Alice))
  398: 
  399:         end).
  400: 
  401: block_jid_message(Config) ->
  402:     escalus:fresh_story(Config, [{alice, 1}, {bob, 1}], fun(Alice, Bob) ->
  403: 
  404:         %% Alice should receive message
  405:         escalus_client:send(Bob,
  406:             escalus_stanza:chat_to(Alice, <<"Hi! What's your name?">>)),
  407:         escalus_assert:is_chat_message(<<"Hi! What's your name?">>,
  408:             escalus_client:wait_for_stanza(Alice)),
  409: 
  410:         %% set the list on server and make it active
  411:         privacy_helper:set_and_activate(Alice, {<<"deny_client_message">>, Bob}),
  412: 
  413:         %% Alice should NOT receive message, while Bob gets error message
  414:         escalus_client:send(Bob, escalus_stanza:chat_to(Alice, <<"Hi, Alice!">>)),
  415:         privacy_helper:gets_error(Bob, <<"service-unavailable">>),
  416:         timer:sleep(?SLEEP_TIME),
  417:         escalus_assert:has_no_stanzas(Alice),
  418: 
  419:         %% Blocking only applies to incoming messages, so Alice can still send
  420:         %% Bob a message
  421:         %% and Bob gets nothing
  422:         escalus_client:send(Alice, escalus_stanza:chat_to(
  423:                                      Bob, <<"Hi, Bobbb!">>)),
  424:         escalus_assert:is_chat_message(<<"Hi, Bobbb!">>,
  425:                                        escalus_client:wait_for_stanza(Bob))
  426: 
  427:         end).
  428: 
  429: block_group_message(Config) ->
  430:     escalus:fresh_story(Config, [{alice, 1}, {bob, 1}], fun(Alice, Bob) ->
  431: 
  432:         %% Alice should receive message
  433:         escalus_client:send(Bob, escalus_stanza:chat_to(Alice, <<"Hi!">>)),
  434:         escalus_assert:is_chat_message(<<"Hi!">>,
  435:             escalus_client:wait_for_stanza(Alice)),
  436: 
  437:         %% add Bob to Alices' group 'ignored'
  438:         add_sample_contact(Alice, Bob, [<<"ignored">>], <<"Ugly Bastard">>),
  439: 
  440:         %% set the list on server and make it active
  441:         privacy_helper:set_and_activate(Alice, <<"deny_group_message">>),
  442: 
  443:         %% Alice should NOT receive message
  444:         escalus_client:send(Bob, escalus_stanza:chat_to(Alice, <<"Hi, blocked group!">>)),
  445:         timer:sleep(?SLEEP_TIME),
  446:         escalus_assert:has_no_stanzas(Alice),
  447:         privacy_helper:gets_error(Bob, <<"service-unavailable">>)
  448: 
  449:         end).
  450: 
  451: block_subscription_message(Config) ->
  452:     escalus:fresh_story(Config, [{alice, 1}, {bob, 1}], fun(Alice, Bob) ->
  453: 
  454:         %% Alice should receive message
  455:         escalus_client:send(Bob, escalus_stanza:chat_to(Alice, <<"Hi!">>)),
  456:         escalus_assert:is_chat_message(<<"Hi!">>,
  457:             escalus_client:wait_for_stanza(Alice)),
  458: 
  459:         %% Alice sends unsubscribe
  460:         Stanza = escalus_stanza:presence_direct(escalus_utils:get_short_jid(Bob),
  461:                                                 <<"unsubscribe">>),
  462:         escalus_client:send(Alice, Stanza),
  463: 
  464:         %% set the list on server and make it active
  465:         privacy_helper:set_and_activate(Alice, <<"deny_unsubscribed_message">>),
  466: 
  467:         %% Alice should NOT receive message
  468:         escalus_client:send(Bob, escalus_stanza:chat_to(Alice, <<"Hi!">>)),
  469:         timer:sleep(?SLEEP_TIME),
  470:         escalus_assert:has_no_stanzas(Alice),
  471:         privacy_helper:gets_error(Bob, <<"service-unavailable">>)
  472: 
  473:         end).
  474: 
  475: allow_subscription_to_from_message(Config) ->
  476:     escalus:fresh_story(Config, [{alice, 1}, {bob, 1}], fun(Alice, Bob) ->
  477:         %% deny all message but not from subscribed "to"
  478:         privacy_helper:set_and_activate(Alice, <<"deny_all_message_but_subscription_to">>),
  479: 
  480:         %% deny all message but not from subscribed "from"
  481:         privacy_helper:set_and_activate(Bob, <<"deny_all_message_but_subscription_from">>),
  482: 
  483:         %% Bob and Alice cannot sent to each other now
  484:         escalus_client:send(Bob, escalus_stanza:chat_to(Alice, <<"Hi, Alice XYZ!">>)),
  485:         escalus_client:send(Alice, escalus_stanza:chat_to(Bob, <<"Hi, Bob XYZ!">>)),
  486: 
  487:         ct:sleep(?SLEEP_TIME),
  488:         %% they received just rejection msgs
  489:         privacy_helper:gets_error(Alice, <<"service-unavailable">>),
  490:         escalus_assert:has_no_stanzas(Alice),
  491:         privacy_helper:gets_error(Bob, <<"service-unavailable">>),
  492:         escalus_assert:has_no_stanzas(Bob),
  493: 
  494:         %% Alice subscribes to Bob
  495:         subscribe_from_to(Alice, Bob, false),
  496: 
  497:         %% Now Alice is subscribed "to" Bob
  498:         %% And Bob is subscribed "from" Alice
  499: 
  500:         escalus_client:send(Bob, escalus_stanza:chat_to(Alice, <<"Hi, Alice XYZ!">>)),
  501:         escalus_assert:is_chat_message(<<"Hi, Alice XYZ!">>,
  502:                                        escalus_client:wait_for_stanza(Alice)),
  503: 
  504:         escalus_client:send(Alice, escalus_stanza:chat_to(Bob, <<"Hi, Bob XYZ!">>)),
  505:         escalus_assert:is_chat_message(<<"Hi, Bob XYZ!">>,
  506:                                        escalus_client:wait_for_stanza(Bob))
  507: 
  508:     end).
  509: 
  510: allow_subscription_both_message(Config) ->
  511:     escalus:fresh_story(Config, [{alice, 1}, {bob, 1}], fun(Alice, Bob) ->
  512: 
  513:         %% Alice subscribes to Bob
  514:         subscribe_from_to(Alice, Bob, false),
  515: 
  516:         %% deny all message but not from subscribed "to"
  517:         privacy_helper:set_and_activate(Alice, <<"deny_all_message_but_subscription_both">>),
  518: 
  519:         %% deny all message but not from subscribed "from"
  520:         privacy_helper:set_and_activate(Bob, <<"deny_all_message_but_subscription_both">>),
  521: 
  522:         %% Bob and Alice cannot write to each other now
  523:         %% Even though they are in subscription "to" and "from" respectively
  524:         escalus_client:send(Bob, escalus_stanza:chat_to(
  525:                                    Alice, <<"Hi, Alice XYZ!">>)),
  526:         escalus_client:send(Alice, escalus_stanza:chat_to(
  527:                                      Bob, <<"Hi, Bob XYZ 1!">>)),
  528: 
  529:         privacy_helper:gets_error(Alice, <<"service-unavailable">>),
  530:         privacy_helper:gets_error(Bob, <<"service-unavailable">>),
  531:         escalus_assert:has_no_stanzas(Alice),
  532:         escalus_assert:has_no_stanzas(Bob),
  533: 
  534:         %% Bob subscribes to Alice
  535:         subscribe_from_to(Bob, Alice, true),
  536: 
  537:         %% Now their subscription is in state "both"
  538:         escalus_client:send(Bob, escalus_stanza:chat_to(Alice, <<"Hi, Alice XYZ!">>)),
  539:         escalus_assert:is_chat_message(<<"Hi, Alice XYZ!">>,
  540:                                        escalus_client:wait_for_stanza(Alice)),
  541: 
  542:         escalus_client:send(Alice, escalus_stanza:chat_to(Bob, <<"Hi, Bob XYZ! 2">>)),
  543:         escalus_assert:is_chat_message(<<"Hi, Bob XYZ! 2">>,
  544:                                        escalus_client:wait_for_stanza(Bob))
  545: 
  546:     end).
  547: 
  548: block_all_message(Config) ->
  549:     escalus:fresh_story(Config, [{alice, 1}, {bob, 1}], fun(Alice, Bob) ->
  550: 
  551:         %% Alice should receive message
  552:         escalus_client:send(Bob, escalus_stanza:chat_to(Alice, <<"Hi!">>)),
  553:         escalus_assert:is_chat_message(<<"Hi!">>,
  554:                                        escalus_client:wait_for_stanza(Alice)),
  555: 
  556:         %% set the list on server and make it active
  557:         privacy_helper:set_and_activate(Alice, <<"deny_all_message">>),
  558: 
  559:         %% Alice should NOT receive message
  560:         escalus_client:send(Bob, escalus_stanza:chat_to(Alice, <<"Hi!">>)),
  561:         timer:sleep(?SLEEP_TIME),
  562:         escalus_assert:has_no_stanzas(Alice),
  563:         privacy_helper:gets_error(Bob, <<"service-unavailable">>)
  564: 
  565:         end).
  566: 
  567: block_jid_presence_in(Config) ->
  568:     escalus:fresh_story(Config, [{alice, 1}, {bob, 1}], fun(Alice, Bob) ->
  569: 
  570:         %% Alice should receive presence in
  571:         Presence1 =  escalus_stanza:presence_direct(escalus_utils:get_short_jid(Alice),
  572:                                                     <<"available">>),
  573:         escalus_client:send(Bob, Presence1),
  574:         Received = escalus_client:wait_for_stanza(Alice),
  575:         escalus:assert(is_presence, Received),
  576:         escalus_assert:is_stanza_from(Bob, Received),
  577: 
  578:         privacy_helper:set_and_activate(Alice, {<<"deny_client_presence_in">>, Bob}),
  579: 
  580:         %% Alice should NOT receive presence in
  581:         Presence2 = escalus_stanza:presence_direct(escalus_utils:get_short_jid(Alice),
  582:                                                    <<"available">>),
  583:         escalus_client:send(Bob, Presence2),
  584:         timer:sleep(?SLEEP_TIME),
  585:         escalus_assert:has_no_stanzas(Alice),
  586:         %% and Bob should NOT receive any response
  587:         escalus_assert:has_no_stanzas(Bob)
  588: 
  589: 
  590:         end).
  591: 
  592: block_jid_presence_out(Config) ->
  593:     escalus:fresh_story(Config, [{alice, 1}, {bob, 1}], fun(Alice, Bob) ->
  594: 
  595:         BobBareJID = escalus_utils:get_short_jid(Bob),
  596: 
  597:         %% Bob should receive presence in
  598:         Presence1 = escalus_stanza:presence_direct(BobBareJID, <<"available">>),
  599:         escalus_client:send(Alice, Presence1),
  600: 
  601:         Received = escalus_client:wait_for_stanza(Bob),
  602:         escalus:assert(is_presence, Received),
  603:         escalus_assert:is_stanza_from(Alice, Received),
  604: 
  605:         privacy_helper:set_and_activate(Alice, {<<"deny_client_presence_out">>, Bob}),
  606: 
  607:         %% Bob should NOT receive presence in
  608:         Presence2 = escalus_stanza:presence_direct(BobBareJID, <<"available">>),
  609:         escalus_client:send(Alice, Presence2),
  610: 
  611:         %% Alice gets an error back from mod_privacy
  612:         ErrorPresence = escalus_client:wait_for_stanza(Alice),
  613:         escalus:assert(is_presence_with_type, [<<"error">>], ErrorPresence),
  614: 
  615:         timer:sleep(?SLEEP_TIME),
  616:         escalus_assert:has_no_stanzas(Bob)
  617: 
  618:         end).
  619: 
  620: version_iq(Type, From, To) ->
  621:     Req = escalus_stanza:iq(Type, [escalus_stanza:query_el(<<"jabber:iq:version">>, [])]),
  622:     Req1 = escalus_stanza:to(Req, To),
  623:     Req2= escalus_stanza:from(Req1, From),
  624:     Req2.
  625: 
  626: iq_reply_doesnt_crash_user_process(Config) ->
  627:     escalus:fresh_story(Config, [{alice, 1}, {bob, 1}], fun(Alice, Bob) ->
  628: 
  629:         QueryWithPrivacyNS = escalus_stanza:query_el(?NS_PRIVACY, []),
  630:         %% Send IQ reply with privacy ns
  631:         %% Send message to check user process still alive
  632:         privacy_helper:does_user_process_crash(Alice,
  633:             Bob,
  634:             <<"error">>,
  635:             QueryWithPrivacyNS,
  636:             <<"Hello, Bob">>),
  637: 
  638:         privacy_helper:does_user_process_crash(Bob,
  639:             Alice,
  640:             <<"result">>,
  641:             QueryWithPrivacyNS,
  642:             <<"Hello, Alice">>)
  643:     end).
  644: 
  645: block_jid_iq(Config) ->
  646:     escalus:fresh_story(Config, [{alice, 1}, {bob, 1}], fun(Alice, Bob) ->
  647: 
  648:         LServer = escalus_utils:get_server(Bob),
  649:         privacy_helper:set_list(Alice, {<<"deny_server_iq">>, LServer}),
  650:         %% activate it
  651:         Stanza = escalus_stanza:privacy_activate(<<"deny_server_iq">>),
  652:         escalus_client:send(Alice, Stanza),
  653:         timer:sleep(500), %% we must let it sink in
  654: 
  655:         %% bob queries for version and gets an error, Alice doesn't receive the query
  656:         escalus_client:send(Bob, version_iq(<<"get">>, Bob, Alice)),
  657:         timer:sleep(?SLEEP_TIME),
  658:         escalus_assert:has_no_stanzas(Alice),
  659:         privacy_helper:gets_error(Bob, <<"service-unavailable">>),
  660:         %% this stanza does not make much sense, but is routed and rejected correctly
  661:         escalus_client:send(Bob, version_iq(<<"set">>, Bob, Alice)),
  662:         timer:sleep(?SLEEP_TIME),
  663:         escalus_assert:has_no_stanzas(Alice),
  664:         privacy_helper:gets_error(Bob, <<"service-unavailable">>),
  665:         %% but another type, like result, is silently dropped
  666:         escalus_client:send(Bob, version_iq(<<"result">>, Bob, Alice)),
  667:         timer:sleep(?SLEEP_TIME),
  668:         escalus_assert:has_no_stanzas(Alice),
  669:         escalus_assert:has_no_stanzas(Bob)
  670: 
  671:         end).
  672: 
  673: block_jid_all(Config) ->
  674:     escalus:fresh_story(Config, [{alice, 1}, {bob, 1}], fun(Alice, Bob) ->
  675: 
  676:         privacy_helper:set_list(Alice, {<<"deny_jid_all">>, Bob}),
  677: 
  678:         %% Alice blocks Bob
  679:         Stanza = escalus_stanza:privacy_activate(<<"deny_jid_all">>),
  680:         escalus_client:send(Alice, Stanza),
  681: 
  682:         %% IQ response is blocked;
  683:         %% do magic wait for the request to take effect
  684:         timer:sleep(200),
  685: 
  686:         %% From now on nothing whatsoever sent by Bob should reach Alice.
  687: 
  688:         %% Alice should NOT receive message, Bob receives err msg
  689:         escalus_client:send(Bob, escalus_stanza:chat_to(Alice, <<"Hi!">>)),
  690:         privacy_helper:gets_error(Bob, <<"service-unavailable">>),
  691: 
  692:         %% Alice should NOT receive presence-in from Bob, no err msg
  693:         AliceBareJID = escalus_utils:get_short_jid(Alice),
  694:         Presence1 = escalus_stanza:presence_direct(AliceBareJID, <<"available">>),
  695:         escalus_client:send(Bob, Presence1),
  696:         timer:sleep(?SLEEP_TIME),
  697:         escalus_assert:has_no_stanzas(Bob),
  698: 
  699:         %% Bob should NOT receive presence-in from Alice, Alice receives err msg
  700:         BobBareJID = escalus_utils:get_short_jid(Bob),
  701:         Presence2 = escalus_stanza:presence_direct(BobBareJID, <<"available">>),
  702:         escalus_client:send(Alice, Presence2),
  703:         timer:sleep(?SLEEP_TIME),
  704:         privacy_helper:gets_error(Alice, <<"not-acceptable">>),
  705: 
  706:         %% Just set the toy list and en~sure that only
  707:         %% the notification push comes back.
  708:         privacy_helper:send_set_list(Alice, {<<"deny_client">>, Bob}),
  709: 
  710:         %% verify
  711:         timer:sleep(?SLEEP_TIME),
  712:         %% ...that nothing else reached Bob
  713:         escalus_assert:has_no_stanzas(Bob),
  714:         %% ...that Alice got a privacy push
  715:         Responses = escalus_client:wait_for_stanza(Alice),
  716:         escalus:assert(fun privacy_helper:is_privacy_list_push/1, Responses),
  717:         %% and Alice didn't get anything else
  718:         escalus_assert:has_no_stanzas(Alice)
  719: 
  720:         end).
  721: 
  722: block_jid_message_but_not_presence(Config) ->
  723:     escalus:fresh_story(Config, [{alice, 1}, {bob, 1}], fun(Alice, Bob) ->
  724: 
  725:         %% Alice should receive message
  726:         Msg =  escalus_stanza:chat_to(Alice, <<"Hi! What's your name?">>),
  727:         escalus_client:send(Bob, Msg),
  728:         escalus_assert:is_chat_message(<<"Hi! What's your name?">>,
  729:                                        escalus_client:wait_for_stanza(Alice)),
  730: 
  731:         %% set the list on server and make it active
  732:         privacy_helper:set_and_activate(Alice, {<<"deny_client_message">>, Bob}),
  733: 
  734:         %% Alice should NOT receive message
  735:         escalus_client:send(Bob, escalus_stanza:chat_to(Alice, <<"Hi, Alice!">>)),
  736:         timer:sleep(?SLEEP_TIME),
  737:         escalus_assert:has_no_stanzas(Alice),
  738:         privacy_helper:gets_error(Bob, <<"service-unavailable">>),
  739: 
  740:         %% ...but should receive presence in
  741:         escalus_client:send(Bob,
  742:                             escalus_stanza:presence_direct(Alice, <<"available">>)),
  743:         Received = escalus_client:wait_for_stanza(Alice),
  744:         escalus:assert(is_presence, Received),
  745:         escalus_assert:is_stanza_from(Bob, Received)
  746: 
  747:         end).
  748: 
  749: newly_blocked_presense_jid_by_new_list(Config) ->
  750:     escalus:fresh_story(Config, [{alice, 1}, {bob, 1}], fun(Alice, Bob) ->
  751:         add_sample_contact(Alice, Bob, [<<"My Friends">>], <<"Bobbie">>),
  752:         subscribe(Bob, Alice),
  753: 
  754:         %% Alice gets notification that a roster contact is now subscribed
  755:         escalus:assert(is_roster_set, escalus_client:wait_for_stanza(Alice)),
  756: 
  757:         %% Bob should receive presence in
  758:         Presence = escalus_stanza:presence_direct(escalus_client:short_jid(Bob),
  759:                                                   <<"available">>),
  760:         escalus_client:send(Alice, Presence),
  761:         Received = escalus_client:wait_for_stanza(Bob),
  762:         escalus:assert(is_presence, Received),
  763:         escalus_assert:is_stanza_from(Alice, Received),
  764: 
  765:         privacy_helper:set_list(
  766:           Alice, <<"deny_bob_presence_out">>,
  767:           [escalus_stanza:privacy_list_jid_item(<<"1">>, <<"deny">>,
  768:                                                 escalus_client:short_jid(Bob),
  769:                                                 [<<"presence-out">>])]),
  770:         privacy_helper:activate_list(Alice, <<"deny_bob_presence_out">>),
  771: 
  772:         %% Bob should receive unavailable, per XEP-0016 2.11
  773:         Received2 = escalus_client:wait_for_stanza(Bob),
  774:         escalus:assert(is_presence_with_type, [<<"unavailable">>], Received2),
  775:         escalus_assert:is_stanza_from(Alice, Received2)
  776: 
  777:         end).
  778: 
  779: newly_blocked_presense_jid_by_list_change(Config) ->
  780:     escalus:fresh_story(Config, [{alice, 1}, {bob, 1}], fun(Alice, Bob) ->
  781:         add_sample_contact(Alice, Bob, [<<"My Friends">>], <<"Bobbie">>),
  782:         subscribe(Bob, Alice),
  783: 
  784:         %% Alice gets notification that a roster contact is now subscribed
  785:         escalus:assert(is_roster_set, escalus_client:wait_for_stanza(Alice)),
  786: 
  787:         %% Alice sets up an initially empty privacy list
  788:         privacy_helper:set_and_activate(Alice, <<"noop_list">>),
  789: 
  790:         %% Bob should receive presence in
  791:         escalus_client:send(Alice,
  792:             escalus_stanza:presence_direct(Bob, <<"available">>)),
  793:         Received = escalus_client:wait_for_stanza(Bob),
  794:         escalus:assert(is_presence, Received),
  795:         escalus_assert:is_stanza_from(Alice, Received),
  796: 
  797:         %% Alice now adds Bob to her currently active privacy list
  798:         privacy_helper:set_list(
  799:           Alice, <<"noop_list">>,
  800:           [escalus_stanza:privacy_list_jid_item(<<"1">>, <<"deny">>,
  801:                                                 escalus_client:short_jid(Bob),
  802:                                                 [<<"presence-out">>])]),
  803: 
  804:         %% Bob should receive unavailable, per XEP-0016 2.11
  805:         Received2 = escalus_client:wait_for_stanza(Bob),
  806:         escalus:assert(is_presence_with_type, [<<"unavailable">>], Received2),
  807:         escalus_assert:is_stanza_from(Alice, Received2)
  808: 
  809:         end).
  810: 
  811: newly_blocked_presence_not_notify_self(Config) ->
  812:     escalus:fresh_story(Config, [{alice, 1}], fun(Alice) ->
  813:         %% Alice sets up an initially empty privacy list
  814:         privacy_helper:set_and_activate(Alice,
  815:                                         <<"deny_not_both_presence_out">>),
  816: 
  817:         %% Alice should not receive an 'unavailable' because she's not a
  818:         %% contact of herself.
  819:         timer:sleep(?SLEEP_TIME),
  820:         escalus_assert:has_no_stanzas(Alice)
  821: 
  822:         end).
  823: 
  824: %%-----------------------------------------------------------------
  825: %% Helpers
  826: %%-----------------------------------------------------------------
  827: 
  828: add_sample_contact(Who, Whom, Groups, Nick) ->
  829:     escalus_client:send(Who,
  830:                         escalus_stanza:roster_add_contact(Whom,
  831:                                                           Groups,
  832:                                                           Nick)),
  833:     Received = escalus_client:wait_for_stanza(Who),
  834:     escalus_assert:is_roster_set(Received),
  835:     escalus_client:send(Who, escalus_stanza:iq_result(Received)),
  836:     escalus:assert(is_iq_result, escalus:wait_for_stanza(Who)).
  837: 
  838: subscribe(Who, Whom) ->
  839:     % 'Who' sends a subscribe request to 'Whom'
  840:     escalus:send(Who, escalus_stanza:presence_direct(
  841:                         escalus_client:short_jid(Whom), <<"subscribe">>)),
  842:     PushReq = escalus:wait_for_stanza(Who),
  843:     escalus:assert(is_roster_set, PushReq),
  844:     escalus:send(Who, escalus_stanza:iq_result(PushReq)),
  845: 
  846:     %% 'Whom' receives subscription request
  847:     Received = escalus:wait_for_stanza(Whom),
  848:     escalus:assert(is_presence_with_type, [<<"subscribe">>], Received),
  849: 
  850:     %% 'Whom' adds new contact to their roster
  851:     escalus:send(Whom, escalus_stanza:roster_add_contact(Who,
  852:                                                         [<<"enemies">>],
  853:                                                         <<"Enemy1">>)),
  854:     PushReq2 = escalus:wait_for_stanza(Whom),
  855:     escalus:assert(is_roster_set, PushReq2),
  856:     escalus:send(Whom, escalus_stanza:iq_result(PushReq2)),
  857:     escalus:assert(is_iq_result, escalus:wait_for_stanza(Whom)),
  858: 
  859:     %% 'Whom' sends subscribed presence
  860:     escalus:send(Whom, escalus_stanza:presence_direct(
  861:                          escalus_client:short_jid(Who), <<"subscribed">>)),
  862: 
  863:     %% 'Who' receives subscribed
  864:     Stanzas = escalus:wait_for_stanzas(Who, 2),
  865: 
  866:     check_subscription_stanzas(Stanzas, <<"subscribed">>),
  867:     escalus:assert(is_presence, escalus:wait_for_stanza(Who)).
  868: 
  869: check_subscription_stanzas(Stanzas, Type) ->
  870:     IsPresWithType = fun(S) ->
  871:                          escalus_pred:is_presence_with_type(Type, S)
  872:                      end,
  873:     escalus:assert_many([is_roster_set, IsPresWithType], Stanzas).
  874: 
  875: subscribe_from_to(From, To, IsSecondSubscription) ->
  876:     %% From subscribes to To
  877:     ToBareJid = escalus_utils:get_short_jid(To),
  878:     SubStanza = escalus_stanza:presence_direct(ToBareJid, <<"subscribe">>),
  879:     escalus_client:send(From, SubStanza),
  880:     PushReq = escalus_client:wait_for_stanza(From),
  881:     escalus:assert(is_roster_set, PushReq),
  882:     Received = escalus_client:wait_for_stanza(To),
  883:     %% To accepts From
  884:     FromBareJid = escalus_utils:get_short_jid(From),
  885:     SubConfirmStanza = escalus_stanza:presence_direct(FromBareJid, <<"subscribed">>),
  886:     escalus_client:send(To, SubConfirmStanza),
  887:     case IsSecondSubscription of
  888:         true ->
  889:             escalus:assert(is_roster_set, Received),
  890:             escalus_client:wait_for_stanzas(To, 2);
  891:         false ->
  892:             escalus:assert(is_presence_with_type, [<<"subscribe">>], Received),
  893:             escalus_client:wait_for_stanza(To)
  894:     end,
  895:     escalus_client:wait_for_stanzas(From, 3).