use of org.signal.zkgroup.groups.GroupMasterKey in project Signal-Android by WhisperSystems.
the class GroupManagerV2 method migrateGroupOnToServer.
@WorkerThread
void migrateGroupOnToServer(@NonNull GroupId.V1 groupIdV1, @NonNull Collection<Recipient> members) throws IOException, MembershipNotSuitableForV2Exception, GroupAlreadyExistsException, GroupChangeFailedException {
GroupMasterKey groupMasterKey = groupIdV1.deriveV2MigrationMasterKey();
GroupSecretParams groupSecretParams = GroupSecretParams.deriveFromMasterKey(groupMasterKey);
GroupDatabase.GroupRecord groupRecord = groupDatabase.requireGroup(groupIdV1);
String name = Util.emptyIfNull(groupRecord.getTitle());
byte[] avatar = groupRecord.hasAvatar() ? AvatarHelper.getAvatarBytes(context, groupRecord.getRecipientId()) : null;
int messageTimer = Recipient.resolved(groupRecord.getRecipientId()).getExpiresInSeconds();
Set<RecipientId> memberIds = Stream.of(members).map(Recipient::getId).filterNot(m -> m.equals(Recipient.self().getId())).collect(Collectors.toSet());
createGroupOnServer(groupSecretParams, name, avatar, memberIds, Member.Role.ADMINISTRATOR, messageTimer);
}
use of org.signal.zkgroup.groups.GroupMasterKey in project Signal-Android by WhisperSystems.
the class GroupManagerV2 method getGroupExternalCredential.
@WorkerThread
@NonNull
GroupExternalCredential getGroupExternalCredential(@NonNull GroupId.V2 groupId) throws IOException, VerificationFailedException {
GroupMasterKey groupMasterKey = SignalDatabase.groups().requireGroup(groupId).requireV2GroupProperties().getGroupMasterKey();
GroupSecretParams groupSecretParams = GroupSecretParams.deriveFromMasterKey(groupMasterKey);
return groupsV2Api.getGroupExternalCredential(authorization.getAuthorizationForToday(selfAci, groupSecretParams));
}
use of org.signal.zkgroup.groups.GroupMasterKey in project Signal-Android by WhisperSystems.
the class GroupsV1MigrationUtil method migrate.
public static void migrate(@NonNull Context context, @NonNull RecipientId recipientId, boolean forced) throws IOException, RetryLaterException, GroupChangeBusyException, InvalidMigrationStateException {
Recipient groupRecipient = Recipient.resolved(recipientId);
Long threadId = SignalDatabase.threads().getThreadIdFor(recipientId);
GroupDatabase groupDatabase = SignalDatabase.groups();
if (threadId == null) {
Log.w(TAG, "No thread found!");
throw new InvalidMigrationStateException();
}
if (!groupRecipient.isPushV1Group()) {
Log.w(TAG, "Not a V1 group!");
throw new InvalidMigrationStateException();
}
if (groupRecipient.getParticipants().size() > FeatureFlags.groupLimits().getHardLimit()) {
Log.w(TAG, "Too many members! Size: " + groupRecipient.getParticipants().size());
throw new InvalidMigrationStateException();
}
GroupId.V1 gv1Id = groupRecipient.requireGroupId().requireV1();
GroupId.V2 gv2Id = gv1Id.deriveV2MigrationGroupId();
GroupMasterKey gv2MasterKey = gv1Id.deriveV2MigrationMasterKey();
boolean newlyCreated = false;
if (groupDatabase.groupExists(gv2Id)) {
Log.w(TAG, "We already have a V2 group for this V1 group! Must have been added before we were migration-capable.");
throw new InvalidMigrationStateException();
}
if (!groupRecipient.isActiveGroup()) {
Log.w(TAG, "Group is inactive! Can't migrate.");
throw new InvalidMigrationStateException();
}
switch(GroupManager.v2GroupStatus(context, gv2MasterKey)) {
case DOES_NOT_EXIST:
Log.i(TAG, "Group does not exist on the service.");
if (!groupRecipient.isProfileSharing()) {
Log.w(TAG, "Profile sharing is disabled! Can't migrate.");
throw new InvalidMigrationStateException();
}
if (!forced && SignalStore.internalValues().disableGv1AutoMigrateInitiation()) {
Log.w(TAG, "Auto migration initiation has been disabled! Skipping.");
throw new InvalidMigrationStateException();
}
List<Recipient> registeredMembers = RecipientUtil.getEligibleForSending(groupRecipient.getParticipants());
if (RecipientUtil.ensureUuidsAreAvailable(context, registeredMembers)) {
Log.i(TAG, "Newly-discovered UUIDs. Getting fresh recipients.");
registeredMembers = Stream.of(registeredMembers).map(Recipient::fresh).toList();
}
List<Recipient> possibleMembers = forced ? getMigratableManualMigrationMembers(registeredMembers) : getMigratableAutoMigrationMembers(registeredMembers);
if (!forced && !groupRecipient.hasName()) {
Log.w(TAG, "Group has no name. Skipping auto-migration.");
throw new InvalidMigrationStateException();
}
if (!forced && possibleMembers.size() != registeredMembers.size()) {
Log.w(TAG, "Not allowed to invite or leave registered users behind in an auto-migration! Skipping.");
throw new InvalidMigrationStateException();
}
Log.i(TAG, "Attempting to create group.");
try {
GroupManager.migrateGroupToServer(context, gv1Id, possibleMembers);
newlyCreated = true;
Log.i(TAG, "Successfully created!");
} catch (GroupChangeFailedException e) {
Log.w(TAG, "Failed to migrate group. Retrying.", e);
throw new RetryLaterException();
} catch (MembershipNotSuitableForV2Exception e) {
Log.w(TAG, "Failed to migrate job due to the membership not yet being suitable for GV2. Aborting.", e);
return;
} catch (GroupAlreadyExistsException e) {
Log.w(TAG, "Someone else created the group while we were trying to do the same! It exists now. Continuing on.", e);
}
break;
case NOT_A_MEMBER:
Log.w(TAG, "The migrated group already exists, but we are not a member. Doing a local leave.");
handleLeftBehind(context, gv1Id, groupRecipient, threadId);
return;
case FULL_OR_PENDING_MEMBER:
Log.w(TAG, "The migrated group already exists, and we're in it. Continuing on.");
break;
default:
throw new AssertionError();
}
Log.i(TAG, "Migrating local group " + gv1Id + " to " + gv2Id);
DecryptedGroup decryptedGroup = performLocalMigration(context, gv1Id, threadId, groupRecipient);
if (newlyCreated && decryptedGroup != null && !SignalStore.internalValues().disableGv1AutoMigrateNotification()) {
Log.i(TAG, "Sending no-op update to notify others.");
GroupManager.sendNoopUpdate(context, gv2MasterKey, decryptedGroup);
}
}
use of org.signal.zkgroup.groups.GroupMasterKey in project Signal-Android by WhisperSystems.
the class GroupIdTest method can_create_for_gv2_from_GroupMasterKey.
@Test
public void can_create_for_gv2_from_GroupMasterKey() throws IOException, InvalidInputException {
assumeLibSignalSupportedOnOS();
GroupId.V2 groupId = GroupId.v2(new GroupMasterKey(Hex.fromStringCondensed("0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef")));
assertEquals("__signal_group__v2__!8c4a5ec277691282f64b965b1b9affc0285380c993c413f7560967d502dcf2e6", groupId.toString());
assertFalse(groupId.isMms());
assertFalse(groupId.isV1());
assertTrue(groupId.isV2());
assertTrue(groupId.isPush());
}
use of org.signal.zkgroup.groups.GroupMasterKey in project Signal-Android by WhisperSystems.
the class GroupId_v1_v2_migration_derivation_Test method deriveMigrationV2MasterKey.
@Test
public void deriveMigrationV2MasterKey() {
GroupId.V1 groupV1Id = GroupId.v1orThrow(Hex.fromStringOrThrow(inputV1GroupId));
GroupMasterKey migratedGroupMasterKey = groupV1Id.deriveV2MigrationMasterKey();
assertEquals(expectedMasterKey, Hex.toStringCondensed(migratedGroupMasterKey.serialize()));
}
Aggregations