Add interim storage support for GroupV2Record.

This commit is contained in:
Greyson Parrelli
2020-03-18 12:37:28 -04:00
parent 707a2aca0a
commit 7a038ab09d
10 changed files with 311 additions and 11 deletions

View File

@@ -0,0 +1,97 @@
package org.whispersystems.signalservice.api.storage;
import com.google.protobuf.ByteString;
import org.signal.zkgroup.InvalidInputException;
import org.signal.zkgroup.groups.GroupMasterKey;
import org.whispersystems.signalservice.internal.storage.protos.GroupV1Record;
import org.whispersystems.signalservice.internal.storage.protos.GroupV2Record;
import java.util.Objects;
public final class SignalGroupV2Record implements SignalRecord {
private final StorageId id;
private final GroupV2Record proto;
private final GroupMasterKey masterKey;
private SignalGroupV2Record(StorageId id, GroupV2Record proto) {
this.id = id;
this.proto = proto;
try {
this.masterKey = new GroupMasterKey(proto.getMasterKey().toByteArray());
} catch (InvalidInputException e) {
throw new AssertionError(e);
}
}
@Override
public StorageId getId() {
return id;
}
public GroupMasterKey getMasterKey() {
return masterKey;
}
public boolean isBlocked() {
return proto.getBlocked();
}
public boolean isProfileSharingEnabled() {
return proto.getWhitelisted();
}
public boolean isArchived() {
return proto.getArchived();
}
GroupV2Record toProto() {
return proto;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
SignalGroupV2Record that = (SignalGroupV2Record) o;
return id.equals(that.id) &&
proto.equals(that.proto);
}
@Override
public int hashCode() {
return Objects.hash(id, proto);
}
public static final class Builder {
private final StorageId id;
private final GroupV2Record.Builder builder;
public Builder(byte[] rawId, GroupMasterKey masterKey) {
this.id = StorageId.forGroupV1(rawId);
this.builder = GroupV2Record.newBuilder();
builder.setMasterKey(ByteString.copyFrom(masterKey.serialize()));
}
public Builder setBlocked(boolean blocked) {
builder.setBlocked(blocked);
return this;
}
public Builder setProfileSharingEnabled(boolean profileSharingEnabled) {
builder.setWhitelisted(profileSharingEnabled);
return this;
}
public Builder setArchived(boolean archived) {
builder.setArchived(archived);
return this;
}
public SignalGroupV2Record build() {
return new SignalGroupV2Record(id, builder.build());
}
}
}

View File

@@ -2,11 +2,14 @@ package org.whispersystems.signalservice.api.storage;
import com.google.protobuf.ByteString;
import org.signal.zkgroup.InvalidInputException;
import org.signal.zkgroup.groups.GroupMasterKey;
import org.whispersystems.libsignal.InvalidKeyException;
import org.whispersystems.signalservice.api.push.SignalServiceAddress;
import org.whispersystems.signalservice.api.util.UuidUtil;
import org.whispersystems.signalservice.internal.storage.protos.ContactRecord;
import org.whispersystems.signalservice.internal.storage.protos.GroupV1Record;
import org.whispersystems.signalservice.internal.storage.protos.GroupV2Record;
import org.whispersystems.signalservice.internal.storage.protos.ManifestRecord;
import org.whispersystems.signalservice.internal.storage.protos.StorageItem;
import org.whispersystems.signalservice.internal.storage.protos.StorageManifest;
@@ -39,6 +42,8 @@ public final class SignalStorageModels {
return SignalStorageRecord.forContact(StorageId.forContact(key), remoteToLocalContactRecord(key, record.getContact()));
} else if (record.hasGroupV1() && type == ManifestRecord.Identifier.Type.GROUPV1_VALUE) {
return SignalStorageRecord.forGroupV1(StorageId.forGroupV1(key), remoteToLocalGroupV1Record(key, record.getGroupV1()));
} else if (record.hasGroupV2() && type == ManifestRecord.Identifier.Type.GROUPV2_VALUE && record.getGroupV2().getMasterKey().size() == GroupMasterKey.SIZE) {
return SignalStorageRecord.forGroupV2(StorageId.forGroupV2(key), remoteToLocalGroupV2Record(key, record.getGroupV2()));
} else {
return SignalStorageRecord.forUnknown(StorageId.forType(key, type));
}
@@ -51,6 +56,8 @@ public final class SignalStorageModels {
builder.setContact(record.getContact().get().toProto());
} else if (record.getGroupV1().isPresent()) {
builder.setGroupV1(record.getGroupV1().get().toProto());
} else if (record.getGroupV2().isPresent()) {
builder.setGroupV2(record.getGroupV2().get().toProto());
} else {
throw new InvalidStorageWriteError();
}
@@ -77,6 +84,7 @@ public final class SignalStorageModels {
.setUsername(contact.getUsername())
.setIdentityKey(contact.getIdentityKey().toByteArray())
.setIdentityState(contact.getIdentityState())
.setArchived(contact.getArchived())
.build();
}
@@ -84,9 +92,22 @@ public final class SignalStorageModels {
return new SignalGroupV1Record.Builder(key, groupV1.getId().toByteArray())
.setBlocked(groupV1.getBlocked())
.setProfileSharingEnabled(groupV1.getWhitelisted())
.setArchived(groupV1.getArchived())
.build();
}
private static SignalGroupV2Record remoteToLocalGroupV2Record(byte[] key, GroupV2Record groupV2) {
try {
return new SignalGroupV2Record.Builder(key, new GroupMasterKey(groupV2.getMasterKey().toByteArray()))
.setBlocked(groupV2.getBlocked())
.setProfileSharingEnabled(groupV2.getWhitelisted())
.setArchived(groupV2.getArchived())
.build();
} catch (InvalidInputException e) {
throw new AssertionError();
}
}
private static class InvalidStorageWriteError extends Error {
}
}

