Search in sources :

Example 86 with DecryptedGroup

use of org.signal.storageservice.protos.groups.local.DecryptedGroup in project Signal-Android by WhisperSystems.

the class GroupsV1MigrationUtil method performLocalMigration.

@Nullable
private static DecryptedGroup performLocalMigration(@NonNull Context context, @NonNull GroupId.V1 gv1Id, long threadId, @NonNull Recipient groupRecipient) throws IOException, GroupChangeBusyException {
    Log.i(TAG, "performLocalMigration(" + gv1Id + ", " + threadId + ", " + groupRecipient.getId());
    try (Closeable ignored = GroupsV2ProcessingLock.acquireGroupProcessingLock()) {
        DecryptedGroup decryptedGroup;
        try {
            decryptedGroup = GroupManager.addedGroupVersion(context, gv1Id.deriveV2MigrationMasterKey());
        } catch (GroupDoesNotExistException e) {
            throw new IOException("[Local] The group should exist already!");
        } catch (GroupNotAMemberException e) {
            Log.w(TAG, "[Local] We are not in the group. Doing a local leave.");
            handleLeftBehind(context, gv1Id, groupRecipient, threadId);
            return null;
        }
        Log.i(TAG, "[Local] Migrating group over to the version we were added to: V" + decryptedGroup.getRevision());
        SignalDatabase.groups().migrateToV2(threadId, gv1Id, decryptedGroup);
        Log.i(TAG, "[Local] Applying all changes since V" + decryptedGroup.getRevision());
        try {
            GroupManager.updateGroupFromServer(context, gv1Id.deriveV2MigrationMasterKey(), LATEST, System.currentTimeMillis(), null);
        } catch (GroupChangeBusyException | GroupNotAMemberException e) {
            Log.w(TAG, e);
        }
        return decryptedGroup;
    }
}
Also used : Closeable(java.io.Closeable) IOException(java.io.IOException) DecryptedGroup(org.signal.storageservice.protos.groups.local.DecryptedGroup) Nullable(androidx.annotation.Nullable)

Example 87 with DecryptedGroup

use of org.signal.storageservice.protos.groups.local.DecryptedGroup in project Signal-Android by WhisperSystems.

the class GroupStateMapper method processChanges.

@NonNull
private static AdvanceGroupStateResult processChanges(@NonNull GlobalGroupState inputState, int maximumRevisionToApply) {
    HashMap<Integer, ServerGroupLogEntry> statesToApplyNow = new HashMap<>(inputState.getServerHistory().size());
    ArrayList<ServerGroupLogEntry> statesToApplyLater = new ArrayList<>(inputState.getServerHistory().size());
    DecryptedGroup current = inputState.getLocalState();
    StateChain<DecryptedGroup, DecryptedGroupChange> stateChain = createNewMapper();
    if (inputState.getServerHistory().isEmpty()) {
        return new AdvanceGroupStateResult(Collections.emptyList(), new GlobalGroupState(current, Collections.emptyList()));
    }
    for (ServerGroupLogEntry entry : inputState.getServerHistory()) {
        if (entry.getRevision() > maximumRevisionToApply) {
            statesToApplyLater.add(entry);
        } else {
            statesToApplyNow.put(entry.getRevision(), entry);
        }
    }
    Collections.sort(statesToApplyLater, BY_REVISION);
    final int from = Math.max(0, inputState.getEarliestRevisionNumber());
    final int to = Math.min(inputState.getLatestRevisionNumber(), maximumRevisionToApply);
    if (current != null && current.getRevision() == PLACEHOLDER_REVISION) {
        Log.i(TAG, "Ignoring place holder group state");
    } else {
        stateChain.push(current, null);
    }
    for (int revision = from; revision >= 0 && revision <= to; revision++) {
        ServerGroupLogEntry entry = statesToApplyNow.get(revision);
        if (entry == null) {
            Log.w(TAG, "Could not find group log on server V" + revision);
            continue;
        }
        if (stateChain.getLatestState() == null && entry.getGroup() != null && current != null && current.getRevision() == PLACEHOLDER_REVISION) {
            DecryptedGroup previousState = DecryptedGroup.newBuilder(entry.getGroup()).setTitle(current.getTitle()).setAvatar(current.getAvatar()).build();
            stateChain.push(previousState, null);
        }
        stateChain.push(entry.getGroup(), entry.getChange());
    }
    List<StateChain.Pair<DecryptedGroup, DecryptedGroupChange>> mapperList = stateChain.getList();
    List<LocalGroupLogEntry> appliedChanges = new ArrayList<>(mapperList.size());
    for (StateChain.Pair<DecryptedGroup, DecryptedGroupChange> entry : mapperList) {
        if (current == null || entry.getDelta() != null) {
            appliedChanges.add(new LocalGroupLogEntry(entry.getState(), entry.getDelta()));
        }
    }
    return new AdvanceGroupStateResult(appliedChanges, new GlobalGroupState(stateChain.getLatestState(), statesToApplyLater));
}
Also used : HashMap(java.util.HashMap) ArrayList(java.util.ArrayList) DecryptedGroupChange(org.signal.storageservice.protos.groups.local.DecryptedGroupChange) DecryptedGroup(org.signal.storageservice.protos.groups.local.DecryptedGroup) NonNull(androidx.annotation.NonNull)

