From 49582cdd364cf1c5a30dffc5ef4361bcd109694e Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 20 Aug 2024 14:48:34 +0000 Subject: [PATCH] =?UTF-8?q?fix:=20Check=20file=20extension=20instead=20of?= =?UTF-8?q?=20mimeType=20[WPB-10605]=20=F0=9F=8D=92=20(#2954)=20(#2956)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Commit with unresolved merge conflicts * Fixed cherry-pick issues --------- Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: boris Co-authored-by: Boris Safonov Co-authored-by: Mohamad Jaara --- .../kalium/logic/feature/UserSessionScope.kt | 6 +- .../asset/ScheduleNewAssetMessageUseCase.kt | 4 +- .../asset/ValidateAssetFileTypeUseCase.kt | 42 +++++++ .../asset/ValidateAssetMimeTypeUseCase.kt | 36 ------ .../logic/feature/message/MessageScope.kt | 8 +- .../receiver/asset/AssetMessageHandler.kt | 6 +- .../ScheduleNewAssetMessageUseCaseTest.kt | 14 +-- .../asset/ValidateAssetFileTypeUseCaseTest.kt | 87 ++++++++++++++ .../receiver/asset/AssetMessageHandlerTest.kt | 107 +++++++++++++++++- 9 files changed, 252 insertions(+), 58 deletions(-) create mode 100644 logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/asset/ValidateAssetFileTypeUseCase.kt delete mode 100644 logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/asset/ValidateAssetMimeTypeUseCase.kt create mode 100644 logic/src/commonTest/kotlin/com/wire/kalium/logic/feature/asset/ValidateAssetFileTypeUseCaseTest.kt diff --git a/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/UserSessionScope.kt b/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/UserSessionScope.kt index 7bd5221bc55..0ed22a8dd67 100644 --- a/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/UserSessionScope.kt +++ b/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/UserSessionScope.kt @@ -159,8 +159,8 @@ import com.wire.kalium.logic.feature.applock.AppLockTeamFeatureConfigObserver import com.wire.kalium.logic.feature.applock.AppLockTeamFeatureConfigObserverImpl import com.wire.kalium.logic.feature.applock.MarkTeamAppLockStatusAsNotifiedUseCase import com.wire.kalium.logic.feature.applock.MarkTeamAppLockStatusAsNotifiedUseCaseImpl -import com.wire.kalium.logic.feature.asset.ValidateAssetMimeTypeUseCase -import com.wire.kalium.logic.feature.asset.ValidateAssetMimeTypeUseCaseImpl +import com.wire.kalium.logic.feature.asset.ValidateAssetFileTypeUseCase +import com.wire.kalium.logic.feature.asset.ValidateAssetFileTypeUseCaseImpl import com.wire.kalium.logic.feature.auth.AuthenticationScope import com.wire.kalium.logic.feature.auth.AuthenticationScopeProvider import com.wire.kalium.logic.feature.auth.ClearUserDataUseCase @@ -1872,7 +1872,7 @@ class UserSessionScope internal constructor( private val clearUserData: ClearUserDataUseCase get() = ClearUserDataUseCaseImpl(userStorage) - private val validateAssetMimeType: ValidateAssetMimeTypeUseCase get() = ValidateAssetMimeTypeUseCaseImpl() + private val validateAssetMimeType: ValidateAssetFileTypeUseCase get() = ValidateAssetFileTypeUseCaseImpl() val logout: LogoutUseCase get() = LogoutUseCaseImpl( diff --git a/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/asset/ScheduleNewAssetMessageUseCase.kt b/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/asset/ScheduleNewAssetMessageUseCase.kt index c6b2a1ff0df..00a9df1a336 100644 --- a/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/asset/ScheduleNewAssetMessageUseCase.kt +++ b/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/asset/ScheduleNewAssetMessageUseCase.kt @@ -111,7 +111,7 @@ internal class ScheduleNewAssetMessageUseCaseImpl( private val selfDeleteTimer: ObserveSelfDeletionTimerSettingsForConversationUseCase, private val scope: CoroutineScope, private val observeFileSharingStatus: ObserveFileSharingStatusUseCase, - private val validateAssetMimeTypeUseCase: ValidateAssetMimeTypeUseCase, + private val validateAssetFileUseCase: ValidateAssetFileTypeUseCase, private val dispatcher: KaliumDispatcher, ) : ScheduleNewAssetMessageUseCase { @@ -133,7 +133,7 @@ internal class ScheduleNewAssetMessageUseCaseImpl( FileSharingStatus.Value.Disabled -> return ScheduleNewAssetMessageResult.Failure.DisabledByTeam FileSharingStatus.Value.EnabledAll -> { /* no-op*/ } - is FileSharingStatus.Value.EnabledSome -> if (!validateAssetMimeTypeUseCase(assetMimeType, it.state.allowedType)) { + is FileSharingStatus.Value.EnabledSome -> if (!validateAssetFileUseCase(assetName, it.state.allowedType)) { kaliumLogger.e("The asset message trying to be processed has invalid content data") return ScheduleNewAssetMessageResult.Failure.RestrictedFileType } diff --git a/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/asset/ValidateAssetFileTypeUseCase.kt b/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/asset/ValidateAssetFileTypeUseCase.kt new file mode 100644 index 00000000000..6a15510cdc5 --- /dev/null +++ b/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/asset/ValidateAssetFileTypeUseCase.kt @@ -0,0 +1,42 @@ +/* + * Wire + * Copyright (C) 2024 Wire Swiss GmbH + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://www.gnu.org/licenses/. + */ +package com.wire.kalium.logic.feature.asset + +/** + * Returns true if the file extension is present in file name and is allowed and false otherwise. + * @param fileName the file name (with extension) to validate. + * @param allowedExtension the list of allowed extension. + */ +interface ValidateAssetFileTypeUseCase { + operator fun invoke(fileName: String?, allowedExtension: List): Boolean +} + +internal class ValidateAssetFileTypeUseCaseImpl : ValidateAssetFileTypeUseCase { + override operator fun invoke(fileName: String?, allowedExtension: List): Boolean { + if (fileName == null) return false + + val split = fileName.split(".") + return if (split.size < 2) { + false + } else { + val allowedExtensionLowerCase = allowedExtension.map { it.lowercase() } + val extensions = split.subList(1, split.size).map { it.lowercase() } + extensions.all { it.isNotEmpty() && allowedExtensionLowerCase.contains(it) } + } + } +} diff --git a/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/asset/ValidateAssetMimeTypeUseCase.kt b/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/asset/ValidateAssetMimeTypeUseCase.kt deleted file mode 100644 index c8a4ab19c4b..00000000000 --- a/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/asset/ValidateAssetMimeTypeUseCase.kt +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Wire - * Copyright (C) 2024 Wire Swiss GmbH - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see http://www.gnu.org/licenses/. - */ -package com.wire.kalium.logic.feature.asset - -/** - * Returns true if the mime type is allowed and false otherwise. - * @param mimeType the mime type to validate. - * @param allowedExtension the list of allowed extension. - */ -interface ValidateAssetMimeTypeUseCase { - operator fun invoke(mimeType: String, allowedExtension: List): Boolean -} - -internal class ValidateAssetMimeTypeUseCaseImpl : ValidateAssetMimeTypeUseCase { - override operator fun invoke(mimeType: String, allowedExtension: List): Boolean { - val extension = mimeType.split("/").last().lowercase() - return allowedExtension.any { - it.lowercase() == extension - } - } -} diff --git a/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/message/MessageScope.kt b/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/message/MessageScope.kt index eadc29abf6f..4a84d066090 100644 --- a/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/message/MessageScope.kt +++ b/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/message/MessageScope.kt @@ -60,9 +60,9 @@ import com.wire.kalium.logic.feature.asset.ScheduleNewAssetMessageUseCase import com.wire.kalium.logic.feature.asset.ScheduleNewAssetMessageUseCaseImpl import com.wire.kalium.logic.feature.asset.UpdateAssetMessageTransferStatusUseCase import com.wire.kalium.logic.feature.asset.UpdateAssetMessageTransferStatusUseCaseImpl +import com.wire.kalium.logic.feature.asset.ValidateAssetFileTypeUseCase +import com.wire.kalium.logic.feature.asset.ValidateAssetFileTypeUseCaseImpl import com.wire.kalium.logic.feature.message.composite.SendButtonActionConfirmationMessageUseCase -import com.wire.kalium.logic.feature.asset.ValidateAssetMimeTypeUseCase -import com.wire.kalium.logic.feature.asset.ValidateAssetMimeTypeUseCaseImpl import com.wire.kalium.logic.feature.message.composite.SendButtonActionMessageUseCase import com.wire.kalium.logic.feature.message.composite.SendButtonMessageUseCase import com.wire.kalium.logic.feature.message.confirmation.ConfirmationDeliveryHandler @@ -160,8 +160,8 @@ class MessageScope internal constructor( protoContentMapper = protoContentMapper ) - private val validateAssetMimeTypeUseCase: ValidateAssetMimeTypeUseCase - get() = ValidateAssetMimeTypeUseCaseImpl() + private val validateAssetMimeTypeUseCase: ValidateAssetFileTypeUseCase + get() = ValidateAssetFileTypeUseCaseImpl() private val messageContentEncoder = MessageContentEncoder() private val messageSendingInterceptor: MessageSendingInterceptor diff --git a/logic/src/commonMain/kotlin/com/wire/kalium/logic/sync/receiver/asset/AssetMessageHandler.kt b/logic/src/commonMain/kotlin/com/wire/kalium/logic/sync/receiver/asset/AssetMessageHandler.kt index 57ac934a25b..9a71c5e2d13 100644 --- a/logic/src/commonMain/kotlin/com/wire/kalium/logic/sync/receiver/asset/AssetMessageHandler.kt +++ b/logic/src/commonMain/kotlin/com/wire/kalium/logic/sync/receiver/asset/AssetMessageHandler.kt @@ -25,7 +25,7 @@ import com.wire.kalium.logic.data.message.MessageContent import com.wire.kalium.logic.data.message.MessageRepository import com.wire.kalium.logic.data.message.PersistMessageUseCase import com.wire.kalium.logic.data.message.hasValidData -import com.wire.kalium.logic.feature.asset.ValidateAssetMimeTypeUseCase +import com.wire.kalium.logic.feature.asset.ValidateAssetFileTypeUseCase import com.wire.kalium.logic.functional.onFailure import com.wire.kalium.logic.functional.onSuccess import com.wire.kalium.logic.kaliumLogger @@ -38,7 +38,7 @@ internal class AssetMessageHandlerImpl( private val messageRepository: MessageRepository, private val persistMessage: PersistMessageUseCase, private val userConfigRepository: UserConfigRepository, - private val validateAssetMimeTypeUseCase: ValidateAssetMimeTypeUseCase + private val validateAssetMimeTypeUseCase: ValidateAssetFileTypeUseCase ) : AssetMessageHandler { override suspend fun handle(message: Message.Regular) { @@ -53,7 +53,7 @@ internal class AssetMessageHandlerImpl( FileSharingStatus.Value.EnabledAll -> true is FileSharingStatus.Value.EnabledSome -> validateAssetMimeTypeUseCase( - messageContent.value.mimeType, + messageContent.value.name, it.state.allowedType ) } diff --git a/logic/src/commonTest/kotlin/com/wire/kalium/logic/feature/asset/ScheduleNewAssetMessageUseCaseTest.kt b/logic/src/commonTest/kotlin/com/wire/kalium/logic/feature/asset/ScheduleNewAssetMessageUseCaseTest.kt index 94ad32bd51c..7ba8fa79b65 100644 --- a/logic/src/commonTest/kotlin/com/wire/kalium/logic/feature/asset/ScheduleNewAssetMessageUseCaseTest.kt +++ b/logic/src/commonTest/kotlin/com/wire/kalium/logic/feature/asset/ScheduleNewAssetMessageUseCaseTest.kt @@ -628,16 +628,15 @@ class ScheduleNewAssetMessageUseCaseTest { // Then assertTrue(result is ScheduleNewAssetMessageResult.Failure.RestrictedFileType) - verify { - arrangement.validateAssetMimeTypeUseCase(eq("text/plain"), eq(listOf("png"))) - }.wasInvoked(exactly = once) + coVerify { arrangement.validateAssetMimeTypeUseCase(eq("some-asset.txt"), eq(listOf("png"))) } + .wasInvoked(exactly = once) } @Test fun givenAssetMimeTypeRestrictedAndFileAllowed_whenSending_thenReturnSendTheFile() = runTest(testDispatcher.default) { // Given val assetToSend = mockedLongAssetData() - val assetName = "some-asset.txt" + val assetName = "some-asset.png" val inputDataPath = fakeKaliumFileSystem.providePersistentAssetPath(assetName) val expectedAssetId = dummyUploadedAssetId val expectedAssetSha256 = SHA256Key("some-asset-sha-256".toByteArray()) @@ -668,9 +667,8 @@ class ScheduleNewAssetMessageUseCaseTest { // Then assertTrue(result is ScheduleNewAssetMessageResult.Success) - verify { - arrangement.validateAssetMimeTypeUseCase(eq("image/png"), eq(listOf("png"))) - }.wasInvoked(exactly = once) + coVerify { arrangement.validateAssetMimeTypeUseCase(eq("some-asset.png"), eq(listOf("png"))) } + .wasInvoked(exactly = once) } private class Arrangement(val coroutineScope: CoroutineScope) { @@ -706,7 +704,7 @@ class ScheduleNewAssetMessageUseCaseTest { private val messageRepository: MessageRepository = mock(MessageRepository::class) @Mock - val validateAssetMimeTypeUseCase: ValidateAssetMimeTypeUseCase = mock(ValidateAssetMimeTypeUseCase::class) + val validateAssetMimeTypeUseCase: ValidateAssetFileTypeUseCase = mock(ValidateAssetFileTypeUseCase::class) @Mock val observerFileSharingStatusUseCase: ObserveFileSharingStatusUseCase = mock(ObserveFileSharingStatusUseCase::class) diff --git a/logic/src/commonTest/kotlin/com/wire/kalium/logic/feature/asset/ValidateAssetFileTypeUseCaseTest.kt b/logic/src/commonTest/kotlin/com/wire/kalium/logic/feature/asset/ValidateAssetFileTypeUseCaseTest.kt new file mode 100644 index 00000000000..613f57bafe0 --- /dev/null +++ b/logic/src/commonTest/kotlin/com/wire/kalium/logic/feature/asset/ValidateAssetFileTypeUseCaseTest.kt @@ -0,0 +1,87 @@ +/* + * Wire + * Copyright (C) 2024 Wire Swiss GmbH + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://www.gnu.org/licenses/. + */ +package com.wire.kalium.logic.feature.asset + +import kotlinx.coroutines.test.runTest +import kotlin.test.Test +import kotlin.test.assertFalse +import kotlin.test.assertTrue + +class ValidateAssetFileTypeUseCaseTest { + + @Test + fun givenRegularFileNameWithAllowedExtension_whenInvoke_thenBeApproved() = runTest { + val (_, validate) = arrange {} + + val result = validate("name.txt", listOf("txt", "jpg")) + + assertTrue(result) + } + + @Test + fun givenRegularFileNameWithNOTAllowedExtension_whenInvoke_thenBeRestricted() = runTest { + val (_, validate) = arrange {} + + val result = validate("name.php", listOf("txt", "jpg")) + + assertFalse(result) + } + + @Test + fun givenRegularFileNameWithoutExtension_whenInvoke_thenBeRestricted() = runTest { + val (_, validate) = arrange {} + + val result = validate("name", listOf("txt", "jpg")) + + assertFalse(result) + } + + @Test + fun givenNullFileName_whenInvoke_thenBeRestricted() = runTest { + val (_, validate) = arrange {} + + val result = validate(null, listOf("txt", "jpg")) + + assertFalse(result) + } + + @Test + fun givenRegularFileNameWithFewExtensions_whenInvoke_thenEachExtensionIsChecked() = runTest { + val (_, validate) = arrange {} + + val result1 = validate("name.php.txt", listOf("txt", "jpg")) + val result2 = validate("name.txt.php", listOf("txt", "jpg")) + val result3 = validate("name..txt.jpg", listOf("txt", "jpg")) + val result4 = validate("name.txt.php.txt.jpg", listOf("txt", "jpg")) + + assertFalse(result1) + assertFalse(result2) + assertFalse(result3) + assertFalse(result4) + } + + private fun arrange(block: Arrangement.() -> Unit) = Arrangement(block).arrange() + + private class Arrangement( + private val block: Arrangement.() -> Unit + ) { + fun arrange() = block().run { + this@Arrangement to ValidateAssetFileTypeUseCaseImpl() + } + } +} diff --git a/logic/src/jvmTest/kotlin/com/wire/kalium/logic/sync/receiver/asset/AssetMessageHandlerTest.kt b/logic/src/jvmTest/kotlin/com/wire/kalium/logic/sync/receiver/asset/AssetMessageHandlerTest.kt index e68281d90de..358d3cdb2a5 100644 --- a/logic/src/jvmTest/kotlin/com/wire/kalium/logic/sync/receiver/asset/AssetMessageHandlerTest.kt +++ b/logic/src/jvmTest/kotlin/com/wire/kalium/logic/sync/receiver/asset/AssetMessageHandlerTest.kt @@ -31,7 +31,7 @@ import com.wire.kalium.logic.data.message.PersistMessageUseCase import com.wire.kalium.logic.data.message.hasValidData import com.wire.kalium.logic.data.message.hasValidRemoteData import com.wire.kalium.logic.data.user.UserId -import com.wire.kalium.logic.feature.asset.ValidateAssetMimeTypeUseCase +import com.wire.kalium.logic.feature.asset.ValidateAssetFileTypeUseCase import com.wire.kalium.logic.functional.Either import com.wire.kalium.util.time.UNIX_FIRST_DATE import io.mockative.Mock @@ -243,6 +243,109 @@ class AssetMessageHandlerTest { }.wasInvoked(exactly = once) } + @Test + fun givenValidPreviewAssetMessageStoredAndExtensionIsAllowed_whenHandlingTheUpdate_itIsCorrectlyProcessedAndVisible() = runTest { + // Given + val previewAssetMessage = PREVIEW_ASSET_MESSAGE.copy(visibility = Message.Visibility.HIDDEN) + val updateAssetMessage = COMPLETE_ASSET_MESSAGE + val isFileSharingEnabled = FileSharingStatus.Value.EnabledSome(listOf("txt", "png", "zip")) + val (arrangement, assetMessageHandler) = Arrangement() + .withSuccessfulFileSharingFlag(isFileSharingEnabled) + .withValidateAssetMime(true) + .withSuccessfulStoredMessage(previewAssetMessage) + .withSuccessfulPersistMessageUseCase(updateAssetMessage) + .arrange() + + // When + assetMessageHandler.handle(updateAssetMessage) + + // Then + assertFalse((previewAssetMessage.content as MessageContent.Asset).value.hasValidRemoteData()) + assertTrue((updateAssetMessage.content as MessageContent.Asset).value.remoteData.hasValidData()) + coVerify { + arrangement.persistMessage( + matches { + it.id == updateAssetMessage.id + && it.conversationId.toString() == updateAssetMessage.conversationId.toString() + && it.visibility == Message.Visibility.VISIBLE + }) + }.wasInvoked(exactly = once) + + coVerify { arrangement.messageRepository.getMessageById(eq(previewAssetMessage.conversationId), eq(previewAssetMessage.id)) } + .wasInvoked(exactly = once) + + coVerify { arrangement.validateAssetMimeType(eq(COMPLETE_ASSET_CONTENT.value.name), eq(isFileSharingEnabled.allowedType)) } + .wasInvoked(exactly = once) + } + + @Test + fun givenValidPreviewAssetMessageStoredAndExtensionIsNotAllowed_whenHandlingTheUpdate_itIsProcessedButNoVisible() = runTest { + // Given + val previewAssetMessage = PREVIEW_ASSET_MESSAGE.copy(visibility = Message.Visibility.HIDDEN) + val updateAssetMessage = COMPLETE_ASSET_MESSAGE + val isFileSharingEnabled = FileSharingStatus.Value.EnabledSome(listOf("txt", "png")) + val (arrangement, assetMessageHandler) = Arrangement() + .withSuccessfulFileSharingFlag(isFileSharingEnabled) + .withValidateAssetMime(true) + .withSuccessfulStoredMessage(previewAssetMessage) + .withSuccessfulPersistMessageUseCase(updateAssetMessage) + .arrange() + + // When + assetMessageHandler.handle(updateAssetMessage) + + // Then + assertFalse((previewAssetMessage.content as MessageContent.Asset).value.hasValidRemoteData()) + assertTrue((updateAssetMessage.content as MessageContent.Asset).value.remoteData.hasValidData()) + coVerify { + arrangement.persistMessage(matches { + it.id == updateAssetMessage.id + && it.conversationId.toString() == updateAssetMessage.conversationId.toString() + && it.visibility == updateAssetMessage.visibility + }) + }.wasInvoked(exactly = once) + + coVerify { arrangement.messageRepository.getMessageById(eq(previewAssetMessage.conversationId), eq(previewAssetMessage.id)) } + .wasInvoked(exactly = once) + + coVerify { arrangement.validateAssetMimeType(eq(COMPLETE_ASSET_CONTENT.value.name), eq(isFileSharingEnabled.allowedType)) } + .wasInvoked(exactly = once) + } + + @Test + fun givenValidPreviewAssetMessageStoredButFileSharingRestricted_whenHandlingTheUpdate_itIsProcessedButNoVisible() = runTest { + // Given + val previewAssetMessage = PREVIEW_ASSET_MESSAGE.copy(visibility = Message.Visibility.HIDDEN) + val updateAssetMessage = COMPLETE_ASSET_MESSAGE + val isFileSharingEnabled = FileSharingStatus.Value.Disabled + val (arrangement, assetMessageHandler) = Arrangement() + .withSuccessfulFileSharingFlag(isFileSharingEnabled) + .withValidateAssetMime(true) + .withSuccessfulStoredMessage(previewAssetMessage) + .withSuccessfulPersistMessageUseCase(updateAssetMessage) + .arrange() + + // When + assetMessageHandler.handle(updateAssetMessage) + + // Then + assertFalse((previewAssetMessage.content as MessageContent.Asset).value.hasValidRemoteData()) + assertTrue((updateAssetMessage.content as MessageContent.Asset).value.remoteData.hasValidData()) + coVerify { + arrangement.persistMessage(matches { + it.id == updateAssetMessage.id + && it.conversationId.toString() == updateAssetMessage.conversationId.toString() + && it.visibility == updateAssetMessage.visibility + }) + }.wasInvoked(exactly = once) + + coVerify { arrangement.messageRepository.getMessageById(eq(previewAssetMessage.conversationId), eq(previewAssetMessage.id)) } + .wasNotInvoked() + + coVerify { arrangement.validateAssetMimeType(any(), any>()) } + .wasNotInvoked() + } + private class Arrangement { @Mock @@ -255,7 +358,7 @@ class AssetMessageHandlerTest { val userConfigRepository = mock(UserConfigRepository::class) @Mock - val validateAssetMimeType = mock(ValidateAssetMimeTypeUseCase::class) + val validateAssetMimeType = mock(ValidateAssetFileTypeUseCase::class) private val assetMessageHandlerImpl = AssetMessageHandlerImpl(messageRepository, persistMessage, userConfigRepository, validateAssetMimeType)