From 59bb505a3ef8f766fe776838efd7ac64270f7c74 Mon Sep 17 00:00:00 2001 From: jeffrey-signal Date: Wed, 11 Feb 2026 18:06:18 -0500 Subject: [PATCH] Support member labels in backups. --- .../backupTests/recipient_groups_00.binproto | Bin 1362 -> 1362 bytes .../backupTests/recipient_groups_01.binproto | Bin 1551 -> 1606 bytes .../backupTests/recipient_groups_02.binproto | Bin 1501 -> 1539 bytes .../backupTests/recipient_groups_03.binproto | Bin 1499 -> 1513 bytes .../backupTests/recipient_groups_04.binproto | Bin 1364 -> 1463 bytes .../backupTests/recipient_groups_05.binproto | Bin 1549 -> 1364 bytes .../backupTests/recipient_groups_06.binproto | Bin 1501 -> 1602 bytes .../backupTests/recipient_groups_07.binproto | Bin 1501 -> 1543 bytes .../backupTests/recipient_groups_08.binproto | Bin 1362 -> 1511 bytes .../backupTests/recipient_groups_09.binproto | Bin 1549 -> 1463 bytes .../backupTests/recipient_groups_10.binproto | Bin 1503 -> 1364 bytes .../backupTests/recipient_groups_11.binproto | Bin 1499 -> 1604 bytes .../securesms/testing/GroupTestingUtils.kt | 4 +++- .../v2/exporters/GroupArchiveExporter.kt | 8 +++++++- .../v2/importer/GroupArchiveImporter.kt | 8 +++++++- app/src/main/protowire/Backup.proto | 2 ++ .../databaseprotos/DecryptedGroupHelper.kt | 8 +++++--- 17 files changed, 24 insertions(+), 6 deletions(-) diff --git a/app/src/androidTest/assets/backupTests/recipient_groups_00.binproto b/app/src/androidTest/assets/backupTests/recipient_groups_00.binproto index a0ff00d246c5dbca8d673fc7b5bb8ebce9fcabb5..ae6049a22f2ae7645aaadd5324123d96a546122b 100644 GIT binary patch delta 94 zcmV-k0HOcV3epO&w*(^4m0aaI*DzP*%0v@_1)((%$(wRghcNexsEv1h`Fr9jY?Ipr zN-r*$O=T|E36_^i^{1p+WeO#b@6n7Tp4-Iw3R#26=>uQ^FabCK2pR?m0T2pM0VgRZ Ax&QzG delta 94 zcmV-k0HOcV3epO&w*(}%J39zSu9D{94N=}F#Tt=PE3eyLqImrn0V-;f z*#t^03?jPOlug8ukgcn_igLcYO}RPXG%DaV-M)Y1W&N{7FabCK2pR?m0T2pM0qp)L AMgRZ+ diff --git a/app/src/androidTest/assets/backupTests/recipient_groups_01.binproto b/app/src/androidTest/assets/backupTests/recipient_groups_01.binproto index d24c86d2df5a4f40ebc8e7d270bc30c132d54eb5..7262c9df4f56ac389eb1ae2620bbb191e7ce96f4 100644 GIT binary patch delta 251 zcmeC@ImWYLHH%3nvrro|2bWYMGnc}JsWDHjt{a3uJ>??Y#JbQ_;N&2UgJ}9=Ft@qD%$HoRZX{L@OOG0S1Osj0_A83=Irm zz$n0I#PVVOqy{U2kfOxolEjkyVg<+4ywt=zD^-wc5I|OK#qU^9kXV$OSfb#PnOvGz zGP!}(!FN*SixaFj+IF^Ao@v=;ZO!4aZql;{yn*-BA2*j&I8RT>k_4Oe3&pI*cegD3 YY+}L4FU8BjD8Qw0py}Q9Iko|e09FQ16#xJL delta 212 zcmX@c)6cVEHH*tef=g0dL?v^~cR670%OBc#cX<4ANeI zJ8n_MUjar1My>gi@3SO1if{=qFmQ7-FgP$YFn|H00FxD1^b{kCC?iA^qy|YXjj%@%V01U}H-T(jq diff --git a/app/src/androidTest/assets/backupTests/recipient_groups_02.binproto b/app/src/androidTest/assets/backupTests/recipient_groups_02.binproto index e63ee49832cc4604d7add9b4cd9ac08fb719ef9e..dc77758be1f7d6b217ef4316ed93ca4d952a300c 100644 GIT binary patch delta 203 zcmcc1-ORILHH+afCZWSj99&ZSn79-!OpSSJb=@HR=_wcCCf0?f0w-q|1+^P|?_SYc zUi-89kph#}RHn)ISUOahtdzI}7#O&@85kTG8W_NUQGn5k$1Sy}C{w{PrzEu~adIH5 zc(M*i9S9(+Gh+ELe^P^$fM;G=YF=hhDo{gaYF=q>kb=~L1YWjn%KP5_n|@L1N64Ri oH>W2)O_r|?-KpleP-<$Fz-Yn5FU8BjD8Qw0tef=g0dL?v^~cR670%OBc#cX<4ANeI zJ8n_MUkOG9Cat%Olkc!}=rdZ0a0xIlaC0*-I50FYfB~Zb6GZeBBZ??c?c{~5A|^o! zvR-RXN{1wK_KVL6c(sRj&9)y?{_CC%T%i6f_wy6xk9#ec_@#I`7zMaAZrnXIWjSjA FBLJEQGkE|2 diff --git a/app/src/androidTest/assets/backupTests/recipient_groups_03.binproto b/app/src/androidTest/assets/backupTests/recipient_groups_03.binproto index e243c2d0902d791ab0e9359152e5aa784c76d8ab..feb69841a630d8eea7faa207a7516dd3c166e79b 100644 GIT binary patch delta 180 zcmcc3{gQjbY8HbvOhPM}IJl&iFmWkdm>Toc>bgPr(^D?OO{@z|1y0T`3Tij_-o2u? zy!L1HBMC;WpObI0xG5`f2{15lb2BhFFf=fL0iytu6^~nLQBkIXV@^qGQQ~A1)-Zq0 zs+(I5$K@7i840>{R%finl28xtuv$p2&SU2g}1Kz-U>W`aCDx9aM@Enzz7^J=a zcHE+hzgll6-)3f?_Lu{o>5@yu=*6{GxRI z)R2-if8T2L`!Fq~p!U~ph)sAm8JMgc}6mJjnMHCPFR z6eT8?B$nhCD>$a+r6%TCi2#*z37!KhhpA?=QUw_T0zgB+Gy~8KD}KjOoYZ delta 178 zcmdnaeT8eoYL@zWj6$;+Ik=>zF>)zvv$p2&SU2g}1Kz-U>W`aCDx9aM@Enzz7^J=a zcHE+hzXFUBj0%ieSwcKqT%jcj&ZSA2Ihl!CY#dAiOcKlnYuYcLV73zB5@6sGJjcM` zz|g<|28;rXU{Np!Su{w2M@wnf%_+V|CQewpdRJG`zTLh%EgzU@Jutnyul`Bu-_5QT OEF4m79E<{70gM2t{4@#x diff --git a/app/src/androidTest/assets/backupTests/recipient_groups_05.binproto b/app/src/androidTest/assets/backupTests/recipient_groups_05.binproto index 29db15b54fe3890ce639e60d8c08a329ab290105..a68416552654574b56aafa9e6db611ac46a2bc27 100644 GIT binary patch delta 146 zcmV;D0B!$`4Acs+s{~e_0TP=52nrgO0SX|{m0aaI*DzP*%0v@_1)((%$(wRghcNex zsEv1h`Fr9R0U!b@Y!VC#3RQFkCZV%T99&W-n79tef=g0dL?v^~cR670%OBc#cX<4ANeI zJ8n_MUj-(u`AkBBT>Q@YdFiF83T}zTC7CIinNi|OqJ^dTDGHgTDVfQMNtq=IiKWRU z`9)GP86_nJ#a8NjgX4hilU>0DOU@`dD z`f~=Wl?ayr0|PfV1A_xY0|OW^3NS%LPccqrWL2qm(%=FsVz`B(h*3y@flKflvY3|; z$S{U?$YMbXwcApkrvE)Hb*y#8y4#oLY|)$Ho2qx6bJ}#TugjN2rg9}PW=Vqe{X*6! fu;J#@CGU(ZSOxf{csUpaxHJwly}LfgHh>WTD2`sa diff --git a/app/src/androidTest/assets/backupTests/recipient_groups_06.binproto b/app/src/androidTest/assets/backupTests/recipient_groups_06.binproto index fe0b3ac6ed0af297383d131797d82357f2c6e73b..80535c55d36c1e2ff4780e00fa51b09644b28899 100644 GIT binary patch delta 418 zcmcc1eTZknYL@y|W}zl#4lb#`Ok4^Vrp7$Ax^58u^puNm6YD}#fs?a~g4zwfcdzIz zul-s5Nb3rdkRTVobADcWX{v%-VsS}kN@ix1xRPjLX?}`AW@$=ha$-_ui9%v&a!G!X zluSlRNkOrdzJ76LdR}6VUVc%!eriZbn!j&BN~RK<#EC^c^{?5r*f^L4m?c;Y{4Z>D~1?wgHR)g0OV3 delta 300 zcmX@abC-L=YL@y1OhR*+IJl%{FmWktv$p2&SU2g}1Kz-U>W`aCDx9aM@Enzz7^J=a zcHE+hzY>gEZyAMnxww7vi;^-GTr!grOQN)tG*a@DQ}a?X6$*;-GxHRRQq%H_ax+sB z^NJPnixNvR^A(CR^7E2Qi=`AZN=gcft@QPaGt=`DbM*3yg46Y*{3FBDTtdF;(jm#5{o->1UhUysv+c)}|GH-b7pQ;B{rrUa<6Z+s3pRc! TUJgb9E{z*^4^3Il8o&qu5nEbt diff --git a/app/src/androidTest/assets/backupTests/recipient_groups_07.binproto b/app/src/androidTest/assets/backupTests/recipient_groups_07.binproto index 8f47bd5683bd47aa5f8527f042d527484c156795..194750b17c2ac0e471a5acb01b653a690604f064 100644 GIT binary patch delta 358 zcmcc1-OjUNHB0>|CZXd@99&X|n79-!OpSSJb=@HR=_wcCCf0?f0w-q|1+^P|?_SYc zUi-89kpQCvqXMJWR3;%_E^goaqNGd(m(1kEk|-@Djg zqlhwE@wlZH6=f`csUpaxHN9u LJv3!GYXBnvh$L!4 delta 305 zcmZqYxy!v_HB0>hCZV}Z99&W}n79tef=g0dL?v^~cR670%OBc#cX<4ANeI zJ8n_MUjar1MyW-Adc0R}F?bCajC^4EjdVBo;e0AVl+ zFgj^)LBww{Fd&Nyf%PGac?p5_ze5%aQrN!LY!0)(zM@i}MF01cD(_OeSZV3=YcFlr wm^@=r<%<&uj9HRkeZN$ZH41FJ`Extem>Toc>bgPr(^D?OO{@z|1y0T`3Tij_-o2u? zy!L1HBLya{pNv90TwI|g3eKfTnK_w>QF2N$W%)U!xuwMlsYONkMG85o`3fb8$(bdY z3WcTlN^BBq9{*axti{H`EWj+mVz8$D@(E@uB`yI525xQ!1}O)I1_m%-6kxLAaRZu> zsozFmfquv$p2&SU2g}1Kz-U>W`aCDx9aM@Enzz7^J=a zcHE+hzY>fJOj=n&JX~C%B?``^NtrpBiCSzNOae?2%m!=PFP~tx65$eH;1WE?z~I2p zzyJn}0*qi$Fb7#QNP$Obm&VO0zDFibSi5>xSJA%RzB?@+m}osPy}PgeN$TItt`-~| MQfwTI0$c%%0F(4IBme*a diff --git a/app/src/androidTest/assets/backupTests/recipient_groups_09.binproto b/app/src/androidTest/assets/backupTests/recipient_groups_09.binproto index 9cac939452ecaefddf0c5e174459dd996d2d0ac6..906ebfb82bc68b93dba4d27e3476b0536f0ea7a2 100644 GIT binary patch delta 252 zcmeC>+0MOTHH%9llh8j#4lb#mj9dyArp7$Ax^58u^puNm6YD}#fs?a~g4zwfcdzIz zul-s5NP$a+r6%TCi2zk|37$hy&19tt zG6MvV&9LHkEGS4UN=+mzgiy0~-s`bR4A bTeAH2S@PXaU^HN~;N*~E<6sov3Sa~Pl(tHU delta 323 zcmdna-OICKHB0mbCZV%T99&W-n79tef=g0dL?v^~cR670%OBc#cX<4ANeI zJ8n_MU#(3diRw7&i3=G`d3=9qo4GdtwD8K{}J;jJ3 z%4j7rIgwSQ-bsTCtcl?ksR9WFb+<3g z*`hbYH&yRC=d|fwUzab5Oyx>o%#sA_`-QAeV8hL)OWqk7FbY|4@=Nh@FbZ&K9B6uX JeU5DaBLKfxS0(@e diff --git a/app/src/androidTest/assets/backupTests/recipient_groups_10.binproto b/app/src/androidTest/assets/backupTests/recipient_groups_10.binproto index 22a3d4bd8ccf7235e750674e12ea47db04e82de1..b6e89deb4137bc1a787212c1e6d83154455ecede 100644 GIT binary patch delta 144 zcmV;B0B`@_3)Bj*s{~e_0TP=52nrgO0SX|{m0aaI*DzP*%0v@_1)((%$(wRghcNex zsEv1h`Fr9J0U!Y?Y!VC#3RQFuQ^I0^_F1_%KV3Qz&C3NlLo delta 261 zcmV+g0s8*b3f~K`s|0_d0urAB2nrgS0tz6uJ39zSu9D{94N=}F#Tt=P zE3eyLqImrf0T=-w0V?eQ5)BFqO>c5yX&^*tV_|e!Dk3OkZ)0U{WN9F9a&KvFAaZ49 zZ*pyEWMOV|Aa8PEbZKuOa%gXEV|8;HA!u}TaC15@FLP;UZeb~GE^l&YFIrDoS7t<1 zXK+bMad}fB1sJ!k_f{$f2m%lS7y~e@p~0L1llcT37z+yk06+kM000000003H0y-25 z5C8zm0h0j*CNdpLt;riyV+oHJoKWh#4Xn2Kl>aTwQJ^RGZS&*<@x3?-4;l>!0T2o( L*xkaErv*>}>?Bxj diff --git a/app/src/androidTest/assets/backupTests/recipient_groups_11.binproto b/app/src/androidTest/assets/backupTests/recipient_groups_11.binproto index 5f09c1c2769eded2b1766d56792774968229a9c6..ae0734648656831173752b124745a7f6db63249d 100644 GIT binary patch delta 360 zcmcc3eS~MjYL@zTW}y~l4lb$xOk4^Vrp7$Ax^58u^puNm6YD}#fs?a~g4zwfcdzIz zul-s5NPxtuv$p2&SU2g}1Kz-U>W`aCDx9aM@Enzz7^J=a zcHE+hzY0uRZyAMnxVS<~6r4+wGIKH$qvVui%JOqcb4!aAQj3c6ixhHF^A$=GlQT;) z6$(r9mDnWKJpQ$WS&NN>S%6uB#b8bQ{?RoaR7_%gSW->7RVqieh eyz%DKCGU(ZxcQ}cIT!`FG#>QNxPL=3fDr&_d`znV diff --git a/app/src/androidTest/java/org/thoughtcrime/securesms/testing/GroupTestingUtils.kt b/app/src/androidTest/java/org/thoughtcrime/securesms/testing/GroupTestingUtils.kt index 3b0837d45f..84068bf036 100644 --- a/app/src/androidTest/java/org/thoughtcrime/securesms/testing/GroupTestingUtils.kt +++ b/app/src/androidTest/java/org/thoughtcrime/securesms/testing/GroupTestingUtils.kt @@ -17,11 +17,13 @@ import kotlin.random.Random * Helper methods for creating groups for message processing tests et al. */ object GroupTestingUtils { - fun member(aci: ACI, revision: Int = 0, role: Member.Role = Member.Role.ADMINISTRATOR): DecryptedMember { + fun member(aci: ACI, revision: Int = 0, role: Member.Role = Member.Role.ADMINISTRATOR, labelEmoji: String = "", labelString: String = ""): DecryptedMember { return DecryptedMember.Builder() .aciBytes(aci.toByteString()) .joinedAtRevision(revision) .role(role) + .labelEmoji(labelEmoji) + .labelString(labelString) .build() } diff --git a/app/src/main/java/org/thoughtcrime/securesms/backup/v2/exporters/GroupArchiveExporter.kt b/app/src/main/java/org/thoughtcrime/securesms/backup/v2/exporters/GroupArchiveExporter.kt index 9c9fd74cee..4a57cb0f46 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/backup/v2/exporters/GroupArchiveExporter.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/backup/v2/exporters/GroupArchiveExporter.kt @@ -123,7 +123,13 @@ private fun Member.Role.toRemote(): Group.Member.Role { } private fun DecryptedMember.toRemote(): Group.Member { - return Group.Member(userId = aciBytes, role = role.toRemote(), joinedAtVersion = joinedAtRevision) + return Group.Member( + userId = aciBytes, + role = role.toRemote(), + joinedAtVersion = joinedAtRevision, + labelEmoji = labelEmoji, + labelString = labelString + ) } private fun DecryptedPendingMember.toRemote(): Group.MemberPendingProfileKey { diff --git a/app/src/main/java/org/thoughtcrime/securesms/backup/v2/importer/GroupArchiveImporter.kt b/app/src/main/java/org/thoughtcrime/securesms/backup/v2/importer/GroupArchiveImporter.kt index c4b5060935..fae6882b2f 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/backup/v2/importer/GroupArchiveImporter.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/backup/v2/importer/GroupArchiveImporter.kt @@ -116,7 +116,13 @@ private fun Group.Member.Role.toLocal(): Member.Role { } private fun Group.Member.toLocal(): DecryptedMember { - return DecryptedMember(aciBytes = userId, role = role.toLocal(), joinedAtRevision = joinedAtVersion) + return DecryptedMember( + aciBytes = userId, + role = role.toLocal(), + joinedAtRevision = joinedAtVersion, + labelEmoji = labelEmoji, + labelString = labelString + ) } private fun Group.MemberPendingAdminApproval.toLocal(): DecryptedRequestingMember { diff --git a/app/src/main/protowire/Backup.proto b/app/src/main/protowire/Backup.proto index 5374d79f1e..5a6914488a 100644 --- a/app/src/main/protowire/Backup.proto +++ b/app/src/main/protowire/Backup.proto @@ -331,6 +331,8 @@ message Group { reserved /*profileKey*/ 3; // This field is ignored in Backups, in favor of Contact frames for members reserved /*presentation*/ 4; // This field is deprecated in the context of static group state uint32 joinedAtVersion = 5; + string labelEmoji = 6; + string labelString = 7; } message MemberPendingProfileKey { diff --git a/app/src/testShared/org/thoughtcrime/securesms/database/model/databaseprotos/DecryptedGroupHelper.kt b/app/src/testShared/org/thoughtcrime/securesms/database/model/databaseprotos/DecryptedGroupHelper.kt index 846e07524d..97f4189e5a 100644 --- a/app/src/testShared/org/thoughtcrime/securesms/database/model/databaseprotos/DecryptedGroupHelper.kt +++ b/app/src/testShared/org/thoughtcrime/securesms/database/model/databaseprotos/DecryptedGroupHelper.kt @@ -42,15 +42,17 @@ fun DecryptedGroupChange.Builder.addMember(aci: ACI) { newMembers += member(aci) } -fun member(serviceId: UUID, role: Member.Role = Member.Role.DEFAULT, joinedAt: Int = 0): DecryptedMember { - return member(ACI.from(serviceId), role, joinedAt) +fun member(serviceId: UUID, role: Member.Role = Member.Role.DEFAULT, joinedAt: Int = 0, labelEmoji: String = "", labelString: String = ""): DecryptedMember { + return member(ACI.from(serviceId), role, joinedAt, labelEmoji, labelString) } -fun member(aci: ACI, role: Member.Role = Member.Role.DEFAULT, joinedAt: Int = 0): DecryptedMember { +fun member(aci: ACI, role: Member.Role = Member.Role.DEFAULT, joinedAt: Int = 0, labelEmoji: String = "", labelString: String = ""): DecryptedMember { return DecryptedMember.Builder() .role(role) .aciBytes(aci.toByteString()) .joinedAtRevision(joinedAt) + .labelEmoji(labelEmoji) + .labelString(labelString) .build() }