Light refactoring.

Signed-off-by: Dominic Fischer <dominicfischer7@gmail.com>
This commit is contained in:
Dominic Fischer 2019-10-24 14:58:11 +01:00
parent 5ab975cc5c
commit 1ac99e92a6
9 changed files with 103 additions and 161 deletions

View file

@ -43,6 +43,7 @@ import im.vector.matrix.android.internal.util.MatrixCoroutineDispatchers
import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import timber.log.Timber import timber.log.Timber
import java.lang.Exception
import java.util.UUID import java.util.UUID
import javax.inject.Inject import javax.inject.Inject
import kotlin.collections.HashMap import kotlin.collections.HashMap
@ -166,72 +167,59 @@ internal class DefaultSasVerificationService @Inject constructor(private val cre
return return
} }
// Download device keys prior to everything // Download device keys prior to everything
checkKeysAreDownloaded( if (checkKeysAreDownloaded(otherUserId!!, startReq) != null) {
otherUserId!!, Timber.v("## SAS onStartRequestReceived ${startReq.transactionID!!}")
startReq, val tid = startReq.transactionID!!
success = { val existing = getExistingTransaction(otherUserId, tid)
Timber.v("## SAS onStartRequestReceived ${startReq.transactionID!!}") val existingTxs = getExistingTransactionsForUser(otherUserId)
val tid = startReq.transactionID!! if (existing != null) {
val existing = getExistingTransaction(otherUserId, tid) // should cancel both!
val existingTxs = getExistingTransactionsForUser(otherUserId) Timber.v("## SAS onStartRequestReceived - Request exist with same if ${startReq.transactionID!!}")
if (existing != null) { existing.cancel(CancelCode.UnexpectedMessage)
// should cancel both! cancelTransaction(tid, otherUserId, startReq.fromDevice!!, CancelCode.UnexpectedMessage)
Timber.v("## SAS onStartRequestReceived - Request exist with same if ${startReq.transactionID!!}") } else if (existingTxs?.isEmpty() == false) {
existing.cancel(CancelCode.UnexpectedMessage) Timber.v("## SAS onStartRequestReceived - There is already a transaction with this user ${startReq.transactionID!!}")
cancelTransaction(tid, otherUserId, startReq.fromDevice!!, CancelCode.UnexpectedMessage) // Multiple keyshares between two devices: any two devices may only have at most one key verification in flight at a time.
} else if (existingTxs?.isEmpty() == false) { existingTxs.forEach {
Timber.v("## SAS onStartRequestReceived - There is already a transaction with this user ${startReq.transactionID!!}") it.cancel(CancelCode.UnexpectedMessage)
// Multiple keyshares between two devices: any two devices may only have at most one key verification in flight at a time. }
existingTxs.forEach { cancelTransaction(tid, otherUserId, startReq.fromDevice!!, CancelCode.UnexpectedMessage)
it.cancel(CancelCode.UnexpectedMessage) } else {
} // Ok we can create
cancelTransaction(tid, otherUserId, startReq.fromDevice!!, CancelCode.UnexpectedMessage) if (KeyVerificationStart.VERIF_METHOD_SAS == startReq.method) {
} else { Timber.v("## SAS onStartRequestReceived - request accepted ${startReq.transactionID!!}")
// Ok we can create val tx = IncomingSASVerificationTransaction(
if (KeyVerificationStart.VERIF_METHOD_SAS == startReq.method) { this,
Timber.v("## SAS onStartRequestReceived - request accepted ${startReq.transactionID!!}") setDeviceVerificationAction,
val tx = IncomingSASVerificationTransaction( credentials,
this, cryptoStore,
setDeviceVerificationAction, sendToDeviceTask,
credentials, taskExecutor,
cryptoStore, myDeviceInfoHolder.get().myDevice.fingerprint()!!,
sendToDeviceTask, startReq.transactionID!!,
taskExecutor, otherUserId)
myDeviceInfoHolder.get().myDevice.fingerprint()!!, addTransaction(tx)
startReq.transactionID!!, tx.acceptToDeviceEvent(otherUserId, startReq)
otherUserId) } else {
addTransaction(tx) Timber.e("## SAS onStartRequestReceived - unknown method ${startReq.method}")
tx.acceptToDeviceEvent(otherUserId, startReq) cancelTransaction(tid, otherUserId, startReq.fromDevice
} else { ?: event.getSenderKey()!!, CancelCode.UnknownMethod)
Timber.e("## SAS onStartRequestReceived - unknown method ${startReq.method}") }
cancelTransaction(tid, otherUserId, startReq.fromDevice }
?: event.getSenderKey()!!, CancelCode.UnknownMethod) } else {
} cancelTransaction(startReq.transactionID!!, otherUserId, startReq.fromDevice!!, CancelCode.UnexpectedMessage)
} }
},
error = {
cancelTransaction(startReq.transactionID!!, otherUserId, startReq.fromDevice!!, CancelCode.UnexpectedMessage)
})
} }
private suspend fun checkKeysAreDownloaded(otherUserId: String, private suspend fun checkKeysAreDownloaded(otherUserId: String,
startReq: KeyVerificationStart, startReq: KeyVerificationStart): MXUsersDevicesMap<MXDeviceInfo>? {
success: (MXUsersDevicesMap<MXDeviceInfo>) -> Unit, return try {
error: () -> Unit) { val keys = deviceListManager.downloadKeys(listOf(otherUserId), true)
runCatching { val deviceIds = keys.getUserDeviceIds(otherUserId) ?: return null
deviceListManager.downloadKeys(listOf(otherUserId), true) keys.takeIf { deviceIds.contains(startReq.fromDevice) }
}.fold( } catch (e: Exception) {
{ null
if (it.getUserDeviceIds(otherUserId)?.contains(startReq.fromDevice) == true) { }
success(it)
} else {
error()
}
},
{
error()
}
)
} }
private suspend fun onCancelReceived(event: Event) { private suspend fun onCancelReceived(event: Event) {

View file

@ -39,7 +39,7 @@ import im.vector.matrix.android.internal.session.room.RoomSummaryUpdater
import im.vector.matrix.android.internal.util.StringProvider import im.vector.matrix.android.internal.util.StringProvider
import org.commonmark.parser.Parser import org.commonmark.parser.Parser
import org.commonmark.renderer.html.HtmlRenderer import org.commonmark.renderer.html.HtmlRenderer
import java.util.* import java.util.UUID
import javax.inject.Inject import javax.inject.Inject
/** /**

View file

@ -30,15 +30,10 @@ import java.io.File
*/ */
@WorkerThread @WorkerThread
fun writeToFile(str: String, file: File): Try<Unit> { fun writeToFile(str: String, file: File): Try<Unit> {
return Try { return Try<Unit> {
val sink = file.sink() file.sink().buffer().use {
it.writeString(str, Charsets.UTF_8)
val bufferedSink = sink.buffer() }
bufferedSink.writeString(str, Charsets.UTF_8)
bufferedSink.close()
sink.close()
} }
} }
@ -47,15 +42,10 @@ fun writeToFile(str: String, file: File): Try<Unit> {
*/ */
@WorkerThread @WorkerThread
fun writeToFile(data: ByteArray, file: File): Try<Unit> { fun writeToFile(data: ByteArray, file: File): Try<Unit> {
return Try { return Try<Unit> {
val sink = file.sink() file.sink().buffer().use {
it.write(data)
val bufferedSink = sink.buffer() }
bufferedSink.write(data)
bufferedSink.close()
sink.close()
} }
} }

View file

@ -17,7 +17,6 @@
package im.vector.riotx.core.images package im.vector.riotx.core.images
import android.content.Context import android.content.Context
import android.database.Cursor
import android.net.Uri import android.net.Uri
import android.provider.MediaStore import android.provider.MediaStore
import androidx.exifinterface.media.ExifInterface import androidx.exifinterface.media.ExifInterface
@ -37,26 +36,24 @@ class ImageTools @Inject constructor(private val context: Context) {
if (uri.scheme == "content") { if (uri.scheme == "content") {
val proj = arrayOf(MediaStore.Images.Media.DATA) val proj = arrayOf(MediaStore.Images.Media.DATA)
var cursor: Cursor? = null
try { try {
cursor = context.contentResolver.query(uri, proj, null, null, null) val cursor = context.contentResolver.query(uri, proj, null, null, null)
if (cursor != null && cursor.count > 0) { cursor?.use {
cursor.moveToFirst() if (it.moveToFirst()) {
val idxData = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA) val idxData = it.getColumnIndexOrThrow(MediaStore.Images.Media.DATA)
val path = cursor.getString(idxData) val path = it.getString(idxData)
if (path.isNullOrBlank()) { if (path.isNullOrBlank()) {
Timber.w("Cannot find path in media db for uri $uri") Timber.w("Cannot find path in media db for uri $uri")
return orientation return orientation
}
val exif = ExifInterface(path)
orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_UNDEFINED)
} }
val exif = ExifInterface(path)
orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_UNDEFINED)
} }
} catch (e: Exception) { } catch (e: Exception) {
// eg SecurityException from com.google.android.apps.photos.content.GooglePhotosImageProvider URIs // eg SecurityException from com.google.android.apps.photos.content.GooglePhotosImageProvider URIs
// eg IOException from trying to parse the returned path as a file when it is an http uri. // eg IOException from trying to parse the returned path as a file when it is an http uri.
Timber.e(e, "Cannot get orientation for bitmap") Timber.e(e, "Cannot get orientation for bitmap")
} finally {
cursor?.close()
} }
} else if (uri.scheme == "file") { } else if (uri.scheme == "file") {
try { try {

View file

@ -17,28 +17,17 @@
package im.vector.riotx.core.intent package im.vector.riotx.core.intent
import android.content.Context import android.content.Context
import android.database.Cursor
import android.net.Uri import android.net.Uri
import android.provider.OpenableColumns import android.provider.OpenableColumns
fun getFilenameFromUri(context: Context?, uri: Uri): String? { fun getFilenameFromUri(context: Context?, uri: Uri): String? {
var result: String? = null
if (context != null && uri.scheme == "content") { if (context != null && uri.scheme == "content") {
val cursor: Cursor? = context.contentResolver.query(uri, null, null, null, null) val cursor = context.contentResolver.query(uri, null, null, null, null)
try { cursor?.use {
if (cursor != null && cursor.moveToFirst()) { if (it.moveToFirst()) {
result = cursor.getString(cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME)) return it.getString(it.getColumnIndex(OpenableColumns.DISPLAY_NAME))
} }
} finally {
cursor?.close()
} }
} }
if (result == null) { return uri.path?.substringAfterLast('/')
result = uri.path
val cut = result?.lastIndexOf('/') ?: -1
if (cut != -1) {
result = result?.substring(cut + 1)
}
}
return result
} }

View file

@ -18,10 +18,10 @@ package im.vector.riotx.features.crypto.keys
import android.content.Context import android.content.Context
import android.os.Environment import android.os.Environment
import arrow.core.Try
import im.vector.matrix.android.api.MatrixCallback import im.vector.matrix.android.api.MatrixCallback
import im.vector.matrix.android.api.session.Session import im.vector.matrix.android.api.session.Session
import im.vector.matrix.android.internal.extensions.foldToCallback import im.vector.matrix.android.internal.extensions.foldToCallback
import im.vector.matrix.android.internal.util.awaitCallback
import im.vector.riotx.core.files.addEntryToDownloadManager import im.vector.riotx.core.files.addEntryToDownloadManager
import im.vector.riotx.core.files.writeToFile import im.vector.riotx.core.files.writeToFile
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
@ -36,28 +36,20 @@ class KeysExporter(private val session: Session) {
* Export keys and return the file path with the callback * Export keys and return the file path with the callback
*/ */
fun export(context: Context, password: String, callback: MatrixCallback<String>) { fun export(context: Context, password: String, callback: MatrixCallback<String>) {
session.exportRoomKeys(password, object : MatrixCallback<ByteArray> { GlobalScope.launch(Dispatchers.Main) {
override fun onSuccess(data: ByteArray) { runCatching {
GlobalScope.launch(Dispatchers.Main) { val data = awaitCallback<ByteArray> { session.exportRoomKeys(password, it) }
withContext(Dispatchers.IO) { withContext(Dispatchers.IO) {
Try { val parentDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS)
val parentDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS) val file = File(parentDir, "riotx-keys-" + System.currentTimeMillis() + ".txt")
val file = File(parentDir, "riotx-keys-" + System.currentTimeMillis() + ".txt")
writeToFile(data, file) writeToFile(data, file)
addEntryToDownloadManager(context, file, "text/plain") addEntryToDownloadManager(context, file, "text/plain")
file.absolutePath file.absolutePath
}
}
.foldToCallback(callback)
} }
} }.foldToCallback(callback)
}
override fun onFailure(failure: Throwable) {
callback.onFailure(failure)
}
})
} }
} }

View file

@ -18,10 +18,11 @@ package im.vector.riotx.features.crypto.keys
import android.content.Context import android.content.Context
import android.net.Uri import android.net.Uri
import arrow.core.Try
import im.vector.matrix.android.api.MatrixCallback import im.vector.matrix.android.api.MatrixCallback
import im.vector.matrix.android.api.session.Session import im.vector.matrix.android.api.session.Session
import im.vector.matrix.android.internal.crypto.model.ImportRoomKeysResult import im.vector.matrix.android.internal.crypto.model.ImportRoomKeysResult
import im.vector.matrix.android.internal.extensions.foldToCallback
import im.vector.matrix.android.internal.util.awaitCallback
import im.vector.riotx.core.intent.getMimeTypeFromUri import im.vector.riotx.core.intent.getMimeTypeFromUri
import im.vector.riotx.core.resources.openResource import im.vector.riotx.core.resources.openResource
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
@ -41,8 +42,8 @@ class KeysImporter(private val session: Session) {
password: String, password: String,
callback: MatrixCallback<ImportRoomKeysResult>) { callback: MatrixCallback<ImportRoomKeysResult>) {
GlobalScope.launch(Dispatchers.Main) { GlobalScope.launch(Dispatchers.Main) {
withContext(Dispatchers.IO) { runCatching {
Try { withContext(Dispatchers.IO) {
val resource = openResource(context, uri, mimetype ?: getMimeTypeFromUri(context, uri)) val resource = openResource(context, uri, mimetype ?: getMimeTypeFromUri(context, uri))
if (resource?.mContentStream == null) { if (resource?.mContentStream == null) {
@ -51,33 +52,17 @@ class KeysImporter(private val session: Session) {
val data: ByteArray val data: ByteArray
try { try {
data = ByteArray(resource.mContentStream!!.available()) data = resource.mContentStream!!.use { it.readBytes() }
resource.mContentStream!!.read(data)
resource.mContentStream!!.close()
data
} catch (e: Exception) { } catch (e: Exception) {
try { Timber.e(e, "## importKeys()")
resource.mContentStream!!.close()
} catch (e2: Exception) {
Timber.e(e2, "## importKeys()")
}
throw e throw e
} }
awaitCallback<ImportRoomKeysResult> {
session.importRoomKeys(data, password, null, it)
}
} }
} }.foldToCallback(callback)
.fold(
{
callback.onFailure(it)
},
{ byteArray ->
session.importRoomKeys(byteArray,
password,
null,
callback)
}
)
} }
} }
} }

View file

@ -170,8 +170,8 @@ class KeysBackupSetupStep3Fragment : VectorBaseFragment() {
private fun exportRecoveryKeyToFile(data: String) { private fun exportRecoveryKeyToFile(data: String) {
GlobalScope.launch(Dispatchers.Main) { GlobalScope.launch(Dispatchers.Main) {
withContext(Dispatchers.IO) { Try {
Try { withContext(Dispatchers.IO) {
val parentDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS) val parentDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS)
val file = File(parentDir, "recovery-key-" + System.currentTimeMillis() + ".txt") val file = File(parentDir, "recovery-key-" + System.currentTimeMillis() + ".txt")

View file

@ -42,7 +42,8 @@ import im.vector.riotx.features.home.room.detail.timeline.format.NoticeEventForm
import im.vector.riotx.features.home.room.detail.timeline.item.MessageInformationData import im.vector.riotx.features.home.room.detail.timeline.item.MessageInformationData
import im.vector.riotx.features.html.EventHtmlRenderer import im.vector.riotx.features.html.EventHtmlRenderer
import java.text.SimpleDateFormat import java.text.SimpleDateFormat
import java.util.* import java.util.Date
import java.util.Locale
/** /**
* Quick reactions state * Quick reactions state