diff --git a/logic/src/appleMain/kotlin/com/wire/kalium/logic/util/BackupUtils.kt b/logic/src/appleMain/kotlin/com/wire/kalium/logic/util/BackupUtils.kt index ec434fc07fd..d104218c7f6 100644 --- a/logic/src/appleMain/kotlin/com/wire/kalium/logic/util/BackupUtils.kt +++ b/logic/src/appleMain/kotlin/com/wire/kalium/logic/util/BackupUtils.kt @@ -22,14 +22,19 @@ import com.wire.kalium.logic.CoreFailure import com.wire.kalium.logic.data.asset.KaliumFileSystem import com.wire.kalium.logic.functional.Either import okio.BufferedSource -import okio.Source -import okio.Sink import okio.Path +import okio.Sink +import okio.Source actual fun createCompressedFile(files: List>, outputSink: Sink): Either = TODO("Implement own iOS compression method") -actual fun extractCompressedFile(inputSource: Source, outputRootPath: Path, fileSystem: KaliumFileSystem): Either = +actual fun extractCompressedFile( + inputSource: Source, + outputRootPath: Path, + param: ExtractFilesParam, + fileSystem: KaliumFileSystem +): Either = TODO("Implement own iOS compression method") actual fun checkIfCompressedFileContainsFileTypes( diff --git a/logic/src/commonJvmAndroid/kotlin/com/wire/kalium/logic/util/BackupUtils.kt b/logic/src/commonJvmAndroid/kotlin/com/wire/kalium/logic/util/BackupUtils.kt index 105c3332043..3e68c8eb988 100644 --- a/logic/src/commonJvmAndroid/kotlin/com/wire/kalium/logic/util/BackupUtils.kt +++ b/logic/src/commonJvmAndroid/kotlin/com/wire/kalium/logic/util/BackupUtils.kt @@ -68,15 +68,22 @@ private fun addToCompressedFile(zipOutputStream: ZipOutputStream, fileSource: So } @Suppress("TooGenericExceptionCaught", "NestedBlockDepth") -actual fun extractCompressedFile(inputSource: Source, outputRootPath: Path, fileSystem: KaliumFileSystem): Either = try { +actual fun extractCompressedFile( + inputSource: Source, + outputRootPath: Path, + param: ExtractFilesParam, + fileSystem: KaliumFileSystem +): Either = try { var totalExtractedFilesSize = 0L ZipInputStream(inputSource.buffer().inputStream()).use { zipInputStream -> var entry: ZipEntry? = zipInputStream.nextEntry while (entry != null) { - readCompressedEntry(zipInputStream, outputRootPath, fileSystem, entry).let { - totalExtractedFilesSize += it.first - entry = it.second + totalExtractedFilesSize += when (param) { + is ExtractFilesParam.All -> readCompressedEntry(zipInputStream, outputRootPath, fileSystem, entry) + is ExtractFilesParam.Only -> readAndExtractIfMatch(zipInputStream, outputRootPath, fileSystem, entry, param.files) } + zipInputStream.closeEntry() + entry = zipInputStream.nextEntry } } Either.Right(totalExtractedFilesSize) @@ -84,6 +91,22 @@ actual fun extractCompressedFile(inputSource: Source, outputRootPath: Path, file Either.Left(StorageFailure.Generic(RuntimeException("There was an error trying to extract the provided compressed file", e))) } +private fun readAndExtractIfMatch( + zipInputStream: ZipInputStream, + outputRootPath: Path, + fileSystem: KaliumFileSystem, + entry: ZipEntry, + fileNames: Set +): Long { + return entry.name.let { + if (fileNames.contains(it)) { + readCompressedEntry(zipInputStream, outputRootPath, fileSystem, entry) + } else { + 0L + } + } +} + @Suppress("TooGenericExceptionCaught", "NestedBlockDepth") actual fun checkIfCompressedFileContainsFileTypes( compressedFilePath: Path, @@ -121,11 +144,7 @@ private fun readCompressedEntry( outputRootPath: Path, fileSystem: KaliumFileSystem, entry: ZipEntry -): Pair { - if (isInvalidEntryPathDestination(entry.name)) { - throw RuntimeException("The provided zip file is invalid or has invalid data") - } - +): Long { var totalExtractedFilesSize = 0L var byteCount: Int val entryPathName = "$outputRootPath/${entry.name}" @@ -137,8 +156,7 @@ private fun readCompressedEntry( } output.write(zipInputStream.readBytes()) } - zipInputStream.closeEntry() - return totalExtractedFilesSize to zipInputStream.nextEntry + return totalExtractedFilesSize } /** diff --git a/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/backup/BackupConstants.kt b/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/backup/BackupConstants.kt index 17c270cb3bf..cae737ef79f 100644 --- a/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/backup/BackupConstants.kt +++ b/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/backup/BackupConstants.kt @@ -21,6 +21,9 @@ package com.wire.kalium.logic.feature.backup object BackupConstants { const val BACKUP_FILE_NAME_PREFIX = "WBX" const val BACKUP_ENCRYPTED_FILE_NAME = "user-backup.cc20" + + // BACKUP_METADATA_FILE_NAME and BACKUP_USER_DB_NAME must not be changed + // if there is a need to change them, please create a new file names and add it to the list of acceptedFileNames() const val BACKUP_USER_DB_NAME = "user-backup-database.db" const val BACKUP_METADATA_FILE_NAME = "export.json" const val BACKUP_ENCRYPTED_EXTENSION = "cc20" @@ -30,6 +33,15 @@ object BackupConstants { const val BACKUP_WEB_EVENTS_FILE_NAME = "events.json" const val BACKUP_WEB_CONVERSATIONS_FILE_NAME = "conversations.json" + /** + * list of accepted file names for the backup file + * this is used when extracting data from the zip file + */ + fun acceptedFileNames() = setOf( + BACKUP_USER_DB_NAME, + BACKUP_METADATA_FILE_NAME + ) + fun createBackupFileName(userHandle: String?, timestampIso: String) = // file names cannot have special characters "$BACKUP_FILE_NAME_PREFIX-$userHandle-${timestampIso.replace(":", "-")}.zip" diff --git a/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/backup/RestoreBackupUseCase.kt b/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/backup/RestoreBackupUseCase.kt index 08899493709..f3d3f978766 100644 --- a/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/backup/RestoreBackupUseCase.kt +++ b/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/backup/RestoreBackupUseCase.kt @@ -26,12 +26,15 @@ import com.wire.kalium.cryptography.backup.BackupHeader.HeaderDecodingErrors.INV import com.wire.kalium.cryptography.backup.Passphrase import com.wire.kalium.cryptography.utils.ChaCha20Decryptor.decryptBackupFile import com.wire.kalium.logic.data.asset.KaliumFileSystem +import com.wire.kalium.logic.data.id.CurrentClientIdProvider import com.wire.kalium.logic.data.id.IdMapper import com.wire.kalium.logic.data.user.UserId import com.wire.kalium.logic.data.user.UserRepository import com.wire.kalium.logic.di.MapperProvider -import com.wire.kalium.logic.data.id.CurrentClientIdProvider import com.wire.kalium.logic.feature.backup.BackupConstants.BACKUP_ENCRYPTED_EXTENSION +import com.wire.kalium.logic.feature.backup.BackupConstants.BACKUP_METADATA_FILE_NAME +import com.wire.kalium.logic.feature.backup.BackupConstants.BACKUP_USER_DB_NAME +import com.wire.kalium.logic.feature.backup.BackupConstants.acceptedFileNames import com.wire.kalium.logic.feature.backup.BackupConstants.createBackupFileName import com.wire.kalium.logic.feature.backup.RestoreBackupResult.BackupRestoreFailure.BackupIOFailure import com.wire.kalium.logic.feature.backup.RestoreBackupResult.BackupRestoreFailure.DecryptionFailure @@ -43,6 +46,7 @@ import com.wire.kalium.logic.functional.flatMap import com.wire.kalium.logic.functional.fold import com.wire.kalium.logic.functional.mapLeft import com.wire.kalium.logic.kaliumLogger +import com.wire.kalium.logic.util.ExtractFilesParam import com.wire.kalium.logic.util.extractCompressedFile import com.wire.kalium.logic.wrapStorageRequest import com.wire.kalium.network.tools.KtxSerializer @@ -208,7 +212,11 @@ internal class RestoreBackupUseCaseImpl( } private fun extractFiles(inputSource: Source, extractedBackupRootPath: Path) = - extractCompressedFile(inputSource, extractedBackupRootPath, kaliumFileSystem) + extractCompressedFile( + inputSource, extractedBackupRootPath, ExtractFilesParam.Only( + acceptedFileNames() + ), kaliumFileSystem + ) private suspend fun getDbPathAndImport( extractedBackupRootPath: Path, diff --git a/logic/src/commonMain/kotlin/com/wire/kalium/logic/util/BackupUtils.kt b/logic/src/commonMain/kotlin/com/wire/kalium/logic/util/BackupUtils.kt index ddbbed89228..8d792a0199b 100644 --- a/logic/src/commonMain/kotlin/com/wire/kalium/logic/util/BackupUtils.kt +++ b/logic/src/commonMain/kotlin/com/wire/kalium/logic/util/BackupUtils.kt @@ -27,11 +27,24 @@ import okio.Sink import okio.Source expect fun createCompressedFile(files: List>, outputSink: Sink): Either -expect fun extractCompressedFile(inputSource: Source, outputRootPath: Path, fileSystem: KaliumFileSystem): Either +expect fun extractCompressedFile( + inputSource: Source, + outputRootPath: Path, + param: ExtractFilesParam, + fileSystem: KaliumFileSystem +): Either + expect fun checkIfCompressedFileContainsFileTypes( compressedFilePath: Path, fileSystem: KaliumFileSystem, expectedFileExtensions: List ): Either> +sealed interface ExtractFilesParam { + data object All : ExtractFilesParam + data class Only(val files: Set) : ExtractFilesParam { + constructor(vararg files: String) : this(files.toSet()) + } +} + expect inline fun decodeBufferSequence(bufferedSource: BufferedSource): Sequence