1: -module(gdpr_SUITE). 2: 3: %% Tests for features related to GDPR compliance. 4: 5: -include_lib("common_test/include/ct.hrl"). 6: -include_lib("escalus/include/escalus.hrl"). 7: -include_lib("exml/include/exml.hrl"). 8: -include_lib("eunit/include/eunit.hrl"). 9: -include("muc_light.hrl"). 10: 11: -export([suite/0, all/0, groups/0]). 12: -export([init_per_suite/1, end_per_suite/1]). 13: -export([init_per_group/2, end_per_group/2]). 14: -export([init_per_testcase/2, end_per_testcase/2]). 15: -export([ 16: retrieve_vcard/1, 17: remove_vcard/1, 18: remove_private/1, 19: remove_multiple_private_xmls/1, 20: dont_remove_other_user_private_xml/1, 21: retrieve_roster/1, 22: retrieve_mam_pm/1, 23: retrieve_mam_muc/1, 24: retrieve_mam_muc_private_msg/1, 25: retrieve_mam_muc_store_pm/1, 26: remove_mam_pm/1, 27: retrieve_mam_muc_light/1, 28: retrieve_mam_pm_and_muc_light_interfere/1, 29: retrieve_mam_pm_and_muc_light_dont_interfere/1, 30: remove_roster/1, 31: retrieve_offline/1, 32: remove_offline/1, 33: retrieve_pubsub_payloads/1, 34: retrieve_created_pubsub_nodes/1, 35: retrieve_all_pubsub_data/1, 36: dont_retrieve_other_user_pubsub_payload/1, 37: retrieve_pubsub_subscriptions/1, 38: retrieve_private_xml/1, 39: dont_retrieve_other_user_private_xml/1, 40: retrieve_multiple_private_xmls/1, 41: retrieve_inbox/1, 42: remove_inbox/1, 43: retrieve_inbox_for_multiple_messages/1, 44: retrieve_inbox_muclight/1, 45: retrieve_inbox_muc/1, 46: remove_inbox_muclight/1, 47: remove_inbox_muc/1, 48: retrieve_logs/1, 49: remove_pubsub_all_data/1, 50: remove_pubsub_dont_remove_node_when_only_publisher/1, 51: remove_pubsub_subscriptions/1, 52: remove_pubsub_dont_remove_flat_pubsub_node/1, 53: remove_pubsub_push_node/1, 54: remove_pubsub_pep_node/1 55: ]). 56: 57: -import(mongooseimctl_helper, [mongooseimctl/3]). 58: -import(distributed_helper, [mim/0, subhost_pattern/1, rpc/4]). 59: -import(muc_light_helper, [room_bin_jid/1]). 60: -import(domain_helper, [host_type/0]). 61: -import(config_parser_helper, [default_mod_config/1, mod_config/2]). 62: -import(graphql_helper, [execute_command/4, get_ok_value/2]). 63: 64: -define(ROOM, <<"tt1">>). 65: 66: %% ------------------------------------------------------------- 67: %% Common Test stuff 68: %% ------------------------------------------------------------- 69: 70: suite() -> 71: escalus:suite(). 72: 73: all() -> 74: [ 75: {group, retrieve_personal_data}, 76: {group, remove_personal_data} 77: ]. 78: 79: groups() -> 80: [ 81: {retrieve_personal_data, [], [ 82: retrieve_vcard, 83: retrieve_roster, 84: retrieve_offline, 85: retrieve_inbox, 86: retrieve_logs, 87: {group, retrieve_personal_data_pubsub}, 88: {group, retrieve_personal_data_private_xml}, 89: {group, retrieve_personal_data_mam}, 90: {group, retrieve_personal_data_inbox} 91: ]}, 92: {retrieve_personal_data_inbox, [],[ 93: retrieve_inbox, 94: retrieve_inbox_for_multiple_messages, 95: retrieve_inbox_muclight, 96: retrieve_inbox_muc 97: ]}, 98: {retrieve_personal_data_pubsub, [], [ 99: retrieve_pubsub_payloads, 100: dont_retrieve_other_user_pubsub_payload, 101: retrieve_pubsub_subscriptions, 102: retrieve_created_pubsub_nodes, 103: retrieve_all_pubsub_data 104: ]}, 105: {retrieve_personal_data_private_xml, [], [ 106: retrieve_private_xml, 107: dont_retrieve_other_user_private_xml, 108: retrieve_multiple_private_xmls 109: ]}, 110: {retrieve_personal_data_mam, [], [ 111: {group, retrieve_personal_data_mam_rdbms}, 112: {group, retrieve_personal_data_mam_cassandra}, 113: {group, retrieve_personal_data_mam_elasticsearch} 114: ]}, 115: {retrieve_personal_data_mam_rdbms, [], all_mam_testcases()}, 116: {retrieve_personal_data_mam_cassandra, [], all_mam_testcases()}, 117: {retrieve_personal_data_mam_elasticsearch, [], all_mam_testcases()}, 118: {remove_personal_data, [], removal_testcases()}, 119: {remove_personal_data_inbox, [], [remove_inbox, remove_inbox_muclight, remove_inbox_muc]}, 120: {remove_personal_data_mam, [], [ 121: {group, remove_personal_data_mam_rdbms}, 122: {group, remove_personal_data_mam_cassandra}, 123: {group, remove_personal_data_mam_elasticsearch} 124: ]}, 125: {remove_personal_data_mam_rdbms, [], mam_removal_testcases()}, 126: {remove_personal_data_mam_cassandra, [], mam_removal_testcases()}, 127: {remove_personal_data_mam_elasticsearch, [], mam_removal_testcases()}, 128: {remove_personal_data_pubsub, [], [ 129: remove_pubsub_subscriptions, 130: remove_pubsub_dont_remove_node_when_only_publisher, 131: remove_pubsub_dont_remove_flat_pubsub_node, 132: remove_pubsub_push_node, 133: remove_pubsub_pep_node, 134: remove_pubsub_all_data 135: ]} 136: ]. 137: 138: removal_testcases() -> 139: [ 140: remove_vcard, 141: remove_roster, 142: remove_offline, 143: remove_private, 144: remove_multiple_private_xmls, 145: dont_remove_other_user_private_xml, 146: {group, remove_personal_data_inbox}, 147: {group, remove_personal_data_pubsub}, 148: {group, remove_personal_data_mam} 149: ]. 150: 151: mam_removal_testcases() -> 152: [ 153: remove_mam_pm 154: ]. 155: 156: 157: mam_testcases() -> 158: [ 159: retrieve_mam_pm, 160: retrieve_mam_muc_light, 161: retrieve_mam_pm_and_muc_light_interfere, 162: retrieve_mam_pm_and_muc_light_dont_interfere 163: ]. 164: 165: all_mam_testcases() -> 166: [ 167: retrieve_mam_muc, 168: retrieve_mam_muc_private_msg, 169: retrieve_mam_muc_store_pm 170: | mam_testcases() 171: ]. 172: 173: init_per_suite(Config) -> 174: #{node := MimNode} = distributed_helper:mim(), 175: Config1 = [{{ejabberd_cwd, MimNode}, get_mim_cwd()} | dynamic_modules:save_modules(host_type(), Config)], 176: muc_helper:load_muc(), 177: Config2 = graphql_helper:init_admin_handler(Config1), 178: escalus:init_per_suite(Config2). 179: 180: end_per_suite(Config) -> 181: delete_files(), 182: escalus_fresh:clean(), 183: graphql_helper:clean(), 184: dynamic_modules:restore_modules(Config), 185: escalus:end_per_suite(Config). 186: 187: init_per_group(GN, Config) when GN =:= remove_personal_data_mam_rdbms; 188: GN =:= retrieve_personal_data_mam_rdbms -> 189: try_backend_for_mam(Config, rdbms); 190: init_per_group(GN, Config) when GN =:= retrieve_personal_data_pubsub; 191: GN =:= remove_personal_data_pubsub -> 192: [{group, GN} | Config]; 193: init_per_group(GN, Config) when GN =:= retrieve_personal_data_mam_cassandra; 194: GN =:= remove_personal_data_mam_cassandra-> 195: try_backend_for_mam(Config, cassandra); 196: init_per_group(GN, Config) when GN =:= retrieve_personal_data_mam_elasticsearch; 197: GN =:= remove_personal_data_mam_elasticsearch -> 198: try_backend_for_mam(Config, elasticsearch); 199: init_per_group(retrieve_personal_data_inbox = GN, Config) -> 200: init_inbox(GN, Config, muclight); 201: init_per_group(remove_personal_data_inbox = GN, Config) -> 202: init_inbox(GN, Config, muclight); 203: init_per_group(retrieve_personal_data_private_xml, Config) -> 204: private_started(), 205: Config; 206: init_per_group(_GN, Config) -> 207: Config. 208: 209: end_per_group(_GN, Config) -> 210: Config. 211: 212: try_backend_for_mam(Config, Backend) -> 213: case is_backend_enabled(Backend) of 214: true -> [{mam_backend, Backend} | Config]; 215: false -> {skip, backend_is_not_configured} 216: end. 217: 218: is_backend_enabled(rdbms) -> mongoose_helper:is_rdbms_enabled(host_type()); 219: is_backend_enabled(cassandra) -> mam_helper:is_cassandra_enabled(host_type()); 220: is_backend_enabled(elasticsearch) -> mam_helper:is_elasticsearch_enabled(host_type()). 221: 222: 223: init_per_testcase(retrieve_logs = CN, Config) -> 224: case is_mim2_started() of 225: false -> {skip, not_running_in_distributed}; 226: _ -> escalus:init_per_testcase(CN, Config) 227: end; 228: init_per_testcase(CN, Config) when CN =:= remove_offline; 229: CN =:= retrieve_offline -> 230: offline_started(), 231: escalus:init_per_testcase(CN, Config); 232: init_per_testcase(CN, Config) when 233: CN =:= remove_inbox; 234: CN =:= retrieve_inbox; 235: CN =:= remove_inbox_muclight; 236: CN =:= retrieve_inbox_muclight -> 237: Config1 = init_inbox(CN, Config, muclight), 238: Config1; 239: init_per_testcase(CN, Config) when CN =:= retrieve_inbox_muc; 240: CN =:= remove_inbox_muc -> 241: muc_helper:load_muc(), 242: Config0 = init_inbox(CN, Config, muc), 243: Config0; 244: 245: init_per_testcase(retrieve_vcard = CN, Config) -> 246: case vcard_helper:is_vcard_ldap() of 247: true -> 248: {skip, skipped_for_simplicity_for_now}; % TODO: Fix the case for LDAP as well 249: _ -> 250: escalus:init_per_testcase(CN, Config) 251: end; 252: init_per_testcase(remove_vcard = CN, Config) -> 253: case vcard_helper:is_vcard_ldap() of 254: true -> 255: {skip, skipped_for_simplicity_for_now}; % TODO: Fix the case for LDAP as well 256: _ -> 257: vcard_started(), 258: escalus:init_per_testcase(CN, Config) 259: end; 260: init_per_testcase(CN, Config) when CN =:= remove_private; 261: CN =:= dont_remove_other_user_private_xml; 262: CN =:= remove_multiple_private_xmls -> 263: private_started(), 264: escalus:init_per_testcase(CN, Config); 265: 266: init_per_testcase(CN, Config) when CN =:= retrieve_mam_muc; 267: CN =:= retrieve_mam_muc_private_msg; 268: CN =:= retrieve_mam_muc_store_pm; 269: CN =:= retrieve_mam_muc_light; 270: CN =:= retrieve_mam_pm_and_muc_light_interfere; 271: CN =:= retrieve_mam_pm_and_muc_light_dont_interfere; 272: CN =:= retrieve_mam_pm; 273: CN =:= remove_mam_pm -> 274: case proplists:get_value(mam_backend, Config, skip) of 275: skip -> 276: {skip, no_mam_backend_configured}; 277: Backend -> 278: dynamic_modules:restore_modules(Config), 279: RequiredModules = mam_required_modules(CN, Backend), 280: dynamic_modules:ensure_modules(host_type(), RequiredModules), 281: ct:log("required modules: ~p~n", [RequiredModules]), 282: escalus:init_per_testcase(CN, [{mam_modules, RequiredModules} | Config]) 283: end; 284: init_per_testcase(remove_roster = CN, Config) -> 285: roster_started(), 286: escalus:init_per_testcase(CN, Config); 287: init_per_testcase(CN, Config) -> 288: GN = proplists:get_value(group, Config), 289: IsPubSub = lists:member(GN, [retrieve_personal_data_pubsub, remove_personal_data_pubsub]), 290: case IsPubSub of 291: true -> 292: dynamic_modules:ensure_modules(host_type(), pubsub_required_modules()); 293: _ -> 294: ok 295: end, 296: escalus:init_per_testcase(CN, Config). 297: 298: 299: end_per_testcase(CN, Config) when CN =:= retrieve_mam_muc_light; 300: CN =:= retrieve_mam_pm_and_muc_light_interfere; 301: CN =:= retrieve_mam_pm_and_muc_light_dont_interfere -> 302: muc_light_helper:clear_db(host_type()), 303: escalus:end_per_testcase(CN, Config); 304: %% mod_inbox 305: end_per_testcase(CN, Config) when 306: CN =:= remove_inbox; 307: CN =:= retrieve_inbox; 308: CN =:= remove_inbox_muclight; 309: CN =:= retrieve_inbox_muclight -> 310: muc_light_helper:clear_db(host_type()), 311: escalus:end_per_testcase(CN, Config); 312: end_per_testcase(CN, Config) when CN =:= retrieve_inbox_muc; 313: CN =:= remove_inbox_muc -> 314: muc_helper:unload_muc(), 315: escalus:end_per_testcase(CN, Config); 316: end_per_testcase(CN, Config) -> 317: escalus_fresh:clean(), 318: escalus:end_per_testcase(CN, Config). 319: 320: init_inbox(CN, Config, GroupChatType) -> 321: case (not ct_helper:is_ct_running()) 322: orelse mongoose_helper:is_rdbms_enabled(host_type()) of 323: true -> 324: dynamic_modules:ensure_modules(host_type(), inbox_required_modules(GroupChatType)), 325: escalus:init_per_testcase(CN, Config); 326: false -> 327: {skip, require_rdbms} 328: end. 329: inbox_required_modules(Type) -> 330: GroupChatModules = groupchat_module(Type), 331: InboxOpts = (inbox_helper:inbox_opts())#{groupchat => [Type]}, 332: Inbox = {mod_inbox, InboxOpts}, 333: GroupChatModules ++ [Inbox] . 334: 335: groupchat_module(muc) -> 336: []; 337: groupchat_module(muclight) -> 338: [{mod_muc_light, mod_config(mod_muc_light, 339: #{backend => mongoose_helper:mnesia_or_rdbms_backend(), 340: rooms_in_rosters => true})}]. 341: 342: mam_required_modules(CN, Backend) when CN =:= remove_mam_pm; 343: CN =:= retrieve_mam_pm -> 344: [{mod_mam, mam_helper:config_opts(#{backend => Backend, pm => #{}})}]; 345: mam_required_modules(CN, Backend) when CN =:= retrieve_mam_pm_and_muc_light_dont_interfere; 346: CN =:= retrieve_mam_muc_light -> 347: HostPattern = subhost_pattern(muc_light_helper:muc_host_pattern()), 348: [{mod_mam, mam_helper:config_opts(#{backend => Backend, 349: pm => #{}, 350: muc => #{host => HostPattern}})}, 351: {mod_muc_light, default_mod_config(mod_muc_light)}]; 352: mam_required_modules(retrieve_mam_pm_and_muc_light_interfere, Backend) -> 353: HostPattern = subhost_pattern(muc_light_helper:muc_host_pattern()), 354: [{mod_mam, mam_helper:config_opts(#{backend => Backend, 355: db_message_format => mam_message_xml, 356: pm => #{archive_groupchats => true}, 357: muc => #{host => HostPattern}})}, 358: {mod_muc_light, default_mod_config(mod_muc_light)}]; 359: mam_required_modules(CN, Backend) when CN =:= retrieve_mam_muc_private_msg; 360: CN =:= retrieve_mam_muc -> 361: HostPattern = subhost_pattern(muc_helper:muc_host_pattern()), 362: [{mod_mam, mam_helper:config_opts(#{backend => Backend, 363: pm => #{}, 364: muc => #{host => HostPattern}})}, 365: {mod_muc, muc_helper:make_opts(#{host => HostPattern})}]; 366: mam_required_modules(retrieve_mam_muc_store_pm, Backend) -> 367: HostPattern = subhost_pattern(muc_helper:muc_host_pattern()), 368: [{mod_mam, mam_helper:config_opts(#{backend => Backend, 369: pm => #{archive_groupchats => true}, 370: muc => #{host => HostPattern}})}, 371: {mod_muc, muc_helper:make_opts(#{host => HostPattern})}]. 372: 373: pick_enabled_backend() -> 374: BackendsList = [ 375: {mongoose_helper:is_rdbms_enabled(host_type()), rdbms} 376: ], 377: proplists:get_value(true, BackendsList, mnesia). 378: 379: roster_required_modules() -> 380: Backend = pick_enabled_backend(), 381: [{mod_roster, roster_backend_opts(Backend)}]. 382: 383: roster_backend_opts(Backend) -> 384: mod_config(mod_roster, #{backend => Backend}). 385: 386: vcard_required_modules() -> 387: Backend = pick_enabled_backend(), 388: [{mod_vcard, mod_config(mod_vcard, vcard_backend_opts(Backend))}]. 389: 390: vcard_backend_opts(Backend) -> 391: #{backend => Backend}. 392: 393: offline_required_modules() -> 394: [{mod_offline, mod_offline_config(pick_enabled_backend())}]. 395: 396: mod_offline_config(Backend) -> 397: config_parser_helper:mod_config(mod_offline, #{backend => Backend}). 398: 399: pubsub_required_modules() -> 400: pubsub_required_modules([<<"flat">>, <<"pep">>, <<"push">>]). 401: pubsub_required_modules(Plugins) -> 402: HostPattern = subhost_pattern("pubsub.@HOST@"), 403: PubsubConfig = mod_config(mod_pubsub, #{backend => mongoose_helper:mnesia_or_rdbms_backend(), 404: host => HostPattern, 405: nodetree => nodetree_tree, 406: plugins => Plugins}), 407: [{mod_caps, config_parser_helper:default_mod_config(mod_caps)}, {mod_pubsub, PubsubConfig}]. 408: 409: is_mim2_started() -> 410: #{node := Node} = distributed_helper:mim2(), 411: case net_adm:ping(Node) of 412: pong -> true; 413: _ -> false 414: end. 415: 416: roster_started() -> 417: dynamic_modules:ensure_modules(host_type(), roster_required_modules()). 418: 419: vcard_started() -> 420: dynamic_modules:ensure_modules(host_type(), vcard_required_modules()). 421: 422: offline_started() -> 423: dynamic_modules:ensure_modules(host_type(), offline_required_modules()). 424: 425: private_required_modules() -> 426: [{mod_private, create_private_config(pick_enabled_backend())}]. 427: 428: create_private_config(Backend) -> 429: mod_config(mod_private, #{backend => Backend}). 430: 431: private_started() -> 432: dynamic_modules:ensure_modules(host_type(), private_required_modules()). 433: 434: %% ------------------------------------------------------------- 435: %% Test cases 436: %% ------------------------------------------------------------- 437: 438: %% ------------------------- Data retrieval - per type verification ------------------------- 439: 440: retrieve_vcard(Config) -> 441: escalus:fresh_story(Config, [{alice, 1}], fun(Alice) -> 442: AliceFields = [{<<"FN">>, <<"Alice">>}, {<<"LN">>, <<"Ecila">>}], 443: AliceSetResultStanza 444: = escalus:send_and_wait(Alice, escalus_stanza:vcard_update(AliceFields)), 445: escalus:assert(is_iq_result, AliceSetResultStanza), 446: AliceU = escalus_utils:jid_to_lower(escalus_client:username(Alice)), 447: AliceS = escalus_utils:jid_to_lower(escalus_client:server(Alice)), 448: ExpectedHeader = ["jid", "vcard"], 449: ExpectedItems = [ 450: #{ "jid" => [{contains, AliceU}, 451: {contains, AliceS}], 452: "vcard" => [{contains, "Alice"}, 453: {contains, "Ecila"}] } 454: ], 455: retrieve_and_validate_personal_data( 456: Alice, Config, "vcard", ExpectedHeader, ExpectedItems) 457: end). 458: 459: remove_vcard(Config) -> 460: escalus:fresh_story(Config, [{alice, 1}], fun(Alice) -> 461: AliceFields = [{<<"FN">>, <<"Alice">>}, {<<"LN">>, <<"Ecila">>}], 462: AliceSetResultStanza 463: = escalus:send_and_wait(Alice, escalus_stanza:vcard_update(AliceFields)), 464: escalus:assert(is_iq_result, AliceSetResultStanza), 465: 466: unregister(Alice, Config), 467: 468: assert_personal_data_via_rpc(Alice, [{vcard,["jid","vcard"],[]}]) 469: 470: end). 471: 472: remove_private(Config) -> 473: escalus:fresh_story(Config, [{alice, 1}], fun(Alice) -> 474: %% Add some private data for Alice 475: Element = #xmlel{name = <<"item">>, 476: attrs = [{<<"xmlns">>, <<"alice:private_remove:ns">>}], 477: children = [#xmlcdata{ content = <<"Something to declare">> }]}, 478: SetPrivateResult = escalus:send_and_wait(Alice, 479: escalus_stanza:private_set(Element)), 480: escalus:assert(is_iq_result, SetPrivateResult), 481: 482: %% Verify the data is stored 483: assert_personal_data_via_rpc(Alice, [{private, ["ns","xml"], 484: [{<<"alice:private_remove:ns">>, 485: <<"<item xmlns='alice:private_remove:ns'>Something to declare</item>">>}]}]), 486: 487: %% Remove Alice 488: unregister(Alice, Config), 489: 490: %% Expect Alice's data to be gone 491: assert_personal_data_via_rpc(Alice, [{private, ["ns","xml"], []}]) 492: 493: end). 494: 495: dont_remove_other_user_private_xml(Config) -> 496: escalus:fresh_story(Config, [{alice, 1}, {bob, 1}], fun(Alice, Bob) -> 497: %% Add some private data for Alice and Bob 498: AliceNS = <<"alice:private:ns">>, 499: AliceContent = <<"To be or not to be">>, 500: BobNS = <<"bob:private:ns">>, 501: BobContent = <<"This is the winter of our discontent">>, 502: send_and_assert_private_stanza(Alice, AliceNS, AliceContent), 503: send_and_assert_private_stanza(Bob, BobNS, BobContent), 504: 505: %% Remove Alice 506: unregister(Alice, Config), 507: 508: %% Expect Alice's data to be gone 509: assert_personal_data_via_rpc(Alice, [{private, ["ns","xml"], []}]), 510: 511: %% Verify that Bob's data is left intact 512: ExpectedHeader = ["ns", "xml"], 513: ExpectedItems = [#{ "ns" => binary_to_list(BobNS), 514: "xml" => [{contains, binary_to_list(BobNS)}, 515: {contains, binary_to_list(BobContent)}] } 516: ], 517: retrieve_and_validate_personal_data( 518: Bob, Config, "private", ExpectedHeader, ExpectedItems) 519: 520: end). 521: 522: remove_multiple_private_xmls(Config) -> 523: escalus:fresh_story(Config, [{alice, 1}], fun(Alice) -> 524: %% Add some private data for Alice for multiple keys 525: NSsAndContents = [ 526: {<<"alice:private:ns1">>, <<"Some text">>}, 527: {<<"alice:private:ns2">>, <<"Other text for another key">>}, 528: {<<"alice:private:ns3">>, <<"Even more of text">>} 529: ], 530: lists:foreach( 531: fun({NS, Content}) -> 532: send_and_assert_private_stanza(Alice, NS, Content) 533: end, NSsAndContents), 534: ExpectedHeader = ["ns", "xml"], 535: ExpectedItems = lists:map( 536: fun({NS, Content}) -> 537: #{ "ns" => binary_to_list(NS), 538: "xml" => [{contains, binary_to_list(NS)}, 539: {contains, binary_to_list(Content)}]} 540: end, NSsAndContents), 541: 542: %% Verify the data is stored 543: retrieve_and_validate_personal_data( 544: Alice, Config, "private", ExpectedHeader, ExpectedItems), 545: 546: %% Remove Alice 547: unregister(Alice, Config), 548: 549: %% Expect all of Alice's data to be gone 550: assert_personal_data_via_rpc(Alice, [{private, ["ns","xml"], []}]) 551: 552: end). 553: 554: retrieve_roster(Config) -> 555: escalus:fresh_story(Config, [{alice, 1}, {bob, 1}], fun(Alice, Bob) -> 556: escalus_story:make_all_clients_friends([Alice, Bob]), 557: BobU = escalus_utils:jid_to_lower(escalus_client:username(Bob)), 558: BobS = escalus_utils:jid_to_lower(escalus_client:server(Bob)), 559: ExpectedItems = [ 560: #{ "jid" => [{contains, BobU}, {contains, BobS}] } 561: ], 562: retrieve_and_validate_personal_data( 563: Alice, Config, "roster", expected_header(mod_roster), ExpectedItems) 564: end). 565: 566: remove_roster(Config) -> 567: escalus:fresh_story(Config, [{alice, 1}, {bob, 1}], fun(Alice, Bob) -> 568: escalus_story:make_all_clients_friends([Alice, Bob]), 569: AliceU = escalus_utils:jid_to_lower(escalus_client:username(Alice)), 570: AliceS = escalus_utils:jid_to_lower(escalus_client:server(Alice)), 571: ExpectedItems = [ 572: #{ "jid" => [{contains, AliceU}, {contains, AliceS}] } 573: ], 574: 575: unregister(Alice, Config), 576: 577: assert_personal_data_via_rpc(Alice, [{roster, expected_header(mod_roster), []}]), 578: retrieve_and_validate_personal_data( 579: Bob, Config, "roster", expected_header(mod_roster), ExpectedItems) 580: 581: end). 582: 583: retrieve_mam_pm(Config) -> 584: F = fun(Alice, Bob) -> 585: Msg1 = <<"1some simple pm message">>, 586: Msg2 = <<"2another simple pm message">>, 587: Msg3 = <<"3third simple pm message">>, 588: escalus:send(Alice, escalus_stanza:chat_to(Bob, Msg1)), 589: escalus:send(Bob, escalus_stanza:chat_to(Alice, Msg2)), 590: escalus:send(Alice, escalus_stanza:chat_to(Bob, Msg3)), 591: [mam_helper:wait_for_archive_size(User, 3) || User <- [Alice, Bob]], 592: AliceJID = escalus_client:full_jid(Alice), 593: BobJID = escalus_client:full_jid(Bob), 594: 595: ExpectedHeader = ["id", "from", "message"], 596: ExpectedItems = [ 597: #{"message" => [{contains, Msg1}], "from" => [{jid, AliceJID}]}, 598: #{"message" => [{contains, Msg3}], "from" => [{jid, AliceJID}]}, 599: #{"message" => [{contains, Msg2}], "from" => [{jid, BobJID}]} 600: ], 601: 602: retrieve_and_validate_personal_data( 603: Alice, Config, "mam_pm", ExpectedHeader, ExpectedItems, ["from", "message"]), 604: retrieve_and_validate_personal_data( 605: Bob, Config, "mam_pm", ExpectedHeader, ExpectedItems, ["from", "message"]) 606: end, 607: escalus_fresh:story(Config, [{alice, 1}, {bob, 1}], F). 608: 609: retrieve_mam_muc(Config) -> 610: F = fun(Alice, Bob, Kate) -> 611: AliceUserCfg = escalus_users:get_user_by_name(alice), 612: RoomCfg = muc_helper:start_fresh_room([], AliceUserCfg, <<"someroom">>, []), 613: [Room, Domain] = [proplists:get_value(Key, RoomCfg) || Key <- [room, muc_host]], 614: AllRoomMembers = [Alice, Bob, Kate], 615: 616: muc_helper:enter_room(RoomCfg, [{Alice, <<"Nancy">>}, 617: {Bob, <<"Sid">>}, 618: {Kate, <<"Johnny">>}]), 619: 620: Body1 = <<"1some simple muc message">>, 621: Body2 = <<"2another one">>, 622: Body3 = <<"3third message">>, 623: muc_helper:send_to_room(RoomCfg, Alice, Body1), 624: muc_helper:verify_message_received(RoomCfg, AllRoomMembers, <<"Nancy">>, Body1), 625: muc_helper:send_to_room(RoomCfg, Alice, Body2), 626: muc_helper:verify_message_received(RoomCfg, AllRoomMembers, <<"Nancy">>, Body2), 627: muc_helper:send_to_room(RoomCfg, Bob, Body3), 628: muc_helper:verify_message_received(RoomCfg, AllRoomMembers, <<"Sid">>, Body3), 629: 630: mam_helper:wait_for_room_archive_size(Domain, Room, 3), 631: 632: ExpectedItemsAlice = [#{"message" => [{contains, binary_to_list(Body1)}]}, 633: #{"message" => [{contains, binary_to_list(Body2)}]}], 634: 635: ExpectedItemsBob = [#{"message" => [{contains, binary_to_list(Body3)}]}], 636: 637: AliceDir = retrieve_all_personal_data(Alice, Config), 638: BobDir = retrieve_all_personal_data(Bob, Config), 639: KateDir = retrieve_all_personal_data(Kate, Config), 640: 641: validate_personal_data( 642: AliceDir, "mam_muc", ["id", "message"], ExpectedItemsAlice, ["message"]), 643: validate_personal_data( 644: BobDir, "mam_muc", ["id", "message"], ExpectedItemsBob, ["message"]), 645: refute_personal_data(KateDir, "mam_muc"), 646: 647: [refute_personal_data(Dir, "mam_pm") || Dir <- [AliceDir, BobDir, KateDir]], 648: 649: muc_helper:destroy_room(RoomCfg) 650: end, 651: escalus_fresh:story(Config, [{alice, 1}, {bob, 1}, {kate, 1}], F). 652: 653: retrieve_mam_muc_private_msg(Config) -> 654: F = fun(Alice, Bob) -> 655: AliceUserCfg = escalus_users:get_user_by_name(alice), 656: RoomCfg = muc_helper:start_fresh_room([], AliceUserCfg, <<"someroom">>, []), 657: [Room, Domain] = [proplists:get_value(Key, RoomCfg) || Key <- [room, muc_host]], 658: 659: muc_helper:enter_room(RoomCfg, [{Alice, <<"Nancy">>}, {Bob, <<"Sid">>}]), 660: 661: PMBody = <<"Hi, Bob!">>, 662: {PrivAddrAlice, _} = send_receive_muc_private_message( 663: Room, Domain, {Alice, <<"Nancy">>}, {Bob, <<"Sid">>}, PMBody), 664: 665: [mam_helper:wait_for_archive_size(User, 1) || User <- [Alice, Bob]], 666: 667: PMExpectedItemsAlice = [#{"message" => [{contains, binary_to_list(PMBody)}], 668: "from" => [{jid, escalus_client:full_jid(Alice)}]}], 669: PMExpectedItemsBob = [#{"message" => [{contains, binary_to_list(PMBody)}], 670: "from" => [{jid, PrivAddrAlice}]}], 671: 672: AliceDir = retrieve_all_personal_data(Alice, Config), 673: BobDir = retrieve_all_personal_data(Bob, Config), 674: 675: validate_personal_data( 676: AliceDir, "mam_pm", ["id", "from", "message"], PMExpectedItemsAlice, []), 677: validate_personal_data( 678: BobDir, "mam_pm", ["id", "from", "message"], PMExpectedItemsBob, []), 679: 680: refute_personal_data(AliceDir, "mam_muc"), 681: refute_personal_data(BobDir, "mam_muc"), 682: 683: muc_helper:destroy_room(RoomCfg) 684: end, 685: escalus_fresh:story(Config, [{alice, 1}, {bob, 1}], F). 686: 687: 688: 689: retrieve_mam_muc_store_pm(Config) -> 690: F = fun(Alice, Bob, Kate) -> 691: AliceUserCfg = escalus_users:get_user_by_name(alice), 692: RoomCfg = muc_helper:start_fresh_room([], AliceUserCfg, <<"someroom">>, []), 693: [Room, Domain] = [proplists:get_value(Key, RoomCfg) || Key <- [room, muc_host]], 694: AllRoomMembers = [Alice, Bob, Kate], 695: 696: muc_helper:enter_room(RoomCfg, [{Alice, <<"Nancy">>}, 697: {Bob, <<"Sid">>}, 698: {Kate, <<"Johnny">>}]), 699: 700: Body1 = <<"1some simple muc message">>, 701: Body2 = <<"2another one">>, 702: Body3 = <<"3third message">>, 703: muc_helper:send_to_room(RoomCfg, Alice, Body1), 704: muc_helper:verify_message_received(RoomCfg, AllRoomMembers, <<"Nancy">>, Body1), 705: muc_helper:send_to_room(RoomCfg, Alice, Body2), 706: muc_helper:verify_message_received(RoomCfg, AllRoomMembers, <<"Nancy">>, Body2), 707: muc_helper:send_to_room(RoomCfg, Bob, Body3), 708: muc_helper:verify_message_received(RoomCfg, AllRoomMembers, <<"Sid">>, Body3), 709: 710: PMBody = <<"4Hi, Bob!">>, 711: {PrivAddrAlice, PrivAddrBob} = send_receive_muc_private_message( 712: Room, Domain, {Alice, <<"Nancy">>}, {Bob, <<"Sid">>}, PMBody), 713: 714: mam_helper:wait_for_room_archive_size(Domain, Room, 3), 715: mam_helper:wait_for_archive_size(Kate, 4), 716: [mam_helper:wait_for_archive_size(User, 5) || User <- [Alice, Bob]], 717: 718: AliceDir = retrieve_all_personal_data(Alice, Config), 719: BobDir = retrieve_all_personal_data(Bob, Config), 720: KateDir = retrieve_all_personal_data(Kate, Config), 721: 722: ExpectedItemsAlice = [#{"message" => [{contains, binary_to_list(Body1)}]}, 723: #{"message" => [{contains, binary_to_list(Body2)}]}], 724: ExpectedItemsBob = [#{"message" => [{contains, binary_to_list(Body3)}]}], 725: 726: validate_personal_data( 727: AliceDir, "mam_muc", ["id", "message"], ExpectedItemsAlice, ["message"]), 728: validate_personal_data( 729: BobDir, "mam_muc", ["id", "message"], ExpectedItemsBob, ["message"]), 730: refute_personal_data(KateDir, "mam_muc"), 731: 732: RoomJID = <<Room/binary, "@", Domain/binary>>, 733: MsgFromAliceToRoom = #{"message" => [{contains, "<body>[1,2]"}], 734: "from" => [{jid, PrivAddrAlice}]}, 735: PMExpectedItemsKate = [#{"message" => [{contains, "<body/>"}], 736: "from" => [{jid, RoomJID}]}, 737: MsgFromAliceToRoom, MsgFromAliceToRoom, 738: #{"message" => [{contains, binary_to_list(Body3)}], 739: "from" => [{jid, PrivAddrBob}]} 740: ], 741: PMExpectedItemsAlice = PMExpectedItemsKate ++ 742: [#{"message" => [{contains, binary_to_list(PMBody)}], 743: "from" => [{jid, escalus_client:full_jid(Alice)}]}], 744: MsgFromAlice = #{"message" => [{contains, "<body>[1,2,4]"}], 745: "from" => [{jid, PrivAddrAlice}]}, 746: PMExpectedItemsBob = [#{"message" => [{contains, "<body/>"}], 747: "from" => [{jid, RoomJID}]}, 748: MsgFromAlice, MsgFromAlice, MsgFromAlice, 749: #{"message" => [{contains, binary_to_list(Body3)}], 750: "from" => [{jid, PrivAddrBob}]} 751: ], 752: SortFn = muc_msg_first(RoomJID), 753: validate_personal_data( 754: KateDir, "mam_pm", ["id", "from", "message"], PMExpectedItemsKate, SortFn), 755: validate_personal_data( 756: AliceDir, "mam_pm", ["id", "from", "message"], PMExpectedItemsAlice, SortFn), 757: validate_personal_data( 758: BobDir, "mam_pm", ["id", "from", "message"], PMExpectedItemsBob, SortFn), 759: 760: muc_helper:destroy_room(RoomCfg) 761: end, 762: escalus_fresh:story(Config, [{alice, 1}, {bob, 1}, {kate, 1}], F). 763: 764: remove_mam_pm(Config) -> 765: F = fun(Alice, Bob) -> 766: Msg1 = <<"1remove_mam_pm message">>, 767: Msg2 = <<"2remove_mam_pm message message">>, 768: Msg3 = <<"3remove_mam_pm message message">>, 769: escalus:send(Alice, escalus_stanza:chat_to(Bob, Msg1)), 770: escalus:send(Bob, escalus_stanza:chat_to(Alice, Msg2)), 771: escalus:send(Alice, escalus_stanza:chat_to(Bob, Msg3)), 772: [mam_helper:wait_for_archive_size(User, 3) || User <- [Alice, Bob]], 773: AliceJID = escalus_client:full_jid(Alice), 774: BobJID = escalus_client:full_jid(Bob), 775: 776: ExpectedHeader = ["id", "from", "message"], 777: ExpectedItems = [ 778: #{"message" => [{contains, Msg1}], "from" => [{jid, AliceJID}]}, 779: #{"message" => [{contains, Msg3}], "from" => [{jid, AliceJID}]}, 780: #{"message" => [{contains, Msg2}], "from" => [{jid, BobJID}]} 781: ], 782: 783: unregister(Alice, Config), 784: 785: assert_personal_data_via_rpc(Alice, [{mam_pm, ExpectedHeader, []}]), 786: 787: retrieve_and_validate_personal_data( 788: Bob, Config, "mam_pm", ExpectedHeader, ExpectedItems, ["from", "message"]) 789: end, 790: escalus_fresh:story(Config, [{alice, 1}, {bob, 1}], F). 791: 792: retrieve_mam_muc_light(Config) -> 793: F = fun(Alice, Bob, Kate) -> 794: RoomJid = muc_light_helper:given_muc_light_room(undefined, Alice, [{Bob, member}, {Kate, member}]), 795: [Room, Domain] = binary:split(RoomJid, <<"@">>), 796: Body1 = <<"1some simple muc message">>, 797: Body2 = <<"2another one">>, 798: Body3 = <<"3third message">>, 799: 800: M1 = muc_light_helper:when_muc_light_message_is_sent(Alice, Room, Body1, <<"Id1">>), 801: muc_light_helper:then_muc_light_message_is_received_by([Alice, Bob, Kate], M1), 802: M2 = muc_light_helper:when_muc_light_message_is_sent(Alice, Room, Body2, <<"Id2">>), 803: muc_light_helper:then_muc_light_message_is_received_by([Alice, Bob, Kate], M2), 804: M3 = muc_light_helper:when_muc_light_message_is_sent(Bob, Room, Body3, <<"Id3">>), 805: muc_light_helper:then_muc_light_message_is_received_by([Alice, Bob, Kate], M3), 806: 807: mam_helper:wait_for_room_archive_size(Domain, Room, 4), 808: 809: ExpectedItemsAlice = [#{"message" => [{contains, binary_to_list(Body1)}]}, 810: #{"message" => [{contains, binary_to_list(Body2)}]}], 811: 812: ExpectedItemsBob = [#{"message" => [{contains, binary_to_list(Body3)}]}], 813: 814: retrieve_and_validate_personal_data( 815: Alice, Config, "mam_muc", ["id", "message"], ExpectedItemsAlice, ["message"]), 816: retrieve_and_validate_personal_data( 817: Bob, Config, "mam_muc", ["id", "message"], ExpectedItemsBob, ["message"]), 818: refute_personal_data(Kate, Config, "mam_muc") 819: end, 820: escalus_fresh:story(Config, [{alice, 1}, {bob, 1}, {kate, 1}], F). 821: 822: retrieve_mam_pm_and_muc_light_dont_interfere(Config) -> 823: F = fun(Alice, Bob, Kate) -> 824: RoomJid = muc_light_helper:given_muc_light_room(undefined, Alice, 825: [{Bob, member}, {Kate, member}]), 826: [Room, Domain] = binary:split(RoomJid, <<"@">>), 827: BodyMucAlice = <<"some simple muc message from Alice">>, 828: BodyMucBob = <<"some simple muc message from Bob">>, 829: BodyPmAlice = <<"some simple pm message from Alice">>, 830: BodyPmBob = <<"some simple pm message from Bob">>, 831: 832: M1 = muc_light_helper:when_muc_light_message_is_sent(Alice, Room, BodyMucAlice, <<"Id1">>), 833: muc_light_helper:then_muc_light_message_is_received_by([Alice, Bob, Kate], M1), 834: M2 = muc_light_helper:when_muc_light_message_is_sent(Bob, Room, BodyMucBob, <<"Id2">>), 835: muc_light_helper:then_muc_light_message_is_received_by([Alice, Bob, Kate], M2), 836: 837: mam_helper:wait_for_room_archive_size(Domain, Room, 3), 838: 839: escalus:send(Alice, escalus_stanza:chat_to(Bob, BodyPmAlice)), 840: escalus:send(Bob, escalus_stanza:chat_to(Alice, BodyPmBob)), 841: 842: [mam_helper:wait_for_archive_size(User, 2) || User <- [Alice, Bob]], 843: 844: false = mongoose_helper:successful_rpc(gen_mod, get_module_opt, 845: [host_type(), mod_mam_pm, archive_groupchats, undefined]), 846: 847: AliceDir = retrieve_all_personal_data(Alice, Config), 848: BobDir = retrieve_all_personal_data(Bob, Config), 849: KateDir = retrieve_all_personal_data(Kate, Config), 850: 851: validate_personal_data( 852: AliceDir, "mam_muc", ["id", "message"], 853: [#{"message" => [{contains, binary_to_list(BodyMucAlice)}]}], []), 854: validate_personal_data( 855: BobDir, "mam_muc", ["id", "message"], 856: [#{"message" => [{contains, binary_to_list(BodyMucBob)}]}], []), 857: 858: PM = [#{"message" => [{contains, BodyPmAlice}], 859: "from" => [{jid, escalus_client:full_jid(Alice)}]}, 860: #{"message" => [{contains, BodyPmBob}], 861: "from" => [{jid, escalus_client:full_jid(Bob)}]}], 862: validate_personal_data(AliceDir, "mam_pm", ["id", "from", "message"], PM, ["from", "message"]), 863: validate_personal_data(BobDir, "mam_pm", ["id", "from", "message"], PM, ["from", "message"]), 864: refute_personal_data(KateDir, "mam_pm"), 865: refute_personal_data(KateDir, "mam_muc") 866: end, 867: escalus_fresh:story(Config, [{alice, 1}, {bob, 1}, {kate, 1}], F). 868: 869: retrieve_mam_pm_and_muc_light_interfere(Config) -> 870: F = fun(Alice, Bob, Kate) -> 871: RoomJid = muc_light_helper:given_muc_light_room(undefined, Alice, 872: [{Bob, member}, {Kate, member}]), 873: [Room, Domain] = binary:split(RoomJid, <<"@">>), 874: BodyMucAlice = <<"some simple muc message from Alice">>, 875: BodyMucBob = <<"some simple muc message from Bob">>, 876: BodyPmAlice = <<"some simple pm message from Alice">>, 877: BodyPmBob = <<"some simple pm message from Bob">>, 878: 879: M1 = muc_light_helper:when_muc_light_message_is_sent(Alice, Room, BodyMucAlice, <<"Id1">>), 880: muc_light_helper:then_muc_light_message_is_received_by([Alice, Bob, Kate], M1), 881: M2 = muc_light_helper:when_muc_light_message_is_sent(Bob, Room, BodyMucBob, <<"Id2">>), 882: muc_light_helper:then_muc_light_message_is_received_by([Alice, Bob, Kate], M2), 883: 884: mam_helper:wait_for_room_archive_size(Domain, Room, 3), 885: 886: escalus:send(Alice, escalus_stanza:chat_to(Bob, BodyPmAlice)), 887: escalus:send(Bob, escalus_stanza:chat_to(Alice, BodyPmBob)), 888: 889: [mam_helper:wait_for_archive_size(User, 5) || User <- [Alice, Bob]], 890: mam_helper:wait_for_archive_size(Kate, 3), 891: 892: true = mongoose_helper:successful_rpc(gen_mod, get_module_opt, 893: [host_type(), mod_mam_pm, archive_groupchats, undefined]), 894: 895: AliceDir = retrieve_all_personal_data(Alice, Config), 896: BobDir = retrieve_all_personal_data(Bob, Config), 897: KateDir = retrieve_all_personal_data(Kate, Config), 898: 899: validate_personal_data( 900: AliceDir, "mam_muc", ["id", "message"], 901: [#{"message" => [{contains, binary_to_list(BodyMucAlice)}]}], []), 902: validate_personal_data( 903: BobDir, "mam_muc", ["id", "message"], 904: [#{"message" => [{contains, binary_to_list(BodyMucBob)}]}], []), 905: 906: AliceRoomJid = <<RoomJid/binary, "/", (escalus_client:short_jid(Alice))/binary>>, 907: BobRoomJid = <<RoomJid/binary, "/", (escalus_client:short_jid(Bob))/binary>>, 908: 909: MucPM = [#{"message" => [{contains, "urn:xmpp:muclight:0#affiliations"}], 910: "from" => [{jid, RoomJid}]}, 911: #{"message" => [{contains, BodyMucAlice}], "from" => [{jid, AliceRoomJid}]}, 912: #{"message" => [{contains, BodyMucBob}], "from" => [{jid, BobRoomJid}]}], 913: AllPM = MucPM ++ [#{"message" => [{contains, BodyPmAlice}], 914: "from" => [{jid, escalus_client:full_jid(Alice)}]}, 915: #{"message" => [{contains, BodyPmBob}], 916: "from" => [{jid, escalus_client:full_jid(Bob)}]}], 917: SortFn = muc_msg_first(RoomJid), 918: validate_personal_data(AliceDir, "mam_pm", ["id", "from", "message"], AllPM, SortFn), 919: validate_personal_data(BobDir, "mam_pm", ["id", "from", "message"], AllPM, SortFn), 920: validate_personal_data(KateDir, "mam_pm", ["id", "from", "message"], MucPM, SortFn), 921: refute_personal_data(KateDir, "mam_muc") 922: end, 923: escalus_fresh:story(Config, [{alice, 1}, {bob, 1}, {kate, 1}], F). 924: 925: retrieve_offline(Config) -> 926: escalus:fresh_story(Config, [{alice, 1}, {bob, 1}, {kate, 1}], fun(Alice, Bob, Kate) -> 927: mongoose_helper:logout_user(Config, Alice), 928: Body1 = <<"1Hey!">>, 929: Body2 = <<"2Here is Johnny!">>, 930: Body3 = <<"3Where is Johnny ?">>, 931: escalus:send(Bob, escalus_stanza:chat_to(Alice, Body1)), 932: escalus:send(Bob, escalus_stanza:chat_to(Alice, Body2)), 933: escalus:send(Kate, escalus_stanza:chat_to(Alice, Body3)), 934: %% Well, jid_to_lower works for any binary :) 935: AliceU = escalus_utils:jid_to_lower(escalus_client:username(Alice)), 936: AliceS = escalus_utils:jid_to_lower(escalus_client:server(Alice)), 937: mongoose_helper:wait_until( 938: fun() -> 939: mongoose_helper:successful_rpc(mod_offline_backend, count_offline_messages, 940: [host_type(), AliceU, AliceS, 10]) 941: end, 3), 942: 943: BobJid = escalus_client:full_jid(Bob), 944: AliceJid = escalus_client:short_jid(Alice), 945: KateJid = escalus_client:full_jid(Kate), 946: ExpectedHeader = ["timestamp", "from", "to", "packet"], 947: Expected = [{Body1, BobJid, AliceJid}, {Body2, BobJid, AliceJid}, {Body3, KateJid, AliceJid}], 948: 949: ExpectedItems = lists:map(fun({Body, From ,To}) -> 950: #{ "packet" => [{contains, Body}], 951: "from" => binary_to_list(From), 952: "to" => binary_to_list(To), 953: "timestamp" => [{validate, fun validate_datetime/1}]} 954: end, Expected), 955: 956: retrieve_and_validate_personal_data( 957: Alice, Config, "offline", ExpectedHeader, ExpectedItems, ["packet"]) 958: end). 959: 960: remove_offline(Config) -> 961: escalus:fresh_story(Config, [{alice, 1}, {bob, 1}, {kate, 1}], fun(Alice, Bob, Kate) -> 962: mongoose_helper:logout_user(Config, Alice), 963: Body1 = <<"Hey!">>, 964: Body2 = <<"Here is Johnny!">>, 965: Body3 = <<"Where is Johnny ?">>, 966: escalus:send(Bob, escalus_stanza:chat_to(Alice, Body1)), 967: escalus:send(Bob, escalus_stanza:chat_to(Alice, Body2)), 968: escalus:send(Kate, escalus_stanza:chat_to(Alice, Body3)), 969: %% Well, jid_to_lower works for any binary :) 970: AliceU = escalus_utils:jid_to_lower(escalus_client:username(Alice)), 971: AliceS = escalus_utils:jid_to_lower(escalus_client:server(Alice)), 972: mongoose_helper:wait_until( 973: fun() -> 974: mongoose_helper:successful_rpc(mod_offline_backend, count_offline_messages, 975: [host_type(), AliceU, AliceS, 10]) 976: end, 3), 977: 978: unregister(Alice, Config), 979: 980: assert_personal_data_via_rpc( 981: Alice, [{offline, ["timestamp","from", "to", "packet"],[]}]) 982: end). 983: 984: retrieve_pubsub_payloads(Config) -> 985: escalus:fresh_story(Config, [{alice, 1}], fun(Alice) -> 986: [Node1={_,NodeName1}, Node2={_,NodeName2}] = pubsub_tools:create_node_names(2), 987: {BinItem1, StringItem1} = item_content(<<"Item1Data">>), 988: {BinItem2, StringItem2} = item_content(<<"Item2Data">>), 989: {BinItem3, StringItem3} = item_content(<<"Item3Data">>), 990: {BinOther, StringOther} = item_content(<<"OtherItemData">>), 991: 992: pubsub_tools:publish(Alice, <<"Item1">>, Node1, [{with_payload, BinItem1}]), 993: pubsub_tools:publish(Alice, <<"Item2">>, Node1, [{with_payload, BinItem2}]), 994: pubsub_tools:publish(Alice, <<"Item3">>, Node1, [{with_payload, BinItem3}]), 995: pubsub_tools:publish(Alice, <<"OtherItem">>, Node2, [{with_payload, BinOther}]), 996: 997: ExpectedItems = [pubsub_payloads_row_map(NodeName1, "Item1", StringItem1), 998: pubsub_payloads_row_map(NodeName1, "Item2", StringItem2), 999: pubsub_payloads_row_map(NodeName1, "Item3", StringItem3), 1000: pubsub_payloads_row_map(NodeName2, "OtherItem", StringOther)], 1001: 1002: retrieve_and_validate_personal_data(Alice, Config, "pubsub_payloads", 1003: ["node_name", "item_id", "payload"], 1004: ExpectedItems, ["item_id"]) 1005: end). 1006: 1007: dont_retrieve_other_user_pubsub_payload(Config) -> 1008: escalus:fresh_story(Config, [{alice, 1}, {bob, 1}], fun(Alice, Bob) -> 1009: [Node1={_,NodeName1}] = pubsub_tools:create_node_names(1), 1010: pubsub_tools:create_nodes([{Alice, Node1, []}]), 1011: 1012: {BinItem1, StringItem1} = item_content(<<"Item1Data">>), 1013: {BinItem2, StringItem2} = item_content(<<"Item2Data">>), 1014: 1015: AffChange = [{Bob, <<"publish-only">>}], 1016: pubsub_tools:set_affiliations(Alice, Node1, AffChange, []), 1017: pubsub_tools:publish(Alice, <<"Item1">>, Node1, [{with_payload, {true, BinItem1}}]), 1018: pubsub_tools:publish(Bob, <<"Item2">>, Node1, [{with_payload, {true, BinItem2}}]), 1019: 1020: retrieve_and_validate_personal_data( 1021: Alice, Config, "pubsub_payloads", ["node_name", "item_id", "payload"], 1022: [pubsub_payloads_row_map(NodeName1, "Item1", StringItem1)]), 1023: 1024: retrieve_and_validate_personal_data( 1025: Bob, Config, "pubsub_payloads", ["node_name","item_id", "payload"], 1026: [pubsub_payloads_row_map(NodeName1, "Item2", StringItem2)]), 1027: 1028: pubsub_tools:delete_node(Alice, Node1, []) 1029: end). 1030: 1031: retrieve_created_pubsub_nodes(Config) -> 1032: escalus:fresh_story(Config, [{alice, 1}, {bob, 1}], fun(Alice, Bob) -> 1033: [Node1={_,NodeName1}, Node2={_,NodeName2}, Node3={_,NodeName3}] = 1034: pubsub_tools:create_node_names(3), 1035: 1036: NodeNS = <<"myns">>, 1037: PepNode = make_pep_node_info(Alice, NodeNS), 1038: AccessModel = {<<"pubsub#access_model">>, <<"authorize">>}, 1039: 1040: pubsub_tools:create_nodes([ 1041: {Alice, Node1, []}, 1042: {Alice, Node2, []}, 1043: {Alice, PepNode, [{config, [AccessModel]}]}, 1044: {Bob, Node3, [{type, <<"push">>}]} 1045: ]), 1046: 1047: ExpectedHeader = ["node_name", "type"], 1048: 1049: retrieve_and_validate_personal_data( 1050: Alice, Config, "pubsub_nodes", ExpectedHeader, 1051: [pubsub_nodes_row_map(NodeNS, "pep"), 1052: pubsub_nodes_row_map(NodeName1, "flat"), 1053: pubsub_nodes_row_map(NodeName2, "flat")]), 1054: 1055: retrieve_and_validate_personal_data( 1056: Bob, Config, "pubsub_nodes", ExpectedHeader, 1057: [pubsub_nodes_row_map(NodeName3, "push")]), 1058: 1059: 1060: Nodes = [{Alice, PepNode}, {Alice, Node1}, {Alice, Node2}, {Bob, Node3}], 1061: [pubsub_tools:delete_node(User, Node, []) || {User, Node} <- Nodes] 1062: end). 1063: 1064: remove_pubsub_subscriptions(Config) -> 1065: escalus:fresh_story(Config, [{alice, 1}, {bob, 1}], fun(Alice, Bob) -> 1066: Node = pubsub_tools:pubsub_node(), 1067: pubsub_tools:create_node(Alice, Node, []), 1068: pubsub_tools:subscribe(Bob, Node, []), 1069: 1070: unregister(Bob, Config), 1071: 1072: assert_personal_data_via_rpc(Bob, 1073: [{pubsub_payloads,["node_name","item_id","payload"],[]}, 1074: {pubsub_nodes,["node_name","type"],[]}, 1075: {pubsub_subscriptions,["node_name"],[]}]) 1076: end). 1077: 1078: retrieve_pubsub_subscriptions(Config) -> 1079: escalus:fresh_story(Config, [{alice, 1}, {bob, 1}], fun(Alice, Bob) -> 1080: Node = {_Domain, NodeName} = pubsub_tools:pubsub_node(), 1081: pubsub_tools:create_node(Alice, Node, []), 1082: pubsub_tools:subscribe(Bob, Node, []), 1083: retrieve_and_validate_personal_data(Bob, Config, "pubsub_subscriptions", ["node_name"], 1084: [pubsub_subscription_row_map(NodeName)]), 1085: 1086: pubsub_tools:delete_node(Alice, Node, []) 1087: end). 1088: 1089: remove_pubsub_dont_remove_flat_pubsub_node(Config) -> 1090: escalus:fresh_story(Config, [{alice, 1}], fun(Alice) -> 1091: Node1 = {_,NodeName} = pubsub_tools:pubsub_node_with_num(1), 1092: pubsub_tools:create_nodes([{Alice, Node1, []}]), 1093: 1094: unregister(Alice, Config), 1095: 1096: assert_personal_data_via_rpc(Alice, 1097: [{pubsub_payloads,["node_name","item_id","payload"],[]}, 1098: {pubsub_nodes,["node_name","type"],[[NodeName, <<"flat">>]]}, 1099: {pubsub_subscriptions,["node_name"],[]}]) 1100: end). 1101: 1102: remove_pubsub_push_node(Config) -> 1103: escalus:fresh_story(Config, [{alice, 1}, {bob, 1}], fun(Alice, Bob) -> 1104: [Node] = pubsub_tools:create_node_names(1), 1105: pubsub_tools:create_nodes([{Alice, Node, [{type, <<"push">>}]}]), 1106: 1107: Content = [ 1108: {<<"message-count">>, <<"1">>}, 1109: {<<"last-message-sender">>, <<"senderId">>}, 1110: {<<"last-message-body">>, <<"message body">>} 1111: ], 1112: Options = [ 1113: {<<"device_id">>, <<"sometoken">>}, 1114: {<<"service">>, <<"apns">>} 1115: ], 1116: 1117: PublishIQ = push_pubsub_SUITE:publish_iq(Bob, Node, Content, Options), 1118: escalus:send(Bob, PublishIQ), 1119: escalus:assert(is_iq_result, escalus:wait_for_stanza(Bob)), 1120: 1121: unregister(Alice, Config), 1122: 1123: assert_personal_data_via_rpc(Alice, [{pubsub_payloads,["node_name","item_id","payload"],[]}, 1124: {pubsub_nodes,["node_name","type"],[]}, 1125: {pubsub_subscriptions,["node_name"],[]}]) 1126: end). 1127: 1128: remove_pubsub_pep_node(Config) -> 1129: escalus:fresh_story(Config, [{alice, 1}], fun(Alice) -> 1130: NodeName = <<"myns">>, 1131: PepNode = make_pep_node_info(Alice, NodeName), 1132: 1133: pubsub_tools:create_nodes([ 1134: {Alice, PepNode, []} 1135: ]), 1136: 1137: unregister(Alice, Config), 1138: 1139: assert_personal_data_via_rpc(Alice, [{pubsub_payloads,["node_name","item_id","payload"],[]}, 1140: {pubsub_nodes,["node_name","type"],[]}, 1141: {pubsub_subscriptions,["node_name"],[]}]) 1142: end). 1143: 1144: remove_pubsub_dont_remove_node_when_only_publisher(Config) -> 1145: escalus:fresh_story(Config, [{alice, 1}, {bob, 1}], fun(Alice, Bob) -> 1146: Node1 = {_,NodeName} = pubsub_tools:pubsub_node_with_num(1), 1147: pubsub_tools:create_nodes([{Alice, Node1, []}]), 1148: 1149: AffChange = [{Bob, <<"publish-only">>}], 1150: pubsub_tools:set_affiliations(Alice, Node1, AffChange, []), 1151: 1152: unregister(Bob, Config), 1153: 1154: assert_personal_data_via_rpc(Alice, 1155: [{pubsub_payloads,["node_name","item_id","payload"],[]}, 1156: {pubsub_nodes,["node_name","type"],[[NodeName, <<"flat">>]]}, 1157: {pubsub_subscriptions,["node_name"],[]}]) 1158: end). 1159: 1160: remove_pubsub_all_data(Config) -> 1161: escalus:fresh_story(Config, [{alice, 1}, {bob, 1}], fun(Alice, Bob) -> 1162: [Node1={_,Name1}, Node2={_,Name2}, Node3={_,Name3}, Node4={_,Name4}] 1163: = pubsub_tools:create_node_names(4), 1164: PepNode = make_pep_node_info(Alice, <<"myns">>), 1165: pubsub_tools:create_nodes([ 1166: {Alice, Node1, []}, 1167: {Alice, Node2, []}, 1168: {Alice, PepNode, []}, 1169: {Bob, Node3, []}, 1170: {Bob, Node4, [{type, <<"push">>}]} 1171: ]), 1172: 1173: AffChange = [{Bob, <<"publish-only">>}], 1174: pubsub_tools:set_affiliations(Alice, Node1, AffChange, []), 1175: pubsub_tools:subscribe(Bob, Node2, []), 1176: pubsub_tools:subscribe(Alice, Node3, []), 1177: 1178: {BinItem1, _} = item_content(<<"Item1Data">>), 1179: {BinItem2, _} = item_content(<<"Item2Data">>), 1180: {BinItem3, _} = item_content(<<"Item3Data">>), 1181: {BinItem4, _} = item_content(<<"Item4Data">>), 1182: AliceToNode1 = <<"Alice publishes to Node1, but nobody is subscribed">>, 1183: AliceToNode2 = <<"Alice published to Node2, so Bob receives it">>, 1184: BobToNode1 = <<"Bob publishes to Node1, but nobody is subscribed">>, 1185: BobToNode3 = <<"Bob publishes to Node3, so Alice receives it">>, 1186: 1187: pubsub_tools:publish(Alice, AliceToNode1, Node1, [{with_payload, {true, BinItem1}}]), 1188: 1189: pubsub_tools:publish(Alice, AliceToNode2, Node2, [{with_payload, {true, BinItem2}}]), 1190: pubsub_tools:receive_item_notification(Bob, AliceToNode2, Node2, []), 1191: 1192: pubsub_tools:publish(Bob, BobToNode1, Node1, [{with_payload, {true, BinItem3}}]), 1193: 1194: pubsub_tools:publish(Bob, BobToNode3, Node3, [{with_payload, {true, BinItem4}}]), 1195: pubsub_tools:receive_item_notification(Alice, BobToNode3, Node3, []), 1196: 1197: unregister(Alice, Config), 1198: 1199: [{pubsub_payloads,["node_name","item_id","payload"], AlicePayloads}, 1200: {pubsub_nodes,["node_name","type"], AliceNodes}, 1201: {pubsub_subscriptions, ["node_name"], []}] 1202: = get_personal_data_via_rpc( 1203: Alice, [pubsub_payloads, pubsub_nodes, pubsub_subscriptions]), 1204: XmlBinItem1 = exml:to_binary(BinItem1), 1205: XmlBinItem2 = exml:to_binary(BinItem2), 1206: [[Name1, AliceToNode1, XmlBinItem1], 1207: [Name2, AliceToNode2, XmlBinItem2]] = lists:sort(AlicePayloads), 1208: [[Name1, <<"flat">>], [Name2, <<"flat">>]] = lists:sort(AliceNodes), 1209: 1210: [{pubsub_payloads,["node_name","item_id","payload"], Payloads}, 1211: {pubsub_nodes,["node_name","type"], Nodes}, 1212: {pubsub_subscriptions, ["node_name"], Subs}] 1213: = get_personal_data_via_rpc( 1214: Bob, [pubsub_payloads, pubsub_nodes, pubsub_subscriptions]), 1215: XmlBinItem3 = exml:to_binary(BinItem3), 1216: XmlBinItem4 = exml:to_binary(BinItem4), 1217: [[Name1, BobToNode1, XmlBinItem3], 1218: [Name3, BobToNode3, XmlBinItem4]] = lists:sort(Payloads), 1219: [[Name3, <<"flat">>], [Name4, <<"push">>]] = lists:sort(Nodes), 1220: [[Name2]] = Subs 1221: end). 1222: 1223: retrieve_all_pubsub_data(Config) -> 1224: escalus:fresh_story(Config, [{alice, 1}, {bob, 1}], fun(Alice, Bob) -> 1225: [Node1={_,NodeName1}, Node2={_,NodeName2}, Node3={_,NodeName3}] = 1226: pubsub_tools:create_node_names(3), 1227: pubsub_tools:create_nodes([{Alice, Node1, []}, {Alice, Node2, []}, {Bob, Node3, []}]), 1228: 1229: AffChange = [{Bob, <<"publish-only">>}], 1230: pubsub_tools:set_affiliations(Alice, Node1, AffChange, []), 1231: pubsub_tools:subscribe(Bob, Node2, []), 1232: 1233: {BinItem1, StringItem1} = item_content(<<"Item1Data">>), 1234: {BinItem2, StringItem2} = item_content(<<"Item2Data">>), 1235: {BinItem3, StringItem3} = item_content(<<"Item3Data">>), 1236: 1237: pubsub_tools:publish(Alice, <<"Item1">>, Node1, [{with_payload, {true, BinItem1}}]), 1238: pubsub_tools:publish(Alice, <<"Item2">>, Node2, [{with_payload, {true, BinItem2}}]), 1239: pubsub_tools:receive_item_notification(Bob, <<"Item2">>, Node2, []), 1240: pubsub_tools:publish(Bob, <<"Item3">>, Node1, [{with_payload, {true, BinItem3}}]), 1241: 1242: %% Bob has one subscription, one node created and one payload sent 1243: retrieve_and_validate_personal_data( 1244: Bob, Config, "pubsub_subscriptions", ["node_name"], 1245: [pubsub_subscription_row_map(NodeName2)]), 1246: 1247: retrieve_and_validate_personal_data( 1248: Bob, Config, "pubsub_nodes", ["node_name", "type"], 1249: [pubsub_nodes_row_map(NodeName3, "flat")]), 1250: 1251: retrieve_and_validate_personal_data( 1252: Bob, Config, "pubsub_payloads", ["node_name", "item_id", "payload"], 1253: [pubsub_payloads_row_map(NodeName1, "Item3", StringItem3)]), 1254: 1255: %% Alice has two nodes created and two payloads sent 1256: retrieve_and_validate_personal_data( 1257: Alice, Config, "pubsub_nodes", ["node_name", "type"], 1258: [pubsub_nodes_row_map(NodeName1, "flat"), 1259: pubsub_nodes_row_map(NodeName2, "flat")]), 1260: retrieve_and_validate_personal_data( 1261: Alice, Config, "pubsub_payloads", ["node_name", "item_id","payload"], 1262: [pubsub_payloads_row_map(NodeName1, "Item1", StringItem1), 1263: pubsub_payloads_row_map(NodeName2, "Item2", StringItem2)]), 1264: 1265: dynamic_modules:ensure_modules(host_type(), pubsub_required_modules()), 1266: Nodes = [{Alice, Node1}, {Alice, Node2}, {Bob, Node3}], 1267: [pubsub_tools:delete_node(User, Node, []) || {User, Node} <- Nodes] 1268: end). 1269: 1270: 1271: retrieve_private_xml(Config) -> 1272: escalus:fresh_story(Config, [{alice, 1}], fun(Alice) -> 1273: NS = <<"alice:gdpr:ns">>, 1274: Content = <<"dGhlcmUgYmUgZHJhZ29ucw==">>, 1275: send_and_assert_private_stanza(Alice, NS, Content), 1276: ExpectedHeader = ["ns", "xml"], 1277: ExpectedItems = [#{ "ns" => binary_to_list(NS), 1278: "xml" => [{contains, binary_to_list(NS)}, 1279: {contains, binary_to_list(Content)}] } 1280: ], 1281: retrieve_and_validate_personal_data( 1282: Alice, Config, "private", ExpectedHeader, ExpectedItems) 1283: end). 1284: 1285: dont_retrieve_other_user_private_xml(Config) -> 1286: escalus:fresh_story(Config, [{alice, 1}, {bob, 1}], fun(Alice, Bob) -> 1287: AliceNS = <<"alice:gdpr:ns">>, 1288: AliceContent = <<"To be or not to be">>, 1289: BobNS = <<"bob:gdpr:ns">>, 1290: BobContent = <<"This is the winter of our discontent">>, 1291: send_and_assert_private_stanza(Alice, AliceNS, AliceContent), 1292: send_and_assert_private_stanza(Bob, BobNS, BobContent), 1293: ExpectedHeader = ["ns", "xml"], 1294: ExpectedItems = [#{ "ns" => binary_to_list(AliceNS), 1295: "xml" => [{contains, binary_to_list(AliceNS)}, 1296: {contains, binary_to_list(AliceContent)}] } 1297: ], 1298: retrieve_and_validate_personal_data( 1299: Alice, Config, "private", ExpectedHeader, ExpectedItems) 1300: end). 1301: 1302: retrieve_multiple_private_xmls(Config) -> 1303: escalus:fresh_story(Config, [{alice, 1}], fun(Alice) -> 1304: NSsAndContents = [ 1305: {<<"alice:gdpr:ns1">>, <<"You do not talk about FIGHT CLUB.">>}, 1306: {<<"alice:gdpr:ns2">>, <<"You do not talk about FIGHT CLUB.">>}, 1307: {<<"alice:gdpr:ns3">>, <<"If someone says stop or goes limp," 1308: " taps out the fight is over.">>}, 1309: {<<"alice:gdpr:ns4">>, <<"Only two guys to a fight.">>}, 1310: {<<"alice:gdpr:ns5">>, <<"One fight at a time.">>} 1311: ], 1312: lists:foreach( 1313: fun({NS, Content}) -> 1314: send_and_assert_private_stanza(Alice, NS, Content) 1315: end, NSsAndContents), 1316: ExpectedHeader = ["ns", "xml"], 1317: ExpectedItems = lists:map( 1318: fun({NS, Content}) -> 1319: #{ "ns" => binary_to_list(NS), 1320: "xml" => [{contains, binary_to_list(NS)}, 1321: {contains, binary_to_list(Content)}]} 1322: end, NSsAndContents), 1323: 1324: retrieve_and_validate_personal_data( 1325: Alice, Config, "private", ExpectedHeader, ExpectedItems) 1326: end). 1327: 1328: retrieve_inbox_muclight(Config) -> 1329: escalus:fresh_story(Config, [{alice, 1}, {bob, 1}], fun(Alice, Bob) -> 1330: muc_light_helper:given_muc_light_room(?ROOM, Alice, [{Bob, member}]), 1331: Domain = muc_light_helper:muc_host(), 1332: 1333: Body = <<"Are you sure?">>, 1334: Res = muc_light_helper:when_muc_light_message_is_sent(Alice, ?ROOM, Body, <<"9128">>), 1335: muc_light_helper:then_muc_light_message_is_received_by([Alice, Bob], Res), 1336: ExpectedHeader = ["jid", "content", "unread_count", "timestamp"], 1337: ExpectedAliceItems = [#{ "jid" => [{contains, <<?ROOM/binary, $@, Domain/binary>>}], 1338: "unread_count" => "0" }], 1339: %% MUC Light affiliations are also stored in inbox 1340: ExpectedBobItems = [#{ "jid" => [{contains, <<?ROOM/binary, $@, Domain/binary>>}], 1341: "unread_count" => "2" }], 1342: 1343: retrieve_and_validate_personal_data( 1344: Alice, Config, "inbox", ExpectedHeader, ExpectedAliceItems), 1345: retrieve_and_validate_personal_data( 1346: Bob, Config, "inbox", ExpectedHeader, ExpectedBobItems), 1347: 1348: StanzaDestroy = escalus_stanza:to(escalus_stanza:iq_set(?NS_MUC_LIGHT_DESTROY, []), room_bin_jid(?ROOM)), 1349: escalus:send(Alice, StanzaDestroy), 1350: ok 1351: end). 1352: 1353: retrieve_inbox_muc(Config) -> 1354: escalus:fresh_story(Config, [{alice, 1}, {bob, 1}], fun(Alice, Bob) -> 1355: {ok, Room} = given_fresh_muc_room(Alice#client.props, []), 1356: Users = [Alice, Bob], 1357: Msg = <<"Hi Room!">>, 1358: Id = <<"MyID">>, 1359: RoomAddr = muc_helper:room_address(Room), 1360: 1361: inbox_helper:enter_room(Room, Users), 1362: inbox_helper:make_members(Room, Alice, [Bob]), 1363: Stanza = escalus_stanza:set_id( 1364: escalus_stanza:groupchat_to(RoomAddr, Msg), Id), 1365: escalus:send(Bob, Stanza), 1366: inbox_helper:wait_for_groupchat_msg(Users), 1367: 1368: ExpectedHeader = ["jid", "content", "unread_count", "timestamp"], 1369: 1370: ExpectedBobItems = [#{ 1371: "content" => [{contains, Msg}], 1372: "jid" => [{contains, RoomAddr}], 1373: "unread_count" => "0" }], 1374: 1375: retrieve_and_validate_personal_data( 1376: Bob, Config, "inbox", ExpectedHeader, ExpectedBobItems), 1377: ExpectedAliceItems = [#{ 1378: "content" => [{contains, Msg}], 1379: "jid" => [{contains, RoomAddr}], 1380: "unread_count" => "1" }], 1381: 1382: retrieve_and_validate_personal_data( 1383: Alice, Config, "inbox", ExpectedHeader, ExpectedAliceItems), 1384: ok 1385: end). 1386: 1387: retrieve_inbox(Config) -> 1388: escalus:fresh_story(Config, [{alice, 1}, {bob, 1}], fun(Alice, Bob) -> 1389: BobU = escalus_utils:jid_to_lower(escalus_client:username(Bob)), 1390: BobS = escalus_utils:jid_to_lower(escalus_client:server(Bob)), 1391: AliceU = escalus_utils:jid_to_lower(escalus_client:username(Alice)), 1392: AliceS = escalus_utils:jid_to_lower(escalus_client:server(Alice)), 1393: Body = <<"With spam?">>, 1394: send_and_assert_is_chat_message(Bob, Alice, Body), 1395: ExpectedHeader = ["jid", "content", "unread_count", "timestamp"], 1396: ExpectedAliceItems = [#{ "content" => [{contains, Body}], 1397: "jid" => [{contains, BobS}, 1398: {contains, BobU}], 1399: "unread_count" => "1" }], 1400: ExpectedBobItems = [#{ "content" => [{contains, Body}], 1401: "jid" => [{contains, AliceS}, 1402: {contains, AliceU}], 1403: "unread_count" => "0" }], 1404: retrieve_and_validate_personal_data( 1405: Alice, Config, "inbox", ExpectedHeader, ExpectedAliceItems), 1406: retrieve_and_validate_personal_data( 1407: Bob, Config, "inbox", ExpectedHeader, ExpectedBobItems) 1408: end). 1409: 1410: remove_inbox(Config) -> 1411: escalus:fresh_story(Config, [{alice, 1}, {bob, 1}], fun(Alice, Bob) -> 1412: AliceU = escalus_utils:jid_to_lower(escalus_client:username(Alice)), 1413: AliceS = escalus_utils:jid_to_lower(escalus_client:server(Alice)), 1414: Body = <<"With spam?">>, 1415: send_and_assert_is_chat_message(Bob, Alice, Body), 1416: 1417: ExpectedHeader = ["jid", "content", "unread_count", "timestamp"], 1418: 1419: unregister(Alice, Config), 1420: 1421: assert_personal_data_via_rpc(Alice, [{inbox, ExpectedHeader, []}]), 1422: 1423: ExpectedBobItems = [ 1424: #{ "content" => [{contains, Body}], 1425: "jid" => [{contains, AliceS}, 1426: {contains, AliceU}], 1427: "unread_count" => "0" } 1428: ], 1429: retrieve_and_validate_personal_data( 1430: Bob, Config, "inbox", ExpectedHeader, ExpectedBobItems) 1431: end). 1432: 1433: remove_inbox_muclight(Config) -> 1434: escalus:fresh_story(Config, [{alice, 1}, {bob, 1}], fun(Alice, Bob) -> 1435: Domain = muc_light_helper:muc_host(), 1436: Room = <<"ttt2">>, 1437: muc_light_helper:given_muc_light_room(Room, Alice, [{Bob, member}]), 1438: 1439: Body = <<"Are you sure?">>, 1440: Res = muc_light_helper:when_muc_light_message_is_sent(Alice, Room , Body, <<"9128">>), 1441: muc_light_helper:then_muc_light_message_is_received_by([Alice, Bob], Res), 1442: 1443: ExpectedHeader = ["jid", "content", "unread_count", "timestamp"], 1444: 1445: unregister(Alice, Config), 1446: 1447: %% MUC Light affiliations are also stored in inbox 1448: %% 1. Added to the room 1449: %% 2. Message 1450: %% 3. Aff change: Alice -> none, Bob -> owner 1451: %% Writing aff changes to inbox is enabled by default 1452: ExpectedBobItems = [#{ 1453: "jid" => [{contains, <<Room/binary, $@, Domain/binary>>}], 1454: "unread_count" => "3" } 1455: ], 1456: 1457: retrieve_and_validate_personal_data( 1458: Bob, Config, "inbox", ExpectedHeader, ExpectedBobItems), 1459: 1460: assert_personal_data_via_rpc(Alice, [{inbox, ExpectedHeader, []}]), 1461: 1462: timer:sleep(5000), 1463: StanzaDestroy = escalus_stanza:to(escalus_stanza:iq_set(?NS_MUC_LIGHT_DESTROY, []), 1464: room_bin_jid(Room)), 1465: escalus:send(Alice, StanzaDestroy), 1466: ok 1467: end). 1468: 1469: remove_inbox_muc(Config) -> 1470: escalus:fresh_story(Config, [{alice, 1}, {bob, 1}], fun(Alice, Bob) -> 1471: {ok, Room} = given_fresh_muc_room(Alice#client.props, []), 1472: 1473: Users = [Alice, Bob], 1474: Msg = <<"Hi Room!">>, 1475: Id = <<"MyID">>, 1476: RoomAddr = muc_helper:room_address(Room), 1477: 1478: inbox_helper:enter_room(Room, Users), 1479: inbox_helper:make_members(Room, Alice, [Bob]), 1480: Stanza = escalus_stanza:set_id( 1481: escalus_stanza:groupchat_to(RoomAddr, Msg), Id), 1482: escalus:send(Bob, Stanza), 1483: inbox_helper:wait_for_groupchat_msg(Users), 1484: 1485: ExpectedHeader = ["jid", "content", "unread_count", "timestamp"], 1486: 1487: unregister(Alice, Config), 1488: 1489: escalus:wait_for_stanza(Bob), 1490: assert_personal_data_via_rpc(Alice, [{inbox, ExpectedHeader, []}]), 1491: 1492: ExpectedBobItems = [#{ 1493: "content" => [{contains, Msg}], 1494: "jid" => [{contains, RoomAddr}], 1495: "unread_count" => "0" }], 1496: 1497: retrieve_and_validate_personal_data( 1498: Bob, Config, "inbox", ExpectedHeader, ExpectedBobItems), 1499: ok 1500: end). 1501: 1502: retrieve_inbox_for_multiple_messages(Config) -> 1503: escalus:fresh_story(Config, [{alice, 1}, {bob, 1}], fun(Alice, Bob) -> 1504: Bodies = [ <<"Nobody exists on purpose.">>, 1505: <<"Nobody belongs anywhere.">>, 1506: <<"We're all going to die.">>, 1507: <<"Come watch TV.">>], 1508: lists:foreach(fun(Body) -> send_and_assert_is_chat_message(Bob, Alice, Body) end, Bodies), 1509: BobU = escalus_utils:jid_to_lower(escalus_client:username(Bob)), 1510: BobS = escalus_utils:jid_to_lower(escalus_client:server(Bob)), 1511: 1512: ExpectedHeader = ["jid", "content", "unread_count", "timestamp"], 1513: ExpectedAliceItems = [#{ "content" => [{contains, lists:last(Bodies)}], 1514: "jid" => [{contains, BobS}, 1515: {contains, BobU}], 1516: "unread_count" => integer_to_list(length(Bodies)) }], 1517: retrieve_and_validate_personal_data( 1518: Alice, Config, "inbox", ExpectedHeader, ExpectedAliceItems) 1519: end). 1520: 1521: retrieve_logs(Config) -> 1522: escalus:fresh_story(Config, [{alice, 1}], 1523: fun(Alice) -> 1524: User = escalus_client:username(Alice), 1525: Domain = escalus_client:server(Alice), 1526: JID = string:to_upper(binary_to_list(escalus_client:short_jid(Alice))), 1527: #{node := MIM2NodeName} = MIM2Node = distributed_helper:mim2(), 1528: mongoose_helper:successful_rpc(net_kernel, connect_node, [MIM2NodeName]), 1529: mongoose_helper:successful_rpc(MIM2Node, error_logger, error_msg, 1530: ["event=disturbance_in_the_force, jid=~s", [JID]]), 1531: Dir = request_and_unzip_personal_data(User, Domain, Config), 1532: Filename = filename:join(Dir, "logs-" ++ atom_to_list(MIM2NodeName) ++ ".txt"), 1533: {ok, Content} = file:read_file(Filename), 1534: {match, _} = re:run(Content, "disturbance_in_the_force") 1535: end). 1536: 1537: %% ------------------------------------------------------------- 1538: %% Internal functions 1539: %% ------------------------------------------------------------- 1540: 1541: assert_personal_data_via_rpc(Client, ExpectedPersonalDataEntries) -> 1542: ExpectedKeys = [ Key || {Key, _, _} <- ExpectedPersonalDataEntries ], 1543: 1544: %% We use wait_until here, because e.g. the deletion in ElasticSearch 1545: %% sometimes is applied with a delay (i.e. immediately after successful deletion 1546: %% the data retrieval still returned valid entries) 1547: mongoose_helper:wait_until( 1548: fun() -> 1549: get_personal_data_via_rpc(Client, ExpectedKeys) 1550: end, ExpectedPersonalDataEntries). 1551: 1552: get_personal_data_via_rpc(Client, ExpectedKeys) -> 1553: ClientU = escalus_utils:jid_to_lower(escalus_client:username(Client)), 1554: ClientS = escalus_utils:jid_to_lower(escalus_client:server(Client)), 1555: AllPersonalData = mongoose_helper:successful_rpc( 1556: gdpr_api, get_data_from_modules, [ClientU, ClientS]), 1557: %% We don't use lists:filter/2 because this line also ensures order 1558: [ lists:keyfind(Key, 1, AllPersonalData) || Key <- ExpectedKeys ]. 1559: 1560: retrieve_and_validate_personal_data(User, Config, FilePrefix, ExpectedHeader, ExpectedItems) -> 1561: Dir = retrieve_all_personal_data(User, Config), 1562: validate_personal_data(Dir, FilePrefix, ExpectedHeader, ExpectedItems, ExpectedHeader). 1563: 1564: retrieve_and_validate_personal_data(User, Config, FilePrefix, ExpectedHeader, ExpectedItems, SortBy) -> 1565: Dir = retrieve_all_personal_data(User, Config), 1566: validate_personal_data(Dir, FilePrefix, ExpectedHeader, ExpectedItems, SortBy). 1567: 1568: validate_personal_data(Dir, FilePrefix, ExpectedHeader, ExpectedItems, SortBy) -> 1569: PersonalCSV = decode_personal_data(Dir, FilePrefix), 1570: UnsortedMaps = csv_to_maps(ExpectedHeader, PersonalCSV), 1571: PersonalMaps = lists:sort(get_sort_fn(SortBy), UnsortedMaps), 1572: try validate_personal_maps(PersonalMaps, ExpectedItems) of 1573: _ -> ok 1574: catch 1575: C:R:S -> 1576: ct:fail(#{ 1577: class => C, 1578: reason => R, 1579: stacktrace => S, 1580: sorted_by => SortBy, 1581: personal_maps => PersonalMaps, 1582: expected_items => ExpectedItems 1583: }) 1584: end. 1585: 1586: 1587: get_sort_fn(SortBy) when is_list(SortBy) -> 1588: %% if SortBy is [], than original list remains unsorted. 1589: fun(Map1, Map2) -> compare_maps(SortBy, Map1, Map2) end; 1590: get_sort_fn(SortFn) when is_function(SortFn, 2) -> 1591: SortFn. 1592: 1593: compare_maps([], _, _) -> true; 1594: compare_maps([Key | T], Map1, Map2) -> 1595: #{Key:=Val1} = Map1, 1596: #{Key:=Val2} = Map2, 1597: if 1598: Val1 =:= Val2 -> compare_maps(T, Map1, Map2); 1599: Val1 > Val2 -> false; 1600: Val1 < Val2 -> true 1601: end. 1602: 1603: muc_msg_first(MucJid) -> 1604: MucJidNormalized = escalus_utils:jid_to_lower(to_binary(MucJid)), 1605: N = erlang:byte_size(MucJidNormalized), 1606: fun(#{"from" := JID1}, #{"from" := JID2}) -> 1607: Jid1Normalized = escalus_utils:jid_to_lower(to_binary(JID1)), 1608: Jid2Normalized = escalus_utils:jid_to_lower(to_binary(JID2)), 1609: case {Jid1Normalized, Jid2Normalized} of 1610: {<<MucJidNormalized:N/binary, _/binary>>, <<MucJidNormalized:N/binary, _/binary>>} -> 1611: Jid1Normalized =< Jid2Normalized; 1612: {<<MucJidNormalized:N/binary, _/binary>>, _} -> 1613: true; 1614: {_, <<MucJidNormalized:N/binary, _/binary>>} -> 1615: false; 1616: {_, _} -> 1617: Jid1Normalized =< Jid2Normalized 1618: end 1619: end. 1620: 1621: csv_to_maps(ExpectedHeader, [ExpectedHeader | Rows]) -> 1622: lists:foldl(fun(Row, Maps) -> [ csv_row_to_map(ExpectedHeader, Row) | Maps ] end, [], Rows). 1623: 1624: csv_row_to_map(Header, Row) -> 1625: maps:from_list(lists:zip(Header, Row)). 1626: 1627: validate_personal_maps(PersonalMaps, ExpectedItems) -> 1628: validate_sorted_personal_maps(PersonalMaps, ExpectedItems). 1629: 1630: validate_sorted_personal_maps([], []) -> ok; 1631: validate_sorted_personal_maps(UnexpectedRecords, []) -> 1632: erlang:error("Unexpected records left ~p", [UnexpectedRecords]); 1633: validate_sorted_personal_maps([Map | RMaps], [Checks | RChecks]) -> 1634: maps:fold(fun(K, Conditions, _) -> 1635: validate_personal_item(maps:get(K, Map), Conditions) 1636: end, ok, Checks), 1637: validate_sorted_personal_maps(RMaps, RChecks). 1638: 1639: validate_personal_item(_Value, []) -> 1640: ok; 1641: validate_personal_item(ExactValue, ExactValue) -> 1642: ok; 1643: validate_personal_item(Value, [{jid, ExpectedValue} | RConditions]) -> 1644: JID = escalus_utils:jid_to_lower(to_binary(Value)), 1645: JID = escalus_utils:jid_to_lower(to_binary(ExpectedValue)), 1646: validate_personal_item(Value, RConditions); 1647: validate_personal_item(Value, [{contains, String} | RConditions]) -> 1648: {match, _} = re:run(Value, String), 1649: validate_personal_item(Value, RConditions); 1650: validate_personal_item(Value, [{validate, Validator} | RConditions]) when is_function(Validator) -> 1651: true = Validator(Value), 1652: validate_personal_item(Value, RConditions). 1653: 1654: to_binary(List) when is_list(List) -> list_to_binary(List); 1655: to_binary(Binary) when is_binary(Binary) -> Binary. 1656: 1657: decode_personal_data(Dir, FilePrefix) -> 1658: CSVPath = filename:join(Dir, FilePrefix ++ ".csv"), 1659: {ok, Content} = file:read_file(CSVPath), 1660: % We expect non-empty list because it must contain at least header with columns names 1661: [_ | _] = csv:decode_binary(Content). 1662: 1663: refute_personal_data(Client, Config, FilePrefix) -> 1664: Dir = retrieve_all_personal_data(Client, Config), 1665: refute_personal_data(Dir, FilePrefix). 1666: 1667: refute_personal_data(Dir, FilePrefix) -> 1668: CSVPath = filename:join(Dir, FilePrefix ++ ".csv"), 1669: false = filelib:is_regular(CSVPath). 1670: 1671: retrieve_all_personal_data(Client, Config) -> 1672: User = escalus_client:username(Client), 1673: Domain = escalus_client:server(Client), 1674: request_and_unzip_personal_data(User, Domain, Config). 1675: 1676: request_and_unzip_personal_data(User, Domain, Config) -> 1677: {Filename, Res} = retrieve_personal_data(User, Domain, Config), 1678: ParsedResult = get_ok_value([data, gdpr, retrievePersonalData], Res), 1679: ?assertEqual(<<"Data retrieved">>, ParsedResult), 1680: FullPath = get_mim_cwd() ++ "/" ++ Filename, 1681: Dir = make_dir_name(Filename, User), 1682: ct:log("extracting logs ~s", [Dir]), 1683: {ok, _} = zip:extract(FullPath, [{cwd, Dir}]), 1684: Dir. 1685: 1686: make_dir_name(Filename, User) when is_binary(User) -> 1687: make_dir_name(Filename, binary_to_list(User)); 1688: make_dir_name(Filename, User) when is_list(User) -> 1689: Filename ++ "." ++ User ++ ".unzipped". 1690: 1691: retrieve_personal_data(User, Domain, Config) -> 1692: Filename = random_filename(Config), 1693: Vars = #{<<"username">> => User, <<"domain">> => Domain, 1694: <<"resultFilepath">> => list_to_binary(Filename)}, 1695: Result = execute_command(<<"gdpr">>, <<"retrievePersonalData">>, Vars, Config), 1696: {Filename, Result}. 1697: 1698: unregister(Client, Config) -> 1699: User = escalus_client:full_jid(Client), 1700: Path = [data, account, removeUser, message], 1701: Vars = #{<<"user">> => User}, 1702: Resp = execute_command(<<"account">>, <<"removeUser">>, Vars, Config), 1703: ?assertNotEqual(nomatch, binary:match(get_ok_value(Path, Resp), 1704: <<"successfully unregister">>)). 1705: 1706: random_filename(Config) -> 1707: TCName = atom_to_list(?config(tc_name, Config)), 1708: TCName ++ "." ++ integer_to_list(erlang:system_time()) ++ ".zip". 1709: 1710: get_mim_cwd() -> 1711: {ok, Cwd} = rpc(mim(), file, get_cwd, []), 1712: Cwd. 1713: 1714: delete_files() -> 1715: Cwd = get_mim_cwd(), 1716: {ok, Filenames} = rpc(mim(), file, list_dir, [Cwd]), 1717: FilteredFilenames = lists:filter( 1718: fun is_file_to_be_deleted/1, 1719: Filenames), 1720: lists:foreach( 1721: fun(Filename) -> rpc(mim(), file, delete, [Cwd ++ "/" ++ Filename]) end, 1722: FilteredFilenames), 1723: ok. 1724: 1725: is_file_to_be_deleted(Filename) -> 1726: DeletableRegexes = ["\.csv", "\.zip"], 1727: lists:any( 1728: fun(Regex) -> 1729: re:run(Filename, Regex) =/= nomatch 1730: end, 1731: DeletableRegexes). 1732: 1733: pubsub_payloads_row_map(Node, ItemId, Payload) -> 1734: #{"node_name" => binary_to_list(Node), "item_id" => ItemId, "payload" => Payload}. 1735: 1736: pubsub_nodes_row_map(Node, Type) -> 1737: #{"node_name" => binary_to_list(Node), "type" => Type}. 1738: 1739: pubsub_subscription_row_map(Node) -> 1740: #{"node_name" => binary_to_list(Node)}. 1741: 1742: make_pep_node_info(Client, NodeName) -> 1743: {escalus_utils:jid_to_lower(escalus_utils:get_short_jid(Client)), NodeName}. 1744: 1745: item_content(Data) -> 1746: Bin = item_content_xml(Data), 1747: {Bin, binary_to_list(exml:to_binary(Bin))}. 1748: 1749: item_content_xml(Data) -> 1750: #xmlel{name = <<"entry">>, 1751: attrs = [{<<"xmlns">>, <<"http://www.w3.org/2005/Atom">>}], 1752: children = [#xmlcdata{content = Data}]}. 1753: 1754: send_and_assert_private_stanza(User, NS, Content) -> 1755: XML = #xmlel{ name = <<"fingerprint">>, 1756: attrs = [{<<"xmlns">>, NS}], 1757: children = [#xmlcdata{ content = Content }]}, 1758: PrivateStanza = escalus_stanza:private_set(XML), 1759: escalus_client:send(User, PrivateStanza), 1760: escalus:assert(is_iq_result, [PrivateStanza], escalus_client:wait_for_stanza(User)). 1761: 1762: send_and_assert_is_chat_message(UserFrom, UserTo, Body) -> 1763: escalus:send(UserFrom, escalus_stanza:chat_to(UserTo, Body)), 1764: Msg = escalus:wait_for_stanza(UserTo), 1765: escalus:assert(is_chat_message, [Body], Msg). 1766: 1767: validate_datetime(TimeStr) -> 1768: [Date, Time] = string:tokens(TimeStr, "T"), 1769: validate_date(Date), 1770: validate_time(Time). 1771: 1772: validate_date(Date) -> 1773: [Y, M, D] = string:tokens(Date, "-"), 1774: Date1 = {list_to_integer(Y), list_to_integer(M), list_to_integer(D)}, 1775: calendar:valid_date(Date1). 1776: 1777: validate_time(Time) -> 1778: [T | _] = string:tokens(Time, "Z"), 1779: validate_time1(T). 1780: 1781: 1782: validate_time1(Time) -> 1783: [H, M, S] = string:tokens(Time, ":"), 1784: check_list([{H, 24}, {M, 60}, {S, 60}]). 1785: 1786: check_list(List) -> 1787: lists:all(fun({V, L}) -> I = list_to_integer(V), I >= 0 andalso I < L end, List). 1788: 1789: expected_header(mod_roster) -> ["jid", "name", "subscription", 1790: "ask", "groups", "askmessage", "xs"]. 1791: 1792: given_fresh_muc_room(UserSpec, RoomOpts) -> 1793: Username = proplists:get_value(username, UserSpec), 1794: RoomName = muc_helper:fresh_room_name(Username), 1795: From = muc_helper:generate_rpc_jid({user, UserSpec}), 1796: muc_helper:create_instant_room(RoomName, From, Username, RoomOpts), 1797: {ok, RoomName}. 1798: 1799: send_receive_muc_private_message(Room, Domain, {User1, Nickname1}, {User2, Nickname2}, Text) -> 1800: RoomPrivAddrUser1 = <<Room/binary, "@", Domain/binary, "/", Nickname1/binary>>, 1801: RoomPrivAddrUser2 = <<Room/binary, "@", Domain/binary, "/", Nickname2/binary>>, 1802: Msg = escalus_stanza:chat_to(RoomPrivAddrUser2, Text), 1803: escalus:send(User1, Msg), 1804: PMStanza = escalus:wait_for_stanza(User2), 1805: escalus:assert(is_chat_message_from_to, 1806: [RoomPrivAddrUser1, escalus_client:full_jid(User2), Text], PMStanza), 1807: {RoomPrivAddrUser1, RoomPrivAddrUser2}.