From c2b5407911d7b2cfd272dec8bb82a35dd6847503 Mon Sep 17 00:00:00 2001 From: Cody Henthorne Date: Mon, 1 Aug 2022 13:18:20 -0400 Subject: [PATCH] Change batch identity check timing behavior. --- .../contacts/paged/SafetyNumberRepository.kt | 12 ++++++++++-- .../forward/MultiselectForwardViewModel.kt | 5 +++-- .../database/identity/IdentityRecordList.java | 2 +- .../mediasend/v2/MediaSelectionViewModel.kt | 5 +++-- .../securesms/mediasend/v2/UntrustedRecords.kt | 18 ++++++++++++------ .../v2/text/TextStoryPostCreationViewModel.kt | 5 +++-- .../text/send/TextStoryPostSendRepository.kt | 4 ++-- .../reply/group/StoryGroupReplySender.kt | 3 ++- .../core/util/concurrent/RxExtensions.kt | 2 ++ 9 files changed, 38 insertions(+), 18 deletions(-) diff --git a/app/src/main/java/org/thoughtcrime/securesms/contacts/paged/SafetyNumberRepository.kt b/app/src/main/java/org/thoughtcrime/securesms/contacts/paged/SafetyNumberRepository.kt index bb813d3d66..437dfe761e 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/contacts/paged/SafetyNumberRepository.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/contacts/paged/SafetyNumberRepository.kt @@ -3,6 +3,7 @@ package org.thoughtcrime.securesms.contacts.paged import androidx.annotation.VisibleForTesting import io.reactivex.rxjava3.core.Single import org.signal.core.util.concurrent.SignalExecutors +import org.signal.core.util.concurrent.safeBlockingGet import org.signal.core.util.logging.Log import org.thoughtcrime.securesms.crypto.storage.SignalIdentityKeyStore import org.thoughtcrime.securesms.dependencies.ApplicationDependencies @@ -26,11 +27,18 @@ class SafetyNumberRepository( private val recentlyFetched: MutableMap = HashMap() fun batchSafetyNumberCheck(newSelectionEntries: List) { - SignalExecutors.UNBOUNDED.execute { batchSafetyNumberCheckSync(newSelectionEntries) } + SignalExecutors.UNBOUNDED.execute { + try { + batchSafetyNumberCheckSync(newSelectionEntries) + } catch (e: InterruptedException) { + Log.w(TAG, "Unable to fetch safety number change", e) + } + } } @Suppress("UNCHECKED_CAST") @VisibleForTesting + @Throws(InterruptedException::class) fun batchSafetyNumberCheckSync(newSelectionEntries: List, now: Long = System.currentTimeMillis(), batchSize: Int = MAX_BATCH_SIZE) { val stopwatch = Stopwatch("batch-snc") val recipientIds: Set = newSelectionEntries.flattenToRecipientIds() @@ -49,7 +57,7 @@ class SafetyNumberRepository( responses .map { it as List } .flatten() - }.blockingGet() + }.safeBlockingGet() stopwatch.split("batch-fetches") diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/mutiselect/forward/MultiselectForwardViewModel.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/mutiselect/forward/MultiselectForwardViewModel.kt index b3cfdd0133..ee8cc36e38 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/mutiselect/forward/MultiselectForwardViewModel.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/mutiselect/forward/MultiselectForwardViewModel.kt @@ -16,7 +16,8 @@ class MultiselectForwardViewModel( private val storySendRequirements: Stories.MediaTransform.SendRequirements, private val records: List, private val isSelectionOnly: Boolean, - private val repository: MultiselectForwardRepository + private val repository: MultiselectForwardRepository, + private val identityChangesSince: Long = System.currentTimeMillis() ) : ViewModel() { private val store = Store( @@ -48,7 +49,7 @@ class MultiselectForwardViewModel( store.update { it.copy(stage = MultiselectForwardState.Stage.FirstConfirmation) } } else { store.update { it.copy(stage = MultiselectForwardState.Stage.LoadingIdentities) } - UntrustedRecords.checkForBadIdentityRecords(selectedContacts.filterIsInstance(ContactSearchKey.RecipientSearchKey::class.java).toSet()) { identityRecords -> + UntrustedRecords.checkForBadIdentityRecords(selectedContacts.filterIsInstance(ContactSearchKey.RecipientSearchKey::class.java).toSet(), identityChangesSince) { identityRecords -> if (identityRecords.isEmpty()) { performSend(additionalMessage, selectedContacts) } else { diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/identity/IdentityRecordList.java b/app/src/main/java/org/thoughtcrime/securesms/database/identity/IdentityRecordList.java index 9b80620b5a..e811742899 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/identity/IdentityRecordList.java +++ b/app/src/main/java/org/thoughtcrime/securesms/database/identity/IdentityRecordList.java @@ -16,7 +16,7 @@ public final class IdentityRecordList { public static final IdentityRecordList EMPTY = new IdentityRecordList(Collections.emptyList()); - private static final long DEFAULT_UNTRUSTED_WINDOW = TimeUnit.SECONDS.toMillis(5); + public static final long DEFAULT_UNTRUSTED_WINDOW = TimeUnit.SECONDS.toMillis(5); private final List identityRecords; private final boolean isVerified; diff --git a/app/src/main/java/org/thoughtcrime/securesms/mediasend/v2/MediaSelectionViewModel.kt b/app/src/main/java/org/thoughtcrime/securesms/mediasend/v2/MediaSelectionViewModel.kt index 624fc3aabf..23e4728009 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/mediasend/v2/MediaSelectionViewModel.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/mediasend/v2/MediaSelectionViewModel.kt @@ -40,7 +40,8 @@ class MediaSelectionViewModel( initialMessage: CharSequence?, val isReply: Boolean, isStory: Boolean, - private val repository: MediaSelectionRepository + private val repository: MediaSelectionRepository, + private val identityChangesSince: Long = System.currentTimeMillis() ) : ViewModel() { private val selectedMediaSubject: Subject> = BehaviorSubject.create() @@ -308,7 +309,7 @@ class MediaSelectionViewModel( fun send( selectedContacts: List = emptyList() ): Maybe { - return UntrustedRecords.checkForBadIdentityRecords(selectedContacts.toSet()).andThen( + return UntrustedRecords.checkForBadIdentityRecords(selectedContacts.toSet(), identityChangesSince).andThen( repository.send( store.state.selectedMedia, store.state.editorStateMap, diff --git a/app/src/main/java/org/thoughtcrime/securesms/mediasend/v2/UntrustedRecords.kt b/app/src/main/java/org/thoughtcrime/securesms/mediasend/v2/UntrustedRecords.kt index 0800bf7202..8fdb76a371 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/mediasend/v2/UntrustedRecords.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/mediasend/v2/UntrustedRecords.kt @@ -14,23 +14,23 @@ import java.util.concurrent.TimeUnit object UntrustedRecords { - fun checkForBadIdentityRecords(contactSearchKeys: Set): Completable { + fun checkForBadIdentityRecords(contactSearchKeys: Set, changedSince: Long): Completable { return Completable.fromAction { - val untrustedRecords: List = checkForBadIdentityRecordsSync(contactSearchKeys) + val untrustedRecords: List = checkForBadIdentityRecordsSync(contactSearchKeys, changedSince) if (untrustedRecords.isNotEmpty()) { throw UntrustedRecordsException(untrustedRecords, contactSearchKeys) } }.subscribeOn(Schedulers.io()) } - fun checkForBadIdentityRecords(contactSearchKeys: Set, consumer: Consumer>) { + fun checkForBadIdentityRecords(contactSearchKeys: Set, changedSince: Long, consumer: Consumer>) { SignalExecutors.BOUNDED.execute { - consumer.accept(checkForBadIdentityRecordsSync(contactSearchKeys)) + consumer.accept(checkForBadIdentityRecordsSync(contactSearchKeys, changedSince)) } } @WorkerThread - private fun checkForBadIdentityRecordsSync(contactSearchKeys: Set): List { + private fun checkForBadIdentityRecordsSync(contactSearchKeys: Set, changedSince: Long): List { val recipients: List = contactSearchKeys .map { Recipient.resolved(it.recipientId) } .map { recipient -> @@ -42,7 +42,13 @@ object UntrustedRecords { } .flatten() - return ApplicationDependencies.getProtocolStore().aci().identities().getIdentityRecords(recipients).getUntrustedRecords(TimeUnit.SECONDS.toMillis(30)) + val calculatedUntrustedWindow = System.currentTimeMillis() - changedSince + return ApplicationDependencies + .getProtocolStore() + .aci() + .identities() + .getIdentityRecords(recipients) + .getUntrustedRecords(calculatedUntrustedWindow.coerceIn(TimeUnit.SECONDS.toMillis(5)..TimeUnit.HOURS.toMillis(1))) } class UntrustedRecordsException(val untrustedRecords: List, val destinations: Set) : Throwable() diff --git a/app/src/main/java/org/thoughtcrime/securesms/mediasend/v2/text/TextStoryPostCreationViewModel.kt b/app/src/main/java/org/thoughtcrime/securesms/mediasend/v2/text/TextStoryPostCreationViewModel.kt index 9182772494..0079155c55 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/mediasend/v2/text/TextStoryPostCreationViewModel.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/mediasend/v2/text/TextStoryPostCreationViewModel.kt @@ -26,7 +26,7 @@ import org.thoughtcrime.securesms.mediasend.v2.text.send.TextStoryPostSendReposi import org.thoughtcrime.securesms.mediasend.v2.text.send.TextStoryPostSendResult import org.thoughtcrime.securesms.util.livedata.Store -class TextStoryPostCreationViewModel(private val repository: TextStoryPostSendRepository) : ViewModel() { +class TextStoryPostCreationViewModel(private val repository: TextStoryPostSendRepository, private val identityChangesSince: Long = System.currentTimeMillis()) : ViewModel() { private val store = Store(TextStoryPostCreationState()) private val textFontSubject: Subject = BehaviorSubject.create() @@ -123,7 +123,8 @@ class TextStoryPostCreationViewModel(private val repository: TextStoryPostSendRe return repository.send( contacts, store.state, - linkPreview + linkPreview, + identityChangesSince ) } diff --git a/app/src/main/java/org/thoughtcrime/securesms/mediasend/v2/text/send/TextStoryPostSendRepository.kt b/app/src/main/java/org/thoughtcrime/securesms/mediasend/v2/text/send/TextStoryPostSendRepository.kt index 5292d53b10..92e22921d4 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/mediasend/v2/text/send/TextStoryPostSendRepository.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/mediasend/v2/text/send/TextStoryPostSendRepository.kt @@ -38,9 +38,9 @@ class TextStoryPostSendRepository { }.subscribeOn(Schedulers.computation()) } - fun send(contactSearchKey: Set, textStoryPostCreationState: TextStoryPostCreationState, linkPreview: LinkPreview?): Single { + fun send(contactSearchKey: Set, textStoryPostCreationState: TextStoryPostCreationState, linkPreview: LinkPreview?, identityChangesSince: Long): Single { return UntrustedRecords - .checkForBadIdentityRecords(contactSearchKey.filterIsInstance(ContactSearchKey.RecipientSearchKey::class.java).toSet()) + .checkForBadIdentityRecords(contactSearchKey.filterIsInstance(ContactSearchKey.RecipientSearchKey::class.java).toSet(), identityChangesSince) .toSingleDefault(TextStoryPostSendResult.Success) .onErrorReturn { if (it is UntrustedRecords.UntrustedRecordsException) { diff --git a/app/src/main/java/org/thoughtcrime/securesms/stories/viewer/reply/group/StoryGroupReplySender.kt b/app/src/main/java/org/thoughtcrime/securesms/stories/viewer/reply/group/StoryGroupReplySender.kt index 3d80342be7..b07018a7de 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/stories/viewer/reply/group/StoryGroupReplySender.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/stories/viewer/reply/group/StoryGroupReplySender.kt @@ -6,6 +6,7 @@ import io.reactivex.rxjava3.core.Single import io.reactivex.rxjava3.schedulers.Schedulers import org.thoughtcrime.securesms.contacts.paged.ContactSearchKey import org.thoughtcrime.securesms.database.SignalDatabase +import org.thoughtcrime.securesms.database.identity.IdentityRecordList import org.thoughtcrime.securesms.database.model.Mention import org.thoughtcrime.securesms.database.model.ParentStoryId import org.thoughtcrime.securesms.database.model.StoryType @@ -36,7 +37,7 @@ object StoryGroupReplySender { } return messageAndRecipient.flatMapCompletable { (message, recipient) -> - UntrustedRecords.checkForBadIdentityRecords(setOf(ContactSearchKey.RecipientSearchKey.KnownRecipient(recipient.id))) + UntrustedRecords.checkForBadIdentityRecords(setOf(ContactSearchKey.RecipientSearchKey.KnownRecipient(recipient.id)), System.currentTimeMillis() - IdentityRecordList.DEFAULT_UNTRUSTED_WINDOW) .andThen( Completable.create { MessageSender.send( diff --git a/core-util/src/main/java/org/signal/core/util/concurrent/RxExtensions.kt b/core-util/src/main/java/org/signal/core/util/concurrent/RxExtensions.kt index c2536d2936..7032127fb0 100644 --- a/core-util/src/main/java/org/signal/core/util/concurrent/RxExtensions.kt +++ b/core-util/src/main/java/org/signal/core/util/concurrent/RxExtensions.kt @@ -2,6 +2,7 @@ package org.signal.core.util.concurrent +import android.annotation.SuppressLint import io.reactivex.rxjava3.core.Single import java.lang.RuntimeException @@ -11,6 +12,7 @@ import java.lang.RuntimeException * * [Single.blockingGet] is considered harmful and should not be used. */ +@SuppressLint("UnsafeBlockingGet") @Throws(InterruptedException::class) fun Single.safeBlockingGet(): T { try {