Example 88 with DecryptedGroup

use of org.signal.storageservice.protos.groups.local.DecryptedGroup in project Signal-Android by signalapp.

the class GroupManagerV2 method addedGroupVersion.

@WorkerThread
@NonNull
DecryptedGroup addedGroupVersion(@NonNull GroupMasterKey groupMasterKey) throws GroupNotAMemberException, IOException, GroupDoesNotExistException {
    GroupsV2StateProcessor.StateProcessorForGroup stateProcessorForGroup = new GroupsV2StateProcessor(context).forGroup(groupMasterKey);
    DecryptedGroup latest = stateProcessorForGroup.getCurrentGroupStateFromServer();
    if (latest.getRevision() == 0) {
        return latest;
    }
    Optional<DecryptedMember> selfInFullMemberList = DecryptedGroupUtil.findMemberByUuid(latest.getMembersList(), selfAci.uuid());
    if (!selfInFullMemberList.isPresent()) {
        return latest;
    }
    DecryptedGroup joinedVersion = stateProcessorForGroup.getSpecificVersionFromServer(selfInFullMemberList.get().getJoinedAtRevision());
    if (joinedVersion != null) {
        return joinedVersion;
    } else {
        Log.w(TAG, "Unable to retreive exact version joined at, using latest");
        return latest;
    }
}
Also used : DecryptedGroup(org.signal.storageservice.protos.groups.local.DecryptedGroup) GroupsV2StateProcessor(org.thoughtcrime.securesms.groups.v2.processing.GroupsV2StateProcessor) DecryptedMember(org.signal.storageservice.protos.groups.local.DecryptedMember) WorkerThread(androidx.annotation.WorkerThread) NonNull(androidx.annotation.NonNull)

Example 89 with DecryptedGroup

use of org.signal.storageservice.protos.groups.local.DecryptedGroup in project Signal-Android by signalapp.

the class GroupsV1MigrationUtil method performLocalMigration.

@Nullable
private static DecryptedGroup performLocalMigration(@NonNull Context context, @NonNull GroupId.V1 gv1Id, long threadId, @NonNull Recipient groupRecipient) throws IOException, GroupChangeBusyException {
    Log.i(TAG, "performLocalMigration(" + gv1Id + ", " + threadId + ", " + groupRecipient.getId());
    try (Closeable ignored = GroupsV2ProcessingLock.acquireGroupProcessingLock()) {
        DecryptedGroup decryptedGroup;
        try {
            decryptedGroup = GroupManager.addedGroupVersion(context, gv1Id.deriveV2MigrationMasterKey());
        } catch (GroupDoesNotExistException e) {
            throw new IOException("[Local] The group should exist already!");
        } catch (GroupNotAMemberException e) {
            Log.w(TAG, "[Local] We are not in the group. Doing a local leave.");
            handleLeftBehind(context, gv1Id, groupRecipient, threadId);
            return null;
        }
        Log.i(TAG, "[Local] Migrating group over to the version we were added to: V" + decryptedGroup.getRevision());
        SignalDatabase.groups().migrateToV2(threadId, gv1Id, decryptedGroup);
        Log.i(TAG, "[Local] Applying all changes since V" + decryptedGroup.getRevision());
        try {
            GroupManager.updateGroupFromServer(context, gv1Id.deriveV2MigrationMasterKey(), LATEST, System.currentTimeMillis(), null);
        } catch (GroupChangeBusyException | GroupNotAMemberException e) {
            Log.w(TAG, e);
        }
        return decryptedGroup;
    }
}
Also used : Closeable(java.io.Closeable) IOException(java.io.IOException) DecryptedGroup(org.signal.storageservice.protos.groups.local.DecryptedGroup) Nullable(androidx.annotation.Nullable)

Example 90 with DecryptedGroup

use of org.signal.storageservice.protos.groups.local.DecryptedGroup in project Signal-Android by signalapp.

the class PendingMemberInvitesRepository method getInvitees.

