mirror of
https://github.com/oxen-io/session-android.git
synced 2025-06-08 12:18:43 +00:00
Support Groups v2 Change Epochs.
This commit is contained in:
parent
70977e5228
commit
b10fc6a0b0
@ -466,7 +466,8 @@ final class GroupManagerV2 {
|
||||
GroupsV2Operations.GroupOperations groupOperations = groupsV2Operations.forGroup(GroupSecretParams.deriveFromMasterKey(groupMasterKey));
|
||||
|
||||
try {
|
||||
return groupOperations.decryptChange(GroupChange.parseFrom(signedGroupChange), true);
|
||||
return groupOperations.decryptChange(GroupChange.parseFrom(signedGroupChange), true)
|
||||
.orNull();
|
||||
} catch (VerificationFailedException | InvalidGroupStateException | InvalidProtocolBufferException e) {
|
||||
Log.w(TAG, "Unable to verify supplied group change", e);
|
||||
}
|
||||
|
@ -341,7 +341,12 @@ public final class GroupsV2StateProcessor {
|
||||
}
|
||||
|
||||
for (DecryptedGroupHistoryEntry entry : groupStatesFromRevision) {
|
||||
history.add(new ServerGroupLogEntry(entry.getGroup(), ignoreServerChanges ? null : entry.getChange()));
|
||||
DecryptedGroup group = entry.getGroup().orNull();
|
||||
DecryptedGroupChange change = ignoreServerChanges ? null : entry.getChange().orNull();
|
||||
|
||||
if (group != null || change != null) {
|
||||
history.add(new ServerGroupLogEntry(group, change));
|
||||
}
|
||||
}
|
||||
|
||||
return history;
|
||||
|
@ -2,29 +2,32 @@ package org.whispersystems.signalservice.api.groupsv2;
|
||||
|
||||
import org.signal.storageservice.protos.groups.local.DecryptedGroup;
|
||||
import org.signal.storageservice.protos.groups.local.DecryptedGroupChange;
|
||||
import org.whispersystems.libsignal.util.guava.Optional;
|
||||
|
||||
/**
|
||||
* Pair of a {@link DecryptedGroup} and the {@link DecryptedGroupChange} for that version.
|
||||
*/
|
||||
public final class DecryptedGroupHistoryEntry {
|
||||
|
||||
private final DecryptedGroup group;
|
||||
private final DecryptedGroupChange change;
|
||||
private final Optional<DecryptedGroup> group;
|
||||
private final Optional<DecryptedGroupChange> change;
|
||||
|
||||
DecryptedGroupHistoryEntry(DecryptedGroup group, DecryptedGroupChange change) {
|
||||
if (group.getRevision() != change.getRevision()) {
|
||||
throw new AssertionError();
|
||||
DecryptedGroupHistoryEntry(Optional<DecryptedGroup> group, Optional<DecryptedGroupChange> change)
|
||||
throws InvalidGroupStateException
|
||||
{
|
||||
if (group.isPresent() && change.isPresent() && group.get().getRevision() != change.get().getRevision()) {
|
||||
throw new InvalidGroupStateException();
|
||||
}
|
||||
|
||||
this.group = group;
|
||||
this.change = change;
|
||||
}
|
||||
|
||||
public DecryptedGroup getGroup() {
|
||||
public Optional<DecryptedGroup> getGroup() {
|
||||
return group;
|
||||
}
|
||||
|
||||
public DecryptedGroupChange getChange() {
|
||||
public Optional<DecryptedGroupChange> getChange() {
|
||||
return change;
|
||||
}
|
||||
}
|
||||
|
@ -17,6 +17,7 @@ import org.signal.zkgroup.auth.AuthCredentialResponse;
|
||||
import org.signal.zkgroup.auth.ClientZkAuthOperations;
|
||||
import org.signal.zkgroup.groups.ClientZkGroupCipher;
|
||||
import org.signal.zkgroup.groups.GroupSecretParams;
|
||||
import org.whispersystems.libsignal.util.guava.Optional;
|
||||
import org.whispersystems.signalservice.internal.push.PushServiceSocket;
|
||||
|
||||
import java.io.IOException;
|
||||
@ -100,12 +101,8 @@ public final class GroupsV2Api {
|
||||
GroupsV2Operations.GroupOperations groupOperations = groupsOperations.forGroup(groupSecretParams);
|
||||
|
||||
for (GroupChanges.GroupChangeState change : changesList) {
|
||||
DecryptedGroup decryptedGroup = groupOperations.decryptGroup(change.getGroupState());
|
||||
DecryptedGroupChange decryptedChange = groupOperations.decryptChange(change.getGroupChange(), false);
|
||||
|
||||
if (decryptedChange.getRevision() != decryptedGroup.getRevision()) {
|
||||
throw new InvalidGroupStateException();
|
||||
}
|
||||
Optional<DecryptedGroup> decryptedGroup = change.hasGroupState () ? Optional.of(groupOperations.decryptGroup(change.getGroupState())) : Optional.absent();
|
||||
Optional<DecryptedGroupChange> decryptedChange = change.hasGroupChange() ? groupOperations.decryptChange(change.getGroupChange(), false) : Optional.absent();
|
||||
|
||||
result.add(new DecryptedGroupHistoryEntry(decryptedGroup, decryptedChange));
|
||||
}
|
||||
|
@ -39,6 +39,7 @@ import java.security.SecureRandom;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
@ -52,6 +53,9 @@ public final class GroupsV2Operations {
|
||||
/** Used for undecryptable pending invites */
|
||||
public static final UUID UNKNOWN_UUID = UuidUtil.UNKNOWN_UUID;
|
||||
|
||||
/** Highest change epoch this class knows now to decrypt */
|
||||
public static final int HIGHEST_KNOWN_EPOCH = 0;
|
||||
|
||||
private final ServerPublicParams serverPublicParams;
|
||||
private final ClientZkProfileOperations clientZkProfileOperations;
|
||||
private final ClientZkAuthOperations clientZkAuthOperations;
|
||||
@ -289,18 +293,24 @@ public final class GroupsV2Operations {
|
||||
}
|
||||
|
||||
/**
|
||||
* @param verify You might want to avoid verification if you already know it's correct, or you
|
||||
* are not going to pass to other clients.
|
||||
* <p>
|
||||
* Also, if you know it's version 0, do not verify because changes for version 0
|
||||
* are not signed, but should be empty.
|
||||
* @param verifySignature You might want to avoid verification if you already know it's correct, or you
|
||||
* are not going to pass to other clients.
|
||||
* <p>
|
||||
* Also, if you know it's version 0, do not verify because changes for version 0
|
||||
* are not signed, but should be empty.
|
||||
* @return {@link Optional#absent} if the epoch for the change is higher that this code can decrypt.
|
||||
*/
|
||||
public DecryptedGroupChange decryptChange(GroupChange groupChange, boolean verify)
|
||||
public Optional<DecryptedGroupChange> decryptChange(GroupChange groupChange, boolean verifySignature)
|
||||
throws InvalidProtocolBufferException, VerificationFailedException, InvalidGroupStateException
|
||||
{
|
||||
GroupChange.Actions actions = verify ? getVerifiedActions(groupChange) : getActions(groupChange);
|
||||
if (groupChange.getChangeEpoch() > HIGHEST_KNOWN_EPOCH) {
|
||||
Log.w(TAG, String.format(Locale.US, "Ignoring change from Epoch %d. Highest known Epoch is %d", groupChange.getChangeEpoch(), HIGHEST_KNOWN_EPOCH));
|
||||
return Optional.absent();
|
||||
}
|
||||
|
||||
return decryptChange(actions);
|
||||
GroupChange.Actions actions = verifySignature ? getVerifiedActions(groupChange) : getActions(groupChange);
|
||||
|
||||
return Optional.of(decryptChange(actions));
|
||||
}
|
||||
|
||||
public DecryptedGroupChange decryptChange(GroupChange.Actions actions)
|
||||
|
@ -130,8 +130,9 @@ message GroupChange {
|
||||
ModifyMembersAccessControlAction modifyMemberAccess = 14;
|
||||
}
|
||||
|
||||
bytes actions = 1;
|
||||
bytes serverSignature = 2;
|
||||
bytes actions = 1;
|
||||
bytes serverSignature = 2;
|
||||
uint32 changeEpoch = 3;
|
||||
}
|
||||
|
||||
message GroupChanges {
|
||||
|
Loading…
x
Reference in New Issue
Block a user