From 4f977ea644a9da7e74a5d7ba0d7f706f40a1515f Mon Sep 17 00:00:00 2001 From: Boris Safonov Date: Thu, 15 Aug 2024 11:58:31 +0300 Subject: [PATCH 1/2] fix: Check file extension instead of mimeType --- .../asset/ScheduleNewAssetMessageUseCase.kt | 2 +- .../asset/ValidateAssetMimeTypeUseCase.kt | 17 +-- .../receiver/asset/AssetMessageHandler.kt | 2 +- .../ScheduleNewAssetMessageUseCaseTest.kt | 6 +- .../receiver/asset/AssetMessageHandlerTest.kt | 117 ++++++++++++++++++ 5 files changed, 132 insertions(+), 12 deletions(-) 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 06532a015c5..a6c0df5dc5d 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 @@ -133,7 +133,7 @@ internal class ScheduleNewAssetMessageUseCaseImpl( FileSharingStatus.Value.EnabledAll -> { /* no-op*/ } - is FileSharingStatus.Value.EnabledSome -> if (!validateAssetMimeTypeUseCase(assetMimeType, it.state.allowedType)) { + is FileSharingStatus.Value.EnabledSome -> if (!validateAssetMimeTypeUseCase(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/ValidateAssetMimeTypeUseCase.kt b/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/asset/ValidateAssetMimeTypeUseCase.kt index c8a4ab19c4b..3d9f3c8de26 100644 --- 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 @@ -18,19 +18,22 @@ 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. + * 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 ValidateAssetMimeTypeUseCase { - operator fun invoke(mimeType: String, allowedExtension: List): Boolean + operator fun invoke(fileName: 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 + override operator fun invoke(fileName: String, allowedExtension: List): Boolean { + val split = fileName.split(".") + return if (split.size < 2) { + false + } else { + val extension = split.last().lowercase() + allowedExtension.any { it.lowercase() == extension } } } } 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 a5fd1737a2f..5b4ae8c6a76 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 @@ -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 fec3e956ca7..1eaf724fcd2 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,7 +628,7 @@ class ScheduleNewAssetMessageUseCaseTest { verify(arrangement.validateAssetMimeTypeUseCase) .function(arrangement.validateAssetMimeTypeUseCase::invoke) - .with(eq("text/plain"), eq(listOf("png"))) + .with(eq("some-asset.txt"), eq(listOf("png"))) .wasInvoked(exactly = once) } @@ -636,7 +636,7 @@ class ScheduleNewAssetMessageUseCaseTest { 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()) @@ -669,7 +669,7 @@ class ScheduleNewAssetMessageUseCaseTest { verify(arrangement.validateAssetMimeTypeUseCase) .function(arrangement.validateAssetMimeTypeUseCase::invoke) - .with(eq("image/png"), eq(listOf("png"))) + .with(eq("some-asset.png"), eq(listOf("png"))) .wasInvoked(exactly = once) } 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 52eb32f8075..c4b30bee205 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 @@ -254,6 +254,123 @@ 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()) + verify(arrangement.persistMessage) + .suspendFunction(arrangement.persistMessage::invoke) + .with(matching { + it.id == updateAssetMessage.id + && it.conversationId.toString() == updateAssetMessage.conversationId.toString() + && it.visibility == Message.Visibility.VISIBLE + }) + .wasInvoked(exactly = once) + + verify(arrangement.messageRepository) + .suspendFunction(arrangement.messageRepository::getMessageById) + .with(eq(previewAssetMessage.conversationId), eq(previewAssetMessage.id)) + .wasInvoked(exactly = once) + + verify(arrangement.validateAssetMimeType) + .suspendFunction(arrangement.validateAssetMimeType::invoke) + .with(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()) + verify(arrangement.persistMessage) + .suspendFunction(arrangement.persistMessage::invoke) + .with(matching { + it.id == updateAssetMessage.id + && it.conversationId.toString() == updateAssetMessage.conversationId.toString() + && it.visibility == updateAssetMessage.visibility + }) + .wasInvoked(exactly = once) + + verify(arrangement.messageRepository) + .suspendFunction(arrangement.messageRepository::getMessageById) + .with(eq(previewAssetMessage.conversationId), eq(previewAssetMessage.id)) + .wasInvoked(exactly = once) + + verify(arrangement.validateAssetMimeType) + .suspendFunction(arrangement.validateAssetMimeType::invoke) + .with(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()) + verify(arrangement.persistMessage) + .suspendFunction(arrangement.persistMessage::invoke) + .with(matching { + it.id == updateAssetMessage.id + && it.conversationId.toString() == updateAssetMessage.conversationId.toString() + && it.visibility == updateAssetMessage.visibility + }) + .wasInvoked(exactly = once) + + verify(arrangement.messageRepository) + .suspendFunction(arrangement.messageRepository::getMessageById) + .with(eq(previewAssetMessage.conversationId), eq(previewAssetMessage.id)) + .wasNotInvoked() + + verify(arrangement.validateAssetMimeType) + .suspendFunction(arrangement.validateAssetMimeType::invoke) + .with(any(), any>()) + .wasNotInvoked() + } + private class Arrangement { @Mock From 5774d19a32ab6a53435da4b693acd6fd5560519a Mon Sep 17 00:00:00 2001 From: Boris Safonov Date: Thu, 15 Aug 2024 15:11:38 +0300 Subject: [PATCH 2/2] Review updates --- .../kalium/logic/feature/UserSessionScope.kt | 6 +- .../asset/ScheduleNewAssetMessageUseCase.kt | 4 +- ...ase.kt => ValidateAssetFileTypeUseCase.kt} | 15 ++-- .../logic/feature/message/MessageScope.kt | 8 +- .../receiver/asset/AssetMessageHandler.kt | 6 +- .../ScheduleNewAssetMessageUseCaseTest.kt | 2 +- .../asset/ValidateAssetFileTypeUseCaseTest.kt | 87 +++++++++++++++++++ .../receiver/asset/AssetMessageHandlerTest.kt | 5 +- 8 files changed, 111 insertions(+), 22 deletions(-) rename logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/asset/{ValidateAssetMimeTypeUseCase.kt => ValidateAssetFileTypeUseCase.kt} (64%) 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 b3ecde01d32..7527415262b 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 @@ -153,8 +153,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 @@ -1796,7 +1796,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 a6c0df5dc5d..a81023e202d 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 @@ -110,7 +110,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.EnabledAll -> { /* no-op*/ } - is FileSharingStatus.Value.EnabledSome -> if (!validateAssetMimeTypeUseCase(assetName, 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/ValidateAssetMimeTypeUseCase.kt b/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/asset/ValidateAssetFileTypeUseCase.kt similarity index 64% rename from logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/asset/ValidateAssetMimeTypeUseCase.kt rename to logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/asset/ValidateAssetFileTypeUseCase.kt index 3d9f3c8de26..6a15510cdc5 100644 --- a/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/asset/ValidateAssetMimeTypeUseCase.kt +++ b/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/asset/ValidateAssetFileTypeUseCase.kt @@ -22,18 +22,21 @@ package com.wire.kalium.logic.feature.asset * @param fileName the file name (with extension) to validate. * @param allowedExtension the list of allowed extension. */ -interface ValidateAssetMimeTypeUseCase { - operator fun invoke(fileName: String, allowedExtension: List): Boolean +interface ValidateAssetFileTypeUseCase { + operator fun invoke(fileName: String?, allowedExtension: List): Boolean } -internal class ValidateAssetMimeTypeUseCaseImpl : ValidateAssetMimeTypeUseCase { - override 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 extension = split.last().lowercase() - allowedExtension.any { it.lowercase() == extension } + 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/message/MessageScope.kt b/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/message/MessageScope.kt index 8f36dfbe885..0895c992136 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 @@ -56,8 +56,8 @@ import com.wire.kalium.logic.feature.asset.UpdateAssetMessageDownloadStatusUseCa import com.wire.kalium.logic.feature.asset.UpdateAssetMessageDownloadStatusUseCaseImpl import com.wire.kalium.logic.feature.asset.UpdateAssetMessageUploadStatusUseCase import com.wire.kalium.logic.feature.asset.UpdateAssetMessageUploadStatusUseCaseImpl -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.message.composite.SendButtonActionMessageUseCase import com.wire.kalium.logic.feature.message.ephemeral.DeleteEphemeralMessageForSelfUserAsReceiverUseCaseImpl import com.wire.kalium.logic.feature.message.ephemeral.DeleteEphemeralMessageForSelfUserAsSenderUseCaseImpl @@ -144,8 +144,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 5b4ae8c6a76..f76d5004c07 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 @@ -24,7 +24,7 @@ import com.wire.kalium.logic.data.message.Message 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.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.name ?: "", + 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 1eaf724fcd2..9c98a282d70 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 @@ -706,7 +706,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 c4b30bee205..ee0d2d9c1f4 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 @@ -29,7 +29,7 @@ import com.wire.kalium.logic.data.message.MessageEncryptionAlgorithm import com.wire.kalium.logic.data.message.MessageRepository import com.wire.kalium.logic.data.message.PersistMessageUseCase 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.logic.sync.receiver.conversation.message.hasValidData import com.wire.kalium.logic.sync.receiver.conversation.message.hasValidRemoteData @@ -44,7 +44,6 @@ import io.mockative.once import io.mockative.verify import junit.framework.TestCase.assertFalse import junit.framework.TestCase.assertTrue -import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.test.runTest import org.junit.Test @@ -383,7 +382,7 @@ class AssetMessageHandlerTest { val userConfigRepository = mock(classOf()) @Mock - val validateAssetMimeType = mock(classOf()) + val validateAssetMimeType = mock(classOf()) private val assetMessageHandlerImpl = AssetMessageHandlerImpl(messageRepository, persistMessage, userConfigRepository, validateAssetMimeType)