kopia lustrzana https://github.com/ryukoposting/Signal-Android
Ensure identity records are good before trying to send media.
rodzic
5b91c927b6
commit
b0458f10a3
|
@ -1,16 +1,11 @@
|
||||||
package org.thoughtcrime.securesms.conversation.mutiselect.forward
|
package org.thoughtcrime.securesms.conversation.mutiselect.forward
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import androidx.core.util.Consumer
|
|
||||||
import io.reactivex.rxjava3.core.Single
|
import io.reactivex.rxjava3.core.Single
|
||||||
import org.signal.core.util.concurrent.SignalExecutors
|
import org.signal.core.util.concurrent.SignalExecutors
|
||||||
import org.thoughtcrime.securesms.contacts.paged.ContactSearchKey
|
import org.thoughtcrime.securesms.contacts.paged.ContactSearchKey
|
||||||
import org.thoughtcrime.securesms.contacts.paged.RecipientSearchKey
|
|
||||||
import org.thoughtcrime.securesms.database.SignalDatabase
|
import org.thoughtcrime.securesms.database.SignalDatabase
|
||||||
import org.thoughtcrime.securesms.database.ThreadDatabase
|
import org.thoughtcrime.securesms.database.ThreadDatabase
|
||||||
import org.thoughtcrime.securesms.database.identity.IdentityRecordList
|
|
||||||
import org.thoughtcrime.securesms.database.model.IdentityRecord
|
|
||||||
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies
|
|
||||||
import org.thoughtcrime.securesms.recipients.Recipient
|
import org.thoughtcrime.securesms.recipients.Recipient
|
||||||
import org.thoughtcrime.securesms.recipients.RecipientId
|
import org.thoughtcrime.securesms.recipients.RecipientId
|
||||||
import org.thoughtcrime.securesms.sharing.MultiShareArgs
|
import org.thoughtcrime.securesms.sharing.MultiShareArgs
|
||||||
|
@ -20,25 +15,12 @@ import org.whispersystems.libsignal.util.guava.Optional
|
||||||
|
|
||||||
class MultiselectForwardRepository(context: Context) {
|
class MultiselectForwardRepository(context: Context) {
|
||||||
|
|
||||||
private val context = context.applicationContext
|
|
||||||
|
|
||||||
class MultiselectForwardResultHandlers(
|
class MultiselectForwardResultHandlers(
|
||||||
val onAllMessageSentSuccessfully: () -> Unit,
|
val onAllMessageSentSuccessfully: () -> Unit,
|
||||||
val onSomeMessagesFailed: () -> Unit,
|
val onSomeMessagesFailed: () -> Unit,
|
||||||
val onAllMessagesFailed: () -> Unit
|
val onAllMessagesFailed: () -> Unit
|
||||||
)
|
)
|
||||||
|
|
||||||
fun checkForBadIdentityRecords(contactSearchKeys: Set<ContactSearchKey>, consumer: Consumer<List<IdentityRecord>>) {
|
|
||||||
SignalExecutors.BOUNDED.execute {
|
|
||||||
val recipients: List<Recipient> = contactSearchKeys
|
|
||||||
.filterIsInstance<RecipientSearchKey>()
|
|
||||||
.map { Recipient.resolved(it.recipientId) }
|
|
||||||
val identityRecordList: IdentityRecordList = ApplicationDependencies.getProtocolStore().aci().identities().getIdentityRecords(recipients)
|
|
||||||
|
|
||||||
consumer.accept(identityRecordList.untrustedRecords)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun canSelectRecipient(recipientId: Optional<RecipientId>): Single<Boolean> {
|
fun canSelectRecipient(recipientId: Optional<RecipientId>): Single<Boolean> {
|
||||||
if (!recipientId.isPresent) {
|
if (!recipientId.isPresent) {
|
||||||
return Single.just(true)
|
return Single.just(true)
|
||||||
|
|
|
@ -4,7 +4,9 @@ import androidx.lifecycle.LiveData
|
||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
import androidx.lifecycle.ViewModelProvider
|
import androidx.lifecycle.ViewModelProvider
|
||||||
import org.thoughtcrime.securesms.contacts.paged.ContactSearchKey
|
import org.thoughtcrime.securesms.contacts.paged.ContactSearchKey
|
||||||
|
import org.thoughtcrime.securesms.contacts.paged.RecipientSearchKey
|
||||||
import org.thoughtcrime.securesms.keyvalue.SignalStore
|
import org.thoughtcrime.securesms.keyvalue.SignalStore
|
||||||
|
import org.thoughtcrime.securesms.mediasend.v2.UntrustedRecords
|
||||||
import org.thoughtcrime.securesms.sharing.MultiShareArgs
|
import org.thoughtcrime.securesms.sharing.MultiShareArgs
|
||||||
import org.thoughtcrime.securesms.util.livedata.Store
|
import org.thoughtcrime.securesms.util.livedata.Store
|
||||||
|
|
||||||
|
@ -23,7 +25,7 @@ class MultiselectForwardViewModel(
|
||||||
store.update { it.copy(stage = MultiselectForwardState.Stage.FirstConfirmation) }
|
store.update { it.copy(stage = MultiselectForwardState.Stage.FirstConfirmation) }
|
||||||
} else {
|
} else {
|
||||||
store.update { it.copy(stage = MultiselectForwardState.Stage.LoadingIdentities) }
|
store.update { it.copy(stage = MultiselectForwardState.Stage.LoadingIdentities) }
|
||||||
repository.checkForBadIdentityRecords(selectedContacts) { identityRecords ->
|
UntrustedRecords.checkForBadIdentityRecords(selectedContacts.filterIsInstance(RecipientSearchKey::class.java).toSet()) { identityRecords ->
|
||||||
if (identityRecords.isEmpty()) {
|
if (identityRecords.isEmpty()) {
|
||||||
performSend(additionalMessage, selectedContacts)
|
performSend(additionalMessage, selectedContacts)
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -22,6 +22,7 @@ import org.thoughtcrime.securesms.components.emoji.EmojiEventListener
|
||||||
import org.thoughtcrime.securesms.contacts.paged.ContactSearchConfiguration
|
import org.thoughtcrime.securesms.contacts.paged.ContactSearchConfiguration
|
||||||
import org.thoughtcrime.securesms.contacts.paged.ContactSearchState
|
import org.thoughtcrime.securesms.contacts.paged.ContactSearchState
|
||||||
import org.thoughtcrime.securesms.conversation.mutiselect.forward.SearchConfigurationProvider
|
import org.thoughtcrime.securesms.conversation.mutiselect.forward.SearchConfigurationProvider
|
||||||
|
import org.thoughtcrime.securesms.conversation.ui.error.SafetyNumberChangeDialog
|
||||||
import org.thoughtcrime.securesms.keyboard.emoji.EmojiKeyboardPageFragment
|
import org.thoughtcrime.securesms.keyboard.emoji.EmojiKeyboardPageFragment
|
||||||
import org.thoughtcrime.securesms.keyboard.emoji.search.EmojiSearchFragment
|
import org.thoughtcrime.securesms.keyboard.emoji.search.EmojiSearchFragment
|
||||||
import org.thoughtcrime.securesms.mediasend.Media
|
import org.thoughtcrime.securesms.mediasend.Media
|
||||||
|
@ -146,6 +147,10 @@ class MediaSelectionActivity :
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onSendError(error: Throwable) {
|
override fun onSendError(error: Throwable) {
|
||||||
|
if (error is UntrustedRecords.UntrustedRecordsException) {
|
||||||
|
Log.w(TAG, "Send failed due to untrusted identities.")
|
||||||
|
SafetyNumberChangeDialog.show(supportFragmentManager, error.untrustedRecords)
|
||||||
|
} else {
|
||||||
setResult(RESULT_CANCELED)
|
setResult(RESULT_CANCELED)
|
||||||
|
|
||||||
// TODO [alex] - Toast
|
// TODO [alex] - Toast
|
||||||
|
@ -154,6 +159,7 @@ class MediaSelectionActivity :
|
||||||
finish()
|
finish()
|
||||||
overridePendingTransition(R.anim.stationary, R.anim.camera_slide_to_bottom)
|
overridePendingTransition(R.anim.stationary, R.anim.camera_slide_to_bottom)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override fun onNoMediaSelected() {
|
override fun onNoMediaSelected() {
|
||||||
Log.w(TAG, "No media selected. Exiting.")
|
Log.w(TAG, "No media selected. Exiting.")
|
||||||
|
|
|
@ -280,7 +280,8 @@ class MediaSelectionViewModel(
|
||||||
fun send(
|
fun send(
|
||||||
selectedContacts: List<RecipientSearchKey> = emptyList()
|
selectedContacts: List<RecipientSearchKey> = emptyList()
|
||||||
): Maybe<MediaSendActivityResult> {
|
): Maybe<MediaSendActivityResult> {
|
||||||
return repository.send(
|
return UntrustedRecords.checkForBadIdentityRecords(selectedContacts.toSet()).andThen(
|
||||||
|
repository.send(
|
||||||
store.state.selectedMedia,
|
store.state.selectedMedia,
|
||||||
store.state.editorStateMap,
|
store.state.editorStateMap,
|
||||||
store.state.quality,
|
store.state.quality,
|
||||||
|
@ -288,10 +289,11 @@ class MediaSelectionViewModel(
|
||||||
store.state.transportOption.isSms,
|
store.state.transportOption.isSms,
|
||||||
isViewOnceEnabled(),
|
isViewOnceEnabled(),
|
||||||
destination.getRecipientSearchKey(),
|
destination.getRecipientSearchKey(),
|
||||||
if (selectedContacts.isNotEmpty()) selectedContacts else destination.getRecipientSearchKeyList(),
|
selectedContacts.ifEmpty { destination.getRecipientSearchKeyList() },
|
||||||
MentionAnnotation.getMentionsFromAnnotations(store.state.message),
|
MentionAnnotation.getMentionsFromAnnotations(store.state.message),
|
||||||
store.state.transportOption
|
store.state.transportOption
|
||||||
)
|
)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun isViewOnceEnabled(): Boolean {
|
private fun isViewOnceEnabled(): Boolean {
|
||||||
|
|
|
@ -0,0 +1,46 @@
|
||||||
|
package org.thoughtcrime.securesms.mediasend.v2
|
||||||
|
|
||||||
|
import androidx.core.util.Consumer
|
||||||
|
import io.reactivex.rxjava3.core.Completable
|
||||||
|
import io.reactivex.rxjava3.schedulers.Schedulers
|
||||||
|
import org.signal.core.util.concurrent.SignalExecutors
|
||||||
|
import org.thoughtcrime.securesms.contacts.paged.RecipientSearchKey
|
||||||
|
import org.thoughtcrime.securesms.database.SignalDatabase
|
||||||
|
import org.thoughtcrime.securesms.database.model.IdentityRecord
|
||||||
|
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies
|
||||||
|
import org.thoughtcrime.securesms.recipients.Recipient
|
||||||
|
|
||||||
|
object UntrustedRecords {
|
||||||
|
|
||||||
|
fun checkForBadIdentityRecords(contactSearchKeys: Set<RecipientSearchKey>): Completable {
|
||||||
|
return Completable.fromAction {
|
||||||
|
val untrustedRecords: List<IdentityRecord> = checkForBadIdentityRecordsSync(contactSearchKeys)
|
||||||
|
if (untrustedRecords.isNotEmpty()) {
|
||||||
|
throw UntrustedRecordsException(untrustedRecords)
|
||||||
|
}
|
||||||
|
}.subscribeOn(Schedulers.io())
|
||||||
|
}
|
||||||
|
|
||||||
|
fun checkForBadIdentityRecords(contactSearchKeys: Set<RecipientSearchKey>, consumer: Consumer<List<IdentityRecord>>) {
|
||||||
|
SignalExecutors.BOUNDED.execute {
|
||||||
|
consumer.accept(checkForBadIdentityRecordsSync(contactSearchKeys))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun checkForBadIdentityRecordsSync(contactSearchKeys: Set<RecipientSearchKey>): List<IdentityRecord> {
|
||||||
|
val recipients: List<Recipient> = contactSearchKeys
|
||||||
|
.map { Recipient.resolved(it.recipientId) }
|
||||||
|
.map { recipient ->
|
||||||
|
when {
|
||||||
|
recipient.isGroup -> recipient.participants
|
||||||
|
recipient.isDistributionList -> Recipient.resolvedList(SignalDatabase.distributionLists.getMembers(recipient.distributionListId.get()))
|
||||||
|
else -> listOf(recipient)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.flatten()
|
||||||
|
|
||||||
|
return ApplicationDependencies.getProtocolStore().aci().identities().getIdentityRecords(recipients).untrustedRecords
|
||||||
|
}
|
||||||
|
|
||||||
|
class UntrustedRecordsException(val untrustedRecords: List<IdentityRecord>) : Throwable()
|
||||||
|
}
|
|
@ -2,19 +2,17 @@ package org.thoughtcrime.securesms.mediasend.v2.text.send
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import io.reactivex.rxjava3.core.Single
|
import io.reactivex.rxjava3.core.Single
|
||||||
import io.reactivex.rxjava3.schedulers.Schedulers
|
|
||||||
import org.signal.core.util.ThreadUtil
|
import org.signal.core.util.ThreadUtil
|
||||||
import org.thoughtcrime.securesms.contacts.paged.ContactSearchKey
|
import org.thoughtcrime.securesms.contacts.paged.ContactSearchKey
|
||||||
import org.thoughtcrime.securesms.contacts.paged.RecipientSearchKey
|
import org.thoughtcrime.securesms.contacts.paged.RecipientSearchKey
|
||||||
import org.thoughtcrime.securesms.database.SignalDatabase
|
import org.thoughtcrime.securesms.database.SignalDatabase
|
||||||
import org.thoughtcrime.securesms.database.ThreadDatabase
|
import org.thoughtcrime.securesms.database.ThreadDatabase
|
||||||
import org.thoughtcrime.securesms.database.identity.IdentityRecordList
|
|
||||||
import org.thoughtcrime.securesms.database.model.StoryType
|
import org.thoughtcrime.securesms.database.model.StoryType
|
||||||
import org.thoughtcrime.securesms.database.model.databaseprotos.StoryTextPost
|
import org.thoughtcrime.securesms.database.model.databaseprotos.StoryTextPost
|
||||||
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies
|
|
||||||
import org.thoughtcrime.securesms.fonts.TextFont
|
import org.thoughtcrime.securesms.fonts.TextFont
|
||||||
import org.thoughtcrime.securesms.keyvalue.SignalStore
|
import org.thoughtcrime.securesms.keyvalue.SignalStore
|
||||||
import org.thoughtcrime.securesms.linkpreview.LinkPreview
|
import org.thoughtcrime.securesms.linkpreview.LinkPreview
|
||||||
|
import org.thoughtcrime.securesms.mediasend.v2.UntrustedRecords
|
||||||
import org.thoughtcrime.securesms.mediasend.v2.text.TextStoryPostCreationState
|
import org.thoughtcrime.securesms.mediasend.v2.text.TextStoryPostCreationState
|
||||||
import org.thoughtcrime.securesms.mms.OutgoingMediaMessage
|
import org.thoughtcrime.securesms.mms.OutgoingMediaMessage
|
||||||
import org.thoughtcrime.securesms.mms.OutgoingSecureMediaMessage
|
import org.thoughtcrime.securesms.mms.OutgoingSecureMediaMessage
|
||||||
|
@ -35,7 +33,17 @@ class TextStoryPostSendRepository(context: Context) {
|
||||||
}
|
}
|
||||||
|
|
||||||
fun send(contactSearchKey: Set<ContactSearchKey>, textStoryPostCreationState: TextStoryPostCreationState, linkPreview: LinkPreview?): Single<TextStoryPostSendResult> {
|
fun send(contactSearchKey: Set<ContactSearchKey>, textStoryPostCreationState: TextStoryPostCreationState, linkPreview: LinkPreview?): Single<TextStoryPostSendResult> {
|
||||||
return checkForBadIdentityRecords(contactSearchKey).flatMap { result ->
|
return UntrustedRecords
|
||||||
|
.checkForBadIdentityRecords(contactSearchKey.filterIsInstance(RecipientSearchKey::class.java).toSet())
|
||||||
|
.toSingleDefault<TextStoryPostSendResult>(TextStoryPostSendResult.Success)
|
||||||
|
.onErrorReturn {
|
||||||
|
if (it is UntrustedRecords.UntrustedRecordsException) {
|
||||||
|
TextStoryPostSendResult.UntrustedRecordsError(it.untrustedRecords)
|
||||||
|
} else {
|
||||||
|
TextStoryPostSendResult.Failure
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.flatMap { result ->
|
||||||
if (result is TextStoryPostSendResult.Success) {
|
if (result is TextStoryPostSendResult.Success) {
|
||||||
performSend(contactSearchKey, textStoryPostCreationState, linkPreview)
|
performSend(contactSearchKey, textStoryPostCreationState, linkPreview)
|
||||||
} else {
|
} else {
|
||||||
|
@ -44,21 +52,6 @@ class TextStoryPostSendRepository(context: Context) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun checkForBadIdentityRecords(contactSearchKeys: Set<ContactSearchKey>): Single<TextStoryPostSendResult> {
|
|
||||||
return Single.fromCallable {
|
|
||||||
val recipients: List<Recipient> = contactSearchKeys
|
|
||||||
.filterIsInstance<RecipientSearchKey>()
|
|
||||||
.map { Recipient.resolved(it.recipientId) }
|
|
||||||
val identityRecordList: IdentityRecordList = ApplicationDependencies.getProtocolStore().aci().identities().getIdentityRecords(recipients)
|
|
||||||
|
|
||||||
if (identityRecordList.untrustedRecords.isNotEmpty()) {
|
|
||||||
TextStoryPostSendResult.UntrustedRecordsError(identityRecordList.untrustedRecords)
|
|
||||||
} else {
|
|
||||||
TextStoryPostSendResult.Success
|
|
||||||
}
|
|
||||||
}.subscribeOn(Schedulers.io())
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun performSend(contactSearchKey: Set<ContactSearchKey>, textStoryPostCreationState: TextStoryPostCreationState, linkPreview: LinkPreview?): Single<TextStoryPostSendResult> {
|
private fun performSend(contactSearchKey: Set<ContactSearchKey>, textStoryPostCreationState: TextStoryPostCreationState, linkPreview: LinkPreview?): Single<TextStoryPostSendResult> {
|
||||||
return Single.fromCallable {
|
return Single.fromCallable {
|
||||||
val messages: MutableList<OutgoingSecureMediaMessage> = mutableListOf()
|
val messages: MutableList<OutgoingSecureMediaMessage> = mutableListOf()
|
||||||
|
|
|
@ -4,5 +4,6 @@ import org.thoughtcrime.securesms.database.model.IdentityRecord
|
||||||
|
|
||||||
sealed class TextStoryPostSendResult {
|
sealed class TextStoryPostSendResult {
|
||||||
object Success : TextStoryPostSendResult()
|
object Success : TextStoryPostSendResult()
|
||||||
|
object Failure : TextStoryPostSendResult()
|
||||||
data class UntrustedRecordsError(val untrustedRecords: List<IdentityRecord>) : TextStoryPostSendResult()
|
data class UntrustedRecordsError(val untrustedRecords: List<IdentityRecord>) : TextStoryPostSendResult()
|
||||||
}
|
}
|
||||||
|
|
Ładowanie…
Reference in New Issue