Encrypt file WIP

This commit is contained in:
Benoit Marty 2019-07-02 09:53:17 +02:00 committed by Benoit Marty
parent 014d03893a
commit 0c2d3f36c3
3 changed files with 91 additions and 26 deletions

View File

@ -42,7 +42,7 @@ object MXEncryptedAttachments {
*/
data class EncryptionResult(
var encryptedFileInfo: EncryptedFileInfo,
var encryptedStream: InputStream
var encryptedByteArray: ByteArray
)

/***
@ -112,7 +112,7 @@ object MXEncryptedAttachments {
hashes = mapOf("sha256" to base64ToUnpaddedBase64(Base64.encodeToString(messageDigest.digest(), Base64.DEFAULT))!!),
v = "v2"
),
encryptedStream = ByteArrayInputStream(outStream.toByteArray())
encryptedByteArray = outStream.toByteArray()
)

outStream.close()

View File

@ -25,13 +25,17 @@ import im.vector.matrix.android.api.session.events.model.Event
import im.vector.matrix.android.api.session.events.model.toContent
import im.vector.matrix.android.api.session.events.model.toModel
import im.vector.matrix.android.api.session.room.model.message.*
import im.vector.matrix.android.internal.crypto.attachments.MXEncryptedAttachments
import im.vector.matrix.android.internal.crypto.model.rest.EncryptedFileInfo
import im.vector.matrix.android.internal.network.ProgressRequestBody
import im.vector.matrix.android.internal.session.room.send.SendEventWorker
import im.vector.matrix.android.internal.worker.SessionWorkerParams
import im.vector.matrix.android.internal.worker.WorkerParamsFactory
import im.vector.matrix.android.internal.worker.getSessionComponent
import timber.log.Timber
import java.io.ByteArrayInputStream
import java.io.File
import java.io.FileInputStream
import javax.inject.Inject


@ -42,7 +46,8 @@ internal class UploadContentWorker(context: Context, params: WorkerParameters) :
override val userId: String,
val roomId: String,
val event: Event,
val attachment: ContentAttachmentData
val attachment: ContentAttachmentData,
val isRoomEncrypted: Boolean
) : SessionWorkerParams

@Inject lateinit var fileUploader: FileUploader
@ -58,17 +63,33 @@ internal class UploadContentWorker(context: Context, params: WorkerParameters) :
val eventId = params.event.eventId ?: return Result.success()
val attachment = params.attachment

val isRoomEncrypted = params.isRoomEncrypted


val thumbnailData = ThumbnailExtractor.extractThumbnail(params.attachment)
val attachmentFile = createAttachmentFile(attachment) ?: return Result.failure()
var uploadedThumbnailUrl: String? = null
var uploadedThumbnailEncryptedFileInfo: EncryptedFileInfo? = null

if (thumbnailData != null) {
fileUploader
.uploadByteArray(thumbnailData.bytes, "thumb_${attachment.name}", thumbnailData.mimeType)
if (isRoomEncrypted) {
Timber.v("Encrypt thumbnail")
val encryptionResult = MXEncryptedAttachments.encryptAttachment(ByteArrayInputStream(thumbnailData.bytes), thumbnailData.mimeType)
?: return Result.failure()

uploadedThumbnailEncryptedFileInfo = encryptionResult.encryptedFileInfo

fileUploader
.uploadByteArray(encryptionResult.encryptedByteArray, "thumb_${attachment.name}", thumbnailData.mimeType)
} else {
fileUploader
.uploadByteArray(thumbnailData.bytes, "thumb_${attachment.name}", thumbnailData.mimeType)
}
.fold(
{ Timber.e(it) },
{ uploadedThumbnailUrl = it.contentUri }
)

}

val progressListener = object : ProgressRequestBody.Listener {
@ -76,12 +97,28 @@ internal class UploadContentWorker(context: Context, params: WorkerParameters) :
contentUploadStateTracker.setProgress(eventId, current, total)
}
}
return fileUploader
.uploadFile(attachmentFile, attachment.name, attachment.mimeType, progressListener)

var uploadedFileEncryptedFileInfo: EncryptedFileInfo? = null

return if (isRoomEncrypted) {
Timber.v("Encrypt file")

val encryptionResult = MXEncryptedAttachments.encryptAttachment(FileInputStream(attachmentFile), attachment.mimeType)
?: return Result.failure()

uploadedFileEncryptedFileInfo = encryptionResult.encryptedFileInfo

fileUploader
.uploadByteArray(encryptionResult.encryptedByteArray, attachment.name, attachment.mimeType, progressListener)
} else {
fileUploader
.uploadFile(attachmentFile, attachment.name, attachment.mimeType, progressListener)
}
.fold(
{ handleFailure(params) },
{ handleSuccess(params, it.contentUri, uploadedThumbnailUrl) }
{ handleSuccess(params, it.contentUri, uploadedFileEncryptedFileInfo, uploadedThumbnailUrl, uploadedThumbnailEncryptedFileInfo) }
)

}

private fun createAttachmentFile(attachment: ContentAttachmentData): File? {
@ -100,39 +137,67 @@ internal class UploadContentWorker(context: Context, params: WorkerParameters) :

private fun handleSuccess(params: Params,
attachmentUrl: String,
thumbnailUrl: String?): Result {
encryptedFileInfo: EncryptedFileInfo?,
thumbnailUrl: String?,
thumbnailEncryptedFileInfo: EncryptedFileInfo?): Result {
contentUploadStateTracker.setSuccess(params.event.eventId!!)
val event = updateEvent(params.event, attachmentUrl, thumbnailUrl)
val event = updateEvent(params.event, attachmentUrl, encryptedFileInfo, thumbnailUrl, thumbnailEncryptedFileInfo)
val sendParams = SendEventWorker.Params(params.userId, params.roomId, event)
return Result.success(WorkerParamsFactory.toData(sendParams))
}

private fun updateEvent(event: Event, url: String, thumbnailUrl: String? = null): Event {
private fun updateEvent(event: Event,
url: String,
encryptedFileInfo: EncryptedFileInfo?,
thumbnailUrl: String? = null,
thumbnailEncryptedFileInfo: EncryptedFileInfo?): Event {
val messageContent: MessageContent = event.content.toModel() ?: return event
val updatedContent = when (messageContent) {
is MessageImageContent -> messageContent.update(url)
is MessageVideoContent -> messageContent.update(url, thumbnailUrl)
is MessageFileContent -> messageContent.update(url)
is MessageAudioContent -> messageContent.update(url)
is MessageImageContent -> messageContent.update(url, encryptedFileInfo)
is MessageVideoContent -> messageContent.update(url, encryptedFileInfo, thumbnailUrl, thumbnailEncryptedFileInfo)
is MessageFileContent -> messageContent.update(url, encryptedFileInfo)
is MessageAudioContent -> messageContent.update(url, encryptedFileInfo)
else -> messageContent
}
return event.copy(content = updatedContent.toContent())
}

private fun MessageImageContent.update(url: String): MessageImageContent {
return copy(url = url)
private fun MessageImageContent.update(url: String,
encryptedFileInfo: EncryptedFileInfo?): MessageImageContent {
return copy(
url = url,
encryptedFileInfo = encryptedFileInfo
)
}

private fun MessageVideoContent.update(url: String, thumbnailUrl: String?): MessageVideoContent {
return copy(url = url, videoInfo = videoInfo?.copy(thumbnailUrl = thumbnailUrl))
private fun MessageVideoContent.update(url: String,
encryptedFileInfo: EncryptedFileInfo?,
thumbnailUrl: String?,
thumbnailEncryptedFileInfo: EncryptedFileInfo?): MessageVideoContent {
return copy(
url = url,
encryptedFileInfo = encryptedFileInfo,
videoInfo = videoInfo?.copy(
thumbnailUrl = thumbnailUrl,
thumbnailFile = thumbnailEncryptedFileInfo
)
)
}

private fun MessageFileContent.update(url: String): MessageFileContent {
return copy(url = url)
private fun MessageFileContent.update(url: String,
encryptedFileInfo: EncryptedFileInfo?): MessageFileContent {
return copy(
url = url,
encryptedFileInfo = encryptedFileInfo
)
}

private fun MessageAudioContent.update(url: String): MessageAudioContent {
return copy(url = url)
private fun MessageAudioContent.update(url: String,
encryptedFileInfo: EncryptedFileInfo?): MessageAudioContent {
return copy(
url = url,
encryptedFileInfo = encryptedFileInfo
)
}

}

View File

@ -101,7 +101,7 @@ internal class DefaultSendService @Inject constructor(private val context: Conte
val event = localEchoEventFactory.createMediaEvent(roomId, attachment).also {
saveLocalEcho(it)
}
val uploadWork = createUploadMediaWork(event, attachment)
val uploadWork = createUploadMediaWork(event, attachment, cryptoService.isRoomEncrypted(roomId))
val sendWork = createSendEventWork(event)

WorkManager.getInstance(context)
@ -148,8 +148,8 @@ internal class DefaultSendService @Inject constructor(private val context: Conte
return TimelineSendEventWorkCommon.createWork<RedactEventWorker>(redactWorkData)
}

private fun createUploadMediaWork(event: Event, attachment: ContentAttachmentData): OneTimeWorkRequest {
val uploadMediaWorkerParams = UploadContentWorker.Params(credentials.userId, roomId, event, attachment)
private fun createUploadMediaWork(event: Event, attachment: ContentAttachmentData, isRoomEncrypted: Boolean): OneTimeWorkRequest {
val uploadMediaWorkerParams = UploadContentWorker.Params(credentials.userId, roomId, event, attachment, isRoomEncrypted)
val uploadWorkData = WorkerParamsFactory.toData(uploadMediaWorkerParams)

return OneTimeWorkRequestBuilder<UploadContentWorker>()