Write additional storage validations based on previous manifest.
This commit is contained in:
parent
0e200b1fb6
commit
25ce2a649a
3 changed files with 81 additions and 5 deletions
|
@ -192,7 +192,7 @@ public class StorageSyncJob extends BaseJob {
|
|||
needsForcePush = true;
|
||||
}
|
||||
|
||||
StorageSyncValidations.validate(writeOperationResult);
|
||||
StorageSyncValidations.validate(writeOperationResult, remoteManifest, needsForcePush);
|
||||
|
||||
Log.i(TAG, "[Remote Newer] MergeResult :: " + mergeResult);
|
||||
|
||||
|
@ -213,6 +213,7 @@ public class StorageSyncJob extends BaseJob {
|
|||
}
|
||||
|
||||
remoteManifestVersion = writeOperationResult.getManifest().getVersion();
|
||||
remoteManifest = Optional.of(writeOperationResult.getManifest());
|
||||
|
||||
needsMultiDeviceSync = true;
|
||||
} else {
|
||||
|
@ -255,7 +256,7 @@ public class StorageSyncJob extends BaseJob {
|
|||
Log.i(TAG, String.format(Locale.ENGLISH, "[Local Changes] Local changes present. %d updates, %d inserts, %d deletes, account update: %b, account insert: %b.", pendingUpdates.size(), pendingInsertions.size(), pendingDeletions.size(), pendingAccountUpdate.isPresent(), pendingAccountInsert.isPresent()));
|
||||
|
||||
WriteOperationResult localWrite = localWriteResult.get().getWriteResult();
|
||||
StorageSyncValidations.validate(localWrite);
|
||||
StorageSyncValidations.validate(localWrite, remoteManifest, needsForcePush);
|
||||
|
||||
Log.i(TAG, "[Local Changes] WriteOperationResult :: " + localWrite);
|
||||
|
||||
|
|
|
@ -278,7 +278,7 @@ public class StorageSyncJobV2 extends BaseJob {
|
|||
//noinspection unchecked Stop yelling at my beautiful method signatures
|
||||
mergeWriteOperation = StorageSyncHelper.createWriteOperation(remoteManifest.get().getVersion(), localStorageIdsAfterMerge, localOnly, contactResult, gv1Result, gv2Result, accountResult);
|
||||
|
||||
StorageSyncValidations.validate(mergeWriteOperation);
|
||||
StorageSyncValidations.validate(mergeWriteOperation, remoteManifest, needsForcePush);
|
||||
db.setTransactionSuccessful();
|
||||
} finally {
|
||||
db.endTransaction();
|
||||
|
@ -302,6 +302,7 @@ public class StorageSyncJobV2 extends BaseJob {
|
|||
}
|
||||
|
||||
remoteManifestVersion = mergeWriteOperation.getManifest().getVersion();
|
||||
remoteManifest = Optional.of(mergeWriteOperation.getManifest());
|
||||
|
||||
needsMultiDeviceSync = true;
|
||||
} else {
|
||||
|
@ -337,7 +338,7 @@ public class StorageSyncJobV2 extends BaseJob {
|
|||
Log.i(TAG, String.format(Locale.ENGLISH, "[Local Changes] Local changes present. %d updates, %d inserts, %d deletes, account update: %b, account insert: %b.", pendingUpdates.size(), pendingInsertions.size(), pendingDeletions.size(), pendingAccountUpdate.isPresent(), pendingAccountInsert.isPresent()));
|
||||
|
||||
WriteOperationResult localWrite = localWriteResult.get().getWriteResult();
|
||||
StorageSyncValidations.validate(localWrite);
|
||||
StorageSyncValidations.validate(localWrite, remoteManifest, needsForcePush);
|
||||
|
||||
Log.i(TAG, "[Local Changes] WriteOperationResult :: " + localWrite);
|
||||
|
||||
|
|
|
@ -5,9 +5,13 @@ import androidx.annotation.NonNull;
|
|||
import com.annimon.stream.Collectors;
|
||||
import com.annimon.stream.Stream;
|
||||
|
||||
import org.signal.core.util.logging.Log;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.util.Base64;
|
||||
import org.thoughtcrime.securesms.util.SetUtil;
|
||||
import org.whispersystems.libsignal.util.guava.Optional;
|
||||
import org.whispersystems.signalservice.api.push.SignalServiceAddress;
|
||||
import org.whispersystems.signalservice.api.storage.SignalRecord;
|
||||
import org.whispersystems.signalservice.api.storage.SignalStorageManifest;
|
||||
import org.whispersystems.signalservice.api.storage.SignalStorageRecord;
|
||||
import org.whispersystems.signalservice.api.storage.StorageId;
|
||||
|
@ -20,9 +24,11 @@ import java.util.Set;
|
|||
|
||||
public final class StorageSyncValidations {
|
||||
|
||||
private static final String TAG = Log.tag(StorageSyncValidations.class);
|
||||
|
||||
private StorageSyncValidations() {}
|
||||
|
||||
public static void validate(@NonNull StorageSyncHelper.WriteOperationResult result) {
|
||||
public static void validate(@NonNull StorageSyncHelper.WriteOperationResult result, @NonNull Optional<SignalStorageManifest> previousManifest, boolean forcePushPending) {
|
||||
validateManifestAndInserts(result.getManifest(), result.getInserts());
|
||||
|
||||
if (result.getDeletes().size() > 0) {
|
||||
|
@ -35,6 +41,53 @@ public final class StorageSyncValidations {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!previousManifest.isPresent()) {
|
||||
Log.i(TAG, "No previous manifest, not bothering with additional validations around the diffs between the two manifests.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (result.getManifest().getVersion() != previousManifest.get().getVersion() + 1) {
|
||||
throw new IncorrectManifestVersionError();
|
||||
}
|
||||
|
||||
if (forcePushPending) {
|
||||
Log.i(TAG, "Force push pending, not bothering with additional validations around the diffs between the two manifests.");
|
||||
return;
|
||||
}
|
||||
|
||||
Set<ByteBuffer> previousIds = Stream.of(previousManifest.get().getStorageIds()).map(id -> ByteBuffer.wrap(id.getRaw())).collect(Collectors.toSet());
|
||||
Set<ByteBuffer> newIds = Stream.of(result.getManifest().getStorageIds()).map(id -> ByteBuffer.wrap(id.getRaw())).collect(Collectors.toSet());
|
||||
|
||||
Set<ByteBuffer> insertedIds = SetUtil.difference(newIds, previousIds);
|
||||
Set<ByteBuffer> deletedIds = SetUtil.difference(previousIds, newIds);
|
||||
|
||||
Set<ByteBuffer> writeInserts = Stream.of(result.getInserts()).map(r -> ByteBuffer.wrap(r.getId().getRaw())).collect(Collectors.toSet());
|
||||
Set<ByteBuffer> writeDeletes = Stream.of(result.getDeletes()).map(ByteBuffer::wrap).collect(Collectors.toSet());
|
||||
|
||||
if (writeInserts.size() > insertedIds.size()) {
|
||||
throw new MoreInsertsThanExpectedError();
|
||||
}
|
||||
|
||||
if (writeInserts.size() < insertedIds.size()) {
|
||||
throw new LessInsertsThanExpectedError();
|
||||
}
|
||||
|
||||
if (!writeInserts.containsAll(insertedIds)) {
|
||||
throw new InsertMismatchError();
|
||||
}
|
||||
|
||||
if (writeDeletes.size() > deletedIds.size()) {
|
||||
throw new MoreDeletesThanExpectedError();
|
||||
}
|
||||
|
||||
if (writeDeletes.size() < deletedIds.size()) {
|
||||
throw new LessDeletesThanExpectedError();
|
||||
}
|
||||
|
||||
if (!writeDeletes.containsAll(deletedIds)) {
|
||||
throw new DeleteMismatchError();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -117,4 +170,25 @@ public final class StorageSyncValidations {
|
|||
|
||||
private static final class SelfAddedAsContactError extends Error {
|
||||
}
|
||||
|
||||
private static final class IncorrectManifestVersionError extends Error {
|
||||
}
|
||||
|
||||
private static final class MoreInsertsThanExpectedError extends Error {
|
||||
}
|
||||
|
||||
private static final class LessInsertsThanExpectedError extends Error {
|
||||
}
|
||||
|
||||
private static final class InsertMismatchError extends Error {
|
||||
}
|
||||
|
||||
private static final class MoreDeletesThanExpectedError extends Error {
|
||||
}
|
||||
|
||||
private static final class LessDeletesThanExpectedError extends Error {
|
||||
}
|
||||
|
||||
private static final class DeleteMismatchError extends Error {
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue