From 38c8f852bf6da6d17cd7e4a3e63d9fc62581b767 Mon Sep 17 00:00:00 2001 From: Greyson Parrelli Date: Fri, 20 Jun 2025 11:47:54 -0400 Subject: [PATCH] Do most of the proto and database groundwork for the new mediaName. --- .../backupTests/account_data_00.binproto | Bin 257 -> 238 bytes .../backupTests/account_data_01.binproto | Bin 543 -> 542 bytes .../backupTests/account_data_02.binproto | Bin 515 -> 563 bytes .../backupTests/account_data_03.binproto | Bin 547 -> 548 bytes .../backupTests/account_data_04.binproto | Bin 450 -> 499 bytes .../backupTests/account_data_05.binproto | Bin 566 -> 560 bytes .../backupTests/account_data_06.binproto | Bin 432 -> 486 bytes .../backupTests/account_data_07.binproto | Bin 449 -> 470 bytes .../backupTests/account_data_08.binproto | Bin 432 -> 414 bytes .../backupTests/account_data_09.binproto | Bin 332 -> 345 bytes .../backupTests/account_data_10.binproto | Bin 463 -> 459 bytes .../backupTests/account_data_11.binproto | Bin 443 -> 460 bytes .../backupTests/account_data_12.binproto | Bin 334 -> 321 bytes .../backupTests/account_data_13.binproto | Bin 468 -> 484 bytes .../backupTests/account_data_14.binproto | Bin 460 -> 449 bytes .../backupTests/account_data_15.binproto | Bin 402 -> 422 bytes .../backupTests/account_data_16.binproto | Bin 412 -> 401 bytes .../backupTests/account_data_17.binproto | Bin 447 -> 459 bytes .../backupTests/account_data_18.binproto | Bin 336 -> 328 bytes .../backupTests/account_data_19.binproto | Bin 440 -> 461 bytes .../backupTests/account_data_20.binproto | Bin 413 -> 395 bytes .../backupTests/account_data_21.binproto | Bin 407 -> 422 bytes .../backupTests/account_data_22.binproto | Bin 466 -> 462 bytes .../backupTests/account_data_23.binproto | Bin 460 -> 477 bytes .../backupTests/account_data_24.binproto | Bin 325 -> 312 bytes .../backupTests/account_data_25.binproto | Bin 449 -> 465 bytes .../backupTests/account_data_26.binproto | Bin 468 -> 457 bytes .../backupTests/account_data_27.binproto | Bin 338 -> 356 bytes .../assets/backupTests/chat_00.binproto | Bin 621 -> 602 bytes .../assets/backupTests/chat_01.binproto | Bin 583 -> 645 bytes .../assets/backupTests/chat_02.binproto | Bin 671 -> 650 bytes .../assets/backupTests/chat_03.binproto | Bin 569 -> 631 bytes .../assets/backupTests/chat_04.binproto | Bin 667 -> 646 bytes .../assets/backupTests/chat_05.binproto | Bin 583 -> 647 bytes .../assets/backupTests/chat_06.binproto | Bin 530 -> 528 bytes .../assets/backupTests/chat_07.binproto | Bin 538 -> 539 bytes .../assets/backupTests/chat_08.binproto | Bin 544 -> 542 bytes .../assets/backupTests/chat_09.binproto | Bin 524 -> 526 bytes .../assets/backupTests/chat_10.binproto | Bin 544 -> 541 bytes .../assets/backupTests/chat_11.binproto | Bin 538 -> 540 bytes .../assets/backupTests/chat_12.binproto | Bin 530 -> 528 bytes .../assets/backupTests/chat_13.binproto | Bin 538 -> 539 bytes .../assets/backupTests/chat_14.binproto | Bin 544 -> 542 bytes .../assets/backupTests/chat_15.binproto | Bin 524 -> 526 bytes .../assets/backupTests/chat_16.binproto | Bin 544 -> 541 bytes .../assets/backupTests/chat_17.binproto | Bin 538 -> 540 bytes .../assets/backupTests/chat_18.binproto | Bin 530 -> 528 bytes .../assets/backupTests/chat_19.binproto | Bin 538 -> 539 bytes .../assets/backupTests/chat_20.binproto | Bin 544 -> 542 bytes .../assets/backupTests/chat_21.binproto | Bin 524 -> 526 bytes .../assets/backupTests/chat_22.binproto | Bin 544 -> 541 bytes .../assets/backupTests/chat_23.binproto | Bin 538 -> 540 bytes .../assets/backupTests/chat_24.binproto | Bin 530 -> 528 bytes .../assets/backupTests/chat_25.binproto | Bin 538 -> 539 bytes .../assets/backupTests/chat_26.binproto | Bin 544 -> 542 bytes .../backupTests/chat_folder_00.binproto | Bin 925 -> 923 bytes .../backupTests/chat_folder_01.binproto | Bin 919 -> 921 bytes .../backupTests/chat_folder_02.binproto | Bin 933 -> 931 bytes .../backupTests/chat_folder_03.binproto | Bin 919 -> 921 bytes .../chat_item_contact_message_00.binproto | Bin 591 -> 582 bytes .../chat_item_contact_message_01.binproto | Bin 770 -> 742 bytes .../chat_item_contact_message_02.binproto | Bin 956 -> 1031 bytes .../chat_item_contact_message_03.binproto | Bin 726 -> 689 bytes .../chat_item_contact_message_04.binproto | Bin 706 -> 769 bytes .../chat_item_contact_message_05.binproto | Bin 1021 -> 1005 bytes .../chat_item_contact_message_06.binproto | Bin 655 -> 720 bytes .../chat_item_contact_message_07.binproto | Bin 588 -> 581 bytes .../chat_item_contact_message_08.binproto | Bin 762 -> 732 bytes .../chat_item_contact_message_09.binproto | Bin 965 -> 1038 bytes .../chat_item_contact_message_10.binproto | Bin 724 -> 689 bytes .../chat_item_contact_message_11.binproto | Bin 699 -> 762 bytes .../chat_item_contact_message_12.binproto | Bin 1026 -> 1010 bytes .../chat_item_contact_message_13.binproto | Bin 657 -> 722 bytes .../chat_item_contact_message_14.binproto | Bin 581 -> 574 bytes .../chat_item_direct_story_reply_00.binproto | Bin 599 -> 569 bytes .../chat_item_direct_story_reply_01.binproto | Bin 740 -> 692 bytes .../chat_item_direct_story_reply_02.binproto | Bin 674 -> 758 bytes .../chat_item_direct_story_reply_03.binproto | Bin 761 -> 696 bytes .../chat_item_direct_story_reply_04.binproto | Bin 657 -> 712 bytes .../chat_item_direct_story_reply_05.binproto | Bin 665 -> 691 bytes .../chat_item_direct_story_reply_06.binproto | Bin 550 -> 550 bytes .../chat_item_direct_story_reply_07.binproto | Bin 571 -> 571 bytes .../chat_item_direct_story_reply_08.binproto | Bin 581 -> 581 bytes .../chat_item_direct_story_reply_09.binproto | Bin 556 -> 554 bytes .../chat_item_direct_story_reply_10.binproto | Bin 576 -> 578 bytes .../chat_item_direct_story_reply_11.binproto | Bin 625 -> 597 bytes .../chat_item_direct_story_reply_12.binproto | Bin 720 -> 669 bytes .../chat_item_direct_story_reply_13.binproto | Bin 663 -> 748 bytes .../chat_item_direct_story_reply_14.binproto | Bin 792 -> 727 bytes ..._direct_story_reply_with_edits_00.binproto | Bin 669 -> 669 bytes ..._direct_story_reply_with_edits_01.binproto | Bin 971 -> 1019 bytes ..._direct_story_reply_with_edits_02.binproto | Bin 776 -> 836 bytes ..._direct_story_reply_with_edits_03.binproto | Bin 973 -> 1014 bytes ..._direct_story_reply_with_edits_04.binproto | Bin 757 -> 818 bytes ..._direct_story_reply_with_edits_05.binproto | Bin 899 -> 979 bytes ..._direct_story_reply_with_edits_06.binproto | Bin 646 -> 646 bytes ..._direct_story_reply_with_edits_07.binproto | Bin 801 -> 881 bytes ..._direct_story_reply_with_edits_08.binproto | Bin 684 -> 684 bytes ..._direct_story_reply_with_edits_09.binproto | Bin 786 -> 866 bytes ..._direct_story_reply_with_edits_10.binproto | Bin 672 -> 672 bytes .../chat_item_gift_badge_00.binproto | Bin 884 -> 882 bytes .../chat_item_gift_badge_01.binproto | Bin 882 -> 884 bytes .../chat_item_gift_badge_02.binproto | Bin 874 -> 874 bytes .../chat_item_gift_badge_03.binproto | Bin 548 -> 548 bytes .../chat_item_gift_badge_04.binproto | Bin 879 -> 879 bytes .../chat_item_gift_badge_05.binproto | Bin 876 -> 876 bytes .../chat_item_gift_badge_06.binproto | Bin 881 -> 881 bytes .../chat_item_gift_badge_07.binproto | Bin 548 -> 548 bytes .../chat_item_gift_badge_08.binproto | Bin 872 -> 872 bytes .../chat_item_gift_badge_09.binproto | Bin 883 -> 881 bytes .../chat_item_gift_badge_10.binproto | Bin 881 -> 883 bytes .../chat_item_gift_badge_11.binproto | Bin 539 -> 539 bytes .../chat_item_gift_badge_12.binproto | Bin 879 -> 879 bytes .../chat_item_gift_badge_13.binproto | Bin 883 -> 883 bytes .../chat_item_gift_badge_14.binproto | Bin 876 -> 876 bytes ...up_change_chat_multiple_update_00.binproto | Bin 1196 -> 1196 bytes ...up_change_chat_multiple_update_01.binproto | Bin 1238 -> 1238 bytes ...up_change_chat_multiple_update_02.binproto | Bin 1198 -> 1198 bytes ...up_change_chat_multiple_update_03.binproto | Bin 1306 -> 1319 bytes ...up_change_chat_multiple_update_04.binproto | Bin 1202 -> 1202 bytes ...up_change_chat_multiple_update_05.binproto | Bin 1202 -> 1202 bytes ...up_change_chat_multiple_update_06.binproto | Bin 1218 -> 1216 bytes ...up_change_chat_multiple_update_07.binproto | Bin 1252 -> 1254 bytes ...up_change_chat_multiple_update_08.binproto | Bin 1202 -> 1202 bytes ..._item_group_change_chat_update_00.binproto | Bin 1152 -> 1152 bytes ..._item_group_change_chat_update_01.binproto | Bin 1152 -> 1152 bytes ..._item_group_change_chat_update_02.binproto | Bin 1152 -> 1152 bytes ..._item_group_change_chat_update_03.binproto | Bin 1152 -> 1152 bytes ..._item_group_change_chat_update_04.binproto | Bin 1152 -> 1152 bytes ..._item_group_change_chat_update_05.binproto | Bin 1164 -> 1164 bytes ..._item_group_change_chat_update_06.binproto | Bin 1169 -> 1169 bytes ..._item_group_change_chat_update_07.binproto | Bin 1165 -> 1165 bytes ..._item_group_change_chat_update_08.binproto | Bin 1154 -> 1154 bytes ..._item_group_change_chat_update_09.binproto | Bin 1152 -> 1152 bytes ..._item_group_change_chat_update_10.binproto | Bin 1152 -> 1152 bytes ..._item_group_change_chat_update_11.binproto | Bin 1208 -> 1159 bytes ..._item_group_change_chat_update_12.binproto | Bin 1182 -> 1191 bytes ..._item_group_change_chat_update_13.binproto | Bin 1172 -> 1225 bytes ..._item_group_change_chat_update_14.binproto | Bin 1154 -> 1154 bytes ..._item_group_change_chat_update_15.binproto | Bin 1154 -> 1154 bytes ..._item_group_change_chat_update_16.binproto | Bin 1154 -> 1154 bytes ..._item_group_change_chat_update_17.binproto | Bin 1154 -> 1154 bytes ..._item_group_change_chat_update_18.binproto | Bin 1154 -> 1154 bytes ..._item_group_change_chat_update_19.binproto | Bin 1154 -> 1154 bytes ..._item_group_change_chat_update_20.binproto | Bin 1154 -> 1154 bytes ..._item_group_change_chat_update_21.binproto | Bin 1152 -> 1152 bytes ..._item_group_change_chat_update_22.binproto | Bin 1172 -> 1170 bytes ..._item_group_change_chat_update_23.binproto | Bin 1170 -> 1172 bytes ..._item_group_change_chat_update_24.binproto | Bin 1152 -> 1152 bytes ..._item_group_change_chat_update_25.binproto | Bin 1152 -> 1152 bytes ..._item_group_change_chat_update_26.binproto | Bin 1170 -> 1170 bytes ..._item_group_change_chat_update_27.binproto | Bin 1170 -> 1170 bytes ..._item_group_change_chat_update_28.binproto | Bin 1152 -> 1152 bytes ..._item_group_change_chat_update_29.binproto | Bin 1152 -> 1152 bytes ..._item_group_change_chat_update_30.binproto | Bin 1152 -> 1152 bytes ..._item_group_change_chat_update_31.binproto | Bin 1152 -> 1152 bytes ..._item_group_change_chat_update_32.binproto | Bin 1154 -> 1154 bytes ..._item_group_change_chat_update_33.binproto | Bin 1154 -> 1154 bytes ...chat_item_payment_notification_00.binproto | Bin 768 -> 763 bytes ...chat_item_payment_notification_01.binproto | Bin 841 -> 852 bytes ...chat_item_payment_notification_02.binproto | Bin 841 -> 818 bytes ...chat_item_payment_notification_03.binproto | Bin 647 -> 656 bytes ...chat_item_payment_notification_04.binproto | Bin 594 -> 591 bytes ...chat_item_payment_notification_05.binproto | Bin 653 -> 662 bytes ...chat_item_payment_notification_06.binproto | Bin 833 -> 810 bytes ...chat_item_payment_notification_07.binproto | Bin 831 -> 840 bytes ...chat_item_payment_notification_08.binproto | Bin 771 -> 768 bytes ...chat_item_payment_notification_09.binproto | Bin 658 -> 665 bytes ...chat_item_payment_notification_10.binproto | Bin 666 -> 645 bytes ...chat_item_payment_notification_11.binproto | Bin 638 -> 649 bytes ...chat_item_payment_notification_12.binproto | Bin 763 -> 760 bytes ...chat_item_payment_notification_13.binproto | Bin 842 -> 851 bytes ...chat_item_payment_notification_14.binproto | Bin 843 -> 820 bytes .../chat_item_remote_delete_00.binproto | Bin 548 -> 546 bytes .../chat_item_remote_delete_01.binproto | Bin 544 -> 546 bytes .../chat_item_remote_delete_02.binproto | Bin 536 -> 536 bytes .../chat_item_remote_delete_03.binproto | Bin 545 -> 545 bytes .../chat_item_remote_delete_04.binproto | Bin 543 -> 543 bytes .../chat_item_remote_delete_05.binproto | Bin 538 -> 538 bytes .../chat_item_remote_delete_06.binproto | Bin 543 -> 543 bytes .../chat_item_remote_delete_07.binproto | Bin 545 -> 545 bytes .../chat_item_remote_delete_08.binproto | Bin 536 -> 536 bytes .../chat_item_remote_delete_09.binproto | Bin 545 -> 543 bytes .../chat_item_remote_delete_10.binproto | Bin 543 -> 545 bytes .../chat_item_remote_delete_11.binproto | Bin 536 -> 536 bytes .../chat_item_remote_delete_12.binproto | Bin 543 -> 543 bytes .../chat_item_remote_delete_13.binproto | Bin 545 -> 545 bytes .../chat_item_remote_delete_14.binproto | Bin 538 -> 538 bytes ...tandard_message_formatted_text_00.binproto | Bin 956 -> 956 bytes ...tandard_message_formatted_text_01.binproto | Bin 972 -> 972 bytes ...tandard_message_formatted_text_02.binproto | Bin 974 -> 974 bytes ...tandard_message_formatted_text_03.binproto | Bin 1004 -> 1004 bytes ...tandard_message_formatted_text_04.binproto | Bin 1034 -> 1034 bytes ...tandard_message_formatted_text_05.binproto | Bin 1008 -> 1008 bytes ...tandard_message_formatted_text_06.binproto | Bin 972 -> 972 bytes ...tandard_message_formatted_text_07.binproto | Bin 1004 -> 1000 bytes ...tandard_message_formatted_text_08.binproto | Bin 958 -> 962 bytes ...tandard_message_formatted_text_09.binproto | Bin 1004 -> 1000 bytes ...tandard_message_formatted_text_10.binproto | Bin 1034 -> 1038 bytes ...tandard_message_formatted_text_11.binproto | Bin 1016 -> 1016 bytes ...tandard_message_formatted_text_12.binproto | Bin 972 -> 972 bytes ...tandard_message_formatted_text_13.binproto | Bin 986 -> 986 bytes ...tandard_message_formatted_text_14.binproto | Bin 968 -> 968 bytes ...tem_standard_message_long_text_00.binproto | Bin 711 -> 664 bytes ...tem_standard_message_long_text_01.binproto | Bin 636 -> 692 bytes ...tem_standard_message_long_text_02.binproto | Bin 760 -> 744 bytes ...tem_standard_message_long_text_03.binproto | Bin 605 -> 656 bytes ...tem_standard_message_long_text_04.binproto | Bin 729 -> 684 bytes ...tem_standard_message_long_text_05.binproto | Bin 660 -> 741 bytes ...tem_standard_message_long_text_06.binproto | Bin 716 -> 671 bytes ...tem_standard_message_long_text_07.binproto | Bin 628 -> 679 bytes ...tem_standard_message_long_text_08.binproto | Bin 750 -> 734 bytes ...tem_standard_message_long_text_09.binproto | Bin 614 -> 666 bytes ...tem_standard_message_long_text_10.binproto | Bin 739 -> 696 bytes ...tem_standard_message_long_text_11.binproto | Bin 649 -> 727 bytes ...tem_standard_message_long_text_12.binproto | Bin 706 -> 661 bytes ...tem_standard_message_long_text_13.binproto | Bin 637 -> 691 bytes ...tem_standard_message_long_text_14.binproto | Bin 762 -> 746 bytes ...chat_item_standard_message_sms_00.binproto | Bin 559 -> 561 bytes ...chat_item_standard_message_sms_01.binproto | Bin 659 -> 639 bytes ...chat_item_standard_message_sms_02.binproto | Bin 1049 -> 969 bytes ...chat_item_standard_message_sms_03.binproto | Bin 560 -> 558 bytes ...chat_item_standard_message_sms_04.binproto | Bin 654 -> 638 bytes ...chat_item_standard_message_sms_05.binproto | Bin 1055 -> 969 bytes ...chat_item_standard_message_sms_06.binproto | Bin 554 -> 558 bytes ...chat_item_standard_message_sms_07.binproto | Bin 660 -> 638 bytes ...chat_item_standard_message_sms_08.binproto | Bin 1049 -> 969 bytes ...chat_item_standard_message_sms_09.binproto | Bin 560 -> 556 bytes ...chat_item_standard_message_sms_10.binproto | Bin 654 -> 640 bytes ...chat_item_standard_message_sms_11.binproto | Bin 1053 -> 967 bytes ...chat_item_standard_message_sms_12.binproto | Bin 554 -> 558 bytes ...chat_item_standard_message_sms_13.binproto | Bin 660 -> 638 bytes ...chat_item_standard_message_sms_14.binproto | Bin 1051 -> 971 bytes ...rd_message_special_attachments_00.binproto | Bin 666 -> 629 bytes ...rd_message_special_attachments_01.binproto | Bin 684 -> 655 bytes ...rd_message_special_attachments_02.binproto | Bin 697 -> 656 bytes ...rd_message_special_attachments_03.binproto | Bin 663 -> 628 bytes ...rd_message_special_attachments_04.binproto | Bin 683 -> 652 bytes ...rd_message_special_attachments_05.binproto | Bin 699 -> 658 bytes ...rd_message_special_attachments_06.binproto | Bin 661 -> 626 bytes ...rd_message_special_attachments_07.binproto | Bin 685 -> 654 bytes ...rd_message_special_attachments_08.binproto | Bin 697 -> 656 bytes ...rd_message_special_attachments_09.binproto | Bin 663 -> 626 bytes ...rd_message_special_attachments_10.binproto | Bin 683 -> 654 bytes ...rd_message_special_attachments_11.binproto | Bin 697 -> 656 bytes ...rd_message_special_attachments_12.binproto | Bin 661 -> 626 bytes ...rd_message_special_attachments_13.binproto | Bin 685 -> 654 bytes ...rd_message_special_attachments_14.binproto | Bin 699 -> 658 bytes ...d_message_standard_attachments_00.binproto | Bin 663 -> 624 bytes ...d_message_standard_attachments_01.binproto | Bin 915 -> 1043 bytes ...d_message_standard_attachments_02.binproto | Bin 1234 -> 1281 bytes ...d_message_standard_attachments_03.binproto | Bin 645 -> 752 bytes ...d_message_standard_attachments_04.binproto | Bin 921 -> 932 bytes ...d_message_standard_attachments_05.binproto | Bin 1171 -> 1343 bytes ...d_message_standard_attachments_06.binproto | Bin 696 -> 648 bytes ...d_message_standard_attachments_07.binproto | Bin 929 -> 1083 bytes ...d_message_standard_attachments_08.binproto | Bin 1197 -> 1256 bytes ...d_message_standard_attachments_09.binproto | Bin 630 -> 709 bytes ...d_message_standard_attachments_10.binproto | Bin 958 -> 959 bytes ...d_message_standard_attachments_11.binproto | Bin 1182 -> 1382 bytes ...d_message_standard_attachments_12.binproto | Bin 658 -> 621 bytes ...d_message_standard_attachments_13.binproto | Bin 916 -> 1042 bytes ...d_message_standard_attachments_14.binproto | Bin 1236 -> 1283 bytes ...tem_standard_message_text_only_00.binproto | Bin 581 -> 568 bytes ...tem_standard_message_text_only_01.binproto | Bin 600 -> 590 bytes ...tem_standard_message_text_only_02.binproto | Bin 620 -> 637 bytes ...tem_standard_message_text_only_03.binproto | Bin 578 -> 567 bytes ...tem_standard_message_text_only_04.binproto | Bin 599 -> 587 bytes ...tem_standard_message_text_only_05.binproto | Bin 622 -> 639 bytes ...tem_standard_message_text_only_06.binproto | Bin 576 -> 565 bytes ...tem_standard_message_text_only_07.binproto | Bin 601 -> 589 bytes ...tem_standard_message_text_only_08.binproto | Bin 620 -> 637 bytes ...tem_standard_message_text_only_09.binproto | Bin 578 -> 565 bytes ...tem_standard_message_text_only_10.binproto | Bin 599 -> 589 bytes ...tem_standard_message_text_only_11.binproto | Bin 620 -> 637 bytes ...tem_standard_message_text_only_12.binproto | Bin 576 -> 565 bytes ...tem_standard_message_text_only_13.binproto | Bin 601 -> 589 bytes ...tem_standard_message_text_only_14.binproto | Bin 622 -> 639 bytes ...em_standard_message_with_edits_00.binproto | Bin 677 -> 614 bytes ...em_standard_message_with_edits_01.binproto | Bin 816 -> 812 bytes ...em_standard_message_with_edits_02.binproto | Bin 665 -> 660 bytes ...dard_message_with_link_preview_00.binproto | Bin 636 -> 631 bytes ...dard_message_with_link_preview_01.binproto | Bin 827 -> 866 bytes ...dard_message_with_link_preview_02.binproto | Bin 779 -> 763 bytes ...dard_message_with_link_preview_03.binproto | Bin 834 -> 862 bytes ...dard_message_with_link_preview_04.binproto | Bin 730 -> 759 bytes ...dard_message_with_link_preview_05.binproto | Bin 886 -> 859 bytes ...dard_message_with_link_preview_06.binproto | Bin 709 -> 723 bytes ...dard_message_with_link_preview_07.binproto | Bin 673 -> 703 bytes ...dard_message_with_link_preview_08.binproto | Bin 853 -> 827 bytes ...dard_message_with_link_preview_09.binproto | Bin 716 -> 729 bytes ...dard_message_with_link_preview_10.binproto | Bin 870 -> 932 bytes ...dard_message_with_link_preview_11.binproto | Bin 757 -> 723 bytes ...dard_message_with_link_preview_12.binproto | Bin 819 -> 823 bytes ...dard_message_with_link_preview_13.binproto | Bin 749 -> 795 bytes ...dard_message_with_link_preview_14.binproto | Bin 701 -> 666 bytes ...em_standard_message_with_quote_00.binproto | Bin 659 -> 622 bytes ...em_standard_message_with_quote_01.binproto | Bin 911 -> 966 bytes ...em_standard_message_with_quote_02.binproto | Bin 1150 -> 1317 bytes ...em_standard_message_with_quote_03.binproto | Bin 824 -> 813 bytes ...em_standard_message_with_quote_04.binproto | Bin 746 -> 769 bytes ...em_standard_message_with_quote_05.binproto | Bin 927 -> 1031 bytes ...em_standard_message_with_quote_06.binproto | Bin 661 -> 626 bytes ...em_standard_message_with_quote_07.binproto | Bin 894 -> 952 bytes ...em_standard_message_with_quote_08.binproto | Bin 876 -> 981 bytes ...em_standard_message_with_quote_09.binproto | Bin 894 -> 892 bytes ...em_standard_message_with_quote_10.binproto | Bin 898 -> 945 bytes ...em_standard_message_with_quote_11.binproto | Bin 864 -> 974 bytes ...em_standard_message_with_quote_12.binproto | Bin 964 -> 929 bytes ...em_standard_message_with_quote_13.binproto | Bin 646 -> 671 bytes ...em_standard_message_with_quote_14.binproto | Bin 639 -> 716 bytes .../chat_item_sticker_message_00.binproto | Bin 723 -> 687 bytes .../chat_item_sticker_message_01.binproto | Bin 665 -> 725 bytes .../chat_item_sticker_message_02.binproto | Bin 765 -> 734 bytes .../chat_item_sticker_message_03.binproto | Bin 634 -> 696 bytes .../chat_item_sticker_message_04.binproto | Bin 744 -> 710 bytes .../chat_item_sticker_message_05.binproto | Bin 679 -> 736 bytes .../chat_item_sticker_message_06.binproto | Bin 734 -> 703 bytes .../chat_item_sticker_message_07.binproto | Bin 651 -> 711 bytes .../chat_item_sticker_message_08.binproto | Bin 753 -> 719 bytes .../chat_item_sticker_message_09.binproto | Bin 654 -> 710 bytes .../chat_item_sticker_message_10.binproto | Bin 753 -> 724 bytes .../chat_item_sticker_message_11.binproto | Bin 661 -> 721 bytes .../chat_item_sticker_message_12.binproto | Bin 718 -> 684 bytes .../chat_item_sticker_message_13.binproto | Bin 670 -> 728 bytes .../chat_item_sticker_message_14.binproto | Bin 774 -> 743 bytes .../chat_item_view_once_00.binproto | Bin 549 -> 547 bytes .../chat_item_view_once_01.binproto | Bin 667 -> 627 bytes .../chat_item_view_once_02.binproto | Bin 610 -> 699 bytes .../chat_item_view_once_03.binproto | Bin 709 -> 665 bytes .../chat_item_view_once_04.binproto | Bin 617 -> 706 bytes .../chat_item_view_once_05.binproto | Bin 695 -> 651 bytes .../chat_item_view_once_06.binproto | Bin 617 -> 706 bytes .../chat_item_view_once_07.binproto | Bin 546 -> 546 bytes .../chat_item_view_once_08.binproto | Bin 659 -> 617 bytes .../chat_item_view_once_09.binproto | Bin 619 -> 706 bytes .../chat_item_view_once_10.binproto | Bin 707 -> 665 bytes .../chat_item_view_once_11.binproto | Bin 610 -> 699 bytes .../chat_item_view_once_12.binproto | Bin 700 -> 656 bytes .../chat_item_view_once_13.binproto | Bin 619 -> 708 bytes .../chat_item_view_once_14.binproto | Bin 539 -> 539 bytes .../notification_profile_00.binproto | Bin 878 -> 873 bytes .../notification_profile_01.binproto | Bin 895 -> 898 bytes .../notification_profile_02.binproto | Bin 900 -> 895 bytes .../notification_profile_03.binproto | Bin 889 -> 892 bytes .../notification_profile_04.binproto | Bin 908 -> 903 bytes .../notification_profile_05.binproto | Bin 906 -> 909 bytes .../notification_profile_06.binproto | Bin 894 -> 889 bytes .../notification_profile_07.binproto | Bin 909 -> 912 bytes .../notification_profile_08.binproto | Bin 892 -> 887 bytes .../notification_profile_09.binproto | Bin 883 -> 886 bytes .../notification_profile_10.binproto | Bin 908 -> 903 bytes .../notification_profile_11.binproto | Bin 904 -> 907 bytes .../recipient_contacts_00.binproto | Bin 458 -> 467 bytes .../recipient_contacts_01.binproto | Bin 588 -> 629 bytes .../recipient_contacts_02.binproto | Bin 581 -> 564 bytes .../recipient_contacts_03.binproto | Bin 564 -> 563 bytes .../recipient_contacts_04.binproto | Bin 464 -> 467 bytes .../recipient_contacts_05.binproto | Bin 558 -> 610 bytes .../recipient_contacts_06.binproto | Bin 578 -> 554 bytes .../recipient_contacts_07.binproto | Bin 565 -> 562 bytes .../recipient_contacts_08.binproto | Bin 483 -> 489 bytes .../recipient_contacts_09.binproto | Bin 564 -> 615 bytes .../recipient_contacts_10.binproto | Bin 565 -> 545 bytes .../recipient_contacts_11.binproto | Bin 555 -> 550 bytes .../recipient_distribution_list_00.binproto | Bin 824 -> 824 bytes .../recipient_distribution_list_01.binproto | Bin 839 -> 836 bytes .../recipient_distribution_list_02.binproto | Bin 833 -> 837 bytes .../recipient_distribution_list_03.binproto | Bin 843 -> 845 bytes .../backupTests/recipient_groups_00.binproto | Bin 1338 -> 1336 bytes .../backupTests/recipient_groups_01.binproto | Bin 1523 -> 1525 bytes .../backupTests/recipient_groups_02.binproto | Bin 1477 -> 1475 bytes .../backupTests/recipient_groups_03.binproto | Bin 1471 -> 1473 bytes .../backupTests/recipient_groups_04.binproto | Bin 1340 -> 1338 bytes .../backupTests/recipient_groups_05.binproto | Bin 1521 -> 1523 bytes .../backupTests/recipient_groups_06.binproto | Bin 1477 -> 1475 bytes .../backupTests/recipient_groups_07.binproto | Bin 1473 -> 1475 bytes .../backupTests/recipient_groups_08.binproto | Bin 1338 -> 1336 bytes .../backupTests/recipient_groups_09.binproto | Bin 1521 -> 1523 bytes .../backupTests/recipient_groups_10.binproto | Bin 1479 -> 1477 bytes .../backupTests/recipient_groups_11.binproto | Bin 1471 -> 1473 bytes .../securesms/database/AttachmentTableTest.kt | 12 +- .../database/AttachmentTableTestUtil.kt | 1 - .../database/AttachmentTableTest_deduping.kt | 6 +- .../database/BackupMediaSnapshotTableTest.kt | 6 +- ...ageProcessorTest_synchronizeDeleteForMe.kt | 2 - .../attachments/ArchivedAttachment.kt | 29 +-- .../securesms/attachments/Attachment.kt | 3 - .../attachments/DatabaseAttachment.kt | 2 - .../attachments/PointerAttachment.kt | 1 - .../attachments/TombstoneAttachment.kt | 2 - .../securesms/attachments/UriAttachment.kt | 1 - .../attachments/WallpaperAttachment.kt | 1 - .../securesms/backup/ArchiveUploadProgress.kt | 4 +- .../securesms/backup/v2/BackupRepository.kt | 11 +- .../v2/DatabaseAttachmentArchiveUtil.kt | 27 ++- .../backup/v2/local/LocalArchiver.kt | 5 +- .../v2/util/ArchiveConverterExtensions.kt | 202 ++++++++++-------- .../securesms/database/AttachmentTable.kt | 185 +++------------- .../database/BackupMediaSnapshotTable.kt | 43 ++-- .../securesms/database/MediaTable.kt | 1 - .../helpers/SignalDatabaseMigrations.kt | 6 +- .../migration/V280_RemoveAttachmentIv.kt | 45 ++++ .../jobs/ArchiveAttachmentBackfillJob.kt | 2 +- .../ArchiveAttachmentReconciliationJob.kt | 4 +- .../jobs/ArchiveThumbnailUploadJob.kt | 3 +- .../securesms/jobs/AttachmentDownloadJob.kt | 52 ++--- .../securesms/jobs/AttachmentUploadJob.kt | 5 +- .../securesms/jobs/BackfillDigestJob.kt | 107 ---------- .../jobs/BackfillDigestsForDataFileJob.kt | 13 +- .../securesms/jobs/BackupMessagesJob.kt | 3 +- .../securesms/jobs/JobManagerFactories.java | 5 +- .../securesms/jobs/RestoreAttachmentJob.kt | 4 +- .../jobs/RestoreAttachmentThumbnailJob.kt | 4 +- .../jobs/RestoreLocalAttachmentJob.kt | 6 +- .../jobs/UploadAttachmentToArchiveJob.kt | 7 +- .../migrations/ApplicationMigrations.java | 2 +- .../migrations/BackfillDigestsMigrationJob.kt | 41 ---- .../securesms/video/exo/PartDataSource.java | 2 +- app/src/main/protowire/Backup.proto | 26 ++- .../sms/UploadDependencyGraphTest.kt | 1 - .../securesms/database/FakeMessageRecords.kt | 1 - .../main/java/org/signal/core/util/Base64.kt | 20 ++ gradle/libs.versions.toml | 2 +- gradle/verification-metadata.xml | 78 ++++++- .../api/SignalServiceMessageReceiver.java | 92 +++----- .../api/attachment/AttachmentApi.kt | 1 - .../api/attachment/AttachmentUploadResult.kt | 1 - .../signalservice/api/backup/MediaName.kt | 4 +- .../api/crypto/AttachmentCipherInputStream.kt | 115 +++++----- .../api/crypto/AttachmentCipherTest.kt | 185 +++++++--------- 431 files changed, 600 insertions(+), 781 deletions(-) create mode 100644 app/src/main/java/org/thoughtcrime/securesms/database/helpers/migration/V280_RemoveAttachmentIv.kt delete mode 100644 app/src/main/java/org/thoughtcrime/securesms/jobs/BackfillDigestJob.kt delete mode 100644 app/src/main/java/org/thoughtcrime/securesms/migrations/BackfillDigestsMigrationJob.kt diff --git a/app/src/androidTest/assets/backupTests/account_data_00.binproto b/app/src/androidTest/assets/backupTests/account_data_00.binproto index 930fef9be2bd65994082d6e2ba79bf10afa6f0a5..12e22c994ea3811f9d97a169339001344d7bfdc2 100644 GIT binary patch delta 137 zcmZopeBK`;OrHlPh3nm>bi7V7TnHIc|VdBvhOXcpZ;L&~i!pn_= zQGwBb(c)|0{(tNNj0ubd3>}P&vl!Vq7)3XibNvUgm_(!I83I{S9L!Q;9Ku2zMiGzx lUsxgCSPYGfO*n+uI2g5C0RYLbEEWI& diff --git a/app/src/androidTest/assets/backupTests/account_data_01.binproto b/app/src/androidTest/assets/backupTests/account_data_01.binproto index 43897924039a639e338486cad34cc30bb2867a65..ebf6db591c8558b9974e1f9600c88672132d0a40 100644 GIT binary patch delta 425 zcmV;a0apH>1fB$tPJf{T3Z4TBAbWUU_zlw0k6NIT!E|16E6HY4p#YJ^sHGm>s0=Ob z=n@HbX>@NcG%_?c8a4_bG%DaV-M)Y1W&N{7*)(6=TCvY^um?EdCGT@^dY%Xtd zXD?1?a9BumT4-cUd1pE)3LrTPBTitAHgSX}CI7dzHk<=bFCik17?1a4dP{XaT^kYu zRZ~P50ZN|%5CIqgC;>RTrlZ~mNC8*@XaR5mcmaR`0f+$tk^xQF;hmU_1wUxmIC>u6A;Mm*@&G+ z?>n#B5wQvXhg})~8UUIB2M7TbDX3QengIt00u`rv(EpkN8wdj$7YK_15(w(^S^pTg zC;u7<00000004kLQZWi3A*Y2AQG=2D#j4O1Y{i;0U`%OVQyq;V`VA_Qg32qa&&Vt8h>bXbZ~PzFE4XxXKrC^ zE^l&YFGFTlWJp&^Iw=Yu48K`|p#eCd-sI5&Z~%w_0+In?H~|t{A_{43VP|D8YH(#|YD)?bEW)&mP_F({vzJcU z9&1ji5)kKm%zrOae+vTd=wL9cEHP6U;HRw$LLg-~H)3OBGG;Y1H)b$mFfwIkWjHo4 zGcaLeGGj9_H8UCj8UUIB2M7Tbl;NKLngIt00u`mRcmJ9J8wdj$7YNS+5(s+GuKxux zSpOOb00000004kLQZfo4d#7SISV=w`uqKRMsAuT3R3CLiS=2LnJjC#aSMn=onGz02 UOiyoXOh($ diff --git a/app/src/androidTest/assets/backupTests/account_data_02.binproto b/app/src/androidTest/assets/backupTests/account_data_02.binproto index abf8888fb942077889ff8d297b74d7dcfa3ac831..0abda25245c8d26c77138078e2f14400bc47c99b 100644 GIT binary patch delta 407 zcmV;I0cie%1hWK?PJgxo3bO+WAbWUU_zlw0k6NIT!E|16E6HY4p#YJ^sHGm>s0=Ob z=n@EJW@c$+E-*M6HVPnV^L0f^m6x6G4C&Gc4Y>4O1Y{lBbRU5f4*qaFXD6r<5Sm4e zpxIyE0aV#D!VMY(&KLqB2ts9YZeem{Zz=~d30SEyg0WbkL_x{_|2T%cE0dN3_0RfT$Za4uFXp=bsDt|i)5HGJ{400)H0BFRp zoK|UeTbi@me7UOE*k>e;FD8AOV^I z2M7Tbj}G|%ngIt00u@OJXaAZ38wdj$7YNk?5(sOc<^MK@TK^gd00000004kLpaB6= zED9hV#&-v;LnQLiXO=jJsvQPAjkR_&`c#ASA9!LcuS*ru5(sT-cX3ooPEeE00XF}? Bl@0&^ delta 358 zcmV-s0h#`@1cL;SPJf023WEa*Ai8}}o~~wGRP@OHOlbzQydBo9fYVWO)e+Vyofm6) zS`rF#VPbM=ZecDkHX1exAQTS%a6D%xsMX-}w314sc-0ayWG0cZhm0eAs`0Re~s0g?eR5-pQ30V-+$8UP>x zngIt00Tq<|ivOAc2M7Wc?k1f&FzPJgEZ3Zw%HAbWUU_zlw0k6NIT!E|16E6HY4p#YJ^sHGm>s0=Ob z=n@NUX=in1Y%Vc4H#HhI3Lr##rVgogAPYi?z17y}{)LSb@ZVRB(A2SZ_Ua&K&GI!-AHAYP(){iey*OLd;| zr(Ht~#Vk@5h;0{A~9gDO110Lteb{Z#+829MG!2vh|QXt#WOGqPa zb$=%X^n~5{oJb==#zBY3PB)?@-rl}8cK;dxAOe~J2M7Tbvv&&rngIt00u@@GG5?wY z8VCa#76=m(2r^jW|J0@}{~8DY000000DwPIBnluHHC647K+;1U7cqV TC*0h&bn{6fHaAn$liLAEmQ#(- delta 372 zcmV-)0gL{m1fv9yPJgBY3ZnxGAi8}}o~~wGRP@OHOlbzQydBo9fYVWO)e+Vyofm6) zS`rCzd0}oYI506X8a4_b(%q;kPyVAK{VJy`3Im8^>##rVgogAPYi?z133nE65)c^Y z2hV)8L}6L`Wg3+=CEXYUA_q!gb8TsEWhw+yZf|!wDGDI!jyj+Jcczi|@BS_IIYFN| z(Ha1^qRCTKRW2~dnpZ>)5(7syngIt00To@YkpG$i2M7WcQ2nw0ngJUK z0~!|y?*S4Bo-z0TUMQLW8VCRYDgXcg0DwPIBnluJmgfh+0$Il<@Y+yO|Fo{7Hz diff --git a/app/src/androidTest/assets/backupTests/account_data_04.binproto b/app/src/androidTest/assets/backupTests/account_data_04.binproto index 3cb0dde1015e9904f4dcfb38175eb1ba45400d68..9049824f432363089834f4dcec0a7dfcf51a2d60 100644 GIT binary patch delta 352 zcmV-m0iXWD1M>rrPJi|S3iARAAbWUU_zlw0k6NIT!E|16E6HY4p#YJ^sHGm>s0=Ob z=n@HbX>@NcG%_?c8a4_b)B5!u80QDie6&PiS^H%gl{F>ZU8$;hFY-Sz${H z6)C7z|C#{@2m%$SdeHxx0UHPd8W#wQ0TKx6^I88GxF`P_2mk;80001hKcE2tQY;D} yM6}4!oFzxgfOteFpR}auC&lw?Ky+TkSoMs`6seIfs5Jz delta 324 zcmV-K0lWV51HuE4PJhJ$3c>;kAi8}}o~~wGRP@OHOlbzQydBo9fYVWO)e+Vyofm6) zS`rFnZDn$KE;u(dG8#4tATRPiG0GrFKKGznmKD^kz4n+~l(u6tBBB2rmonHzZW0i= zi!1H^x=Bd?Uf{Ebcw*TY1Tq?EbaZfYIxjDCX=iR>Y%XtdXErZGW>#cKS4v8c0SEyQ z0T=-w0Vn}50XU)FI6{WLx|C#|C2m=}y2+sl%2zt=2{{=Ew{~8DY000000DwQB0Rd7h z3Lr<@MAi~;pxi$2vbJ~B;O?(8aRQ12?Q(IXDd2Xv(?1x5rRdbwkK5=E2oeSe0V)Cr W3kDJd2m&$y91s0=Ob z=n@EJW@c$+E-*M6HVPncCu2&vi!1H^x=Bd?Uf{Ebcw*UX8 z8EtFf#;5I4i6SjX2p9z-22*rpc4=iQ22F2lX>MUM9B6cOaDQ_;FE4XxXKrC^E^l&Y zFLY;eSVl}xQ)@aY3LrTPBTitAHgSX}CI7dzHk<=bFCik17?1a4dP{XaT^kYuRZ~P5 z0ZP095CIqgC;>S4{@c_CNC8*@XaR5mcmaR`0f+$tk^yTHXCew|ZDD6+FKTdQXIdOg zN>VH~Hf1h;Lz6%O6Ms1h5VZgMC0KctJ|%j&M@O}44^=kRrzVZ?3x)Sz|qE8UP>!ngIt00Tqu9`2UM7WcNeE~EngJUK0~!|y z)dCU-YoO)-HilaN8VCRY00000fIm_!3Lwna8QDzbiG}S$7$1};qlQJREmt`xp-S5> YkdSei6;JIL#pC6x!ua``eUk$MGmLklqW}N^ delta 412 zcmV;N0b~BK1hxc_PJg)r3bq3ZAi8}}o~~wGRP@OHOlbzQydBo9fYVWO)e+Vyofm6) zS`rF#VPbM=ZecDkHX1exAR?_x`o`f1S^IF?pAw3&8EtFf#;5I4i6SjX2)(M@`4SMv zGr~j+I_54)TA;i3d#aEa1tJGSVQyq;V`VA_Qg32qa&&Vt8(U~}bZ~PzFE4XxXKrC^ zE^l&YFLYs0NOwVYZ#pRoAPmJCky0zK+g_r0{iey*OLd;|r(Ht~#Vk18@L{0RoZ%e>edWd6P5&D}PH05Pvr=8<+Cf>R>A7$cz8GXc7=Z zOUiOIYG3($F@lo4Zgc+_{H3QrLLf9VG-6|6H!?FcHeoepW;r)wGchCbSngIt00u}EmsQ;P)8wdj$7YL;R5(o%qdH)XT^ZyzM00000 z05Jf7KT<3TAoB0@?*kH^&(Vp=^IAA;N~Vw080J^~jH?TPzl-xLofzZOm-4p%%&u3H G{Q)x@5vA<_ diff --git a/app/src/androidTest/assets/backupTests/account_data_06.binproto b/app/src/androidTest/assets/backupTests/account_data_06.binproto index 44572df1e8818bbcf994c4b827bbd056af20617b..7bb18720c05e408607482b0aa29ffffedc612398 100644 GIT binary patch delta 319 zcmV-F0l@yS1LgyePJihF3g!X|AbWUU_zlw0k6NIT!E|16E6HY4p#YJ^sHGm>s0=Ob z=n@NUX=in1Y%Vc4H#HhI3LxsFkdMbR!bA)@<}ONFpu6^as*q;dQ_A)XPRRhW-sKVy zDWkISm9X|Z)W{e~hK30j7zQE;LS=GpVRB?|DhE?^VQy??c}O}Z3Luhs=*R`whPj7% z%!IZ(I|xXwlIGwIQQjxxgLHU9mt+zHMO9KtxB&;03?jPOlug8ukgcn_igLcY8UP>#ngIt00Tr`%3jdk`2M7WcTAnfgngJRJ0~!_x R6A}nASmOWGrY)0j0YLXmg6jYP delta 265 zcmV+k0rvjp1F!>-PJgok3a|nSAi8}}o~~wGRP@OHOlbzQydBo9fYVWO)e+Vyofm6) zS`rCzd0}oYI506X8a4_b_6$zR0J7fYfd_?3DWkISm9X|Z)W{e~hK30j)m0h&5)eLQ z*Y2p7KaeQ?gdLtQ@yi$nA_PTtVQwk}NO@#sIwuMs4mNJ)v`v^T+#4Gb)9uNZ^iW$Z z3`RyXL|n1?rix@pM-l@?RZ>ce0SEyQ0T=-w0Vn}50XW<2jRQylPytv0U;$_WZ~=G$ zfB^xB0RfT$F%m746#*(N02%-w1)2c|2muvcu8{wl0S5>I6;S=L|C#|C2m=}y2=4(B P2%a(b|6VAWlcoVcr5;_1 diff --git a/app/src/androidTest/assets/backupTests/account_data_07.binproto b/app/src/androidTest/assets/backupTests/account_data_07.binproto index dbf948079c90cfe816d1e556ae3fc06adbbd44bf..fd91e243f70dbeb12c02314bd0e9d41ed5c32e8f 100644 GIT binary patch delta 351 zcmV-l0igcD1J(nOPJh_~3f2M&AbWUU_zlw0k6NIT!E|16E6HY4p#YJ^sHGm>s0=Ob z=n@HbX>@NcG%_?c8a4_bTgig@K4jPKsFy#GDE@>Uo-gssSeyL)R}Kmgwjj}35)ikF zJ9e5>p*d-4uo`vtkc$`xA_qcYa$;d}VJZhhVRCYBY-}Y%Xtd zXD>r$R%A$5N;)YDAnJ~v|97U5_wW8K^*KSGIMEsax1z~YR8=l8$eLF~4iW=LLQoh1 zN=7)L-sI5&Z~%w_0+Im+H~|O&AO@NN2M7Tbl;NKLngIt00u`mRcmJ9J8wdj$7YNS+ z5(s+GuKxuxSU>+72mk;80001hKTs0=Ob z=n@EJW@c$+E-*M6HVPm`jB3k$wq@mK{mUB0g{ZFE(wwv|m`!Ca*9n%FO7*7_5G9cB z(TpUX+r;_`S%b;x0~iQ09B6cOaC15@FLP;UZeeULZ*pfZbbn`ZSVl}xQ)^072mv4g zFabFC{@c_CPyt{8Z~%w_0g?d*H~|O(AP1TO2M7Tbj}G|%ngIt00u@OJXaAZ38wdj$ z7YNk?5(sOc<^MK@TK^gd00000004kLpaB6=ED9hV#&-v;L-NsQmN7%XRZJM delta 297 zcmV+^0oMMW1F!>-PJgok3a|nSAi8}}o~~wGRP@OHOlbzQydBo9fYVWO)e+Vyofm6) zS`rF#VPbM=ZecDkHX1exATHMlmX}KPr=(eB3MG*5(TpUX+r;_`S%b;x1N_*OG7=D{ zhE|mnxT?9erN7e~zYc~N2r?UJbaZfYIxjDCX=iR>Y%XtdXMZnrVNghSL3VFSVh8~c z0T=-w0Vn}50XXEsuJi*)0Z;*00bl`W0dN6$0e}GkhyekT0R#vFAP1TO2M7Tbl>CbS zngIt00u}EmsQ;P)8wdj$7YL;R5(o%qdH)XT^ZyzM00000004kLpaB6=E(##cFOd!P vW`ai$V{GWJ8y-oLMErXt8)e4R`QD#o#ryF85(-dFR#|UVMR8bolUM;pb>nS~ diff --git a/app/src/androidTest/assets/backupTests/account_data_09.binproto b/app/src/androidTest/assets/backupTests/account_data_09.binproto index 44f05adaa89030818228babfe04c414e26423eb6..c1f5e828320e3f21afa34b9b34f989b2d637d6ba 100644 GIT binary patch delta 232 zcmX@Zbdza0n7*q4vqN;DrnmkFHoMcW(uc?%Nki zY{4a|Wtpj3Y`*z9nR$s;np_H&+{%6ly=H|i>Z<>@Z#A34?60q=)F;vZJ*CRK)Gk(9 zh&eRaMS{^QM1WC(QG?OqYv2BV>>i8}j2Vmtj1`OxjEo(Ou}qT~SvZ&#IA$@jb1;f- zF6a6WVljzE%`*hDq&S$R#5jb7IE*45{lBtI_rDYe0~j>e2dQu=NSKDc?Q^)~ENfV& e`_6Lr4@M8ZdFprWY%BTfsbppzd}XpMqdovDhfP=j delta 219 zcmcb~bcShyU;TMTt}~2W3cG3p=B-PM3Hfs3pHC*+<~_34);3%YEV?RqO>?ezc4d?j zyK`b*N@jAZ7JE>BQfg62v6Uv50?$#Yi9y=yZ^tdF_`B@nHSf}SpO(iu^BmO)cpxg1 zYVcQxIW*Wsg3-&>;`WPmx3}Db;AEd&iAT{kd`vIoN<7$3e9czCp+`MP4W1^>C Tc>CCV`>^vfs0=Ob z=n@HbX>@NcG%_?c8a4_bG%DaV-M)Y1W&N{7*)(6=TCvY^um?EdCGT@^dc&Y-M>eAAe|cbZ~PzFE4XxXKrC^ zE^l&YFHUE0SV(kQXk<)zXF4YeAd-3L$OYJjxrceogtj|72uQAy=HLxc-Y4UOba+FT zWD)~KRZ>b*2mv4gFabEbrlZ~mPyt{8Z~%w_0g?d*H~|O*APJfQ2M7TbDX3QengIt0 z0u`rv(EpkN8%ziT8W#wQ0TKx6^I88GxF`P_2mk;80001hKcE2tQY;D}M6}4!oJY%m pctj_kw4~`L#q(=GbY8_+^^D3DUH6zC7~Y)RqW4O1Y{i;0U`uNc42NR1W0*gWilFQbaZfYI)5)Ob7^O8VQemMa%V3? zW>#cKS4ui33Lp+PZsxR@E!-O$64UL;m-J9uEeu9RGelgm`KF3wNJkO_MO9KtVh8~c z0T=-w0Vn}50XU)Fa0W*M{e+>Wt diff --git a/app/src/androidTest/assets/backupTests/account_data_11.binproto b/app/src/androidTest/assets/backupTests/account_data_11.binproto index b804ffce36581073bce4ad93b536c822d31888ff..c15d1d5585448f58b1384e19c1bacc71c8e4c350 100644 GIT binary patch delta 342 zcmV-c0jd7G1Iz=EPJhn=3d{luAbWUU_zlw0k6NIT!E|16E6HY4p#YJ^sHGm>s0=Ob z=n@EJW@c$+E-*M6HVPnV^L0f^m6x6G4C&Gc4Y>4O1Y{lBbRU5f4*qaFXD6r<5Sm4e zpxIyE0aV#D!VMY(&KLqB2SQkdSei6;JIL#pC6x!ua``eUpX(HN#$j9{>OV delta 325 zcmV-L0lNOo1G@u|PJg}v3cCUdAi8}}o~~wGRP@OHOlbzQydBo9fYVWO)e+Vyofm6) zS`rF#VPbM=ZecDkHX1exAQTS%a6D%xsMX-}w3Y%Xtd zXD@VNP)K({c5gZ<3Lxr^pZ|BJk@xTZE%iA;pE%JP0JoyaQ&d$hFvyx$L=F-IM?z2- z0ZK+V18@L{0RoZ%1~>r-1t1EV0S5>H6_osn|C#{@2m%%FDX9ON0UHPd8W#wq z0TKuZXLN@lP8VCRY00000fIm_!3Lx_D^zQ=_p3l*V$@5w`Y)Yn&)EMSh{fw&% XfWM3LE1ekQ)0gtL|IDsela~QCD7l1h diff --git a/app/src/androidTest/assets/backupTests/account_data_12.binproto b/app/src/androidTest/assets/backupTests/account_data_12.binproto index bccd830a1c8787402d624f03765b2b2e7e7602b9..0591b596b7f22ed290a48b30d7588b8ccd2303d0 100644 GIT binary patch delta 190 zcmV;v073uG0>J{1PJhG!3c&#iAbWUU_zlw0k6NIT!E|16E6HY4p#YJ^sHGm>s0=Ob z=n@NUX=in1Y%Vc4H#HhI3Lr##rVgogAPYi?z17z0XA2mv4gFabFAj=%l~Pyt{8a5Dgi0RfT$1~>r-1|SQX s0S5>H6|;8=|C#{@2m%#ao-zNL0U8Jc8Wso>5(qL_;{Vj9Et3raL6#0hQUCw| delta 202 zcmV;*05$)?0?q=EPJht>3eEuvAi8}}o~~wGRP@OHOlbzQydBo9fYVWO)e+Vyofm6) zS`rCzd0}oYI506X8a4_b(%q;kPyVAK{VJy`3Im8^>##rVgogAPYi?z133nE65)c^Y z2hV)8L}6L`Wg3+=CEXYUN?r&75CIqgAOR==FabE*?2Q9R0YFdzSOH)GXaR5mcmaR` z0f+$sk^uw=1|SQX0S5>H6s0=Ob z=n@HbX>@NcG%_?c8a4_b)B5!u80QDie6&PiS^H%gl{F>ZU8$;hFY-Sz${Y%Xtd zXD?1?a9BumT4-cUd1pE)3LrTPBTitAHgSX}CI7dzHk<=bFCik17?1a4dP{XaT^kYu zRZ~P50ZLU60T=-&0XVy+quvKd0ayWO0dN6$0e}GkhyenU0R#vKAPkxT2M7TbDX3Qe zngIt00u`rv&{F@J0UHPd8W#wQ0TKx6^I88GxF`P_2mk;80001hKTMw delta 333 zcmV-T0kZz&1JnbMPJh<|3e*A$Ai8}}o~~wGRP@OHOlbzQydBo9fYVWO)e+Vyofm6) zS`rFnZDn$KE;u(dG8#4tATRPiG0GrFKKGznmKD^kz4n+~l(u6tBBB2rmonHzZW0i= zi!1H^x=Bd?Uf{Ebcw*TY1R@7RVQyq;V`VA_Qg32qa&&Vt8h>bXbZ~PzFE4XxXKrC^ zE^l&YFGFTlWJp&^Iw=Yu48K`|MmV9~I6{WLx|C#|C2m=}y z2+sl%2zt=2|3U>aSpOOb00000004kLQZfo4d#7SISV=w`uqKRMsAuT3RCPmH)H8ZK f#PEk#@+)VV5)MdAPj72YT2O6jcX3oolb!)ae^h^k diff --git a/app/src/androidTest/assets/backupTests/account_data_14.binproto b/app/src/androidTest/assets/backupTests/account_data_14.binproto index 63b6e087bb7018b6c192c5568f1431b399ed567a..31c6f8b855c2c62f4bd296851bcfb2a2135002c3 100644 GIT binary patch delta 339 zcmV-Z0j&Pa1Hl83PJhG#3c&&jAbWUU_zlw0k6NIT!E|16E6HY4p#YJ^sHGm>s0=Ob z=n@EJW@c$+E-*M6HVPncCu2&vi!1H^x=Bd?Uf{Ebcw*UX8 z8EtFf#;5I4i6SjX2p9z-2ts9YZeem{Zz=~b*2mv4gFabFC{@c_CPyt{8Z~%w_0g?d*H~|O#YEtwZwBXO=jJ lsvQPAjkR_&`c#ASA9!LcuS*ru5(sT-cX3ooPEeDd0WH7qe$D^@ delta 350 zcmV-k0ipiE1Iz=EPJhn=3d{luAi8}}o~~wGRP@OHOlbzQydBo9fYVWO)e+Vyofm6) zS`rF#VPbM=ZecDkHX1exAR?_x`o`f1S^IF?pAw3&8EtFf#;5I4i6SjX2)(M@`4SMv zGr~j+I_54)TA;i3d#aEa1tJ7Rc42NR1W0*gWilIRbaZfYI)5)Ob7^O8VQemMa%V4e zVNghSL3VFCCkh}AHg4v$m@V8J8xqs)$(Qs{TP+MmMl(cQvH7NoWJpI614UI*N@55B z5CIqgAOR==FabE^!mjiKNC8j*SOH)GXaR5mcmaR`0f+$sk^uw=2p|ob0S5>H6_osn z|C#{@2m%%FDO0HbngJUK0~!|yr2!HM2xoc!4(jv&8VCRY00000fIpxC0a7jsAk8n4 w4fSS%M-XFd=&u_|l0^J_B^zbN)A`s0=Ob z=n@NUX=in1Y%Vc4H#HhI3LxsFkdMbR!bA)@<}ONFpu6^as*q;dQ_A)XPRRhW-sKVy zDWkISm9X|Z)W{e~hK30j7zQE-LSb@ZVRB(A2SZ_Ua&K&GI)5n&AYP(){iey*OLd;| zr(Ht~#VkmU57y&2&IQ5Rd{s%|_SOI7OZ~=G$ zfB^xB0RoZ%1PBQr4w?Z62muwdcMAWS0S5>I6&-o CK5%aU delta 284 zcmV+%0ptFr1Cj%fPJfjG3X%c}Ai8}}o~~wGRP@OHOlbzQydBo9fYVWO)e+Vyofm6) zS`rCzd0}oYI506X8a4_b_6$zR0J7fYfd_?3DWkISm9X|Z)W{e~hK30j)m0h&5)eLQ z*Y2p7KaeQ?gdLtQ@yi$nA_q!gb8TsEWhw+yZf|!wDGDI!j(?y3cczi|@BS_IIYFN| z(Ha1^qRCTKRW2~dnpZ>)5(7s<@YaRD`#-)#B- diff --git a/app/src/androidTest/assets/backupTests/account_data_16.binproto b/app/src/androidTest/assets/backupTests/account_data_16.binproto index fbaefee333f6e6f0f56d71a952c6182ef0ef7b02..cfa08b99471d0de79a6dcb514e94cbb5c8e310e0 100644 GIT binary patch delta 283 zcmV+$0p$Li1CaxePJfgF3XuW|AbWUU_zlw0k6NIT!E|16E6HY4p#YJ^sHGm>s0=Ob z=n@HbX>@NcG%_?c8a4_bTgig@K4jPKsFy#GDE@>Uo-gssSeyL)R}Kmgwjj}35)ikF zJ9e5>p*d-4uo`vtkc$`xG9PGkbZ~PzFE4XxXKrC^E^l&YFMm#Fa9BumT4-cUd1p#f z2mv4gFabEbrlZ~mPyt{8Z~%w_0g?d*H~|O>AP<@W2M7TbDX3QengIt00u`rv(EpkN z8wdj$7YK_15(w(^S^pTgC;u7<00000004kLpaB6=ED9h*w8+t%N6UbCL?@rLr0FNc h^J_qKUd34Tj1bBdUH6zC7~Y)RqW0oneM1DpepPJf>Q3Y-E8Ai8}}o~~wGRP@OHOlbzQydBo9fYVWO)e+Vyofm6) zS`rFnZDn$KE;u(dG8#4tAXg3w5Vj!ETAjUIDz}O|cA8Y7IcaLJ8g=%Ni#Y%XtdXMZn4W>#cKS4v7^2mufQ z7y%#wC;>15IHBI;(E>;TPytv0U;$_WZ~=G$fB^xB0RfT$1PBTs51Ii72muw8;hz7R z0S5>I6{WLx|C#|C2m=}y2+sl%2zt=2{{=Ew{~8DY000000DwQB0Rd7h3Lr<@MAi~; spxi$2vbJ~B;2Z9*GjRfn1nqKhq$%KbxYIuvgr(@z){ooh50hL0H8PED2mk;8 diff --git a/app/src/androidTest/assets/backupTests/account_data_17.binproto b/app/src/androidTest/assets/backupTests/account_data_17.binproto index 87a8f3e5abfa20f10a4b4fa1977c72312ab16a0b..dad836434915138f0ab969232b68427dd344aa62 100644 GIT binary patch delta 340 zcmV-a0jvJM1Iq)DPJhk<3d;ftAbWUU_zlw0k6NIT!E|16E6HY4p#YJ^sHGm>s0=Ob z=n@EJW@c$+E-*M6HVPm`jB3k$wq@mK{mUB0g{ZFE(wwv|m`!Ca*9n%FO7*7_5G9cB z(TpUX+r;_`S%b;x0~iP*22*rpc4=iQ22F2lX>MUM9B6cOaDQ_;FE4XxXKrC^E^l&Y zFLY;eSVl}xQ)@aY3LrTPBTitAHgSX}CI7dzHk<=bFCik17?1a4dP{XaT^kYuRZ~P5 z0ZLU60T=-&0XX;m+tde00ayWO0dN6$0e}GkhyenU0R#vOAP|}X2M7Tbj}G|%ngIt0 z0u@OJXaAZ38%YQQ8W#xF0ul&opymHIhFbp`2mk;80001hKT<3TAk5bp*-Yh$h3!Ka mlqaKxMXN1WIVhn@+b)ohahVlQ?HI-5<*UN@`I>!`i2*hfOn^85 delta 328 zcmV-O0k{6k1HS{1PJhAz3cmshAi8}}o~~wGRP@OHOlbzQydBo9fYVWO)e+Vyofm6) zS`rF#VPbM=ZecDkHX1exATHMlmX}KPr=(eB3MG*5(TpUX+r;_`S%b;x1N_*OG7=D{ zhE|mnxT?9erN7e~zYc~N2qFhVVQyq;V`VA_Qg32qa&&Vt8-HkYbZ~PzFE4XxXKrC^ zE^l&YFLYs0NOwVYZ#pRoAPmJCky0zK+g_r0{iey*OLd;|r(Ht~#VkCbSngIt00u}EmsQ;P)8wdj$ z7YL;R5(o%qc|HFQ>hu2^2mk;80001hKT<3TAoB0@?*kH^&(Vp=^IAA;N~Vw080J^~ ajH?TPzl-xLofzZOm-4p%%&u3Hl>s&)2Ziha diff --git a/app/src/androidTest/assets/backupTests/account_data_18.binproto b/app/src/androidTest/assets/backupTests/account_data_18.binproto index ff58c6f18a22eba98f829b1ef93304c118b15730..e175c08f4140df3a25941a276e2af48fc312f358 100644 GIT binary patch delta 180 zcmV;l089VS0>}c8PJhb*3djKpAbWUU_zlw0k6NIT!E|16E6HY4p#YJ^sHGm>s0=Ob z=pqP0WpZv|a%68R2UB!mZfs?FIwuMsl6mOJ1=xnUhk49|wmUlrNUoCR;0;mUC*y;3 zcte+D5(7n5Qc6z<0U!Y|0XX%Jzy1eM0bl`e0Ehtrk^u%d0V)U#AQ74Y2M7Tbvv&&r ingIt00u@@GG5?wY8VCa#76=m(2r^jW|J0@}k^fPiK0;#v delta 188 zcmV;t07L)C0?-1GPJhz@3eW)xAi8}}o~~wGRP@OHOlbzQydBo9fYVWO)e+Vyofm6) zS|S8Rc42NR1W0*gWjZGcAPzQe=CqhC+#4Gb)9uNZ^iW$Z3`RyXL|n1?rix@pM-l@? zRZ>b`2mufQ7y%#wC;>15INR)v14sc-0ayWG0cZhm0eAs`0WtxI0RfT$1PBZu5t;!9 q2muvcu8{wl0S5>I6;S=L|C#|C2m=}y2=4(B2%a(b|6VAWk@r!aKtK5a diff --git a/app/src/androidTest/assets/backupTests/account_data_19.binproto b/app/src/androidTest/assets/backupTests/account_data_19.binproto index 9b82f0c193f273ed907656d6b7af50041cd56331..e3fdef2dc3d0bfce33b7cfd5ba4d91c092c13d8c 100644 GIT binary patch delta 351 zcmV-l0igc41I+`FPJhq>3e5rvAbWUU_zlw0k6NIT!E|16E6HY4p#YJ^sHGm>s0=Ob z=n@HbX>@NcG%_?c8a4_bG%DaV-M)Y1W&N{7*)(6=TCvY^um?EdCGT@^d4O1Y{i;0U`%VVRLP1Ze=P2Q*Li}G8$-fbboMjIxjDCX=iR>Y%Xtd zXD>r$R%A$5N;)YDAnJ~v|97U5_wW8K^*KSGIMEsax1z~YR8=l8$eLF~4iW=LLQoh1 zN=7)L-sI5&Z~%w_0+Im+H~|O^AQGAZ2M7Tbl;NKLngIt00u`mRcmJ9J8wdj$7YNS+ z5(s+GuKxuxSU>+72mk;80001hKTMMi)d5JlC`9AEuSisQ1$T*3S&4Q7GPeFJVBRdD9Xg}YN{~#8Vs3%7{kR{E*EG5oy zl}U&rd%@HHW^Gabr8pSCpuv6tBV&*bmxA1}a`v^(pDw0PvuIx>%VyKNwaoZeNb_g; biX@%&-aMk0ggA1u$_qoh`~oItF&YB^prv9L delta 297 zcmV+^0oMMD1DykqPJf^R3Y`K9Ai8}}o~~wGRP@OHOlbzQydBo9fYVWO)e+Vyofm6) zS`rF#VPbM=ZecDkHX1exAQTS%a6D%xsMX-}w3Y%XtdXMZnrVNghSL3VFSVh8~c z0T=-w0Vn}50XXEsuJi*)0Z;*00bl`W0dN6$0e}GkhyekT0R#vRAQPGa2M7Tbl>CbS zngIt00u}EmsQ;P)8wdj$7YL;R5(o%qdH)XT^ZyzM00000004kLpaB6=E(##cFOd!P vW`ai$V{GWJ8y-oLMErXt8)e4R`QD#o#ryF85(-dFR#|UVMR8bolUM;WP<3oc diff --git a/app/src/androidTest/assets/backupTests/account_data_21.binproto b/app/src/androidTest/assets/backupTests/account_data_21.binproto index dc43c45deb72a5ba0bb2ef45d84bb424a2a3dea3..c52a09b5381f5d0f19f0192b37e825a3e93e22ec 100644 GIT binary patch delta 302 zcmV+}0nz@K1EvFzPJgKa3Z?=IAbWUU_zlw0k6NIT!E|16E6HY4p#YJ^sHGm>s0=Ob z=n@NUX=in1Y%Vc4H#HhI3Lr##rVgogAPYi?z17y}{(Q*>o^X=N$~O>b;zZecnp3V$Fu3nNZojW%(FCnf*4 zwKkjsPcI=Nju?;kWO_?=K3y9U165N*7y(LD5CIqgC;>S2j=%l~NC8*@XaR5mcmaR` z0f+$tk^uw=4H6|;8=|C#{@2m%#ao-zNL0U8Jc8Wso>5(qL_;{Vj9E&mz_ z00000004kLQX?b^AQ&}O?T$dwLme@GE$%tH_yI@`o+sSgwsiAJA~rWu)RSNVHwejT A&Hw-a delta 287 zcmV+)0pR|o1D6AkPJfyL3YP*3Ai8}}o~~wGRP@OHOlbzQydBo9fYVWO)e+Vyofm6) zS`rCzd0}oYI506X8a4_b(%q;kPyVAK{VJy`3Im8^>##rVgogAPYi?z133nE65)c^Y z2hV)8L}6L`Wg3+=CEXYUA_qfZZe(d=Whw_!Z(?O~baOf>3V$FB#Tt=PE3eyLqImtL z$<|ACp7N(%Lkz_%P~a6DWib5`165N*7y(K}INR)v18@L{0RoZ%1~>r-4H z6s0=Ob z=n@HbX>@NcG%_?c8a4_b)B5!u80QDie6&PiS^H%gl{F>ZU8$;hFY-Sz${c&Y-M>eAAe|cbZ~PzFE4XxXKrC^ zE^l&YFHUE0SV(kQXk<)zXF4YeAd-3L$OYJjxrceogtj|72uQAy=HLxc-Y4UOba+FT zWD)~KRZ>b*2mv4gFabEbrlZ~mPyt{8Z~%w_0g?d*H~|O{AQhSc2M7TbDX3QengIt0 z0u`rv(EpkN8%ziT8W#wQ0TKx6^I88GxF`P_2mk;80001hKcE2tQY;D}M6}4!oJY%m pctj_kw4~`L#q(=GbY8_+^^D3DUH6zC7~Y)RqW#cKS4ui33Lp+PZsxR@E!-O$64UL;m-J9uEeu9RGelgm`KF3wNJkO_MO9KtVh8~c z0T=-w0Vn}50XU)Fa0X9QCg7N?W diff --git a/app/src/androidTest/assets/backupTests/account_data_23.binproto b/app/src/androidTest/assets/backupTests/account_data_23.binproto index 6689dfdbfde8d9808a1a44d663707509f2ea2e89..501b8a6f0d672a2c011211d90b1395d468e8b67f 100644 GIT binary patch delta 342 zcmV-c0jd7X1Kk6VPJiG63f%$s0=Ob z=n@EJW@c$+E-*M6HVPncCu2&vi!1H^x=Bd?Uf{Ebcw*UX8 z8EtFf#;5I4i6SjX2p9z-2SQkdSei6;JIL#pC6x!ua``eUpX(Mk-u`g8%>k delta 325 zcmV-L0lNO(1Iz=EPJhn=3d{luAi8}}o~~wGRP@OHOlbzQydBo9fYVWO)e+Vyofm6) zS`rF#VPbM=ZecDkHX1exAR?_x`o`f1S^IF?pAw3&8EtFf#;5I4i6SjX2)(M@`4SMv zGr~j+I_54)TA;i3d#aEa1tJGZVRLP1Ze=P2Q*Li}G8<@gbboMjIxjDCX=iR>Y%Xtd zXD@VNP)K({c5gZ<3Lxr^pZ|BJk@xTZE%iA;pE%JP0JoyaQ&d$hFvyx$L=F-IM?z2- z0ZK+V18@L{0RoZ%1~>r-5g-H6_osn|C#{@2m%%FDX9ON0UHPd8W#wq z0TKuZXLN@lP8VCRY00000fIm_!3Lx_D^zQ=_p3l*V$@5w`Y)Yn&)EMSh{fw&% XfWM3LE1ekQ)0gtL|IDsela~QT1|fw? diff --git a/app/src/androidTest/assets/backupTests/account_data_24.binproto b/app/src/androidTest/assets/backupTests/account_data_24.binproto index 6ec32daa62c9fe1565329a6e1d93aafe7c80e646..a8d380e976414e7b80ff92b33806e6a6bb259cab 100644 GIT binary patch delta 190 zcmV;v073u70=NQ@PJg=r3b+9ZAbWUU_zlw0k6NIT!E|16E6HY4p#YJ^sHGm>s0=Ob z=n@NUX=in1Y%Vc4H#HhI3LxsFkdMbR!bA)@<}ONFpu6^as*q;dQ_A)XPRRhW-sKVy zDWkISm9X|Z)W{e~hK30j7zRpD2mv4gFabFAj=%l~Pyt{8a5Dgi0RfT$1~>r-5-0(h s0S5>H6|;8=|C#{@2m%#ao-zNL0U8Jc8Wso>5(qL_;{Vj9Et3raI3mDCo&W#< delta 202 zcmV;*05$)(0>uK5PJhS&3dI2mAi8}}o~~wGRP@OHOlbzQydBo9fYVWO)e+Vyofm6) zS`rCzd0}oYI506X8a4_b_6$zR0J7fYfd_?3DWkISm9X|Z)W{e~hK30j)m0h&5)eLQ z*Y2p7KaeQ?gdLtQ@yi$nN?r&75CIqgAOR==FabE*?2Q9R0YFdzSOH)GXaR5mcmaR` z0f+$sk^uw=5-0(h0S5>H6s0=Ob z=n@HbX>@NcG%_?c8a4_bTgig@K4jPKsFy#GDE@>Uo-gssSeyL)R}Kmgwjj}35)ikF zJ9e5>p*d-4uo`vtkc$`xA_h}*Wp-(0Dh5q&Y-w&`G9PGkbboMjIxjDCX=iR>Y%Xtd zXD?1?a9BumT4-cUd1pE)3LrTPBTitAHgSX}CI7dzHk<=bFCik17?1a4dP{XaT^kYu zRZ~P50ZLU60T=-&0XVy+quvKd0ayWO0dN6$0e}GkhyenU0R#vWC<2-R2M7TbDX3Qe zngIt00u`rv&{F@J0UHPd8W#wQ0TKx6^I88GxF`P_2mk;80001hKTbXbZ~PzFE4XxXKrC^ zE^l&YFGFTlWJp&^Iw=Yu48K`|MmV9~I6{WLx|C#|C2m=}y z2+sl%2zt=2|3U>aSpOOb00000004kLQZfo4d#7SISV=w`uqKRMsAuT3RCPmH)H8ZK f#PEk#@+)VV5)MdAPj72YT2O6jcX3oolb!)HzL|aS diff --git a/app/src/androidTest/assets/backupTests/account_data_26.binproto b/app/src/androidTest/assets/backupTests/account_data_26.binproto index ea4c057c416a86b7725a70b2ab0ee16b3052cfad..e1b6cbbe354c59ea4b29e6b3a2a113fbaf2b3ed4 100644 GIT binary patch delta 339 zcmV-Z0j&Pi1IYuBPJhe-3dsTrAbWUU_zlw0k6NIT!E|16E6HY4p#YJ^sHGm>s0=Ob z=n@EJW@c$+E-*M6HVPm`jB3k$wq@mK{mUB0g{ZFE(wwv|m`!Ca*9n%FO7*7_5G9cB z(TpUX+r;_`S%b;x0~iP*2ts9YZeem{Zz=~b*2mv4gFabFC{@c_CPyt{8Z~%w_0g?d*H~|P0C#YEtwZwBXO=jJ lsvQPAjkR_&`c#ASA9!LcuS*ru5(sT-cX3ooPEeDd0W~bDfmr|m delta 350 zcmV-k0ipiM1JnbMPJh<|3e*A$Ai8}}o~~wGRP@OHOlbzQydBo9fYVWO)e+Vyofm6) zS`rF#VPbM=ZecDkHX1exATHMlmX}KPr=(eB3MG*5(TpUX+r;_`S%b;x1N_*OG7=D{ zhE|mnxT?9erN7e~zYc~N2qFYUc42NR1W0*gWilIRbaZfYI)5)Ob7^O8VQemMa%V4e zVNghSL3VFCCkh}AHg4v$m@V8J8xqs)$(Qs{TP+MmMl(cQvH7NoWJpI614UI*N@55B z5CIqgAOR==FabE^!mjiKNC8j*SOH)GXaR5mcmaR`0f+$sk^uw=6et6l0S5>H6_osn z|C#{@2m%%FDO0HbngJUK0~!|yr2!HM2xoc!4(jv&8VCRY00000fIpxC0a7jsAk8n4 w4fSS%M-XFd=&u_|l0^J_B^zbN)A`0n7*q4vqN;DrnmkFHoMcW(uc?%Nki z>`sYANr^>?TI|k=MMe2JIaZon3UP}n{w_Ot&AW8or{%HEJV$i`9*D}M8vOlstwfK{ zEbo~Rv%6D(1fy4o0HXw>2BXE-zWx8$Js2YxGZ+gPD;OIX8RI(`nI`>7)3n#e`T5Oe<=?X%48`<3jo9yQqcea delta 216 zcmaFDbctz#U;R}^u1kzu3cG3p=B-PM3Hfs3pHC*+<~_34);3%YEV?RqO>?ezc4d?j zyH{dyZf0Jp7E5qmez}zmo8bE&#AFf;_`4CvlICER z66bi&D8w<(@caKbjhX+YI2gd7!9GZZOF?SdbM^yFk;m2iwmR1SR=9c3TE|3Bz3}$2 Q`SxMwXUJchtixyl04K*#=Kufz diff --git a/app/src/androidTest/assets/backupTests/chat_00.binproto b/app/src/androidTest/assets/backupTests/chat_00.binproto index 3dba406f9d86459e6522e786ccea338bc37d6acc..b5cc1a3ba49ec308d62faf83a1f65eec52fe8c2c 100644 GIT binary patch delta 107 zcmV-x0F?jj1lk0!_W@&K8ej+m5Ck{@KmkfnH~|t$A_{43VP|D8YH(#|YB~xKEW)&m zP_F({vzJcU9&1ji81ws>zX4JptSm88MyU1Nz^9f1`K1#O$nM#Qoks6Fui6o@3IB&( N8UPvqQ1-C@vnESUfR delta 126 zcmV-^0D=G71nmT{_W^cw8gmE(5Cj+jH~~NbN?|ww5?dk)X>DO=WiM)QWoK$j3J@&9 zw2V-${!_D;PT3x7PN@V_0UC(`2m=rV7y%#wDCqpLw95l9;^n!!{4q*w5@?eW0xCs2 z3J@=^VhnOAX#i-%u$)$DcI6nU|CR_i08${AQh9~970pkHa`Y&k5wb2j*Dg^|2k}}V T21_?ge191l03ZQS!-nZ+C8;Uc delta 51 zcmV-30L=e|1;+%i_W>JE8chfT5Ck9rD4@;iz4#0;$M)^Bo;6A_5-pP!0xAmt8UP>x JP^Oiy_5{$I5x4*V diff --git a/app/src/androidTest/assets/backupTests/chat_02.binproto b/app/src/androidTest/assets/backupTests/chat_02.binproto index f5d6fa006791a277e240f58fc156c5e662f472cf..25246afb3da6c7e34b076ccde4412481d9344696 100644 GIT binary patch delta 117 zcmV-*0E+*g1&Rf*_W>c10UC}02m=rVD8RO}jL`}(qmI$~oHIB9Kmkf{H~|uBlN$mn zM?4A;;0{A~9gDO110Lteb{Z#+829MG!2vh|QXt#WOGqPab$=%X^n~5{oJb==#zBY3 XPB)?@-rl}8cK;dxAOcXf?#i(P<=`%! delta 138 zcmV;50CoS01)l}5_W>lP0UDzL2m=rV7y&4_g13UH8Zhkd+se&1H~~NbN`e760TO(Z z7y>Igc#)Rv!et!0zx1- sFlIJoF=IJoVq`HiVl+51Gd5&5H8*B5H!wA3G&nRG03ZTT_>9ua1{i%Wp#T5? diff --git a/app/src/androidTest/assets/backupTests/chat_03.binproto b/app/src/androidTest/assets/backupTests/chat_03.binproto index 428c6798f93b71dce28ca3a82c66ba87af69e540..ad32f43e940d55b3ad5673a0e00ef2c984d49ce7 100644 GIT binary patch delta 99 zcmV-p0G$811os56_W=)o8hr=@5Cj+jAOT8k5^0kJ0xCy53J_G8>?vQTJs!$N(w~MJ z@edgD`-Fa$6rWk0t52MY8UP>zQ1-C@ Fvb|0UC+{2m=rVDCqpLw95l9;^n!!{4qEIKmkf^H~|u8lNtgm zLpcf%wEz1hSb3E`C3?9>N409@7^(l32vQ(;+09f#OUiOIYG3($F@lo4Zgc;TBF6e} TuDcakV?Aja03ZZV!-nZ+=9VuS delta 134 zcmV;10D1q01)Bx1_W>iK0UDnH2m=rV7y&4t&Fa1Q3^2#`?X#XWH~~NbN`E*35_yvt z0xMQa3J`xcE*qEf*y>;^=E#fxyJ!*+LrcnXG-_Y@d@+KOy>4^=82qKDKtdoiGc;mj oVK*`}G&W&1W@b4zV>2;0GC4A0WHx0tGiGKQ03ZZVrj@Vu1U+IgbpQYW diff --git a/app/src/androidTest/assets/backupTests/chat_05.binproto b/app/src/androidTest/assets/backupTests/chat_05.binproto index 11304a626fcd8d1b97ff603986de56380c54b599..13db26d4ea8b5197b9d14b8e56ac5cf016107b9e 100644 GIT binary patch delta 115 zcmV-(0F3{~1cwE%_W>V{0UC<|2m=rV7y%#wD8RO}jL`}(qmI$~oHI&o5^0kX0xCy5 z3J~~l_=B39;@Hz@S-H@*(pnhz=)u7OH~>;03?jPOlug8u Vkgcn_igLcY8UP>#P`2*Mu>*^TGL`@U delta 51 zcmV-30L=e~1;+%i_W>JE8chfT5Ck9rD7b>Rf~guX?C;yk%{NLh5-pP!0xAmt8UP># JQ230}%Lc!O5pw_l diff --git a/app/src/androidTest/assets/backupTests/chat_06.binproto b/app/src/androidTest/assets/backupTests/chat_06.binproto index 8b954d38e21374cc5084146dc57e1690f64472a6..a818a196e5a8cf502913714f450e7a85b8983cb0 100644 GIT binary patch delta 33 pcmbQlGJ$2ocScDGDKQRa0Tv5J2SzV83q}q`1-5{18~$%$2LOJf2sHoz delta 35 rcmbQhGKpowcSdO`DG3f{0Tu~H3q}Vj$8X*V+5Cj+jAOR@o{IRsl12E#{xx4%^N(2Z3AO}#xhUsTR CI}iW> delta 43 zcmV+`0M!4R1eye}_W>g!8XyP*5Ck9rD4@;iz4#0;$M)^Bo;6AY2m&AnP^Oiy_5?)c B5BLB8 diff --git a/app/src/androidTest/assets/backupTests/chat_08.binproto b/app/src/androidTest/assets/backupTests/chat_08.binproto index af462927b8817d38ee2ee2aeb5b457efd257cf52..d854b90550dda26d58888d5d877a5afe0d9c6d51 100644 GIT binary patch delta 47 zcmV+~0MP%S1fB%2_W>s+8YBn<5CkZ|wzG`U3NWLN(fXV-H~~NbN(MLq2m>GpP`2*M Fu>*TB5A*;4 delta 49 zcmV-10M7rO1fT@4_W>y=8YTz>5Cj+jD7b>Rf~guX?C;yk%{Mp!KmkeyH~|O)AP7+S HjMB>njRO#O diff --git a/app/src/androidTest/assets/backupTests/chat_09.binproto b/app/src/androidTest/assets/backupTests/chat_09.binproto index bcc0409f705f63642d9cdd6c1ef7bd794f42f6f5..fe3a7c34e1bc0a2665ed5999e9cc1b07bab1c2f0 100644 GIT binary patch delta 31 mcmeBS>0{aOol#s&N`!-1fJK5)fzgYFgGGTe;M<1(Ti5|^oCmT1 delta 29 kcmeBU>0#OMol#UoN{EA5fJK4Pi-m(lfiqz1=hsu20A*7LT>t<8 diff --git a/app/src/androidTest/assets/backupTests/chat_10.binproto b/app/src/androidTest/assets/backupTests/chat_10.binproto index cbd4585e8315cb5060c5528348084d21656ec907..165d34376cd59b50896f6f21b9b91fdda008ec81 100644 GIT binary patch delta 46 zcmV+}0MY-T1f2x1_W>p)8Y2h;5Ckab{IRsl12E#{xx4%^H~~NbN(MLq2n8StP{W4l EXNEZtj{pDw delta 49 zcmV-10M7rN1fT@4_W>y=8YTz>5Cj+jD4@;iz4#0;$M)^Bo;5fDKmkeyH~|O+APP{X Hm9O>$oox`s diff --git a/app/src/androidTest/assets/backupTests/chat_11.binproto b/app/src/androidTest/assets/backupTests/chat_11.binproto index daea7d3bceb0ca230caf1321b91fea664cb90785..e95a931df216002f2388666a47fccec988aa6f52 100644 GIT binary patch delta 45 zcmV+|0Mh@O1e^r0_W>m&8X^b-5Cj+jAOR@AwzG`U3NWLN(fXV-N(2Z7APZ2o?#i(P DKGP3z delta 43 zcmV+`0M!4S1eye}_W>g!8XyP*5Ck9rD7b>Rf~guX?C;yk%{NK}2nHYvQ230}%LX_q B54HdR diff --git a/app/src/androidTest/assets/backupTests/chat_12.binproto b/app/src/androidTest/assets/backupTests/chat_12.binproto index 44ce2fd62b65eab4da7decad6d40422431fcc48e..f885eb5c3f41308ed86a72970fbdbf48610e5d9f 100644 GIT binary patch delta 33 pcmbQlGJ$2ocScDGDKQRa0Tv5J2SzV83q}rh1)hL!8~$%$2LOKq2tfb< delta 35 rcmbQhGKpowcSdO`DG3f{0Tu~H3q}Vj$8X*V+5Cj+jAOR@o{IRsl12E#{xx4%^N(2Z9APrE%hUsTR Cj}Qz1 delta 43 zcmV+`0M!4R1eye}_W>g!8XyP*5Ck9rD4@;iz4#0;$M)^Bo;6AY2nZkzP^Oiy_5?*n B5Ci}K diff --git a/app/src/androidTest/assets/backupTests/chat_14.binproto b/app/src/androidTest/assets/backupTests/chat_14.binproto index 772973b3fce22af7777b1ae8e7f6af66e115f7f0..feb44958e4f1c5c042f8e2cdee892c0b22a3e8da 100644 GIT binary patch delta 47 zcmV+~0MP%S1fB%2_W>s+8YBn<5CkZ|wzG`U3NWLN(fXV-H~~NbN(MLq2niq#P`2*M Fu>*UM5C8xG delta 49 zcmV-10M7rO1fT@4_W>y=8YTz>5Cj+jD7b>Rf~guX?C;yk%{Mp!KmkeyH~|O=AP!LY HjMB>njbjjl diff --git a/app/src/androidTest/assets/backupTests/chat_15.binproto b/app/src/androidTest/assets/backupTests/chat_15.binproto index 8807550d4e15de71153202113c21506a1f19f3a6..78cb5217493d8b453557dabc1acc7d998424ba0a 100644 GIT binary patch delta 31 mcmeBS>0{aOol#s&N`!-1fJK5)fzgYFgG+%w;M<1(Ti5|^{0F`O delta 29 kcmeBU>0#OMol#UoN{EA5fJK4Pi-m(rfj?mD=hsu20A;fWX#fBK diff --git a/app/src/androidTest/assets/backupTests/chat_16.binproto b/app/src/androidTest/assets/backupTests/chat_16.binproto index cecb85635f5b7470a860ef2c0df38b0ba3361a3b..22655afb063902f7c5155b2936cad81fcfe21ab6 100644 GIT binary patch delta 46 zcmV+}0MY-T1f2x1_W>p)8Y2h;5Ckab{IRsl12E#{xx4%^H~~NbN(MLq2n!$(P{W4l EXNHXsn*aa+ delta 49 zcmV-10M7rN1fT@4_W>y=8YTz>5Cj+jD4@;iz4#0;$M)^Bo;5fDKmkeyH~|O?AP`Wd Hm9O>$oy`!@ diff --git a/app/src/androidTest/assets/backupTests/chat_17.binproto b/app/src/androidTest/assets/backupTests/chat_17.binproto index ee8fa2a346354154b5963b9117a2512906bfe313..668a4dc027609b52ef76fa6186aaa32677a4bc15 100644 GIT binary patch delta 45 zcmV+|0Mh@O1e^r0_W>m&8X^b-5Cj+jAOR@AwzG`U3NWLN(fXV-N(2ZDAQ4cu?#i(P DKQj+~ delta 43 zcmV+`0M!4S1eye}_W>g!8XyP*5Ck9rD7b>Rf~guX?C;yk%{NK}2n-+*Q230}%LX`# B55fQd diff --git a/app/src/androidTest/assets/backupTests/chat_18.binproto b/app/src/androidTest/assets/backupTests/chat_18.binproto index 86ba04796113a6765732a3c5dd027eac3ac6a986..bedaf696bafceb4891078e4d100ba577cbbb36e7 100644 GIT binary patch delta 33 pcmbQlGJ$2ocScDGDKQRa0Tv5J2SzV83q}rJ1)+d%8~$%$2LOL#2u%P0 delta 35 rcmbQhGKpowcSdO`DG3f{0Tu~H3q}Vj$8X*V+5Cj+jAOR@o{IRsl12E#{xx4%^N(2ZFAQMo-hUsTR C;}94C delta 43 zcmV+`0M!4R1eye}_W>g!8XyP*5Ck9rD4@;iz4#0;$M)^Bo;6AY2o4|s+8YBn<5CkZ|wzG`U3NWLN(fXV-H~~NbN(MLq2oE3>P`2*M Fu>*VX5DWkS delta 49 zcmV-10M7rO1fT@4_W>y=8YTz>5Cj+jD7b>Rf~guX?C;yk%{Mp!KmkeyH~|O`AQVve HjMB>njl&R+ diff --git a/app/src/androidTest/assets/backupTests/chat_21.binproto b/app/src/androidTest/assets/backupTests/chat_21.binproto index b807fae3c5b6798408e26632829540da8a17c82a..4ea0f9d7b55059e0741b6b104773d3700f338b9d 100644 GIT binary patch delta 31 mcmeBS>0{aOol#s&N`!-1fJK5)fzgYFLqI_^;M<1(Ti5|_TnEYk delta 29 kcmeBU>0#OMol#UoN{EA5fJK4Pi-ki#K{R0N=hsu20A>>hbpQYW diff --git a/app/src/androidTest/assets/backupTests/chat_22.binproto b/app/src/androidTest/assets/backupTests/chat_22.binproto index cef596c97e4569240c3f1b890e98dc2ae88c6024..63797f65f66a75d592933dd8692217644c53eb90 100644 GIT binary patch delta 46 zcmV+}0MY-T1f2x1_W>p)8Y2h;5Ckab{IRsl12E#{xx4%^H~~NbN(MLq2oWF_P{W4l EXNKVrrvLx| delta 49 zcmV-10M7rN1fT@4_W>y=8YTz>5Cj+jD4@;iz4#0;$M)^Bo;5fDKmkeyH~|O|AQn)j Hm9O>$o-GjF diff --git a/app/src/androidTest/assets/backupTests/chat_23.binproto b/app/src/androidTest/assets/backupTests/chat_23.binproto index f2decffcc58bdc13d264ce3b11884b9c5da510fe..befe449f73931869d85754c051b3f71c43f79084 100644 GIT binary patch delta 45 zcmV+|0Mh@O1e^r0_W>m&8X^b-5Cj+jAOR@AwzG`U3NWLN(fXV-N(2ZJC;?Em?#i(P DKRFM3 delta 43 zcmV+`0M!4S1eye}_W>g!8XyP*5Ck9rD7b>Rf~guX?C;yk%{NK}2ofj(Q230}%LX`* B55NEb diff --git a/app/src/androidTest/assets/backupTests/chat_24.binproto b/app/src/androidTest/assets/backupTests/chat_24.binproto index af05b5607bf24651eee321189cd00d30f81daf2d..a73835b84bb5d1de6a4ebc4f8c834c00c2f94a87 100644 GIT binary patch delta 33 pcmbQlGJ$2ocScDGDKQRa0Tv5J2SzV83q}rM4W@u^8~$%$2LOL*2ulC} delta 35 rcmbQhGKpowcSdO`DG3f{0Tu~H3q}Vj$8X*V+5Cj+jAOR@o{IRsl12E#{xx4%^N(2ZLC<9Q#hUsTR C>kt+I delta 43 zcmV+`0M!4R1eye}_W>g!8XyP*5Ck9rD4@;iz4#0;$M)^Bo;6AY2oxv-P^Oiy_5?+& B5DowU diff --git a/app/src/androidTest/assets/backupTests/chat_26.binproto b/app/src/androidTest/assets/backupTests/chat_26.binproto index dbcf7b32a3852b293b9bc6383ea6331b37ff976f..595468e1c98e928ae73b38765bd913c3698e07fd 100644 GIT binary patch delta 47 zcmV+~0MP%S1fB%2_W>s+8YBn<5CkZ|wzG`U3NWLN(fXV-H~~NbN(MLq2o)LtP`2*M Fu>*T*5BLB8 delta 49 zcmV-10M7rO1fT@4_W>y=8YTz>5Cj+jD7b>Rf~guX?C;yk%{Mp!KmkeyH~|P18URrE HjMB>njXe;1 diff --git a/app/src/androidTest/assets/backupTests/chat_folder_00.binproto b/app/src/androidTest/assets/backupTests/chat_folder_00.binproto index cc97e0efe2004e197e4f1792f91cae983db39828..0a1f0cc0374d56b9f66a20e85d36dbea9fedb859 100644 GIT binary patch delta 56 zcmbQsKAU|*HnV}glP(uuU}=7ef@f(;W^!UuW{Cu&0;2|_0h1FWmzThv7jud&v`n;P Mc;c(42UWHL0KrxeYXATM delta 58 zcmbQuK9_w%HnWkTlRg(;U}=7ef@f(;W^!UuW{Ci!1fv3@2BQI!6C;f=hmKYFHEv}1VU KtEUH5wgLdV3J}i# delta 52 zcmbQqKAn9-HnWbllO~ryKu%&weqL&>f=hmKYFHEv}1VU KtEUH5wgLdA2M`Vb delta 52 zcmbQqKAn9-HnWbllO`8mU}=7ef@f(;W^!UuW{Cll6*DUfmzO}1W+p?%kqvXgGRvNd ImxW9K0FIOpVE_OC diff --git a/app/src/androidTest/assets/backupTests/chat_item_contact_message_00.binproto b/app/src/androidTest/assets/backupTests/chat_item_contact_message_00.binproto index c3ba3adebf6375f3c8723103d6aa110a1faf3e75..d60b2cc6fc5acf46d87eed95f4e9dc4743a04769 100644 GIT binary patch delta 77 zcmV-T0J8tj1jYoQ0!Bq5LkI#81Q_d=xzxZhLJ$b9(VXq`Fc6`@nT(P#AOT_|3L*+1 j3I#)KX=Y{;219INa%*KO210USZe(dP2SIgmWo&708sHiz delta 86 zcmX@ca-L-YlfR#m4+oO~i^RH%bKZV7a1!FUd*=V)qlN+t|Fm43Z6d*_z?h`XrOBnv p#o?BdT9TZRS|r5jo|%)AT3nEss>SA#SdfvIYQ*8236uhg0su`49y$O3 diff --git a/app/src/androidTest/assets/backupTests/chat_item_contact_message_01.binproto b/app/src/androidTest/assets/backupTests/chat_item_contact_message_01.binproto index e1f1c7c8b1c52598a26dbe84b50338b0d8321c41..0b93708d00740d42ed4a508ab347ba1662a26cbf 100644 GIT binary patch delta 238 zcmV!N3HZZZfctc|cZWY+-Y8b!B=kV`pz|5CJL)2mvAmOJ#0! zXfjG73TbU&XJs#HaAjv|Itmc{a{K3QwHm;UhaR_YE`B%|_nF?M0#YD(5$Ab=MDare oq+3-AneGkq|1!ibB8>3tlH(XGkF4Yx06GdnVoP;zbV7D>ODHr{4FCWD delta 267 zcmV+m0rdXn1%d{k0)K!4BK-jf0uTfkp}?7pk}*OK2;R*9!^JTWqWpx>n>1qI0Sep! z3MmQ(Qg3cZ*Cd`O>!5DE-5G&eUe zFgY+VGdM920U{I%5KCold0{|Eb#8QJaxPZz2k5ZDD6+ zFKTdQXKG&x5D9wOw7_l3#tSQ82g8JChY}D!KpslplhWdr6ylS^=Wk9J_rdj}0wM@u zSZPdCV`oe#05I16;l=GSLLf6{G%zt`G+|_BIWuH3WimN7F*Ic|IWuE3Wj8ivG-Vn9 RItzGKb!K=;QUp?DO;TnDSvmj! diff --git a/app/src/androidTest/assets/backupTests/chat_item_contact_message_02.binproto b/app/src/androidTest/assets/backupTests/chat_item_contact_message_02.binproto index b5fbaf90d3da21a6172c0ce5a672094fccf85522..5958964467bf3ae2781c55e5a6bec723432fcee5 100644 GIT binary patch delta 438 zcmV;n0ZIP62Zsot0)K@BB7y`60uTWh>zBFIz%fb&3IqrQ8USMK0}AN_3N8u;L2PAs zX>$?@L}_DdWpZYlRX1Be=1rC0}=*COi)v6K^g^QOIBBFA`NzW zQ$|i_a9BumT4-b{2y|gkNOwVYZ!!mEYFJljM^QQmbU{mWP*zx0LJMelT0>NFMqyfU zLP`#5a!OQhS9MNNdT38VaWZ)#32AL%XJs#NZf80PVQy|`d3sKGdO+L~NIzN}OlC}I zlavD)Ogst@og06de~20YItx`+WOPhSdSp#vc1fs;T>t<8 delta 377 zcmWm8&rae%0Dy6}gHVPgHh3}P!KB{E1}hNxbCI@|B1J5=2=+E*o3;x~p-!vi;&C5< zE7|P6z+N}m_!7Q{p1gQm_W{0NzVGZ)_9yfB7w~@o%W$9ee?M4@Q08ajb@r^wwLBeG0Q>d{?FIC z96yLxzRw>)PIE|t+uevzCoE5c#RpMXpAU3m%L$exRV)oyrdWvAMrYtICtYfJUr|o6 zuIvt3n^q~)>FdT!tgsa8-Fq<(T3P4p+hpviLy4uLM)jM?O)u{ymTZO{Y^|iym<7d5 z;zraBQGuwJ1MIKJd}!aA{LaS?^)@d|9aUO<&R<~HIbIUCl}WI&x;5JGdtHCC1&6yS PlxjiA)}nw)@tyV$cff0t diff --git a/app/src/androidTest/assets/backupTests/chat_item_contact_message_03.binproto b/app/src/androidTest/assets/backupTests/chat_item_contact_message_03.binproto index 06ffdd33a98c0b1c798c17a12da6c565b148a82c..5f5dc1126a5bb950c09bd9d1a11a48e97e999742 100644 GIT binary patch delta 185 zcmV;q07n1T1+fL70)MXoBCG)j0uTWhmBhHG|1nAr3JnMZ5aW!%#;7nN0tf+OjR6XZ z0SXHm1Wjpkb0PytNl7w$A_{43VP|D8YH(#|Itfu{VnS#_Ze&G3vj|Ae6IvWhM@K4V zEG=m+Y%Om;Mnd#H~G7 delta 222 zcmV<403rXe1=adWuWMwuoG&y2r YGdDLhWn^Y#HfA(5WH~uuWo2U;01)?0T>t<8 diff --git a/app/src/androidTest/assets/backupTests/chat_item_contact_message_04.binproto b/app/src/androidTest/assets/backupTests/chat_item_contact_message_04.binproto index eba7b0574495498e8ef59d148e949b17d9a27a3b..e0ce2f6a4de1d47d77d354d6eeb5a5d2d1a9e4d1 100644 GIT binary patch delta 266 zcmV+l0rmdE1%U>j0)PJjBK!de0uTWh>zBFIz%fb<3JVAX5RAdl-=sAn0Ak+(3fut- zAPNOTY-wg@5(YzTVRCC_Dh5JwVQyq;G6z9*a%F63ZyFE^3^X)1H!v_cFfcSUFc1VH z9ts*mc6dQgX=!nKL{3m{VnBIeLqbPEdM$jD1I;_%G`N&!Ws__?@^jm?ZLEiEi8O^gIs zltj1$LPN8?-9sD-LPA|b^zw_+1z5B=IT)2#Q@q2%MY4^Il{hnV6Vp@m3-Zz(-U@g; bWt%*mNnU_KiouGzBCIs6!ZRo+#Wx55@C!0Z diff --git a/app/src/androidTest/assets/backupTests/chat_item_contact_message_05.binproto b/app/src/androidTest/assets/backupTests/chat_item_contact_message_05.binproto index 7d7dc339a162e0e3ab1a98ec39a2d486bb9137c7..ccf43166f6207b74b00d160b91dd6d67fadfd97e 100644 GIT binary patch delta 435 zcmV;k0Zjh=2ki%-0)OiRBIpAM0uTWhmBhHG|1nAk3I+%SDgp=rV$cH$%>xQA3J6DK zZ)Rq4WqA??O<`nYZ+IF5O>!N3HZZZfCkh%vc6dQgX=!nKL{3m{VnBIeLqbPEdMp!Gbxu)wXiq|MGIJsdX>DO=WiM)QWoJ4GVQy|`d3sKGdRiPzN>VH~Hf1i8 zdIJ?oItma}Vi=?$S=>mI2PuesLbDqgA!9oBbs;Q dbmphC;Z%XA6khQf06Gg*R%CQcOnPKZVstlfeQP2OmQ!*tpS64}Ib8Tv03J}Dohhhlit=-A(V^^Pg zeFzc|fR)d6f1+9$8^38=WIVl07`L|6tOOzmVOVKQQ)6dLC;~9n{^7;#F+w0XFgZ12 tW;ZoAC1znVHDNJ1F=Aq7HaRt7HZ(J1Vq`R98UQ*9LSjpGZ*)R-b4x9siD>`; diff --git a/app/src/androidTest/assets/backupTests/chat_item_contact_message_06.binproto b/app/src/androidTest/assets/backupTests/chat_item_contact_message_06.binproto index b0cb8443955bd8c26e89cdf2a6f35d95bca6e813..cbf7a83214fe8879ea43347dc9f042b85b19f3a9 100644 GIT binary patch delta 202 zcmV;*05$)Q1<(bc0)Nf{BFg~?0uTWh>zBFIz%fb<3JVAX5aW!%#;7nV0Aj8I3abGM zE(!)gY-M<9a}o(eX=7_;a&vEP8U#&pb1otSQ*tgU2TfskcV%pBG6hp~Wp-sUc_ImE zZDD6+FK}*WItfu{VnS#_Ze&G3+!9DXS{zJCO*(y2LO4GyUXywP5SVn12C<8Fw$iUd}F-mclkRjE1rtV|vn E0Mj^2V*mgE delta 151 zcmcb>+RwUxslJy{sf&?=Nq|ve-NiX?KO1=Qa&dF82;5lwdh0qq244#p%EE+sAnE>`E9 g%(OHiHs_qgqU=;HHm9P*yp&8McE{49)SS$G0AYz1r2qf` delta 83 zcmX@ga)xCAlaIHOCkK-Nqr}1kGkYc(dhv7da6Oo0)N^8BG&;30uTWh>zBFIz%fb&3IqrQG5})10SdkW3NH!>M`dqj zW^!eD5(Z6SWMpr68UsyoE+PX;axN+dQFUo4l2uopfXl!L=ZW<2?3o$n_I5jmj zFflVU5CI|=3KLUwVPknfR%L8qb8&TLdM;ycZ4dz}2?zlq1zk&JZggleN+JqrZDD6+ zFKTdQXKFeM5d3oc=Wewcz>S9Z*Cd`O>!5DE-5G&eUeFgY+VGdM92 z0U{I%5KCold0{|Eb#8QJaxP}0vZKTS9NuD8W;)-F*h+dH8nLbF*7s}1AiI^Mni2waZyepCkh%v zc6dQgX=!nKL{3m{VnBIeLqbPEdMctc|cZWY+-Y8 zb!B=kV{dH`0~!oudPq!9Z);6jP;F`|PzVAN26<<7bZ2rJ4Q@wGPGM@k zLUA&AA_-}2VP|D8aBgQh31Mz-XL))~czQtG5=cK<986|RXp@}-8B9D15S<&9*np}% zBC+H>SNPG2JsAAR`R)QD2Sh|>SVn12C;~9v$iUd}F# R06Gg*R%CQcOnPKZVs@L2m^T0b delta 412 zcmWm8&u^1Z0KoALW=r2}B=ut6Oib|BxZ1UKEqGV~`LV$m9kg`Z9utAJ9cNc9j&`zElQD6Yp(G7E^kIP@ z1l!&2ewXJ51HRW`DOj7CBTYFaD+lg?`@LSj-){5mcK3R)$I`HtEAq(8^IYMc0Cqf{ z8Jas>xMRg_;Vk-}uWh+_E1o0?_Y|;3n3ia$=P3!Z);Yes6YA?%mYoK2iDXF=n-)Vg z>c!eot!OdTi66g)HN`&()O79o&5CN;&P?nu1nIWE5(_L;!;7gGYa@vvqCxD*baJ#E zm%i*~D)N_7(_`pHrHpbCWw4%V#}-PK>3kHNx!k?G9TI>1L-qBJz}1pV6otoW diff --git a/app/src/androidTest/assets/backupTests/chat_item_contact_message_10.binproto b/app/src/androidTest/assets/backupTests/chat_item_contact_message_10.binproto index 41bd4309baf266c0ad3e73e34cd8943c1021f3e4..ec3f85534b378a91245795d1a4f42b7b6815e05f 100644 GIT binary patch delta 158 zcmV;P0Ac^s1+fL70#mO6BCG)j0uTWh>zBFIz%fb>3JnMZ5RAdl-=sA<0tf+OjR6XZ z0SXHm1Wjpkb0PytNl7w$A_{43VP|D8YH(#|Itfu{VnS#_Ze&G3vj|Ae6O&N_A3r<_ z5E6ARFHWpFEgrE(wo8yQd>HEZ=Yj$_0#YCcuGdO$V-#mx;*%TPLTF_Uw4_fngq9yt M=W?n~)@h>}09#%)WdHyG delta 220 zcmV<203-jg1=Izg0)Ns0BF_N`0uTWhuF;(B^Ds&c3JVAX5U-uerK>SI0AjKM3a)TT14&6qGM@n=3TbU&XJs#HaAjvY2uD#wL}pkS@33Jf$fH#aaaIWRCZG%yeZA|47FLw0yU zPibj!dPGi8Zel=rVM9VkL3%E4a%T_(DhUVyA_YrjZggleZxJF1X>DO=WiN1UXF!}2 zNbU-gi~=7^JPHsdT|V_d%#%b0akv_nF?M0wM=QL}pkK+H;>3`&fRSr1BbPcChg(i+NpePN zkr1bQW=>9OaY1IP7Mn|AK}KGx5r=OkPzoq2#m~iUY;0z1X=!0$X<{V6q9np45E`28 z?H=M#5EAMdqL*KkF2JJ2$-$_^n&KT6o^52T#F?4Po0y)eUyzsX@K(U%Dcj@;O!5K@ TQVdqy6=9`m6`nysDZW7fYuzp= diff --git a/app/src/androidTest/assets/backupTests/chat_item_contact_message_12.binproto b/app/src/androidTest/assets/backupTests/chat_item_contact_message_12.binproto index 7960153e5cdbaa79dc3e55981c693351098841f0..4a8ba09d7e800adb7f096946fcb39d7398f0c38c 100644 GIT binary patch delta 440 zcmV;p0Z0CV2=WJ@0)OxWBJBeR0uTWh>zBFIz%fb<3JVAX5aW!%#;7n#0AkPs3e5uw zFA4}pWp8F?a%FiE22EjPWN&yH15I)+A_GctE-D96b!l#NZ*DROOJQ_qY-MF`8V?E! zF*h+dH8nLbF*7s}0U8$y3^X)1H!v_cFfcSUFc1P71yNUZbzXHM7YY+obYWw8KvrdJ zVRLbHWqK}SZ*33(A}0zOLw0yUPibj!dPGi8Zel=rVM9VkL3%E4a%T_%8V6TKabaV6 zcPdZ_0uly!XLWREavBY8M@>#)X>o3BQDRwClP3c=e=1rC0}=*COi)v6K^g^QOIBBF zA`NzWQ$|i_a9BumT4-b{2y|gkNOwVYZ!!mEYFJljM^QQmbU{mWP*zx0LJMelT0>NF zMqyfULP`#5a!OQhS9MNNdT38VaWZov3TbU&XJs#HaAjvY31Mz-XL))~czRkKOiEHL zHa2B0lYavhN;(PMrxafC8UQ*ARaRtlOiX%YO=5O5%8g9|{mvRclK}R6uZ4RYg=TZ*pf40vZW=P(yZjK~HIEDozLj5)F2GQ$|i_ za9BumT4-b%2}N2@Vn%LyR9Y$qModssYe6yybYW0PcR_Y#)X>o3BQDRwCA_YrjZggmq z-2yikGL-=$3TbU&XJs#HaAjvY26b$_B-85_T8TVy=FOc=Me)T{&|2w_-hOjBcLOeg{{*8bte?J+_iI50UiV`eus pH)dfnHDNJ1F=Aq7HaRt7HZ(J1Vq`R98UQ*9LSjpGZ*)R-b4#_7i%tLl diff --git a/app/src/androidTest/assets/backupTests/chat_item_contact_message_13.binproto b/app/src/androidTest/assets/backupTests/chat_item_contact_message_13.binproto index 7d43c29852220812bb45ca081aa9cf579b3ef22d..823c042aa127f3dc04a3a62b5f94949d083ccd7d 100644 GIT binary patch delta 202 zcmV;*05$)S1=0ne0)Nl}BFzB^0uTWhmBhHG|1nAr3JnMZ5RAdl-=sB40tf+Ot^o?G z0SYb(20?6PcxiJI2}EgQYh`kCZ*Cd{O>%QCA_G%$E-D92VR(0CY-}o^Wiojp z32AL%XJs#NZf80PQDSVn12C<8Fw$iUd}F-mclkRjE1rtV|vn E0E~7^0RR91 delta 153 zcmcb_I+1k&Q++?9QV$~slK`W{!UHpVCK-D1bMbPp2&|ubYUyf2FD4Ggq&%)1E*&oR zpv2^i#MB%icITYL%98v%DHh+NVm&41;37RO4xjv@qQuO+R3m23vP2^rCC<#;#Pn4C zg1mGq4);J8m$V4COot!B9+^=xKAyf-wLwl6_PTLCdMQFCvHp5_+1~L*rJnZrDOn6s F3;=?DEfN3# diff --git a/app/src/androidTest/assets/backupTests/chat_item_contact_message_14.binproto b/app/src/androidTest/assets/backupTests/chat_item_contact_message_14.binproto index 964701ccf18610bff8192a65048b9b5e2b790dd0..d550c1b373367b351d455c573a7c7e8780ab0586 100644 GIT binary patch delta 69 zcmX@gvX5l}lbx-SH3yRbqr~g!JFgrt^y1)R<6!Y(;$TWr;ZovK;9_;o$xKTVVsp+( ZEXq#RVsk1=%uC5MVs|VpO3lg42LN|X62Jfe delta 76 zcmdnTa+GBOldFr869+sTMFA&676SkP diff --git a/app/src/androidTest/assets/backupTests/chat_item_direct_story_reply_00.binproto b/app/src/androidTest/assets/backupTests/chat_item_direct_story_reply_00.binproto index b9e69bb821bfceecbac9f822304e27dbf950f8a1..d6589a066b770c8fb39449afd49d05b83ea6d656 100644 GIT binary patch delta 64 zcmV-G0Kfm&1i1vD0y#J$HV6U`1Q@UWrP;wZLJ$b9(VXq`Fc6`@nT(P#AOV^I777#! W5(*G>Z**ZGa%FIJWNBe;WMO6K%@(@= delta 94 zcmV-k0HOc61lI(h0#{ZdR0skP1Q?T!iuC(6LJ|nw%>Tp1F%Y5rgwdNc7y%#wngKEj zFbXaTENx+Pb73HEZ*6IAVRmUCb7gLGWpZhBAY^4@Z*pZIX>N37a&U5GbYXI7b7*!W A0RR91 diff --git a/app/src/androidTest/assets/backupTests/chat_item_direct_story_reply_01.binproto b/app/src/androidTest/assets/backupTests/chat_item_direct_story_reply_01.binproto index 7d225396402e11eb520508cb7fe63ed050d8559f..a00cbaa5633d117dfe63c2356c132509fd786608 100644 GIT binary patch delta 188 zcmV;t07L)e1+)dA0)MgrBCi1m0uTfku>Pgl!8bw>2(Qtc?ej1YqQIGqk}((ongNah z8W9Qv@Sl=^5CIt9+^&GvF(3g7c?u#58g^xJX>@gSAa!naZ6I}YX>MU{Aah}GX=QE_ z1P}or0TNRp6Le*GbT4=O%{AWgYB;4~`WHQl~{^;w0%zg@BHsZB0uTfkl#Yt@`!zxi2;R*9!^JTWqWpx>n>3mMzyTT& z3Iy<K57WoBt^X>@6CZe?>Ic5iHTbZ}vGAah}7 zX>@dHa}op)0U!YqeUo7V7H4D%5HxCE`Ft^glD%$o|Bxca`VtUXV?AlrU77ayarlFp zoZ{FR=(eTn0wN7XLs3_Cb#+BXLv2HGC;%{wmZP=uF+w0UIW{vhWHvcuH8o^8Ic7Fy UI5#n7I5;yoVL4-EGGsU!02>Zb`2YX_ diff --git a/app/src/androidTest/assets/backupTests/chat_item_direct_story_reply_02.binproto b/app/src/androidTest/assets/backupTests/chat_item_direct_story_reply_02.binproto index 30de5bd0d7db9ae8a3e3f80120aa8aaf63c50577..5deec4e8e049f222b9ddc2f820c55c138aa90d1e 100644 GIT binary patch delta 237 zcmZ3)`i*q~Q~ei4rH_mpOahD&8~-i6dC=U8jf;hYMT%h-<1I!hK`xdL^CvX`CGX!^ z*KplX0V*`HSAa$00Yr$2Ya=69AeVD-Vos_;VQFG&QEFaFX|6&_W^qAjNn%N6eqJV6 zys$J?Au&&(peVH@6DVJrlnE4(RwzmZie!NFUOoNv$Z+uh1>d zOwUWq(JjbH%*?am&dSIOP76tQ%g^@7vf&aqpXO!R5E-YnTy^8~hGiLY0utLdo&LsR s!4#y>@%WRM;__C(z~+g+k8aA{=Jw(aSFp_FL%(k*f2 z0vUgX0U{H0Wq5Qicr9~jXKrC^EpTjMX>K|NVOL2)NNQ#Z5NG|%8pegFuG`X_v@V!U zWfBmVO7*9tS!D_(knhoqB%a$CtcTOc10oGYLs3_Cb#+BXLv2HGC<8EzmZP=uF*pK3 nAUQWQVP-X9H(@k2IW{#gVKOy2FlAZj)RB z8&*{!6Le*GbT4=aTwQJ@+CfaOJc delta 153 zcmX@XI+1k&Q++?9QV$~slK`W{^uDeyzfHY(xwtu41lG?zwRE+i62mOUd?`ULmJjnM zH2{?~?r1xB!AOCTD~ijOOEEJ~Atf~}GcU6wGe0l2SfMOGr?jLXu|%ObF+H=SB(qqE zje|{qNr6d-MSxL(5lFIt*(?goLXt|tC8-r9`a%`D#hK}Oi8;CjIf0tgE1S!?I58(xp|CVDwJ0?&r8HL|C9}Aov?Q@4Ge0jA pEM8ces*sqcP*9Xwk_nVAP0B1RrH68!} delta 138 zcmdnYI+Jw)Q~h*Cr74UYOahD&Gy1x|{5JLC;9}!o(PH9YoW)opCCJ6{Vg95Bplsug zwu2Xp6c`~w6MF?%B$^;XOk5#cL0np;C7F4Nxe6uuC5Z|}sRgAenTdHRiKz-nMWrRF g3T3H9nI)yg3Z;3axk79li~_6*EI^uR@=PWv0Eq!9_y7O^ diff --git a/app/src/androidTest/assets/backupTests/chat_item_direct_story_reply_06.binproto b/app/src/androidTest/assets/backupTests/chat_item_direct_story_reply_06.binproto index 852ddc0f702babca35dfb08641029820c728ffe3..3481b30745798f12d12892b451019e8b49e73bf1 100644 GIT binary patch delta 38 wcmV+>0NMYh1f~SA2m&6p{-xQ$H%bi(3kU=d0NMYh1f~SA2m&6Nj*9gAHA)Q%3kU=d*rV&Ut~DwEngIq91n{4dfDO0~3IG5A diff --git a/app/src/androidTest/assets/backupTests/chat_item_direct_story_reply_07.binproto b/app/src/androidTest/assets/backupTests/chat_item_direct_story_reply_07.binproto index dd191cfba8cafe93f4879849e266ca155b66bd07..965181cb18b90c3a0bc0735eabfbed05808a631d 100644 GIT binary patch delta 59 zcmdnZvYTZC2b1x(e@ky3H231?;^klw=s9@d{t{CoCJx3~jFM7Iq PUBh)l1x6vDz{FkvgfQf?O;g=1=SuV3BwL5n>Vo3G@K~ DG_e&_ delta 52 zcmX@ga+GBQ2NT=uzOFC7O(*j)i77VjXghepNP$sGkc;KR{E58+ED}u+AtoV^Kpy}Q C=M*9U diff --git a/app/src/androidTest/assets/backupTests/chat_item_direct_story_reply_09.binproto b/app/src/androidTest/assets/backupTests/chat_item_direct_story_reply_09.binproto index 77af7f7fc07d83c30405271fc944c6bdc55cd0ae..2277ddcfad50b7565cc17bb53e632212a7729881 100644 GIT binary patch delta 49 zcmV-10M7rc1gZp}0xBsYCkO%%0T{UcrP;wZN(~AN2m}!0jKIdIFggI50SXcb@Sl;5 H@Sl&qf94U> delta 51 zcmV-30L=fY1gr$00xT;cDF^}(0T`T)iuC(6N)HMR2m}z=qwBSqQC4#ruG3Q~exEFb1i dY5*#_e`j68bwdS4A?^?JC$4K`xdL^CvX` bl{D^XJ9xoJfl-M2!~BUWA2sv>#diY$IcFMz diff --git a/app/src/androidTest/assets/backupTests/chat_item_direct_story_reply_11.binproto b/app/src/androidTest/assets/backupTests/chat_item_direct_story_reply_11.binproto index 8ab0bf08bf9449b5275cbcd0d56d65d1fbb4e7d5..a7a841bf08eb9c643431ec9ebc3f80e6ac8a4d57 100644 GIT binary patch delta 92 zcmey!a+PHPQ)q}%5C@Y0qr|R%OK%=D_hRE>;b3uMn8j!#CCJ6{Vg95BpxpgC>l&^b oDlkHXCiV)jNIZZDF>#4-32_OOEqr|+vt}nk$z1X-|I9Qw*W-&%c339P~m_MljDA%~7?cfC? z1xAR_#9jdwi6)2;6PE#(9+ysTVsUYzLSBAuW?o`hrb2OQUU6zsW{E;dYI1&2szPR7 PNor9+QEEwIQD!j!F~unK diff --git a/app/src/androidTest/assets/backupTests/chat_item_direct_story_reply_12.binproto b/app/src/androidTest/assets/backupTests/chat_item_direct_story_reply_12.binproto index 9b9d2dac9d07fa51ea4187c29630d4c469f44e5f..91c5378c39b07910cd5d8d920c5bb92cf7f2fc9e 100644 GIT binary patch delta 165 zcmV;W09yah1)T+;0)LwUBA5XP0uTWhyZ)uw!8b|`3JVAX5aW!%#;7n#0Ga`N3V8}5 z3L180a%psRb0BqYb!{MZbZKs3Z6I@DaA{?35(E$dAOR9nA`^6Fcyup#EpusSZeeUK zaBN{|ZfZIT5d4KardXjMC*&zX;^FjKmKf8Dr>O%{AWgYB;2tz8;5FU8f8=HTvqjl7 TU))-;&vLK_IN>Glb8s2}pWZ)a delta 216 zcmV;}04M*Q1<(bc0)Nf{BFg~?0uTWhpN@+3`!z}p3JVAX5ZI&ZwXQWv0Ga`<0Sc-C z3MmR9X>K57WoBt^X>@6CZe?>Ic5iHTbZ}vGAah}7X>@dHa}op)0U!YqeIgTdWq5Qi zcr9~jXKrC^EpTjMX>Mv{3J^4EU-^77f|9*%bN`Sc#`+QvSy5v>Y1Lhs_V{u5gPNS; z*cj-xrRxGB4MjsyS9NuDMMgtyLvbhoFpQR?wem4SAT>EQGc#m1Ib=08WH~uzHfA_C SF=jY8GdW>7V`VaAI2r)yiB2W} diff --git a/app/src/androidTest/assets/backupTests/chat_item_direct_story_reply_13.binproto b/app/src/androidTest/assets/backupTests/chat_item_direct_story_reply_13.binproto index 0cbc5ad8ec858441b4ef1f3ec9a436ed7a4bb6ba..8d726bfff8e1027017acc4071905ebf46ef22a58 100644 GIT binary patch delta 244 zcmbQv`i6A@Q~fJOrRR(sOahD&d;TrGdC=U8pNp4+MWE;4h5JiPy_h%{XE7dUloI4( z`7nP{15nldJL?**8!9kzZDiyM=f%t=)!EKN);O3h0t%~eRrEG{T5Ni50C&&vdh z7nY_fB<3j;6s4AA0_97SGC?9msX&1YpqAXyyb>W60Tu-&Fv%-aU&kJDME)+gJzwI?>+^S5l-R>7BLniX k6E&C&{!dtO{jFh?KyLQKW6R$Lbt>t4aO_=m=cg0{074^MP5=M^ delta 151 zcmaFEI-PX^Q~gv%rAdq&OahD&3;Mdg{5JLC=i=pH5m-O>)Y8?4UQ8T}vlxq|1i4r~ z%%9W%RMfbm?cfC?1xBtoE(Wq$FIDT2Z23p<6t8784H-drD+@Wn@5J7K0Q608U#i A_y7O^ diff --git a/app/src/androidTest/assets/backupTests/chat_item_direct_story_reply_14.binproto b/app/src/androidTest/assets/backupTests/chat_item_direct_story_reply_14.binproto index 7d9cfa1a7fb758662bdacde815ac0572ee650a25..691c8917ac79160de96dfb74aef0b3b10bd71db7 100644 GIT binary patch delta 223 zcmbQicAa$rQ~gy&rAv$)OahD&d;cxHdC=U8gNu!W#fyo9X%^#7MkzrqmJjnMH2|gW z-&xmi-B1B4G_hBJMdATOh>2?gBbOGJKuLZ{qC!z>L1{{6VqQvOst_9oqX4S{3y@|K zU{YWO(riGQQ7B1CxFofrM886}I3hDWFEK~AASW?1&x$)MBQH2DB;74P+b7G0OW=H( zS3_i+)^gR2&l{Fy$O%Yn-*oyLiv?4VLdWAzUW&_G1p}KW{yw@XcbnUbJ6ypslMnsA Nu}Gd>)#R!a0|5SlN|*ou delta 276 zcmcc4I)iNiQ~fk1rO8YjOahD&3;Vjh{5JLC;9}!o@d66XV*JG@CCJ6{Vg95BpmgJo zwu2Xp6re&Adj(h|njk_Ymoic(7wi!zIa*f7ww=pUSm!wvd=vU|#XQt;R=I9pWBxdGW zu_lIlI(cNJaS5dVJuP*tb;Y{dm*#BIo8g-(Brx6U>+&U$sa&cP-e2rdnRi=aP5b2& z%u2kj&Vk{jrKPTJ&biKo8q5Yg(-v?2WN5+Uq+n@ol9*UO)f< diff --git a/app/src/androidTest/assets/backupTests/chat_item_direct_story_reply_with_edits_00.binproto b/app/src/androidTest/assets/backupTests/chat_item_direct_story_reply_with_edits_00.binproto index 72ce2d59d5a289e0add1a77c1b5044effbb1c441..3154da64eede4efdbdb8af1d0627c0cdbd9ee0f4 100644 GIT binary patch delta 139 zcmbQsI+t|=7gPPiGqXRgG&PFmU=m=Fc=~lZkmJP1aU0AKcmk$oG1_ujb6Ikk=av>L z6qM$aW#%OoDdZ+*rWThZmSh$yB&H~&WG0s+Dx~HEIXRiBd8N4ux%oLcK)KA)VxW1~ b!L|rI08_IVWx1reB)P;(OB5z|GKl~HsJ%AU delta 139 zcmbQsI+t|=7gPP5TeA*cG&Kt6U=m=Fcsz3&kmDr8aTClCcm$>-7!??2F`9B2a~X2! z7w6}smME0wE7AfQ==A|U&mKH0d7M5nFq~anVMIctB{+YlLM5? zEG;(51RLH5F3h~2Xo zJ-NUZ)t6e8|3dM;9K=+rV<|?EYC6;BTBr4?RW|ovB z=7HRll$iun2=rWDVy=@A$NxE?uoLJ22O-2Cix{N@xmZ5TpVT10D6xC_v6mN&6d1XB z7`gPh)KkHsQk0abFj<#bB`Q)$xFofrM886}I5RyjF-Nx`CowZG%YjQEEVJyXcv;AV zJul`ITWFbROYA-OtV)R|sw&qn&#THcu`I_!gTdhBr+ru68%7CC52|e4E_&9#v*?S) KJi$$RQVam?GrMpA delta 422 zcmey(ewuv&Q~gP1rDMz-Oad$tzuPW!ZZb3q2XhV`I}PMG332QIGXxHTDG5de##xM} zT*h36T>8cNIjJQIr8zl?xykuO1*t^}xruoxiMgf43aN#qnJKBc3Z*4LE>JwRq_o&b z8*K1lh{1duJHd>40fmnp^_37$}~YtB{#jlA4o~nx0sqkeZWO z;>5@C5$s(BfnQ*H7ULmCDM2ol5A!EA2rx?goxl6_S7QZ6t~HbMn2oC{m4r)DD@yb$ zbc-|7^AdA(3vv=O^Rg1S1d22>88VJ+m=l&+_EfwqWP*@@g_enS3{QOZ^q|Vt?V@M> zCC*QLvWroP)7>LGHz%*k&rO5DVC8~EyT2MbDHvNAB^sL;C7C80B%7w0Cs~@C8kt*K Qm?oJUnkJ{1q)9OV0CjGeO8@`> diff --git a/app/src/androidTest/assets/backupTests/chat_item_direct_story_reply_with_edits_02.binproto b/app/src/androidTest/assets/backupTests/chat_item_direct_story_reply_with_edits_02.binproto index a962fe37fc3be8e144a5a2749e99a10c02e9ba5f..a00a2392ec51d3e5e6b9e24eb1879a302bf7bc24 100644 GIT binary patch delta 279 zcmeBRJHobrss0d?(taimCIJ?Shi7JgTxn_)4dy)kIvvPy;^VjtW(Yh1Q?nRtxvaS? zxy*A*ixmn=bILOF5{nda6EjnbOA<>mixm=66jCyiOA-}Q^MRb4%+$QnT!q~HoE)HB zW@$0dyz5|F1Rj8?S&Z6;8KnfdSU$|3)F8kpv3vQkmluo_ph6RSfv(yE5n|$+#W;B- zlT|{zl5k0CMTvfeZgFOMUSf`JK~7?3o)w2nNP2;%S7BwA4VOT~LIw3FnvRbieuQoHl8oqz;5wS^?h+c4VP4i6axUx CCT~;# delta 219 zcmX@Y*1@)bslJU#shNp`Nq|LS&aGJoFPa*KgE^09P6KkBgg9=383K>Mlmw#!<19u~ zE@Li3F8$*CoYWG9(wv;c+~oYCg47~~+{C<;#N5(ih19~*%#_qzh0+or7bu=uQd$f& zYZBN7f!SaRVwP4rqm&>Q%ZK@s8Uz?6{?6b1`m3=5RA^!^&{h8+LQGuolUFfWsj4Um nm!wvd=vU|#XQt;R=I9pWBxdGWai)fpr1|?6q-16>NHG8aH_%T* diff --git a/app/src/androidTest/assets/backupTests/chat_item_direct_story_reply_with_edits_03.binproto b/app/src/androidTest/assets/backupTests/chat_item_direct_story_reply_with_edits_03.binproto index e0a7084e88f2915cee5d5ba32c697c000c10bf5e..820e2212ff8c27cea996ffeade37f7edba89523b 100644 GIT binary patch delta 463 zcmX@h{*8SBQ~eiarH{-UOad$topZ15{b_0x4d(P7y9nes@o_YR83H|EY8Im{mo=9q zmw9e!u|h#nVMIctB{+YlLM5? zEG;(51RLH5F3h~2Xo zJ-NUZ#g=83rRJsNE2JeRmF6TCD`Wt9K>e8|3dM;9K=+rV<|?EYC6;BTBr4?RW|ovB z=7HRll$iun2=rWDVy=@A$NxE?uoLJ22O-2Ca~Zj2P3C4cO-of0E=jE@(XY@g&P>ls z%+W2#NzBZ%;>`95baxFZDG$zacKW==;g~#fdo)iNB^oO^+ delta 405 zcmeyyewKX!Q~haXr4!5?Oad$tzuPW!ZZb3q2XhV`I}PMG332QIGXxHTDG5de##xM} zT*h36T>8cNIjJQIr8zl?xykuO1*t^}xruoxiMgf43aN#qnJKBc3Z*4LE>JwRq_o&b z8*K1lh{1duJHd>40fmnp^_37$}~YtB{#jlA4o~nx0sqkeZWO z;>5@C5$s)FfnQ*H7UK~{u7i`KnN69x87EI<7Axh8@{bHpa|uZ=@boII49-g85{Uer zDmB$q^=|CSRh9am>C7AqvCD5PX2mn15r<^wr7nW=fDxeB@YIXOVN z%+g|@dDp?V2s{8&vlt~dGD-<@v3!_6sX>5IV)yc6FE1D=FmlaioII7uEi^<)xFofr zM886}I5RyjF-Nx`CowZG%bH7oUDf33_w-%sj$H1(Q@uRNTw?FJXH^!=K? zav5_Oa_JZ6=cJY>l;-3l<|gMC6{Hp^ic4op{wy}s11qGw1-J)pc zL#S;^F^CUgXKSUC8LejibNkMJM(y|ZLt{8?F1|M7M$+n@-F>`#FQsLJghSmstK z7dL6&vo8OQoCG6*T}L~_gN7AWOcWCKX=Y2R;lL@^j|Mayxcv>|&{wp=f`a5|3>CAT zGR$0|GbbqTb>g4f+3k{3f5PD7aABUbzV5G&lBoOiIQe`_Aqt_ZvAgzj2;D3-cYguz CL73bC delta 313 zcmcc2-psy$slJg}=^qmZlK_jv@3sq_n+%P@!JI?KP6IhkLL58541t4SN`g^=aTcQ~ zmob+imws`6PHKrlX--aJZgPH6L28jgZem_aVs2@%LTX`YW=d+VLTL$*3lvW+DJ?eA z1{-`BVlW@aPB5ch0AkZDMqVy%E>14?#GFi^<^rQwu<9ca)j}M*zzhM1Ziq9ixh%QN zxlEHwixQJEOMuqoWhP}PIn zIPr0O1bbIc;1`&l#aJyR$i?zu{-g#0Mv1@kcfbB>tiT8nn%D~roqu4V$u-R30Nd$x AjQ{`u diff --git a/app/src/androidTest/assets/backupTests/chat_item_direct_story_reply_with_edits_06.binproto b/app/src/androidTest/assets/backupTests/chat_item_direct_story_reply_with_edits_06.binproto index d80251ffa3581fc97253719b259a0b3f5d331d50..954c1aa3ef6f0ec8044eabbd2e085ef56f467f10 100644 GIT binary patch delta 132 zcmZo;ZDZZQ#Z>d~%Cm;_iPo_?JUp#T5? delta 132 zcmZo;ZDZZQ#Z)ur)~tgUO^w1im;_iP9?zTx7--fcunhvU Q!4$+SHX)V|^CvX`033@lrT_o{ diff --git a/app/src/androidTest/assets/backupTests/chat_item_direct_story_reply_with_edits_07.binproto b/app/src/androidTest/assets/backupTests/chat_item_direct_story_reply_with_edits_07.binproto index 415a43a7dc7bfa3131d826857526e3e7cd788485..e884d8c364ec029b2138d7f0093dd17a801f4da2 100644 GIT binary patch delta 378 zcmXw#yGq1B6o#3wEMW?XsiM`vM+k_BShynMGgwWMaXpZkS>}><1r-!rMaxA|D<48^ zQ)}Tv2!dK#>Fh+Sng86r^Pl_vSN|>=e?&{~Q5+?`?DXdK>3ccf4Pw&1crloZ55p%p z3(u6S(>1zESA;V#a&?1}X%Gy#vCN_YRzZcOWx$meHFD_$2vyfUhtA{}hM#xC)A*mI4P0xbvG9D9mTPW&6);`8Kd>sD);@0Y zVPIYS8#(TbbnGeFp#fwXY`Clx?6Jbt%)q`^z8@_ZHuC#hE?}rxgB1fM&{`&EI~7>? rLT^qoF-YT|>)Gv+lW@Y$$HL+~?S0-}9V8@sd}!aEb0Db?Tuy!gEm)IA delta 298 zcmey!wvcTBQ~i78cNIjJQIr8zl?xykuO1*t^}xruoxiMgf43aN#qnJKBc3Z*4LE>JwRq_o&b z8*K1lh{1duJHd>40fmnp^_37$}~YtB{#jlA4o~nx0sqkeZWO s;>5@C5$s)MfnQ*H7New;AQ#Jr`I8z17$yGB-~IZlu>zwIP+(#&02teD@&Et; diff --git a/app/src/androidTest/assets/backupTests/chat_item_direct_story_reply_with_edits_08.binproto b/app/src/androidTest/assets/backupTests/chat_item_direct_story_reply_with_edits_08.binproto index 6cebf5e9a5916119e3abf4585ab860861524ad07..ac64e2dd17eb6f786d963cdddc1ae9e74d9d77c1 100644 GIT binary patch delta 171 zcmZ3(x`uTF7gPPiGqXRgG&PFmU=m=Fc=~lZkmJP1aU0AKcmk$oG1_ujb6Ikk=av>L z6qM$aW#%OoDdZ+*rWThZmSh$yB&H~&WG0s+Dx~HEIXRiBd8N4ux%oLcK)KA)VxW1~ y!L|rI08_IVb)*EjSU$|3)F7bDD6xC_v6mN&6c{056MKQ~*aHz_5&|lk*arZrqeaC4 delta 171 zcmZ3(x`uTF7gPP5TeA*cG&Kt6U=m=Fcsz3&kmDr8aTClCcm$>-7!??2F`9B2a~X2! z7w6}smME0wE7AfQ==A|U&mKH0d7M5nFq~bF5XMQ6BWxid)s=&f5D*cu@I=ICu$m<6Igs5A`zP%cDkyj!S_b8O5iPH` zuoT26xYkNH8?9!(-I@8#HxHw)(Q`cejJH1GBu+QRH&5>`-`n|V5cAcW7n9B8A|&Z; z2wk+#_Si1l5zav4>XsyG5J=ouv}6D)sHn6ETzOFwmrj6Cb?yJinViD#yJ2{iT&`w4 zCLL(w2%;`JW=HIh9h6EMZnxscs@zXH8;KrP?zoxtV*Y~f4BKG zuonMDt_C9myNga(097ruTviIsuy8dRIQPo;lLdo~-`{cpQ;jWE2uhH(DEplXDtw_g cCs9nY$vR>ZL*UQE0FKoPyl>h($ delta 283 zcmaFFHi>NkQ~d-crCufuCIJ?S-)$E_oWVAV$;s)aaqff)i2-4JJ3b6Ikk zbD1WW79}QSmH@5E%S_5p$S)|#%+FIu&d)1OO)ddi3=~hyRmjXMNzKVgO;0RQNX^MC eapL3n2==asz%MX8i;+u+L z6qM$aW#%OoDdZ+*rWThZmSh$yB&H~&WG0s+Dx~HEIXRiBd8N4ux%oLcK)KA)VxW1~ v!L|rI08_IV6{G~YSU$|3)F2?vD6xC_v6mN&6c~lLKg^%F@=-%CP+~U#hE_v5 delta 159 zcmZ3$x`1^97gPP5TeA*cG&Kt6U=m=Fcsz3&kmDr8aTClCcm$>-7!??2F`9B2a~X2! z7w6}smME0wE7AfQ==A|U&mKH0d7M5nFq~XSU$|3)F2?vDDijx?$=+96&QuMKg^%F@=-%CP+~U#BV|99 diff --git a/app/src/androidTest/assets/backupTests/chat_item_gift_badge_00.binproto b/app/src/androidTest/assets/backupTests/chat_item_gift_badge_00.binproto index a9d17df69e486c7f9c2573703af84c4da7c22572..a22ea18864109fe45a5e148ac3dd7fe42a60c4e4 100644 GIT binary patch delta 379 zcmV->0fhea2J!}=0)OxVBJBbQ0uTfk>zBFIz%fD)2(Hnb?ej1Yp}?7pk})6wiUG_5 z3dsThc%a+yx#;0zyZc&vF0U;SH*}1>68-Zx>{8@TUE75xUa5S2x5V{-_&}W|ugc7o zs20!zGwDrY%U?MVL?LZvI7HGq7Bk3}AQZk7+=%C;CFJ0000000031 Z00000004N|%~V56%5pSnU-^77f|4ZPs9FF3 delta 381 zcmV-@0fPSW2J{A?0)O%XBJTnS0uTfkuF;(B^DsgZ2;I#8!^JTWq5Oo=n=}{!AOVU2 z%mNC@0swxg(Lv=H)_(XIAvd+FF`}fwXNZwU0g}o*ye{Xth60vS0E`?Ms!_|Ml*GLC z6e)!+c4^=;R<*W%lbDZuR1;osfXq5+M(h_HPoxpEq~t7zix69>ZeSi_$FH- z%GgHbteOIb@^FEtnz58LtPyMAaiZ%tf}uze<4X#-sd3}SoMKm^v>>iSBWUI+SZ$v+ z?(9T$l*|+o2E=lJ000000001gu~u8X2U#D8NALosLOj@KGUDVosQgTLU8_-1;<5+> zzhzCVY4cwPLUyEvb%)HH36KhOL9;h%HT!*%X|?18yo#v~RY-fbfLM?ujcqU+QTaak zXj+ku+ptS+g`tcGj=TI$;MU-1%T>nHVR#P63DYxi+Citit950000000000 b0RR9100000>-Fa$6rWk0t52MY3J+nEPkgD~ diff --git a/app/src/androidTest/assets/backupTests/chat_item_gift_badge_01.binproto b/app/src/androidTest/assets/backupTests/chat_item_gift_badge_01.binproto index db06c660eae6e27a538456cfdf421f69ec9786f3..411d0eb7200d633f2a49f8fcbf19d5764b37a0a5 100644 GIT binary patch delta 381 zcmV-@0fPSW2J{A?0)O%XBJTnS0uTfk?3cOJz%fD)2(Qtc?ej1YqQIGqk}((oiUH07 z3dsThc%a+yx#;0zyZc&vF0U;SH*}1>68-Zx>{8@TUE75xUa5S2x5V{-_&}W|ugc7o zs20!zGwDrY%U?MVL?LZvI7HGq7Bk3}AQZk7+=%C;CFJ0000000031 b00000004N|%~V56%5pSnU-^77f|3vcc%G0fhea2J!}=0)OxVBJBbQ0uTfkuhE?C^DsgV2;R*9!^JTWqWpx>n>306&H@U_ z0swxg(Lv=H)_(XIAvd+FF`}fwXNZwU0g}o*ye{Xth60vS0E`?Ms!_|Ml*GLC6e)!+ zc4^=;R<*W%lbDZuR1;osfXq5+M(h_HPoxpE#A<-ZhvwU>ZeSi_$FH-%GgHb zteOIb@^FEtnz58LtPyMAaiZ%tf}uze<4X#-sd3}SoMKm^v>>iSBWUI+SZ$v+?(9T$ zl*|+o2E=lJ000000001gu~u8X2U#D8NALosLOj@KGUDVosQgTLU8_-1;<5+>zhzCV zY4cwPLZpUuhjh%G36KhOL9;h%HT!*%X|?18yo#v~RY-fbfLM?ujcqU+QTaakXj+ku z+ptS+g`tcGj=TI$;MU-1%T>nHVR#P63DYxi+Citit9500000000000RR91 Z00000>-Fa$6rWk0t52MY3J+nE5CI8JsjvV5 diff --git a/app/src/androidTest/assets/backupTests/chat_item_gift_badge_02.binproto b/app/src/androidTest/assets/backupTests/chat_item_gift_badge_02.binproto index c7fbf5c13f028e839604d859c0dcf1007c4c9294..a7f507987b0ec04d8001ad83f6ab11b73a3e2f63 100644 GIT binary patch delta 362 zcmaFG_KIx-7gPP)={v6+F!W;MV&PzsV(4N#$HaA#iJ@Y_?TPKz1^xFx3Z>o`;o8pKOE+&tv_{U>I$(7%*HQ$lTOE53b-idrdhaL zvJx{sF-<{apU9n#=Swx%VtI0UB<`eV*JyrP%wqXN_UZ3-zu7O}*LS^$?^d%-RIp>( ztf){_cH={au*_s7-GEw!+rj0P9IYPP*$t-FTx6?>S+x4(sb@jVv)fnaNK`g3K)}AY zGitqz5;xtNX7x6_oO?=#5tB}u+U1Sw#7u8JZP?H1TO0kkgV!x7{7Q0-X1k|z@cgnF z{Mv5yZ>HbUN{XM%o^&nm{KX>frOZ6%EIN-~c=R(ZM8YP*Yvz}-^U8v9NeR50AJ2TS z^|{mccj1@h4XWB4Zroh@OYzN@8vhHwj~-l>!UA;%10$4Car115v-hbYldSlkHHJ-- G1egG&LY}e! delta 362 zcmV-w0hRvh2I>Z|3Iczy(VXq`FiHjr1PBBg0Ez+50t(3j0Dh^_LFE|Me)t(7H?^xV zqNKrRh>=GDlFB^1F6X(10+vz$j2sxMQOl#0#Ju$sDTOX}Y2Y$ewYGkfn2&r^6JBtD z%sOf0`EQu&FnPK))T`1h-q62paue#OOrrQETO!KXM&+!U0)~I`aDk_qv6M8d5o_Ra zqU$$;p-2(qOA5HDapT9FVppQHAg)6rXyz$cZJ##o>_l~x%oGv^#BzWD00000004in zR$ILXSs#c;@B*enJlJP4;^a7}{7iUVt5H$nvIqmeWlgMU^Ir!-q=t2e%$y033UooU zH)=KeeUfRl^A`9Aq*T9J<1uuE=*p^OKPybfhhuVa!r zVFxDM`Cw_87$>_<0f+UuHlanV!sY}30000000001000000002%_2(fJpIM!&Pn?Ph I4`GuK0+u45X8-^I diff --git a/app/src/androidTest/assets/backupTests/chat_item_gift_badge_03.binproto b/app/src/androidTest/assets/backupTests/chat_item_gift_badge_03.binproto index 49a564ac47aa57f5643813344145469657397710..4bf2265e8a315fba886e01d8fc64f1412b1f5513 100644 GIT binary patch delta 36 scmZ3&vV>&=2b0XZ={v6+F!bW*;^klwc-(W~*a`zBCJx3fMkWDf0Py4sPyhe` delta 36 scmZ3&vV>&=2b0Xki*w$7Ht^!-;^klwxUu;4)^(;zOdO0|j7$Q|0QUL|tN;K2 diff --git a/app/src/androidTest/assets/backupTests/chat_item_gift_badge_04.binproto b/app/src/androidTest/assets/backupTests/chat_item_gift_badge_04.binproto index 2e133c8480d27d11d052adfe4104f1acac51f8c1..0f4edf9f5bdeff9b362997dba8cad6512e63988b 100644 GIT binary patch delta 367 zcmV-#0g(Rh2JZ&23Ic!cm$}ryF-i>z3kU=djKR>~q%|S{iUG_53dsThc%a+yx#;0z zyZc&vF0U;SH*}1>68-Zx>{8@TUE75xUa5S2x5V{-_&}W|ugc7os20!zGwDrY%U?MV zL?LZvI7HGq7Bk3}AQZk7+=%C;CXJ(XKQ>Z@}mSf_#J=c`-e`O>FJ000000003100000004N|%~V56 N%5pSnU-^77f|3L~qN)G@ delta 367 zcmV-#0g(Rh2JZ&23Icz!(VXq`FiH&y3kU=dubs-Jt1%(~iUG_53dsTheyPzx!tI{pr(7$eS6Y8f-qWC6TBFcZ*M&+!U0*3N%fv1|W zlr*dnYv6IB>op3b?6p~0YBgv3eUfRly2PWM4U}>2cC%aAohxNHOp+&61<^%u$000000003100000008Ut=OGlI NS)Hp-oQet$VUwa3qagqQ diff --git a/app/src/androidTest/assets/backupTests/chat_item_gift_badge_05.binproto b/app/src/androidTest/assets/backupTests/chat_item_gift_badge_05.binproto index 2731dd0f22c2dbe2fc29aabf1deadc241c8c15f0..a140a79d31b6c681e18e4383ba2198cfc68ffcb8 100644 GIT binary patch delta 364 zcmaFE_J(Z(7gPO*={v6+F!bW!V&h=ZV&Y)zVm!yhb&`ppV!`c?J6}9Z-u*kOMsK~Y zpm|BpUZKCA&EEt)@r%9Psvftprgr<0uk}A1=Blkfb!O@cu?x(`FMX3v$6E@xDCVYF zxLmRlGd?j*L1drEosQ>AHP~W#a(X20q-WP?ep<|8`9t>U?{>f0^)KIdy@>BtvrSa6 zW7@2!P*ir~Lx!--WF_5zT7}!e<&_+*9^2Usrq*0!tBF~(`sAr+LCmw;SLaAnHZVZI zzPB@Ky^In!-I`|gHoTmBN{11XPMX@~jqAirZ#`|;&+1zn{kenJEh+p;a*bxYr*rW9 zvKjo^ZuM`b-_lBoPnpbqE${rrBJQQkJm)Mrk6w86Gc82ICc4A#&6gVg3%`#ZT$aKDbq50@lu>c>Y>2b>sUnlC_@6a~ IO_Kx|0q7c@*#H0l delta 364 zcmV-y0h9jh2J8l~3Icz#(VXq`FiHpt1_%Ty0tf+$0nP#n$pQd=snJ2@7}kFH86h{d zt1+Ua!Don(M*)(`JiIRFxrPFkQUHt`7^+drqm;zF^%NZeSi_$FH-%GgHbteSrUhVpQMr<$>pG^`P8 z;BlhsH-e!^5#vh=xT$gD$DCqUqO>5cLnCPBDOhcvHty_1b(G8$5(dO_fB*mh00000 zf3a3uy$4wzh)3`Orb0Z}XENgCIH>$gcwMVeQR1=)1HWZWtZDOK2STKVb%)HH36KhO zL9;h%HT!*%X|-hJ1iXr=4pm5dwt!fWB#mt_8&UZ_`Dj{^j@z(HZiS(Y2adcBWl*nU zk~(1rCfxa8X_*)&yG{Xz^|>~oMXbW+1ONa40000000961000000PFSVArzlkovTlr KiV6>5lMn&gQlE|h diff --git a/app/src/androidTest/assets/backupTests/chat_item_gift_badge_06.binproto b/app/src/androidTest/assets/backupTests/chat_item_gift_badge_06.binproto index 0572e04d199fc4d006433c81dff5d1694cb6faaa..9c0b101d4ca65a79b9ce09a8374b01dc62261904 100644 GIT binary patch delta 369 zcmV-%0gnFh2Jr^43Ic!em$}ryF-i>z3kU=d68-Zx>{8@TUE75xUa5S2x5V{-_&}W|ugc7os20!zGwDrY%U?MV zL?LZvI7HGq7Bk3}AQZk7+=%C;CXJ(XKQ>Z@}mSf_#J=c`-e`O>FJ000000003100000004N|%~V56 P%5pSnU-^77f|3vdRzsr3 delta 369 zcmV-%0gnFh2Jr^43Icz$(VXq`FiH&y3kU=d*rV&Ut~DwEiUH073dsTheyPzx!tI{pr(7$eS6Y8f-qWC6TBFcZ*M&+!U0*3N%fv1|W zlr*dnYv6IB>op3b?6p~0YBg#5eUfRly2PWM4U}>2cC%aAohxNHOp+&61<^%u$000000003100000008Ut=OGlI PS)Hp-oQet$VUrL7ioT<) diff --git a/app/src/androidTest/assets/backupTests/chat_item_gift_badge_07.binproto b/app/src/androidTest/assets/backupTests/chat_item_gift_badge_07.binproto index e6941ca8a16faefd1a31ebfee086c6b75b44ea93..23cffce86bf5373f3de2c2c5676a4baec5c491cd 100644 GIT binary patch delta 36 scmZ3&vV>&=2b0XF={v6+F!bW*;^klw=s9@d{t{CoCJx3fMkWDf0P(X6YybcN delta 36 scmZ3&vV>&=2b0X!i*w$7Ht^!-;^klwSU>mF($$7WOdO0|j7$Q|0P=|oSpWb4 diff --git a/app/src/androidTest/assets/backupTests/chat_item_gift_badge_08.binproto b/app/src/androidTest/assets/backupTests/chat_item_gift_badge_08.binproto index 36744216361b6274ae2a819e31bc7d957be78c24..89c1bdfbddb83dce0d1688eb6ce5e9fedf31f6e6 100644 GIT binary patch delta 360 zcmaFC_JVB#7gPP`={v6+F!W;MV&PyhV(4N#!^CxxiJ@Y_?TPKz1^xFx3Z>o`;o8pKOE+&tv_{U>I$(7%*HQ$lTOE53b-idrdhaL zvJx{sF-<{apU9n#=Swx%VtI0UB<`eV*JyrP%wqXN_UZ3-zu7O}*LS^$?^d%-RIp>( ztf){_cH={au*_s7-GEw!+rj0P9IYPP*$t-FTx6?>S+x4(sb@jVv)fnaNK`g3K)}AY zGitqz5;xtNX7x6_oO?=#5tB}u+U1Sw#7u8JZP?H1TO0kkgV!x7{7Q0-X1k|z@cgnF z{Mv5yZ>HbUN{XM%o^UPi{KX>frOZ6%EIN-~c=R(ZM8YP*Yvz}-^U8v9NeR50AJ2TS z^|{mccj1@h4XWB4Zroh@OYzN@8vhHwj~-l>!UA;%10$4Car115v-hbYldSlkHHJ-- E0EY9Pwg3PC delta 360 zcmV-u0hj*h2IvN`3Icz&(VXq`FiHjr1PBB&0Ez+30t(3j0Dh^_LFE|Me)t(7H?^xV zqNKrRh>=GDlFB^1F6X(10+vz$j2sxMQOl#0#Ju$sDTOX}Y2Y$ewYGkfn2&r^6JBtD z%sOf0`EQu&FnPK))T`1h-q62paue#OOrrQETO!KXM&+!U0)~I`aDk_qv6M8d5o_Ra zqU$$;p-2(qOA5HDapT9FVppQHAg)6rXyz$cZJ##o>_l~x%oGv^#BzWD00000004in zR$ILXSs#c;@B*enJlJP4;^a7}{7iUVt5H$nvIqmeWlgMU^Ir!-q=t2e%$y033UooU zH)=KeeUfRl6im47&NPD(`Sdb)*Z7>^A`9Aq*T9J<1uuE=*p^OKPybfhhuVa!r zVFxDM`Cw_87$>_<0f+UuHlanV!sY}30000000001000000002%_2(fJpIM!&Pn?Ph G4`GvbX`gEV diff --git a/app/src/androidTest/assets/backupTests/chat_item_gift_badge_09.binproto b/app/src/androidTest/assets/backupTests/chat_item_gift_badge_09.binproto index 29791dd17cbc6a4103ca8f3b8522576fcb24b7cc..c3f8f67e0e7e24d0863d75990474f8ae28a93241 100644 GIT binary patch delta 378 zcmV-=0fqka2Jr@<0)OuUBJ2VP0uTWh^q0BRz%fb<3JVAX5aW!%#;7nl0Ez+50t(3j z0C=F=@ww>XW4rrWd@ipo5jS*rDCtj(1eYeE*fA~P1Ca=oOm8cfb z12gGOV#{AS5JVwuW;jIBIukn3~Y=T+<#|ld@1sy1UdK}<@<+D zo9XY0=wFK_Jz*d|0<$3?a(3A8XcHWhA}vsTAlp-Sc?g9_w+Aqle9;DcT%xPV%H~o7 zn}@4x70)O!WBJKhR0uTWhx6z#K^Ds&e3JnMZ5ZI&ZwXQWf0tf+$0nP#n z$pQd=snJ2@7}kFH86h{dt1+Ua!Don(M*)(`JiIRFxrPFkQUHt`7^+drqm;zF^%NpG^`P8;BlhsH-e!^5#vh=xT$gD$DCqUqO>5cLnCPBDOhcvHty_1 zb(G8$5(dO_fB*mh00000f3a3uy$4wzh)3`Orb0Z}XENgCIH>$gcwMVeQR1=)1HWZW ztZDOK2STKVb#;f#oC%N$bV0K>YBl?Pl4-T%1iXr=4pm5dwt!fWB#mt_8&UZ_`Dj{^ zj@z(HZiS(Y2adcBWl*nUk~(1rCfxa8X_*)&yG{Xz^|>~oMXbW+1ONa40000000961 a000000PFSVArzlkovTlriV6>5lMn$1m8JOr diff --git a/app/src/androidTest/assets/backupTests/chat_item_gift_badge_10.binproto b/app/src/androidTest/assets/backupTests/chat_item_gift_badge_10.binproto index e568e17a7718da4fc21833f6931f5c99464485ac..f4c616ea9f910979a5aa4da1b374cce9530f7cbe 100644 GIT binary patch delta 380 zcmV-?0fYYW2J;4>0)O!WBJKhR0uTWh^_RKSz%fb>3JnMZ5RAdl-=sA<0tf+$0nP#n z$pQd)pxg1e=;33#`&xW1uPqTbbd0?c{qr~MQshou+l41yseFC6#PxspK%FM9%FLCh z7SIDT=}ltGUpWv&A#G+jMAAAIGsu=86uuPPi07p!23-tnjDHy1XKQ>Z@}mSf_#Nf@ zhfbU6?~3SOizYo`AU*=KAs}*g*zjl*9Frm~P<%g2i9)S(Q*r=0}ReMiN(<3`DRoYJXlJZ z^mfl95guY-4YT8!;I-#M_wHBHA251`K-k%(`XTJ}d{5B(#lfaz1ONa40000000961 a000000C?HWR6|S3ax`jR`Ft^gk`MykU8NlW delta 378 zcmV-=0fqka2Jr@<0)OuUBJ2VP0uTWhxY3;L^Ds&c3JVAX5U-uerK>SI0Ez+50t(3j z0Dh^_LFE|Me)t(7H?^xVqNKrRh>=GDlFB^1F6X(10+vz$j2sxMQOl#0#Ju$sDTOX} zY2Y$ewYGkfn2&r^6JBtD%sOf0`EQu&FnPK))T`1h-q62pa(@%*r%a;wCR-xP*hb~7 zngWLMaDk_qv6M8d5o_RaqU$$;p-2(qOA5HDapT9FVppQHAg)6rXyz$cZJ##o>_l~x z%oGv^#BzWD00000004inR$ILXSs#c;@B*enJlJP4;^a7}{7iUVt5H$nvIqmeWlgMU z^Ir!-q=t2e%yXOxkP37`vo~rr`+bsWwd4f6im47&NPD(`Sdb)*Z7>^A`9Aq*T9J<1 zuuE=*p^OKPybfhhuVa!rVFxDM`Cw_87$>_<0f+UuHlanV!sY}3000000000100000 Y0002%_2(fJpIM!&Pn?Ph4`GuK0!C`3e*gdg diff --git a/app/src/androidTest/assets/backupTests/chat_item_gift_badge_11.binproto b/app/src/androidTest/assets/backupTests/chat_item_gift_badge_11.binproto index af0d405b57c75c3c801884c4d468e6ce48b4767a..891c56b7c6c95b7465b5393741660735ac18fd23 100644 GIT binary patch delta 27 jcmbQuGMi-s2b1u(={v6+F!W;MV&PzMV(4OI5?}@ZfRP7d delta 27 jcmbQuGMi-s2b1v5i*w$7Ht=HOV&PzMV(4OI5?}@Zg0KgU diff --git a/app/src/androidTest/assets/backupTests/chat_item_gift_badge_12.binproto b/app/src/androidTest/assets/backupTests/chat_item_gift_badge_12.binproto index 15d7e21b7a3748c2e2686c2e3a023a73eda20e9d..fb6819546351ed21a77d37b926c4d74a950e333c 100644 GIT binary patch delta 367 zcmV-#0g(Rh2JZ&23Ic!km$}ryF-i>z3kU=d68-Zx>{8@TUE75xUa5S2x5V{-_&}W|ugc7os20!zGwDrY%U?MV zL?LZvI7HGq7Bk3}AQZk7+=%C;CXJ(XKQ>Z@}mSf_#J=c`-e`O>FJ000000003100000004N|%~V56 N%5pSnU-^77f|5FHqS62W delta 367 zcmV-#0g(Rh2JZ&23Icz+(VXq`FiH&y3kU=d*rV&Ut~E*kiUG_53dsTheyPzx!tI{pr(7$eS6Y8f-qWC6TBFcZ*M&+!U0*3N%fv1|W zlr*dnYv6IB>op3b?6p~0YBgv3eUfRly2PWM4U}>2cC%aAohxNHOp+&61<^%u$000000003100000008Ut=OGlI NS)Hp-oQet$VUukeqqqP7 diff --git a/app/src/androidTest/assets/backupTests/chat_item_gift_badge_13.binproto b/app/src/androidTest/assets/backupTests/chat_item_gift_badge_13.binproto index d25a3e47c7137a48b8284c27dbaf969218aeac58..2f99fa57f12ce02e37f0636733f6ccd9f07d88dc 100644 GIT binary patch delta 371 zcmV-(0gV3h2J;563Ic!lm$}ryF-i{#4G07fjKR>~q%}$c2my)#&H@U_0swfR+wr;R z;bXh|T6`|AEfF_#jJ*>5^Ed2LgqFSW21ncF!Xb9%5h( zv*VfIwdX?j?pM+uFnWeS*x9A}A?);gPtg0t!KP#c00000000000RR9100000c-hTV RLrcnXG-_Y@d@+KO5CO*nqX_^2 delta 371 zcmV-(0gV3h2J;563Icz-(VXq`FiH;!4G07fubs-Jt1(If2my)#&H@U_0swxg(Lv=H z)_(XIAvd+FF`}fwXNZwU0g}o*ye{Xth60vS0E`?Ms!_|Ml*GLC6e)!+c4^=;R<*W% zlbDZuR1;osfXq5+M(h_HPoxpE#A<-ZgLaqr%a;wCR=|Z%GgHbteOIb@^FEt znz58LtPyMAaiZ%tf}uze<4X#-sd3}SoMKm^v>>iSBWUI+SZ$v+?(9T$l*|+o2E=lJ z000000001gu~u8X2U#D8NALosLOj@KGUDVosQgTLU8_-1;<5+>zhzCVY4cwPLZpUu zhs>M_kP37`vo~vMHT!*%X|?18yo#v~RY-fbfLM?ujcqU+QTaakXj+ku+ptS+g`tcG zj=TI$;MU-1%T>nHVR#P63DYxi+Citit9500000000000RR9100000>-Fa$ R6rWk0t52MY3J+nE5CLYYqksSa diff --git a/app/src/androidTest/assets/backupTests/chat_item_gift_badge_14.binproto b/app/src/androidTest/assets/backupTests/chat_item_gift_badge_14.binproto index 02ca4063b4d17b41f064c344d8554b613312073f..af0dbfdd6a6deb307a339e5b9b49c2d0b4c22aed 100644 GIT binary patch delta 364 zcmaFE_J(Z(7gPPu={v6+F!bW!V&h=(V&Y)xVm!yhb&`ppV!`c?J6}9Z-u*kOMsK~Y zpm|BpUZKCA&EEt)@r%9Psvftprgr<0uk}A1=Blkfb!O@cu?x(`FMX3v$6E@xDCVYF zxLmRlGd?j*L1drEosQ>AHP~W#a(X20q-WP?ep<|8`9t>U?{>f0^)KIdy@>BtvrSa6 zW7@2!P*ir~Lx!--WF_5zT7}!e<&_+*9^2Usrq*0!tBF~(`sAr+LCmw;SLaAnHZVZI zzPB@Ky^In!-I`|gHoTmBN{11XPMX@~jqAirZ#`|;&+1zn{kenJEh+p;a*bxYr*rW9 zvKjo^ZuM`b-_lBoPnpbqE${rrBJQQkJm)Mrk6w86Gc82ICc4A#&6gVg3%`#ZT$aKDbq50@lu>c>Y>2b>sUnlC_@6a~ IO_Kze03idP1ONa4 delta 364 zcmV-y0h9jh2J8l~3Icz;(VXq`FiHpt1_%U70tf<%0nP#n$pQd=snJ2@7}kFH86h{d zt1+Ua!Don(M*)(`JiIRFxrPFkQUHt`7^+drqm;zF^%NZeSi_$FH-%GgHbteSrUhVpQMr<$>pG^`P8 z;BlhsH-e!^5#vh=xT$gD$DCqUqO>5cLnCPBDOhcvHty_1b(G8$5(dO_fB*mh00000 zf3a3uy$4wzh)3`Orb0Z}XENgCIH>$gcwMVeQR1=)1HWZWtZDOK2STKVb%)HH36KhO zL9;h%HT!*%X|-hJ1iXr=4pm5dwt!fWB#mt_8&UZ_`Dj{^j@z(HZiS(Y2adcBWl*nU zk~(1rCfxa8X_*)&yG{Xz^|>~oMXbW+1ONa40000000961000000PFSVArzlkovTlr KiV6>5lMn(EJD<4# diff --git a/app/src/androidTest/assets/backupTests/chat_item_group_change_chat_multiple_update_00.binproto b/app/src/androidTest/assets/backupTests/chat_item_group_change_chat_multiple_update_00.binproto index 31a0c3853a272f863aed8312cd0458b90ac6caf4..823064b8ef21bfb7df60ca39c389e5f85bfd901a 100644 GIT binary patch delta 18 acmZ3(xrTE?91Gj*DR&>-Fqxdf;sF3j2nW6Z delta 18 acmZ3(xrTE?91C0fyV<9&n@vt(@c;lw%LlFi diff --git a/app/src/androidTest/assets/backupTests/chat_item_group_change_chat_multiple_update_01.binproto b/app/src/androidTest/assets/backupTests/chat_item_group_change_chat_multiple_update_01.binproto index 089a33777aff1dac019484ec5827040871ee6795..884fca74e2e16bd350b9c69c2c0352b052ed38be 100644 GIT binary patch delta 18 acmcb{d5v>J91GjLi%mao8c$APDFOga;Rrea delta 18 acmcb{d5v>J91Gjw<~NuBm`qM#DFOgcvIuzq diff --git a/app/src/androidTest/assets/backupTests/chat_item_group_change_chat_multiple_update_02.binproto b/app/src/androidTest/assets/backupTests/chat_item_group_change_chat_multiple_update_02.binproto index 8d16efbb7449ed4a85530b70af097c59ae78872a..f30bbe4a6380b9b494b5cd5787409dab55824362 100644 GIT binary patch delta 18 acmZ3-xsG!~91Gj*DR&>-Fqxdf;spRnP6xyQ delta 18 acmZ3-xsG!~91C0fyV<9&n@vt(@d5xz5eKvY diff --git a/app/src/androidTest/assets/backupTests/chat_item_group_change_chat_multiple_update_03.binproto b/app/src/androidTest/assets/backupTests/chat_item_group_change_chat_multiple_update_03.binproto index 44c341153739cf8f56e0a2cdb1b9359a57e0bf7b..7fc4d4317ed742efcff58cad643ada8e52942279 100644 GIT binary patch delta 218 zcmbQmwVZ217)$+mMx`^19LxfY67w!L{k&-$#89<|QD`S4m$a57mjDA8I50Fo7>q)! zxtV#Hxm?y-mRKZJQxXd@lS+#fQY#cvGLuUZixo;s5_3z76jIYuOB8YwD>8FSi@9R8 zqT!l@5JtNfr52Q?WG3dNB&I4PrfJc#89=KQD_Y#myebgmjDA8I50Fo7>q(@ z$@zI@i8(o$#R|oVIjIV{nR%JH3I#=psl};zB?>8t1(`{u#R{nv3MrY%C5gofr6q~E zrA1suS_W85lgV{WtjNp-YA8xgE=escO$9OvN>efu^HLI1xiqxYuxJv>%P%e|D$P~M O%}+@!N-W7NEd~JUQ#ZN* diff --git a/app/src/androidTest/assets/backupTests/chat_item_group_change_chat_multiple_update_04.binproto b/app/src/androidTest/assets/backupTests/chat_item_group_change_chat_multiple_update_04.binproto index 14ec8a67f45e3b1fa184edd8f10f466386f72c79..76082d6498ae6eb3ff79509c2871c62460e989d7 100644 GIT binary patch delta 18 acmdnQxruW_91Gj*DR&>-Fqxdf;s*dp+6T}8 delta 18 acmdnQxruW_91C0fyV<9&n@vt(@dE%!od>`G diff --git a/app/src/androidTest/assets/backupTests/chat_item_group_change_chat_multiple_update_05.binproto b/app/src/androidTest/assets/backupTests/chat_item_group_change_chat_multiple_update_05.binproto index e9ae913ec190b831783eaff97ba181056a745677..79fcaa42637338d8e215f5c7c76a1dae550839ee 100644 GIT binary patch delta 18 acmdnQxruW_91GjLi%mao8c$AP@dE%!^#{%X delta 18 acmdnQxruW_91Gjw<~NuBm`qM#@dE%$#t01n diff --git a/app/src/androidTest/assets/backupTests/chat_item_group_change_chat_multiple_update_06.binproto b/app/src/androidTest/assets/backupTests/chat_item_group_change_chat_multiple_update_06.binproto index b07d7cf808c7a3107a57452dcbc26c5ff4c3c2a2..0da136c811dcfce4bc49af8a700aec788f049b62 100644 GIT binary patch delta 40 wcmX@ad4O|67>h`zQaT5-0Heh0DR&>-FbQI)iVzB$oW-KgtmdUMc@B#T01EO9djJ3c delta 43 zcmX@Wd5CjE7>h`@QYHtp0HZ|vyV<9&n*}jcMF~Yr&SKGL*6>oBJcmVvNrDjoFgXm8 diff --git a/app/src/androidTest/assets/backupTests/chat_item_group_change_chat_multiple_update_07.binproto b/app/src/androidTest/assets/backupTests/chat_item_group_change_chat_multiple_update_07.binproto index 0513ebc606852e6fe4078f65e19c1b55d220034e..bb1835d8b0f6a159485b4affbdb33cf855a154f6 100644 GIT binary patch delta 52 zcmaFD`HXWz7>iUNqf$2`2eSa9#Jr15KW`cbF;vwERdH!}sZB0mQDK!}i^Nqf#d$2eSa9#Np;Qm;aaqF;rCvRdA_!O+Lt?I(Z+9-FqxdfVmi5zMS_tD0DfKw>Hq)$ delta 44 scmdnQxruW_91C0fyV<9&n@vt(F_mQG5-Sqn5?}xW2Zja+gHeD904t*jQ~&?~ diff --git a/app/src/androidTest/assets/backupTests/chat_item_group_change_chat_update_00.binproto b/app/src/androidTest/assets/backupTests/chat_item_group_change_chat_update_00.binproto index 0d03c30ec0474dd0b5440290504254e76715f644..f7fb12311fdf689608bbeb279ef1bc5c78d4a4a3 100644 GIT binary patch delta 42 ucmZqRY~b7w$D%ZQ%H0PyOoAAyB!tAcM7V^w1Q@sk&oMAKFf=fL0V4nk&Iw5X delta 42 ucmZqRY~b7w$D-8!ZuaTxW-Fqxdfq6+{;R|jnX delta 18 acmbQpIgxWi91C0fyV<9&n@vt((FFiS8V6kf diff --git a/app/src/androidTest/assets/backupTests/chat_item_group_change_chat_update_07.binproto b/app/src/androidTest/assets/backupTests/chat_item_group_change_chat_update_07.binproto index 73e19bf549e2c98ec22221991df2b138d0edcad3..c266f408b7b64d4220ab54b6e1a44dd59c1108ca 100644 GIT binary patch delta 41 wcmeC>?B(1L$09KAV$;u?#z72KszS?B(1L$0BgJ`OW1&CP55UszS} delta 27 icmZqTY~tJy$HL$KZuaTxW-FbQI)vKO-DvevTX5@6sGJjcM`z|g<|28=?g pDTxJ{Nu|XKsTB$-naL%I#R{b*iMgdk3aRO-B?`HT6`8rE#Q-%18NdJl delta 80 zcmZ3^IgfKg7>kFyk}C(Z0HZ|vyV<9&n*}jcnF*P28EF}C2{3R8o?~EeU}#_f14bd4 f+{B8^+|pu&qSWM))WXtKAfuo(B{MNEB{3BMQU4Zb diff --git a/app/src/androidTest/assets/backupTests/chat_item_group_change_chat_update_13.binproto b/app/src/androidTest/assets/backupTests/chat_item_group_change_chat_update_13.binproto index b5d238b0f36eb9a2fa823ee5f81a261ad78a37a8..1297329fc4ace5ce6ab18e24a46c917bbba18268 100644 GIT binary patch delta 109 zcmbQjd6IKO7>h)aQUM3E0Hegbi%mao8V4~{B?`rJ#cD-QW@Hlfa4$+NC{4*s%u7j3 zRY*=PNiE7($jdJ-DJsoX$jwhlElMoOEGk6hk~Igj0Heg=<~NuBm;^CY=?H0YX=tfUW@Hi;7Rt*nE-5O_Rmjax MNi9k&$t*1f0NK0|jsO4v diff --git a/app/src/androidTest/assets/backupTests/chat_item_group_change_chat_update_14.binproto b/app/src/androidTest/assets/backupTests/chat_item_group_change_chat_update_14.binproto index bc9b40bf7ea23847b76bd4ac07357aff6d361854..3407dc0fd8a65c51f0b27a408bfde9c2aa725a98 100644 GIT binary patch delta 27 jcmZqTY~tJy$HG5*%H0PyOoAAyq=Y26#Ed2@u!sTxh#Cl9 delta 27 icmZqTY~tJy$HL$KZuaTxWWP1Q-~&xfvK77#bMBfKh-602bj0#sB~S delta 44 wcmZqTY~tJy$D-2yZuaTxWZX@kO~Ma delta 28 jcmZqTY~tJy$HI5G`OW1&CP55UQbH13Vw2@rL>ZX@lu-z4 diff --git a/app/src/androidTest/assets/backupTests/chat_item_group_change_chat_update_20.binproto b/app/src/androidTest/assets/backupTests/chat_item_group_change_chat_update_20.binproto index 3c2ad649c8ab6f46d5f38cd5ac87405d336e107a..d0ccb5db9a34a346b4f5561376cb4727412165cf 100644 GIT binary patch delta 27 jcmZqTY~tJy$HG5*%H0PyOoAAyq=Y26#GEE8u!sTxh-wIK delta 27 icmZqTY~tJy$HL$KZuaTxWO| delta 42 ucmZqRY~b7w$D(w&`OW1&CP55U5<+5JB2GeF0t^h?+zbp33=Irmzz6^g0SM~= diff --git a/app/src/androidTest/assets/backupTests/chat_item_group_change_chat_update_22.binproto b/app/src/androidTest/assets/backupTests/chat_item_group_change_chat_update_22.binproto index c4edfa4eb8e842480af83c03ddc65ccfebb18fd0..9dbb281ba3f058e57862e4134a50555f1a67a9dd 100644 GIT binary patch delta 36 scmbQjIf-*a7>k6pk|hVT0Heh0DR&>-FbQI)(h}0(Qu9)ooX4U90KRYv6aWAK delta 39 vcmbQlIfZjW7>k6hk~Igj0HZ|vyV<9&n*}jc=?H0YX?Uqk&SOzwl3)Y?+@cCA diff --git a/app/src/androidTest/assets/backupTests/chat_item_group_change_chat_update_23.binproto b/app/src/androidTest/assets/backupTests/chat_item_group_change_chat_update_23.binproto index 056bb57da39f91ec8ada1d0b2b8667c7dc7f6718..e027381a545f291f276ea0a19092b3b8d519ed6b 100644 GIT binary patch delta 39 vcmbQlIfZjW7>k6hk~Igj0Hegbi%mao8V4~{=?H0YX?Uqk&SOzwl3)Y?-LMKd delta 36 scmbQjIf-*a7>k6pk|hVT0Heg=<~NuBm;^CYX$fg?sd=eP&SOyl0K&csQ2+n{ diff --git a/app/src/androidTest/assets/backupTests/chat_item_group_change_chat_update_24.binproto b/app/src/androidTest/assets/backupTests/chat_item_group_change_chat_update_24.binproto index 23169fe556032f6f8a8e20f147d6ec6551d7cc05..2ea11a67ca7b391b2eb3f44873a6379a5c2e135f 100644 GIT binary patch delta 42 ucmZqRY~b7w$D%ZQ%H0PyOoAAyB!tAcM1q941Q@sk&oMAKFf=fL0V4nqZV8b9 delta 42 ucmZqRY~b7w$D-8!ZuaTxW-Fqxdfq6Yv)dIxX- delta 18 acmbQlIf-*a91C0fyV<9&n@vt((E|WQJqKU_ diff --git a/app/src/androidTest/assets/backupTests/chat_item_group_change_chat_update_27.binproto b/app/src/androidTest/assets/backupTests/chat_item_group_change_chat_update_27.binproto index 622c5b076ea81d19770876af81a45adbe931211d..dd84182548553d2f03eb52a90e7ab7988e5a487b 100644 GIT binary patch delta 18 acmbQlIf-*a91GjLi%mao8c$AP(E|WQl?QGB delta 18 acmbQlIf-*a91Gjw<~NuBm`qM#(E|WSW(TbR diff --git a/app/src/androidTest/assets/backupTests/chat_item_group_change_chat_update_28.binproto b/app/src/androidTest/assets/backupTests/chat_item_group_change_chat_update_28.binproto index 33dea2e9653e681cf96e8c638a248ec93e3b49cc..f0f1103af2dcba3574fc8fb9660e7fe068286fcf 100644 GIT binary patch delta 42 ucmZqRY~b7w$D%ZQ%H0PyOoAAyB!tAcM3RKK1Q@sk&oMAKFf=fL0V4nrt_h(4 delta 42 ucmZqRY~b7w$D-8!ZuaTxW@d=Rt diff --git a/app/src/androidTest/assets/backupTests/chat_item_group_change_chat_update_29.binproto b/app/src/androidTest/assets/backupTests/chat_item_group_change_chat_update_29.binproto index a509a05665c8ddde3c0ceb17a7ae6b254a4bba87..b5130c304708e16f4c482547fd6eaae2f5186ad5 100644 GIT binary patch delta 42 ucmZqRY~b7w$D%avV$;u?#z72K5<+5JB1uAA0t^h?+zbp33=Irmzz6^a$Oy~; delta 42 ucmZqRY~b7w$D(w&`OW1&CP55U5<+5JB1uAA0t^h?+zbp33=Irmzz6^ife8x$ diff --git a/app/src/androidTest/assets/backupTests/chat_item_group_change_chat_update_30.binproto b/app/src/androidTest/assets/backupTests/chat_item_group_change_chat_update_30.binproto index 2183a5e3d66e8a78a12c7fb1c3d7e611c91c7100..bf889a230ca26707f4925e0580c1d5add21d574c 100644 GIT binary patch delta 42 ucmZqRY~b7w$D%ZQ%H0PyOoAAyB!tAcM6!gq1Q@sk&oMAKFf=fL0V4nsP6??1 delta 42 ucmZqRY~b7w$D-8!ZuaTxW>u!t}+0RWnp2%rD} delta 29 kcmZqTY~tJy$HL$KZuaTxW-Fa$6rWk0t52MY3J+nE7%sNKzMP3OAOI);G9b{l z(pt<-T7p@JDRTUUJf>KoASdK0LE_=`T9&*_awj@dlg_2 AQ2+n{ diff --git a/app/src/androidTest/assets/backupTests/chat_item_payment_notification_01.binproto b/app/src/androidTest/assets/backupTests/chat_item_payment_notification_01.binproto index 88e4052921faaf07422316af3d8f0977c6e7a172..d645a2452f92231662cff98c90f680cbc2f92d89 100644 GIT binary patch delta 287 zcmV+)0pR}02GjmG&49hG&wOdH8M9eHWCsxHZwFeH#s&oI5s#lG%++WIT}Q1ZgypE zX>w&CX>Mt4X=8PBAaQkRb0B7Aa&2X9baibYVRB=2AZ~ANb$@MnAY*TCc42I6X>%ZR zX>Dn2X>oOBAZ=x7BDetxwE+kL5+Vv9nd>K)Z?dJG&on8Zk2QFinN2BCY4deON|l$L z?+oeE81Lk~(ZV$#@~MJ}zm=586DYp%`?CKvG9U^Ah-2%pKkbBu^cibzWo!v|7H`w~ l^&S}K2hV)8L|HDTO1s45jxj5UTiE$|tm#~GI zsinDzv6-cXxrwQyODWA&$j#45EiTDSRY*&%FDlAZD9S7@EmlZOEi6q{+QG=R zm63x{NQp~f!rIllx{CJg_T6duz(nhT>D_(xPg4JGcD-p5e2hl_uzxG XR>53A^BI6(GAFY$$2=wwlYs#MiQ#Ef diff --git a/app/src/androidTest/assets/backupTests/chat_item_payment_notification_02.binproto b/app/src/androidTest/assets/backupTests/chat_item_payment_notification_02.binproto index e0008a3fb35f6f6dc1ba4e0bee9fd5926fd2978b..7b16164acb79bfa23f08b47fcdb364784f4fb3e2 100644 GIT binary patch delta 252 zcmV4MbY*iOWNBk`b!~HWAa-GLX?1fTX=HJAWg@r%3bg?U0%Q^*5+J#YEA9TeNl5=* z;IoH#V%cot!E++5OZvv)2wD4Z+n*TlBE$j+0uTWhrOEA$*)vK83IqrQ8UTU;tpW-aF*Z0dF*PzV zIWjXjH!(OkF*7tWIT8~zGdMOhIWaReGB-3fG%-0iIW`(ZX>N99ZfSC5AZc!CZE0h5 zb0BebX>%ZEWpZt0Zgh2RAYpQ2bs%nUZgp*WAY*TCc42I6X@7Gdb7^g9Y-w?IWgu;3 zX(G4*3bg?U0umw;AX)om8kIFA-Ce1wc`x!mG0GrFKKGznmKD^kz4n+~lo+_dzMP3O zAgts1r2FRe?g}WW^0b$=HZmalaNC~}im(}NYvIPH?NW&%El3Exs@(bNq>zutGr~kV ZQwkyqAOHXW0F&neLkQ*r00000007Y_WTF57 diff --git a/app/src/androidTest/assets/backupTests/chat_item_payment_notification_03.binproto b/app/src/androidTest/assets/backupTests/chat_item_payment_notification_03.binproto index 310e55cf3d94135bb0a413a7488374567855246e..e6435ff62cd90a6133bc4046410f7558d8d9be31 100644 GIT binary patch delta 152 zcmZo?oxr+)slJa~v5Bd*?b5)%hw6Js)$u!Wha zrMZc*nWcrfiK(%rxrK#=keHd7i5XDH)Xdn($jr>l*u>P_(#%ZCpg2D{GqYHsuryO4 tH$Nw}xFj6Emla$OfD(SEiO?gODxJPEmp|nNGU8$Rbmoi001n-DNq0a diff --git a/app/src/androidTest/assets/backupTests/chat_item_payment_notification_04.binproto b/app/src/androidTest/assets/backupTests/chat_item_payment_notification_04.binproto index 64b4635901b3478fe6bca65fb1a2817318fdac26..191d2de7e162abfeca47b7274ddfc05ac41f52f7 100644 GIT binary patch delta 86 zcmcb_a-L-YlfR#m4+oO~qr~q6D;~@=@#5v;=3o)%Ie6jz5>q9HCPsZOVRJ(Z3qxZQ pBTEwtGgC`*6Js+=At6Ic3rjO|Gcyx2AlKB)*vLqUMTm)m5dbcF6$t3FM7U{{6-jElg;n*{yyQrk`;?~l#vUWlT1M+jM7?{AhZNih^kZ|(^N_Ul`>Ll zsRa~JnC%|@WIYa+qeq8L7rcV)dT0Xooeys2P3Nb&&Dtf5%Wkm`mOG1i Hlu}0j8%`~Q delta 149 zcmbQn+RM6tslJ<0se_S&Nq|ve#mTq5H;uhGxY#&Yw3s*;n-~kYge}ZWEzM1g%`7d< zO-zj~%`Ge}gv89uOw52nre?-QMrLMa#wMobmS$#B)*1P^sYUq;1*t`u$)!1&#R_F0 xZeeL+YEf!lN@=b_ZhlT`aY<&XLRxB3QKmvsW-(uBu|i^MVQH!oix3kB698hvDZl^# diff --git a/app/src/androidTest/assets/backupTests/chat_item_payment_notification_06.binproto b/app/src/androidTest/assets/backupTests/chat_item_payment_notification_06.binproto index 6c8f586fadba8f65f0da98ce4efbb1fc9e92ce96..43e8e7d5b4360a827b0e4992afc7022b1180caea 100644 GIT binary patch delta 234 zcmX@ewu)^5Q~e4irKL<9OahD&e-Es9Fw?|~my4T&Mc{GIfnzHSv>2Kg+nKn8%?&Lq z42?~UEKMxTOfAh#jLj^CgbXb$EX~Z#%uLLHTvIb+BO@t;;{4>y%wmPY(oBWi{G8O{ zlFU>fBd;X2SRo}dxui6=xJ02Wu_&{&SRpf|uryUEY$YStGDaaKA%zJ_$A0Cn+btTI zY@2yCcILMqg+H2S&3Sa=az^CN3)?P5NxXZq=i(t#1qKZUBZaP_eY<^kT0St*dSH5Y iU;UHRznfien#A9U+IYTb1G~k;$#0l^IkXuWzyJW-msczR delta 279 zcmZ3*c93lWQ~iD>r9Dg>OahD&D^I@dy=m;l%f-#XB5-5z>#gfdwHTTh=P_}K8k$)c z8JZdyS{fN!nj2bJ7#f=xSqcf87+aW`SQ;9e8kw7znHXAHSei+>WagEn=4BS8DrDwm z=4K|B7Aq8%W)>@?r55F;=9QG@DkK&qmn!7t=auGGDkRtE=anVqSk43y1psh>UBv(Z diff --git a/app/src/androidTest/assets/backupTests/chat_item_payment_notification_07.binproto b/app/src/androidTest/assets/backupTests/chat_item_payment_notification_07.binproto index 3951e2e40b544a35d2f4a546a1f70f132d3d8f56..326aad26c61c286119ef25231bc56895cd638760 100644 GIT binary patch delta 279 zcmdnbc7kmIQ~fa}rNc}dOahD&{|>BpFw?|~pNp4+MWE;4h5JiPjhHwXn-~`}afzFo zm>OG}TUb~anHXD`nOGVcn;My$mKgS(sTEn;4oHT1r_KZdmgFmxB^G6t7Auq_CTHd*mZTOd6qnW~mSvUz*$Sm4iMgdkN;??2 zwlZ=s3MmOG#ImHw-YSuA6yf_ad7t6o=>#Ll^bN2H!TU-*Y ag1MBq6c|8Y@;4@_$^6V39IT9BJ_7*Hs$rx6 delta 279 zcmX@Xwx4YQQ~h2hrCm%MOahD&t4_Y{y=m;l&&A8ZBCvk$simt8jhHwXn;2&?aS2

{@)Qj1G6Q-O@UlGI{_l+5Ik(%j+_g|ft=%+g|o`plHV(p04#j9gn8IT(eMgcMZY z7Z=oUNrf!$3eKAOT77!{rloVwn`kcRH?5dC(^oT4V*9~;b2^O`PAuwq{rvUYJM|hz z{;xQ`&CEz48U2&40!;`60{{R30002T!bySv delta 195 zcmV;!06hPI27?Bm0)K%5BK`pg0uTWhtI6$+*)vK83IqrQG5~@B=K%^8F*Z0dF*PzV zIWjXjH!(OkF*7tWIT8~zGdMOhIWaReGB-3fG%-0iIW{7=0SdJN2m%r!5+GUoWg3+= zCEZ=As(CN+KQYQ6NIv(VT9y^mt-bb`T$C8N!M>b{Ga#(v`Y)vW=JoChD5>(am$f!B xAp3CJpAw3&8EtFf#;5I4i6SjX2)(M@`Rb&QkH<5@M3bumO$g=#00000006NgNHPEb diff --git a/app/src/androidTest/assets/backupTests/chat_item_payment_notification_09.binproto b/app/src/androidTest/assets/backupTests/chat_item_payment_notification_09.binproto index 2302fa7ab5871d61a9f36feef9d29ac6fa46d8ea..489f83566ec80bc85cb7587bcf6ba16758c5fe26 100644 GIT binary patch delta 161 zcmbQlI+Jw)Q~h*Cr74UYOahD&4F^{|m}%n0%f-#XBJjB9z_AquRt!yyK*CT2oHW@g4FrskGrW)@}^#wLa)hL%z;nR#WYd6`A23YmGC zxtYnO#R`R`nZ*iesYSV|c_pQ}3W-I@r3!iZd8N6P3dvIWd1Z+?IY0%)K-D>!g{7$q Lxv7~-OhOC*q<%2< delta 154 zcmbQqI*D}wQ~d-+rCvr3CILo?H7DQp-Zb{&=i=pH5xBAV_11N!R!kg>O^kV5!WL$x zmgXkLW|kJ_CZ@)g<`xzfLSklSCT2h(Q!`^DBQrBIV-r(zOEWVm>x}%|)S`Tag4CkS z9-Zb{&<>KaG5m-O>)Y8?4Rt!yy6PMhd1a}2nMJ7znR%JH znaQQa3WcSa#R_SuMY*YYC8fCviABk!3VHc?rMZ;~$@$WGWr;aCKn2A>)j64krKt+J MshLVFLQEWt0PQm{-2eap diff --git a/app/src/androidTest/assets/backupTests/chat_item_payment_notification_11.binproto b/app/src/androidTest/assets/backupTests/chat_item_payment_notification_11.binproto index 3663d2a4f5843b462210c3df30b162037e8323d9..1183ac128a225b6d80306eaf1059969410b0eccf 100644 GIT binary patch delta 145 zcmeyz(#g7jslJ_2sfCe)Nq|wJ>EMb7GflkMxL7z?oEVxI^SH##O-zj~%`Ge}j7*Fz z%uFl|jZKZrP0WOZ%*>2UOwBFL%q+|-j7@|lgZ6 diff --git a/app/src/androidTest/assets/backupTests/chat_item_payment_notification_13.binproto b/app/src/androidTest/assets/backupTests/chat_item_payment_notification_13.binproto index 1924dc523b123715fe195c075fbb78a7e38d91b1..cad152580de1f824b836da8a98a0292f0be5c634 100644 GIT binary patch delta 282 zcmX@bcA0GfQ~gCIrE^RiOahD&EeBUTm}%n0&&A8ZBG7a2!u=(tUQ8T}O^oZ9xWvs( zOpPtgEi5dIOpGneOe_tJO^wV=%!Gu@%#2M;%`MH$EX*v7O$<#8Eu~yC^U6~5GK*3b zGV?NXGm}e;6$(o;ixtvRi*i%*N=kDT5{r^c74q`)N^|Qg6_WGw$`W&OfC`F%s&g_6 zOH&ncQ!|xzFmi2Wkj|Ns+x(BHt*&_piVvU46yX2cNgha_wDkGyWc9$W7xz z67Qevxp>G_;nT{d&izxToDkO7_wo0p|E5L?T+AKGuQ%AgZE5==nVpxK!&xqtfBDx} eIf>`&=WDjOBr;hAPnKm?nJmq$&cVva00sbtgJetq delta 275 zcmV+u0qp+M2FeDY0)NN?BE*)vKH3JnMZ5U-uerK>SY0tf+u0i^;8 z6F4?CIX5&jHaR#qG&M6hH#j&r5*9W#G&VCfIW;yjGBP$cHZwFeH#s&o8arrjZDn$A zAaG@JX=8P4X>%ZUWpZyIadly3a%FC0b!{MRZ)|0AbZKQEW`AXJa%muPX>)aRAYo;3 zb!8&B0SdJN2mulz5+Eh-b8vhL8dRr>Q)-#(Czo%srJc_-DWH!vc$t|^DNz`=!M>b{ zGa$&KjO*v??c9GT#Q&(rwl*>#RM|7a4H^W_*(90uN2Qc5mlF%kc^vKf{0=FVZNcEp ZI#UWF3LpRg0Fws;Lo1&oWMZW7jmPgK x!=`&r8`)dEG#79BICaA}>nkTDJlonh#jl1+{^)@N?ZyI43nQTxpF*XW&i^KagAj7 diff --git a/app/src/androidTest/assets/backupTests/chat_item_remote_delete_00.binproto b/app/src/androidTest/assets/backupTests/chat_item_remote_delete_00.binproto index ccf0933371c8d16d1144d229b4b965f737dcc6ab..b017b057f9e2913074d14782373dfcd82a427444 100644 GIT binary patch delta 41 zcmV+^0M`Gc1fm3>0wN(I9|!^v1Q_d=xzxZhLJ$b9(VXq`Fc6`@nT(P#AOUg!BI^$v delta 43 zcmV+`0M!4Y1f&F@0wg0MAqWBx1Q@Q-obB^4LJ|nw%>Tp1F%Y5rgwdNc7y%#wasW;) B5EcLc diff --git a/app/src/androidTest/assets/backupTests/chat_item_remote_delete_01.binproto b/app/src/androidTest/assets/backupTests/chat_item_remote_delete_01.binproto index 442453e55f12395723f0ed93bf0a3602751aae40..767fa2c1e6b2e149d10648878fdb9fdf6d5da1ca 100644 GIT binary patch delta 41 zcmV+^0M`GY1fm3>0wN(I9|!^v1Q_g>xzxZhLJ$bA(VXq`Fc6}^nT(P#7y)tsB3us> delta 39 xcmV+?0NDSc1fT?<0w5nE9S8yt1Q@T;obB^4LJkPt%>Tp1F%Y8sgwdNcasUlU56b`m diff --git a/app/src/androidTest/assets/backupTests/chat_item_remote_delete_02.binproto b/app/src/androidTest/assets/backupTests/chat_item_remote_delete_02.binproto index ccf5d935eef8aa756e5ba712688fe233d31efebd..f425845834ee1c4af0f5edc542247b5cd12ebb27 100644 GIT binary patch delta 24 gcmbQiGJ|CU2a~|t={v6+F!W;MV&PzsVklw&0BB$a`v3p{ delta 24 gcmbQiGJ|CU2a~{ti*w$7Ht=HOV&PzsVklw&0BQaQCIA2c diff --git a/app/src/androidTest/assets/backupTests/chat_item_remote_delete_03.binproto b/app/src/androidTest/assets/backupTests/chat_item_remote_delete_03.binproto index ed8d2743ffc8744e7b2ea68941f9692de54264aa..c373526b2a293bc00049a41eae65f8924ce4a95b 100644 GIT binary patch delta 33 pcmZ3;vXEs12b1Kx={v6+F!bW*;^klwc-(W~*a`zBCJx3T1^~^=3mE_a delta 33 pcmZ3;vXEs12b1K+i*w$7Ht^!-;^klwxUu;4)^(;zOdO0w3;@#23v~bh diff --git a/app/src/androidTest/assets/backupTests/chat_item_remote_delete_04.binproto b/app/src/androidTest/assets/backupTests/chat_item_remote_delete_04.binproto index d1ab375595fd0ca95e447457939a47f22570b5a1..d4e0679161fb0a85f038ce37e89b2190d516dbd2 100644 GIT binary patch delta 31 ncmbQwGM{Aw2b1{w={v6+F!bW(;^trx=s9@d{t{Cqh9U+4w?GRG delta 31 ncmbQwGM{Aw2b1`wi*w$7Ht^!*;^trxSU>mF($$7a3`Gn8xOEEp diff --git a/app/src/androidTest/assets/backupTests/chat_item_remote_delete_05.binproto b/app/src/androidTest/assets/backupTests/chat_item_remote_delete_05.binproto index 917a992c0044e2e0e2fe3ba8b196ed21e7971f1a..cbd66f679227ce53e952e1c61d398e8202ad9a1a 100644 GIT binary patch delta 26 icmbQmGK*yc2b0i;={v6+F!bW!V&h=ZV&Y&dVgLYk=LaJI delta 26 icmbQmGK*yc2b0j|i*w$7Ht^!$V&h=ZV&Y&dVgLYm+Xqen diff --git a/app/src/androidTest/assets/backupTests/chat_item_remote_delete_06.binproto b/app/src/androidTest/assets/backupTests/chat_item_remote_delete_06.binproto index d91cd80e1bc3fb28bfdde202bd5f9effd7dc59e3..c93c838c573858aaf99e242e392c5c85a33d3f86 100644 GIT binary patch delta 31 ncmbQwGM{Aw2b1{6={v6+F!bW(;^trxc-(W~*a`zJh9U+4x91BF delta 31 ncmbQwGM{Aw2b1`gi*w$7Ht^!*;^trxxUu;4)^(;@3`Gn8yfF)F diff --git a/app/src/androidTest/assets/backupTests/chat_item_remote_delete_07.binproto b/app/src/androidTest/assets/backupTests/chat_item_remote_delete_07.binproto index 51faac47471121d276b803cc420019639b6baaee..4ab531fbefaef2ff49d5c95349280cd004bfa4fe 100644 GIT binary patch delta 33 pcmZ3;vXEs12b1Kd={v6+F!bW*;^klw=s9@d{t{CoCJx3T1^~`R3pD@$ delta 33 pcmZ3;vXEs12b1L1i*w$7Ht^!-;^klwSU>mF($$7WOdO0w3;@qn3nBmj diff --git a/app/src/androidTest/assets/backupTests/chat_item_remote_delete_08.binproto b/app/src/androidTest/assets/backupTests/chat_item_remote_delete_08.binproto index 079b440674ec84c0615a3abb8f6946c9d5350d4e..399a36e086730dde9c76d4bb000880a7e375ea43 100644 GIT binary patch delta 24 gcmbQiGJ|CU2a~|(={v6+F!W;MV&PyhVklw&0BIlx82|tP delta 24 gcmbQiGJ|CU2a~|Ii*w$7Ht=HOV&PyhVklw&0BXJmL;wH) diff --git a/app/src/androidTest/assets/backupTests/chat_item_remote_delete_09.binproto b/app/src/androidTest/assets/backupTests/chat_item_remote_delete_09.binproto index 1b84609d4f879e8c436487bea72f5ebeef723343..312717584c0df51f6a488ad2309b6592fb483c3f 100644 GIT binary patch delta 38 ucmZ3;GM{Aulf0ag3=3o(c+;iaA3Ii*KA_f4}Dhs0k delta 40 wcmbQwvXEr~lcIu>90!vCqr~=$bKZV7@Z#s<90!vCqr}(gJFgrt^y25@qQC4#pw|0PKwm!2kdN delta 38 ucmZ3;GM{Aulf0ag3R{#J2 diff --git a/app/src/androidTest/assets/backupTests/chat_item_remote_delete_12.binproto b/app/src/androidTest/assets/backupTests/chat_item_remote_delete_12.binproto index d498235d7b2b2c25c5f73eb1e54ef229b6fa2709..d26b7628d2b311b61171568d12f5e6183b16ea4c 100644 GIT binary patch delta 31 ncmbQwGM{Aw2b1{s={v6+F!bW(;^trxc-(W~*a`zLh9U+4xbX`$ delta 31 ncmbQwGM{Aw2b1`&i*w$7Ht^!*;^trxxUu;4)^(;{3`Gn8y*mq$ diff --git a/app/src/androidTest/assets/backupTests/chat_item_remote_delete_13.binproto b/app/src/androidTest/assets/backupTests/chat_item_remote_delete_13.binproto index d4621a24846ed231cb569ce7b2d6c4c82f87126c..cd2791ede914ab939616419517a3963a53e72a05 100644 GIT binary patch delta 33 pcmZ3;vXEs12b1KF={v6+F!bW*;^klw=s9@d{t{C!CJx3T1^~}&3sV39 delta 33 pcmZ3;vXEs12b1LPi*w$7Ht^!-;^klwSU>mF($$7uOdO0w3;@u33qSw> diff --git a/app/src/androidTest/assets/backupTests/chat_item_remote_delete_14.binproto b/app/src/androidTest/assets/backupTests/chat_item_remote_delete_14.binproto index c59c450568fc232b3050d9f5e62d9b8898b59e0e..03e4d7cefcd4bf14de8fbb6906dbe16ddb706b1c 100644 GIT binary patch delta 26 icmbQmGK*yc2b0jx={v6+F!bW!V&h=(V&Y&bVgLYmOb1N> delta 26 icmbQmGK*yc2b0jAi*w$7Ht^!$V&h=(V&Y&bVgLYoKnHjL diff --git a/app/src/androidTest/assets/backupTests/chat_item_standard_message_formatted_text_00.binproto b/app/src/androidTest/assets/backupTests/chat_item_standard_message_formatted_text_00.binproto index ffe052779e134d66a626e92c6f22a4ad8ac97cea..a1157973d2bcef213b0693799a06de5bad2b55ba 100644 GIT binary patch delta 61 zcmdnPzK4B-3$xg|rq=oAjhuuy-Y#D=^^d8*w)e}wO){Ds#VjK>XVH#beP$R^J%bO){Ds#cUupchQbreP$R^3z&5P DZD<_> delta 61 zcmX@ZeujO63$xgXZ*MoxGj-zQXuUIYORu@W##OH;tuvS$#cUw<_WkWsXU#FB7BK4o E0EGe_A^-pY diff --git a/app/src/androidTest/assets/backupTests/chat_item_standard_message_formatted_text_02.binproto b/app/src/androidTest/assets/backupTests/chat_item_standard_message_formatted_text_02.binproto index f063a9db34087f179fd951119c63ad79da8ff1f5..f81484c3144129a4c7b2a5917a67a3058f877620 100644 GIT binary patch delta 29 lcmX@devW;E3p3k>rq=oAjV60ByRgk$v}0GF+2kqARsgjm3Z~~)MR%C>0N$S-i~s-t diff --git a/app/src/androidTest/assets/backupTests/chat_item_standard_message_formatted_text_05.binproto b/app/src/androidTest/assets/backupTests/chat_item_standard_message_formatted_text_05.binproto index 868ceb312a84c1dd4b115ecd442ee345e5fd2868..2485cc03e3970bb6a3022c10ef6d3aae916033a9 100644 GIT binary patch delta 29 lcmeys{(*gi3p3m1rq=oAjV60BC$TMDv}0GF+2l>kb^yM&42=K) delta 29 ncmV+&0OJ4f2k-~5L<0uQ_U*HtHIqsMVg~W=+se&1ld=Oo*uM^V diff --git a/app/src/androidTest/assets/backupTests/chat_item_standard_message_formatted_text_06.binproto b/app/src/androidTest/assets/backupTests/chat_item_standard_message_formatted_text_06.binproto index fa25914abd242c92c5e48c2a6f56746b0a6c1712..71fa31e4eed25216cfba92b722051c12adca1d29 100644 GIT binary patch delta 102 zcmX@ZeujO63v<+#rq=oAjl86|xH(t^9`_tLw!%P*0mxw$c(ecU)!k-V3{iYSJX~A` ihDOFFre@|AmZ3_)9LxfY5{nk?*wtr-Tj%6?%z6N>h#?{X delta 102 zcmX@ZeujO63v<-jZ*MoxGxd_<;^trxxUu;4)^(;@3_uR6z}++d4<9wuVu<1s;^E>l jFf=kYF*P%{unbiS=3o|Jl=$@i_NlYxxOGmR$E*hcIesIF diff --git a/app/src/androidTest/assets/backupTests/chat_item_standard_message_formatted_text_07.binproto b/app/src/androidTest/assets/backupTests/chat_item_standard_message_formatted_text_07.binproto index f336814dc7eef1bceeda48053ca8d99becc74b93..0d3593c7cfc570c231fac65a186816f941d78265 100644 GIT binary patch delta 105 zcmaFE{(^mj4YN+LQXmJj0Heg#rq=oAjl5*IcsW=EdJbN=zr@stiGz`gn}bzg_q2bl e=go{5CTB5g=!7eUf;B8&v}0GF837Fkm~{Z9!60`4 delta 109 zcmaFC{)T;n4YOXTQZNUz0HegYZ*MoxGxd_=;^klwSU>mF($$7WOdO0rE~~)8KP?w$ dn}E2JGnh5>B9+3yT0XzOed??^K`ncjbpU1+A=&@{ diff --git a/app/src/androidTest/assets/backupTests/chat_item_standard_message_formatted_text_08.binproto b/app/src/androidTest/assets/backupTests/chat_item_standard_message_formatted_text_08.binproto index 6461a067b50faba8a22df4d675ed7945e5ca72ef..17c1f76e00901e0b72dc07f660090b34aa191dad 100644 GIT binary patch delta 77 zcmdnTeu#a84YQoJk|hVT0HegVrq=oAjlB4{SU6aW7`WItSdExC7$-+C%gK2vxr3D~ PS+rwUpBaXdNz6I`oM;c9 delta 73 zcmX@azK?x_4YQ1;k~s&n0HehDZ*MoxGxg%(V&PyhVgQn?MhugqnB`>Lm0ZCJzP!JE M>a01Mf@#b;0JCioW&i*H diff --git a/app/src/androidTest/assets/backupTests/chat_item_standard_message_formatted_text_09.binproto b/app/src/androidTest/assets/backupTests/chat_item_standard_message_formatted_text_09.binproto index 7cb90f5ec53087085d9f159bd5983c4ababc8246..4e14923533511e93b2788a324f2fd0eda99b3c21 100644 GIT binary patch delta 97 zcmaFE{(^mj4YNkDQXmJj0HehArq=oAjl5*IxH(t^9`_tLw!*-Qfs2=eRp8D3$5(fo bO-^Ih(Fj)x1uI^3GE>7 delta 101 zcmaFC{)T;n4YO9LQZNUz0Hef(Z*MoxGxd_=;^klwxUu;4)^(;m=QRL;RHz$me!sdfH&BQF^)UJe$4o`Vm!RRLa3Dz$kI?+uP0aOueMIxH(t^*3Uh)bhV)s1CYZiu<%dI#n~p4 Z)0hJ^LY0ESiodous^#Bz$Arb%p diff --git a/app/src/androidTest/assets/backupTests/chat_item_standard_message_formatted_text_11.binproto b/app/src/androidTest/assets/backupTests/chat_item_standard_message_formatted_text_11.binproto index 824c126f7c75da5e99780feca91400952941eac6..4c80639c7aad7fae485db49882436f30d75f7071 100644 GIT binary patch delta 29 lcmeyt{)2sk3p3l!rq=oAjV60B=dmqcv}0GF+2no9Rsg}_47~sV delta 29 ncmV+&0OJ4n2lxlDL<0uW_U*HtHIqsMZU*=7+se&1lfDBw+vyId diff --git a/app/src/androidTest/assets/backupTests/chat_item_standard_message_formatted_text_12.binproto b/app/src/androidTest/assets/backupTests/chat_item_standard_message_formatted_text_12.binproto index 3c327aa3e8c93f8b20d6d3fcb0a0e9e93b658773..f85145cecc1e380cd75d987ad6d087fba482d94b 100644 GIT binary patch delta 102 zcmX@ZeujO63v<-2rq=oAjl86|xH(t^9`_tLw!*-R0mxw$c(ecU)!k-Z3{iYSJX~A` ihDOFFre@|AmZ3_)9LxfY5-S$%*wtr-Tj%6?%z6OC)FF-l delta 102 zcmX@ZeujO63v<-vZ*MoxGxd_<;^trxxUu;4)^(;{3_uR6z}++d4<9x3Vu<1s;^E>l jFf=kYF*P%{unbiS=3o|Jl=$)f_NlYxxOGmR$E*hcPs$_p diff --git a/app/src/androidTest/assets/backupTests/chat_item_standard_message_formatted_text_13.binproto b/app/src/androidTest/assets/backupTests/chat_item_standard_message_formatted_text_13.binproto index 53fb0dd6c81e8db800c933dd88ab89a75db44f49..0e5a9645931075bd6aa739a950f6b75053f2d4ad 100644 GIT binary patch delta 85 zcmcb`ev5sB3$xPhrq=oAjlATzcsW=EdJbN=zr@swiGvZyWfj;x?O*G8v&m`9N=hpi O?by|4hF94tW&;2i_8t=e delta 85 zcmcb`ev5sB3$xOdZ*MoxGxd_=;^klwSU>mF($$7uOdO0rE~~)8KP?w$n@mn)R#N); P{`RS}=6IE@Vm1H(Xha`U diff --git a/app/src/androidTest/assets/backupTests/chat_item_standard_message_formatted_text_14.binproto b/app/src/androidTest/assets/backupTests/chat_item_standard_message_formatted_text_14.binproto index 7bf920e8c8d3e1fef57cd9ab9f0c4af93dc47b52..f9b501a9cac22a8dbad01ac2802dc10d36cab941 100644 GIT binary patch delta 29 lcmX@Xeu9023p3lErq=oAjV60BTd}QLv}0GF+2k%}I{>t{3;zHB delta 29 ncmV+&0OJ412gnDoL<0uZ_U*HtHIqsMItKdh+se&1lZpdA&b|%m diff --git a/app/src/androidTest/assets/backupTests/chat_item_standard_message_long_text_00.binproto b/app/src/androidTest/assets/backupTests/chat_item_standard_message_long_text_00.binproto index 3773f14a709218bcc8287f0e4bed72efb340a5df..0872e219b0118e0652706abf1a57e298acddfe4a 100644 GIT binary patch delta 160 zcmV;R0AK&d1(*e(0)LhPB9j3K0uTfk>zBFIz%fD)2(Hnb?ej1Yp}?7pk})6wT67W= z3KC*+b#!GQc4cyDbaiteb#8TSDqJEHbY*ySFL*6;X=iR>Y%OqXVQFq^LkbXBp&%#Z zDM8}l^jem@OmZg}%%%lA`^6Fcyup#EpusSZeeUK zaBN{|Zfax-5HxCE`Ft^glD%$o|Bxca`VtUXV?AlrU77ayaY*=snw;X;80fa8>jEMT zMMF_nb#-+`Mni2waVP*VjFzLd@-adnH90mjGh{Y7WHmKpIXPxFW;i!7W;i%AIbk_t JWin(q8UQ^MPn!S$ diff --git a/app/src/androidTest/assets/backupTests/chat_item_standard_message_long_text_01.binproto b/app/src/androidTest/assets/backupTests/chat_item_standard_message_long_text_01.binproto index 23c6a8f9644f2b0158ddf97ce615ceedc1a7d398..62a2eb3eb59d75c04f39a039f3ed3ca8b3f15861 100644 GIT binary patch delta 188 zcmV;t07L)$1hfU90)MgrBCi1m0uTfk?3cOJz%fD)2(Qtc?ej1YqQIGqk}((oT8{w| z7YY?~VQ^_>ZXk4WX>)XGadl-Nb75>{Dq$iMbY*ySFL*6;X=iR>Y%OqXVQFqU3S&b} zWo2q;Zc}DzJPHu|aNC~}im(}NYvIPH?NW&tx3bIj1ULXvAT{=Ts*q;dQ_A)XPRRhW q-sOP@g-R)-vhkI$_B+(b7)crcG7$;{@Sl=^5CItdpQFB$Gavyx+f66{ delta 114 zcmV-&0FD2&1^fh{0!Moyc?bd!1Q@T;obB^4LJkPt%>Tp1F%Y8sgwdNcT3iw%3L$B3 zAY^4`X>MtBX>V?2b0BtaY;|;SVRRsKVP|P{bZK)cB9lM@79R&>Syy>kP;P1f8UQj8 U3Iy<R6Pa=_4wjf;hYMT#NnETfPumvu^JaY1QGVo7Fx zUZz4}X<}+&X{thEodUpNv$Z+ zuh1>dOwUWq(JjbH%*?amNO#N6_VMt^&2r`v$YfVFx%xeQ*SaH@yYEylPcoNyzU5K_ zs}f&iwp)a+zf)nZb4p}*r3SOX!4ErTeKm{{*r3)EyCVI?mXK2C$ScNGHc|{mf?O;g e=1*z>`r+^V#rq~3D=W?o{hLP>r} zqC!z>L1{{6VqQvOszOpxX-TR=S!z*cNolb{X zPGV-B6>DO+r;|rk8ka!&-_ugZT34*QeQC}Xy&1l#LITq(y}mAA5}C@SI^q4r9+i2w zCDycGKEbTS>*^dBURqk}>gJs5T&Tfp&@*lE)=!2OOil`x<|c`0ritc>CZ?8VrUr>d zrj`b&X(@&l$wnrYsVPZP3`T-nEFb1iY5@9a+tl+njvFa3LWCyv3b06QhX^qN0J1Y& A>Hq)$ diff --git a/app/src/androidTest/assets/backupTests/chat_item_standard_message_long_text_03.binproto b/app/src/androidTest/assets/backupTests/chat_item_standard_message_long_text_03.binproto index 2b210a81fb1ec4d5aad0c11ad5b67e9cbb697591..ca01243250d8b08c2f35273686f63dbe87d23afb 100644 GIT binary patch delta 152 zcmV;J0B8T*1ds)w0)LJHB8veC0uTWh?w7gLz%fb>3JnMZ5aW!%#;7nN0tf+GZ4wj; z5@K?7bY&oRWpZhBb#owfZgp)cRU#8~Wq5Qicr9~jXKrC^EpTjMX>Mvf3J^N?o+*s{ z@<|$&=Lf(7S;rX6>(AT-I0I53O3Y9|)=sE4@;Xf73_>8QIT372j=k^Hn?$t8(VR!i GfEobaWjdn( delta 100 zcmbQhdY5GZQ*4Y<6bF+4qr}FGbKZV7@Z#s<E{CHfV*#hK}Oi8;CjIf; zb7634Wo{sJa%ppPX>oOBAah}CWhz`E6Le*GbT4=+yo*HS!+gEO;18`Z9`;PS9vG^FfGCGxSI7bS`Z8(y4jRX i#F3D#tGbGEzPlO#G7$;{@Sl=^5CItdpQFB$Gav!*Zbah% delta 225 zcmV<703QFW1=$6l0)N*5BGds00uTWhveBIF^Ds&c3JVAX5U-uerK>R_09v;J5+e#B zX>K57WoBt^X>@6CZe?>Ic5iHTbZ}vGAah}7X>@dHb1Hoz6Le*GbT4=4^=kRrzV5)fHqJ!#clnfCZ`_*#RSoZ{FR=(eTn0wN7X zLs3_Cb#+BXLv2HGC;%{wmZP=uF+w0UIW{vhWHvcuH8o^8Ic7FyI5#n7I5;yoVL4-E bGGsU!05TB@1n{4dfDi!~ww2G=$1)%RPxMqP diff --git a/app/src/androidTest/assets/backupTests/chat_item_standard_message_long_text_05.binproto b/app/src/androidTest/assets/backupTests/chat_item_standard_message_long_text_05.binproto index d5dcdc93cf66cdcbfef2e796d89d311b114f1f2a..64de0f9de760127a8b5dcd50806642e6a33b6833 100644 GIT binary patch delta 237 zcmbQj`jmA6Q~hH`r3Z{0OahD&AExiTa=_4wgNu!WMT?1pG3o@PkS&*WN@j6EX-Q&9 zW`16#LSboQYGG-rLSmjmK~ZW+W@)ZMX;LOgq$m|Akdc~~Qkqu+RF+u`6x2#o5-v%t zDABLbEzV5OOU%(N$Vtr1v*Jp2_DxOA%E${&OUtt168K$kd%jTD2Fcv)hsTz`4eFHG zzUlNg77KTiXCZyd8KJ|^q?oqDSU$|3 c)ByCr-}#I8O*U3wga}RS6=0G02N7Zd0Ebds%K!iX delta 138 zcmaFLI)!xslg}hZrG7>ZCILo?%@^mq{cPaH!NtbGqQ%6)7*!#p!=+VPl9`v7t5A|( zlBiIWT2PvjnV6T7n5vLeR9cd%P?lPhSyEc8P?}eotEDtKj!DdjJtZ={GBO}9i$RLP iNRW%=!~97NK-0HPJ%8i4kpd$`XkxDbi^O(_5EB5pDJ^#Z diff --git a/app/src/androidTest/assets/backupTests/chat_item_standard_message_long_text_06.binproto b/app/src/androidTest/assets/backupTests/chat_item_standard_message_long_text_06.binproto index 51878197e5c1ed2209381d88461785fd1717a4a6..c1905bc0d00d172f2c592b37a3361563587ddc27 100644 GIT binary patch delta 167 zcmV;Y09gOb1)l|=0)L$WBANjR0uTWh@t3*Oz%fb<3JVAX5aW!%#;7nV09t+$6bcez za&>fNAa-SPX>@gSAa!naZ7OCW6Le*GbT4=N37a&U5GbYXI7b1H@bA`^6Fcyup#EpusSZeeUKaBN{| zZaM{FS4l!hYGw)$XZ_0>#)YV^+tQr0E|^Va5)hY4^{1p+WlahtknhoqB%a$CtcTOc z10oGYLs3_Cb#+BXLv2HGC<8EzmZP=uF*pK3AUQWQVP-X9H(@k2IW{#gVKOy2FlA3JnMZ5RAdl-=sA%0tf+Gg8>p3 z3KerMvf3J^N? zo+*s{@<|$&=Lf(7S;rX6>(AT-I0I53O3Y9|)=sE4@;Xf73@Ab%t2t~-j=k^Hn?$t8 d(VR!ifEoZY5efwGpOSzO0T}(CqrQ_fAOV}0Lu3E| delta 106 zcmV-w0G0oz1@r`<0!VWraR>qs0T{K>obB^4N)HMR2m}zXoyw)FF){)O0a{ZMBMKpD zZXjf3W@&C|bZKvHWpf~QZ)|mRaA9;Hb75y`baZKRDjAbM0u~kk8UQj83Iy<dOwUWq(JjbH%*@Mj<`RflsG$Bt)A7;6FY!^+_V^U3OPqOq{tk;0Uu3phgs;C- zVXkvZWO$_pgTcWMJ7#?~j1u5c+I4e^?~#cU)~?>wRkUxn6oZi<7t4qFlNx|7|2u#2 UzRAW4j1ZxTy#g!}{~$t407SJ|d;kCd delta 246 zcmcb|`i^x0Q~eu8rI(BxOahD&+b+&|``N&Yjf;hY#fTy5GNX_VmsV*>W?o{hLP>r} zqC!z>L1{{6VqQvOszOpxX-TR=S!z*cNolb{X8Kf~lpMv2lu-Ws0e3ilt?mS(=5pVVZ@7v1OuV oa;i~^g%pF4AQ#Jr`I8zzKAC#{#&IJBMu^bFUI7+~?GPa*04)+*xBvhE diff --git a/app/src/androidTest/assets/backupTests/chat_item_standard_message_long_text_09.binproto b/app/src/androidTest/assets/backupTests/chat_item_standard_message_long_text_09.binproto index 5cb464b13fe20204d1b110a50ea1986f87dc5029..053158a0c2401070c12d8184900abc66b9e136f2 100644 GIT binary patch delta 162 zcmV;T0A2s)1eyh)0)LnRB9#FM0uTWh^q0BRz%fb<3JVAX5aW!%#;7nl09ttx6bcez za&>fNAa-SPX>@gSAa!naZ7N|R6Le*GbT4=A!X>E{CHfV*#hK}Oi8;CjIf3JnMZ5RAdl-=sA<0tf+GlmQYK z3KerK|QXGU*p zOh`;^YC{ST2PHJs_h-7U#M6u1d#7SI80WOofCVBBS!+gEO*v0Oacx6nSyy=|12Dnx uxSI7bS`e@%j9sW_=(JRILs`@_dOR8cG7$;{@Sl=^5CItdpQFB$Gav!414mx~ delta 218 zcmV<0044vp1>*&v0!rZlBHjTA0uTWhxY3;L^Ds&c3JVAX5U-uerK>SI09wHT5+e#B zX>K57WoBt^X>@6CZe?>Ic5iHTbZ}vGAah}7X>@dHb1H@blRp9$e+6MzNkT|!W(p8z z{mUB0g{ZFE(wwv|m`!C85SL2zr=(eB3MG*5(TpUX+Ze2e)5rrN4MjsyS9NuDMMgty zLvbhrFpQR?wem4I0zx1;H#A{pHDNblG&MOkH85c^H90V4W@IrqV=^>3Wn^L+05TB@ U1n{4dfDi!~ww2G=1jjNU0XXJPr~m)} diff --git a/app/src/androidTest/assets/backupTests/chat_item_standard_message_long_text_11.binproto b/app/src/androidTest/assets/backupTests/chat_item_standard_message_long_text_11.binproto index 6e7df96b5b70abb38a947173fdb6c310e01a6ab3..2bf0b96178c1433d45886d33cdad935a0881e95a 100644 GIT binary patch delta 223 zcmeBVz0SITss1XX(j`U?CILo?Z_{^PIbi6;#>K+H;=~ZOhf&Cu%Q_{qxS+Hou_QA; zFH@ngG%>ZXG*uxnPobbFwIs7NSD`d16C_fU3KYml%}XiGD*-CYECvc{g(?Y`q*j#Z zSLhaJrspN*=oaK8X69wta0ys_pQqXL=aZ+@w20^I2bdy{OPqOq{tk-;bC819nE;1t zek;sAS@}HTaZ*@qnd9BJ_x+XGE?Z7qoa27FL5jghkc;KR{7DT!C;y$lc;94W1xAR_ N#9jdwiGL6wCIIAlR%ZYJ delta 145 zcmcc4+R3_rslJ_2sfCe)Nq|ve=fyd1KO1fNAa-SPX>@gSAa!naZ7N(M6Le*GbT4=+yo*HS!+gEO;18`Z9`;PS9vG^Fv0M+nilmjS`Z8(y4jRX#F3D# LtGbGEzPlO#F7`ZT delta 202 zcmV;*05$)W1;PcO0)M~(BE10!0uTWhy3w5N^Ds&c3JVAX5ZI&ZwXQWv09v2{5+4d3 zb7gLGWpZhBAY^4@Z*pZIX>N37a&U5GbYXI7b1Hoz6Le*GbT4=4^=kRrzV5)fHqJ!#clnfCZ`_=B39;zQUN=(eTn0wN7XLs3_C zb#+BXLv2HGC;%{wmZP=uF+w0UIW{vhWHvcuH8o^8Ic7FyI5#n7I5;yoVL4-EGGsU! E062t8l>h($ diff --git a/app/src/androidTest/assets/backupTests/chat_item_standard_message_long_text_13.binproto b/app/src/androidTest/assets/backupTests/chat_item_standard_message_long_text_13.binproto index 2aa9b391dfc4f5aebbc43053613695798c11ad93..0375d18fbcc9ed04bc0dc4149c1cfb08ed1154bd 100644 GIT binary patch delta 187 zcmV;s07U=&1hWO80)MdqBCY`l0uTWh_?NlVz%fb>3JnMZ5RAdl-=sB40tf+Gj{y=F z3KerK|SV?#}4 zWol?{Q)X&B3K08n+n*AOuo-P@;l`)!Qi&M1vdi`aH~>;0_B4B{kY?Ib%JvLS$pEt6 p<$(uOahD&Kd0}!a=_4wgNu!W#fyo9De5evkS&*WN@j6EX-Q&9 zW`16#LSboQYGG-rLSmjmK~ZW+W@)ZMX;LOgq$m|Akdc~~Qkqu+RF+u`6x2$a?8hWl z#*yxppY7w}lbhwtCBUv~a`k)qu60K)ci*XAo@6fZe9NTcl*+uEqXJ2Q-uVkdwpHLBr=stb;A3LJu35VORQNytK5` z)y+BAxln`Ipl90Rt)C1nn4AoqDSU$|3)ByCuwyEcDh#xmnV1$TG>=j^<*bWo}3NZly<0e*Y diff --git a/app/src/androidTest/assets/backupTests/chat_item_standard_message_sms_00.binproto b/app/src/androidTest/assets/backupTests/chat_item_standard_message_sms_00.binproto index bdb56ae7d1ccaa7fb4b98c964b5468ffe732c1fe..4e8fed95ac1b2f1a916db19de4af06c05fcd81bd 100644 GIT binary patch delta 56 zcmV-80LTBY1hE950x>WmE(ih;1Q_d=xzxZhH~~Ts2(Hnb?ej1Yp}?7pk})6wS`88l O3JGvYN^yBpYfMob;S&h} delta 54 zcmV-60LlNc1g`|30xvEiEC>P+1Q@Q-obB^4H~~Tu2;I#8!^JTWq5Oo=n=}{!AOTtl M5(f$eaAavpS_SqJga7~l diff --git a/app/src/androidTest/assets/backupTests/chat_item_standard_message_sms_01.binproto b/app/src/androidTest/assets/backupTests/chat_item_standard_message_sms_01.binproto index 9775c36b7e85d2a93d58614b76fdfd2570f56d48..a80f49fdf39961839d3421a5d3dbbc5999d6fc5f 100644 GIT binary patch delta 134 zcmV;10D1qD1^)z~0)KuYdxzxZhH~~Ts2(Qtc?ej1YqQIGqk}((oT3Zqc z3I|0}bazuxbsA0zN+JqrZDD6+FKTdQXKFeM5LlrgC*&zX;^FjKmb^@ICm5}Tp1F%Y8sgwdNcT5l2y z3JF5LshA zY1Lhs_V{u5gPNS;*cj-xrRxGhAT>EQGc#m1Ib=08WH~uzHWX$!H!)^7I5Rn6Ib&rq JWH=fC7y(v-I#B=s diff --git a/app/src/androidTest/assets/backupTests/chat_item_standard_message_sms_02.binproto b/app/src/androidTest/assets/backupTests/chat_item_standard_message_sms_02.binproto index c68f336276b3fc6a0208744d075af613efc97e95..cd01efba24abef1374e30bc2cbde110ac507e11e 100644 GIT binary patch delta 414 zcmbQqagu!jQ~hyfr6bH7OahD&Z>R6Pa=_4n(Tk0Xg@Z+kA!-e?5H}ZRfu~ntWpK7n zpp+k%ml9WIZen_>epW$hdX^QJK*T}?^(UH+j~;%BnzqNMNL^y>#`&k2gA{m_cHNxf zdt~B-wX1h^746&YyVLT4iPi(tyZh>&r2gIPD#akdC{@W-t|Y+;F|Z&n-HN@)v8u=; zGTTAcw^-?~)^cqw z=8ojo8|>e3#K3i&BdF{K2F{6&HBm-3D34R zPVuXul7FL5HvO_ox&Cg&bo&WlKNNE1D{+=(rlf*wFmZSw>2X1F@=9iTd!X6>&K@~h zAa(tX_mAaYm0M0NhXjrVFnIV>PEkAtc*zkD;}uA4mDZR?ao GDFy&L?WlnO delta 494 zcmX@fK9gesQ~h)nr70{NOahD&8!pay``N&P(Tk0Xg@Z+kA?gpa5IYxZK}x1qlvDy& zj1pI7Zen_>epW$hdX^8DfJs*T&l|&zke- zhQy0)OJ6fNDVSQC85^gVS*DnprdV30nWb5n8>U%U7+WS<>L;ffrC3NYNH9uGX5^Z{ zsKg1eq#!Tdir3XSFub(1)YZ*7*SXMP5|_t1smars&o1a6hcH;VB6E3ipdUvc%p z=Pg14H{%IsL8^!=Pl+?JG$k`%Kexcxiqp?E+`Y)Ls>s9PI)}$;xh$ZKMmJpZ z3e=Omc6P^Vzx}t%(?dw0y&~ym&f|l{N^8A;9ecrf)(h`%+QVk6(OfA74ZeiqV1bVnEGbI&dt%<`;VUKIfle3xS1A+Es zW^Irv{WhW7)}?Q=Yfsi`A%XP2r=^ayu2^^b(wr@NGkjAa!E3?nq+n*AmXe%g2sGZp aG|?h4H6xzxZhH~~rx3JVAX5RAdl-=sAn09suV3knHv zNlI~fQ)^678cqsIA_{43VP|D8YH(#|YB~xKSfL;%DO=WiM)QWoK$k3J^4EU-^77f|9*%bN`Sc#`+QvSz|qE)m@qP z_;L7ynw;X;80fa8>jFX`H90mjGh{Y7WHmKpIXPxFW;i!7W)C7V`VaAI2r&L E0d=x8t^fc4 diff --git a/app/src/androidTest/assets/backupTests/chat_item_standard_message_sms_05.binproto b/app/src/androidTest/assets/backupTests/chat_item_standard_message_sms_05.binproto index e673f1123c4b8e8ce6890da39af31f4de32f1a85..3ca89b7638bbc92b4fe19a5263112ca84f0a3d5d 100644 GIT binary patch delta 440 zcmbQwagu!jQ~hyfr6bH7OahD&AExiTa=_4n(TjtNje|vtiGwj}6|)d07rSdvNqKN! zsgxg=ml9WIZen_>epW$hdX^QJK*T}?^(UH+j~;%BnzqNMNL^y>#`&k2gA{m_cHNxf zdt~B-wX1h^746&YyVLT4iPi(tyZh>&r2gIPD#akdC{@W-u2jznF|Z&n-HN@)v8u=; zGTTAcK&8yvUw`;Cr{*4f za8_c&eN%}W?H^j$Ef|6n{QoUh`m42En~S+4`Sk|-w=Hd7B(w8Ub2!Vz@-P4TDksGt z70(r|#FYpIcyT#S!7_?^KxUoZ_%p!s8_?$oy~Bt0tt~3O@CX$L}P=rh88% zCcS@tklBJMNI`S)rjJuMe6zlCLc+7HjZ^$;sN~=1lTE+uQm(&SG2MOw*ms3o`AVE+ znJK9t3rrjyNP1k5oV=b{-X3W5zq3b<7D!!xFASJyk!eAT>S9hfBaDEB{GHBoLWwn|U>M=C>b( zKbmLFd2~bK#kQrdnVb|%EzOLLQ_L(=OifcPEz``>EX)nlOf4*oEfX!1Q;kwAq!=U^ zr6x0SO<+{wgjiCLmu|)D>KqteT3YJr=A7$X=rD=PW1ZCG=}hwVep~{#O5__w`2H2x zq^qyE`rz{xA%UCm_ZUNN8Xw}7VmWtHW#(6jXJ@x`vRE)UDWq7Mrlq7B7@C@-SQ;BA z8yTb+CK{L|r>0mMnE;(*D#ajG#FeMSnOK^VnXjK)U~I+d=Nj%_$%f{}Mn;J#CP`_D$!4jB1{S84U=O!2ay0@yT$Y)V3bNM3;ij<1HRj3L z%<_Ri`!cgONR@t@&~59|x7oEP>$H$S`rp%1$68mcyM1ZS7QGq1sgU5cV0Kb4GfzuN gPBH`KaG5qR8l;MfWSEruvwA#N_t0#C2P J%HV9DKmeY74|@Or delta 49 zcmZ3-vWjH^la{8EItP;gqr{erbKZV7uweA!<>KaG5xBAV_11N!S`1N~LhM|u1u24^=kRrzV5)fHq zJ!#clnfCZ`_=B39;@BAIwx#O=LLfCcHZwD1HaTQ9HDozCW)(JOI5#n7I5;yoVL4-E KGGsU!02l#hI5sN) diff --git a/app/src/androidTest/assets/backupTests/chat_item_standard_message_sms_08.binproto b/app/src/androidTest/assets/backupTests/chat_item_standard_message_sms_08.binproto index 817cd32fa0c5b0a04b0ace2d01a0dcd9c289d089..9cc6cbee7077ae739eefe864d9ac55f63738b566 100644 GIT binary patch delta 414 zcmbQqagu!jQ~hyfr6bH7OahD&pQrDepW$hdX^QJK*T}?^(UH+j~;%BnzqNMNL^y>#`&k2gA{m_cHNxf zdt~B-wX1h^746&YyVLT4iPi(tyZh>&r2gIPD#akdC{@W-t|Y+;F|Z&n-HN@)v8u=; zGTTAcw^-?~)^cqw z=8ojo8|>e3#K3i&BdF{K2F{6&HBm-3D34R zPVuXul7FL5HvO_ox&Cg&bo&WlKNNE1D{+=(rlf*wFmZSw>2X1F@=9iTd!X6>&K@~h zAa(tX_mAaYm0M0NhXjrVFnIV>PEkAtc*zkD;}uA4mDZR?ao GDFy&(BdDJM delta 494 zcmX@fK9gesQ~h)nr70{NOahD&+b+&|``N&P(Tk0Xg@eV2A?gpa5IYxZK}x1qlvDy& zj1pI7Zen_>epW$hdX^8DfJs*T&l|&zke- zhQy0)OJ6fNDVSQC85^gVS*DnprdV30nWb5n8>U%U7+WS<>L;ffrC3NYNH9uGX5^Z{ zsKg1eq#!Tdir3XSFub(1)YZ*7*SXMP5|_t1smars&o1a6hcH;VB6E3ipdUvc%p z=Pg14H{%IsL8^!=Pl+?JG$k`%Kexcxiqp?E+`Y)Ls>s9PI)}$;xh$ZKMmJpZ z3e=Omc6P^Vzx}t%(?dw0y&~ym&f|l{N^8A;9ecrf)(h`%+QVk6(OfA74ZeiqV1bVnEGbI&dt%<`;VUKIfle3xS1A+Es zW^Irv{WhW7)}?Q=Yfsi`A%XP2r=^ayu2^^b(wr@NGkjAa!E3?nq+n*AmXe%g2sGZp aG|?h4H6KaG5qR8l;MfWSD~2d;AxQM^LjT%3{N LX)Yn@1)g32!+Q_Y diff --git a/app/src/androidTest/assets/backupTests/chat_item_standard_message_sms_10.binproto b/app/src/androidTest/assets/backupTests/chat_item_standard_message_sms_10.binproto index 0c79ec802c835b72179602482d1341a0be983ac9..0d7c9c39e4f7de24333000f3d9541eb9eb8ae81e 100644 GIT binary patch delta 136 zcmV;30C)e61%L&h0)KxZeFy>&0T}g{xzxZhH~~rz3JnMZ5RAdl-=sA<0tf+GT@nil z32;eDad}f~Oi>z63Q8ghX>DO=WiM)QWoK$S3J_SKASdK0LE_=`T9&*_awizAv7gHW qQXmW>y4jRX#F3D#tGbGEzPnAiIp8!Z;5FU8f8=HTvqc&J7y$uG#WQ#S delta 150 zcmV;H0BQe#1&#%v0)LDFB8dSA0uTWhxY3;L^DsC8N(~AN2m}zXoyw)FF**QRYZ3DO=WiM)QWoK$k3J^4EU-^77f|9*%bN`Sc#`+QvSz|qE)m@qP z_;L7ynw;X;80fa8>jFX`H90mjGh{Y7WHmKpIXPxFW;i!7W)C7V`VaAI2r&L E0Xh*hPXGV_ diff --git a/app/src/androidTest/assets/backupTests/chat_item_standard_message_sms_11.binproto b/app/src/androidTest/assets/backupTests/chat_item_standard_message_sms_11.binproto index 8b0d759560c7e36c35413111705a0afff316561e..2d0c770d46c237d94bb518aebc33d7da10cc6a03 100644 GIT binary patch delta 438 zcmV;n0ZIOy2*(GY0)NE=BEka*0uTWh_LsTTz%e)hN(Kr92n0d^TB-vQ2?_^AQgnAy zQFR(l3Q8ghX>DO=WiM)QWoK$S3J_SKASdK0LE_=`T9&*_awizAv7gHWQXmW>y4jRX z#F3D#tGbGEzPnAiIp8!Z;5FU8f8=HTvqc&J7y%l23U?w2X@6~DXJs#NZf80NazT1> zNLgz@9Z1<8S{zJfOlUS%Z(%u3NmoC2PDU+nZ%i#aS3y`fZ+U7w3J`f5?fU!;0PyVAK{VJy`3Im8^>##rVgogAPYi?z133nE6)B5!u8UPw! z3R@xxVRd9_Z)-1Ya5FjxSWQntacx6nK%*E)=>=*$3J~^ts*q;dQ_A)XPRRhW-sKpQ z@8`h-I08~2DWkISm9X|Z)W{e~hK30j)m0h&Tgig@K4jPKsFy#G8UPpp8gUA5A_;bB zWMywJZE!R|;2B8J8I!F8A3r<_5dO`?#c&$e>`VBk^&^DJrx>lVpUVR{15zLkWY;NA g6Q6*U4UVbtjlK|&<5GHQ^!7Fjev_Lgwj4>s;tCiOXZ1)a0p5^7VdP0=G)!8%6m371*S! zuekc)^A;h2oALJ;Lv9)$;+0}KcT;8NSBYn5w{)^tFgPisSemA#q#78Snxt478z&nX zq!=a|m?WpBSQ?oContD+AXUVbr^K09nv$8XpIcyT#p&l7?q1|rRpjAtox|g_To%wq zqZ_Vy1?tIOJG*1G-~QX>=^-T0UXgS&=kdW}rM2F_jy>dvlvvY#`2@2C(8m_$<`!l~ zDVAo*sm95M=Eg=wi76&YX^F{ZsfGp?rj}q2w=i-w0zF)onUV^!*2Lkau*Ws#$(hXZ zfk68*vo=VTew)y3>(aN`wI}PekU;w1(^AJ;SFF2zY0ehC8NR8I;I&|OQZO@5OG!>L e1R8H)nrM-jnv#@aWSN{~Vw7rWVUl77^dSH{wXHG$ diff --git a/app/src/androidTest/assets/backupTests/chat_item_standard_message_sms_12.binproto b/app/src/androidTest/assets/backupTests/chat_item_standard_message_sms_12.binproto index ad53a185c0309d21a55436674caa2627c0ee6ada..feb09dc7720ecd9e0fa531f18a32d43603714920 100644 GIT binary patch delta 53 zcmZ3*vW{f|lb)`UHV2acqr~^=JFgrtv|#k&<>KaG5qR8l;MfWSFNP>yA#N_t0#C2P J%HV9DKmehE51{}6 delta 49 zcmZ3-vWjH^la{8EItP;gqr|R@bKZV7uweA!<>KaG5xBAV_11N!UJOy3LhM|u1u24^=kRrzV5)fHq zJ!#clnfCZ`_=B39;@BAIwx#O=LLfCcHZwD1HaTQ9HDozCW)(JOI5#n7I5;yoVL4-E KGGsU!02l#viZ)3A diff --git a/app/src/androidTest/assets/backupTests/chat_item_standard_message_sms_14.binproto b/app/src/androidTest/assets/backupTests/chat_item_standard_message_sms_14.binproto index b2f0f0e2481a1ccd626db20c9027ade1bbf97c98..eb027926e689705660e832839137fb7d1c5be02b 100644 GIT binary patch delta 416 zcmbQuahiPrQ~gP1rDMz-OahD&Kd0}!a=_4n(TjtNjf2IDiGwL>4YLq87iWQ|S7Bvv zwojmxAD5RBS7vTvda8a_L27!I6_-H7LIw3FnvRbieuYt?k-RvsGAi*eA$t6{;#0fF5ATQmDy~weu z$Rje_LDu7@+~f^R^7S@c0+ljvfBoUpoSJ*^!C8q7_e~{kw0~$}w_pfT@c*}1>95vu zZ7$}HrR6JL-5@%v*N@l)(Zh^5CM})7xQ(>-i zio;?FkC&`jK;yqvubPl{EBMqm9>0?eo9;c8nDqYnL1qi4AO+3Eo6J5=-SEx&$_WY2 zwl+@jtD%yAqfa*dvP-%CZpC!_31B}Ia^)*=mSv`-f^0Bxcp&L+E7i&RErdO0y z0#}R@S7vTvda8a_L27!I50`*RR{YNz!=_1l^NRmZP&)QYNFXxVHuGxi%x^yme>BgU z^XP`ei)~9^GdU@kTACRfrU39+OgFWrjQ)j2S{w6xUK%{kY(&|wmn$2zIWGnwS;{kQ~fmB=@W@ck>WNmpNS z^}**YLIOAA?=gnlG(N;D#d7YZ%FM44&(3b?WU*jyQb@5hO-o5NFf=tuu{1VLHZn*t zOf)b_PED~iG66crREj~Wh$~NtGqE%!GhaWqz}Sk@&o$h=$g!%(!{IuI$7#7Npp8a1 zT=NRllf8C!$7;X*x69K*NT9tU>1NL3gT+c~y?-5h$Pp>Arv35>W(%N?EzHd=%#2bj z&5~1%lMT&{jf@ggOp?+Plg&~M4J=G8!5(g5cl*+uEqXJ2Qz5}?!R(}9W}cRkoMZ?z c-oiA|A~7{3DaFV#ImyH*)zZQw#SG{}0Qp3$jQ{`u diff --git a/app/src/androidTest/assets/backupTests/chat_item_standard_message_special_attachments_00.binproto b/app/src/androidTest/assets/backupTests/chat_item_standard_message_special_attachments_00.binproto index 04fd57b73a788686116060ab3eaedfa00df8f061..668a69b07da9ea779cddd75445386c31ef037ed3 100644 GIT binary patch delta 124 zcmV-?0E7RU1@#1=0(EpEatHzt1Q@ZUmFB55LJ$b9(VXq`Fc6`@nT(P#AOTua8c_;M zA_-x2WNB|NZE!PcJPHtCD(1+G|GQ{-+09f#OUiN>@~MJ}2Oap e`0+7X5PUI$lD%$o|Bxca`fskg6&e5#0T==MX);3q delta 162 zcmV;T0A2s}1eyh)0)LnRB9#FM0uTfkz4fcuu{1&w2;I#8!^JTWq5Oo=n=}{!AOTu* z8gdG3A_-x2WNB|NZE!PcT?!C35N_-ZrU$?1Rs`hZXAgH05EP$TovTlriV6>5leGW) zB^Z+W@}2@B24`?dN^yB805H~w_~i33LLf0TIc7CEIb>mCG#h3)V>n?jVK8PkF*!40 QG-hUIVlp)v01yEf0khURe*gdg diff --git a/app/src/androidTest/assets/backupTests/chat_item_standard_message_special_attachments_01.binproto b/app/src/androidTest/assets/backupTests/chat_item_standard_message_special_attachments_01.binproto index b2b4a0dde2b19502a763e20d0a863ea801f3ca66..bfb4689640010a78bc0575463d8863caf98780c9 100644 GIT binary patch delta 151 zcmV;I0BHZL1&;-w0)LGGB8mYB0uTfkvZa;gsWd_m2(Qtc?ej1YqQIGqk}((oT5B3s z3Q{5oX>DO=WiN1UXKF(V5Z&2VZ2~D~1g?pcsy*d|AQ*wAh{p#a4tPmYQe;h1ZbD*9 zb#HVi05G}wh3E4zS`c9NksEHn>1R90UC4) za3Tq5ZDD6+FK}*WYGDcx6+>3|B8=fU2E4QY@-c3#5)cgn&JnSuV1_lN>uFS0&nFnm zrkafcA_`+fX?HHZV9gGc{o~Wnwlt iH8eFgV`efp8UPRiG7$;{@Sl=^5CIsC-s6djG#~*LG(d^~ diff --git a/app/src/androidTest/assets/backupTests/chat_item_standard_message_special_attachments_02.binproto b/app/src/androidTest/assets/backupTests/chat_item_standard_message_special_attachments_02.binproto index 5d477fda48f948ab9f25a69281863f05a1646493..748953ca696b1037150e42504274e8d6f78d43f5 100644 GIT binary patch delta 152 zcmdnVI)QZoQ+*$!Qa2+9lK`W{=A~1gtu*ms<6_}pkz$A{lk(&8P~t4hOi9hx&n+;? zvg8uzP4Ju=yJDtZ-=<1=w@-6sODuT(BrZt7{kF?Bp@Ic>>^^MTR(|EdyYEr7escOahD&`@gQfvC+hfjf;hYMT#M69-~wlSAh~|S!POVzJ6|j zNme44z}K`UcY)-b7we@xC%OEoRuvNXd2fEo(cd5b->;g|b=xStQ)2VNlmFS2xZG3R z%BxcIJo8dD7z{4WIp6r%&`BZ9G9}eA&CDd(G%YF3AT2E=&B{E{(!?S$CCS*x%-q6K nia~%`g3(Bji{-=oNew_p_1=5j*=?c#6`I&9z#`EH5n=)WnDIq? diff --git a/app/src/androidTest/assets/backupTests/chat_item_standard_message_special_attachments_03.binproto b/app/src/androidTest/assets/backupTests/chat_item_standard_message_special_attachments_03.binproto index 5d0733805b51585d74bdd7872ba6186fbabc4ced..79ee80da9adccd6e011d2d46422117d29185c612 100644 GIT binary patch delta 123 zcmV->0EGXS1@r`<0(5gCaR>qs0T{HUmFB55N)HMR2m}!0jKIdIFd_m70a{ZUQ3^{U z31M|)X>TuWa5HK=3J_o_=E#fxyJ&dX%~V56%5oU;se*|IA_sMKMMgtyLnr_+-1pe{ d@iAHud@+KOy>4^=kRrzVZ?3x)8UPRh7y+R4F2eu- delta 159 zcmV;Q0AT<01eXP%0)LeOB9Z|J0uTWh!1b%xu{25#3JnMZ5ZI&ZwXQWH0tf+GbQ*FB zY$6F^b!2I8FKuu$YF!EtHV|&?4WR_09uIw8gvS9 zA_-}2VP|D8aBgR6VG0lxLss}AjNv#2ytDxFF>b695Dfy(5wWIVhBc+@X;fCvCm747 znvDV?3S&fRcR_7gc}Z+205JNsj`Hj=LLe|?FfwChF)?B>VJtQ_FgP|dHDNVnVm3K7 hG&MG3W->P#01yH)5efwGpOSzO0T_+m00OufEMmGW+%=FFB@@cKzykb?Vdmuo@=3+~u`*tD(u%7b_7jSHE& zSl$*DF425Yw&SwB6oUY>1f!847t4qFlNx}QP560r;W0x6Mq!B9#9jdwiHQ&~CIC{{ BIhX(d delta 195 zcmbQlx|?+YQ~gdxrEQEHOahD&hrX`9vC+hfgNu!WMT?1pF=`&8R2f%+5@%UvN@~7- zZh=WwBA39|v?h0f p!cvMsfLVgkNRW%=!~97NKxg&dd)(P=q5u_|*ek#y(FYM?0szL~MW_G( diff --git a/app/src/androidTest/assets/backupTests/chat_item_standard_message_special_attachments_06.binproto b/app/src/androidTest/assets/backupTests/chat_item_standard_message_special_attachments_06.binproto index cfab6bd85ff956f1eb7fdf53b46cc97811b9f1be..5ead9dc8489912b9df1331cc6e146ef9eba8e08c 100644 GIT binary patch delta 121 zcmV-<0EYjS1@Z)-0&;O8ZwLYq0T{QXmFB55N(~AN2m}!0jKIdIFe(6AQyNhUOCkwj zb!2I8FKuu$YCH-MU@GRwi~qZ5c-hTVLrcnX81kuti3cJFb#+BXLv2GS05IJ5*!b}= bS`d6Of|9*%bN`Sc#`J$5CIqgg8DAC delta 157 zcmV;O0Am001eFD#0)LYMB9H+H0uTWh!}Y7!u{25z3JVAX5ZI&ZwXQWP09te!atdrB z31M|)X>TuWa5HLM3J^9BZtM-F2fyf61mxpq4|fs}6rWk0t52MY3J+nEwEz1h7?S$( zo&q8UXK+bMad{{JFxH6p`TT7=fjT#|I(~cu7)HWKB|TLSjpG zZ*(XCFuD4L=kqaI5McI^8*bQ(KtY8-NV6|kfEoZ00x}T_1P}0^l7J8a7?AnZp~f*F E0pQv+*Z=?k delta 181 zcmV;m080Ok1+4|30)MLkBB%if0uTWh#PzG#u{25#3JnMZ5U-uerK>SA0tf+Gi2)jP z3UDF`X>DO=WiN1UXKG;z5EVmK_#%wqI0n450P-@h+hFk~kswS7Ef diff --git a/app/src/androidTest/assets/backupTests/chat_item_standard_message_special_attachments_08.binproto b/app/src/androidTest/assets/backupTests/chat_item_standard_message_special_attachments_08.binproto index ec545d3094773660a7689301b9ac8f8da63a305c..0ab853721443537931a12d06dcfbfe9b03f243d2 100644 GIT binary patch delta 152 zcmdnVI)QZoQ+*$!Qa2+9lK`W{&ZSeItu*ms<6_}pF=B`+lk(&8P~t4hOi9hx&n+;? zvg8uzP4Ju=yJDtZ-=<1=w@-6sODuT(BrZt7{kF?Bp@Ic>>^^MTR(|EdyYEr7escOahD&N58JVvC+hfjf;hY#fTwl9-~wlSAh~|S!POVzJ6|j zNme44z}K`UcY)-b7we@xC%OEoRuvNXd2fEo(cd5b->;g|b=xStQ)2VNlmFS2xZG3R z%BxcIJo8dD7z{4WIp6r%&`BZ9G9}eA&CDd(G%YF3AT2E=&B{E{(!?S$CCS*x%-q6K nia~%`g3(Bji{-=oNew_p_1=5j*=?c#6`I&9z#`EH5n=)WtZ_w} diff --git a/app/src/androidTest/assets/backupTests/chat_item_standard_message_special_attachments_09.binproto b/app/src/androidTest/assets/backupTests/chat_item_standard_message_special_attachments_09.binproto index 220bc2ec909d684ef1b3daf67bfec5c5ebb43743..d042e7b4ed4dbe842bc122cd2d20f28ee3888a1c 100644 GIT binary patch delta 121 zcmV-<0EYjU1@Z)-0&;O8ZwLYq0T{ZamFB55N(~AN2m}!0jKIdIFggHQQyNhUOCkwj zb!2I8FKuu$YCH-MU@GRwi~qZ5c-hTVLrcnX81kuti3cJFb#+BXLv2GS05IJ5*!b}= bS`d6Of|9*%bN`Sc#`J$5CIqgikdFU delta 159 zcmV;Q0AT;}1eXP%0)LeOB9Z|J0uTWh#`UY%u{25#3JnMZ5ZI&ZwXQWf0tf+GbQ*FB zY$6F^b!2I8FKuu$YF!EtHV|&?4WHhlm9 diff --git a/app/src/androidTest/assets/backupTests/chat_item_standard_message_special_attachments_10.binproto b/app/src/androidTest/assets/backupTests/chat_item_standard_message_special_attachments_10.binproto index 1a8b492bc3e89c40fcfaa673c4cd3d67aa0ad239..099ff35112e89d82d7344567efb7fabbea8344c7 100644 GIT binary patch delta 150 zcmV;H0BQfL1&#%v0)LDFB8dSA0uTWhyQP)psWeIt3JnMZ5RAdl-=sA<0tf+GYZ_Jx zQX&ayZDD6+FK}*WYC{ST-Pu=d0x4z$u8EYYJ>`TT7=fjT#|I(~cu7)HWKB|TLSjpG zZ*(XCFuD4L=kqaI5McI^8*bQ(KtY8-NV6|kfEoZ00x}T_1P}0^l7J8a7?AnZp~f*F E0p!gz;Q#;t delta 179 zcmV;k08Iam1*-+10)MFiBBlWd0uTWh$Mvh&u{25z3JVAX5U-uerK>SI09uIw8gvS9 zA_-}2VP|D8aBgR6VG0lxLss}AjNv#2ytDxFF>b695Dfy(5wWIVhBc+@X;fCvCm747 znvDV?3S&fRcR_7gc}Z+205JNsj`Hj=LLe|?FfwChF)?B>VJtQ_FgP|dHDNVnVm3K7 hG&MG3W->P#01yH)5efwGpOSzO0T_+m>^^MTR(|EdyYEr7escOahD&C%&$}vC+hfjf;hY#fc$m9-~wlSAh~|S!POVzJ6|j zNme44z}K`UcY)-b7we@xC%OEoRuvNXd2fEo(cd5b->;g|b=xStQ)2VNlmFS2xZG3R z%BxcIJo8dD7z{4WIp6r%&`BZ9G9}eA&CDd(G%YF3AT2E=&B{E{(!?S$CCS*x%-q6K nia~%`g3(Bji{-=oNew_p_1=5j*=?c#6`I&9z#`EH5n=)WxWPrO diff --git a/app/src/androidTest/assets/backupTests/chat_item_standard_message_special_attachments_12.binproto b/app/src/androidTest/assets/backupTests/chat_item_standard_message_special_attachments_12.binproto index 01ca7900643d08cdc3b69ae1b60325fdd5eeb778..c49c335f658929d1da42df4ab83577b2f3acbb64 100644 GIT binary patch delta 121 zcmV-<0EYjS1@Z)-0&;O8ZwLYq0T{idmFB55N(~AN2m}!0jKIdIFiHSgQyNhUOCkwj zb!2I8FKuu$YCH-MU@GRwi~qZ5c-hTVLrcnX81kuti3cJFb#+BXLv2GS05IJ5*!b}= bS`d6Of|9*%bN`Sc#`J$5CIqgkXA0+ delta 157 zcmV;O0Am001eFD#0)LYMB9H+H0uTWh$@Qz)u{25z3JVAX5ZI&ZwXQWv09te!atdrB z31M|)X>TuWa5HLM3J^9BZtM-F2fyf61mxpq4|fs}6rWk0t52MY3J+nEwEz1h7?S$( zo&q8UXK+bMad{{JFxH6p`TT7=fjT#|I(~cu7)HWKB|TLSjpG zZ*(XCFuD4L=kqaI5McI^8*bQ(KtY8-NV6|kfEoZ00x}T_1P}0^l7J8a7?AnZp~f*F E0q&?Y_5c6? delta 181 zcmV;m080Ok1+4|30)MLkBB%if0uTWh%Jr+*u{25#3JnMZ5U-uerK>SY0tf+Gi2)jP z3UDF`X>DO=WiN1UXKG;z5EVmK_#%wqI0n450P-@h+hFk~ks#_c?U diff --git a/app/src/androidTest/assets/backupTests/chat_item_standard_message_special_attachments_14.binproto b/app/src/androidTest/assets/backupTests/chat_item_standard_message_special_attachments_14.binproto index d56316ee106321ae33fb67112d05f3e59bbc6627..4788c508ca43fd658c661d3b4f5962f82fc3538e 100644 GIT binary patch delta 154 zcmdnZI*D}wQ~d-+rCvr3CILo?{Y$4lTWR9O!NtbG;>E00OufEMmGW+%=FFB@@cKzykb?Vdmuo@=3+~u`*tD(u%7b_7jSHE& zSl$*DF425Yw&SwB6oUY>1f!847t4qFlNx}QP560r;W0x6Mq!B9#9jdwiHQ&~CIDx{ BIl=${ delta 195 zcmbQlx|?+YQ~gdxrEQEHOahD&r@yYgvC+hfgNu!W#fyo9DQX_0R2f%+5@%UvN@~7- zZh=WwBA39|v?h0f p!cvMsfLVgkNRW%=!~97NKxg&dd)(P=q5u_|*ek#y(FYM?0s!KLMbZEO diff --git a/app/src/androidTest/assets/backupTests/chat_item_standard_message_standard_attachments_00.binproto b/app/src/androidTest/assets/backupTests/chat_item_standard_message_standard_attachments_00.binproto index 8ef3ccc0c546fbc06d9c16b53e4be10b22dbf6e4..57c32011aab503e0cf8b8126b09d876c381cf884 100644 GIT binary patch delta 119 zcmV--0EqvW1@Hu*0&s64Z3qGo1Q_d=xzxZhLJ$b9(VXq`Fc6`@nT(P#AOTuV8cYgG zA_{43VP|D8YH(#|YB~xKRM|7a4H^W_*(90uN2Qc57{0WLg#%I`PyVAK{VJy`3Im8^ Z>##rVgogAPYi?z133nE6)B5!u8UV_PFXaFL delta 159 zcmV;Q0AT;{1eXP%0)LeOB9Z|J0uTfkuF;(B^DsgZ2;I#8!^JTWq5Oo=n=}{!AOTu& z8gB|~A_{43VP|D8YH(#|YFi2rr;1Z*nd>K)Z?dJG&on8Z5)he9DN$+jbwx^*m!0nn z>CzakgvfOw1w&+6S9vG^Fv0M+n)NY4AUQcSWHLE5F*Z47GZ;5DG&M9~IW;*qIb>yK NFk@voWHK567y)f}I+y?e diff --git a/app/src/androidTest/assets/backupTests/chat_item_standard_message_standard_attachments_01.binproto b/app/src/androidTest/assets/backupTests/chat_item_standard_message_standard_attachments_01.binproto index 04d9714a5970008d068caa25b979db05a6861c3a..4089f263de877823941b4fa7a84d36189b001609 100644 GIT binary patch delta 502 zcmbQtKAB?!BU3$#QXdNklK_jvo9R2R958ee;8=fg&fCuh0*emJ?3rXJ!5H<9SxAIS zD5enDQkmH>~{Gd-`U1-rjhubPl{ zEBKT_gMbx#XtuX|NO*z6PC<`rGC>ScGCpZO8D?SmiI#qz;gd_51nX_M1SUKVs>=NG z&5XNl@@%)QQxYZC{63wj#Nm@$;!~009iYKvu>0SMZQl%|1kR^c}dQdiO#G}?v7RAlTR_pgIu!r{gv4+TTWb@<9@oK!bN?)#Hp>PzOY#^1u4AB zGHKCjnQg{w8~RRZZA0gc&2rqm37%79SIpGw+f*qp#URzi$W@}mnOK^VnXjK)V2m|H z9JWb%yb=xKb}LLwt}1s+sq*m2vgHzZz#DikLH%)aNrm(D6rQ6}6D9U->1<_23Ihgs t7{o2A_`B@nHSf}SpO(iu0~KQp10z8$mJjnMH3%?D^f&a)J!GoD2mld~!TA6H delta 357 zcmbQtF`0b>BU1{qQXex1lK_jv`ipbkel~F8Q%B{ey}C{-aduOzjopeVH@u_&`xDwNAni8C`dF+EkkATQmDE7{pMH8m?E zFF4I%iM+>b=E((2iY^RN3`znU?w&a6{N919Lo4jLM9!M$QtKGGRx-jgr)Q>FaiqKD zXZv{g#jj7VoCuj91@=A2|{W;96#Oj<98D6QuY;f?yj#*y~Ets4Xl8uv%jLcGi zgkh>hT57VfsgY5lX{t$bicy-Sp+Slig9M|L5tp12XJTneX1;!Ifw9A1VUMYTLF^&n i1tFo@t|3`i{bD4@#qwePqy_;-i7Dq6bUrauU<3f_>3*{S diff --git a/app/src/androidTest/assets/backupTests/chat_item_standard_message_standard_attachments_02.binproto b/app/src/androidTest/assets/backupTests/chat_item_standard_message_standard_attachments_02.binproto index e08bf6ca90c90d491b2e6f0a0848e02000d2a4d8..48cfe642597e53c6c0a12b7f5f6c40c0e852478e 100644 GIT binary patch delta 680 zcmcb_*~qnk$>%?-(jQh1CILo?x6^lCIbi6;#>K+HBE=B(j8#aSOSCw#ATu>jp`<9Y zxFoZ%G*zKEF(*~3kSkw_vn(?uHD5osz{H9@G~3%fB)nj9ER%e_C6|EN(EwF$?YEs> zZTo}lN}s-!So8aIW{?8+ExyoMZ-nMuKcf7{@8)mw2@j=S@}=)wamn-s(8T$_uz zBl-0P`?oD^UnH~hQgb-V#quxz`YH$X>M};Ienuruh*t~paQGA!v=DDjKFX|EZ^I=p z;c-w^=9h0~+;x*@yKSA42o7K*zcIo6c0SFkAu>*Dx$4H}4a+j*1aSDRhmorj?wIt< zG?WnDA?C4$Ify49FUh$w(V5lB-LWcsvKEVcD$pf+-(Q*SvgO3ZIqs($DqPg(LxS0Y zDM;Z}mPw0N%WN}d+t7DPYa2RmY?kBhP4Ju=yJDtZ-=<1=DF!1!E|w4TCp7@mUVlU1 U+(V`cj1ZxTy#g!}6CgrN0KtF-`v3p{ delta 624 zcmZqVy2QDFDfR-Z(pgpxCILo?4HxIU{cPaH#>K+HBE=B3omEJgOEEJ~Atf~}GcU6w zGe0l2SfMOGr?jLXu|%ObF+H=SB(qp*79-bGMkUU&%#_r8{oDc*E3RZ`-_+EsjJ)8q z$v#Z-^)XxmZ%YM++eA&eB@Bit3m3aGQUki&8 zt8+?Zc%=rD!NCtZW_>kuQb;v3Ge|N{OG-_&NVQB$OEWi5G_y2JGfz!ROEpSKGnHbH zV3Z2sa!}&R%uP&B)z2zOO}FAmcgxTA@$kuYSR(JiG@E(y1180K1}O$5fem+09Cd#0 zz}2A@_FN)o&2y=Iu54tjS% zd!CnA_Sf&_(9UIE! zsKg0zY(ZW+a%h2E3v}!aWict; z8Rj8osD~_=oD`CclZ}kbQh aCZQ?k7IZ!_RDcRi>=oc*k(de*V*&u*souK) diff --git a/app/src/androidTest/assets/backupTests/chat_item_standard_message_standard_attachments_03.binproto b/app/src/androidTest/assets/backupTests/chat_item_standard_message_standard_attachments_03.binproto index e8ac0cf4365e38076652af43b4e1d6a5a6f898b5..d0db77285f2461535afc6ca457ec6e987dea5904 100644 GIT binary patch delta 248 zcmZo={lL0_ss0_K(rZQzCILo?chh%XIbi6;&&A8ZBJjB9z_AquN=zJ#QD+#1Y`Lsc zGK&jJOA<>m^Ybzl3QH4H3rkZK67v)aic(85OLG-UlQKafMX5l6jMTi8(!3I&vdm(j zpi~zlSBVm5VrfcdzJ6|jv6cXj)iXV>s0F*fRTr+BkajEhltF`l!!}8eSE51OZiR`- zRpo9eRUSTBwp;=acmwaLKW;9maGsvRb5v@g#J(+^t;|XsKDi}66)D~U8Vm-z|DD+O v%`i$JZc)YGWhbwBm(KgNJk}Ygm_dS3Nx;S2=gOIUug-?IH9V^xuwDQFOV3~x delta 141 zcmeys+RD0sslJ&}sezG$Nq|ve0g_8V|M1`W%g3^@C#JrTmRE4CX(vnn#vecr?lG0*@(!A1KDI+d9CC)^kihTXt t0%M22!X8rvgV;mD3qnF&L$Vm87?cDy+&yvB`Mm>IhZbAdbBUZa&jAGlFslFn diff --git a/app/src/androidTest/assets/backupTests/chat_item_standard_message_standard_attachments_04.binproto b/app/src/androidTest/assets/backupTests/chat_item_standard_message_standard_attachments_04.binproto index 4f99799c64aca6f05ea3cc2ab51ae226c02fb17c..c23efb59c6657f0bd0887956767b8fc9bfa5ac26 100644 GIT binary patch delta 384 zcmV-`0e}9P2c!p}0y?4tBA){Y0uTWh@0YpMz%fb<3JVAX5RAdl-=sAn09t|r8gUA5 zA_;bBWMywJZE!R?2UTlJM^smElRp9n;eHpNgS3oGr3iiW>ZK6T~o7_9rtX;L5y z+74Bk>=K^W#3TGp+50z;;Tq`bcw|dZC<8FN{>ZlWFBn%N+JqrZDD6+FKTdQXKFeM z5LDSS!VMY(&e4FHXu*_qayt(rz;8rh-2%pKkbBu^cibzWo!v| e7H`w~^&T1kG7$;{@Sl=^5CIsEfR3HQH6Q`j6O~W^ delta 364 zcmZ3&K9hX`ll^pNr76rDOahD&n=a0I``N&Ymy4T&MPU8hQ%hGHDltTTXOf!5$TgKw ziL)#-B{g3^x4^`TE7{pMH8m?EFF0+o6_b2@441&$lheNhMCifb!de>m&jT3Tq>U{8(C{sG?&2guHdYhuhpmL zZ(2I{you%lA%U5`nt_?0OI^LDPM`ap=jA1dbuA}KVQyuByVcUtB*nZ_&Dh-3 s#MC6w($v!2G9@+5AURdaGQ|kwSR+9$mJjnMH2{Nj%DDxdPYe|p0bPrPSO5S3 diff --git a/app/src/androidTest/assets/backupTests/chat_item_standard_message_standard_attachments_05.binproto b/app/src/androidTest/assets/backupTests/chat_item_standard_message_standard_attachments_05.binproto index 4df88f857c3379d48acd2c1c45da75c0e75f3e61..58b76fe6108b42f5f9e884cfabf09b00865ecfd4 100644 GIT binary patch delta 769 zcmbQtxu0tRQ^sC4rCn?sOahD&AExiTa=_4wgNu!WMT?1pF=`Q;kO-GhQc-D1szO<6 zQD#YLu|jEHX|B{VMy`HFCC<#;#Pn4Cg1mGs0UoPodR|crc7Lm0H6iU*@F{}^0W0>< zY;X6F@B)XOf*#joCdV@=*4uCiOn4krmHFkH8F$^}*=}2>BucFLeL7Q#!zZ`Iry|8W zK!eF(_rDX{z8OXdoKN#=h>X)(uDbDg!?FxH0VxIvMkN6kbDt|`^1V76-q!G}dcb-? zs)v!Q6YiMw%rq;mP}h*issQJ*3P*<>VjgRlgLne+lAJ3Oo$H<49jn5lWPIG+wbFES zGxc(G^X=VL>g=OR%nLmH3~ftXjkADm-248@Y?m!3F3xd3-B978K40S0)>B{DESQ26 zUS*lIXtm5XW3~-_r?j@A^TuX5?%o8?sj(|&>h*1^l$TSE+7QQ}N2P07sH&n+-U z4x4&-;5clP^mrv2#O+p?m|RuvmQv;6lV!^#@PIe)p8DhFk_zYPDLhA|CQ9tv(%H(4 z6gmv>(1}}A@pswDYu=^vJ}r-R1}erLI)z;MN}OexDXAdGaGAg(W%6`p`Fcw(0kfk4 zs@&RdJGuS!O0jpJt8CT9*r4v6PF%Y}2jRd(^KFpug08G^V4SjPDnJO?s PgeLY1ut-dR2r&Tw-^M1W delta 560 zcmdnbHJNh(Q~X3$r9M^;CILo?%@^mq{cPaH!NtbGqQ%6)81;=sNS;f!I5n?0wJ5Vh zAtg0AzbI89Gp{7IsGumdB(W&7SSpmuQHe7%H!(d`zaTH&iYwXKH#IdYBQH43VTruQ zZ05-sOo}cHQVdE08}6Ps>iph;t3xa7xkS#I=Thq!xmGg5G^b~#S#hMhC_>n(aNAms!3(j!U3-Ynkz{kmk?w6-hely+tnx2^>D8c1KCB z|Bb2A(kEy2C-O>k_5C@_tiB4K0|Q6q1dTjf~7vfP`VHMOtdI zv8j$?0DLqIG%P+>BjfHvU{DB=9U@^Y2%E z^Z%DGoA~|xKi#hqZ@=toVS%}v3F>kug;X;$gCyg$q|`)3xEz$YATg0ukeZGZn!t!)0>;D=7Da2Ut~V0oV)-zCQUfpzOgXop^NFDX QBSdIouKZXk4WX>)XGadl-Nb75>{8cYgGA_{43VP|D8YH(#|YB~xKRM|7a4H^W_*(90u yN2Qc57{0WLg#%I`PyVAK{VJy`3Im8^>##rVgogAPYi?z12?=)=Z`1nq9vT4cku@0r delta 192 zcmV;x06+hT1-J#E0)MsvBC`Pq0uTWhw9%aH^Ds&c3JVAX5ZI&ZwXQWP09uv-5+e#B zX>K57WoBt^X>@6CZe?>Ic5iHTbZ}vGAah}7X>@dHa~f|7Ya$A1ZDD6+FKTdQXKGst z5T}Y$YMJXNmv6GAozFBWpb`+7O({`n^L0f^m6x6G4C&Gst~rFrbs_~rWLZ~vC;%|Q u@VJ`wF+w0YIW%N4IW;jhIc76AH8eFeVL3H9H#uZwW-w!AIb<>#02l!*XGBE+ diff --git a/app/src/androidTest/assets/backupTests/chat_item_standard_message_standard_attachments_07.binproto b/app/src/androidTest/assets/backupTests/chat_item_standard_message_standard_attachments_07.binproto index eae3a563301af8c1fcabdfb9c7a07c143d8ae798..0fdd517aea5bbbea52e6479d1308202f8b8ff4a9 100644 GIT binary patch delta 527 zcmZ3;zMEqKQ~gdBrEM%6OahD&pQi7;a=_4wpNp4+MWE;4h5JiPjhHwXqo%V6*>YK@ zWEK~cmL!&B=I3Q96qY8Y7M7+eB<3j;6s4AAmgXvyCS`&|ic*0B8L4?GrFkVlWtqi5 zL8)boT>XqnoSC_a>8bh!dFfgLJXX*2yrLHD{w7(yYC_tr;8O+-0#@vy+1~CU;ROym z1wF3GOfF_ptheD3nD98LD)Y-XGw!;{v)#5%Nt9Ug`*fxfhfi*aPeqD%fCiJn?tdq? zeKU*_IG^U#5E-YnTy^8~hGiLY0#XbTj7kD7<~~=>2CyshC`^?>z)R1YIpC)_pZ znQ2yBp{^m3RRPXr6^;%~q82k`{tB{^3nItJ645HzQH69a>?HJS7y6xIdO50 z`{{-X7xnoPr?#H@!e+q~r0^=sq(!S`wi&Z+=sTsg4V^bO%W?N6cutL7F;lN^Q>DBV zgH#tISBVm5VrfcdzJ6|jF;Wm9Lcn30q{l1KAa1w9#N?`Sx0EUmpDbH0fd{;S_Y%|} zHJF%vC7KFG*A=N-Zc&$xO^kNlaBpDk?2WRVYg>$}A}@Rw&IY&6Nt}a#Z5X%uP&B z)i20Px8h26_DxOA%E${&b66tpF`GGvAxg$4%_qYwEI)Db5++d>1}O$5fem+09Cd#0 zz}2A@_FN)o&2y=Bj9e=jVFsmVrde^MyX9y5c=+TxOyKr-ClSO`>K0L1kmceN8k+4r z*_K(pK8{PEcWasPuaM@?@)b!s>%B!U2?-oNq;^M1uK$gx($Xhq^(XR5boKo?%&f%f zoDvycsljY;@WYN-UkxpooD`CclZ}kbQhg3c#~ G3XA}A)`Ttq diff --git a/app/src/androidTest/assets/backupTests/chat_item_standard_message_standard_attachments_08.binproto b/app/src/androidTest/assets/backupTests/chat_item_standard_message_standard_attachments_08.binproto index 1db2c3bdff3675a2262188bd50dadedc9d27a042..2963f1dc6378e1722ab873d1523dbe4d7917e2de 100644 GIT binary patch delta 655 zcmZ3>`GRu+lkqcFrN^usOahD&pQrD&#N73vxiSry=1R^jNdQ_$m@Ob|nqjE`54j+xoyM@-`Nwp;?U z%eEbM^D;iLdr#k*(Dm|rBu;HT^@UA|!zZ`Iry|8WK!e#}_rDX{z8OXdRCDeOSglgb zxN_bqo%jiffl>?-j7kD7<~~=>2CyshC`^?>z)ln<8|vdglpxCBCO8Xw}7VmWtH zW#(7+rBn1I_HF5GWe$o^@c*}1>95vuZ7$}HoqDSU$|3)BsFk{SAF{51A@3LWCyv3b05_fCw=G0CGCnDu{t@=Lu_=Q1IIX9=5szv`R+zkJ!m@9+QVewBFpC30U2ixR7IN@RGY29v?T z4?AXkHFQ!)H8V3vGEPfMO|(e0OiN2MH%~OPG)yy3O-oBPN=Y-7Vvt~z3gL24;>yfT zOi$I%Do9PY;z)PP&-U@~$#qyF?=hQs@^L1`dIl*5C4mihPaJiA@4(fe74}>rXU%h| ze6DO{omtUb0?WICvu3_lpPs*I>D==snhS&kX8LLdW_~Vp^_n_;?t7k>mn7D;oG67k zl>zQlOG}d!BTG|5Gs`q%b5j#jlSE5XOLNPV)HH+SR1M1%Bd}XTxg3=^A#N?mOGgez zsAKmt<8tgeMy{2>NPuWg&rCz|=LBw#cM?H7rEU?G1z9dWp`qE{z-V!I*GkjT&D6`$ z&9`?~sk4tNF)#4&Gqf#nHO`9T66oDpX8bFp`LldQlFoW>(Mv)ChYzXUQIhM=ePgP$ z^vPNMiM$eBeSZ!!!~Dt&^{WMwlR~m_vXPNl3Xm{NwMa`%Ha0afN;FM1Nlr0JvothF k0eRL)kc;KR{7DVKBsJySg3c#~3Q(bmy#g!}Qz1f300#)+&Hw-a diff --git a/app/src/androidTest/assets/backupTests/chat_item_standard_message_standard_attachments_09.binproto b/app/src/androidTest/assets/backupTests/chat_item_standard_message_standard_attachments_09.binproto index 82396c984f4216d4f09e9219ce14b985ce7dd91b..ed346f2c37e10fc60f0ba162c5f4460e1b0e4b73 100644 GIT binary patch delta 205 zcmV;;05bpf1jPlQ0)N8+BESI%0uTWh^q0BRz%fb<3JVAX5aW!%#;7nl09vB~5)=v& zVsdqKWgvECa%psRb0BqYb!{4o0Sa^?31M|)X>TuWa5E|p3_9j6N?M@1_Is+3X4+HA zFn|z1wi!t36;caEabaV6cSdA-NK9%y3J~B8QQjxxgLHU9mqug^#TtSiy)=PDs@~2%x48L^n*-%x_AGfbDz? Hs^A6C1Mp8# delta 125 zcmV-@0D}L;1@;7>0(NyGa|i+u0T{Q@obB^4N)HMR2m}z=qwBSd+7;LQPfQu{z diff --git a/app/src/androidTest/assets/backupTests/chat_item_standard_message_standard_attachments_10.binproto b/app/src/androidTest/assets/backupTests/chat_item_standard_message_standard_attachments_10.binproto index 1f4ac06de0e631d9c44bd9152d86b93efefd0c33..22bff7e2165b9aa5359a81d4d98d6806ba93beb6 100644 GIT binary patch delta 449 zcmV;y0Y3h|2fqiP0)M>&BDw3JnMZ5RAdl-=sA<0tf+Gn*$OT z3Ker>20U`=%ZDD6+FKTdQ zXDSd3I_54)TA;i3d#aFT+EdCffDk$gRYg=;dQd}lctJq95lGe?QUF>UOiEHLHa2B0 zenWV5B}{KjO_Lb|41YZe5Swz2uy8sOn78VP$&a1 zyZ*?w_Ay!zdkMKvt0Z#)sh+AVUyxx@8UPppA`nD3Ow`P8N{N8&dDO=WiM)QWoK$S3J_G;Gr|oT1kTwcne|7dlr9*)w26fSQZ^t@{-YxODyJ(71Bhem rus`jDhV&V0Ze?r~TEKw*ifb!de>m&jT3Tq>U{8(C{s zG?&2guHdYhuhpmLZ(2I{you%lA%U5`nt_?0OI^LDPM`ap=jA1dbuA}KVQyuByVcUt zB*nZ_&Dh-3#MC6w($v!25*V}w$*EG7DMld28VPc-e3(C}0T?Ay&MoMCVyM6f E05j8?^#A|> diff --git a/app/src/androidTest/assets/backupTests/chat_item_standard_message_standard_attachments_11.binproto b/app/src/androidTest/assets/backupTests/chat_item_standard_message_standard_attachments_11.binproto index e404cc7c7cbdb01c802c77140c57e9e3a0d137af..6fda1fcbb904c96018267172054a496b360d073b 100644 GIT binary patch delta 829 zcmbQo`HX7;Q~eV*rH5=BOahD&-=^=pa=_4wjf;hY#fc&6G@Fnumvu^JaY1QGVo7Fx zUZz4}X<}+&X{thEo$dS#U7gN?H&?d;ILEB!~kn7ED13ud+;9v|47HG24c|Q(D{5d1JF2cW;8{)Yug>_4+nd%1bdwbun_4C~+p1 zrex;p=N1@a4FZR4k{+)_gSg!a6O*gT-BPMNe6no01Rn4P-m6!C++0%OJUxZysMJJ> zeOo$PnUTVP0Uic%iz@yuJ9*8!bl#`svCcrn*u$WZD_@DTEHfn)msJ<<@@N+10i`$gcG1TX1v)DRAH7 z3!U{wXx{ZB%76TB{x+ZRQ0gUL`py-XOm8rqGMfDc7y_#qxu!5GaY0f+RzWKEWPlPI z;Divw0CZNpSCEdGS*l*0b497DPri?DO|X%wad^0AesL}+jAoZ@JM89Vd|>yUzBQri z<@Z411}TV`;Xzc*xiet3N-^Wgd8>5dCnN@94)KORKabGcPe$p(MW~ zQK2Zcpfn{jF)t-CRUxUUv?NubEVU@Jq_kL}G_N#QDwNAni8C`dF+EkkATQmDE7{pM zH8m?EFF4I%iM+>b=E?m`iuDXq3`znU?w&a6{N919Lo4jLM9!M$QtKGGRx-jgr)Q>F zaiqKDXZv{gtS4i_``HCc+_1>bFgai&BQoExh*I)m}RB7pxv-%TxCA#|l z9A;Kxbxw&4uhd{RIQU`5tgnU^Oil{P#>qxTW+_0zFx4V0HQCtI$SBb?)g(E^D9zH) zAVrEnf>FwdOHPS15f~i#`nd(h4u6F`rV0kJhlCe|gt~@gVfW=MMlQ*zKyQ|1rlf+j znIMPJWOEkz`WP;Owp{UOaNFn B($W9` diff --git a/app/src/androidTest/assets/backupTests/chat_item_standard_message_standard_attachments_12.binproto b/app/src/androidTest/assets/backupTests/chat_item_standard_message_standard_attachments_12.binproto index 69e2bb43c542321bd022f9fac56ec3c109088b52..6dc70c84a466b72619d68632f259f10639b408b9 100644 GIT binary patch delta 116 zcmV-)0E_>U1?>c&0&Q#}Y6t=l0T}m}xzxZhN(~AN2m}!0jKIdIFiHSgP8v)KN+Jqr zZDD6+FKTdQXKFeM5LDSS!VMY(&e4FAW#0IBK<0-D+&XMW9zU# W?SzK(8EbB3YzcQ3Z`1nq9vT2|%`ANY delta 154 zcmV;L0A>H}1d;`y0)LPJB8>qE0uTWhy3w5N^Ds&c3JVAX5ZI&ZwXQWv09tVxZwhN7 z3TbU&XJs#HaAjv|TM7`Tic@Nt>nE3QvZbBRG%27G5SdLWQEBsaMM{;Io$n0k(ipCU z$aNwGLu6T3c_;ud!SJ}6^)W&qIXN_BGC4IdHaTW9H#IahG!tPtH90pqWMyVBV`VvH IG8zCF0V$a_k^lez diff --git a/app/src/androidTest/assets/backupTests/chat_item_standard_message_standard_attachments_13.binproto b/app/src/androidTest/assets/backupTests/chat_item_standard_message_standard_attachments_13.binproto index a298ca01a7ef00a3dc7242a5b7ebecbca6368898..39a12a83cf7cd0f7633fc2b7ee4280e93d33a885 100644 GIT binary patch delta 501 zcmbQjK8a%iQ~d-MrCt^eCILo?AJcbUIbi6;&&A8ZBG7a2!u=(tUQ8T}QSX?AM7V^K zib_jT70ObJGD}K}6-x6;bETFsa`iJRac1Twrl;x`2 zPZ=}_Sh0s@d%K5(7dY$`^tdJy#1JLpljf6Q7M7oA>E{_fxr|A$-iAwH!sDQ-%rD=} zxa%g*cH257QDV*S)0s*fKDi}66)D~U8cYVe|DD+O%`i&fe41B7WSrJ=)s4>^mSxBZ zNHIt-Dharl`&>Db@73AxwuWcb1J(;tJ&atPaL1)*rde@?x`sqn1vr;gI6CYQ^H{?i z#1oL0n*~#l!mBKk z7Oj@qX3Vys@08Xybl%u3$K9LYIW>00OufEMmGV*yQeBK(B}$x$r74;D`nd(hSVP2N zo217p(I9TO!o=jNa<`N!51%YsE`bNUf%g*BA2*j&I8RUEIVv?#V&9g|R%WCyV1S1~ r+@gxV%T8YNE}i#jd8{)~G1f3J669j}Fn>}5FmC%B`sN-oRbT`F2>ri5 delta 385 zcmbQlF@=2rQ`#hErG91(CILo?-52M){cPaH&&A8ZBCvk$simt8y_h%{qdqVR$#cmT zr{)!>7G;(wq@*V27o{p>=9Q!t6%?hGBo<{BONDYdDsg7!CZ?zA7v!Z|aV0zZrlw|P zifb!de>m&jT3TxuO7*Gfj1=Jd=oD~@!x z{A?c&pInCt+#c^Ff_O^ZA}R~ATzo=9v%RBaeB9l&(sXn)^>TFc?cG)C?4wG|3q1S` zZA)B@v*Ne}dbgGt{|agTEMJkNv))_ul90gRLuz-Fb ztj;Ns;guT91_wXvnDy1rg2_oC**MwA$Seg&7^YgJr6wDj8W|;;rkW(D7^PVn8l*@u zNH9tnamguhCYGjT=IiGc7(4tG_LwRd#2yk}5EAMdl7-cmMuJ={{2%5|Y5<1wlyeI@ JpBO4I0sv6>gN^_I diff --git a/app/src/androidTest/assets/backupTests/chat_item_standard_message_standard_attachments_14.binproto b/app/src/androidTest/assets/backupTests/chat_item_standard_message_standard_attachments_14.binproto index e0b2532aa5a838642f07d7edeab3773fbc0f9e93..915d255bce2dd43c1cc34d919dadaf48f02d3a10 100644 GIT binary patch delta 682 zcmcb@+03B+eyToLG>Vnx{}w zlv!MoSy-B?P@I^PDpkmpuf$oFnUb2XpIcyJ#U7gN?H&?dFgcz{zTT2c!0c#%D!2CA z&aSroL3X82-%70ceL6Epf%_I;=&UzF^R6FJ{^NJ^xA}yJQZM<^cdoc(dV}ed(d;); z3{tBZxu!5Gab@Nvrl;y>6{MzX3Gi4w)ANd2u=`u}stIYgf=?MV2v~82x`sqn1vr;g zI6CYU^tdJy#1JLp;}xW1W;U6VS-jqsOJH`{w!>~-#s_xq>01-JUVe|nsja8Juqko) zB|6OfnWT$$+1>g4WN6+T&qMLreilD+S*%y!vw;^G|l(+w3a>hmGN zY{3+y@G8rsMXP1D8MAHZJEgS^oi{eiarY*8PK{kLQ?GARrMwh_ksue#hxwBlfT^#) Wp>OUXQw2td(8OK=7KsTEAtnH9;sx3O delta 654 zcmZqXy281DDgF|x(s@=6CILo?Js0P^{cPaH!NtbG;>E3)@X`(yfTOi$I%Do9PY;z)PP&-U@~$#qyF?@>RSIfx-j#>Xp2$IL8MugJJRy<5wSe}y!E zmajTp1F%Y5rgwdNc7y%#wS|Ji2 i3LSH0ZgXXFX>=fDWn*u0Wguy8bY*gIa%FU3a%po!;~cyI diff --git a/app/src/androidTest/assets/backupTests/chat_item_standard_message_text_only_01.binproto b/app/src/androidTest/assets/backupTests/chat_item_standard_message_text_only_01.binproto index cc803cdb611e3a5acdaa74834b7c47fffc3c4b08..acf3f0551e48ac645ff21455f2f71b9150cee90c 100644 GIT binary patch delta 85 zcmV-b0IL7k1kMDY0!~dLO9%oG1Q_g>xzxZhLJ$bA(VXq`Fc6}^nT(P#7y()=5*G>; rb7634Wo{sJa%ppPX>oOBAah}CWik;81n{4dfDi!~?&Q4D!ZjcPQR^T$ delta 95 zcmV-l0HFWQ1lRTp1F%Y8sgwdNcS~wCT3L$B3 zAY^4`X>MtBX>V?2b0BtaY;|;SVRRsKVP|P{bZK)k5efwGpOSzO0T{NyzMP3OAOR60 BB|iWF diff --git a/app/src/androidTest/assets/backupTests/chat_item_standard_message_text_only_02.binproto b/app/src/androidTest/assets/backupTests/chat_item_standard_message_text_only_02.binproto index 5a5d19cacd2efa3cdcb0e192e79bdb23bc650b90..dd1cf9b6bc2a477dbacd4d816bb5ed7acea25f54 100644 GIT binary patch delta 132 zcmaFE@|R@+Q*Dh>6$g_5qr}_kJFgrt^kU;;;b4(sh)NZ*<+4u6EG{T5Ni50C&&yOO zEKN);EKOBN%u^^RN-fDO%~dE($^?lNr2+*qQu9(u^GblqGK+zNMuJ={ALdVL0Gj;n W$)1acOcfX*LKAxhSR~#C`&EMEGaEkD9tO)H4@}v`7nP{1JIyt2lvhCG*)1Q2u=3o)%Ie6jz5>q9HC>8nf--zB!%73XA~dwjk{Q diff --git a/app/src/androidTest/assets/backupTests/chat_item_standard_message_text_only_05.binproto b/app/src/androidTest/assets/backupTests/chat_item_standard_message_text_only_05.binproto index cb543ed12333367e223aaefe637dc679fc13f364..812076108222cda8b629eb6c46935c98050bfda0 100644 GIT binary patch delta 134 zcmaFI@}Fe^Q+=IM4F{6|qr`{lJFgrt^y1)R<6zNZ;$VzQ6|&{BPRT4TC@o1W$;{8o zR46P>Of4);RY=TJC@4xT$t=xPC{4-)i4>&*1u|0eQcCkmfXXt9fr3VYTr3~vPig>~ Y{qD)0i-$}V7$HIvdj(h|-a~|#04f_W>i_@% delta 117 zcmey*@{VNzQ(mr8HV2acqr~QmbKZV7@Z#WN<6zNZ;$Vyl5z^t(DlN&(OUzX$$uCJ% zC`v6TP038mOG!*sNGd8VNmVFIEy^q@EmkPaE6p_$=j^<*bWh50s!Y(C@KH| diff --git a/app/src/androidTest/assets/backupTests/chat_item_standard_message_text_only_06.binproto b/app/src/androidTest/assets/backupTests/chat_item_standard_message_text_only_06.binproto index 12bc152a20d54c160645e4b27258200d17997dac..e6fb110b5c6a2a82edb81214b228ee84b3b49155 100644 GIT binary patch delta 60 zcmX@WvXx~4lc|Z45eJh1qr}JQJFgrt^y1~>=3o(c+;iaA3Ii>MC@~=sE}^8N(vnn# Qvecr?lG0*@(!A1K05(+$ diff --git a/app/src/androidTest/assets/backupTests/chat_item_standard_message_text_only_07.binproto b/app/src/androidTest/assets/backupTests/chat_item_standard_message_text_only_07.binproto index 183379c426aacb16fe62ea61026ecfffa89f328e..b9674e4561116b36b6ccdadc44591550de27b410 100644 GIT binary patch delta 84 zcmcb~a+YNQldq4G7YCC7qr|7_JFgrt^y25@q244#p@QA#pCz;>3c? o)I5cfqRirw%)-)Ch2q4VR3kwymJjnMH2^igd$Q-^AyWlL0EcB9-2eap delta 96 zcmX@ha+75NQ)Glv7zdL8qr}#WbKZV7@Z#s<6$g_5qr~UwJFgrt^kU;;;b1Xhh)NZ*<+4u6EG{T5Ni50C&&yOO zEKN);EKOBN%u^^RN-fDO%~dE($^?lNr2+*qQu9(u^GblqGK+zNMuJ={ALdVL0Gj;n W$)1acOcfX*LKAxhSR~#C`&EMEGaEkD9tO)H4@}v`7nP{1IVC*`{r~SD==3o(c+;iaA3Ii*KC@~=sE}^8N(vnn# Qvecr?lG0*@(!A1K066p$l>h($ delta 73 zcmdnWa)@OClar&8JqMEjqr~=$bKZV7@Z#s<qQC4#p@QA#pCz;>3c? o)I5cfqRirw%)-)Ch2q4VR3kwymJjnMH2^igd$Q-^AyWlL0ErwN<^TWy delta 94 zcmX@ha-C%XQ+SwC2nUk@qr{GjbKZV7@Z#m-=3o(6Kljwq)rM9KQ5HhVT#A`_3Mr{+ ynR%HdnfZCC#R_HlIi)29i6sifiRqaoC7H!Wf?O;g=1*z>8nf--zB!%73XA~l>>&*R diff --git a/app/src/androidTest/assets/backupTests/chat_item_standard_message_text_only_11.binproto b/app/src/androidTest/assets/backupTests/chat_item_standard_message_text_only_11.binproto index 519a5f85ad65d9d7031f965f1ae32ebfaadac1c5..7997fb54907ddd0a5d98b3ee06cf2d71c574e082 100644 GIT binary patch delta 132 zcmaFE@|R@+Q*Dh>6$g_5qr|uAJFgrt^kU;;;b3uMh)NZ*<+4u6EG{T5Ni50C&&yOO zEKN);EKOBN%u^^RN-fDO%~dE($^?lNr2+*qQu9(u^GblqGK+zNMuJ={ALdVL0Gj;n W$)1acOcfX*LKAxhSR~#C`&EMEGaEkD9tO)H4@}v`7nP{1JIyt2lvhCG*)1Q2u=3o(c+;iaA3Ii{OC@~=sE}^8N(vnn# Qvecr?lG0*@(!A1K06L=+rT_o{ delta 71 zcmdnWa)4z4lY_mIEeDeTqr|R@bKZV7@Z#m-=3o)HvH11Yb*5enQHnzHT(ZTfdBv$k bnI#G-smb|8sS25SC8qcG4#p@QA#pCz;>3c? o)I5cfqRirw%)-)Ch2q4VR3kwymJjnMH2^igd$Q-^AyWlL0FAR8`v3p{ delta 96 zcmX@ha+75NQ)Glv7zdL8qr~oubKZV7@Z#s<?* AHvj+t diff --git a/app/src/androidTest/assets/backupTests/chat_item_standard_message_text_only_14.binproto b/app/src/androidTest/assets/backupTests/chat_item_standard_message_text_only_14.binproto index 7c9c5f91202d765255ba4939ebadeef14b173313..be5a8c3f66a777b5bb509bbea8e4a9a2c5e88d7d 100644 GIT binary patch delta 134 zcmaFI@}Fe^Q+=IM4F{6|qr}hYJFgrt^y1)R<6!Y(;$VtO6|&{BPRT4TC@o1W$;{8o zR46P>Of4);RY=TJC@4xT$t=xPC{4-)i4>&*1u|0eQcCkmfXXt9fr3VYTr3~vPig>~ Y{qD)0i-$}V7$HIvdj(h|-a~|#06Y>g6#xJL delta 117 zcmey*@{VNzQ(mr8HV2acqr{$zbKZV7@Z#WN<6!Y(;$Vsj5z^t(DlN&(OUzX$$uCJ% zC`v6TP038mOG!*sNGd8VNmVFIEy^q@EmkPaE6p_$=j^<*bWh50s!`gC{zFd diff --git a/app/src/androidTest/assets/backupTests/chat_item_standard_message_with_edits_00.binproto b/app/src/androidTest/assets/backupTests/chat_item_standard_message_with_edits_00.binproto index 829314faf1c84fbb3a3acd6a4cf556b964986145..7081787fb86c24a049bcd7da41e527443ac4b687 100644 GIT binary patch delta 109 zcmZ3=`ix}(Q(CH0G6$0Yi^Pq^ueYuNo@ w%>07HTqgmJb6`CJ*TIwoW0a(jIG1Q!=^6abAbPE5}%DakAb0D`VU A6951J diff --git a/app/src/androidTest/assets/backupTests/chat_item_standard_message_with_edits_01.binproto b/app/src/androidTest/assets/backupTests/chat_item_standard_message_with_edits_01.binproto index f2601b768df2e17dadf2a793b72402c768814652..806d8539f5e5a215cc543c8a1024319cd47ad722 100644 GIT binary patch delta 224 zcmdnMwuWs1Q_?CXrR7W*tC16-x3;5*3P43rbTm6Z29MQx%emN=s4!9hX(e delta 232 zcmZ3(wt;N{Q~f$7rPWLvOad$t>*tZCIJ?S8;f6WU1w^f3FiF1{~XA1;^X)TW(fQOQ&BuZTwEN9 zc_o?o1&O&%0vzYSdIYY6DGA0XS0QIE$I`sgT!qq-%)G>0h2q45%+x%ElA_GwlFY)= lRG>gkszPCDVro%pUP@`Ms6t9+aY1QGBGAaZOt1t{6#$pzJq-W= delta 144 zcmbQjI+Jw)Q~h*Cr74UYOad$tHx|F%y3W)n0?he+|2dH3B*gI%%nsHA4UZ diff --git a/app/src/androidTest/assets/backupTests/chat_item_standard_message_with_link_preview_00.binproto b/app/src/androidTest/assets/backupTests/chat_item_standard_message_with_link_preview_00.binproto index b6554998a78392a0e79d835e929773ee9c96eb59..5f12a71b7c2c90e44b0adb6fddb14ca391e83dc7 100644 GIT binary patch delta 126 zcmeyv@||S?Q+b(E2?vt^i^QAVe-3>&aT4HIcX7_!&jtbu56tYDWT?Ox6)L31rIVIg zRFtWZm{XEkl&FwVQc_TCrLSL{nVy%JqnBTlt{;+K;OSLZ8Jz7C=&q#9B~L(!1_J;H Chb`g& delta 131 zcmey)@`q&sQ%$u}B?prLi^P_XhaNsObQ0pYd*=V)qlN+t|Fm43Z6d*_z!()FWXfe+ zT9TQUn5$5nSdf{Tr%+OqSzMA?SemMkQBqP+Y^ASXoSB}Nn4_0pl&#oj!qUWCg^bMH)V##h{9=Wi#QdVv)DnfX()7#{g@U5glFZUvh4iAt)Z~1HlA^@q zlEf0Avc%N9)Wp2WflMOxA?XF4UWJvx**<~pN=F#ESqrkZ58B iNLJ&|kvH>?8yE?4v3!_6sX>5I;^~67TQ3K+HBE=B(fKkYhOFus)GhZP$HAkT! zzo0ZHUm>HUq@dVJU%xmrJufjwFTW^VKP0`t)2pyDINK-CU8#kUOP+ulA>NS0lFa-( z1)tRPRMDbTDPtwh%-qEERQ-aybcYs3k24&Tw=yZah~?(z9~yeGaj|f)NHIixU=#}H3N1=4C`!#p%}XiG zD^Vyc%`7e~O;sq)PtMFNR!GUu$uCkUNG&SK%u7tpOjIbyFDT8)S4c}OD#}#IC@Co@ zw$j%x&P>ls%+bp)O4s-IElA1qit<;==aPm>n_-g|;`K?)FG@`^xedZpNp4+Mc{GIfnzHSl$baeqjoU~>2c|# zr4|)sDkSEVq!uMAWR#Q?6kF-*7iXsDCFbbm7p3cmq!)O46;=jk`vkfxwKH+a6Hp_> z>62fSnp>|>mYO5g!l=ZRnVXoNs-IPmn(i=H-s2r>l#GwNyH=WxZl+$2Zoa*{N}YXF ziFtvCpP_Aut8rEUm%#ZnuZGAtt>vm4pEoSakQ0zN)b=u6iOV%3+1WQWH7g@egV|vA z>@&;18Coy}DReyk&vn^{JF%vC5(EXYjFQz$9QEH23`EKOC&C@Co@w$j%x&P>ls%+bp)O4s-IElA1qit<-_ z!pJ3!M_x$4y+}DRH921)q$n}DB(WsFSZXSx5?5w!VtT56RzYgI!+U0rWz3UjFv-^^ zatYYF^lf(S$vR!TE%j;o-_ue;0=F;C*`hbYH&yRC=d|fwUzba4`TTk+lM+XSufJ1a zu5*e8v%!-~8>YTBv|w^lNJ&aDvP@1gF-omSmRZDx?=BrY7erloTZyODWA&NXaZNC@o1W$;{8oQ~-$=mZmBs<|z~urIus@(<)w_3I5Tq-(^K^e^3okXNP1k7p1hk$S@Q4v#rq~3 Y8wql;e3(C}0qE2>%Wh4ZV4}bX02~iT4gdfE diff --git a/app/src/androidTest/assets/backupTests/chat_item_standard_message_with_link_preview_05.binproto b/app/src/androidTest/assets/backupTests/chat_item_standard_message_with_link_preview_05.binproto index 68be1e7f51d5f26b89478ffc04667c2b52ab08c4..6a829d50da146d187de3af249e702e5cdae72a6e 100644 GIT binary patch delta 318 zcmeyycAIShQ~gaQrE5$aOahD&A9w#b^xedZgNu!WMT?1pF=`)^kRg|TeoAJ(LT+k~ zLP35(X->XEMoCFQv6a4lab|j6Vvb&ZQM!IedV!}`VP$Z(PoTTfBStQH0&0Y~ee;Ww zG8F=f@>w$Tq-rOxWYVtp=Mv~m@SGaEVy0f-rb>CYPjhBVeBJPW3%e4RYeurOZ)$2* zMxF+f!R*;*mVYx0QgFZRa!sgU!5zB~o3@o-dGKz%aUoL|%iE&DC7KV)c3ifXVo=h_ z$j?nJ%2&uqP0!3NEmp|Q&&kOwRw&6YDlARSD^bWvOa_T2Rsd!7iZu>>m~nohnUNqD f%ZK@s8h|14biv!Lmy8q`Awm;-1z04WL4=q9K2Ca| delta 315 zcmcc3_Kj@;Q`8qGrH@P;OahD&J3k(J_|VXcgNu!WMT?1pG3q9hP&ij;QEEX^YDQ{a zN@-q+LSboUabanyLUDd_W@fQMN`6j$kwQUgQAuWAVsd7pLP35(X->XET53^I=41mV z5ng}af|N|JD1W8vj9k)_4Vi?cVIo3&L76G3dBqALiMfTPiMdj}jFX$0wCm%!1a2Fp zcdpyBbz$1VC-?WhVw4gR5Ytr6A&7>HV1WR*DiZYW^ zixo2i`G79N&>7=C= z6=fFXC~rspN*=;ars>xZNlczP99250*Ox+~Rl$rDf_#2b=W zl9`{U;3JWmo?4VDWvs-RnVXoNs$YywyYlq#KCqTp7Vo>?Mgti+j_o0y)eUyzsX@R8SJ3eV)}Ov)UrK)XtdH5dR1 C;ya-L diff --git a/app/src/androidTest/assets/backupTests/chat_item_standard_message_with_link_preview_07.binproto b/app/src/androidTest/assets/backupTests/chat_item_standard_message_with_link_preview_07.binproto index 123920193acf842ad77b30357c47ab78d3713d29..593a9f05c61dad081eab88928b0e1a5a1ee6dbb6 100644 GIT binary patch delta 169 zcmZ3;x}S9cQ~F*;rCp31OahD&pLhQ`^xedZpNp4+MWE;4h5JiPjhHwXqh>P-C33}= zB<2>DCgv(+Wag&kC8p*VE94~R7p10_D5RC9XO<`w6s4AAmgXv?7bT`9=PQ&HB_@|7 zmH?F{rskz4=1mS{5)lYVFYxp#tPIZf33OLd=8~UW$Rw3NAc wdih1^`u@HJDVbhT{z~#((x}o(DDoN%MuJ={ALdVL0J`VRvRl(8m?$s;08SY?M*si- diff --git a/app/src/androidTest/assets/backupTests/chat_item_standard_message_with_link_preview_08.binproto b/app/src/androidTest/assets/backupTests/chat_item_standard_message_with_link_preview_08.binproto index 4b58ecc3a7c86c72f21a45bd4645bbe678862b0c..56a951829e281506e4dc36528cdeaa84f26ef8eb 100644 GIT binary patch delta 324 zcmcc0wwrAMQ~gdRrEN?cOahD&Uv~dF^xedZjf;hY#fTwl0h5p+mwtXqX1+phYK}rd zenDwYzCuPxNkOrdzJ76LdR}6VUVc%!en@(Or&nQRaJEmNyV4OxE_niKgt&e4i;^-G z0*dl8^XjGImAEo<6Vp@mvkFqvv;4UPVp&pTZBiDNo)K$@@D>V k10z8$mJjnMH2}lq>4LXgFBvH?LWCyv3b05#g9tGJ0BMhTBme*a delta 350 zcmdnZc9m@bQ~hNor3*|POahD&dp;g|_|VXcjf;hY#fTwl7n4vpS7=dcK~ZW(YFL26M+W?o`)W}-qtenDwYzCv1RQBkHsMoCFQ zv6a4lab|j6Vvb&ZQM$grZ$V0?SCqff4n{6%hPxl;K` zT$#Cv>8biz1*z#-@mvC_e>c0{G>N|xweft>26l^wLIO2hQX$K`g0p76R-c}~Y3W>v z<6A#GWl`dY@bz~p%ymxDU@&-cX~WdFhE59R$p(priKZrr<`&_Jrp9K8mX@hWM&_30 zW@$-AiKdn*QVdFhr8y-7=C= z6=fFXC~rspN*=;ars>xZNlczP99250*Ox+}FXa>)}=Bg7k$ zSdy8ary%K*nx0yeDrKz1nVFlIo~mDvm+sKQ=y8T)@*E~*IkDXQoSe*Jh0NT7)S{Hk U)Dne)(xTF0jYA)1oS$e00Out{;Q#;t delta 182 zcmcb~dWLlYQ~fDMrQ?hoOahD&dp{m}_|VXcpNp4+Mc~Hb*IU<_S}}1jMy+5JGUYNZ zEy>JF%vC5(EXYjFQz$9QEH23`EKOC&C@Co@w$j%x&P>ls%+bp)O4s-IElA1qit<;= z=aR-FEyU}Sm@iwDnp&dZR+^q!B4w<^nVFlIo~mDvm+tV9*JBFLxYw6><{ui&9fd6w*r5GfNZ-ic(85OLG;{ixN|l^A$>p5|c|3 zOMuD}Q}a?2^Ckx{i3o0t5BAjBh|vF z#Fd$wn4YSiRgjwQFjwB=9cz?~kGs28nvQO!UXE_Qy}L@CeN>5gfrp==ZHcRKRsfg4 z`82PF$T+R#svDm-EX$A+kT}%#GF^$wH6z*CH#IdYBTs|bVD{`Y%fA^~Fa;@eJpNSg zrMSFRFtB;z@1vV?x4FHz!xbzu`Oxnhi{#l=O|D8YC&VeqJijm&wWbxw-i%iAAXj1*thXsd*)-#Xw~W1*JJyODWA&NXaZNC@o1W$;{8oQ~-$=mZmBs<|z~urIus@FASJyk!e zAT{0LJ+sF$=EERyIYoon;K`*8Q{Ng|FgYotB&8TxCMTH~rCM5;q?nl+rKXr0 zSX!D{nwuo1nI@V`F(^r<klnL~GdR}I6ab~Wl27{3x7t4qFlNx|w N_h#9xX%kEo7yL26M+W?o`)W}-qtenDwYzCv1RQBkHsMoCFQ zv6a4lab|j6Vvb&ZQM$grZ$V0?SCqd}B$qT)S{<9bl(7#Z?dtGAQ#Jr`I8!ePJXlO*0c#G3XBk;iM;|W5^o_wOaR@*P^JI? diff --git a/app/src/androidTest/assets/backupTests/chat_item_standard_message_with_link_preview_12.binproto b/app/src/androidTest/assets/backupTests/chat_item_standard_message_with_link_preview_12.binproto index b2856d6666b058024cda6fa09b9bcda39f5d5b51..020f82b5f6b683c89b27e43489cea9e622c372e6 100644 GIT binary patch delta 282 zcmdnYww-MOQ~g#ZrA7=C= z6=fFXC~rspN*=;ars>xZNlczP99250*Ox+^_m_4+nd%Da78hW}gGmAG6plAV21 zQ?oMiG?)x#&pxyKn_-ZG`)!wNLIn%%*nQZvt^CS^ck7J{nYvis78Nehd{DOIvb_|8 zl1@f`Zfa4!LQZOWW^QS*LT-LePG+$}Nq$jbX=+}HLQY~bNHnnmD9cf-ap=R0^ApVg DBHL|_ delta 277 zcmdnawwY}KQ~gFJrFBdkOahD&2R_7gN0^j2B7FUw3Ui%PG?)yYT-q@8t)Y{Gp_!4Tk*S%b zL5i_qqD4}oVWN3bszs8qg^@vGlBKbk6oZmrX%5g2$*IK(rA2v(3VHc?8ov+hYxrjj E0CcrubpQYW diff --git a/app/src/androidTest/assets/backupTests/chat_item_standard_message_with_link_preview_13.binproto b/app/src/androidTest/assets/backupTests/chat_item_standard_message_with_link_preview_13.binproto index b5266b2f358e982abd749e83f908c2848e4a903e..8e9929e92bde20ed04439e4bd0d18ce67f184e51 100644 GIT binary patch delta 261 zcmaFMI-6|)Q~gXPrD;qYOahD&KX?B*^xedZpNp4+MWE;4h5JiPy_h%{qrNi=C33}= zB<2>DCgv(+Wag&kC8p*VE94~R7p10_D5RC9XO<`w6s4AAmgXv?7bT`9=PQ&HB_@|7 zmH?F{rskz4<|$;9loS+O>FXC~rspN*=;ars>xZNlc=~!3Rt9JL1iCBLbIIdS15+Zz z8K>(d2qw_Y+*U<3ed8eES6 delta 215 zcmbQu_Lg-4Q~hg3r5B7GOahD&2R|Nq_|VXcpNp4+MPU8hQ%hGHdNFY@MxA67^5AkS zEKN);O3h0t%~eRrEG{T5Ni50C&&yN*i5HfpDkSD96cnYFWCGSFGfSk5l{hnV6Vp@m3-Zz( qKJt1@;hB7fNm-h;D6_bq@qm43S5?bb_13XBl3iM;|W63-w)OaPf*Hl+Xn delta 197 zcmbQmx|ekUQ~hp6r5%hMOahD&hdv&9_|VXcgNu!W#fyo9DQW?uP&ij;QEEX^YDQ{a zN@-q+LSboUabanyLUDd_W@fQMN`6j$kwQUgQAuWAVsd7pLP35(X->XET53^Irb0$Z zNkOrdzJ76LdR}6VUVc%!zQ1olN~TwozmhzcG+5dWySxU2ksue#hxwBlfDU`J?AEji SCJKxYp^3c$ED~=aLQDYKCPWhe diff --git a/app/src/androidTest/assets/backupTests/chat_item_standard_message_with_quote_00.binproto b/app/src/androidTest/assets/backupTests/chat_item_standard_message_with_quote_00.binproto index 9c25c3e8d6c35810490ef966d00ba73539325543..7bc1c0cbdaf50ea0726b40e6632837e8935d6083 100644 GIT binary patch delta 85 zcmV-b0IL6!1?~i}Ap%WIB1#AX5Cj;M?tr`5GeQsuuF;(B^Dq#hz?qDaF(3h2D+&|{ r0T2Wl32TbYXO5Aa8AHbaY{DfZ-X| delta 122 zcmV-=0EPeV1d|1@Ap&x7B5w!+5CjF+vgu-OT^P#W4_}{Dje)G#CLO0a{K9 z6bJzj1R4wq3NSG;Gc+|eH#j*c0TMO}G+}gaZEtdQZ6Ix7Wn*P-VRImJb#r5BaA{#~ cbaiqdY-wk8Y+)c{Z*6UFWN#p3X=8P6biHCJ8vpfQs2VJh2#RMGOi+I7dgBY_qfRtCF7IklVKK?pJ?gl8E#+h=cb#V z@1tuS?igW_UzueGboI}r%l>HSeM`{Jz5YL0t4iYU;qL5ioT$-zpl30+LR0w_N>iq`(LOa}1On delta 338 zcmX@c-p{^(NqjA%(key{CIJ=+Mkh87Mgc|%#;BQ$LX&qesn$ysa^)&HOtF0wVJx=dSjj)5XP~IC;ze->MRmetnw9q{Nn9 z;OSLZsli}yt>ed&&xTG4h9;J2rk0i|iAg4DmdO^028jk~W`>r=KyF%El98ztg9PI} zMy1;j=R7Env@xr39?fi zeh7G+Vv3USN%P4t3(HTm^z#h2FZXlP&CmDIwGMZTu*k2>Vvu6cU=%XpGRiMXEXmAQ z$V)9OO;t!qP0lY$RVdFa&QvH$P0!5F1BzuP=PTqUmKJ3eDrEC5h9HHh8@^dz zIU(WM*2XD*HB|C%^vR}Qb}852t(a~;3$CxK7&}%1K<8 zYGmZ9hq)*{GtG*%#5E(?+2NA3#}oD-_Oy_6xBP6MC>bAjcdg0inI%DPFf*#FxVE4F zx7@LE_O;HRE=t@x^JFfg5_@T>tDAGKvj(%lo$oh(d^C&_SS8D5)4R3I_*Y2tXZeaG z9VrH>Hb$-jCCc5J-{YxJ5Qk50iBCm}cR&`ZhnL zZgX9&8*VA_X=PI7ED13KATsq znQj{t`yl1k;cGEFD>`n8o_Ztj_ePqBhi$1)VTTlh2BS~_mtR_HPG+$}abiwsNn%N9 zu|i6IPJU6ULP=3#GEgADSRu76wWuVsq_jvOCAB2AsHilvxHz>$p|sel6eyCDnhesF qo1c?fT#}iXY9z?T@?rj@2B6<>>~6XG-$;QGA~dlVn3iusgqQ#sGzy^r delta 520 zcmZ3=^^ao#llT)RrH4!$Oad$tj81GEi~@`jj8PYugeLQ|NXkhCaoH(xX67cQr|K8v zrCYJPIp;bT2KqTn;__H0H94C}(V0PtK}q2HSI;fm#GM*CwY6^8DBoHqwU&`<1tUyn zdS;pxd$@a%V^xud!*vdi({e#Pg}Kftk>Qn*0eRVplYLp_>*KftrtKFzBkGEQr`#QyDfa+KK83p~9FD>ax6u66u)^4ZXW$w|S) zEXmZ;#LUn***wW8EiExQ&CJXs(Zayg(lpg5G0|L#L4r}rfJ;V+GqE%!GhaWqz}VrY zu*Ws#AXZN&59cW3EUX@x#-ubE6gZ3$j}FXT`q9vfjf;hYMT#NnFC*8P$($?-YAYGJ zxF7+PRgju4HH(pJDx(sTh{Fwj%}e$u>m6NLn>Y`mVF zeLH-u!77^oj*RP%C8mGccAr&=!`m%ADciXy7wF5Svo>FT3HD`*Ns?iTxtXz9Qc9Ak zd18vOL1LnDvZ;ZAg_%W)d8#qUml}*hKu4CP7UdfWa2ZtXDqD5 diff --git a/app/src/androidTest/assets/backupTests/chat_item_standard_message_with_quote_03.binproto b/app/src/androidTest/assets/backupTests/chat_item_standard_message_with_quote_03.binproto index 99aac1c8304ad4e2e7bd52fabe6b8e01373d6a5f..92ef5c7354d22d79676a216d3b4af92d5eff3864 100644 GIT binary patch delta 283 zcmdnNww7%HQ+={hA_tQIiv*(+8waBRqXc7App-wCrxIskX-a0ker|zrmKB$PdTjx_ zP4(-;p3~~O-$`}tm6*8k{amIX1(U4VwrAL{Z5EVCaq;Z*jwskVuYqAs%VoRNR}oSi zx@}SnAR~`6Dji`2+QKL?{awTEo5o)JT)Z4C0*`wR95Y>Epv1(%7`2pb_9gLIjFv&;RaS5cl&zh*B(E8`tS&38Txolq~ zK3-b%n^B1~%&*G5s3apJQ-i_a{@HuGUmHdVbQfL=R(iUzL_Au4o#3KIFDV8IMh!+G YVJ^Y4(wu_QlEji!h5X#il9I$+0Q=ov2LJ#7 delta 321 zcmZ3>wu5Z}Q+*GkQYRw^lK_hZqZ1nkqX44>V^pP7Iai?)XJTneX1;!IfpJz6mq3o# zJI{z^5*nu0%O380zammdz%f$&=}XpSF&`h_u?R`7O_W$Z_sU&HC2r5C{OkzFlE}26 zEDZ*OLkG_+e{bldU}9)$X=I*inrdlanrLR4oMxD6oRVx@Z((X;W^A5fW+=q~vU>%i z(o&Ff7$qJbn7j0&p%*_FF9(ajjm59Gt}|6);$VzwW90Gyx|2o8g^MdQH!(d`KdT@$ zUCNBhL-q@Q7B5rC&kl0!rsr-GSVcZt{^BND9hC_!ZOV?tEj{*i$RLPN`p}d zs5P-9KR3UqG*=-vF*P|gFR@smxU@Jqvmi4uucWj{Aty7vG$&CZIX^cyKP6uwB{R7+ GuLJ-w-evLt diff --git a/app/src/androidTest/assets/backupTests/chat_item_standard_message_with_quote_04.binproto b/app/src/androidTest/assets/backupTests/chat_item_standard_message_with_quote_04.binproto index 998f9e9a9525059a15682c584449fc05769a44db..a08966a22d85d4121a1b144ff2ff7fc525cc45ee 100644 GIT binary patch delta 141 zcmaFG+Q_!Sl}T|IqtbRp4kiIci5c%2cHcDi;^pGzU=ip!c;WsMQzeF|S(DS4Y~sDS zJd08biZXLE3rkZK5>xVXQj3#Q^NNAYjM8L<x%%Hofe`?<#WSJ+ delta 118 zcmZorf25o0mU+t^A&OvON%m#6_QJf5>t%? VxmZ5TpVR;}`}T+blUt1y7y&KLDRKY+ diff --git a/app/src/androidTest/assets/backupTests/chat_item_standard_message_with_quote_05.binproto b/app/src/androidTest/assets/backupTests/chat_item_standard_message_with_quote_05.binproto index 5a26cdcf8ccd5212cb8c7c0e55ed16b651899c7f..74181c146dbfbab2aeaacf38436a4ade0ef68393 100644 GIT binary patch delta 398 zcmbQw-p;XrNqiBb(tJh^CIJ=+Mkh87Mgc|%#;86;T%Pe1S$0eZlWzOrFfeE`9 z?-(^rspOH9SpD+v|5FsW2#G8(c delta 278 zcmZqYn9sg|N&G0I(ji6;CIJ=+Mkh87Mgc|%#;A>qLX%H2+15)Ha^)&HOtF0wVJx=dSjj)5XP~IC;ze->MRmetnw9q{Nn9 z;OSLZsli}yt>ed&&xTG4h9;J2rk0i|iAg4DmdO^028jk~W`>r=KyF%El98ztg9PI> zMy1Oj=P*h=H=|@8^4lXth7A+;-!M4n&9v01SIq Ap8x;= diff --git a/app/src/androidTest/assets/backupTests/chat_item_standard_message_with_quote_06.binproto b/app/src/androidTest/assets/backupTests/chat_item_standard_message_with_quote_06.binproto index 653c24360fb0198649a95d2e20cf41d0c6352ab2..0e1cf09ce448e55f6df0c8975acfb41048f8b891 100644 GIT binary patch delta 84 zcmbQr`iW(O8k3K=k|zg~0HegLcMZF58hi0_adWT;JnlJgY=waqLzFI;7zd*OixeLh oPe5u(YLP-fVo`Q#kp`oXFqdFiX-+|DNn%N=LVj*$Nl9WZ00fN~;Q#;t delta 119 zcmeywGL?0M8dH9rQVs``0HegS19O*tH1y)-;^trxxUu;4)^(;@3{e4GVjPSDEK+=2 zJOQaCsYMC_iAC9|MH-AkW?UwTCHcAeMWwk4xrwRCsd7_Y|3d#Aox%nyi3MrY%rFkU)#)v0~ diff --git a/app/src/androidTest/assets/backupTests/chat_item_standard_message_with_quote_07.binproto b/app/src/androidTest/assets/backupTests/chat_item_standard_message_with_quote_07.binproto index 4bc6c59b1b2927b6e863743f4b5749da0cddd75c..85b709cbd4d43bce0df36fc368c11a18f33ff5a2 100644 GIT binary patch delta 433 zcmeyzwu5~EQ~e@FrTL5;Oad$tj81GEi~@`jj9Gn*T-}UZ0{bs{3P?|GxV6>5)IQ23 ze2I|4md|~{3{zIWx#3p%q244#ubtj9k5pKsVL2S<|NKKb2<0?`@;yb(*_qfRtCF7IklVKK?pEy~X zS+w4cOCaIr(q(@%^u8r%=U)GxtW_oPck$USCMC`=zbf~ll8lT@4JL#8XYcKP4Rqgo zs}w_1lW*A*zOSwN^S&}$ia~-=gHgzv%d;r8peQppv#>N(Au%OCC$%^^HLn=R%qUG( zNY2kIF3Bt@Ey-8N$ShXKEiFkbQOGPPF3nX_NJ%WnOezHmCT6A<1I06ojRd*CVF~o| NjomF*{~IYV0szZsp%efB delta 392 zcmdnN{*P?|Q~g0krG1PXOad$tj81GEi~@`jj9F_LxmGc93AFp0JbCdl=0@hSkC_*_ zTD64~F8)2yCF)zgL&B|)Db&PVe!-46ha=qNWom!xO{#ACRiVW4Vg95Btvn^p%-qEE zRQ-ay^sIO;fr%+B4$8mFVwo-7{Q$*8mq<$i9u`T0J&*5Qs37WtJ~3{ngl zj6x<{M)^gFC7JmOd8vh^sR}8n$@xX83gwx_nF>Xz>6!U?K(Wl^e1+V^(xS{_h2+wr X#8e|eE^r6|U3&Y&|H-Y!3XF^Z0;+|( diff --git a/app/src/androidTest/assets/backupTests/chat_item_standard_message_with_quote_08.binproto b/app/src/androidTest/assets/backupTests/chat_item_standard_message_with_quote_08.binproto index 918e388011f936263fefd414ac4a6b4f8c3f3807..f42379c44239e27c912dc4b8cecc52a8cad2e5c5 100644 GIT binary patch delta 453 zcmaFEc9nerQ~ef3rHzanOad$tj81GEi~@`jj9Cj9x#lu*32Zr3Dxv)Np7M#th7-%r zmIMhYB+0ZsOcRxwt&-gEq38PgnKCXb1LRn`Kj~Dh4RZOkHbIHy!~BW8T8TE7uD#l@}_DVf=6sSd08Jl=_9*>DMX1hb z%z4+a`=+rM8y5=)ixERq3lmo-BhVi#N)3!$P-kQnq^3(1aTUOv1>!s074%pt5;b`T zlUzN}F?F}LPjY_8^=rC6|HN6@XBZ_`zx;oU)q*KV!DsWTHPdZ_Vjra3I(#i=XGO;? z(Nk{({@zIQ@USfvD(sMA&|nk_;POjL&B-iQC{D~NElDgXEmla$&&e-JRVXP+Oa=<% z7b~Qer52TBmXsDLq@$X_QjHXaUL2Ua^rNAd1sfL&2a6Fy)MG}jO^iSn zuqdr$wj%}e$u>m z6NLn>Y`mVFeLH-u!77^oj*RP%C8mGccAr&=!`m%ADciXySA*GL>8#C{Um994IVq%= zBpIfdn;DxWr6ie}C#D!1Bqkasn;IBcm|3Klry5H!NHA(J3ISbNmRgi=B*+Ey<)j9n b`)_~vKUuuhSb-5DHnA5NhIfEsKp`doxtw-~ diff --git a/app/src/androidTest/assets/backupTests/chat_item_standard_message_with_quote_09.binproto b/app/src/androidTest/assets/backupTests/chat_item_standard_message_with_quote_09.binproto index c7a2729eebe61e02896b823a66feb1e7c328078e..93cb1488a01c4cb43c7656419d067f31c5264a3c 100644 GIT binary patch delta 389 zcmeyz_J?f&Q~hQ}r45W6Oad$tj81GEi~@`jj9K#;x#lo(2}GxEn&}&SoH<47@8TcF zj@}efkkrsoSQy^1Up8w&*{$R5A6?c-TU|+VOL?`xtLI(*vX@FMALdW&(@Id{%FInn zPt`9^O)9YB$Z`xwk19wEa+u8K@th~iflFZ9`#mdP9dQZSvAF*Cg|yQ#(GrukoIb^- z#2w|H<{w-Z6y)bptif!s?Z@TiuMDFEQvLd;aQ}EwUgvb{kc69|mlVTMMx{d_S2Ie? zeb=!2rm+_<7dHosz~i0+$5t3vF+?q8&Dn5=@-bg43~BADYqe22Pg z;vPE~qhx$iJpCi={ah_0O+xAlf&zlFTn!^E(@e99O3bqCxCBz&XH8U5X#I2Sti&nv zT(&O~A1^KX&8Wl~=2zujRFaXAsli}y|LncpuYu0(F1!}3^mJp1c(nXF!9|Tg=SnbY bFbWBC36_=S6qJ@EmZU1==Vq3aB<2DDZJvitq)ObPs<^TbYgU3KVIUU)s~U#Ha^`T6fpvna8Am_M;kt6qsKGdD3k zRlhtnslbZ8urSdppdi#i*`rM=E0Ie;Sadme#viAU`J3-F*W2}3JrEL@yJGwLqq$q= z${7Bc+5heJc8M>ymv3fM;s`5B&(A0c4$@#Y__pq9+Xq7nCMN~Ulthap^Tf1dQ?ryL z6U!9CWMjj$WJ^nnv^2BSq$G1Gh82uTOF^Dulz4ey?$VEjUi@6V94rDi7Qf!Q&eV#D zgE6X&k;@0@Tb6ny7cQt{vkFqvrOdcYV2%gz9U4SEE(%4-_@sFHN7(zhT1J|L)D;8; z1ZBAzMp&kqW)+o~Wid!GXfO%^btabN=jIoc<|^bSrY5K6B^E0bmlh{y7Gx&om6R4K bXcwTZ=&1p1J1BRXbo@2F}k126{m_M=i!~FhzT7gQO znYoGSsrm(Z=?DN`UoYwS+8|utzT?}aj7gCK67?O6XMSe1U=C7{YnpC; zeu~uLcg8&tE|;fTa$H_4YH??_SEyW{MsgOPvJ^urlTs5C(5Z|P^WHV=zG>{m&&A8Z zBG7a2!u=(tR!kg>QI8q98W@3|U{R{z;(}P8Rgju4mBp2zgv5`M@$m}MF*8fmtDC%^ zNu=J2OQ1-otW~%9_$0U6orUUVzvfH)U3|8SDM%rd&sfOmZjHh378O2&_SJLbJT80s zFy5WH?6}7q?J2+cr5H3Ag}k{ui&6`UGIKKvOH&mRQ}T0Ci<49Hih<0G(qx6?{Ji3l z%#zZQe1(k6Vujq&lEe~)%!1<5T!oaxg3Kg^QlMaBW@<4|JhRwHkc;KR{7DT!Z{FD5 Ka`nHF0wVyU#+dW~ delta 357 zcmV-r0h<1?2Z9Hn0)J^DX9xli1Q-EA1_%KV0T=;lR|-`M5F~*%%PWT6J65F8b|?R) z+Y%s3sYteYd#Bz2=Jegjqsn3zA6*ubs-Jt1&tNTJ`}7 zssRWA5CkHj0SXFfZDD6+FKTdQXBv_L3XK7i=K?E#UkVVU8mfe{`lVdpY_IqkyK|Ki z5M7xY1hm`*8=j);4j)$+R~XX7tnvXO2unt1VrxTkZ72dTrJA$T=`lheHDozCF=8+@ zVl-r9Ff}n^Ib~roWnwU8F=jP4F*h|g8UPppC;<{Q3NmkUVRUJ4AZ}%Gb!8xAWn*u0 zWgvGjX>(~Ha%E>}Z*FBEWNBk>AZ=lFa%poQV|8+2Wik;81n{4dfDi!~+wlLBg)<-l Db_{&~ diff --git a/app/src/androidTest/assets/backupTests/chat_item_standard_message_with_quote_11.binproto b/app/src/androidTest/assets/backupTests/chat_item_standard_message_with_quote_11.binproto index 006e204e7cac2ae609e7061108aa003e21218f01..a9d4a9500ec5c92f24f47d0262581633a170377a 100644 GIT binary patch delta 457 zcmaFBc8+}kQ~gRtrDcp9Oad$tj81GEi~@`jj9F6|xh64k3H(Y`?(C>-Xkm>luj`AR z?jWR4Z>jGk&U0$j>nD;vc~jcEBBq!{Em|^Fn{T`D^UYyz-zsr`m_KplqlVrO^C#`r z@>k-_%uP&B)i20P&vM`rV6x0OlV9t~8yQHeXsJBr30!2oCgl{9^&vF;w#P#2T45=Mg-lBGn1F6&l$ignVfRgAFE%a~ z4i+bds17EsUPhqfS(I8Bxws&fW)-BSOOtl3J2lR8*Q-T%2lGqEK2~3KYpnO$O=8&Cf|KF3C(xH4@}v d0fuA)(8D)&w_N>iq`(Lfn%E1BubU7dCIG70sQdr` delta 361 zcmX@d{(x-(Q~e1>rK5}-Oad$tj81GEi~@`jj9FV4xi&I#30x89-&=C=kdScArN2r^ zyxKwvp4)$TwO`uPp?ohnfJv#O@KgI8@$TxiU+;fUb&Hwn|6Gat!~BUWA2sxTm_KQ^ zR-O`PW^Q77s(wLUdR9D_z{C_52j$;ovCNikf82J&9~2Upv9129Qp2jL(gji8#)6^8 zXG^^Pv;G>B5=U53dVWSpaF7Or!MAl++dddNDOg%0nWdN-8Ce)4CR&;rCYc+UCYmG} z8ygy$nkJiDCP^_&VN{w3@(QEG>jQI_el+xA<6_}pabk$7;qn3cj77~k5f!hGCrQZR<%J+7WTSvK6)u8vHp5_+1~L*rJnZrDOn6s3>u6= nK!eLti}H;GxmbWcZ2;PM`@{dqt;PzB5TS{^!0@~S5n=)W3p{+y diff --git a/app/src/androidTest/assets/backupTests/chat_item_standard_message_with_quote_12.binproto b/app/src/androidTest/assets/backupTests/chat_item_standard_message_with_quote_12.binproto index 827eafd581fd78772ba0012048e7d97d326338fa..8a3f8ae4a0c704bc068ad1b7eefe5335eea0b976 100644 GIT binary patch delta 401 zcmX@YzL0%`G*kU4eZ?N`a@aymzip$(RC^BDboeQ>LPAumgQ&W?V0)9uS|HvsZq5N~yw2p;= z-*OGtEe%d!F7EN=_~EGho4>jLeCFpezF(#ck}KSghE29ReYCv!4R=nCQ?tth?)ohU z*Ts4Eb3)z0zzAj7&0*bgz9QnYa#obrt))Ky1sJWBEIF727$p|GYuJ6$*o&8on}bE* sanFHcD-66CqGY+)I2Z+3G?;{hxdh8fa|%jJ5=%H!74ma4OG*-R0mciZasU7T delta 436 zcmV;l0Zaa&2gC=k8v=i9-oqN5tX+3TBx++7@r?0h(+PQ^-|0OZ=sqOzlUH|?2!we` z!?eWL*PYr=yi^5o^*z!*PRWl@>s}v)ehEJgfq?O}J$91=EZjd+>Ye{)^3+{4=!LYk z%UzKj96u*K13v;3pI0&yJo8aJ*gs|4^1o%yAC)tt`(6}ljguSO z?P#^r&dgN`o&eWQNrZv4>^fg|fB*mh00000Teq+su&#f$)MH$DkYWO$|qS zQUht?x`R9h7lcpW;(cD>!rL=1HQu%31Lp0VofZ;>QZwKw>-!%KN?zDh2LXg%14-Rz z0X?roFCtOmhgyGjg|XddF-i>z z3kU=d*rV&Ut~E*kT0ja02mufTC;}2T3N&GKZ*6aKb!{vlZDD0&Wo}_}AaiwdV`*?{ eVQzGFav*GJXLW30AY*TBZEs|6AY^G{b#8P&A+{3$ diff --git a/app/src/androidTest/assets/backupTests/chat_item_standard_message_with_quote_13.binproto b/app/src/androidTest/assets/backupTests/chat_item_standard_message_with_quote_13.binproto index b1e61d43af66843d17ce1b361f72f3cae734ae45..d9c82f37c1bb7e7b1ec91c014238d2c09c9e41f6 100644 GIT binary patch delta 148 zcmZo;ozJ>KgsHxhQK^lQgGqo1snSCJx4^KrS{8MgbNL zW+4+Uqx_=8lFWRCywt+dRE3n(slg}|z~z^gnv+?qP@I@kT9Q~&TC9+gpOasds!&ptm<$xiFIGq`OD!tN zEGaEgNJ%Y8Eh;L_EG|whQ7A1g1q$S(CWAEP=I7|77MElurWy%yv3!_6sR8JW8@pSs U{x?!!ga}RS6=0FL2@zrf0OD;segFUf delta 84 zcmX@Z`k!TkB9m0CQZxsX0Hega19O*tH1y)&V&h=(V&Y(ma+z$$B(BTG#Zs19ly4-+ g#qwePqz0hE+aLZzBFIz%fD)2(Hnb?ej1Yp}?7pk})6wYKj30 zhXD!@U@GRwi~qZ5c-hTVLrcnX5+Hmrf|9*%bN`Sc#`7`L*^_5@NO l-M)Y1W&N{7*)(6=TCvY^um?EdCGT@^dN409@e>W~0m-5)^ zU@GRw7ziQ+@Sl=^Dr+JMX>DO=WiN1UXKGvu5PUI$lD%$o|5T77#`zut zGr~j+I_54)TA;fa=d{v*1tJAdZfjvzC;~9ng_V@n>1>73StTn z=vD;e<7W?d>-Fa$6rWk05+Di>VUx7~`z2U;l|ChUxkpE}YUO`7E*qEf*y>;^=ExWp zA_VZCk&P-OA_{43VP|D8VQ_9|It+1bLu6T3d09|yYhggs9U4gS4Qc=y01^=j1n{4d PfDi!~+QNv|%rYPWX`Mki diff --git a/app/src/androidTest/assets/backupTests/chat_item_sticker_message_02.binproto b/app/src/androidTest/assets/backupTests/chat_item_sticker_message_02.binproto index abc7f3bb821c886102ea089872440864911adb6a..b95e90add5f83698eb60060fe4fede8f4540af9c 100644 GIT binary patch delta 230 zcmey%dXIGhQ~e!ArJIZ#OahD&Z>R6Pa=_4wjf;hYMT#NoFeBG2MlOK_t!F2?|L@MI zxOq0j+51$HkV1`N)1OCap{;9I$2?jlBlu;h^@(Z$Go!kSYy0_s%N;9cmtqhSS9Q~hs7r5}tOOahD&8!pay``N&Yjf;hYMT#No5hK@5MlOLDVJuG`r}LM; z{`y=|WPapaAq6h}#K~L!|5lBtoNA|9wbR{wYu3|xb3N(lpKiQL(0X=4LRyLC!~BVT zTGdKinYoGSsru!qNd;D{o=zUlQ4aH&J>D~C#c>Ht_xiegNn~9rm+FM~7kgCZ-4+sP zKKYXQ&y6WYKjv?IwY)8Cs>Hw6pEFpMSe*mIOG`DF4fbE3`1OUM1(TD4g>kZFs-=N( zT5^horHQdonuTRrl3{9MqPc~cshOpz6oZf;7tj@x8h{?Vb*SUo86yQoh|t7d0Tzkd H5FsW2HDG1l diff --git a/app/src/androidTest/assets/backupTests/chat_item_sticker_message_03.binproto b/app/src/androidTest/assets/backupTests/chat_item_sticker_message_03.binproto index 47beb147d36e56e56d600d5e01cce201d4ef99a6..0d9528549ec3193b6fc1f125ac102cf111c2d87a 100644 GIT binary patch delta 192 zcmV;x06+iw1h@sD0)MsvBC`Pq0uTWh?w7gLz%fb>3JnMZ5aW!%#;7nN0tf+WlmQBn z0SXXcD(1+G|GQ{-+09f#OUiN*Abc@`lD%$o|Bxca`fskg6R>A7$QTGB j2=Jegjqsn3zA67`L*^ z_5@NO-M)Y1W&N{7*)(6=TCvY^um?EdCGT@^dR_0BXho3a|kR z5a?C}kRrzVZ?3x)5)jp0 znfCZ`_=B39;@Hz@S-BYI&9sRGA_YTHS9NtL05HGTk@e^?LLg){HDozCW;SLxH!)^7 qI5Rn6Ib&rqWH@9qHaImoVmTTB5)ldn@Sl=^5CIt4!id()G9Uq%B4acF diff --git a/app/src/androidTest/assets/backupTests/chat_item_sticker_message_05.binproto b/app/src/androidTest/assets/backupTests/chat_item_sticker_message_05.binproto index 31c8d75c53365e3bcb3e1303a13aa85fa6c5ac64..8d4d29498e1972f823f89758a4935e766fc458f7 100644 GIT binary patch delta 232 zcmZ3^`hax-Q~fs1lLV{di$BDw(x0uTWh@t3*Oz%fb<3JVAX5aW!%#;7nV0BW593Yq~5 z5MV0i$cz8GXn5JpR6|S3auOhXF@lo4Zgc;TBF6e}uDcakV?AlrU77ayarlFpoZ{FR z8zKbopOK9!Tp|i-ZDD6+FLz~Pa5@NQMsI6ONK9=&kPAre7(i+~3J|Dg=(JRILs`@_ zdOXDNhgTTKweaNxI08~2gDA052NJcdt6buy91--TJIH$wHZp#A*1r$?9>#YE8UQU& BQ@#KI delta 230 zcmVOaq0)N~ABG~~50uTWhw9%aH^Ds&c3JVAX5ZI&ZwXQWP0BXDe3b_Fa z5a?C}ZgWQl^Fho`IrSF1w&C+b#*8MFu&K4_2@A;0zx1-Gh;br gIWRM3V`MlvG&3@0I5}owF=b(4H#jymHaRsK01U%h00000 diff --git a/app/src/androidTest/assets/backupTests/chat_item_sticker_message_07.binproto b/app/src/androidTest/assets/backupTests/chat_item_sticker_message_07.binproto index 507664766c0578b12298769824968586c84c0ebe..df8edc1d11e7b606e833905576bd87960d4f26c7 100644 GIT binary patch delta 207 zcmV;=05JcH1;+)T0)NE;BEkU(0uTWh@|U^Pz%fb>3JnMZ5RAdl-=sA%0tf+WqX7zy z0SXXcD(1+G|GQ{-+09f#OUiN*Abc@`lD%$o|Bxca`fskg6SA0tf+WXbMvb z5a?C}9FhxrqG zKg{pnr{$@{nVFlIo~mDvm!4(CCGbSk@zKLCQPcML6sfOe7ibHR*uLrXH& zr2gIPdebESPSnQpMH|>H9;&`CE~w#>3R&J2oF&B|B*?|`Vg95Bpi}#QAMN{WqQD3d On%FDAA~69X!~_7>6I|^8 delta 249 zcmX@l`jK@3Q~i5Jr8kTmOahD&+b+&|``N&Yjf;hY#fTy68Y9Px# diff --git a/app/src/androidTest/assets/backupTests/chat_item_sticker_message_09.binproto b/app/src/androidTest/assets/backupTests/chat_item_sticker_message_09.binproto index e9be214aa8ce3964502f8cbd1dbba8dce2be1b24..76b0805f92c8ab2b05363cd6e37c94757b03f742 100644 GIT binary patch delta 206 zcmV;<05SiL1;z!S0)NB-BEbO&0uTWh^q0BRz%fb<3JVAX5aW!%#;7nl0BWQG3ZVfC z5MV0i$cz8GXn5JpR6|S3auOhXF@lo4Zgc;TBF6e}uDcakV?AlrU77ayarlFpoZ{FR z8zKwvpOLBJfQ|5zutGr~j+I_54)TA;fa=d{v*1tJAdZfjvzC;~9ng_V@3JnMZ5RAdl-=sA<0tf+WumK91 z0SXXcD(1+G|GQ{-+09f#OUiN*Abc@`lD%$o|Bxca`fskg6SI0BX+x3b_Fa z5a?C}ZgWQl^Fho`IrSF1w&C+b#*8MFu&K4_2@A;0zx1-Gh;br zIWRM3V`MlvG&3@0I5}owF=b(4H#jymHaRsK01^=j1n{4dfDi!~+QNv|%rYPWELUPT diff --git a/app/src/androidTest/assets/backupTests/chat_item_sticker_message_11.binproto b/app/src/androidTest/assets/backupTests/chat_item_sticker_message_11.binproto index d9160805b89bc1ca2a1344dda50df9e474d80c1b..b575a6bba106986d584bca0a39c03ca2ab657065 100644 GIT binary patch delta 217 zcmbQrdXaSjQ~h~Hr8A5iOahD&-=^=pa=_4wjf;hY#fc$n8zWaQBbPve*0U4c|959p z+&mlN?0u?8NTJ5CY0}=j;{Owrj{VACw_7wa**5cP?96XJ3V$@un)B#}gs>9JhxrqG zwfvPhGjkKuQ}qk-(jEQ^drTF~vf>gbi8~tcwda&*?DrXR0**oQc@o<XdheQ36^mv(1=oL*FT_ZRotQS&mzZK}e7bX!4{6pkw=gAMN{WqQD3d On%FDAA~69X!~_6eBv)Sm delta 157 zcmcb}I+b++Q~hK{r3s82OahD&J1@?8``N&Yjf;hY#fc%Snk$$~;6)hAlgH`&<*&a! zR}`5aIaf%5i$8JlmjAz1BPyrbsaEZDci)=zwBB4#ditjuuM)JLosf`LV)-zCVy~8{ z5@%*^VtT56L0-DUFKbT>bQ1B%t(O|A~vyCfJNdqNX$rq F2><~zI}rc? diff --git a/app/src/androidTest/assets/backupTests/chat_item_sticker_message_12.binproto b/app/src/androidTest/assets/backupTests/chat_item_sticker_message_12.binproto index 0e0f36c7a94fe4977c0efb822af2d248ee1aabfb..246421dbb64c43e4fa8885407ae860b326f24fa2 100644 GIT binary patch delta 180 zcmV;l089VQ1*`?20)MIjBBuce0uTWh_m{cUz%fb<3JVAX5aW!%#;7n#0BVW>3Wos- z5MV0i$cz8GXn5JpR6|S3auOhXF@lo4Zgc;TBF6e}uDcakV?AlrU77ayarlFpoZ{FR z8zKbopOKC#Ng@epZDD6+FK}*WYB~xK4^=kRrzVZ%?kf6%r8DU77ayarlFp zoZ{HiXj!=!=FPN;1R@1PQCD?!C;%|O*OB$;F+w0@H8o^8Ic7FyI5#n7I5;yoVL4-E QGGsVpGd4IiIbt~)023)!82|tP diff --git a/app/src/androidTest/assets/backupTests/chat_item_sticker_message_13.binproto b/app/src/androidTest/assets/backupTests/chat_item_sticker_message_13.binproto index 81378115f20276cbd9e92fde947d17b95980ed1e..b59484f06cf578e44808d4a840a8a5420ccded74 100644 GIT binary patch delta 224 zcmV<603ZLJ1=t0k0)N&4BGUl~0uTWh_?NlVz%fb>3JnMZ5RAdl-=sB40tf+Wv;hj9 z0SXXcD(1+G|GQ{-+09f#OUiN*Abc@`lD%$o|Bxca`fskg6SY0tf+WdkSU> z5a?C}>0m}tIEdT%j diff --git a/app/src/androidTest/assets/backupTests/chat_item_sticker_message_14.binproto b/app/src/androidTest/assets/backupTests/chat_item_sticker_message_14.binproto index 16e20e3285f14a4f9302adedc5bd9c175ef854f3..d8d5c3c6da8cd55d8aa9bb50d3c1d3e6b37b3b0d 100644 GIT binary patch delta 239 zcmZo;d(OImss1UW(j!I=CILo?pVN0E0H%(r&F7C9cfe#Pn4C^3gTR%Kyv0w^PXx7*m#4faT?dq6E%VY$C69AsGW4{0Z delta 271 zcmaFP+QznkslJ6tsga3;Nq|ve&&4@!KO1;)aItZ)cmaj7UNUkWVB`{b5ytZ5aXNqb z>#xrhMdnA&6;j~hPn^8v|8LcZ%Bgm$RXg3?w`M)9H`kM%{^`c61g&Q$B&3zNKg^%F z@=-(YhxwCsYgH?8W#%TPr|OrdCKXt*dOCSHM>))A_IS^nRUgMCFx~6x@+Fa}T&fe^ zU+httcUwrH`Q%IHKR2cr{g}V;)$+EmsS^KMf6ic4Vs#D-FD=zzHrRiC;@2037EDeG z7RJezsg?%DX~`)TmL|qVX%?1gNrtJ3iRKn&re>C=QVc?ZTr5CWGyr{g>rltFGe!!G Q5TS{^0xS|7w;^Io0QJpj)c^nh diff --git a/app/src/androidTest/assets/backupTests/chat_item_view_once_00.binproto b/app/src/androidTest/assets/backupTests/chat_item_view_once_00.binproto index e2d6569756d5dabeb5089ef7e8c679ef6a7afdf3..f658afc24800085117e89b47d520cbac7127163d 100644 GIT binary patch delta 42 zcmV+_0M-Ac1fv9?0wW?KAP52w1Q_d=xzxZhLJ$b9(VXq`Fc6`@nT(P#AOVsA05c;G ALI3~& delta 44 zcmV+{0Mq}Y1f>L^0wp9OA_xKy1Q@Q-obB^4LJ|nw%>Tp1F%Y5rgwdNc7y%#wk^ul; CY7jgC diff --git a/app/src/androidTest/assets/backupTests/chat_item_view_once_01.binproto b/app/src/androidTest/assets/backupTests/chat_item_view_once_01.binproto index 6a187b1c087dab3b73397e3cc0b6b8365059ca88..f1be90bc1b7ba3c0a1a5a1e823d25fd67910ade8 100644 GIT binary patch delta 122 zcmV-=0EPdX1@i=;0&{XAa0mhr1Q_g>xzxZhLJ$bA(VXq`Fc6}^nT(P#7y*(2Pzp{8 zN+JqrZDD6+FKTdQXKFeM5O~?mR6|S3ax`jR`Ft^gk{I61n>3OEcnWq3 zav}<8ZDD6+FKTdQXKG>!5a?C}q RGi5S0H(_EqG&dRm7y;QtJX8Px diff --git a/app/src/androidTest/assets/backupTests/chat_item_view_once_02.binproto b/app/src/androidTest/assets/backupTests/chat_item_view_once_02.binproto index bfe2d481bf511a1740b1cf990420e9912d72dd39..06b53fb232dd4a6c8d7e89adcbaf4a4dae1e3d0a 100644 GIT binary patch delta 168 zcmV;Z09XIw1iJ;G0!X<5BDMht0uTWh?U%XKz%fb&3IqrQ8UT_3p8*P-0Sbo!A_-}2 zVP|D8aBgQR5LDSS!VMY(&ehN1>yvt0xn@9UkCya0T{5+obB^4N(Kr92m~4ck^xByM+!3{32AL%XJs#N lZf8Kp97wDVlSl#|6#yClA`tFXJpze3JnMZ5aW!%#;7nN0tf+;0d)#< z3U49_X>DO=WiMxGWvz oAjJ9#S%b;x1N_*OGWegd>ZgWQl@z$DxwWOg(;L4Ih8h4E0lvvLs{jB1 delta 178 zcmV;j08Rgy1;quR0zAV3BESI%0uTWhvC*9E^Ds&e3JnMZ5ZI&ZwXQWH0tf+;0iXd2 zodF7%0U`-$ZDD6+FK20HK-&mNlN^&d0v~E+3J?|4t-bb`T$HwBGa{k?9G4Oha3^C* zxr;09{<=v>|6bs;7_h3$qXr@jNlI~fQ)^67M@3R}C<8FIzr~gFF*pK3AU7~FH#Rdg gVPZKrVlrZ7WM*YzVKg~3IA&%wWo0m8Ga3LG0r=uRNB{r; diff --git a/app/src/androidTest/assets/backupTests/chat_item_view_once_04.binproto b/app/src/androidTest/assets/backupTests/chat_item_view_once_04.binproto index f74d5337d1bba30d559ad280957c1a6d5c554c67..d3425e12faef0d9bbe9a86528c3a7c94c227dea2 100644 GIT binary patch delta 175 zcmV;g08szw1i}TN0#CpJBE10!0uTWh@0YpMz%fb<3JVAX5RAdl-=sAn0FnWp0ScS} z3WotA33h2@Wp6KSa5O3qRM|7a4H^W_*(90uN2Qc5Fn|z1-Wf=$1d}xaA5=dI5cg-g zuEf)e+NCkwpF diff --git a/app/src/androidTest/assets/backupTests/chat_item_view_once_05.binproto b/app/src/androidTest/assets/backupTests/chat_item_view_once_05.binproto index 2617acf09f58d4a1d8926b9c6e94dd77f2309e45..4cd770e6096c0f8d8f86ebf9a873728819932b83 100644 GIT binary patch delta 108 zcmV-y0F(c>1&als0wIY3B8CA70uTWh@RzyNz%fb)3I+%SDgp=rk^ycCYzkv02l!Wt0b)e delta 152 zcmV;J0B8S;1-AvD0wlEoBC-Jp0uTWhv(cRG^Ds&X3I+%SDgp=rk^z|k3YGy1kpYt- z0xM`^3K09)q8|q(G}ZTKx~|02i`)_rSV=w`uqKRMsAuT3RCPmH7|Zgps|O+sNlI~f zQ)^67M@3R}C;~9Hzr~gFF+w0UI5askWieu6FfukcV>M)9I5szBIASz4G&eOgGc`FH G02l!z+cDGt diff --git a/app/src/androidTest/assets/backupTests/chat_item_view_once_06.binproto b/app/src/androidTest/assets/backupTests/chat_item_view_once_06.binproto index ce4bbbef05cb265dcfa9aa5e826d1ba248450cee..7a02b0b6ac1e7e6637544617c2e52b30b5c5a4e1 100644 GIT binary patch delta 175 zcmV;g08szw1i}TN0#CpJBE10!0uTWh@t3*Oz%fb<3JVAX5aW!%#;7nV0FnWp0ScS} z3WotA32AL%XJs#NZf7bGRM|7a4H^W_*(90uN2Qc5Fn|z1t{+I<29q@cA5=dI5P}=c zg3Q+$*-Yh$h3!Kalo*Dh^yUU43UWwUYera2PeO4h12Dw;#_R1dS`e!(S2-x5O4}}w dka3w6Pwg52A`r;vd6Bt>NCkwDO=WiN1UXF$gsNURQ%PXZqm02%-y5bjky0*Qc4B8wig*Of_Njl2jP9RL6T diff --git a/app/src/androidTest/assets/backupTests/chat_item_view_once_07.binproto b/app/src/androidTest/assets/backupTests/chat_item_view_once_07.binproto index e89a4b223499d2094f9cd95f7f126a0e3acf15a7..3c319f0163e94171323325989c2311cd190e622e 100644 GIT binary patch delta 34 qcmZ3)vWR5^2b0vN={v6+F!bW*;^klw=s9@d{t{CoCJx3)j0^zUIty6< delta 34 qcmZ3)vWR5^2b0v+i*w$7Ht^!-;^klwSU>mF($$7WOdO1p7#RTDHVZ}o diff --git a/app/src/androidTest/assets/backupTests/chat_item_view_once_08.binproto b/app/src/androidTest/assets/backupTests/chat_item_view_once_08.binproto index 4f5cc9712bb9cec16765cbd17ef46083700861e2..f502647e44f392300dd89110565c70fb110808f8 100644 GIT binary patch delta 112 zcmV-$0FVEZ1?dE!0%>R>W(Wch0T}a_xzxZhN(Kr92m~?!k^xW(P6|pQ3TbU&XJs#H zaAjv|ItmbY+09f#OUiOIYG3($F@lm9-pu5k0a75EoZ{HiXj!??w$fV6OKMp&%#ZDM8{I02l$jtt+!5a?C}qGi5S0H(_Eq JG&dRm7y)aFG(G?T diff --git a/app/src/androidTest/assets/backupTests/chat_item_view_once_09.binproto b/app/src/androidTest/assets/backupTests/chat_item_view_once_09.binproto index 05c6c657c2d95c508abd58e8a8dc124da7575422..c560ee4874bbea2cc60d54e8a3f0cbe81cff4ebd 100644 GIT binary patch delta 175 zcmV;g08szy1i}TN0#CpJBE10!0uTWh^q0BRz%fb<3JVAX5aW!%#;7nl0FnWp0ScS} z3WotA32AL%XJs#NZf7bGRM|7a4H^W_*(90uN2Qc5Fn|z1t{+I<29q}eA5=dI5bLl% z?SzK(8EbB3YzcQ3Zy45xpqKNCkw3JnMZ5RAdl-=sA<0tf+;0d)#< z3U49_X>DO=WiMxGWvz oAjJ9#S%b;x1N_*OGWegd>ZgWQl@z$DxwWOg(;L4Ih8h4E0n9Bn&Hw-a delta 176 zcmV;h08js!1;YiP0y@C~BEA6#0uTWhxY3;L^Ds&c3JVAX5U-uerK>SI0FnWq0ScV~ z3YY;R32AL%XJs#EX=Xs%2uPD0lQ{w(YGn!#71XW0_Ly9hwqr9Qq5mA05)g1FV@kP; zEA9TeNl5=*;IkO8s?4JXA`D4Nad}f~Oi@QgQgkQ-Ft)$NmGdz;0zx1+FfunbGc;jh eIXGf6Vr67zWny78IW#zCW;JDHFk&+r02l$NkUi-D diff --git a/app/src/androidTest/assets/backupTests/chat_item_view_once_11.binproto b/app/src/androidTest/assets/backupTests/chat_item_view_once_11.binproto index b8fa5a5dabd3c405a25196e9e2d522cf064ad4ad..83834d2adf1d0ca665df129428803f4a7c7abff9 100644 GIT binary patch delta 168 zcmV;Z09XIw1iJ;G0!X<5BDMht0uTWh_LsTTz%fb&3IqrQLI9Ehp8*P-0Sbo!A_;bB zWMywJZE!Ry5LDSS!VMY(&echN1>yvt0xn@9UkCya0T{W_obB^4N(Kr92n0d^k^xByM+!3{33h2@Wp6KS la5O;08%T!^lSl#|6#yClA`tFXJpze1&{@x0w#_DB8veC0uTWh_m{cUz%fb<3JVAX5aW!%#;7n#0FnW23Tz5! zlPLl#KROB!9ZIdq8&qQnj~AR!>bwoC7}kfNm;_QFI`^I_jQsLR8kXk=zyevvCQh|M TefuEU-a9NbE+=u@8UPppfA=WP delta 157 zcmV;O0Al};1-u2I0x7xyBDVnu0uTWhy3w5N^Ds&c3JVAX5ZI&ZwXQWv0FnWj0ScA@ z3XuVmCITyHV+s)a*rFc?B{bFdXS%M$(~H~^5Lih*8?YvfU8ra1v{ZFNSs2Umv8x9n z3`t6Hc~fglQAb5mbSMHaw!g)d^D#moH8?amGi5PiVlXl`IAb+rVK_E7WjJCqH8eLh LG&40h8UPppZB;fV diff --git a/app/src/androidTest/assets/backupTests/chat_item_view_once_13.binproto b/app/src/androidTest/assets/backupTests/chat_item_view_once_13.binproto index c0764c40b42c203fd145f846c80586517602302f..3ad6d1c8c70f3d9c3c4a5a5bd95734333e217ae4 100644 GIT binary patch delta 177 zcmV;i08anw1jGfP0#U*NBEJC$0uTWh_?NlVz%fb>3JnMZ5RAdl-=sB40tf+;0iOX1 zoB;}l0U`-$ZDD6+FK}*WDiBoJGr|oT1kTwcne|7dlrAuU5J0XUNZkgLHv%72KMD|n z8_j~u*BRMN<%xyuLl~48hNAT51|kY_NLgz}SWQntaVP^Y#QMhT?J-&qt1VYKD4|N* fE|8FMnH5j%8UP{?$mn^IxrRsugv@z|2s=Br;~qmT delta 88 zcmV-e0H^=N1?vQ$0ykcVb6;> J#THs7+5i`W6xsj) delta 58 zcmaFK_Kt0X4YQGmB?dk_!+ delta 51 zcmeyv_LFUc4KuTimDOZ>W^rXJW)@a1kM)89o0ub5B3L8Xk_7bEC-D?%W-??P*)S(8 Hv+OAVY_ku0 diff --git a/app/src/androidTest/assets/backupTests/notification_profile_04.binproto b/app/src/androidTest/assets/backupTests/notification_profile_04.binproto index f85c699e35e91bf2f89dee5f7897e37ad1cf3f18..bdd289eb72376b912c41bcc51848418598c44124 100644 GIT binary patch delta 49 zcmeBSZ)e|N!_4euRF0sZw!JVlzB3>il@ K%n8dZdkO$;><@JS diff --git a/app/src/androidTest/assets/backupTests/notification_profile_05.binproto b/app/src/androidTest/assets/backupTests/notification_profile_05.binproto index 04c8048e1877bfb99f93dad77f254a33d3b17321..746e5c92ef0b011256941682a54fca47aea429e5 100644 GIT binary patch delta 56 zcmeBT?`7X$!^|9Dd3IJ=~4|xCp diff --git a/app/src/androidTest/assets/backupTests/notification_profile_06.binproto b/app/src/androidTest/assets/backupTests/notification_profile_06.binproto index 636634a2d99991e93f90c2cd7d4f8442331cc401..e26a740bc41f386294311ad28f369c04618374c7 100644 GIT binary patch delta 69 zcmeyz_LFUc4YRF{l@%9PXo-SzX;NlRW}@ty8{hsLFj_IOa(Vn`4=9OXieQdliC~Rj Zi(pR@2+J&cDqa>cVb6;>#THs7+5kBf7nT43 delta 74 zcmey#_K$6Y4YQM@l|2_%Xo-SzX;NlRW}@ty8{htGFd8sgF|l$vFnX*P4A{gR!4$z9 e!4kn5!4|=uB%r@OiKj?2lOf~ChB;xGWlsTnX&3DP diff --git a/app/src/androidTest/assets/backupTests/notification_profile_07.binproto b/app/src/androidTest/assets/backupTests/notification_profile_07.binproto index 4da8e55dc8d1c427d7924ca18e947626749a0fb1..4aae82fbd0ff734387a19d7cdb8a9b228175c6cb 100644 GIT binary patch delta 62 zcmeBWpTNGshM76oDsZwrv$CEBqZKm?E0+VK$A9*Kk_g5KrU>Q;mI&4ewg~nlfw0W7 Sr{ZNH6ZX8AQ*5DSq74Am=n&%o delta 59 zcmbQh-pjthhM76Q%5Sngv$D1oGYc!1$9lnlP0SID5lj)x5iAj`5o{6cNdo%olX!|W PGZ`|DY?u?4S@skFsV)#s diff --git a/app/src/androidTest/assets/backupTests/notification_profile_08.binproto b/app/src/androidTest/assets/backupTests/notification_profile_08.binproto index 1aad3053979270f972d46685a4fe7c745b137f1c..c2faa652922ea3ecca6712a745792e0ea5e9ee14 100644 GIT binary patch delta 41 xcmeyv_ML5m4KuTqmBnOxW_d{iMvwpO0VPQSVVPx5#mhn_?0GS#*h0%h8vq}14qpHO delta 46 zcmey)_J?hQ4KuU7mF;AEW_dXcMgv9%MvwJ^0h^eU1oYP@@f2xhGGrXtFefat>?r^@ C^A5HE diff --git a/app/src/androidTest/assets/backupTests/notification_profile_09.binproto b/app/src/androidTest/assets/backupTests/notification_profile_09.binproto index e76246a52fc4a3f5a21f9d50e5fc46b60b6b592d..49add81696291ef741b5663f2a51175b80db3796 100644 GIT binary patch delta 48 zcmey&_Kj_W4KuT)mHA|QW^n}#Mk_`Z2S$(o>;WYaj7b7vnPpGK%R(mXc`>KhLd!%O E09R@cBLDyZ delta 45 zcmeyy_L*&i4KuTumC0m#W^q|7Mi!6tf&rVDBN&qe^w%fx6lrEMWE|NrCoHqRF0sZw!JVlzB3>il@ K%n8dZdkO$tiVp|? diff --git a/app/src/androidTest/assets/backupTests/notification_profile_11.binproto b/app/src/androidTest/assets/backupTests/notification_profile_11.binproto index 092a36ff20a3a831d8a332ba0a31f24771baacb6..fdb40ad8e99ef3e48f530248941d227b70bd70b6 100644 GIT binary patch delta 54 zcmeBR?`Gd%!_4ewqNd!v-YXn=8Kv-tkQ}MEp34315 KDYnou(FOo;w+~$a delta 51 zcmeBX?_l3x!_4e$PNjycGnG6|6Hp~gj HEPDz7NC*zd diff --git a/app/src/androidTest/assets/backupTests/recipient_contacts_00.binproto b/app/src/androidTest/assets/backupTests/recipient_contacts_00.binproto index 188bbf1633b6219c68d474e75844741c833859b7..1129e03fd4537762d08667a24bab025f6826135a 100644 GIT binary patch delta 75 zcmX@be3^MeHY0nwP$~zDP~zkwMlJII#tgAMiPs%XV-6$t?H$ zWSNwD-*kijTGf7=<)YYqGV@Z36DyP0-13W(Qi~_wXH?JT;bL)5%t;ku@yIXA>tb{) z%`44SC@sm%OUzX$PAtew%~L2T$}BF)EG$h03go0J6qY8Y7NzE;0M(^r78jJ3B$j06 k=VgM$fr=(EviRobCC*}G@u|$qTLh#M^AcAuGCDB;08&6f^Z)<= delta 149 zcmV;G0BZmB1k41mYXJ)10TSE+2m}(>0h4tBH#0B+N+2NyOE*k>e;MyexeMS9Lw6mE zv-txa=gD>&Cytje|0-GpMQ&+iVh2WYWo2z)Zj<8yCq@zq1x;afa$yn)Qg38(X=in1 zdWr!MbZ>NFAaZ4Jb!2H_Ze(F)k^u!yZ){<1ngIq=Zh2&7a-snTO<{C&Xk~Y(0Rch) D-<~q8 diff --git a/app/src/androidTest/assets/backupTests/recipient_contacts_02.binproto b/app/src/androidTest/assets/backupTests/recipient_contacts_02.binproto index 7fb227c761d108bf45b9fc071b343fb667450f58..3b3ffebab0bf243cc0d55be3f3fedecc75ffbeed 100644 GIT binary patch delta 120 zcmV-;0Ehp@1hfROYXJ$z0TRRk2m}(plXL+(7BB)(0a^)4Z*ygEXlZU`Vg*NXVQzGj z$pI-x4+;iQVQpn>VG;#GVQy=4iUAIAa%FUBb!{MZVrg-8Ws(5~L}hYmV{4iL1Ve9c aYoY-MMrCYiV`*Wi0Rln?2-u_RwXQYJjwf6I delta 137 zcmV;40CxYh1jPifYXJ$^0TR^#2m}()lXL+(8z=!V0#E^32Tfsab!BW}VhT`YZfN0h0UCB?a%psRb0BqYb!{MZbZKs3Z6I@D raA{?3k^u%na$#;{X_^5ALV0C!bD{wRO>b^tr~v{(2ME}s>$R>m!R0Oh diff --git a/app/src/androidTest/assets/backupTests/recipient_contacts_03.binproto b/app/src/androidTest/assets/backupTests/recipient_contacts_03.binproto index 5f602ec265487bef5466b80a204ffd692e9211aa..f11d1b0c9c4293b8a1fc4546762d6c814dbff878 100644 GIT binary patch delta 106 zcmdnOvYBN=HY4XTMxn!u94tcnCYLapuxK!PDNJ6+C?i_!w^=TV&8es|F|Q>TUo Jo?5!v5CF(&A~yg4 delta 107 zcmV-x0F?i;1hfROYXJ$z0TRRk2m}(plXL+z21+0y21_@StN|PmS_e#NZe(*|d13}e zZ*pQ~bCcZxB{UQY2v%uwXK8L}VG;;aXk~D4VRB@W0S8faX>N3HZlVDOL}hYmV{51Z N140J~ubs-Jt1;B)B4Pjl diff --git a/app/src/androidTest/assets/backupTests/recipient_contacts_04.binproto b/app/src/androidTest/assets/backupTests/recipient_contacts_04.binproto index effe33c600fb51de3a08d42476b6249b6bee9091..42cc6bc7b23fbcc864075bcbe75ed0b4ec86b862 100644 GIT binary patch delta 75 zcmcb>e3^MeHY0nwP$~zDP~zkwMlEv##sJ0)#wJEKE*AI1oYXEx!J^cH(v-}^yp+UL fg`}d=lGIs@EZ(WP1&bJ2gYuIy^HwmjSTO(q9x4@~ delta 72 zcmcc2e1UmGHY0nAP!b1=P~7AqMlBN!MgztG#tgW!avRE+y0Kd}|8~^|S diff --git a/app/src/androidTest/assets/backupTests/recipient_contacts_05.binproto b/app/src/androidTest/assets/backupTests/recipient_contacts_05.binproto index 1a03a944a50ab00612ae00a292a0b3a21c2191f2..c2a7e462ef011c467cacce0be5614ce024d9c1f4 100644 GIT binary patch delta 170 zcmZ3-@`zVT0Hqaqk4p6Xn;^G{~E z=O@dg)cd9z{MU+Nam~w2Nn&>^N=?m8%$xj}QC&lzB)=q4p(wSWG$k`JFC{T`5+j>? WY7tO+79(45US&#Z(F#UZCk6mf$|!9B diff --git a/app/src/androidTest/assets/backupTests/recipient_contacts_06.binproto b/app/src/androidTest/assets/backupTests/recipient_contacts_06.binproto index 0f3f671db0b9d1d8385e1778b00e1cc0d3c5ddce..bf15218a01bbe6fb89e5d471e2fa88b1a90f5468 100644 GIT binary patch delta 112 zcmV-$0FVE|1gZqEYXJ$p0TQ|a2m}(flXL+(6i@+L2}*BsWpHR|Ze?NxM{;3qbd$#c zCqWDf1V>?PWfBBPZ*p#m0S<6-WprtEZ6I}GX>oOBk^uxwZ*F0l0R%&DZ)>6f21asa SWMp}$0R}<`2-u_RwXQX*WF)Bo delta 136 zcmV;30C)eY1i}QcYXJ$>0TR*y2m}(%lXL+(87Kiz0a^!5VQzJ0Y++&wP-SjzX>Mn9 zZ*G&q0Vh-v3I$DJb#h@62~uxla%pFEWqOJM8g^xJX>@gSAa!naZ6I}YX>MU{Aah}G qX=QGb0R>KPY+-Ji0R=*NWpZ<(0R>ZZWp-t#0R}<`2-u_RwXQYB7cNf# diff --git a/app/src/androidTest/assets/backupTests/recipient_contacts_07.binproto b/app/src/androidTest/assets/backupTests/recipient_contacts_07.binproto index bf94a61835f256553555620c7dad2bb7b84bfe2b..8613dfd36fe3f86b52a27f008aa1c354498c92aa 100644 GIT binary patch delta 103 zcmV-t0GR)^1hNFMYXJ$x0TRLi2m}(nlXL+z1}FhA0ZJf~umKzudrq?+S_VRLd0}pJ zVh2cXY-4Y2Vw2qgCoB&N22f#bWo%&*1wvtNYjctT21I3YX=7`m0R&88Zegea2SNu3 Jubs-Jt1&IUAN&9S delta 106 zcmV-w0G0o;1hoXPYXJ$!0TRUl2m}(qlXL+z2rvOkARz`zHtCP~qevMlE*@Mgyh*#tgn;^G{~E=O@dg z)cd9z{MV}X+bkEw?vt69Qk+dR5Xi` Y#iueaZxJKATWU^ba%SQRMouRN0D}-fMF0Q* delta 103 zcmaFPvV~EJn8Ayvmf+qD72sE~!PC$=NFy HIh_~)S7{&Q diff --git a/app/src/androidTest/assets/backupTests/recipient_contacts_10.binproto b/app/src/androidTest/assets/backupTests/recipient_contacts_10.binproto index 395596400b8a1febdd6d2cc62e843c6d702d50ee..547d8f1d0d1c6c5a70bc319603feea8bfe96d3dd 100644 GIT binary patch delta 101 zcmV-r0Gj``1fc}5YXJ$g0TQtR2m}(WlXL+(7BB%&0a^)4Z*ygEXlZU`Vg*NXVQzGj z$pI-e4sdd1bZK>MAa!DCadl;q0S8TCbaZHCcbWkNLvL?uq5%a`Z(?a~r~wK>2ME}s H>$R>mNZTRE delta 121 zcmV-<0EYje1hoXPYXJ$!0TRUl2m}(qlXL+(8z=!V0Z;*22Tfsab!BW}VhT`YZf2ME}s>$R>mI^Zd3 diff --git a/app/src/androidTest/assets/backupTests/recipient_contacts_11.binproto b/app/src/androidTest/assets/backupTests/recipient_contacts_11.binproto index ef18d9da2dd12970f80ea08b470298701a0c32eb..4f54f4ae2eb7ba590fc33c8899e1887da489de53 100644 GIT binary patch delta 91 zcmV-h0Hpt`1f~SAYXJ$l0TQ+W2m}(blXL+z1}FhA0!kp0umKzudrq?+S_VRLd0}pJ xVh2cXY-4Y2Vw2qgCm;+81V>?PWfBBPZ*p#u0R&BNZegea3ql77ubs-Jt1+<^8=3$B delta 96 zcmV-m0H6P+1giwFYXJ$q0TR0b2m}(glXL+z2rvRlARz`zHz0R>KPY+-Jw0SiJ02(O*WrK>SI Ce;u#@ diff --git a/app/src/androidTest/assets/backupTests/recipient_distribution_list_00.binproto b/app/src/androidTest/assets/backupTests/recipient_distribution_list_00.binproto index 37419ba59b1ecff0ad8b28fb94890d282b4d01c8..c690f11ca1fce03bdee6e592444ee159d0d6c65f 100644 GIT binary patch delta 31 ncmdnNwu5bhBD46<&D}C5pZhWQsY{h<{Wq8{Fl*6;hA(CS&Sed^ delta 31 ncmdnNwu5bhBC~j)-gWD!kM05O-fW7J^))^MHx|F%y3P~;vUUtY diff --git a/app/src/androidTest/assets/backupTests/recipient_distribution_list_01.binproto b/app/src/androidTest/assets/backupTests/recipient_distribution_list_01.binproto index ff22da0db2a58607b54765c49204d37d8b690c0e..4bf8235ea419abb9aae6c9e0e7f4102973ef8f2d 100644 GIT binary patch delta 53 zcmX@kc7$z%IJ2&fkQN7rk{Xx5&&}O3C!hN<_o+*jY5g~tE+xdp=~|kr;G18RlqtX{ J!KlQ@0syX&4#EHc delta 56 zcmX@YcARa4IJ1GikS+&@k|vixpx$-ssE_Ue?cQvPlJzw{QleZuUZuq)`3lbYdFiF8 L0*n%jN{lQ3ussfK diff --git a/app/src/androidTest/assets/backupTests/recipient_distribution_list_02.binproto b/app/src/androidTest/assets/backupTests/recipient_distribution_list_02.binproto index d64e13841e0dfb15ab3abc36191e32c437eea070..c1e929b8d2b311905ac29b1ef6da11370337cbef 100644 GIT binary patch delta 56 zcmX@ec9d;{D6@gSkS+&@k|vkH&&}O3C!hN<_o+*jY5g~tE+xvv>zG%PnO~5Ys}NY4 MpCZAi#Kg)50P8*wcK`qY delta 52 zcmX@gc93m@D6@{XkR}I*k}8)#px$-ssE_Ue?cQvPlJzw{Qi5EZuBEvOzWGH-nG%dj HOss4GYa9&l diff --git a/app/src/androidTest/assets/backupTests/recipient_distribution_list_03.binproto b/app/src/androidTest/assets/backupTests/recipient_distribution_list_03.binproto index 70ab5137fd9f120344d3a2ac375895ccaab13930..763629a99976ca34652da315c936c5ee889c3161 100644 GIT binary patch delta 61 zcmX@jc9v~}1hc7$kP!!mk{*}9&&}O3C!hN<_o+*jY5g~tE+xgq?^v2#l3%0{kds)F RpO=~|z$n3}#LU9V1^`bb5t#r0 delta 59 zcmX@hcA9O21hcV`kO2pWk`9+Zpx$-ssE_Ue?cQvPlJzw{QW9Lej(H`S`2~r&3W25h ODFTcVj7rQbtZV?~84mOS diff --git a/app/src/androidTest/assets/backupTests/recipient_groups_00.binproto b/app/src/androidTest/assets/backupTests/recipient_groups_00.binproto index bd64b3af3a3f4e0b7912fa4170a579e76693fd22..b3df57e51d22f48d2ea26cd6457d69bf7e57b2b7 100644 GIT binary patch delta 74 zcmV-Q0JZ#Tt=P gE3eyLqImrn0V-;f!31gzFabCK2pR?m0T2pM0o7y}9smFU delta 76 zcmV-S0JHzN3c3ogkpwWF0TP=52nrgO0SX`@ju?;kWO_?=K3y9d&#lt8D3h3ydFaRm i*oL`>dCY_u0V-^h!31g#U;!`zH~#Tt=P cE3eyLqImrf0U!Y?pR>aR0|5eH0h7iBExa`vBLDyZ delta 67 zcmV-J0KEV83-b%Gkpwc(0us#v2nrg=0tz4^ju?;kWO_?=K3y9d&#lt8D3h3ydFaRm Z*oL`>dCY_m0U!Y?owLIP0|ArB1ucD!8i@b^ diff --git a/app/src/androidTest/assets/backupTests/recipient_groups_02.binproto b/app/src/androidTest/assets/backupTests/recipient_groups_02.binproto index 8d5931e648cd6605a450952c8a4e3b490b489cfb..7e83aee0262ca0a6d09da531776ce6a1c032a742 100644 GIT binary patch delta 113 zcmV-%0FM8~3&RVrkpwcJ0ur492nrgQ0tz6uJ39zSu9D{94N=}F#Tt=P zE3eyLqImrn0U!b@?UTa<&N3ZJt;riyV+oHJoKWh#4Xn2Kl>aTwQJ^RGZS&*<@x3?# T4;l>!0T2o(*xkaErv*>}=(sK% delta 115 zcmV-(0F3{`3&jhtkpwcL0urAB2nrgS0tz4^ju?;kWO_?=K3y9d&#lt8D3h3ydFaRm z*oL`>dCY_u0U!b@?~}s>&NLP&C20*YsJa?^=(B#Tt=P kE3eyLqImr(?UTO*u?V-dHk<=bFCmki1Q-Hf0h5pgFNsDSzyJUM delta 95 zcmV-l0HFWD3%?7nkpwQB0uq@52nrgM0tz4^ju?;kWO_?=K3y9d&#lt8D3h3ydFaRm z*oL`>dCY_=>yy6(u^_L|%M+&k2~vchc;9GQxvV)0BTitAHgSX}CI7dzHk^}^1ushl BDP#Zu diff --git a/app/src/androidTest/assets/backupTests/recipient_groups_04.binproto b/app/src/androidTest/assets/backupTests/recipient_groups_04.binproto index 74fffbb49523d54428d73ffbb5766963ab6cf16e..f0e23d0859f3827ce8746ee1c67b86ebe91bf424 100644 GIT binary patch delta 76 zcmV-S0JHzR3c3ogkpwiJ0TP=52nrgO0SX|tJ39zSu9D{94N=}F#Tt=P iE3eyLqImrf0T=-w0V-;f#RO^#I0Oh91_%KV3Qz(6lo&Gr delta 78 zcmV-U0I~nN3cL!ikpwiL0TP`72nrgQ0SX`@ju?;kWO_?=K3y9d&#lt8D3h3ydFaRm k*oL`>dCY_m0T=-w0V-^h#RO^%U;#J;2pR?m0T2pM0ZW$|Z2$lO diff --git a/app/src/androidTest/assets/backupTests/recipient_groups_05.binproto b/app/src/androidTest/assets/backupTests/recipient_groups_05.binproto index 5ad6e57f27976a2094ce6c2bfa383579c0385edc..75a60c4d4427f61d8648681f17722b8072fd5ec8 100644 GIT binary patch delta 68 zcmV-K0K5P33-b%GkpwW%0us#v2nrg=0tz6uJ39zSu9D{94N=}F#Tt=P aE3eyLqImrv0xF-g!2|;V0$>4?#04#kry2tQ delta 65 zcmV-H0KWh83-JrEkpwW#0usvt2nrg;0tz4^ju?;kWO_?=K3y9d&#lt8D3h3ydFaRm X*oL`>dCY_$0xF%e!2|;Vlg0%tOvoB( diff --git a/app/src/androidTest/assets/backupTests/recipient_groups_06.binproto b/app/src/androidTest/assets/backupTests/recipient_groups_06.binproto index 50b3ca41ea8a2da1a2a57f90869dc4affcf96da4..05f177bd6f6db6dbb6589a61f3d13c4592c2f97f 100644 GIT binary patch delta 97 zcmV-n0G|KF3&RVrkpwWH0ur492nrgQ0tz6uJ39zSu9D{94N=}F#Tt=P zE3eyLqImrn0V?g2!354A9ZIdq8&qQnj~AR!>bwoCw)m9)EzMD&C-!agdCY_u0V?m4!354W7AYlZ4Kb*?8hhxof(p4d7&TSxjzH2w9Wj0_?m4^oU;!`z VI0g?I4F~}c3Mkm!!jz{4Pyrr;E8PG9 diff --git a/app/src/androidTest/assets/backupTests/recipient_groups_07.binproto b/app/src/androidTest/assets/backupTests/recipient_groups_07.binproto index 01350e2de54d70b8a731a5fa99cd6d63d3b7dc67..d2b0d3bb98de8c8cea9ace9dda2269c4cdf6c155 100644 GIT binary patch delta 82 zcmV-Y0ImPQ3&RVrkpwcJ0ur492nrgQ0tz6uJ39zSu9D{94N=}F#Tt=P oE3eyLqImrf0U!Y??UTa#Tt=P gE3eyLqImrn0U!b@YLmkRY700B2pR?m0T2pM0nwxw82|tP delta 76 zcmV-S0JHzN3c3ogkpwcH0TP=52nrgO0SX`@ju?;kWO_?=K3y9d&#lt8D3h3ydFaRm i*oL`>dCY_u0U!b@Y?H$TY7JlkI0y(D1_%KV3Qz$X!5LEk diff --git a/app/src/androidTest/assets/backupTests/recipient_groups_09.binproto b/app/src/androidTest/assets/backupTests/recipient_groups_09.binproto index e133bcd1651c3b083ec0964e8f049167576744a3..7ba84602c1f540a2800bfa849be5f936924e1e1f 100644 GIT binary patch delta 66 zcmV-I0KNb53-b%GkpwQ#0us#v2nrg=0tz6uJ39zSu9D{94N=}F#Tt=P YE3eyLqImr(pR>ON0|5eH0h7W7FJ74$-2eap delta 63 zcmV-F0KotA3-JrEkpwQz0usvt2nrg;0tz4^ju?;kWO_?=K3y9d&#lt8D3h3ydFaRm V*oL`>dCY_=owL6L0|Ar71uq?%8bbg8 diff --git a/app/src/androidTest/assets/backupTests/recipient_groups_10.binproto b/app/src/androidTest/assets/backupTests/recipient_groups_10.binproto index 167f53fce3940b5ec113dd70bdfebfe490782171..82e11ff8c8829f311b6ffcae7f905d6b8464fa09 100644 GIT binary patch delta 115 zcmV-(0F3{~3&jhtkpwiN0urAB2nrgS0tz6uJ39zSu9D{94N=}F#Tt=P zE3eyLqImrf0T=-w0V?g2#RSeW9ZIdq8&qQnj~AR!>bwoCw)m9)EzMD&C-!agdCY_m0T=-w0V?m4#RSeY7AYlZ4Kb*?8hhxof(p4d7&TSxjzH2w9Wj0_?m4^o XU;#J^4;l>!0T2o(*xkaErv*>}HexIC diff --git a/app/src/androidTest/assets/backupTests/recipient_groups_11.binproto b/app/src/androidTest/assets/backupTests/recipient_groups_11.binproto index 55e0f3fce558d45bb3e681661ec4f0f476a09479..6f3a874551da5dd3bc91d7a98348ea8e5b7453a8 100644 GIT binary patch delta 80 zcmV-W0I&bQ3&9JpkpwWF0uq}72nrgO0tz6uJ39zSu9D{94N=}F#Tt=P mE3eyLqImrv0xIp3!341gx3xB$15Ym@lbr+@0$>4?k_9cdC>`bi delta 97 zcmV-n0G|KB3%?7nkpwWD0uq@52nrgM0tz4^ju?;kWO_?=K3y9d&#lt8D3h3ydFaRm z*oL`>dCY_$0xIj1!341&uh7dAru_+0grIoeXj!?eISV6BV2w6$geN8cx3xB$lavK5 DeE%tm diff --git a/app/src/androidTest/java/org/thoughtcrime/securesms/database/AttachmentTableTest.kt b/app/src/androidTest/java/org/thoughtcrime/securesms/database/AttachmentTableTest.kt index 2756e0964f..cf87832881 100644 --- a/app/src/androidTest/java/org/thoughtcrime/securesms/database/AttachmentTableTest.kt +++ b/app/src/androidTest/java/org/thoughtcrime/securesms/database/AttachmentTableTest.kt @@ -15,6 +15,7 @@ import org.junit.Before import org.junit.Ignore import org.junit.Test import org.junit.runner.RunWith +import org.signal.core.util.Base64.decodeBase64OrThrow import org.signal.core.util.copyTo import org.signal.core.util.readFully import org.signal.core.util.stream.NullOutputStream @@ -200,7 +201,7 @@ class AttachmentTableTest { // Give data to attachment table val cipherInputStream = AttachmentCipherInputStream.createForAttachment(cipherFile, plaintext.size.toLong(), key, badlyPaddedDigest, null, 4) - SignalDatabase.attachments.finalizeAttachmentAfterDownload(mmsId, attachmentId, cipherInputStream, iv) + SignalDatabase.attachments.finalizeAttachmentAfterDownload(mmsId, attachmentId, cipherInputStream) // Verify the digest has been updated to the properly padded one val properlyPaddedPlaintext = PaddingInputStream(plaintext.inputStream(), plaintext.size.toLong()).readFully() @@ -231,7 +232,7 @@ class AttachmentTableTest { // Give data to attachment table val cipherInputStream = AttachmentCipherInputStream.createForAttachment(cipherFile, plaintext.size.toLong(), key, digest, null, 4) - SignalDatabase.attachments.finalizeAttachmentAfterDownload(mmsId, attachmentId, cipherInputStream, iv) + SignalDatabase.attachments.finalizeAttachmentAfterDownload(mmsId, attachmentId, cipherInputStream) // Verify the digest hasn't changed val newDigest = SignalDatabase.attachments.getAttachment(attachmentId)!!.remoteDigest!! @@ -239,7 +240,7 @@ class AttachmentTableTest { } @Test - fun resetArchiveTransferStateByDigest_singleMatch() { + fun resetArchiveTransferStateByPlaintextHashAndRemoteKey_singleMatch() { // Given an attachment with some digest val blob = BlobProvider.getInstance().forData(byteArrayOf(1, 2, 3, 4, 5)).createForSingleSessionInMemory() val attachment = createAttachment(1, blob, AttachmentTable.TransformProperties.empty()) @@ -248,8 +249,9 @@ class AttachmentTableTest { SignalDatabase.attachments.setArchiveTransferState(attachmentId, AttachmentTable.ArchiveTransferState.FINISHED) // Reset the transfer state by digest - val digest = SignalDatabase.attachments.getAttachment(attachmentId)!!.remoteDigest!! - SignalDatabase.attachments.resetArchiveTransferStateByDigest(digest) + val plaintextHash = SignalDatabase.attachments.getAttachment(attachmentId)!!.dataHash!!.decodeBase64OrThrow() + val remoteKey = SignalDatabase.attachments.getAttachment(attachmentId)!!.remoteKey!!.decodeBase64OrThrow() + SignalDatabase.attachments.resetArchiveTransferStateByPlaintextHashAndRemoteKey(plaintextHash, remoteKey) // Verify it's been reset assertThat(SignalDatabase.attachments.getAttachment(attachmentId)!!.archiveTransferState).isEqualTo(AttachmentTable.ArchiveTransferState.NONE) diff --git a/app/src/androidTest/java/org/thoughtcrime/securesms/database/AttachmentTableTestUtil.kt b/app/src/androidTest/java/org/thoughtcrime/securesms/database/AttachmentTableTestUtil.kt index 6b4d651eee..d5dab750a7 100644 --- a/app/src/androidTest/java/org/thoughtcrime/securesms/database/AttachmentTableTestUtil.kt +++ b/app/src/androidTest/java/org/thoughtcrime/securesms/database/AttachmentTableTestUtil.kt @@ -22,7 +22,6 @@ object AttachmentTableTestUtil { remoteId = SignalServiceAttachmentRemoteId.V4("somewhere-${Random.nextLong()}"), cdnNumber = Cdn.CDN_3.cdnNumber, key = databaseAttachment.remoteKey?.let { Base64.decode(it) } ?: Util.getSecretBytes(64), - iv = databaseAttachment.remoteIv ?: Util.getSecretBytes(16), digest = Random.nextBytes(32), incrementalDigest = Random.nextBytes(16), incrementalDigestChunkSize = 5, diff --git a/app/src/androidTest/java/org/thoughtcrime/securesms/database/AttachmentTableTest_deduping.kt b/app/src/androidTest/java/org/thoughtcrime/securesms/database/AttachmentTableTest_deduping.kt index 2a59eeeae9..811ce65bc8 100644 --- a/app/src/androidTest/java/org/thoughtcrime/securesms/database/AttachmentTableTest_deduping.kt +++ b/app/src/androidTest/java/org/thoughtcrime/securesms/database/AttachmentTableTest_deduping.kt @@ -726,7 +726,7 @@ class AttachmentTableTest_deduping { } fun upload(attachmentId: AttachmentId, uploadTimestamp: Long = System.currentTimeMillis()) { - SignalDatabase.attachments.createKeyIvIfNecessary(attachmentId) + SignalDatabase.attachments.createRemoteKeyIfNecessary(attachmentId) SignalDatabase.attachments.finalizeAttachmentAfterUpload(attachmentId, AttachmentTableTestUtil.createUploadResult(attachmentId, uploadTimestamp)) val attachment = SignalDatabase.attachments.getAttachment(attachmentId)!! @@ -747,8 +747,7 @@ class AttachmentTableTest_deduping { SignalDatabase.attachments.finalizeAttachmentAfterDownload( mmsId = 1, attachmentId = attachmentId, - inputStream = LimitedInputStream(paddedData.inputStream(), data.size.toLong()), - iv = Util.getSecretBytes(16) + inputStream = LimitedInputStream(paddedData.inputStream(), data.size.toLong()) ) } @@ -842,7 +841,6 @@ class AttachmentTableTest_deduping { assertEquals(lhsAttachment.remoteLocation, rhsAttachment.remoteLocation) assertEquals(lhsAttachment.remoteKey, rhsAttachment.remoteKey) - assertArrayEquals(lhsAttachment.remoteIv, rhsAttachment.remoteIv) assertArrayEquals(lhsAttachment.remoteDigest, rhsAttachment.remoteDigest) assertArrayEquals(lhsAttachment.incrementalDigest, rhsAttachment.incrementalDigest) assertEquals(lhsAttachment.incrementalMacChunkSize, rhsAttachment.incrementalMacChunkSize) diff --git a/app/src/androidTest/java/org/thoughtcrime/securesms/database/BackupMediaSnapshotTableTest.kt b/app/src/androidTest/java/org/thoughtcrime/securesms/database/BackupMediaSnapshotTableTest.kt index c797c4b8c9..f0f26ff1c8 100644 --- a/app/src/androidTest/java/org/thoughtcrime/securesms/database/BackupMediaSnapshotTableTest.kt +++ b/app/src/androidTest/java/org/thoughtcrime/securesms/database/BackupMediaSnapshotTableTest.kt @@ -146,7 +146,8 @@ class BackupMediaSnapshotTableTest { val mismatches = SignalDatabase.backupMediaSnapshots.getMediaObjectsWithNonMatchingCdn(remoteData) assertThat(mismatches.size).isEqualTo(1) assertThat(mismatches[0].cdn).isEqualTo(99) - assertThat(mismatches[0].digest).isEqualTo(localData[1].digest) + assertThat(mismatches[0].plaintextHash).isEqualTo(localData[1].plaintextHash) + assertThat(mismatches[0].remoteKey).isEqualTo(localData[1].remoteKey) } @Test @@ -300,7 +301,8 @@ class BackupMediaSnapshotTableTest { mediaId = "media_id_$seed", thumbnailMediaId = "thumbnail_media_id_$seed", cdn = cdn, - digest = Util.toByteArray(seed) + plaintextHash = Util.toByteArray(seed), + remoteKey = Util.toByteArray(seed) ) } diff --git a/app/src/androidTest/java/org/thoughtcrime/securesms/messages/SyncMessageProcessorTest_synchronizeDeleteForMe.kt b/app/src/androidTest/java/org/thoughtcrime/securesms/messages/SyncMessageProcessorTest_synchronizeDeleteForMe.kt index d58e5ea9cb..ea215371fa 100644 --- a/app/src/androidTest/java/org/thoughtcrime/securesms/messages/SyncMessageProcessorTest_synchronizeDeleteForMe.kt +++ b/app/src/androidTest/java/org/thoughtcrime/securesms/messages/SyncMessageProcessorTest_synchronizeDeleteForMe.kt @@ -684,7 +684,6 @@ class SyncMessageProcessorTest_synchronizeDeleteForMe { cdn = this.cdn, location = this.remoteLocation, key = this.remoteKey, - iv = this.remoteIv, digest = digest, incrementalDigest = this.incrementalDigest, incrementalMacChunkSize = this.incrementalMacChunkSize, @@ -718,7 +717,6 @@ class SyncMessageProcessorTest_synchronizeDeleteForMe { remoteId = SignalServiceAttachmentRemoteId.V4(this.remoteLocation ?: "some-location"), cdnNumber = this.cdn.cdnNumber, key = this.remoteKey?.let { Base64.decode(it) } ?: Util.getSecretBytes(64), - iv = this.remoteIv ?: Util.getSecretBytes(16), digest = digest, incrementalDigest = this.incrementalDigest, incrementalDigestChunkSize = this.incrementalMacChunkSize, diff --git a/app/src/main/java/org/thoughtcrime/securesms/attachments/ArchivedAttachment.kt b/app/src/main/java/org/thoughtcrime/securesms/attachments/ArchivedAttachment.kt index 492de4a058..0dd4b92971 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/attachments/ArchivedAttachment.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/attachments/ArchivedAttachment.kt @@ -23,13 +23,7 @@ class ArchivedAttachment : Attachment { val archiveCdn: Int? @JvmField - val archiveMediaName: String - - @JvmField - val archiveMediaId: String - - @JvmField - val archiveThumbnailMediaId: String + val plaintextHash: ByteArray constructor( contentType: String?, @@ -37,13 +31,9 @@ class ArchivedAttachment : Attachment { cdn: Int, uploadTimestamp: Long?, key: ByteArray, - iv: ByteArray?, cdnKey: String?, archiveCdn: Int?, - archiveMediaName: String, - archiveMediaId: String, - archiveThumbnailMediaId: String, - digest: ByteArray, + plaintextHash: ByteArray, incrementalMac: ByteArray?, incrementalMacChunkSize: Int?, width: Int?, @@ -66,8 +56,7 @@ class ArchivedAttachment : Attachment { cdn = Cdn.fromCdnNumber(cdn), remoteLocation = cdnKey, remoteKey = Base64.encodeWithoutPadding(key), - remoteIv = iv, - remoteDigest = digest, + remoteDigest = null, incrementalDigest = incrementalMac, fastPreflightId = null, voiceNote = voiceNote, @@ -85,24 +74,18 @@ class ArchivedAttachment : Attachment { uuid = uuid ) { this.archiveCdn = archiveCdn - this.archiveMediaName = archiveMediaName - this.archiveMediaId = archiveMediaId - this.archiveThumbnailMediaId = archiveThumbnailMediaId + this.plaintextHash = plaintextHash } constructor(parcel: Parcel) : super(parcel) { archiveCdn = parcel.readInt().takeIf { it != NO_ARCHIVE_CDN } - archiveMediaName = parcel.readString()!! - archiveMediaId = parcel.readString()!! - archiveThumbnailMediaId = parcel.readString()!! + plaintextHash = parcel.createByteArray()!! } override fun writeToParcel(dest: Parcel, flags: Int) { super.writeToParcel(dest, flags) dest.writeInt(archiveCdn ?: NO_ARCHIVE_CDN) - dest.writeString(archiveMediaName) - dest.writeString(archiveMediaId) - dest.writeString(archiveThumbnailMediaId) + dest.writeByteArray(plaintextHash) } override val uri: Uri? = null diff --git a/app/src/main/java/org/thoughtcrime/securesms/attachments/Attachment.kt b/app/src/main/java/org/thoughtcrime/securesms/attachments/Attachment.kt index 38c8db6410..291298d781 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/attachments/Attachment.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/attachments/Attachment.kt @@ -39,8 +39,6 @@ abstract class Attachment( @JvmField val remoteKey: String?, @JvmField - val remoteIv: ByteArray?, - @JvmField val remoteDigest: ByteArray?, @JvmField val incrementalDigest: ByteArray?, @@ -90,7 +88,6 @@ abstract class Attachment( cdn = Cdn.deserialize(parcel.readInt()), remoteLocation = parcel.readString(), remoteKey = parcel.readString(), - remoteIv = ParcelUtil.readByteArray(parcel), remoteDigest = ParcelUtil.readByteArray(parcel), incrementalDigest = ParcelUtil.readByteArray(parcel), fastPreflightId = parcel.readString(), diff --git a/app/src/main/java/org/thoughtcrime/securesms/attachments/DatabaseAttachment.kt b/app/src/main/java/org/thoughtcrime/securesms/attachments/DatabaseAttachment.kt index 8f47b5ac9a..313e06438a 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/attachments/DatabaseAttachment.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/attachments/DatabaseAttachment.kt @@ -54,7 +54,6 @@ class DatabaseAttachment : Attachment { cdn: Cdn, location: String?, key: String?, - iv: ByteArray?, digest: ByteArray?, incrementalDigest: ByteArray?, incrementalMacChunkSize: Int, @@ -85,7 +84,6 @@ class DatabaseAttachment : Attachment { cdn = cdn, remoteLocation = location, remoteKey = key, - remoteIv = iv, remoteDigest = digest, incrementalDigest = incrementalDigest, fastPreflightId = fastPreflightId, diff --git a/app/src/main/java/org/thoughtcrime/securesms/attachments/PointerAttachment.kt b/app/src/main/java/org/thoughtcrime/securesms/attachments/PointerAttachment.kt index 0ddef132e8..7c14cb93be 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/attachments/PointerAttachment.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/attachments/PointerAttachment.kt @@ -47,7 +47,6 @@ class PointerAttachment : Attachment { cdn = cdn, remoteLocation = location, remoteKey = key, - remoteIv = iv, remoteDigest = digest, incrementalDigest = incrementalDigest, fastPreflightId = fastPreflightId, diff --git a/app/src/main/java/org/thoughtcrime/securesms/attachments/TombstoneAttachment.kt b/app/src/main/java/org/thoughtcrime/securesms/attachments/TombstoneAttachment.kt index a784561846..8c4cb92a49 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/attachments/TombstoneAttachment.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/attachments/TombstoneAttachment.kt @@ -23,7 +23,6 @@ class TombstoneAttachment : Attachment { cdn = Cdn.CDN_0, remoteLocation = null, remoteKey = null, - remoteIv = null, remoteDigest = null, incrementalDigest = null, fastPreflightId = null, @@ -66,7 +65,6 @@ class TombstoneAttachment : Attachment { cdn = Cdn.CDN_0, remoteLocation = null, remoteKey = null, - remoteIv = null, remoteDigest = null, incrementalDigest = incrementalMac, fastPreflightId = null, diff --git a/app/src/main/java/org/thoughtcrime/securesms/attachments/UriAttachment.kt b/app/src/main/java/org/thoughtcrime/securesms/attachments/UriAttachment.kt index e6182fc95a..18439eb2e1 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/attachments/UriAttachment.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/attachments/UriAttachment.kt @@ -75,7 +75,6 @@ class UriAttachment : Attachment { cdn = Cdn.CDN_0, remoteLocation = null, remoteKey = null, - remoteIv = null, remoteDigest = null, incrementalDigest = null, fastPreflightId = fastPreflightId, diff --git a/app/src/main/java/org/thoughtcrime/securesms/attachments/WallpaperAttachment.kt b/app/src/main/java/org/thoughtcrime/securesms/attachments/WallpaperAttachment.kt index 06877ef329..c6e4d417c9 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/attachments/WallpaperAttachment.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/attachments/WallpaperAttachment.kt @@ -20,7 +20,6 @@ class WallpaperAttachment() : Attachment( cdn = Cdn.CDN_0, remoteLocation = null, remoteKey = null, - remoteIv = null, remoteDigest = null, incrementalDigest = null, fastPreflightId = null, diff --git a/app/src/main/java/org/thoughtcrime/securesms/backup/ArchiveUploadProgress.kt b/app/src/main/java/org/thoughtcrime/securesms/backup/ArchiveUploadProgress.kt index fc26147a00..490fea2e55 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/backup/ArchiveUploadProgress.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/backup/ArchiveUploadProgress.kt @@ -22,7 +22,6 @@ import org.thoughtcrime.securesms.database.SignalDatabase import org.thoughtcrime.securesms.dependencies.AppDependencies import org.thoughtcrime.securesms.jobs.ArchiveCommitAttachmentDeletesJob import org.thoughtcrime.securesms.jobs.ArchiveThumbnailUploadJob -import org.thoughtcrime.securesms.jobs.BackfillDigestJob import org.thoughtcrime.securesms.jobs.UploadAttachmentToArchiveJob import org.thoughtcrime.securesms.keyvalue.SignalStore import org.thoughtcrime.securesms.keyvalue.protos.ArchiveUploadProgressState @@ -109,7 +108,6 @@ object ArchiveUploadProgress { ) } - AppDependencies.jobManager.cancelAllInQueue(BackfillDigestJob.QUEUE) AppDependencies.jobManager.cancelAllInQueue(ArchiveCommitAttachmentDeletesJob.ARCHIVE_ATTACHMENT_QUEUE) UploadAttachmentToArchiveJob.getAllQueueKeys().forEach { AppDependencies.jobManager.cancelAllInQueue(it) @@ -126,7 +124,7 @@ object ArchiveUploadProgress { Log.d(TAG, "Flushing job manager queue...") AppDependencies.jobManager.flush() - val queues = setOf(BackfillDigestJob.QUEUE, ArchiveThumbnailUploadJob.KEY, ArchiveCommitAttachmentDeletesJob.ARCHIVE_ATTACHMENT_QUEUE) + UploadAttachmentToArchiveJob.getAllQueueKeys() + val queues = setOf(ArchiveThumbnailUploadJob.KEY, ArchiveCommitAttachmentDeletesJob.ARCHIVE_ATTACHMENT_QUEUE) + UploadAttachmentToArchiveJob.getAllQueueKeys() Log.d(TAG, "Waiting for cancelations to occur...") while (!AppDependencies.jobManager.areQueuesEmpty(queues)) { delay(1.seconds) diff --git a/app/src/main/java/org/thoughtcrime/securesms/backup/v2/BackupRepository.kt b/app/src/main/java/org/thoughtcrime/securesms/backup/v2/BackupRepository.kt index 5e113f6fe7..30215f8d53 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/backup/v2/BackupRepository.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/backup/v2/BackupRepository.kt @@ -691,7 +691,7 @@ object BackupRepository { val localArchivableAttachments = dbSnapshot .attachmentTable .getLocalArchivableAttachments() - .associateBy { MediaName.fromDigest(it.remoteDigest) } + .associateBy { MediaName.fromPlaintextHashAndRemoteKey(it.plaintextHash, it.remoteKey) } localBackupProgressEmitter.onAttachment(0, localArchivableAttachments.size.toLong()) @@ -1965,13 +1965,14 @@ class ArchiveMediaItemIterator(private val cursor: Cursor) : Iterator - val iv = attachment.remoteIv val combinedKey = Base64.decode(attachment.remoteKey) val destination: OutputStream? = filesFileSystem.fileOutputStream(mediaName) @@ -84,7 +83,7 @@ object LocalArchiver { // todo [local-backup] but deal with attachment disappearing/deleted by normal app use try { PaddingInputStream(sourceStream, attachment.size).use { input -> - AttachmentCipherOutputStream(combinedKey, iv, destination).use { output -> + AttachmentCipherOutputStream(combinedKey, null, destination).use { output -> StreamUtil.copy(input, output) } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/backup/v2/util/ArchiveConverterExtensions.kt b/app/src/main/java/org/thoughtcrime/securesms/backup/v2/util/ArchiveConverterExtensions.kt index 0d077d3e44..16e1c825c4 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/backup/v2/util/ArchiveConverterExtensions.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/backup/v2/util/ArchiveConverterExtensions.kt @@ -24,7 +24,6 @@ import org.thoughtcrime.securesms.backup.v2.proto.FilePointer import org.thoughtcrime.securesms.conversation.colors.AvatarColor import org.thoughtcrime.securesms.database.AttachmentTable import org.thoughtcrime.securesms.stickers.StickerLocator -import org.whispersystems.signalservice.api.backup.MediaName import org.whispersystems.signalservice.api.messages.SignalServiceAttachmentPointer import org.whispersystems.signalservice.api.messages.SignalServiceAttachmentRemoteId import org.whispersystems.signalservice.api.util.UuidUtil @@ -48,81 +47,84 @@ fun FilePointer?.toLocalAttachment( ): Attachment? { if (this == null || this.locatorInfo == null) return null - val hasMediaName = this.locatorInfo.mediaName.isNotEmpty() - val hasTransitInfo = this.locatorInfo.transitCdnKey != null + val attachmentType = when { + this.locatorInfo.plaintextHash != null -> AttachmentType.ARCHIVE + this.locatorInfo.encryptedDigest != null && this.locatorInfo.transitCdnKey != null -> AttachmentType.TRANSIT + else -> AttachmentType.INVALID + } - if (hasTransitInfo && !hasMediaName) { - val signalAttachmentPointer = SignalServiceAttachmentPointer( - cdnNumber = this.locatorInfo.transitCdnNumber ?: Cdn.CDN_0.cdnNumber, - remoteId = SignalServiceAttachmentRemoteId.from(locatorInfo.transitCdnKey), - contentType = contentType, - key = this.locatorInfo.key.toByteArray(), - size = Optional.ofNullable(locatorInfo.size), - preview = Optional.empty(), - width = this.width ?: 0, - height = this.height ?: 0, - digest = Optional.ofNullable(this.locatorInfo.digest.toByteArray()), - incrementalDigest = Optional.ofNullable(this.incrementalMac?.toByteArray()), - incrementalMacChunkSize = this.incrementalMacChunkSize ?: 0, - fileName = Optional.ofNullable(fileName), - voiceNote = voiceNote, - isBorderless = borderless, - isGif = gif, - caption = Optional.ofNullable(this.caption), - blurHash = Optional.ofNullable(this.blurHash), - uploadTimestamp = this.locatorInfo.transitTierUploadTimestamp?.clampToValidBackupRange() ?: 0, - uuid = UuidUtil.fromByteStringOrNull(uuid) - ) - return PointerAttachment.forPointer( - pointer = Optional.of(signalAttachmentPointer), - stickerLocator = stickerLocator, - transferState = if (wasDownloaded) AttachmentTable.TRANSFER_NEEDS_RESTORE else AttachmentTable.TRANSFER_PROGRESS_PENDING - ).orNull() - } else if (!hasMediaName) { - return TombstoneAttachment( - contentType = contentType, - incrementalMac = this.incrementalMac?.toByteArray(), - incrementalMacChunkSize = this.incrementalMacChunkSize, - width = this.width, - height = this.height, - caption = this.caption, - fileName = this.fileName, - blurHash = this.blurHash, - voiceNote = voiceNote, - borderless = borderless, - gif = gif, - quote = quote, - stickerLocator = stickerLocator, - uuid = UuidUtil.fromByteStringOrNull(uuid) - ) - } else { - return ArchivedAttachment( - contentType = contentType, - size = this.locatorInfo.size.toLong(), - cdn = this.locatorInfo.transitCdnNumber ?: Cdn.CDN_0.cdnNumber, - uploadTimestamp = this.locatorInfo.transitTierUploadTimestamp ?: 0, - key = this.locatorInfo.key.toByteArray(), - iv = null, - cdnKey = this.locatorInfo.transitCdnKey?.nullIfBlank(), - archiveCdn = this.locatorInfo.mediaTierCdnNumber, - archiveMediaName = this.locatorInfo.mediaName, - archiveMediaId = importState.mediaRootBackupKey.deriveMediaId(MediaName(this.locatorInfo.mediaName)).encode(), - archiveThumbnailMediaId = importState.mediaRootBackupKey.deriveMediaId(MediaName.forThumbnailFromMediaName(this.locatorInfo.mediaName)).encode(), - digest = this.locatorInfo.digest.toByteArray(), - incrementalMac = this.incrementalMac?.toByteArray(), - incrementalMacChunkSize = this.incrementalMacChunkSize, - width = this.width, - height = this.height, - caption = this.caption, - blurHash = this.blurHash, - voiceNote = voiceNote, - borderless = borderless, - gif = gif, - quote = quote, - stickerLocator = stickerLocator, - uuid = UuidUtil.fromByteStringOrNull(uuid), - fileName = fileName - ) + return when (attachmentType) { + AttachmentType.ARCHIVE -> { + ArchivedAttachment( + contentType = contentType, + size = this.locatorInfo.size.toLong(), + cdn = this.locatorInfo.transitCdnNumber ?: Cdn.CDN_0.cdnNumber, + uploadTimestamp = this.locatorInfo.transitTierUploadTimestamp ?: 0, + key = this.locatorInfo.key.toByteArray(), + cdnKey = this.locatorInfo.transitCdnKey?.nullIfBlank(), + archiveCdn = this.locatorInfo.mediaTierCdnNumber, + plaintextHash = this.locatorInfo.plaintextHash!!.toByteArray(), + incrementalMac = this.incrementalMac?.toByteArray(), + incrementalMacChunkSize = this.incrementalMacChunkSize, + width = this.width, + height = this.height, + caption = this.caption, + blurHash = this.blurHash, + voiceNote = voiceNote, + borderless = borderless, + stickerLocator = stickerLocator, + gif = gif, + quote = quote, + uuid = UuidUtil.fromByteStringOrNull(uuid), + fileName = fileName + ) + } + AttachmentType.TRANSIT -> { + val signalAttachmentPointer = SignalServiceAttachmentPointer( + cdnNumber = this.locatorInfo.transitCdnNumber ?: Cdn.CDN_0.cdnNumber, + remoteId = SignalServiceAttachmentRemoteId.from(locatorInfo.transitCdnKey!!), + contentType = contentType, + key = this.locatorInfo.key.toByteArray(), + size = Optional.ofNullable(locatorInfo.size), + preview = Optional.empty(), + width = this.width ?: 0, + height = this.height ?: 0, + digest = Optional.ofNullable(this.locatorInfo.encryptedDigest!!.toByteArray()), + incrementalDigest = Optional.ofNullable(this.incrementalMac?.toByteArray()), + incrementalMacChunkSize = this.incrementalMacChunkSize ?: 0, + fileName = Optional.ofNullable(fileName), + voiceNote = voiceNote, + isBorderless = borderless, + isGif = gif, + caption = Optional.ofNullable(this.caption), + blurHash = Optional.ofNullable(this.blurHash), + uploadTimestamp = this.locatorInfo.transitTierUploadTimestamp?.clampToValidBackupRange() ?: 0, + uuid = UuidUtil.fromByteStringOrNull(uuid) + ) + PointerAttachment.forPointer( + pointer = Optional.of(signalAttachmentPointer), + stickerLocator = stickerLocator, + transferState = if (wasDownloaded) AttachmentTable.TRANSFER_NEEDS_RESTORE else AttachmentTable.TRANSFER_PROGRESS_PENDING + ).orNull() + } + AttachmentType.INVALID -> { + TombstoneAttachment( + contentType = contentType, + incrementalMac = this.incrementalMac?.toByteArray(), + incrementalMacChunkSize = this.incrementalMacChunkSize, + width = this.width, + height = this.height, + caption = this.caption, + fileName = this.fileName, + blurHash = this.blurHash, + voiceNote = voiceNote, + borderless = borderless, + gif = gif, + quote = quote, + stickerLocator = stickerLocator, + uuid = UuidUtil.fromByteStringOrNull(uuid) + ) + } } } @@ -192,21 +194,17 @@ fun FilePointer.Builder.setLegacyLocators(attachment: DatabaseAttachment, mediaA } fun DatabaseAttachment.toLocatorInfo(): FilePointer.LocatorInfo { - if (this.remoteKey.isNullOrBlank() || this.remoteDigest == null || this.size == 0L) { - return FilePointer.LocatorInfo() - } + val attachmentType = this.toRemoteAttachmentType() - if (this.transferState == AttachmentTable.TRANSFER_PROGRESS_PERMANENT_FAILURE && this.archiveTransferState != AttachmentTable.ArchiveTransferState.FINISHED) { + if (attachmentType == AttachmentType.INVALID) { return FilePointer.LocatorInfo() } val locatorBuilder = FilePointer.LocatorInfo.Builder() - val remoteKey = Base64.decode(this.remoteKey).toByteString() - val archiveMediaName = this.getMediaName()?.toString() + val remoteKey = Base64.decode(this.remoteKey!!).toByteString() locatorBuilder.key = remoteKey - locatorBuilder.digest = this.remoteDigest.toByteString() locatorBuilder.size = this.size.toInt() if (this.remoteLocation.isNotNullOrBlank()) { @@ -215,8 +213,17 @@ fun DatabaseAttachment.toLocatorInfo(): FilePointer.LocatorInfo { locatorBuilder.transitTierUploadTimestamp = this.uploadTimestamp.takeIf { it > 0 }?.clampToValidBackupRange() } - locatorBuilder.mediaTierCdnNumber = this.archiveCdn?.takeIf { archiveMediaName != null } - locatorBuilder.mediaName = archiveMediaName.emptyIfNull() + @Suppress("KotlinConstantConditions") + when (attachmentType) { + AttachmentType.ARCHIVE -> { + locatorBuilder.plaintextHash = Base64.decode(this.dataHash!!).toByteString() + locatorBuilder.mediaTierCdnNumber = this.archiveCdn + } + AttachmentType.TRANSIT -> { + locatorBuilder.encryptedDigest = this.remoteDigest!!.toByteString() + } + AttachmentType.INVALID -> Unit + } return locatorBuilder.build() } @@ -260,3 +267,30 @@ fun RemoteAvatarColor.toLocal(): AvatarColor { RemoteAvatarColor.A210 -> AvatarColor.A210 } } + +private fun DatabaseAttachment.toRemoteAttachmentType(): AttachmentType { + if (this.remoteKey.isNullOrBlank()) { + return AttachmentType.INVALID + } + + if (this.transferState == AttachmentTable.TRANSFER_PROGRESS_PERMANENT_FAILURE && this.archiveTransferState != AttachmentTable.ArchiveTransferState.FINISHED) { + return AttachmentType.INVALID + } + + val activelyOnArchiveCdn = this.archiveTransferState == AttachmentTable.ArchiveTransferState.FINISHED + val couldBeOnArchiveCdn = this.transferState == AttachmentTable.TRANSFER_PROGRESS_DONE && this.archiveTransferState != AttachmentTable.ArchiveTransferState.PERMANENT_FAILURE + + if (this.dataHash != null && (activelyOnArchiveCdn || couldBeOnArchiveCdn)) { + return AttachmentType.ARCHIVE + } + + if (this.remoteDigest != null && this.remoteLocation.isNotNullOrBlank()) { + return AttachmentType.TRANSIT + } + + return AttachmentType.INVALID +} + +private enum class AttachmentType { + TRANSIT, ARCHIVE, INVALID +} diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/AttachmentTable.kt b/app/src/main/java/org/thoughtcrime/securesms/database/AttachmentTable.kt index 98cc123760..0f3d237e2c 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/AttachmentTable.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/database/AttachmentTable.kt @@ -36,7 +36,6 @@ import org.signal.core.util.Base64 import org.signal.core.util.SqlUtil import org.signal.core.util.StreamUtil import org.signal.core.util.ThreadUtil -import org.signal.core.util.allMatch import org.signal.core.util.copyTo import org.signal.core.util.count import org.signal.core.util.delete @@ -61,7 +60,6 @@ import org.signal.core.util.requireNonNullString import org.signal.core.util.requireObject import org.signal.core.util.requireString import org.signal.core.util.select -import org.signal.core.util.stream.LimitedInputStream import org.signal.core.util.stream.NullOutputStream import org.signal.core.util.toInt import org.signal.core.util.update @@ -79,17 +77,6 @@ import org.thoughtcrime.securesms.crypto.AttachmentSecret import org.thoughtcrime.securesms.crypto.ClassicDecryptingPartInputStream import org.thoughtcrime.securesms.crypto.ModernDecryptingPartInputStream import org.thoughtcrime.securesms.crypto.ModernEncryptingPartOutputStream -import org.thoughtcrime.securesms.database.AttachmentTable.ArchiveTransferState.COPY_PENDING -import org.thoughtcrime.securesms.database.AttachmentTable.ArchiveTransferState.FINISHED -import org.thoughtcrime.securesms.database.AttachmentTable.ArchiveTransferState.NONE -import org.thoughtcrime.securesms.database.AttachmentTable.ArchiveTransferState.PERMANENT_FAILURE -import org.thoughtcrime.securesms.database.AttachmentTable.ArchiveTransferState.UPLOAD_IN_PROGRESS -import org.thoughtcrime.securesms.database.AttachmentTable.ArchiveTransferState.entries -import org.thoughtcrime.securesms.database.AttachmentTable.Companion.DATA_FILE -import org.thoughtcrime.securesms.database.AttachmentTable.Companion.DATA_HASH_END -import org.thoughtcrime.securesms.database.AttachmentTable.Companion.PREUPLOAD_MESSAGE_ID -import org.thoughtcrime.securesms.database.AttachmentTable.Companion.TRANSFER_PROGRESS_DONE -import org.thoughtcrime.securesms.database.AttachmentTable.ThumbnailRestoreState.entries import org.thoughtcrime.securesms.database.MessageTable.SyncMessageId import org.thoughtcrime.securesms.database.SignalDatabase.Companion.messages import org.thoughtcrime.securesms.database.SignalDatabase.Companion.threads @@ -144,7 +131,6 @@ class AttachmentTable( const val MESSAGE_ID = "message_id" const val CONTENT_TYPE = "content_type" const val REMOTE_KEY = "remote_key" - const val REMOTE_IV = "remote_iv" const val REMOTE_LOCATION = "remote_location" const val REMOTE_DIGEST = "remote_digest" const val REMOTE_INCREMENTAL_DIGEST = "remote_incremental_digest" @@ -203,7 +189,6 @@ class AttachmentTable( MESSAGE_ID, CONTENT_TYPE, REMOTE_KEY, - REMOTE_IV, REMOTE_LOCATION, REMOTE_DIGEST, REMOTE_INCREMENTAL_DIGEST, @@ -284,7 +269,6 @@ class AttachmentTable( $THUMBNAIL_RANDOM BLOB DEFAULT NULL, $THUMBNAIL_RESTORE_STATE INTEGER DEFAULT ${ThumbnailRestoreState.NONE.value}, $ATTACHMENT_UUID TEXT DEFAULT NULL, - $REMOTE_IV BLOB DEFAULT NULL, $OFFLOAD_RESTORED_AT INTEGER DEFAULT 0 ) """ @@ -297,7 +281,7 @@ class AttachmentTable( "CREATE INDEX IF NOT EXISTS attachment_transfer_state_index ON $TABLE_NAME ($TRANSFER_STATE);", "CREATE INDEX IF NOT EXISTS attachment_sticker_pack_id_index ON $TABLE_NAME ($STICKER_PACK_ID);", "CREATE INDEX IF NOT EXISTS attachment_data_hash_start_index ON $TABLE_NAME ($DATA_HASH_START);", - "CREATE INDEX IF NOT EXISTS attachment_data_hash_end_index ON $TABLE_NAME ($DATA_HASH_END);", + "CREATE INDEX IF NOT EXISTS attachment_data_hash_end_remote_key_index ON $TABLE_NAME ($DATA_HASH_END, $REMOTE_KEY);", "CREATE INDEX IF NOT EXISTS $DATA_FILE_INDEX ON $TABLE_NAME ($DATA_FILE);", "CREATE INDEX IF NOT EXISTS attachment_archive_transfer_state ON $TABLE_NAME ($ARCHIVE_TRANSFER_STATE);", "CREATE INDEX IF NOT EXISTS attachment_remote_digest_index ON $TABLE_NAME ($REMOTE_DIGEST);" @@ -511,7 +495,7 @@ class AttachmentTable( return readableDatabase .select(*PROJECTION) .from(TABLE_NAME) - .where("$REMOTE_KEY IS NOT NULL AND $REMOTE_DIGEST IS NOT NULL AND $REMOTE_IV IS NOT NULL AND $DATA_FILE IS NOT NULL") + .where("$REMOTE_KEY IS NOT NULL AND $DATA_HASH_END IS NOT NULL AND $DATA_FILE IS NOT NULL") .orderBy("$ID DESC") .run() .readToList { @@ -519,16 +503,15 @@ class AttachmentTable( file = File(it.requireNonNullString(DATA_FILE)), random = it.requireNonNullBlob(DATA_RANDOM), size = it.requireLong(DATA_SIZE), - remoteDigest = it.requireBlob(REMOTE_DIGEST)!!, remoteKey = it.requireBlob(REMOTE_KEY)!!, - remoteIv = it.requireBlob(REMOTE_IV)!! + plaintextHash = Base64.decode(it.requireNonNullString(DATA_HASH_END)) ) } } fun getRestorableAttachments(batchSize: Int): List { return readableDatabase - .select(ID, MESSAGE_ID, DATA_SIZE, REMOTE_DIGEST, REMOTE_KEY) + .select(ID, MESSAGE_ID, DATA_SIZE, DATA_HASH_END, REMOTE_KEY) .from(TABLE_NAME) .where("$TRANSFER_STATE = ?", TRANSFER_NEEDS_RESTORE) .limit(batchSize) @@ -539,7 +522,7 @@ class AttachmentTable( attachmentId = AttachmentId(it.requireLong(ID)), mmsId = it.requireLong(MESSAGE_ID), size = it.requireLong(DATA_SIZE), - remoteDigest = it.requireBlob(REMOTE_DIGEST), + plaintextHash = it.requireBlob(DATA_HASH_END), remoteKey = it.requireBlob(REMOTE_KEY) ) } @@ -549,7 +532,7 @@ class AttachmentTable( return readableDatabase .select(ID, MESSAGE_ID, DATA_SIZE, REMOTE_DIGEST, REMOTE_KEY) .from(TABLE_NAME) - .where("$TRANSFER_STATE = ?", TRANSFER_RESTORE_OFFLOADED) + .where("$TRANSFER_STATE = ? AND $DATA_HASH_END NOT NULL AND $REMOTE_KEY NOT NULL", TRANSFER_RESTORE_OFFLOADED) .orderBy("$ID DESC") .run() .readToList { @@ -557,8 +540,8 @@ class AttachmentTable( attachmentId = AttachmentId(it.requireLong(ID)), mmsId = it.requireLong(MESSAGE_ID), size = it.requireLong(DATA_SIZE), - remoteDigest = it.requireBlob(REMOTE_DIGEST), - remoteKey = it.requireBlob(REMOTE_KEY) + plaintextHash = it.requireNonNullBlob(DATA_HASH_END), + remoteKey = it.requireNonNullBlob(REMOTE_KEY) ) } } @@ -595,49 +578,31 @@ class AttachmentTable( } /** - * At archive creation time, we need to ensure that all relevant attachments have populated (key, iv, digest) tuples. + * At archive creation time, we need to ensure that all relevant attachments have populated [REMOTE_KEY]s. * This does that. */ - fun createKeyIvDigestForAttachmentsThatNeedArchiveUpload(): Int { + fun createRemoteKeyForAttachmentsThatNeedArchiveUpload(): Int { var count = 0 - writableDatabase.select(ID, REMOTE_KEY, REMOTE_IV, REMOTE_DIGEST, DATA_FILE, DATA_RANDOM) + writableDatabase.select(ID, REMOTE_KEY, DATA_FILE, DATA_RANDOM) .from(TABLE_NAME) .where( """ $ARCHIVE_TRANSFER_STATE = ${ArchiveTransferState.NONE.value} AND $DATA_FILE NOT NULL AND $TRANSFER_STATE = $TRANSFER_PROGRESS_DONE AND - ( - $REMOTE_KEY IS NULL OR - $REMOTE_IV IS NULL OR - $REMOTE_DIGEST IS NULL - ) + $REMOTE_KEY IS NULL """ ) .run() .forEach { cursor -> val attachmentId = AttachmentId(cursor.requireLong(ID)) - Log.w(TAG, "[createKeyIvDigestForAttachmentsThatNeedArchiveUpload][$attachmentId] Missing key, iv, or digest. Generating.") + Log.w(TAG, "[createRemoteKeyForAttachmentsThatNeedArchiveUpload][$attachmentId] Missing key. Generating.") val key = cursor.requireString(REMOTE_KEY)?.let { Base64.decode(it) } ?: Util.getSecretBytes(64) - val iv = cursor.requireBlob(REMOTE_IV) ?: Util.getSecretBytes(16) - val digest = run { - val fileInfo = getDataFileInfo(attachmentId)!! - try { - calculateDigest(fileInfo, key, iv) - } catch (e: FileNotFoundException) { - Log.w(TAG, "[createKeyIvDigestForAttachmentsThatNeedArchiveUpload][$attachmentId] Could not find file ${fileInfo.file}. Delete all later?") - return@forEach - } - } writableDatabase.update(TABLE_NAME) - .values( - REMOTE_KEY to Base64.encodeWithPadding(key), - REMOTE_IV to iv, - REMOTE_DIGEST to digest - ) + .values(REMOTE_KEY to Base64.encodeWithPadding(key)) .where("$ID = ?", attachmentId.id) .run() @@ -717,14 +682,14 @@ class AttachmentTable( /** * Sets the archive transfer state for the given attachment by digest. */ - fun resetArchiveTransferStateByDigest(digest: ByteArray) { + fun resetArchiveTransferStateByPlaintextHashAndRemoteKey(plaintextHash: ByteArray, remoteKey: ByteArray) { writableDatabase .update(TABLE_NAME) .values( ARCHIVE_TRANSFER_STATE to ArchiveTransferState.NONE.value, ARCHIVE_CDN to null ) - .where("$REMOTE_DIGEST = ?", digest) + .where("$DATA_HASH_END = ? AND $REMOTE_KEY = ?", plaintextHash, remoteKey) .run() } @@ -1188,11 +1153,9 @@ class AttachmentTable( * When we find out about a new inbound attachment pointer, we insert a row for it that contains all the info we need to download it via [insertAttachmentWithData]. * Later, we download the data for that pointer. Call this method once you have the data to associate it with the attachment. At this point, it is assumed * that the content of the attachment will never change. - * - * @return True if we had to change the digest as part of saving the file, otherwise false. */ @Throws(MmsException::class) - fun finalizeAttachmentAfterDownload(mmsId: Long, attachmentId: AttachmentId, inputStream: LimitedInputStream, iv: ByteArray, offloadRestoredAt: Duration? = null): Boolean { + fun finalizeAttachmentAfterDownload(mmsId: Long, attachmentId: AttachmentId, inputStream: InputStream, offloadRestoredAt: Duration? = null) { Log.i(TAG, "[finalizeAttachmentAfterDownload] Finalizing downloaded data for $attachmentId. (MessageId: $mmsId, $attachmentId)") val existingPlaceholder: DatabaseAttachment = getAttachment(attachmentId) ?: throw MmsException("No attachment found for id: $attachmentId") @@ -1200,23 +1163,6 @@ class AttachmentTable( val fileWriteResult: DataFileWriteResult = writeToDataFile(newDataFile(context), inputStream, TransformProperties.empty(), closeInputStream = false) val transferFile: File? = getTransferFile(databaseHelper.signalReadableDatabase, attachmentId) - val paddingAllZeroes = inputStream.use { limitStream -> - limitStream.leftoverStream().allMatch { it == 0x00.toByte() } - } - - // Existing digest may be null for non-user attachments, like things pulled from S3 - val digest = if (existingPlaceholder.remoteDigest != null && paddingAllZeroes) { - Log.d(TAG, "[finalizeAttachmentAfterDownload] $attachmentId has all-zero padding. Digest is good.") - existingPlaceholder.remoteDigest - } else { - Log.w(TAG, "[finalizeAttachmentAfterDownload] $attachmentId has non-zero padding bytes. Recomputing digest.") - - val key = Base64.decode(existingPlaceholder.remoteKey!!) - calculateDigest(fileWriteResult, key, iv) - } - - val digestChanged = !digest.contentEquals(existingPlaceholder.remoteDigest) - val foundDuplicate = writableDatabase.withinTransaction { db -> // We can look and see if we have any exact matches on hash_ends and dedupe the file if we see one. // We don't look at hash_start here because that could result in us matching on a file that got compressed down to something smaller, effectively lowering @@ -1263,15 +1209,10 @@ class AttachmentTable( values.put(REMOTE_LOCATION, existingPlaceholder.remoteLocation) values.put(CDN_NUMBER, existingPlaceholder.cdn.serialize()) values.put(REMOTE_KEY, existingPlaceholder.remoteKey!!) - values.put(REMOTE_IV, iv) - values.put(REMOTE_DIGEST, digest) + values.put(REMOTE_DIGEST, existingPlaceholder.remoteDigest) values.put(REMOTE_INCREMENTAL_DIGEST, existingPlaceholder.incrementalDigest) values.put(REMOTE_INCREMENTAL_DIGEST_CHUNK_SIZE, existingPlaceholder.incrementalMacChunkSize) - if (digestChanged) { - values.put(UPLOAD_TIMESTAMP, 0) - } - if (offloadRestoredAt != null) { values.put(OFFLOAD_RESTORED_AT, offloadRestoredAt.inWholeMilliseconds) } @@ -1313,8 +1254,6 @@ class AttachmentTable( if (MediaUtil.isAudio(existingPlaceholder)) { GenerateAudioWaveFormJob.enqueue(existingPlaceholder.attachmentId) } - - return digestChanged } @Throws(IOException::class) @@ -1390,7 +1329,6 @@ class AttachmentTable( CDN_NUMBER to uploadResult.cdnNumber, REMOTE_LOCATION to uploadResult.remoteId.toString(), REMOTE_KEY to Base64.encodeWithPadding(uploadResult.key), - REMOTE_IV to uploadResult.iv, REMOTE_DIGEST to uploadResult.digest, REMOTE_INCREMENTAL_DIGEST to uploadResult.incrementalDigest, REMOTE_INCREMENTAL_DIGEST_CHUNK_SIZE to uploadResult.incrementalDigestChunkSize, @@ -1500,9 +1438,8 @@ class AttachmentTable( } } - fun createKeyIvIfNecessary(attachmentId: AttachmentId) { + fun createRemoteKeyIfNecessary(attachmentId: AttachmentId) { val key = Util.getSecretBytes(64) - val iv = Util.getSecretBytes(16) writableDatabase.withinTransaction { writableDatabase @@ -1510,12 +1447,6 @@ class AttachmentTable( .values(REMOTE_KEY to Base64.encodeWithPadding(key)) .where("$ID = ? AND $REMOTE_KEY IS NULL", attachmentId.id) .run() - - writableDatabase - .update(TABLE_NAME) - .values(REMOTE_IV to iv) - .where("$ID = ? AND $REMOTE_IV IS NULL", attachmentId.id) - .run() } } @@ -1562,30 +1493,14 @@ class AttachmentTable( .readToList { it.requireNonNullString(DATA_FILE) } } - /** - * As part of the digest backfill process, this updates the (key, IV, digest) tuple for an attachment. - */ - fun updateKeyIvDigest(attachmentId: AttachmentId, key: ByteArray, iv: ByteArray, digest: ByteArray) { - writableDatabase - .update(TABLE_NAME) - .values( - REMOTE_KEY to Base64.encodeWithPadding(key), - REMOTE_IV to iv, - REMOTE_DIGEST to digest - ) - .where("$ID = ?", attachmentId.id) - .run() - } - /** * As part of the digest backfill process, this updates the (key, IV, digest) tuple for all attachments that share a data file (and are done downloading). */ - fun updateKeyIvDigestByDataFile(dataFile: String, key: ByteArray, iv: ByteArray, digest: ByteArray) { + fun updateRemoteKeyAndDigestByDataFile(dataFile: String, key: ByteArray, digest: ByteArray) { writableDatabase .update(TABLE_NAME) .values( REMOTE_KEY to Base64.encodeWithPadding(key), - REMOTE_IV to iv, REMOTE_DIGEST to digest ) .where("$DATA_FILE = ? AND $TRANSFER_STATE = $TRANSFER_PROGRESS_DONE", dataFile) @@ -1907,37 +1822,6 @@ class AttachmentTable( notifyConversationListeners(threadId) } - /** - * This will ensure that a (key/iv/digest) tuple exists for an attachment, filling each one if necessary. - */ - @Throws(IOException::class) - fun createKeyIvDigestIfNecessary(attachment: DatabaseAttachment) { - if (attachment.remoteKey != null && attachment.remoteIv != null && attachment.remoteDigest != null) { - return - } - - val attachmentId = attachment.attachmentId - - Log.w(TAG, "[createKeyIvDigestIfNecessary][$attachmentId] Missing one of (key, iv, digest). Filling in the gaps.") - - val key = attachment.remoteKey?.let { Base64.decode(it) } ?: Util.getSecretBytes(64) - val iv = attachment.remoteIv ?: Util.getSecretBytes(16) - val digest: ByteArray = run { - val fileInfo = getDataFileInfo(attachmentId) ?: throw IOException("No data file found for $attachmentId!") - calculateDigest(fileInfo, key, iv) - } - - writableDatabase - .update(TABLE_NAME) - .values( - REMOTE_KEY to Base64.encodeWithPadding(key), - REMOTE_IV to iv, - REMOTE_DIGEST to digest - ) - .where("$ID = ?", attachmentId.id) - .run() - } - fun getAttachments(cursor: Cursor): List { return try { if (cursor.getColumnIndex(ATTACHMENT_JSON_ALIAS) != -1) { @@ -1966,7 +1850,6 @@ class AttachmentTable( cdn = Cdn.deserialize(jsonObject.getInt(CDN_NUMBER)), location = jsonObject.getString(REMOTE_LOCATION), key = jsonObject.getString(REMOTE_KEY), - iv = null, digest = null, incrementalDigest = null, incrementalMacChunkSize = 0, @@ -2067,11 +1950,11 @@ class AttachmentTable( /** * Updates all attachments that share the same digest with the given archive CDN. */ - fun setArchiveCdnByDigest(digest: ByteArray, archiveCdn: Int) { + fun setArchiveCdnByPlaintextHashAndRemoteKey(plaintextHash: ByteArray, remoteKey: ByteArray, archiveCdn: Int) { writableDatabase .update(TABLE_NAME) .values(ARCHIVE_CDN to archiveCdn) - .where("$REMOTE_DIGEST = ?", digest) + .where("$DATA_HASH_END= ? AND $REMOTE_KEY = ?", plaintextHash, remoteKey) .run() } @@ -2098,11 +1981,7 @@ class AttachmentTable( .run() } - private fun calculateDigest(fileInfo: DataFileWriteResult, key: ByteArray, iv: ByteArray): ByteArray { - return calculateDigest(file = fileInfo.file, random = fileInfo.random, length = fileInfo.length, key = key, iv = iv) - } - - private fun calculateDigest(fileInfo: DataFileInfo, key: ByteArray, iv: ByteArray): ByteArray { + private fun calculateDigest(fileInfo: DataFileWriteResult, key: ByteArray, iv: ByteArray = Util.getSecretBytes(16)): ByteArray { return calculateDigest(file = fileInfo.file, random = fileInfo.random, length = fileInfo.length, key = key, iv = iv) } @@ -2364,6 +2243,8 @@ class AttachmentTable( Log.d(TAG, "[insertAttachment] Inserting attachment for messageId $messageId.") val attachmentId: AttachmentId = writableDatabase.withinTransaction { db -> + val plaintextHash = attachment.plaintextHash.takeIf { it.isNotEmpty() }?.let { Base64.encodeWithPadding(it) } + val contentValues = ContentValues().apply { put(MESSAGE_ID, messageId) put(CONTENT_TYPE, attachment.contentType) @@ -2389,6 +2270,11 @@ class AttachmentTable( put(ATTACHMENT_UUID, attachment.uuid?.toString()) put(BLUR_HASH, attachment.blurHash?.hash) + if (plaintextHash != null) { + put(DATA_HASH_START, plaintextHash) + put(DATA_HASH_END, plaintextHash) + } + attachment.stickerLocator?.let { sticker -> put(STICKER_PACK_ID, sticker.packId) put(STICKER_PACK_KEY, sticker.packKey) @@ -2525,7 +2411,6 @@ class AttachmentTable( contentValues.put(REMOTE_LOCATION, uploadTemplate?.remoteLocation) contentValues.put(REMOTE_DIGEST, uploadTemplate?.remoteDigest) contentValues.put(REMOTE_KEY, uploadTemplate?.remoteKey) - contentValues.put(REMOTE_IV, uploadTemplate?.remoteIv) contentValues.put(FILE_NAME, StorageUtil.getCleanFileName(attachment.fileName)) contentValues.put(FAST_PREFLIGHT_ID, attachment.fastPreflightId) contentValues.put(VOICE_NOTE, if (attachment.voiceNote) 1 else 0) @@ -2576,7 +2461,7 @@ class AttachmentTable( fun insertWallpaper(dataStream: InputStream): AttachmentId { return insertAttachmentWithData(WALLPAPER_MESSAGE_ID, dataStream, WallpaperAttachment(), quote = false).also { id -> - createKeyIvIfNecessary(id) + createRemoteKeyIfNecessary(id) } } @@ -2673,7 +2558,6 @@ class AttachmentTable( cdn = cursor.requireObject(CDN_NUMBER, Cdn.Serializer), location = cursor.requireString(REMOTE_LOCATION), key = cursor.requireString(REMOTE_KEY), - iv = cursor.requireBlob(REMOTE_IV), digest = cursor.requireBlob(REMOTE_DIGEST), incrementalDigest = cursor.requireBlob(REMOTE_INCREMENTAL_DIGEST), incrementalMacChunkSize = cursor.requireInt(REMOTE_INCREMENTAL_DIGEST_CHUNK_SIZE), @@ -3043,16 +2927,15 @@ class AttachmentTable( val file: File, val random: ByteArray, val size: Long, - val remoteDigest: ByteArray, - val remoteKey: ByteArray, - val remoteIv: ByteArray + val plaintextHash: ByteArray, + val remoteKey: ByteArray ) class RestorableAttachment( val attachmentId: AttachmentId, val mmsId: Long, val size: Long, - val remoteDigest: ByteArray?, + val plaintextHash: ByteArray?, val remoteKey: ByteArray? ) { override fun equals(other: Any?): Boolean { diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/BackupMediaSnapshotTable.kt b/app/src/main/java/org/thoughtcrime/securesms/database/BackupMediaSnapshotTable.kt index 747f3b7fe9..398e26e057 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/BackupMediaSnapshotTable.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/database/BackupMediaSnapshotTable.kt @@ -91,9 +91,14 @@ class BackupMediaSnapshotTable(context: Context, database: SignalDatabase) : Dat const val LAST_SEEN_ON_REMOTE_SNAPSHOT_VERSION = "last_seen_on_remote_snapshot_version" /** - * The remote digest for the media object. This is used to find matching attachments in the attachment table when necessary. + * The plaintext hash of the media object. This is used to find matching attachments in the attachment table when necessary. */ - const val REMOTE_DIGEST = "remote_digest" + const val PLAINTEXT_HASH = "plaintext_hash" + + /** + * The remote that was used for encrypting for the media object. This is used to find matching attachments in the attachment table when necessary. + */ + const val REMOTE_KEY = "remote_key" /** Constant representing a [SNAPSHOT_VERSION] version that has not yet been set. */ const val UNKNOWN_VERSION = -1 @@ -111,7 +116,8 @@ class BackupMediaSnapshotTable(context: Context, database: SignalDatabase) : Dat $SNAPSHOT_VERSION INTEGER NOT NULL DEFAULT $UNKNOWN_VERSION, $IS_PENDING INTEGER NOT NULL DEFAULT 0, $IS_THUMBNAIL INTEGER NOT NULL DEFAULT 0, - $REMOTE_DIGEST BLOB NOT NULL, + $PLAINTEXT_HASH BLOB NOT NULL, + $REMOTE_KEY BLOB NOT NULL, $LAST_SEEN_ON_REMOTE_SNAPSHOT_VERSION INTEGER NOT NULL DEFAULT 0 ) """.trimIndent() @@ -130,11 +136,11 @@ class BackupMediaSnapshotTable(context: Context, database: SignalDatabase) : Dat .chunked(SqlUtil.MAX_QUERY_ARGS) .forEach { chunk -> writePendingMediaObjectsChunk( - chunk.map { MediaEntry(it.mediaId, it.cdn, it.digest, isThumbnail = false) } + chunk.map { MediaEntry(it.mediaId, it.cdn, it.plaintextHash, it.remoteKey, isThumbnail = false) } ) writePendingMediaObjectsChunk( - chunk.map { MediaEntry(it.thumbnailMediaId, it.cdn, it.digest, isThumbnail = true) } + chunk.map { MediaEntry(it.thumbnailMediaId, it.cdn, it.plaintextHash, it.remoteKey, isThumbnail = true) } ) } } @@ -238,14 +244,15 @@ class BackupMediaSnapshotTable(context: Context, database: SignalDatabase) : Dat return readableDatabase.rawQuery( """ WITH input_pairs($MEDIA_ID, $CDN) AS (VALUES $inputValues) - SELECT a.$REMOTE_DIGEST, b.$CDN + SELECT a.$PLAINTEXT_HASH, a.$REMOTE_KEY b.$CDN FROM $TABLE_NAME a JOIN input_pairs b ON a.$MEDIA_ID = b.$MEDIA_ID WHERE a.$CDN != b.$CDN AND a.$IS_THUMBNAIL = 0 AND $SNAPSHOT_VERSION = $MAX_VERSION """ ).readToList { cursor -> CdnMismatchResult( - digest = cursor.requireNonNullBlob(REMOTE_DIGEST), + plaintextHash = cursor.requireNonNullBlob(PLAINTEXT_HASH), + remoteKey = cursor.requireNonNullBlob(REMOTE_KEY), cdn = cursor.requireInt(CDN) ) } @@ -277,7 +284,7 @@ class BackupMediaSnapshotTable(context: Context, database: SignalDatabase) : Dat */ fun getMediaObjectsLastSeenOnCdnBeforeSnapshotVersion(snapshotVersion: Long): Cursor { return readableDatabase - .select(MEDIA_ID, CDN, REMOTE_DIGEST, IS_THUMBNAIL) + .select(MEDIA_ID, CDN, PLAINTEXT_HASH, REMOTE_KEY, IS_THUMBNAIL) .from(TABLE_NAME) .where("$LAST_SEEN_ON_REMOTE_SNAPSHOT_VERSION < $snapshotVersion AND $SNAPSHOT_VERSION = $snapshotVersion") .run() @@ -288,21 +295,23 @@ class BackupMediaSnapshotTable(context: Context, database: SignalDatabase) : Dat contentValuesOf( MEDIA_ID to it.mediaId, CDN to it.cdn, - REMOTE_DIGEST to it.digest, + PLAINTEXT_HASH to it.plaintextHash, + REMOTE_KEY to it.remoteKey, IS_THUMBNAIL to it.isThumbnail.toInt(), SNAPSHOT_VERSION to UNKNOWN_VERSION, IS_PENDING to 1 ) } - val query = SqlUtil.buildSingleBulkInsert(TABLE_NAME, arrayOf(MEDIA_ID, CDN, REMOTE_DIGEST, IS_THUMBNAIL, SNAPSHOT_VERSION, IS_PENDING), values) + val query = SqlUtil.buildSingleBulkInsert(TABLE_NAME, arrayOf(MEDIA_ID, CDN, PLAINTEXT_HASH, REMOTE_KEY, IS_THUMBNAIL, SNAPSHOT_VERSION, IS_PENDING), values) writableDatabase.execSQL( query.where + """ ON CONFLICT($MEDIA_ID) DO UPDATE SET $CDN = excluded.$CDN, - $REMOTE_DIGEST = excluded.$REMOTE_DIGEST, + $PLAINTEXT_HASH = excluded.$PLAINTEXT_HASH, + $REMOTE_KEY = excluded.$REMOTE_KEY, $IS_THUMBNAIL = excluded.$IS_THUMBNAIL, $IS_PENDING = excluded.$IS_PENDING """, @@ -314,18 +323,21 @@ class BackupMediaSnapshotTable(context: Context, database: SignalDatabase) : Dat val mediaId: String, val thumbnailMediaId: String, val cdn: Int?, - val digest: ByteArray + val plaintextHash: ByteArray, + val remoteKey: ByteArray ) class CdnMismatchResult( - val digest: ByteArray, + val plaintextHash: ByteArray, + val remoteKey: ByteArray, val cdn: Int ) class MediaEntry( val mediaId: String, val cdn: Int?, - val digest: ByteArray, + val plaintextHash: ByteArray, + val remoteKey: ByteArray, val isThumbnail: Boolean ) { companion object { @@ -333,7 +345,8 @@ class BackupMediaSnapshotTable(context: Context, database: SignalDatabase) : Dat return MediaEntry( mediaId = cursor.requireNonNullString(MEDIA_ID), cdn = cursor.requireIntOrNull(CDN), - digest = cursor.requireNonNullBlob(REMOTE_DIGEST), + plaintextHash = cursor.requireNonNullBlob(PLAINTEXT_HASH), + remoteKey = cursor.requireNonNullBlob(REMOTE_KEY), isThumbnail = cursor.requireBoolean(IS_THUMBNAIL) ) } diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/MediaTable.kt b/app/src/main/java/org/thoughtcrime/securesms/database/MediaTable.kt index a1351ee03d..448852b524 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/MediaTable.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/database/MediaTable.kt @@ -31,7 +31,6 @@ class MediaTable internal constructor(context: Context?, databaseHelper: SignalD ${AttachmentTable.TABLE_NAME}.${AttachmentTable.CDN_NUMBER}, ${AttachmentTable.TABLE_NAME}.${AttachmentTable.REMOTE_LOCATION}, ${AttachmentTable.TABLE_NAME}.${AttachmentTable.REMOTE_KEY}, - ${AttachmentTable.TABLE_NAME}.${AttachmentTable.REMOTE_IV}, ${AttachmentTable.TABLE_NAME}.${AttachmentTable.REMOTE_DIGEST}, ${AttachmentTable.TABLE_NAME}.${AttachmentTable.FAST_PREFLIGHT_ID}, ${AttachmentTable.TABLE_NAME}.${AttachmentTable.VOICE_NOTE}, diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/helpers/SignalDatabaseMigrations.kt b/app/src/main/java/org/thoughtcrime/securesms/database/helpers/SignalDatabaseMigrations.kt index 3e60dc5019..8e217c13a8 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/helpers/SignalDatabaseMigrations.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/database/helpers/SignalDatabaseMigrations.kt @@ -134,6 +134,7 @@ import org.thoughtcrime.securesms.database.helpers.migration.V276_AttachmentCdnD import org.thoughtcrime.securesms.database.helpers.migration.V277_AddNotificationProfileStorageSync import org.thoughtcrime.securesms.database.helpers.migration.V278_BackupSnapshotTableVersions import org.thoughtcrime.securesms.database.helpers.migration.V279_AddNotificationProfileForeignKey +import org.thoughtcrime.securesms.database.helpers.migration.V280_RemoveAttachmentIv import org.thoughtcrime.securesms.database.SQLiteDatabase as SignalSqliteDatabase /** @@ -273,10 +274,11 @@ object SignalDatabaseMigrations { 276 to V276_AttachmentCdnDefaultValueMigration, 277 to V277_AddNotificationProfileStorageSync, 278 to V278_BackupSnapshotTableVersions, - 279 to V279_AddNotificationProfileForeignKey + 279 to V279_AddNotificationProfileForeignKey, + 280 to V280_RemoveAttachmentIv ) - const val DATABASE_VERSION = 279 + const val DATABASE_VERSION = 280 @JvmStatic fun migrate(context: Application, db: SignalSqliteDatabase, oldVersion: Int, newVersion: Int) { diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/helpers/migration/V280_RemoveAttachmentIv.kt b/app/src/main/java/org/thoughtcrime/securesms/database/helpers/migration/V280_RemoveAttachmentIv.kt new file mode 100644 index 0000000000..aa5a433ab5 --- /dev/null +++ b/app/src/main/java/org/thoughtcrime/securesms/database/helpers/migration/V280_RemoveAttachmentIv.kt @@ -0,0 +1,45 @@ +/* + * Copyright 2025 Signal Messenger, LLC + * SPDX-License-Identifier: AGPL-3.0-only + */ + +package org.thoughtcrime.securesms.database.helpers.migration + +import android.app.Application +import org.thoughtcrime.securesms.database.SQLiteDatabase + +/** + * We've changed our mediaName calculation to be based on plaintextHash + remoteKey instead of remoteDigest. That means we no longer need to store the IV + * in the database, because the only reason we were storing it before was to have a consistent remoteDigest calculation. + * + * Also, because we're changing the mediaName calculation, we need to reset all of the archive status's. + */ +object V280_RemoveAttachmentIv : SignalDatabaseMigration { + override fun migrate(context: Application, db: SQLiteDatabase, oldVersion: Int, newVersion: Int) { + db.execSQL("ALTER TABLE attachment DROP COLUMN remote_iv") + db.execSQL("DROP INDEX attachment_data_hash_end_index") + db.execSQL("CREATE INDEX IF NOT EXISTS attachment_data_hash_end_remote_key_index ON attachment (data_hash_end, remote_key)") + + // Rebuild table to allow us to have new non-null columns + db.execSQL("DROP TABLE backup_media_snapshot") + db.execSQL( + """ + CREATE TABLE backup_media_snapshot ( + _id INTEGER PRIMARY KEY, + media_id TEXT NOT NULL UNIQUE, + cdn INTEGER, + snapshot_version INTEGER NOT NULL DEFAULT -1, + is_pending INTEGER NOT NULL DEFAULT 0, + is_thumbnail INTEGER NOT NULL DEFAULT 0, + plaintext_hash BLOB NOT NULL, + remote_key BLOB NOT NULL, + last_seen_on_remote_snapshot_version INTEGER NOT NULL DEFAULT 0 + ) + """ + ) + db.execSQL("CREATE INDEX IF NOT EXISTS backup_snapshot_version_index ON backup_media_snapshot (snapshot_version DESC) WHERE snapshot_version != -1") + + // Reset archive transfer state + db.execSQL("UPDATE attachment SET archive_transfer_state = 0 WHERE archive_transfer_state != 0") + } +} diff --git a/app/src/main/java/org/thoughtcrime/securesms/jobs/ArchiveAttachmentBackfillJob.kt b/app/src/main/java/org/thoughtcrime/securesms/jobs/ArchiveAttachmentBackfillJob.kt index 3d89fd3187..047e478562 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/jobs/ArchiveAttachmentBackfillJob.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/jobs/ArchiveAttachmentBackfillJob.kt @@ -45,7 +45,7 @@ class ArchiveAttachmentBackfillJob private constructor(parameters: Parameters) : val jobs = SignalDatabase.attachments.getAttachmentsThatNeedArchiveUpload() .map { attachmentId -> UploadAttachmentToArchiveJob(attachmentId) } - SignalDatabase.attachments.createKeyIvDigestForAttachmentsThatNeedArchiveUpload() + SignalDatabase.attachments.createRemoteKeyForAttachmentsThatNeedArchiveUpload() ArchiveUploadProgress.onAttachmentsStarted(SignalDatabase.attachments.getPendingArchiveUploadBytes()) diff --git a/app/src/main/java/org/thoughtcrime/securesms/jobs/ArchiveAttachmentReconciliationJob.kt b/app/src/main/java/org/thoughtcrime/securesms/jobs/ArchiveAttachmentReconciliationJob.kt index dbc8a9cc16..8470a53ca3 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/jobs/ArchiveAttachmentReconciliationJob.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/jobs/ArchiveAttachmentReconciliationJob.kt @@ -127,7 +127,7 @@ class ArchiveAttachmentReconciliationJob private constructor( val entry = BackupMediaSnapshotTable.MediaEntry.fromCursor(it) // TODO [backup] Re-enqueue thumbnail uploads if necessary if (!entry.isThumbnail) { - SignalDatabase.attachments.resetArchiveTransferStateByDigest(entry.digest) + SignalDatabase.attachments.resetArchiveTransferStateByPlaintextHashAndRemoteKey(entry.plaintextHash, entry.remoteKey) } } @@ -170,7 +170,7 @@ class ArchiveAttachmentReconciliationJob private constructor( if (cdnMismatches.isNotEmpty()) { Log.w(TAG, "Found ${cdnMismatches.size} items with CDNs that differ from what we have locally. Updating our local store.") for (mismatch in cdnMismatches) { - SignalDatabase.attachments.setArchiveCdnByDigest(mismatch.digest, mismatch.cdn) + SignalDatabase.attachments.setArchiveCdnByPlaintextHashAndRemoteKey(mismatch.plaintextHash, mismatch.remoteKey, mismatch.cdn) } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/jobs/ArchiveThumbnailUploadJob.kt b/app/src/main/java/org/thoughtcrime/securesms/jobs/ArchiveThumbnailUploadJob.kt index feff3df35f..2aadf03c9d 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/jobs/ArchiveThumbnailUploadJob.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/jobs/ArchiveThumbnailUploadJob.kt @@ -24,6 +24,7 @@ import org.thoughtcrime.securesms.net.SignalNetwork import org.thoughtcrime.securesms.util.ImageCompressionUtil import org.thoughtcrime.securesms.util.MediaUtil import org.thoughtcrime.securesms.util.RemoteConfig +import org.thoughtcrime.securesms.util.Util import org.whispersystems.signalservice.api.NetworkResult import org.whispersystems.signalservice.api.messages.SignalServiceAttachment import org.whispersystems.signalservice.api.messages.SignalServiceAttachmentStream @@ -105,7 +106,7 @@ class ArchiveThumbnailUploadJob private constructor( .then { form -> SignalNetwork.attachments.getResumableUploadSpec( key = mediaRootBackupKey.deriveThumbnailTransitKey(attachment.requireThumbnailMediaName()), - iv = attachment.remoteIv!!, + iv = Util.getSecretBytes(16), uploadForm = form ) } diff --git a/app/src/main/java/org/thoughtcrime/securesms/jobs/AttachmentDownloadJob.kt b/app/src/main/java/org/thoughtcrime/securesms/jobs/AttachmentDownloadJob.kt index daccdf257e..de4a84a565 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/jobs/AttachmentDownloadJob.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/jobs/AttachmentDownloadJob.kt @@ -11,7 +11,6 @@ import org.greenrobot.eventbus.EventBus import org.signal.core.util.Base64 import org.signal.core.util.Hex import org.signal.core.util.logging.Log -import org.signal.core.util.stream.LimitedInputStream import org.signal.libsignal.protocol.InvalidMacException import org.signal.libsignal.protocol.InvalidMessageException import org.thoughtcrime.securesms.attachments.Attachment @@ -214,15 +213,9 @@ class AttachmentDownloadJob private constructor( Log.i(TAG, "Downloading push part $attachmentId") SignalDatabase.attachments.setTransferState(messageId, attachmentId, AttachmentTable.TRANSFER_PROGRESS_STARTED) - val digestChanged = when (attachment.cdn) { - Cdn.S3 -> { - retrieveAttachmentForReleaseChannel(messageId, attachmentId, attachment) - false - } - - else -> { - retrieveAttachment(messageId, attachmentId, attachment) - } + when (attachment.cdn) { + Cdn.S3 -> retrieveAttachmentForReleaseChannel(messageId, attachmentId, attachment) + else -> retrieveAttachment(messageId, attachmentId, attachment) } if (SignalStore.backup.backsUpMedia) { @@ -231,11 +224,6 @@ class AttachmentDownloadJob private constructor( Log.i(TAG, "[$attachmentId] Already archived. Skipping.") } - digestChanged -> { - Log.i(TAG, "[$attachmentId] Digest for attachment changed after download. Re-uploading to archive.") - AppDependencies.jobManager.add(UploadAttachmentToArchiveJob(attachmentId)) - } - attachment.cdn !in CopyAttachmentToArchiveJob.ALLOWED_SOURCE_CDNS -> { Log.i(TAG, "[$attachmentId] Attachment CDN doesn't support copying to archive. Re-uploading to archive.") AppDependencies.jobManager.add(UploadAttachmentToArchiveJob(attachmentId)) @@ -268,7 +256,7 @@ class AttachmentDownloadJob private constructor( messageId: Long, attachmentId: AttachmentId, attachment: DatabaseAttachment - ): Boolean { + ) { val maxReceiveSize: Long = RemoteConfig.maxAttachmentReceiveSizeBytes val attachmentFile: File = SignalDatabase.attachments.getOrCreateTransferFile(attachmentId) @@ -289,7 +277,7 @@ class AttachmentDownloadJob private constructor( } } - val downloadResult = AppDependencies + val decryptingStream = AppDependencies .signalServiceMessageReceiver .retrieveAttachment( pointer, @@ -298,7 +286,7 @@ class AttachmentDownloadJob private constructor( progressListener ) - return SignalDatabase.attachments.finalizeAttachmentAfterDownload(messageId, attachmentId, downloadResult.dataStream, downloadResult.iv) + SignalDatabase.attachments.finalizeAttachmentAfterDownload(messageId, attachmentId, decryptingStream) } catch (e: RangeException) { Log.w(TAG, "Range exception, file size " + attachmentFile.length(), e) if (attachmentFile.delete()) { @@ -314,7 +302,7 @@ class AttachmentDownloadJob private constructor( if (SignalStore.backup.backsUpMedia && e.code == 404 && attachment.archiveTransferState === AttachmentTable.ArchiveTransferState.FINISHED) { Log.i(TAG, "Retrying download from archive CDN") RestoreAttachmentJob.restoreAttachment(attachment) - return false + return } Log.w(TAG, "Experienced exception while trying to download an attachment.", e) @@ -334,8 +322,6 @@ class AttachmentDownloadJob private constructor( markFailed(messageId, attachmentId) } } - - return false } @Throws(InvalidAttachmentException::class) @@ -399,21 +385,17 @@ class AttachmentDownloadJob private constructor( try { S3.getObject(attachment.fileName!!).use { response -> val body = response.body - if (body != null) { - if (body.contentLength() > RemoteConfig.maxAttachmentReceiveSizeBytes) { - throw MmsException("Attachment too large, failing download") - } - - SignalDatabase.attachments.createKeyIvIfNecessary(attachmentId) - val updatedAttachment = SignalDatabase.attachments.getAttachment(attachmentId)!! - - SignalDatabase.attachments.finalizeAttachmentAfterDownload( - messageId, - attachmentId, - LimitedInputStream.withoutLimits((body.source() as Source).buffer().inputStream()), - iv = updatedAttachment.remoteIv!! - ) + if (body.contentLength() > RemoteConfig.maxAttachmentReceiveSizeBytes) { + throw MmsException("Attachment too large, failing download") } + + SignalDatabase.attachments.createRemoteKeyIfNecessary(attachmentId) + + SignalDatabase.attachments.finalizeAttachmentAfterDownload( + messageId, + attachmentId, + (body.source() as Source).buffer().inputStream() + ) } } catch (e: MmsException) { Log.w(TAG, "Experienced exception while trying to download an attachment.", e) diff --git a/app/src/main/java/org/thoughtcrime/securesms/jobs/AttachmentUploadJob.kt b/app/src/main/java/org/thoughtcrime/securesms/jobs/AttachmentUploadJob.kt index 219c2a884d..d477f89d5c 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/jobs/AttachmentUploadJob.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/jobs/AttachmentUploadJob.kt @@ -31,6 +31,7 @@ import org.thoughtcrime.securesms.net.SignalNetwork import org.thoughtcrime.securesms.recipients.Recipient import org.thoughtcrime.securesms.service.AttachmentProgressService import org.thoughtcrime.securesms.util.RemoteConfig +import org.thoughtcrime.securesms.util.Util import org.whispersystems.signalservice.api.attachment.AttachmentUploadResult import org.whispersystems.signalservice.api.crypto.AttachmentCipherStreamUtil import org.whispersystems.signalservice.api.messages.AttachmentTransferProgress @@ -131,7 +132,7 @@ class AttachmentUploadJob private constructor( throw NotPushRegisteredException() } - SignalDatabase.attachments.createKeyIvIfNecessary(attachmentId) + SignalDatabase.attachments.createRemoteKeyIfNecessary(attachmentId) val databaseAttachment = SignalDatabase.attachments.getAttachment(attachmentId) ?: throw InvalidAttachmentException("Cannot find the specified attachment.") @@ -155,7 +156,7 @@ class AttachmentUploadJob private constructor( .then { form -> SignalNetwork.attachments.getResumableUploadSpec( key = Base64.decode(databaseAttachment.remoteKey!!), - iv = databaseAttachment.remoteIv!!, + iv = Util.getSecretBytes(16), uploadForm = form ) } diff --git a/app/src/main/java/org/thoughtcrime/securesms/jobs/BackfillDigestJob.kt b/app/src/main/java/org/thoughtcrime/securesms/jobs/BackfillDigestJob.kt deleted file mode 100644 index 1715eb1345..0000000000 --- a/app/src/main/java/org/thoughtcrime/securesms/jobs/BackfillDigestJob.kt +++ /dev/null @@ -1,107 +0,0 @@ -/* - * Copyright 2024 Signal Messenger, LLC - * SPDX-License-Identifier: AGPL-3.0-only - */ - -package org.thoughtcrime.securesms.jobs - -import org.signal.core.util.Base64 -import org.signal.core.util.copyTo -import org.signal.core.util.logging.Log -import org.signal.core.util.stream.NullOutputStream -import org.signal.core.util.withinTransaction -import org.thoughtcrime.securesms.attachments.AttachmentId -import org.thoughtcrime.securesms.database.SignalDatabase -import org.thoughtcrime.securesms.jobmanager.Job -import org.thoughtcrime.securesms.jobs.protos.BackfillDigestJobData -import org.thoughtcrime.securesms.util.Util -import org.whispersystems.signalservice.api.crypto.AttachmentCipherOutputStream -import org.whispersystems.signalservice.internal.crypto.PaddingInputStream -import java.io.IOException - -/** - * This goes through all attachments with pre-existing data and recalcuates their digests. - * This is important for backupsV2, where we need to know an attachment's digest in advance. - * - * This job needs to be careful to (1) minimize time in the transaction, and (2) never write partial results to disk, i.e. only write the full (key/iv/digest) - * tuple together all at once (partial writes could poison the db, preventing us from retrying properly in the event of a crash or transient error). - */ -class BackfillDigestJob private constructor( - private val attachmentId: AttachmentId, - params: Parameters -) : Job(params) { - - companion object { - private val TAG = Log.tag(BackfillDigestJob::class) - const val KEY = "BackfillDigestJob" - const val QUEUE = "BackfillDigestJob" - } - - constructor(attachmentId: AttachmentId) : this( - attachmentId = attachmentId, - params = Parameters.Builder() - .setQueue(QUEUE) - .setMaxAttempts(3) - .setLifespan(Parameters.IMMORTAL) - .build() - ) - - override fun serialize(): ByteArray { - return BackfillDigestJobData(attachmentId = attachmentId.id).encode() - } - - override fun getFactoryKey(): String = KEY - - override fun run(): Result { - val (originalKey, originalIv, decryptingStream) = SignalDatabase.rawDatabase.withinTransaction { - val attachment = SignalDatabase.attachments.getAttachment(attachmentId) - if (attachment == null) { - Log.w(TAG, "$attachmentId no longer exists! Skipping.") - return Result.success() - } - - if (!attachment.hasData) { - Log.w(TAG, "$attachmentId no longer has any data! Skipping.") - return Result.success() - } - - val stream = try { - SignalDatabase.attachments.getAttachmentStream(attachmentId, offset = 0) - } catch (e: IOException) { - Log.w(TAG, "Could not open a stream for $attachmentId. Assuming that the file no longer exists. Skipping.", e) - return Result.success() - } - - // In order to match the exact digest calculation, we need to use the same padding that we would use when uploading the attachment. - Triple(attachment.remoteKey?.let { Base64.decode(it) }, attachment.remoteIv, PaddingInputStream(stream, attachment.size)) - } - - val key = originalKey ?: Util.getSecretBytes(64) - val iv = originalIv ?: Util.getSecretBytes(16) - - val cipherOutputStream = AttachmentCipherOutputStream(key, iv, NullOutputStream) - decryptingStream.copyTo(cipherOutputStream) - - val digest = cipherOutputStream.transmittedDigest - - SignalDatabase.attachments.updateKeyIvDigest( - attachmentId = attachmentId, - key = key, - iv = iv, - digest = digest - ) - - return Result.success() - } - - override fun onFailure() { - Log.w(TAG, "Failed to backfill digest for $attachmentId!") - } - - class Factory : Job.Factory { - override fun create(parameters: Parameters, serializedData: ByteArray?): BackfillDigestJob { - val attachmentId = AttachmentId(BackfillDigestJobData.ADAPTER.decode(serializedData!!).attachmentId) - return BackfillDigestJob(attachmentId, parameters) - } - } -} diff --git a/app/src/main/java/org/thoughtcrime/securesms/jobs/BackfillDigestsForDataFileJob.kt b/app/src/main/java/org/thoughtcrime/securesms/jobs/BackfillDigestsForDataFileJob.kt index e4674f869a..710b6fa0ec 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/jobs/BackfillDigestsForDataFileJob.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/jobs/BackfillDigestsForDataFileJob.kt @@ -32,12 +32,13 @@ class BackfillDigestsForDataFileJob private constructor( companion object { private val TAG = Log.tag(BackfillDigestsForDataFileJob::class) const val KEY = "BackfillDigestsForDataFileJob" + const val QUEUE = "BackfillDigestJob" } constructor(dataFile: String) : this( dataFile = dataFile, params = Parameters.Builder() - .setQueue(BackfillDigestJob.QUEUE) + .setQueue(QUEUE) .setMaxAttempts(3) .setLifespan(Parameters.IMMORTAL) .build() @@ -50,7 +51,7 @@ class BackfillDigestsForDataFileJob private constructor( override fun getFactoryKey(): String = KEY override fun run(): Result { - val (originalKey, originalIv, decryptingStream) = SignalDatabase.rawDatabase.withinTransaction { + val (originalKey, decryptingStream) = SignalDatabase.rawDatabase.withinTransaction { val attachment = SignalDatabase.attachments.getMostRecentValidAttachmentUsingDataFile(dataFile) if (attachment == null) { Log.w(TAG, "No attachments using file $dataFile exist anymore! Skipping.") @@ -65,21 +66,19 @@ class BackfillDigestsForDataFileJob private constructor( } // In order to match the exact digest calculation, we need to use the same padding that we would use when uploading the attachment. - Triple(attachment.remoteKey?.let { Base64.decode(it) }, attachment.remoteIv, PaddingInputStream(stream, attachment.size)) + Pair(attachment.remoteKey?.let { Base64.decode(it) }, PaddingInputStream(stream, attachment.size)) } val key = originalKey ?: Util.getSecretBytes(64) - val iv = originalIv ?: Util.getSecretBytes(16) - val cipherOutputStream = AttachmentCipherOutputStream(key, iv, NullOutputStream) + val cipherOutputStream = AttachmentCipherOutputStream(key, iv = null, NullOutputStream) decryptingStream.copyTo(cipherOutputStream) val digest = cipherOutputStream.transmittedDigest - SignalDatabase.attachments.updateKeyIvDigestByDataFile( + SignalDatabase.attachments.updateRemoteKeyAndDigestByDataFile( dataFile = dataFile, key = key, - iv = iv, digest = digest ) diff --git a/app/src/main/java/org/thoughtcrime/securesms/jobs/BackupMessagesJob.kt b/app/src/main/java/org/thoughtcrime/securesms/jobs/BackupMessagesJob.kt index 96b3128bf7..f20da6c89d 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/jobs/BackupMessagesJob.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/jobs/BackupMessagesJob.kt @@ -100,7 +100,6 @@ class BackupMessagesJob private constructor( .addConstraint(if (SignalStore.backup.backupWithCellular) NetworkConstraint.KEY else WifiConstraint.KEY) .setMaxAttempts(3) .setMaxInstancesForFactory(1) - .setQueue(BackfillDigestJob.QUEUE) // We want to ensure digests have been backfilled before this runs. Could eventually remove this constraint. .build() ) @@ -132,7 +131,7 @@ class BackupMessagesJob private constructor( val stopwatch = Stopwatch("BackupMessagesJob") - SignalDatabase.attachments.createKeyIvDigestForAttachmentsThatNeedArchiveUpload().takeIf { it > 0 }?.let { count -> Log.w(TAG, "Needed to create $count key/iv/digests.") } + SignalDatabase.attachments.createRemoteKeyForAttachmentsThatNeedArchiveUpload().takeIf { it > 0 }?.let { count -> Log.w(TAG, "Needed to create $count key/iv/digests.") } stopwatch.split("key-iv-digest") if (isCanceled) { diff --git a/app/src/main/java/org/thoughtcrime/securesms/jobs/JobManagerFactories.java b/app/src/main/java/org/thoughtcrime/securesms/jobs/JobManagerFactories.java index ef54421527..47ef188e69 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/jobs/JobManagerFactories.java +++ b/app/src/main/java/org/thoughtcrime/securesms/jobs/JobManagerFactories.java @@ -50,7 +50,6 @@ import org.thoughtcrime.securesms.migrations.AvatarColorStorageServiceMigrationJ import org.thoughtcrime.securesms.migrations.AvatarIdRemovalMigrationJob; import org.thoughtcrime.securesms.migrations.AvatarMigrationJob; import org.thoughtcrime.securesms.migrations.BackfillDigestsForDuplicatesMigrationJob; -import org.thoughtcrime.securesms.migrations.BackfillDigestsMigrationJob; import org.thoughtcrime.securesms.migrations.BackupJitterMigrationJob; import org.thoughtcrime.securesms.migrations.BackupNotificationMigrationJob; import org.thoughtcrime.securesms.migrations.BadE164MigrationJob; @@ -131,7 +130,6 @@ public final class JobManagerFactories { put(AutomaticSessionResetJob.KEY, new AutomaticSessionResetJob.Factory()); put(AvatarGroupsV1DownloadJob.KEY, new AvatarGroupsV1DownloadJob.Factory()); put(AvatarGroupsV2DownloadJob.KEY, new AvatarGroupsV2DownloadJob.Factory()); - put(BackfillDigestJob.KEY, new BackfillDigestJob.Factory()); put(BackfillDigestsForDataFileJob.KEY, new BackfillDigestsForDataFileJob.Factory()); put(BackupDeleteJob.KEY, new BackupDeleteJob.Factory()); put(BackupMessagesJob.KEY, new BackupMessagesJob.Factory()); @@ -284,7 +282,6 @@ public final class JobManagerFactories { put(AvatarColorStorageServiceMigrationJob.KEY, new AvatarColorStorageServiceMigrationJob.Factory()); put(AvatarIdRemovalMigrationJob.KEY, new AvatarIdRemovalMigrationJob.Factory()); put(AvatarMigrationJob.KEY, new AvatarMigrationJob.Factory()); - put(BackfillDigestsMigrationJob.KEY, new BackfillDigestsMigrationJob.Factory()); put(BackfillDigestsForDuplicatesMigrationJob.KEY, new BackfillDigestsForDuplicatesMigrationJob.Factory()); put(BackupJitterMigrationJob.KEY, new BackupJitterMigrationJob.Factory()); put(BackupNotificationMigrationJob.KEY, new BackupNotificationMigrationJob.Factory()); @@ -394,6 +391,8 @@ public final class JobManagerFactories { put("BackupMediaSnapshotSyncJob", new FailingJob.Factory()); put("PnpInitializeDevicesJob", new FailingJob.Factory()); put("BackupRestoreJob", new FailingJob.Factory()); + put("BackfillDigestsMigrationJob", new PassingMigrationJob.Factory()); + put("BackfillDigestJob", new FailingJob.Factory()); }}; } diff --git a/app/src/main/java/org/thoughtcrime/securesms/jobs/RestoreAttachmentJob.kt b/app/src/main/java/org/thoughtcrime/securesms/jobs/RestoreAttachmentJob.kt index e67d8ed795..770450d711 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/jobs/RestoreAttachmentJob.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/jobs/RestoreAttachmentJob.kt @@ -256,7 +256,7 @@ class RestoreAttachmentJob private constructor( } } - val downloadResult = if (useArchiveCdn) { + val decryptingStream = if (useArchiveCdn) { archiveFile = SignalDatabase.attachments.getOrCreateArchiveTransferFile(attachmentId) val cdnCredentials = BackupRepository.getCdnReadCredentials(BackupRepository.CredentialType.MEDIA, attachment.archiveCdn ?: RemoteConfig.backupFallbackArchiveCdn).successOrThrow().headers @@ -280,7 +280,7 @@ class RestoreAttachmentJob private constructor( ) } - SignalDatabase.attachments.finalizeAttachmentAfterDownload(messageId, attachmentId, downloadResult.dataStream, downloadResult.iv, if (manual) System.currentTimeMillis().milliseconds else null) + SignalDatabase.attachments.finalizeAttachmentAfterDownload(messageId, attachmentId, decryptingStream, if (manual) System.currentTimeMillis().milliseconds else null) } catch (e: RangeException) { val transferFile = archiveFile ?: attachmentFile Log.w(TAG, "Range exception, file size " + transferFile.length(), e) diff --git a/app/src/main/java/org/thoughtcrime/securesms/jobs/RestoreAttachmentThumbnailJob.kt b/app/src/main/java/org/thoughtcrime/securesms/jobs/RestoreAttachmentThumbnailJob.kt index d4a4d953d6..c8185ef4cd 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/jobs/RestoreAttachmentThumbnailJob.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/jobs/RestoreAttachmentThumbnailJob.kt @@ -131,7 +131,7 @@ class RestoreAttachmentThumbnailJob private constructor( val pointer = attachment.createArchiveThumbnailPointer() Log.i(TAG, "Downloading thumbnail for $attachmentId") - val downloadResult = AppDependencies.signalServiceMessageReceiver + val decryptingStream = AppDependencies.signalServiceMessageReceiver .retrieveArchivedThumbnail( SignalStore.backup.mediaRootBackupKey.deriveMediaSecrets(attachment.requireThumbnailMediaName()), cdnCredentials, @@ -142,7 +142,7 @@ class RestoreAttachmentThumbnailJob private constructor( progressListener ) - SignalDatabase.attachments.finalizeAttachmentThumbnailAfterDownload(attachmentId, attachment.remoteDigest, downloadResult.dataStream, thumbnailTransferFile) + SignalDatabase.attachments.finalizeAttachmentThumbnailAfterDownload(attachmentId, attachment.remoteDigest, decryptingStream, thumbnailTransferFile) if (!SignalDatabase.messages.isStory(messageId)) { AppDependencies.messageNotifier.updateNotification(context) diff --git a/app/src/main/java/org/thoughtcrime/securesms/jobs/RestoreLocalAttachmentJob.kt b/app/src/main/java/org/thoughtcrime/securesms/jobs/RestoreLocalAttachmentJob.kt index 0d37246ceb..badd01a104 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/jobs/RestoreLocalAttachmentJob.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/jobs/RestoreLocalAttachmentJob.kt @@ -52,8 +52,8 @@ class RestoreLocalAttachmentJob private constructor( possibleRestorableAttachments .forEachIndexed { index, attachment -> - val fileInfo = if (attachment.remoteKey != null && attachment.remoteDigest != null) { - val mediaName = MediaName.fromDigest(attachment.remoteDigest).name + val fileInfo = if (attachment.plaintextHash != null && attachment.remoteKey != null) { + val mediaName = MediaName.fromPlaintextHashAndRemoteKey(attachment.plaintextHash, attachment.remoteKey).name mediaNameToFileInfo[mediaName] } else { null @@ -158,7 +158,7 @@ class RestoreLocalAttachmentJob private constructor( incrementalDigest = null, incrementalMacChunkSize = 0 ).use { input -> - SignalDatabase.attachments.finalizeAttachmentAfterDownload(attachment.mmsId, attachment.attachmentId, input, iv) + SignalDatabase.attachments.finalizeAttachmentAfterDownload(attachment.mmsId, attachment.attachmentId, input) } } catch (e: InvalidMessageException) { Log.w(TAG, "Experienced an InvalidMessageException while trying to read attachment.", e) diff --git a/app/src/main/java/org/thoughtcrime/securesms/jobs/UploadAttachmentToArchiveJob.kt b/app/src/main/java/org/thoughtcrime/securesms/jobs/UploadAttachmentToArchiveJob.kt index 352cc76c3c..e9ee4182c4 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/jobs/UploadAttachmentToArchiveJob.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/jobs/UploadAttachmentToArchiveJob.kt @@ -26,6 +26,7 @@ import org.thoughtcrime.securesms.jobs.protos.UploadAttachmentToArchiveJobData import org.thoughtcrime.securesms.keyvalue.SignalStore import org.thoughtcrime.securesms.net.SignalNetwork import org.thoughtcrime.securesms.service.AttachmentProgressService +import org.thoughtcrime.securesms.util.Util import org.whispersystems.signalservice.api.NetworkResult import org.whispersystems.signalservice.api.archive.ArchiveMediaUploadFormStatusCodes import org.whispersystems.signalservice.api.attachment.AttachmentUploadResult @@ -124,8 +125,8 @@ class UploadAttachmentToArchiveJob private constructor( return Result.success() } - if (attachment.remoteKey == null || attachment.remoteIv == null) { - Log.w(TAG, "[$attachmentId] Attachment is missing remote key or IV! Cannot upload.") + if (attachment.remoteKey == null) { + Log.w(TAG, "[$attachmentId] Attachment is missing remote key! Cannot upload.") return Result.failure() } @@ -144,7 +145,7 @@ class UploadAttachmentToArchiveJob private constructor( if (uploadSpec == null) { Log.d(TAG, "[$attachmentId] Need an upload spec. Fetching...") - val (spec, result) = fetchResumableUploadSpec(key = Base64.decode(attachment.remoteKey), iv = attachment.remoteIv) + val (spec, result) = fetchResumableUploadSpec(key = Base64.decode(attachment.remoteKey), iv = Util.getSecretBytes(16)) if (result != null) { return result } diff --git a/app/src/main/java/org/thoughtcrime/securesms/migrations/ApplicationMigrations.java b/app/src/main/java/org/thoughtcrime/securesms/migrations/ApplicationMigrations.java index ae213b248b..d5e1879801 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/migrations/ApplicationMigrations.java +++ b/app/src/main/java/org/thoughtcrime/securesms/migrations/ApplicationMigrations.java @@ -732,7 +732,7 @@ public class ApplicationMigrations { } if (lastSeenVersion < Version.BACKFILL_DIGESTS_V2) { - jobs.put(Version.BACKFILL_DIGESTS_V2, new BackfillDigestsMigrationJob()); +// jobs.put(Version.BACKFILL_DIGESTS_V2, new BackfillDigestsMigrationJob()); } if (lastSeenVersion < Version.CALL_LINK_STORAGE_SYNC) { diff --git a/app/src/main/java/org/thoughtcrime/securesms/migrations/BackfillDigestsMigrationJob.kt b/app/src/main/java/org/thoughtcrime/securesms/migrations/BackfillDigestsMigrationJob.kt deleted file mode 100644 index 94872f40a4..0000000000 --- a/app/src/main/java/org/thoughtcrime/securesms/migrations/BackfillDigestsMigrationJob.kt +++ /dev/null @@ -1,41 +0,0 @@ -package org.thoughtcrime.securesms.migrations - -import org.signal.core.util.logging.Log -import org.thoughtcrime.securesms.database.SignalDatabase -import org.thoughtcrime.securesms.dependencies.AppDependencies -import org.thoughtcrime.securesms.jobmanager.Job -import org.thoughtcrime.securesms.jobs.BackfillDigestJob - -/** - * Finds all attachments that need new digests and schedules a [BackfillDigestJob] for each. - */ -internal class BackfillDigestsMigrationJob( - parameters: Parameters = Parameters.Builder().build() -) : MigrationJob(parameters) { - - companion object { - val TAG = Log.tag(BackfillDigestsMigrationJob::class.java) - const val KEY = "BackfillDigestsMigrationJob" - } - - override fun getFactoryKey(): String = KEY - - override fun isUiBlocking(): Boolean = false - - override fun performMigration() { - val jobs = SignalDatabase.attachments.getAttachmentsThatNeedNewDigests() - .map { BackfillDigestJob(it) } - - AppDependencies.jobManager.addAll(jobs) - - Log.i(TAG, "Enqueued ${jobs.size} backfill digest jobs.") - } - - override fun shouldRetry(e: Exception): Boolean = false - - class Factory : Job.Factory { - override fun create(parameters: Parameters, serializedData: ByteArray?): BackfillDigestsMigrationJob { - return BackfillDigestsMigrationJob(parameters) - } - } -} diff --git a/app/src/main/java/org/thoughtcrime/securesms/video/exo/PartDataSource.java b/app/src/main/java/org/thoughtcrime/securesms/video/exo/PartDataSource.java index 3897e0ec68..4011e50dc7 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/video/exo/PartDataSource.java +++ b/app/src/main/java/org/thoughtcrime/securesms/video/exo/PartDataSource.java @@ -86,7 +86,7 @@ class PartDataSource implements DataSource { throw new InvalidMessageException("Missing digest!"); } - this.inputStream = AttachmentCipherInputStream.createForArchivedMediaOuterAndInnerLayers(mediaKeyMaterial, archiveFile, originalCipherLength, attachment.size, decodedKey, attachment.remoteDigest, attachment.getIncrementalDigest(), attachment.incrementalMacChunkSize); + this.inputStream = AttachmentCipherInputStream.createForArchivedMedia(mediaKeyMaterial, archiveFile, originalCipherLength, attachment.size, decodedKey, attachment.remoteDigest, attachment.getIncrementalDigest(), attachment.incrementalMacChunkSize); } catch (InvalidMessageException e) { throw new IOException("Error decrypting attachment stream!", e); } diff --git a/app/src/main/protowire/Backup.proto b/app/src/main/protowire/Backup.proto index b19ebe330f..c7b3efc37d 100644 --- a/app/src/main/protowire/Backup.proto +++ b/app/src/main/protowire/Backup.proto @@ -749,15 +749,25 @@ message FilePointer { } message LocatorInfo { - // Must be non-empty if transitCdnKey or mediaName are set/nonempty. + // Must be non-empty if transitCdnKey or plaintextHash are set/nonempty. // Otherwise must be empty. bytes key = 1; + // From the sender of the attachment (incl. ourselves) - // Must be non-empty if transitCdnKey or mediaName are set/nonempty. - // Otherwise must be empty. - bytes digest = 2; - // Must be non-zero if transitCdnKey or mediaName are set/nonempty. - // Otherwise must be zero. + // Will be reserved once all clients start reading integrityCheck + bytes legacyDigest = 2; + + oneof integrityCheck { + // Set if file was at one point downloaded and its plaintextHash was calculated + bytes plaintextHash = 10; + + // Set if file has not been downloaded so its integrity has not been verified + // From the sender of the attachment + bytes encryptedDigest = 11; + } + + // NB: This is the plaintext size, and empty content attachments are legal, so this + // may be zero even if transitCdnKey or mediaName are set/nonempty. uint32 size = 3; // Either both transit cdn key and number are set or neither should be set. @@ -775,7 +785,9 @@ message FilePointer { // Nonempty any time the attachment was downloaded and its // digest validated, whether free tier or paid subscription. - string mediaName = 8; + // Will be reserved once all clients start reading integrityCheck, + // when mediaName will be derived from the plaintextHash and encryption key + string legacyMediaName = 8; // Separate key used to encrypt this file for the local backup. // Generally required for local backups. diff --git a/app/src/test/java/org/thoughtcrime/securesms/sms/UploadDependencyGraphTest.kt b/app/src/test/java/org/thoughtcrime/securesms/sms/UploadDependencyGraphTest.kt index 0433f10341..3b03b3589d 100644 --- a/app/src/test/java/org/thoughtcrime/securesms/sms/UploadDependencyGraphTest.kt +++ b/app/src/test/java/org/thoughtcrime/securesms/sms/UploadDependencyGraphTest.kt @@ -234,7 +234,6 @@ class UploadDependencyGraphTest { cdn = attachment.cdn, location = attachment.remoteLocation, key = attachment.remoteKey, - iv = attachment.remoteIv, digest = attachment.remoteDigest, incrementalDigest = attachment.incrementalDigest, incrementalMacChunkSize = attachment.incrementalMacChunkSize, diff --git a/app/src/testShared/org/thoughtcrime/securesms/database/FakeMessageRecords.kt b/app/src/testShared/org/thoughtcrime/securesms/database/FakeMessageRecords.kt index d73cde1a36..71ffdd3451 100644 --- a/app/src/testShared/org/thoughtcrime/securesms/database/FakeMessageRecords.kt +++ b/app/src/testShared/org/thoughtcrime/securesms/database/FakeMessageRecords.kt @@ -79,7 +79,6 @@ object FakeMessageRecords { cdn = Cdn.fromCdnNumber(cdnNumber), location = location, key = key, - iv = iv, digest = digest, incrementalDigest = incrementalDigest, incrementalMacChunkSize = incrementalMacChunkSize, diff --git a/core-util-jvm/src/main/java/org/signal/core/util/Base64.kt b/core-util-jvm/src/main/java/org/signal/core/util/Base64.kt index aeb4bf9a30..e2d9ffe6d3 100644 --- a/core-util-jvm/src/main/java/org/signal/core/util/Base64.kt +++ b/core-util-jvm/src/main/java/org/signal/core/util/Base64.kt @@ -130,4 +130,24 @@ object Base64 { private fun String.stripPadding(): String { return this.replace("=", "") } + + fun String.decodeBase64OrThrow(): ByteArray { + return try { + decode(this) + } catch (e: IOException) { + throw AssertionError("Invalid Base64 string: $this", e) + } + } + + fun String?.decodeBase64(): ByteArray? { + if (this == null) { + return null + } + + return try { + decode(this) + } catch (e: IOException) { + return null + } + } } diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 9bcfb0036a..0b79d06e4a 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -13,7 +13,7 @@ androidx-window = "1.3.0" glide = "4.15.1" gradle = "8.9.0" kotlin = "2.1.0" -libsignal-client = "0.74.0" +libsignal-client = "0.74.1" mp4parser = "1.9.39" android-gradle-plugin = "8.7.2" accompanist = "0.28.0" diff --git a/gradle/verification-metadata.xml b/gradle/verification-metadata.xml index 0b224b0032..1c4d3161cf 100644 --- a/gradle/verification-metadata.xml +++ b/gradle/verification-metadata.xml @@ -6769,6 +6769,14 @@ https://docs.gradle.org/current/userguide/dependency_verification.html + + + + + + + + @@ -6798,6 +6806,11 @@ https://docs.gradle.org/current/userguide/dependency_verification.html + + + + + @@ -6827,6 +6840,14 @@ https://docs.gradle.org/current/userguide/dependency_verification.html + + + + + + + + @@ -6864,6 +6885,14 @@ https://docs.gradle.org/current/userguide/dependency_verification.html + + + + + + + + @@ -6872,6 +6901,14 @@ https://docs.gradle.org/current/userguide/dependency_verification.html + + + + + + + + @@ -6880,6 +6917,14 @@ https://docs.gradle.org/current/userguide/dependency_verification.html + + + + + + + + @@ -6888,6 +6933,11 @@ https://docs.gradle.org/current/userguide/dependency_verification.html + + + + + @@ -6904,6 +6954,14 @@ https://docs.gradle.org/current/userguide/dependency_verification.html + + + + + + + + @@ -7311,20 +7369,20 @@ https://docs.gradle.org/current/userguide/dependency_verification.html - - - + + + - - + + - - - + + + - - + + diff --git a/libsignal-service/src/main/java/org/whispersystems/signalservice/api/SignalServiceMessageReceiver.java b/libsignal-service/src/main/java/org/whispersystems/signalservice/api/SignalServiceMessageReceiver.java index 6dbc82bb4a..7fa3a2d66f 100644 --- a/libsignal-service/src/main/java/org/whispersystems/signalservice/api/SignalServiceMessageReceiver.java +++ b/libsignal-service/src/main/java/org/whispersystems/signalservice/api/SignalServiceMessageReceiver.java @@ -7,10 +7,8 @@ package org.whispersystems.signalservice.api; import org.signal.core.util.StreamUtil; -import org.signal.core.util.stream.LimitedInputStream; import org.signal.libsignal.protocol.InvalidMessageException; import org.signal.libsignal.zkgroup.profiles.ProfileKey; -import org.whispersystems.signalservice.api.attachment.AttachmentDownloadResult; import org.whispersystems.signalservice.api.backup.MediaRootBackupKey; import org.whispersystems.signalservice.api.crypto.AttachmentCipherInputStream; import org.whispersystems.signalservice.api.crypto.AttachmentCipherStreamUtil; @@ -27,7 +25,6 @@ import org.whispersystems.signalservice.internal.util.Util; import java.io.File; import java.io.FileInputStream; -import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.time.ZonedDateTime; @@ -68,7 +65,7 @@ public class SignalServiceMessageReceiver { */ public InputStream retrieveAttachment(SignalServiceAttachmentPointer pointer, File destination, long maxSizeBytes) throws IOException, InvalidMessageException, MissingConfigurationException { - return retrieveAttachment(pointer, destination, maxSizeBytes, null).getDataStream(); + return retrieveAttachment(pointer, destination, maxSizeBytes, null); } public InputStream retrieveProfileAvatar(String path, File destination, ProfileKey profileKey, long maxSizeBytes) @@ -99,9 +96,9 @@ public class SignalServiceMessageReceiver { * @throws IOException * @throws InvalidMessageException */ - public AttachmentDownloadResult retrieveAttachment(SignalServiceAttachmentPointer pointer, File destination, long maxSizeBytes, ProgressListener listener) + public InputStream retrieveAttachment(SignalServiceAttachmentPointer pointer, File destination, long maxSizeBytes, ProgressListener listener) throws IOException, InvalidMessageException, MissingConfigurationException { - if (!pointer.getDigest().isPresent()) throw new InvalidMessageException("No attachment digest!"); + if (pointer.getDigest().isEmpty()) throw new InvalidMessageException("No attachment digest!"); if (pointer.getKey() == null) throw new InvalidMessageException("No key!"); socket.retrieveAttachment(pointer.getCdnNumber(), Collections.emptyMap(), pointer.getRemoteId(), destination, maxSizeBytes, listener); @@ -111,16 +108,13 @@ public class SignalServiceMessageReceiver { StreamUtil.readFully(tempStream, iv); } - return new AttachmentDownloadResult( - AttachmentCipherInputStream.createForAttachment( - destination, - pointer.getSize().orElse(0), - pointer.getKey(), - pointer.getDigest().get(), - null, - 0 - ), - iv + return AttachmentCipherInputStream.createForAttachment( + destination, + pointer.getSize().orElse(0), + pointer.getKey(), + pointer.getDigest().get(), + null, + 0 ); } @@ -136,13 +130,13 @@ public class SignalServiceMessageReceiver { * * @return An InputStream that streams the plaintext attachment contents. */ - public AttachmentDownloadResult retrieveArchivedAttachment(@Nonnull MediaRootBackupKey.MediaKeyMaterial archivedMediaKeyMaterial, - @Nonnull Map readCredentialHeaders, - @Nonnull File archiveDestination, - @Nonnull SignalServiceAttachmentPointer pointer, - @Nonnull File attachmentDestination, - long maxSizeBytes, - @Nullable ProgressListener listener) + public InputStream retrieveArchivedAttachment(@Nonnull MediaRootBackupKey.MediaKeyMaterial archivedMediaKeyMaterial, + @Nonnull Map readCredentialHeaders, + @Nonnull File archiveDestination, + @Nonnull SignalServiceAttachmentPointer pointer, + @Nonnull File attachmentDestination, + long maxSizeBytes, + @Nullable ProgressListener listener) throws IOException, InvalidMessageException, MissingConfigurationException { if (pointer.getDigest().isEmpty()) { @@ -160,29 +154,16 @@ public class SignalServiceMessageReceiver { .map(s -> AttachmentCipherStreamUtil.getCiphertextLength(PaddingInputStream.getPaddedSize(s))) .orElse(0L); - // There's two layers of encryption -- one from the backup, and one from the attachment. This only strips the outermost backup encryption layer. - try (InputStream backupDecrypted = AttachmentCipherInputStream.createForArchivedMediaOuterLayer(archivedMediaKeyMaterial, archiveDestination, originalCipherLength)) { - try (FileOutputStream fos = new FileOutputStream(attachmentDestination)) { - // TODO [backup] I don't think we should be doing the full copy here. This is basically doing the entire download inline in this single line. - StreamUtil.copy(backupDecrypted, fos); - } - } - - byte[] iv = new byte[16]; - try (InputStream tempStream = new FileInputStream(attachmentDestination)) { - StreamUtil.readFully(tempStream, iv); - } - - LimitedInputStream dataStream = AttachmentCipherInputStream.createForAttachment( + return AttachmentCipherInputStream.createForArchivedMedia( + archivedMediaKeyMaterial, attachmentDestination, + originalCipherLength, pointer.getSize().orElse(0), pointer.getKey(), pointer.getDigest().get(), null, 0 ); - - return new AttachmentDownloadResult(dataStream, iv); } /** @@ -197,13 +178,13 @@ public class SignalServiceMessageReceiver { * * @return An InputStream that streams the plaintext attachment contents. */ - public AttachmentDownloadResult retrieveArchivedThumbnail(@Nonnull MediaRootBackupKey.MediaKeyMaterial archivedMediaKeyMaterial, - @Nonnull Map readCredentialHeaders, - @Nonnull File archiveDestination, - @Nonnull SignalServiceAttachmentPointer pointer, - @Nonnull File attachmentDestination, - long maxSizeBytes, - @Nullable ProgressListener listener) + public InputStream retrieveArchivedThumbnail(@Nonnull MediaRootBackupKey.MediaKeyMaterial archivedMediaKeyMaterial, + @Nonnull Map readCredentialHeaders, + @Nonnull File archiveDestination, + @Nonnull SignalServiceAttachmentPointer pointer, + @Nonnull File attachmentDestination, + long maxSizeBytes, + @Nullable ProgressListener listener) throws IOException, InvalidMessageException, MissingConfigurationException { if (pointer.getKey() == null) { @@ -217,26 +198,13 @@ public class SignalServiceMessageReceiver { .map(s -> AttachmentCipherStreamUtil.getCiphertextLength(PaddingInputStream.getPaddedSize(s))) .orElse(0L); - // There's two layers of encryption -- one from the backup, and one from the attachment. This only strips the outermost backup encryption layer. - try (InputStream backupDecrypted = AttachmentCipherInputStream.createForArchivedMediaOuterLayer(archivedMediaKeyMaterial, archiveDestination, originalCipherLength)) { - try (FileOutputStream fos = new FileOutputStream(attachmentDestination)) { - // TODO [backup] I don't think we should be doing the full copy here. This is basically doing the entire download inline in this single line. - StreamUtil.copy(backupDecrypted, fos); - } - } - - byte[] iv = new byte[16]; - try (InputStream tempStream = new FileInputStream(attachmentDestination)) { - StreamUtil.readFully(tempStream, iv); - } - - LimitedInputStream dataStream = AttachmentCipherInputStream.createForArchiveThumbnailInnerLayer( + return AttachmentCipherInputStream.createForArchivedThumbnail( + archivedMediaKeyMaterial, attachmentDestination, + originalCipherLength, pointer.getSize().orElse(0), pointer.getKey() ); - - return new AttachmentDownloadResult(dataStream, iv); } public void retrieveBackup(int cdnNumber, Map headers, String cdnPath, File destination, ProgressListener listener) throws MissingConfigurationException, IOException { diff --git a/libsignal-service/src/main/java/org/whispersystems/signalservice/api/attachment/AttachmentApi.kt b/libsignal-service/src/main/java/org/whispersystems/signalservice/api/attachment/AttachmentApi.kt index 1ffedd2ebc..bea50827db 100644 --- a/libsignal-service/src/main/java/org/whispersystems/signalservice/api/attachment/AttachmentApi.kt +++ b/libsignal-service/src/main/java/org/whispersystems/signalservice/api/attachment/AttachmentApi.kt @@ -91,7 +91,6 @@ class AttachmentApi( remoteId = SignalServiceAttachmentRemoteId.V4(attachmentData.resumableUploadSpec.cdnKey), cdnNumber = attachmentData.resumableUploadSpec.cdnNumber, key = resumableUploadSpec.attachmentKey, - iv = resumableUploadSpec.attachmentIv, digest = digestInfo.digest, incrementalDigest = digestInfo.incrementalDigest, incrementalDigestChunkSize = digestInfo.incrementalMacChunkSize, diff --git a/libsignal-service/src/main/java/org/whispersystems/signalservice/api/attachment/AttachmentUploadResult.kt b/libsignal-service/src/main/java/org/whispersystems/signalservice/api/attachment/AttachmentUploadResult.kt index 67a27d74da..6acc497336 100644 --- a/libsignal-service/src/main/java/org/whispersystems/signalservice/api/attachment/AttachmentUploadResult.kt +++ b/libsignal-service/src/main/java/org/whispersystems/signalservice/api/attachment/AttachmentUploadResult.kt @@ -14,7 +14,6 @@ class AttachmentUploadResult( val remoteId: SignalServiceAttachmentRemoteId, val cdnNumber: Int, val key: ByteArray, - val iv: ByteArray, val digest: ByteArray, val incrementalDigest: ByteArray?, val incrementalDigestChunkSize: Int, diff --git a/libsignal-service/src/main/java/org/whispersystems/signalservice/api/backup/MediaName.kt b/libsignal-service/src/main/java/org/whispersystems/signalservice/api/backup/MediaName.kt index 479225db4f..cd4b5efd7b 100644 --- a/libsignal-service/src/main/java/org/whispersystems/signalservice/api/backup/MediaName.kt +++ b/libsignal-service/src/main/java/org/whispersystems/signalservice/api/backup/MediaName.kt @@ -14,8 +14,8 @@ import org.signal.core.util.Hex value class MediaName(val name: String) { companion object { - fun fromDigest(digest: ByteArray) = MediaName(Hex.toStringCondensed(digest)) - fun fromDigestForThumbnail(digest: ByteArray) = MediaName("${Hex.toStringCondensed(digest)}_thumbnail") + fun fromPlaintextHashAndRemoteKey(plaintextHash: ByteArray, remoteKey: ByteArray) = MediaName(Hex.toStringCondensed(plaintextHash + remoteKey)) + fun fromPlaintextHashAndRemoteKeyForThumbnail(plaintextHash: ByteArray, remoteKey: ByteArray) = MediaName(Hex.toStringCondensed(plaintextHash + remoteKey) + "_thumbnail") fun forThumbnailFromMediaName(mediaName: String) = MediaName("${mediaName}_thumbnail") /** diff --git a/libsignal-service/src/main/java/org/whispersystems/signalservice/api/crypto/AttachmentCipherInputStream.kt b/libsignal-service/src/main/java/org/whispersystems/signalservice/api/crypto/AttachmentCipherInputStream.kt index 22e4417169..e97ea7c1ec 100644 --- a/libsignal-service/src/main/java/org/whispersystems/signalservice/api/crypto/AttachmentCipherInputStream.kt +++ b/libsignal-service/src/main/java/org/whispersystems/signalservice/api/crypto/AttachmentCipherInputStream.kt @@ -96,56 +96,6 @@ object AttachmentCipherInputStream { ) } - /** - * After removing the server layer of encryption using [createForArchivedMediaOuterLayer], use this to decrypt the inner layer of the attachment. - * Thumbnails have a special path because we don't do any additional digest/hash validation on them. - */ - @JvmStatic - @Throws(InvalidMessageException::class, IOException::class) - fun createForArchiveThumbnailInnerLayer( - file: File, - plaintextLength: Long, - combinedKeyMaterial: ByteArray - ): LimitedInputStream { - return create( - streamSupplier = { FileInputStream(file) }, - streamLength = file.length(), - plaintextLength = plaintextLength, - combinedKeyMaterial = combinedKeyMaterial, - digest = null, - incrementalDigest = null, - incrementalMacChunkSize = 0, - ignoreDigest = true - ) - } - - /** - * When you archive an attachment, you give the server an encrypted attachment, and the server wraps it in *another* layer of encryption. - * This will return a stream that unwraps the server's layer of encryption, giving you a stream that contains a "normally-encrypted" attachment. - * - * Because we're validating the encryptedDigest/plaintextHash of the inner layer, there's no additional out-of-band validation of this outer layer. - */ - @JvmStatic - @Throws(InvalidMessageException::class, IOException::class) - fun createForArchivedMediaOuterLayer(archivedMediaKeyMaterial: MediaKeyMaterial, file: File, originalCipherTextLength: Long): LimitedInputStream { - val mac = initMac(archivedMediaKeyMaterial.macKey) - - if (file.length() <= BLOCK_SIZE + mac.macLength) { - throw InvalidMessageException("Message shorter than crypto overhead!") - } - - FileInputStream(file).use { macVerificationStream -> - verifyMac(macVerificationStream, file.length(), mac, null) - } - - val encryptedStream = FileInputStream(file) - val encryptedStreamExcludingMac = LimitedInputStream(encryptedStream, file.length() - mac.macLength) - val cipher = createCipher(encryptedStreamExcludingMac, archivedMediaKeyMaterial.aesKey) - val inputStream: InputStream = BetterCipherInputStream(encryptedStreamExcludingMac, cipher) - - return LimitedInputStream(inputStream, originalCipherTextLength) - } - /** * When you archive an attachment, you give the server an encrypted attachment, and the server wraps it in *another* layer of encryption. * @@ -156,7 +106,7 @@ object AttachmentCipherInputStream { */ @JvmStatic @Throws(InvalidMessageException::class, IOException::class) - fun createForArchivedMediaOuterAndInnerLayers( + fun createForArchivedMedia( archivedMediaKeyMaterial: MediaKeyMaterial, file: File, originalCipherTextLength: Long, @@ -185,6 +135,42 @@ object AttachmentCipherInputStream { ) } + /** + * When you archive an attachment, you give the server an encrypted attachment, and the server wraps it in *another* layer of encryption. + * + * This creates a stream decrypt both the inner and outer layers of an archived attachment at the same time by basically double-decrypting it. + * + * @param incrementalDigest If null, incremental mac validation is disabled. + * @param incrementalMacChunkSize If 0, incremental mac validation is disabled. + */ + @JvmStatic + @Throws(InvalidMessageException::class, IOException::class) + fun createForArchivedThumbnail( + archivedMediaKeyMaterial: MediaKeyMaterial, + file: File, + originalCipherTextLength: Long, + plaintextLength: Long, + combinedKeyMaterial: ByteArray + ): LimitedInputStream { + val keyMaterial = CombinedKeyMaterial.from(combinedKeyMaterial) + val mac = initMac(keyMaterial.macKey) + + if (originalCipherTextLength <= BLOCK_SIZE + mac.macLength) { + throw InvalidMessageException("Message shorter than crypto overhead!") + } + + return create( + streamSupplier = { createForArchivedMediaOuterLayer(archivedMediaKeyMaterial, file, originalCipherTextLength) }, + streamLength = originalCipherTextLength, + plaintextLength = plaintextLength, + combinedKeyMaterial = combinedKeyMaterial, + digest = null, + incrementalDigest = null, + incrementalMacChunkSize = 0, + ignoreDigest = true + ) + } + /** * Creates a stream to decrypt sticker data. Stickers have a special path because the key material is derived from the pack key. */ @@ -209,6 +195,33 @@ object AttachmentCipherInputStream { return BetterCipherInputStream(encryptedStreamExcludingMac, cipher) } + /** + * When you archive an attachment, you give the server an encrypted attachment, and the server wraps it in *another* layer of encryption. + * This will return a stream that unwraps the server's layer of encryption, giving you a stream that contains a "normally-encrypted" attachment. + * + * Because we're validating the encryptedDigest/plaintextHash of the inner layer, there's no additional out-of-band validation of this outer layer. + */ + @JvmStatic + @Throws(InvalidMessageException::class, IOException::class) + private fun createForArchivedMediaOuterLayer(archivedMediaKeyMaterial: MediaKeyMaterial, file: File, originalCipherTextLength: Long): LimitedInputStream { + val mac = initMac(archivedMediaKeyMaterial.macKey) + + if (file.length() <= BLOCK_SIZE + mac.macLength) { + throw InvalidMessageException("Message shorter than crypto overhead!") + } + + FileInputStream(file).use { macVerificationStream -> + verifyMac(macVerificationStream, file.length(), mac, null) + } + + val encryptedStream = FileInputStream(file) + val encryptedStreamExcludingMac = LimitedInputStream(encryptedStream, file.length() - mac.macLength) + val cipher = createCipher(encryptedStreamExcludingMac, archivedMediaKeyMaterial.aesKey) + val inputStream: InputStream = BetterCipherInputStream(encryptedStreamExcludingMac, cipher) + + return LimitedInputStream(inputStream, originalCipherTextLength) + } + @JvmStatic @Throws(InvalidMessageException::class, IOException::class) private fun create( diff --git a/libsignal-service/src/test/java/org/whispersystems/signalservice/api/crypto/AttachmentCipherTest.kt b/libsignal-service/src/test/java/org/whispersystems/signalservice/api/crypto/AttachmentCipherTest.kt index 0ac129f145..cc47e7bed6 100644 --- a/libsignal-service/src/test/java/org/whispersystems/signalservice/api/crypto/AttachmentCipherTest.kt +++ b/libsignal-service/src/test/java/org/whispersystems/signalservice/api/crypto/AttachmentCipherTest.kt @@ -9,7 +9,6 @@ import org.junit.Assert import org.junit.Test import org.signal.core.util.StreamUtil import org.signal.core.util.allMatch -import org.signal.core.util.copyTo import org.signal.core.util.readFully import org.signal.core.util.stream.LimitedInputStream import org.signal.libsignal.protocol.InvalidMessageException @@ -224,89 +223,72 @@ class AttachmentCipherTest { } @Test - fun attachment_encryptDecryptPaddedContent() { - val lengths = intArrayOf(531, 600, 724, 1019, 1024) - - for (length in lengths) { - val plaintextInput = ByteArray(length) - - for (i in 0..