1 package org
.asamk
.signal
.manager
.syncStorage
;
3 import org
.asamk
.signal
.manager
.api
.PhoneNumberSharingMode
;
4 import org
.asamk
.signal
.manager
.api
.TrustLevel
;
5 import org
.asamk
.signal
.manager
.storage
.configuration
.ConfigurationStore
;
6 import org
.asamk
.signal
.manager
.storage
.groups
.GroupInfoV1
;
7 import org
.asamk
.signal
.manager
.storage
.groups
.GroupInfoV2
;
8 import org
.asamk
.signal
.manager
.storage
.identities
.IdentityInfo
;
9 import org
.asamk
.signal
.manager
.storage
.recipients
.Recipient
;
10 import org
.whispersystems
.signalservice
.api
.push
.ServiceId
.ACI
;
11 import org
.whispersystems
.signalservice
.api
.push
.ServiceId
.PNI
;
12 import org
.whispersystems
.signalservice
.api
.push
.UsernameLinkComponents
;
13 import org
.whispersystems
.signalservice
.api
.storage
.SignalAccountRecord
;
14 import org
.whispersystems
.signalservice
.api
.storage
.SignalContactRecord
;
15 import org
.whispersystems
.signalservice
.api
.storage
.SignalGroupV1Record
;
16 import org
.whispersystems
.signalservice
.api
.storage
.SignalGroupV2Record
;
17 import org
.whispersystems
.signalservice
.api
.util
.UuidUtil
;
18 import org
.whispersystems
.signalservice
.internal
.storage
.protos
.AccountRecord
;
19 import org
.whispersystems
.signalservice
.internal
.storage
.protos
.AccountRecord
.UsernameLink
;
20 import org
.whispersystems
.signalservice
.internal
.storage
.protos
.ContactRecord
;
21 import org
.whispersystems
.signalservice
.internal
.storage
.protos
.ContactRecord
.IdentityState
;
22 import org
.whispersystems
.signalservice
.internal
.storage
.protos
.GroupV1Record
;
23 import org
.whispersystems
.signalservice
.internal
.storage
.protos
.GroupV2Record
;
25 import java
.util
.Optional
;
27 import okio
.ByteString
;
29 import static org
.signal
.core
.util
.StringExtensionsKt
.emptyIfNull
;
31 public final class StorageSyncModels
{
33 private StorageSyncModels() {
36 public static AccountRecord
.PhoneNumberSharingMode
localToRemote(PhoneNumberSharingMode phoneNumberPhoneNumberSharingMode
) {
37 return switch (phoneNumberPhoneNumberSharingMode
) {
38 case EVERYBODY
-> AccountRecord
.PhoneNumberSharingMode
.EVERYBODY
;
39 case CONTACTS
, NOBODY
-> AccountRecord
.PhoneNumberSharingMode
.NOBODY
;
43 public static PhoneNumberSharingMode
remoteToLocal(AccountRecord
.PhoneNumberSharingMode phoneNumberPhoneNumberSharingMode
) {
44 return switch (phoneNumberPhoneNumberSharingMode
) {
45 case EVERYBODY
-> PhoneNumberSharingMode
.EVERYBODY
;
46 case NOBODY
-> PhoneNumberSharingMode
.NOBODY
;
51 public static AccountRecord
localToRemoteRecord(
52 ConfigurationStore configStore
,
54 UsernameLinkComponents usernameLinkComponents
56 final var builder
= SignalAccountRecord
.Companion
.newBuilder(self
.getStorageRecord());
57 if (self
.getProfileKey() != null) {
58 builder
.profileKey(ByteString
.of(self
.getProfileKey().serialize()));
60 if (self
.getProfile() != null) {
61 builder
.givenName(emptyIfNull(self
.getProfile().getGivenName()))
62 .familyName(emptyIfNull(self
.getProfile().getFamilyName()))
63 .avatarUrlPath(emptyIfNull(self
.getProfile().getAvatarUrlPath()));
65 builder
.typingIndicators(Optional
.ofNullable(configStore
.getTypingIndicators()).orElse(true))
66 .readReceipts(Optional
.ofNullable(configStore
.getReadReceipts()).orElse(true))
67 .sealedSenderIndicators(Optional
.ofNullable(configStore
.getUnidentifiedDeliveryIndicators())
69 .linkPreviews(Optional
.ofNullable(configStore
.getLinkPreviews()).orElse(true))
70 .unlistedPhoneNumber(Optional
.ofNullable(configStore
.getPhoneNumberUnlisted()).orElse(false))
71 .phoneNumberSharingMode(Optional
.ofNullable(configStore
.getPhoneNumberSharingMode())
72 .map(StorageSyncModels
::localToRemote
)
73 .orElse(AccountRecord
.PhoneNumberSharingMode
.UNKNOWN
))
74 .e164(self
.getAddress().number().orElse(""))
75 .username(self
.getAddress().username().orElse(""));
76 if (usernameLinkComponents
!= null) {
77 final var linkColor
= configStore
.getUsernameLinkColor();
78 builder
.usernameLink(new UsernameLink
.Builder().entropy(ByteString
.of(usernameLinkComponents
.getEntropy()))
79 .serverId(UuidUtil
.toByteString(usernameLinkComponents
.getServerId()))
80 .color(linkColor
== null ? UsernameLink
.Color
.UNKNOWN
: UsernameLink
.Color
.valueOf(linkColor
))
84 return builder
.build();
87 public static ContactRecord
localToRemoteRecord(Recipient recipient
, IdentityInfo identity
) {
88 final var address
= recipient
.getAddress();
89 final var builder
= SignalContactRecord
.Companion
.newBuilder(recipient
.getStorageRecord())
90 .aci(address
.aci().map(ACI
::toString
).orElse(""))
91 .e164(address
.number().orElse(""))
92 .pni(address
.pni().map(PNI
::toString
).orElse(""))
93 .username(address
.username().orElse(""))
94 .profileKey(recipient
.getProfileKey() == null
96 : ByteString
.of(recipient
.getProfileKey().serialize()));
97 if (recipient
.getProfile() != null) {
98 builder
.givenName(emptyIfNull(recipient
.getProfile().getGivenName()))
99 .familyName(emptyIfNull(recipient
.getProfile().getFamilyName()));
101 if (recipient
.getContact() != null) {
102 builder
.systemGivenName(emptyIfNull(recipient
.getContact().givenName()))
103 .systemFamilyName(emptyIfNull(recipient
.getContact().familyName()))
104 .systemNickname(emptyIfNull(recipient
.getContact().nickName()))
105 .nickname(new ContactRecord
.Name
.Builder().given(emptyIfNull(recipient
.getContact()
106 .nickNameGivenName()))
107 .family(emptyIfNull(recipient
.getContact().nickNameFamilyName()))
109 .note(emptyIfNull(recipient
.getContact().note()))
110 .blocked(recipient
.getContact().isBlocked())
111 .whitelisted(recipient
.getContact().isProfileSharingEnabled())
112 .mutedUntilTimestamp(recipient
.getContact().muteUntil())
113 .hideStory(recipient
.getContact().hideStory())
114 .unregisteredAtTimestamp(recipient
.getContact().unregisteredTimestamp() == null
116 : recipient
.getContact().unregisteredTimestamp())
117 .archived(recipient
.getContact().isArchived())
118 .hidden(recipient
.getContact().isHidden());
120 if (identity
!= null) {
121 builder
.identityKey(ByteString
.of(identity
.getIdentityKey().serialize()))
122 .identityState(localToRemote(identity
.getTrustLevel()));
124 return builder
.build();
127 public static GroupV1Record
localToRemoteRecord(GroupInfoV1 group
) {
128 final var builder
= SignalGroupV1Record
.Companion
.newBuilder(group
.getStorageRecord());
129 builder
.id(ByteString
.of(group
.getGroupId().serialize()));
130 builder
.blocked(group
.isBlocked());
131 builder
.archived(group
.archived
);
132 builder
.whitelisted(true);
133 return builder
.build();
136 public static GroupV2Record
localToRemoteRecord(GroupInfoV2 group
) {
137 final var builder
= SignalGroupV2Record
.Companion
.newBuilder(group
.getStorageRecord());
138 builder
.masterKey(ByteString
.of(group
.getMasterKey().serialize()));
139 builder
.blocked(group
.isBlocked());
140 builder
.whitelisted(group
.isProfileSharingEnabled());
141 return builder
.build();
144 public static TrustLevel
remoteToLocal(IdentityState identityState
) {
145 return switch (identityState
) {
146 case DEFAULT
-> TrustLevel
.TRUSTED_UNVERIFIED
;
147 case UNVERIFIED
-> TrustLevel
.UNTRUSTED
;
148 case VERIFIED
-> TrustLevel
.TRUSTED_VERIFIED
;
152 private static IdentityState
localToRemote(TrustLevel local
) {
153 return switch (local
) {
154 case TRUSTED_VERIFIED
-> IdentityState
.VERIFIED
;
155 case UNTRUSTED
-> IdentityState
.UNVERIFIED
;
156 default -> IdentityState
.DEFAULT
;