Update spam UX and reporting flows.

This commit is contained in:
Cody Henthorne
2024-02-09 15:25:31 -05:00
committed by Clark Chen
parent a4fde60c1c
commit aa76cefb1c
66 changed files with 1578 additions and 894 deletions

View File

@@ -200,11 +200,12 @@ public final class GroupManager {
@Nullable GroupSecretParams groupSecretParams,
int revision,
long timestamp,
@Nullable byte[] signedGroupChange)
@Nullable byte[] signedGroupChange,
@Nullable String serverGuid)
throws GroupChangeBusyException, IOException, GroupNotAMemberException
{
try (GroupManagerV2.GroupUpdater updater = new GroupManagerV2(context).updater(groupMasterKey)) {
return updater.updateLocalToServerRevision(revision, timestamp, groupRecord, groupSecretParams, signedGroupChange);
return updater.updateLocalToServerRevision(revision, timestamp, groupRecord, groupSecretParams, signedGroupChange, serverGuid);
}
}

View File

@@ -805,11 +805,16 @@ final class GroupManagerV2 {
}
@WorkerThread
GroupsV2StateProcessor.GroupUpdateResult updateLocalToServerRevision(int revision, long timestamp, @NonNull Optional<GroupRecord> localRecord, @Nullable GroupSecretParams groupSecretParams, @Nullable byte[] signedGroupChange)
GroupsV2StateProcessor.GroupUpdateResult updateLocalToServerRevision(int revision,
long timestamp,
@NonNull Optional<GroupRecord> localRecord,
@Nullable GroupSecretParams groupSecretParams,
@Nullable byte[] signedGroupChange,
@Nullable String serverGuid)
throws IOException, GroupNotAMemberException
{
return new GroupsV2StateProcessor(context).forGroup(serviceIds, groupMasterKey, groupSecretParams)
.updateLocalGroupToRevision(revision, timestamp, localRecord, getDecryptedGroupChange(signedGroupChange));
.updateLocalGroupToRevision(revision, timestamp, localRecord, getDecryptedGroupChange(signedGroupChange), serverGuid);
}
@WorkerThread

View File