View File

@@ -9,13 +9,14 @@ public class SignalStorageRecord implements SignalRecord {
private final StorageId id;
private final Optional<SignalContactRecord> contact;
private final Optional<SignalGroupV1Record> groupV1;
private final Optional<SignalGroupV2Record> groupV2;
public static SignalStorageRecord forContact(SignalContactRecord contact) {
return forContact(contact.getId(), contact);
}
public static SignalStorageRecord forContact(StorageId key, SignalContactRecord contact) {
return new SignalStorageRecord(key, Optional.of(contact), Optional.<SignalGroupV1Record>absent());
return new SignalStorageRecord(key, Optional.of(contact), Optional.<SignalGroupV1Record>absent(), Optional.<SignalGroupV2Record>absent());
}
public static SignalStorageRecord forGroupV1(SignalGroupV1Record groupV1) {
@@ -23,20 +24,30 @@ public class SignalStorageRecord implements SignalRecord {
}
public static SignalStorageRecord forGroupV1(StorageId key, SignalGroupV1Record groupV1) {
return new SignalStorageRecord(key, Optional.<SignalContactRecord>absent(), Optional.of(groupV1));
return new SignalStorageRecord(key, Optional.<SignalContactRecord>absent(), Optional.of(groupV1), Optional.<SignalGroupV2Record>absent());
}
public static SignalStorageRecord forGroupV2(SignalGroupV2Record groupV2) {
return forGroupV2(groupV2.getId(), groupV2);
}
public static SignalStorageRecord forGroupV2(StorageId key, SignalGroupV2Record groupV2) {
return new SignalStorageRecord(key, Optional.<SignalContactRecord>absent(), Optional.<SignalGroupV1Record>absent(), Optional.of(groupV2));
}
public static SignalStorageRecord forUnknown(StorageId key) {
return new SignalStorageRecord(key,Optional.<SignalContactRecord>absent(), Optional.<SignalGroupV1Record>absent());
return new SignalStorageRecord(key,Optional.<SignalContactRecord>absent(), Optional.<SignalGroupV1Record>absent(), Optional.<SignalGroupV2Record>absent());
}
private SignalStorageRecord(StorageId id,
Optional<SignalContactRecord> contact,
Optional<SignalGroupV1Record> groupV1)
Optional<SignalGroupV1Record> groupV1,
Optional<SignalGroupV2Record> groupV2)
{
this.id = id;
this.contact = contact;
this.groupV1 = groupV1;
this.groupV2 = groupV2;
}
@Override
@@ -56,6 +67,10 @@ public class SignalStorageRecord implements SignalRecord {
return groupV1;
}
public Optional<SignalGroupV2Record> getGroupV2() {
return groupV2;
}
public boolean isUnknown() {
return !contact.isPresent() && !groupV1.isPresent();
}

View File

@@ -17,6 +17,10 @@ public class StorageId {
return new StorageId(ManifestRecord.Identifier.Type.GROUPV1_VALUE, raw);
}
public static StorageId forGroupV2(byte[] raw) {
return new StorageId(ManifestRecord.Identifier.Type.GROUPV2_VALUE, raw);
}
public static StorageId forType(byte[] raw, int type) {
return new StorageId(type, raw);
}