1 package org
.asamk
.signal
.manager
.syncStorage
;
3 import org
.asamk
.signal
.manager
.groups
.GroupUtils
;
4 import org
.asamk
.signal
.manager
.storage
.SignalAccount
;
5 import org
.asamk
.signal
.manager
.util
.KeyUtils
;
6 import org
.jetbrains
.annotations
.NotNull
;
7 import org
.signal
.libsignal
.zkgroup
.InvalidInputException
;
8 import org
.signal
.libsignal
.zkgroup
.groups
.GroupMasterKey
;
9 import org
.slf4j
.Logger
;
10 import org
.slf4j
.LoggerFactory
;
11 import org
.whispersystems
.signalservice
.api
.storage
.SignalGroupV2Record
;
12 import org
.whispersystems
.signalservice
.api
.storage
.StorageId
;
13 import org
.whispersystems
.signalservice
.internal
.storage
.protos
.GroupV2Record
;
15 import java
.sql
.Connection
;
16 import java
.sql
.SQLException
;
17 import java
.util
.Arrays
;
18 import java
.util
.Optional
;
20 import okio
.ByteString
;
22 public final class GroupV2RecordProcessor
extends DefaultStorageRecordProcessor
<SignalGroupV2Record
> {
24 private static final Logger logger
= LoggerFactory
.getLogger(GroupV2RecordProcessor
.class);
25 private final SignalAccount account
;
26 private final Connection connection
;
28 public GroupV2RecordProcessor(SignalAccount account
, Connection connection
) {
29 this.account
= account
;
30 this.connection
= connection
;
34 protected boolean isInvalid(SignalGroupV2Record remote
) {
35 return remote
.getProto().masterKey
.size() != GroupMasterKey
.SIZE
;
39 protected Optional
<SignalGroupV2Record
> getMatching(SignalGroupV2Record remote
) throws SQLException
{
40 final var id
= GroupUtils
.getGroupIdV2(getGroupMasterKeyOrThrow(remote
.getProto().masterKey
));
41 final var group
= account
.getGroupStore().getGroup(connection
, id
);
44 return Optional
.empty();
47 final var storageId
= account
.getGroupStore().getGroupStorageId(connection
, id
);
48 return Optional
.of(new SignalGroupV2Record(storageId
, StorageSyncModels
.localToRemoteRecord(group
)));
52 protected SignalGroupV2Record
merge(SignalGroupV2Record remoteRecord
, SignalGroupV2Record localRecord
) {
53 final var remote
= remoteRecord
.getProto();
54 final var local
= localRecord
.getProto();
56 final var mergedBuilder
= SignalGroupV2Record
.Companion
.newBuilder(remote
.unknownFields().toByteArray())
57 .masterKey(remote
.masterKey
)
58 .blocked(remote
.blocked
)
59 .whitelisted(remote
.whitelisted
)
60 .archived(remote
.archived
)
61 .markedUnread(remote
.markedUnread
)
62 .mutedUntilTimestamp(remote
.mutedUntilTimestamp
)
63 .dontNotifyForMentionsIfMuted(remote
.dontNotifyForMentionsIfMuted
)
64 .hideStory(remote
.hideStory
)
65 .storySendMode(remote
.storySendMode
)
66 .avatarColor(remote
.avatarColor
);
67 final var merged
= mergedBuilder
.build();
69 final var matchesRemote
= doProtosMatch(merged
, remote
);
74 final var matchesLocal
= doProtosMatch(merged
, local
);
79 return new SignalGroupV2Record(StorageId
.forGroupV2(KeyUtils
.createRawStorageId()), mergedBuilder
.build());
83 protected void insertLocal(SignalGroupV2Record
record) throws SQLException
{
84 StorageRecordUpdate
<SignalGroupV2Record
> update
= new StorageRecordUpdate
<>(null, record);
89 protected void updateLocal(StorageRecordUpdate
<SignalGroupV2Record
> update
) throws SQLException
{
90 final var groupV2Record
= update
.newRecord();
91 final var groupV2Proto
= groupV2Record
.getProto();
92 final var groupMasterKey
= getGroupMasterKeyOrThrow(groupV2Proto
.masterKey
);
94 final var group
= account
.getGroupStore().getGroupOrPartialMigrate(connection
, groupMasterKey
);
95 group
.setBlocked(groupV2Proto
.blocked
);
96 group
.setProfileSharingEnabled(groupV2Proto
.whitelisted
);
97 account
.getGroupStore().updateGroup(connection
, group
);
98 account
.getGroupStore()
99 .storeStorageRecord(connection
, group
.getGroupId(), groupV2Record
.getId(), groupV2Proto
.encode());
103 private static GroupMasterKey
getGroupMasterKeyOrThrow(final ByteString masterKey
) {
105 return new GroupMasterKey(masterKey
.toByteArray());
106 } catch (InvalidInputException e
) {
107 throw new AssertionError(e
);
112 public int compare(SignalGroupV2Record lhs
, SignalGroupV2Record rhs
) {
113 if (lhs
.getProto().masterKey
.equals(rhs
.getProto().masterKey
)) {
120 private static boolean doProtosMatch(GroupV2Record merged
, GroupV2Record other
) {
121 return Arrays
.equals(merged
.encode(), other
.encode());