Change batch identity check timing behavior.
This commit is contained in:
parent
dc04c8ed98
commit
c2b5407911
9 changed files with 38 additions and 18 deletions
|
@ -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")
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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 {
|
||||
|
|
Loading…
Add table
Reference in a new issue