@@ -238,10 +238,10 @@ public class GroupsV2StateProcessor {
updateLocalDatabaseGroupState(inputGroupState, newLocalState);
if (localState.revision == GroupsV2StateProcessor.RESTORE_PLACEHOLDER_REVISION) {
info("Inserting single update message for restore placeholder");
profileAndMessageHelper.insertUpdateMessages(timestamp, null, Collections.singleton(new LocalGroupLogEntry(newLocalState, null)));
profileAndMessageHelper.insertUpdateMessages(timestamp, null, Collections.singleton(new LocalGroupLogEntry(newLocalState, null)), null);
} else {
info("Inserting force update messages");
profileAndMessageHelper.insertUpdateMessages(timestamp, localState, advanceGroupStateResult.getProcessedLogEntries());
profileAndMessageHelper.insertUpdateMessages(timestamp, localState, advanceGroupStateResult.getProcessedLogEntries(), null);
}
profileAndMessageHelper.persistLearnedProfileKeys(inputGroupState);
@@ -259,7 +259,7 @@ public class GroupsV2StateProcessor {
@Nullable DecryptedGroupChange signedGroupChange)
throws IOException, GroupNotAMemberException
{
return updateLocalGroupToRevision(revision, timestamp, groupDatabase.getGroup(groupId), signedGroupChange);
return updateLocalGroupToRevision(revision, timestamp, groupDatabase.getGroup(groupId), signedGroupChange, null);
}
/**
@@ -271,7 +271,8 @@ public class GroupsV2StateProcessor {
public GroupUpdateResult updateLocalGroupToRevision(final int revision,
final long timestamp,
@NonNull Optional<GroupRecord> localRecord,
@Nullable DecryptedGroupChange signedGroupChange)
@Nullable DecryptedGroupChange signedGroupChange,
@Nullable String serverGuid)
throws IOException, GroupNotAMemberException
{
if (localIsAtLeast(localRecord, revision)) {
@@ -287,7 +288,6 @@ public class GroupsV2StateProcessor {
localState.revision + 1 == signedGroupChange.revision &&
revision == signedGroupChange.revision)
{
if (notInGroupAndNotBeingAdded(localRecord, signedGroupChange) && notHavingInviteRevoked(signedGroupChange)) {
warn("Ignoring P2P group change because we're not currently in the group and this change doesn't add us in. Falling back to a server fetch.");
} else if (SignalStore.internalValues().gv2IgnoreP2PChanges()) {
@@ -306,7 +306,7 @@ public class GroupsV2StateProcessor {
if (inputGroupState == null) {
try {
return updateLocalGroupFromServerPaged(revision, localState, timestamp, false);
return updateLocalGroupFromServerPaged(revision, localState, timestamp, false, serverGuid);
} catch (GroupNotAMemberException e) {
if (localState != null && signedGroupChange != null) {
try {
@@ -346,9 +346,9 @@ public class GroupsV2StateProcessor {
updateLocalDatabaseGroupState(inputGroupState, newLocalState);
if (localState != null && localState.revision == GroupsV2StateProcessor.RESTORE_PLACEHOLDER_REVISION) {
info("Inserting single update message for restore placeholder");
profileAndMessageHelper.insertUpdateMessages(timestamp, null, Collections.singleton(new LocalGroupLogEntry(newLocalState, null)));
profileAndMessageHelper.insertUpdateMessages(timestamp, null, Collections.singleton(new LocalGroupLogEntry(newLocalState, null)), null);
} else {
profileAndMessageHelper.insertUpdateMessages(timestamp, localState, advanceGroupStateResult.getProcessedLogEntries());
profileAndMessageHelper.insertUpdateMessages(timestamp, localState, advanceGroupStateResult.getProcessedLogEntries(), serverGuid);
}
profileAndMessageHelper.persistLearnedProfileKeys(inputGroupState);
@@ -398,7 +398,7 @@ public class GroupsV2StateProcessor {
/**
* Using network, attempt to bring the local copy of the group up to the revision specified via paging.
*/
private GroupUpdateResult updateLocalGroupFromServerPaged(int revision, DecryptedGroup localState, long timestamp, boolean forceIncludeFirst) throws IOException, GroupNotAMemberException {
private GroupUpdateResult updateLocalGroupFromServerPaged(int revision, DecryptedGroup localState, long timestamp, boolean forceIncludeFirst, @Nullable String serverGuid) throws IOException, GroupNotAMemberException {
boolean latestRevisionOnly = revision == LATEST && (localState == null || localState.revision == GroupsV2StateProcessor.RESTORE_PLACEHOLDER_REVISION);
info("Paging from server revision: " + (revision == LATEST ? "latest" : revision) + ", latestOnly: " + latestRevisionOnly);
@@ -456,7 +456,7 @@ public class GroupsV2StateProcessor {
int requestRevision = (revision == LATEST) ? latestServerGroup.getRevision() : revision;
if (newLocalRevision < requestRevision) {
warn( "Paging again with force first snapshot enabled due to error processing changes. New local revision [" + newLocalRevision + "] hasn't reached our desired level [" + requestRevision + "]");
return updateLocalGroupFromServerPaged(revision, localState, timestamp, true);
return updateLocalGroupFromServerPaged(revision, localState, timestamp, true, serverGuid);
}
}
@@ -467,7 +467,7 @@ public class GroupsV2StateProcessor {
updateLocalDatabaseGroupState(inputGroupState, newLocalState);
if (localState == null || localState.revision != GroupsV2StateProcessor.RESTORE_PLACEHOLDER_REVISION) {
timestamp = profileAndMessageHelper.insertUpdateMessages(timestamp, localState, advanceGroupStateResult.getProcessedLogEntries());
timestamp = profileAndMessageHelper.insertUpdateMessages(timestamp, localState, advanceGroupStateResult.getProcessedLogEntries(), serverGuid);
}
for (ServerGroupLogEntry entry : inputGroupState.getServerHistory()) {
@@ -491,7 +491,7 @@ public class GroupsV2StateProcessor {
if (localState != null && localState.revision == GroupsV2StateProcessor.RESTORE_PLACEHOLDER_REVISION) {
info("Inserting single update message for restore placeholder");
profileAndMessageHelper.insertUpdateMessages(timestamp, null, Collections.singleton(new LocalGroupLogEntry(finalState, null)));
profileAndMessageHelper.insertUpdateMessages(timestamp, null, Collections.singleton(new LocalGroupLogEntry(finalState, null)), serverGuid);
}
profileAndMessageHelper.persistLearnedProfileKeys(profileKeys);
@@ -735,7 +735,8 @@ public class GroupsV2StateProcessor {
long insertUpdateMessages(long timestamp,
@Nullable DecryptedGroup previousGroupState,
Collection<LocalGroupLogEntry> processedLogEntries)
Collection<LocalGroupLogEntry> processedLogEntries,
@Nullable String serverGuid)
{
for (LocalGroupLogEntry entry : processedLogEntries) {
if (entry.getChange() != null && DecryptedGroupUtil.changeIsEmptyExceptForProfileKeyChanges(entry.getChange()) && !DecryptedGroupUtil.changeIsEmpty(entry.getChange())) {
@@ -746,7 +747,7 @@ public class GroupsV2StateProcessor {
if (entry.getChange() != null && DecryptedGroupUtil.changeIsEmpty(entry.getChange()) && previousGroupState != null) {
Log.w(TAG, "Empty group update message seen. Not inserting.");
} else {
storeMessage(GroupProtoUtil.createDecryptedGroupV2Context(masterKey, new GroupMutation(previousGroupState, entry.getChange(), entry.getGroup()), null), timestamp);
storeMessage(GroupProtoUtil.createDecryptedGroupV2Context(masterKey, new GroupMutation(previousGroupState, entry.getChange(), entry.getGroup()), null), timestamp, serverGuid);
timestamp++;
}
}
@@ -782,7 +783,7 @@ public class GroupsV2StateProcessor {
}
}
void storeMessage(@NonNull DecryptedGroupV2Context decryptedGroupV2Context, long timestamp) {
void storeMessage(@NonNull DecryptedGroupV2Context decryptedGroupV2Context, long timestamp, @Nullable String serverGuid) {
Optional<ServiceId> editor = getEditor(decryptedGroupV2Context);
boolean outgoing = !editor.isPresent() || aci.equals(editor.get());
@@ -806,7 +807,7 @@ public class GroupsV2StateProcessor {
try {
MessageTable smsDatabase = SignalDatabase.messages();
RecipientId sender = RecipientId.from(editor.get());
IncomingMessage groupMessage = IncomingMessage.groupUpdate(sender, timestamp, groupId, decryptedGroupV2Context);
IncomingMessage groupMessage = IncomingMessage.groupUpdate(sender, timestamp, groupId, decryptedGroupV2Context, serverGuid);
Optional<MessageTable.InsertResult> insertResult = smsDatabase.insertMessageInbox(groupMessage);
if (insertResult.isPresent()) {