]> nmode's Git Repositories - signal-cli/blob - lib/src/main/java/org/asamk/signal/manager/syncStorage/GroupV1RecordProcessor.java
22d18c8b610f569206f8dd2c5f50923d5f2cba2e
[signal-cli] / lib / src / main / java / org / asamk / signal / manager / syncStorage / GroupV1RecordProcessor.java
1 package org.asamk.signal.manager.syncStorage;
2
3 import org.asamk.signal.manager.api.GroupId;
4 import org.asamk.signal.manager.api.GroupIdV1;
5 import org.asamk.signal.manager.storage.SignalAccount;
6 import org.asamk.signal.manager.storage.groups.GroupInfoV2;
7 import org.asamk.signal.manager.util.KeyUtils;
8 import org.slf4j.Logger;
9 import org.slf4j.LoggerFactory;
10 import org.whispersystems.signalservice.api.storage.SignalGroupV1Record;
11 import org.whispersystems.signalservice.api.storage.StorageId;
12 import org.whispersystems.signalservice.internal.storage.protos.GroupV1Record;
13
14 import java.sql.Connection;
15 import java.sql.SQLException;
16 import java.util.Arrays;
17 import java.util.Optional;
18
19 /**
20 * Handles merging remote storage updates into local group v1 state.
21 */
22 public final class GroupV1RecordProcessor extends DefaultStorageRecordProcessor<SignalGroupV1Record> {
23
24 private static final Logger logger = LoggerFactory.getLogger(GroupV1RecordProcessor.class);
25 private final SignalAccount account;
26 private final Connection connection;
27
28 public GroupV1RecordProcessor(SignalAccount account, Connection connection) {
29 this.account = account;
30 this.connection = connection;
31 }
32
33 /**
34 * We want to catch:
35 * - Invalid group IDs
36 * - GV1 IDs that map to GV2 IDs, meaning we've already migrated them.
37 */
38 @Override
39 protected boolean isInvalid(SignalGroupV1Record remote) throws SQLException {
40 try {
41 final var id = GroupId.unknownVersion(remote.getProto().id.toByteArray());
42 if (!(id instanceof GroupIdV1)) {
43 return true;
44 }
45 final var group = account.getGroupStore().getGroup(connection, id);
46
47 if (group instanceof GroupInfoV2) {
48 logger.debug("We already have an upgraded V2 group for this V1 group -- marking as invalid.");
49 return true;
50 } else {
51 return false;
52 }
53 } catch (AssertionError e) {
54 logger.debug("Bad Group ID -- marking as invalid.");
55 return true;
56 }
57 }
58
59 @Override
60 protected Optional<SignalGroupV1Record> getMatching(SignalGroupV1Record remote) throws SQLException {
61 final var id = GroupId.v1(remote.getProto().id.toByteArray());
62 final var group = account.getGroupStore().getGroup(connection, id);
63
64 if (group == null) {
65 return Optional.empty();
66 }
67
68 final var storageId = account.getGroupStore().getGroupStorageId(connection, id);
69 return Optional.of(new SignalGroupV1Record(storageId, StorageSyncModels.localToRemoteRecord(group)));
70 }
71
72 @Override
73 protected SignalGroupV1Record merge(SignalGroupV1Record remoteRecord, SignalGroupV1Record localRecord) {
74 final var remote = remoteRecord.getProto();
75 final var local = localRecord.getProto();
76
77 final var mergedBuilder = SignalGroupV1Record.Companion.newBuilder(remote.unknownFields().toByteArray())
78 .id(remote.id)
79 .blocked(remote.blocked)
80 .whitelisted(remote.whitelisted)
81 .markedUnread(remote.markedUnread)
82 .mutedUntilTimestamp(remote.mutedUntilTimestamp)
83 .archived(remote.archived);
84
85 final var merged = mergedBuilder.build();
86
87 final var matchesRemote = doProtosMatch(merged, remote);
88 if (matchesRemote) {
89 return remoteRecord;
90 }
91
92 final var matchesLocal = doProtosMatch(merged, local);
93 if (matchesLocal) {
94 return localRecord;
95 }
96
97 return new SignalGroupV1Record(StorageId.forGroupV1(KeyUtils.createRawStorageId()), mergedBuilder.build());
98 }
99
100 @Override
101 protected void insertLocal(SignalGroupV1Record record) throws SQLException {
102 // TODO send group info request (after server message queue is empty)
103 // context.getGroupHelper().sendGroupInfoRequest(groupIdV1, account.getSelfRecipientId());
104 StorageRecordUpdate<SignalGroupV1Record> update = new StorageRecordUpdate<>(null, record);
105 updateLocal(update);
106 }
107
108 @Override
109 protected void updateLocal(StorageRecordUpdate<SignalGroupV1Record> update) throws SQLException {
110 final var groupV1Record = update.newRecord();
111 final var groupV1Proto = groupV1Record.getProto();
112 final var groupIdV1 = GroupId.v1(groupV1Proto.id.toByteArray());
113
114 final var group = account.getGroupStore().getOrCreateGroupV1(connection, groupIdV1);
115 if (group != null) {
116 group.setBlocked(groupV1Proto.blocked);
117 account.getGroupStore().updateGroup(connection, group);
118 account.getGroupStore()
119 .storeStorageRecord(connection, group.getGroupId(), groupV1Record.getId(), groupV1Proto.encode());
120 }
121 }
122
123 @Override
124 public int compare(SignalGroupV1Record lhs, SignalGroupV1Record rhs) {
125 if (lhs.getProto().id.equals(rhs.getProto().id)) {
126 return 0;
127 } else {
128 return 1;
129 }
130 }
131
132 private static boolean doProtosMatch(GroupV1Record merged, GroupV1Record other) {
133 return Arrays.equals(merged.encode(), other.encode());
134 }
135 }