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;
|
needsForcePush = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
StorageSyncValidations.validate(writeOperationResult);
|
StorageSyncValidations.validate(writeOperationResult, remoteManifest, needsForcePush);
|
||||||
|
|
||||||
Log.i(TAG, "[Remote Newer] MergeResult :: " + mergeResult);
|
Log.i(TAG, "[Remote Newer] MergeResult :: " + mergeResult);
|
||||||
|
|
||||||
|
@ -213,6 +213,7 @@ public class StorageSyncJob extends BaseJob {
|
||||||
}
|
}
|
||||||
|
|
||||||
remoteManifestVersion = writeOperationResult.getManifest().getVersion();
|
remoteManifestVersion = writeOperationResult.getManifest().getVersion();
|
||||||
|
remoteManifest = Optional.of(writeOperationResult.getManifest());
|
||||||
|
|
||||||
needsMultiDeviceSync = true;
|
needsMultiDeviceSync = true;
|
||||||
} else {
|
} 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()));
|
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();
|
WriteOperationResult localWrite = localWriteResult.get().getWriteResult();
|
||||||
StorageSyncValidations.validate(localWrite);
|
StorageSyncValidations.validate(localWrite, remoteManifest, needsForcePush);
|
||||||
|
|
||||||
Log.i(TAG, "[Local Changes] WriteOperationResult :: " + localWrite);
|
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
|
//noinspection unchecked Stop yelling at my beautiful method signatures
|
||||||
mergeWriteOperation = StorageSyncHelper.createWriteOperation(remoteManifest.get().getVersion(), localStorageIdsAfterMerge, localOnly, contactResult, gv1Result, gv2Result, accountResult);
|
mergeWriteOperation = StorageSyncHelper.createWriteOperation(remoteManifest.get().getVersion(), localStorageIdsAfterMerge, localOnly, contactResult, gv1Result, gv2Result, accountResult);
|
||||||
|
|
||||||
StorageSyncValidations.validate(mergeWriteOperation);
|
StorageSyncValidations.validate(mergeWriteOperation, remoteManifest, needsForcePush);
|
||||||
db.setTransactionSuccessful();
|
db.setTransactionSuccessful();
|
||||||
} finally {
|
} finally {
|
||||||
db.endTransaction();
|
db.endTransaction();
|
||||||
|
@ -302,6 +302,7 @@ public class StorageSyncJobV2 extends BaseJob {
|
||||||
}
|
}
|
||||||
|
|
||||||
remoteManifestVersion = mergeWriteOperation.getManifest().getVersion();
|
remoteManifestVersion = mergeWriteOperation.getManifest().getVersion();
|
||||||
|
remoteManifest = Optional.of(mergeWriteOperation.getManifest());
|
||||||
|
|
||||||
needsMultiDeviceSync = true;
|
needsMultiDeviceSync = true;
|
||||||
} else {
|
} 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()));
|
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();
|
WriteOperationResult localWrite = localWriteResult.get().getWriteResult();
|
||||||
StorageSyncValidations.validate(localWrite);
|
StorageSyncValidations.validate(localWrite, remoteManifest, needsForcePush);
|
||||||
|
|
||||||
Log.i(TAG, "[Local Changes] WriteOperationResult :: " + localWrite);
|
Log.i(TAG, "[Local Changes] WriteOperationResult :: " + localWrite);
|
||||||
|
|
||||||
|
|
|
@ -5,9 +5,13 @@ import androidx.annotation.NonNull;
|
||||||
import com.annimon.stream.Collectors;
|
import com.annimon.stream.Collectors;
|
||||||
import com.annimon.stream.Stream;
|
import com.annimon.stream.Stream;
|
||||||
|
|
||||||
|
import org.signal.core.util.logging.Log;
|
||||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||||
import org.thoughtcrime.securesms.util.Base64;
|
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.push.SignalServiceAddress;
|
||||||
|
import org.whispersystems.signalservice.api.storage.SignalRecord;
|
||||||
import org.whispersystems.signalservice.api.storage.SignalStorageManifest;
|
import org.whispersystems.signalservice.api.storage.SignalStorageManifest;
|
||||||
import org.whispersystems.signalservice.api.storage.SignalStorageRecord;
|
import org.whispersystems.signalservice.api.storage.SignalStorageRecord;
|
||||||
import org.whispersystems.signalservice.api.storage.StorageId;
|
import org.whispersystems.signalservice.api.storage.StorageId;
|
||||||
|
@ -20,9 +24,11 @@ import java.util.Set;
|
||||||
|
|
||||||
public final class StorageSyncValidations {
|
public final class StorageSyncValidations {
|
||||||
|
|
||||||
|
private static final String TAG = Log.tag(StorageSyncValidations.class);
|
||||||
|
|
||||||
private StorageSyncValidations() {}
|
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());
|
validateManifestAndInserts(result.getManifest(), result.getInserts());
|
||||||
|
|
||||||
if (result.getDeletes().size() > 0) {
|
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 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