public void getInvitees(@NonNull Consumer<InviteeResult> onInviteesLoaded) {
    executor.execute(() -> {
        GroupDatabase groupDatabase = SignalDatabase.groups();
        GroupDatabase.V2GroupProperties v2GroupProperties = groupDatabase.getGroup(groupId).get().requireV2GroupProperties();
        DecryptedGroup decryptedGroup = v2GroupProperties.getDecryptedGroup();
        List<DecryptedPendingMember> pendingMembersList = decryptedGroup.getPendingMembersList();
        List<SinglePendingMemberInvitedByYou> byMe = new ArrayList<>(pendingMembersList.size());
        List<MultiplePendingMembersInvitedByAnother> byOthers = new ArrayList<>(pendingMembersList.size());
        ByteString self = Recipient.self().requireServiceId().toByteString();
        boolean selfIsAdmin = v2GroupProperties.isAdmin(Recipient.self());
        Stream.of(pendingMembersList).groupBy(DecryptedPendingMember::getAddedByUuid).forEach(g -> {
            ByteString inviterUuid = g.getKey();
            List<DecryptedPendingMember> invitedMembers = g.getValue();
            if (self.equals(inviterUuid)) {
                for (DecryptedPendingMember pendingMember : invitedMembers) {
                    try {
                        Recipient invitee = GroupProtoUtil.pendingMemberToRecipient(context, pendingMember);
                        UuidCiphertext uuidCipherText = new UuidCiphertext(pendingMember.getUuidCipherText().toByteArray());
                        byMe.add(new SinglePendingMemberInvitedByYou(invitee, uuidCipherText));
                    } catch (InvalidInputException e) {
                        Log.w(TAG, e);
                    }
                }
            } else {
                Recipient inviter = GroupProtoUtil.uuidByteStringToRecipient(context, inviterUuid);
                ArrayList<UuidCiphertext> uuidCipherTexts = new ArrayList<>(invitedMembers.size());
                for (DecryptedPendingMember pendingMember : invitedMembers) {
                    try {
                        uuidCipherTexts.add(new UuidCiphertext(pendingMember.getUuidCipherText().toByteArray()));
                    } catch (InvalidInputException e) {
                        Log.w(TAG, e);
                    }
                }
                byOthers.add(new MultiplePendingMembersInvitedByAnother(inviter, uuidCipherTexts));
            }
        });
        onInviteesLoaded.accept(new InviteeResult(byMe, byOthers, selfIsAdmin));
    });
}
Also used : InvalidInputException(org.signal.zkgroup.InvalidInputException) ByteString(com.google.protobuf.ByteString) ArrayList(java.util.ArrayList) Recipient(org.thoughtcrime.securesms.recipients.Recipient) UuidCiphertext(org.signal.zkgroup.groups.UuidCiphertext) GroupDatabase(org.thoughtcrime.securesms.database.GroupDatabase) DecryptedPendingMember(org.signal.storageservice.protos.groups.local.DecryptedPendingMember) DecryptedGroup(org.signal.storageservice.protos.groups.local.DecryptedGroup)

Aggregations

DecryptedGroup (org.signal.storageservice.protos.groups.local.DecryptedGroup)328 Test (org.junit.Test)306 DecryptedGroupChange (org.signal.storageservice.protos.groups.local.DecryptedGroupChange)182 UUID (java.util.UUID)110 GroupChange (org.signal.storageservice.protos.groups.GroupChange)58 ProfileKey (org.signal.zkgroup.profiles.ProfileKey)50 ProtoTestUtils.randomProfileKey (org.whispersystems.signalservice.api.groupsv2.ProtoTestUtils.randomProfileKey)46 DecryptedMember (org.signal.storageservice.protos.groups.local.DecryptedMember)44 ProtoTestUtils.newProfileKey (org.whispersystems.signalservice.api.groupsv2.ProtoTestUtils.newProfileKey)24 ProtoTestUtils.withProfileKey (org.whispersystems.signalservice.api.groupsv2.ProtoTestUtils.withProfileKey)24 Group (org.signal.storageservice.protos.groups.Group)22 ByteString (com.google.protobuf.ByteString)16 PrepareForTest (org.powermock.core.classloader.annotations.PrepareForTest)14 DecryptedPendingMember (org.signal.storageservice.protos.groups.local.DecryptedPendingMember)12 DecryptedRequestingMember (org.signal.storageservice.protos.groups.local.DecryptedRequestingMember)8 NonNull (androidx.annotation.NonNull)6 ArrayList (java.util.ArrayList)6 GroupDatabase (org.thoughtcrime.securesms.database.GroupDatabase)6 Nullable (androidx.annotation.Nullable)4 WorkerThread (androidx.annotation.WorkerThread)4