Change batch identity check timing behavior.

This commit is contained in:
Cody Henthorne 2022-08-01 13:18:20 -04:00 committed by Greyson Parrelli
parent dc04c8ed98
commit c2b5407911
9 changed files with 38 additions and 18 deletions

View file

@ -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<RecipientId, Long> = HashMap()
fun batchSafetyNumberCheck(newSelectionEntries: List<ContactSearchKey>) {
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<ContactSearchKey>, now: Long = System.currentTimeMillis(), batchSize: Int = MAX_BATCH_SIZE) {
val stopwatch = Stopwatch("batch-snc")
val recipientIds: Set<RecipientId> = newSelectionEntries.flattenToRecipientIds()
@ -49,7 +57,7 @@ class SafetyNumberRepository(
responses
.map { it as List<IdentityCheckResponse.AciIdentityPair> }
.flatten()
}.blockingGet()
}.safeBlockingGet()
stopwatch.split("batch-fetches")

View file

@ -16,7 +16,8 @@ class MultiselectForwardViewModel(
private val storySendRequirements: Stories.MediaTransform.SendRequirements,
private val records: List<MultiShareArgs>,
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 {

View file

@ -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<IdentityRecord> identityRecords;
private final boolean isVerified;

View file

@ -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<List<Media>> = BehaviorSubject.create()
@ -308,7 +309,7 @@ class MediaSelectionViewModel(
fun send(
selectedContacts: List<ContactSearchKey.RecipientSearchKey> = emptyList()
): Maybe<MediaSendActivityResult> {
return UntrustedRecords.checkForBadIdentityRecords(selectedContacts.toSet()).andThen(
return UntrustedRecords.checkForBadIdentityRecords(selectedContacts.toSet(), identityChangesSince).andThen(
repository.send(
store.state.selectedMedia,
store.state.editorStateMap,

View file

@ -14,23 +14,23 @@ import java.util.concurrent.TimeUnit
object UntrustedRecords {
fun checkForBadIdentityRecords(contactSearchKeys: Set<ContactSearchKey.RecipientSearchKey>): Completable {
fun checkForBadIdentityRecords(contactSearchKeys: Set<ContactSearchKey.RecipientSearchKey>, changedSince: Long): Completable {
return Completable.fromAction {
val untrustedRecords: List<IdentityRecord> = checkForBadIdentityRecordsSync(contactSearchKeys)
val untrustedRecords: List<IdentityRecord> = checkForBadIdentityRecordsSync(contactSearchKeys, changedSince)
if (untrustedRecords.isNotEmpty()) {
throw UntrustedRecordsException(untrustedRecords, contactSearchKeys)
}
}.subscribeOn(Schedulers.io())
}
fun checkForBadIdentityRecords(contactSearchKeys: Set<ContactSearchKey.RecipientSearchKey>, consumer: Consumer<List<IdentityRecord>>) {
fun checkForBadIdentityRecords(contactSearchKeys: Set<ContactSearchKey.RecipientSearchKey>, changedSince: Long, consumer: Consumer<List<IdentityRecord>>) {
SignalExecutors.BOUNDED.execute {
consumer.accept(checkForBadIdentityRecordsSync(contactSearchKeys))
consumer.accept(checkForBadIdentityRecordsSync(contactSearchKeys, changedSince))
}
}
@WorkerThread
private fun checkForBadIdentityRecordsSync(contactSearchKeys: Set<ContactSearchKey.RecipientSearchKey>): List<IdentityRecord> {
private fun checkForBadIdentityRecordsSync(contactSearchKeys: Set<ContactSearchKey.RecipientSearchKey>, changedSince: Long): List<IdentityRecord> {
val recipients: List<Recipient> = 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<IdentityRecord>, val destinations: Set<ContactSearchKey.RecipientSearchKey>) : Throwable()

View file

@ -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<TextFont> = BehaviorSubject.create()
@ -123,7 +123,8 @@ class TextStoryPostCreationViewModel(private val repository: TextStoryPostSendRe
return repository.send(
contacts,
store.state,
linkPreview
linkPreview,
identityChangesSince
)
}

View file

@ -38,9 +38,9 @@ class TextStoryPostSendRepository {
}.subscribeOn(Schedulers.computation())
}
fun send(contactSearchKey: Set<ContactSearchKey>, textStoryPostCreationState: TextStoryPostCreationState, linkPreview: LinkPreview?): Single<TextStoryPostSendResult> {
fun send(contactSearchKey: Set<ContactSearchKey>, textStoryPostCreationState: TextStoryPostCreationState, linkPreview: LinkPreview?, identityChangesSince: Long): Single<TextStoryPostSendResult> {
return UntrustedRecords
.checkForBadIdentityRecords(contactSearchKey.filterIsInstance(ContactSearchKey.RecipientSearchKey::class.java).toSet())
.checkForBadIdentityRecords(contactSearchKey.filterIsInstance(ContactSearchKey.RecipientSearchKey::class.java).toSet(), identityChangesSince)
.toSingleDefault<TextStoryPostSendResult>(TextStoryPostSendResult.Success)
.onErrorReturn {
if (it is UntrustedRecords.UntrustedRecordsException) {

View file

@ -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(

View file

@ -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 <T : Any> Single<T>.safeBlockingGet(): T {
try {