From a39e5698a9ee35b51bc438927e1017b55c1e12fa Mon Sep 17 00:00:00 2001 From: Julian Raufelder Date: Wed, 20 Apr 2022 17:29:51 +0200 Subject: [PATCH] `NoDirFileDialog` not shown using Local storage if dir file missing Fixes #437 --- .../data/cloud/crypto/CryptoImplDecorator.kt | 22 +++- .../cloud/crypto/CryptoImplVaultFormat7.kt | 115 +++++++++--------- .../cloud/crypto/CryptoImplVaultFormatPre7.kt | 36 ++++-- .../crypto/CryptoImplVaultFormat7Test.kt | 2 +- .../crypto/CryptoImplVaultFormatPre7Test.kt | 48 ++++---- 5 files changed, 125 insertions(+), 98 deletions(-) diff --git a/data/src/main/java/org/cryptomator/data/cloud/crypto/CryptoImplDecorator.kt b/data/src/main/java/org/cryptomator/data/cloud/crypto/CryptoImplDecorator.kt index 8c9cbaf1..f32cd3e3 100644 --- a/data/src/main/java/org/cryptomator/data/cloud/crypto/CryptoImplDecorator.kt +++ b/data/src/main/java/org/cryptomator/data/cloud/crypto/CryptoImplDecorator.kt @@ -85,10 +85,13 @@ abstract class CryptoImplDecorator( abstract fun write(cryptoFile: CryptoFile, data: DataSource, progressAware: ProgressAware, replace: Boolean, length: Long): CryptoFile @Throws(BackendException::class, EmptyDirFileException::class) - abstract fun loadDirId(folder: CryptoFolder): String + abstract fun loadDirId(folder: CryptoFolder): String? @Throws(BackendException::class) - abstract fun createDirIdInfo(folder: CryptoFolder): DirIdInfo + abstract fun getOrCreateDirIdInfo(folder: CryptoFolder): DirIdInfo + + @Throws(BackendException::class) + abstract fun getDirIdInfo(folder: CryptoFolder): DirIdInfo? private fun dirHash(directoryId: String): String { return cryptor().fileNameCryptor().hashDirectoryId(directoryId) @@ -162,7 +165,7 @@ abstract class CryptoImplDecorator( @Throws(BackendException::class) private fun file(cryptoParent: CryptoFolder, cleartextName: String, ciphertextName: String, cleartextSize: Long?): CryptoFile { val ciphertextSize = cleartextSize?.let { cryptor().fileContentCryptor().ciphertextSize(it) + cryptor().fileHeaderCryptor().headerSize() } - val cloudFile = cloudContentRepository.file(dirIdInfo(cryptoParent).cloudFolder, ciphertextName, ciphertextSize) + val cloudFile = cloudContentRepository.file(getOrCreateCachingAwareDirIdInfo(cryptoParent).cloudFolder, ciphertextName, ciphertextSize) return file(cryptoParent, cleartextName, cloudFile, cleartextSize) } @@ -212,7 +215,9 @@ abstract class CryptoImplDecorator( @Throws(BackendException::class) private fun exists(folder: CryptoFolder): Boolean { requireNotNull(folder.dirFile) - return cloudContentRepository.exists(folder.dirFile) && cloudContentRepository.exists(dirIdInfo(folder).cloudFolder) + return cloudContentRepository.exists(folder.dirFile) && getCachingAwareDirIdInfo(folder)?.let { + cloudContentRepository.exists(it.cloudFolder) + } ?: false } @Throws(BackendException::class) @@ -352,8 +357,13 @@ abstract class CryptoImplDecorator( } @Throws(BackendException::class) - fun dirIdInfo(folder: CryptoFolder): DirIdInfo { - return dirIdCache[folder] ?: return createDirIdInfo(folder) + fun getOrCreateCachingAwareDirIdInfo(folder: CryptoFolder): DirIdInfo { + return dirIdCache[folder] ?: return getOrCreateDirIdInfo(folder) + } + + @Throws(BackendException::class) + fun getCachingAwareDirIdInfo(folder: CryptoFolder): DirIdInfo? { + return dirIdCache[folder] ?: return getDirIdInfo(folder) } @Throws(BackendException::class) diff --git a/data/src/main/java/org/cryptomator/data/cloud/crypto/CryptoImplVaultFormat7.kt b/data/src/main/java/org/cryptomator/data/cloud/crypto/CryptoImplVaultFormat7.kt index 7576d1ea..6c5ce70a 100644 --- a/data/src/main/java/org/cryptomator/data/cloud/crypto/CryptoImplVaultFormat7.kt +++ b/data/src/main/java/org/cryptomator/data/cloud/crypto/CryptoImplVaultFormat7.kt @@ -64,7 +64,7 @@ open class CryptoImplVaultFormat7 : CryptoImplDecorator { @Throws(BackendException::class) override fun folder(cryptoParent: CryptoFolder, cleartextName: String): CryptoFolder { val dirFileName = encryptFolderName(cryptoParent, cleartextName) - val dirFolder = cloudContentRepository.folder(dirIdInfo(cryptoParent).cloudFolder, dirFileName) + val dirFolder = cloudContentRepository.folder(getOrCreateCachingAwareDirIdInfo(cryptoParent).cloudFolder, dirFileName) val dirFile = cloudContentRepository.file(dirFolder, CLOUD_FOLDER_DIR_FILE_PRE + CLOUD_NODE_EXT) return folder(cryptoParent, cleartextName, dirFile) } @@ -73,7 +73,7 @@ open class CryptoImplVaultFormat7 : CryptoImplDecorator { override fun encryptName(cryptoParent: CryptoFolder, name: String): String { var ciphertextName: String = cryptor() // .fileNameCryptor() // - .encryptFilename(BaseEncoding.base64Url(), name, dirIdInfo(cryptoParent).id.toByteArray(StandardCharsets.UTF_8)) + CLOUD_NODE_EXT + .encryptFilename(BaseEncoding.base64Url(), name, getOrCreateCachingAwareDirIdInfo(cryptoParent).id.toByteArray(StandardCharsets.UTF_8)) + CLOUD_NODE_EXT if (ciphertextName.length > shorteningThreshold) { ciphertextName = deflate(cryptoParent, ciphertextName) } @@ -85,7 +85,7 @@ open class CryptoImplVaultFormat7 : CryptoImplDecorator { val longFilenameBytes = longFileName.toByteArray(StandardCharsets.UTF_8) val hash = MessageDigestSupplier.SHA1.get().digest(longFilenameBytes) val shortFileName = BaseEncoding.base64Url().encode(hash) + LONG_NODE_FILE_EXT - var dirFolder = cloudContentRepository.folder(dirIdInfo(cryptoParent).cloudFolder, shortFileName) + var dirFolder = cloudContentRepository.folder(getOrCreateCachingAwareDirIdInfo(cryptoParent).cloudFolder, shortFileName) // if folder already exists in case of renaming if (!cloudContentRepository.exists(dirFolder)) { @@ -98,6 +98,14 @@ open class CryptoImplVaultFormat7 : CryptoImplDecorator { return shortFileName } + @Throws(BackendException::class) + private fun inflate(cloudNode: CloudNode): String { + val metadataFile = metadataFile(cloudNode) + val out = ByteArrayOutputStream() + cloudContentRepository.read(metadataFile, null, out, ProgressAware.NO_OP_PROGRESS_AWARE_DOWNLOAD) + return String(out.toByteArray(), StandardCharsets.UTF_8) + } + @Throws(BackendException::class) private fun metadataFile(cloudNode: CloudNode): CloudFile { val cloudFolder = when (cloudNode) { @@ -114,14 +122,6 @@ open class CryptoImplVaultFormat7 : CryptoImplDecorator { return cloudContentRepository.file(cloudFolder, LONG_NODE_FILE_CONTENT_NAME + LONG_NODE_FILE_EXT) } - @Throws(BackendException::class) - private fun inflate(cloudNode: CloudNode): String { - val metadataFile = metadataFile(cloudNode) - val out = ByteArrayOutputStream() - cloudContentRepository.read(metadataFile, null, out, ProgressAware.NO_OP_PROGRESS_AWARE_DOWNLOAD) - return String(out.toByteArray(), StandardCharsets.UTF_8) - } - override fun decryptName(dirId: String, encryptedName: String): String? { return extractEncryptedName(encryptedName)?.let { return cryptor().fileNameCryptor().decryptFilename(BaseEncoding.base64Url(), it, dirId.toByteArray(StandardCharsets.UTF_8)) @@ -132,34 +132,41 @@ open class CryptoImplVaultFormat7 : CryptoImplDecorator { override fun list(cryptoFolder: CryptoFolder): List { dirIdCache.evictSubFoldersOf(cryptoFolder) - val dirIdInfo = dirIdInfo(cryptoFolder) - val dirId = dirIdInfo(cryptoFolder).id + val dirIdInfo = getCachingAwareDirIdInfo(cryptoFolder) + ?: when (cryptoFolder.dirFile) { + null -> { + Timber.tag("CryptoFs").e(String.format("Dir-file of folder is null %s", cryptoFolder.path)) + throw FatalBackendException(String.format("Dir-file of folder is null %s", cryptoFolder.path)) + } + else -> { + Timber.tag("CryptoFs").e("No dir file exists in %s", cryptoFolder.dirFile.path) + throw NoDirFileException(cryptoFolder.name, cryptoFolder.dirFile.path) + } + } + + val dirId = dirIdInfo.id val lvl2Dir = dirIdInfo.cloudFolder - val ciphertextNodes: List = try { + return try { cloudContentRepository.list(lvl2Dir) } catch (e: NoSuchCloudFileException) { - if (cryptoFolder is RootCryptoFolder) { - Timber.tag("CryptoFs").e("No lvl2Dir exists for root folder in %s", lvl2Dir.path) - throw FatalBackendException(String.format("No lvl2Dir exists for root folder in %s", lvl2Dir.path), e) - } else if (cryptoFolder.dirFile == null) { - Timber.tag("CryptoFs").e(String.format("Dir-file of folder is null %s", lvl2Dir.path)) - throw FatalBackendException(String.format("Dir-file of folder is null %s", lvl2Dir.path)) - } else if (cloudContentRepository.exists(cloudContentRepository.file(cryptoFolder.dirFile.parent, CLOUD_NODE_SYMLINK_PRE + CLOUD_NODE_EXT))) { - throw SymLinkException() - } else if (!cloudContentRepository.exists(cryptoFolder.dirFile)) { - Timber.tag("CryptoFs").e("No dir file exists in %s", cryptoFolder.dirFile.path) - throw NoDirFileException(cryptoFolder.name, cryptoFolder.dirFile.path) + when { + cryptoFolder is RootCryptoFolder -> { + Timber.tag("CryptoFs").e("No lvl2Dir exists for root folder in %s", lvl2Dir.path) + throw FatalBackendException(String.format("No lvl2Dir exists for root folder in %s", lvl2Dir.path), e) + } + cryptoFolder.dirFile == null -> { + Timber.tag("CryptoFs").e(String.format("Dir-file of folder is null %s", lvl2Dir.path)) + throw FatalBackendException(String.format("Dir-file of folder is null %s", lvl2Dir.path)) + } + cloudContentRepository.exists(cloudContentRepository.file(cryptoFolder.dirFile.parent, CLOUD_NODE_SYMLINK_PRE + CLOUD_NODE_EXT)) -> { + throw SymLinkException() + } + else -> return emptyList() } - return emptyList() - } - - return ciphertextNodes - .map { node -> - ciphertextToCleartextNode(cryptoFolder, dirId, node) - } - .toList() - .filterNotNull() + }.map { node -> + ciphertextToCleartextNode(cryptoFolder, dirId, node) + }.toList().filterNotNull() } @Throws(BackendException::class) @@ -247,11 +254,17 @@ open class CryptoImplVaultFormat7 : CryptoImplDecorator { } @Throws(BackendException::class) - override fun createDirIdInfo(folder: CryptoFolder): DirIdInfo { - val dirId = loadDirId(folder) + override fun getOrCreateDirIdInfo(folder: CryptoFolder): DirIdInfo { + val dirId = loadDirId(folder) ?: newDirId() return dirIdCache.put(folder, createDirIdInfoFor(dirId)) } + override fun getDirIdInfo(folder: CryptoFolder): DirIdInfo? { + return loadDirId(folder)?.let { + dirIdCache.put(folder, createDirIdInfoFor(it)) + } + } + @Throws(BackendException::class) override fun encryptFolderName(cryptoFolder: CryptoFolder, name: String): String { return encryptName(cryptoFolder, name) @@ -263,17 +276,13 @@ open class CryptoImplVaultFormat7 : CryptoImplDecorator { } @Throws(BackendException::class, EmptyDirFileException::class) - override fun loadDirId(folder: CryptoFolder): String { - var dirFile: CloudFile? = null - if (folder.dirFile != null) { - dirFile = folder.dirFile - } + override fun loadDirId(folder: CryptoFolder): String? { return if (RootCryptoFolder.isRoot(folder)) { CryptoConstants.ROOT_DIR_ID - } else if (dirFile != null && cloudContentRepository.exists(dirFile)) { - String(loadContentsOfDirFile(dirFile), StandardCharsets.UTF_8) + } else if (folder.dirFile != null && cloudContentRepository.exists(folder.dirFile)) { + String(loadContentsOfDirFile(folder.dirFile), StandardCharsets.UTF_8) } else { - newDirId() + null } } @@ -302,7 +311,7 @@ open class CryptoImplVaultFormat7 : CryptoImplDecorator { assertCryptoFolderAlreadyExists(folder) shortName = true } - val dirIdInfo = dirIdInfo(folder) + val dirIdInfo = getOrCreateCachingAwareDirIdInfo(folder) val createdCloudFolder = cloudContentRepository.create(dirIdInfo.cloudFolder) var dirFolder = folder.dirFile.parent var dirFile = folder.dirFile @@ -407,17 +416,13 @@ open class CryptoImplVaultFormat7 : CryptoImplDecorator { requireNotNull(node.dirFile) val cryptoSubfolders = deepCollectSubfolders(node) for (cryptoSubfolder in cryptoSubfolders) { - try { - cloudContentRepository.delete(dirIdInfo(cryptoSubfolder).cloudFolder) - } catch (e: NoSuchCloudFileException) { - // Ignoring because nothing can be done if the dir-file doesn't exists in the cloud - } - } - try { - cloudContentRepository.delete(dirIdInfo(node).cloudFolder) - } catch (e: NoSuchCloudFileException) { - // Ignoring because nothing can be done if the dir-file doesn't exists in the cloud + getCachingAwareDirIdInfo(cryptoSubfolder)?.let { + cloudContentRepository.delete(it.cloudFolder) + } ?: Timber.tag("CryptoFs").w("Dir file doesn't exists of a sub folder while deleting the parent, continue anyway") } + getCachingAwareDirIdInfo(node)?.let { + cloudContentRepository.delete(it.cloudFolder) + } ?: Timber.tag("CryptoFs").w("Dir file doesn't exists while deleting the folder, continue anyway") cloudContentRepository.delete(node.dirFile.parent) evictFromCache(node) } else if (node is CryptoFile) { diff --git a/data/src/main/java/org/cryptomator/data/cloud/crypto/CryptoImplVaultFormatPre7.kt b/data/src/main/java/org/cryptomator/data/cloud/crypto/CryptoImplVaultFormatPre7.kt index c0f05464..a750bf6e 100644 --- a/data/src/main/java/org/cryptomator/data/cloud/crypto/CryptoImplVaultFormatPre7.kt +++ b/data/src/main/java/org/cryptomator/data/cloud/crypto/CryptoImplVaultFormatPre7.kt @@ -16,6 +16,7 @@ import org.cryptomator.domain.CloudNode import org.cryptomator.domain.exception.AlreadyExistException import org.cryptomator.domain.exception.BackendException import org.cryptomator.domain.exception.EmptyDirFileException +import org.cryptomator.domain.exception.NoDirFileException import org.cryptomator.domain.exception.NoSuchCloudFileException import org.cryptomator.domain.exception.ParentFolderIsNullException import org.cryptomator.domain.repository.CloudContentRepository @@ -27,7 +28,6 @@ import java.io.ByteArrayOutputStream import java.nio.charset.StandardCharsets import java.util.function.Supplier import java.util.regex.Pattern -import kotlin.streams.toList import timber.log.Timber internal class CryptoImplVaultFormatPre7( @@ -44,7 +44,7 @@ internal class CryptoImplVaultFormatPre7( @Throws(BackendException::class) override fun folder(cryptoParent: CryptoFolder, cleartextName: String): CryptoFolder { val dirFileName = encryptFolderName(cryptoParent, cleartextName) - val dirFile = cloudContentRepository.file(dirIdInfo(cryptoParent).cloudFolder, dirFileName) + val dirFile = cloudContentRepository.file(getOrCreateCachingAwareDirIdInfo(cryptoParent).cloudFolder, dirFileName) return folder(cryptoParent, cleartextName, dirFile) } @@ -52,7 +52,7 @@ internal class CryptoImplVaultFormatPre7( override fun create(folder: CryptoFolder): CryptoFolder { requireNotNull(folder.dirFile) assertCryptoFolderAlreadyExists(folder) - val dirIdInfo = dirIdInfo(folder) + val dirIdInfo = getOrCreateCachingAwareDirIdInfo(folder) val createdCloudFolder = cloudContentRepository.create(dirIdInfo.cloudFolder) val dirId = dirIdInfo.id.toByteArray(StandardCharsets.UTF_8) val createdDirFile = cloudContentRepository.write(folder.dirFile, from(dirId), ProgressAware.NO_OP_PROGRESS_AWARE_UPLOAD, false, dirId.size.toLong()) @@ -68,7 +68,7 @@ internal class CryptoImplVaultFormatPre7( @Throws(BackendException::class) private fun encryptName(cryptoParent: CryptoFolder, name: String, prefix: String): String { - var ciphertextName = prefix + cryptor().fileNameCryptor().encryptFilename(BaseEncoding.base32(), name, dirIdInfo(cryptoParent).id.toByteArray(StandardCharsets.UTF_8)) + var ciphertextName = prefix + cryptor().fileNameCryptor().encryptFilename(BaseEncoding.base32(), name, getOrCreateCachingAwareDirIdInfo(cryptoParent).id.toByteArray(StandardCharsets.UTF_8)) if (ciphertextName.length > shorteningThreshold) { ciphertextName = deflate(ciphertextName) } @@ -120,8 +120,8 @@ internal class CryptoImplVaultFormatPre7( @Throws(BackendException::class) override fun list(cryptoFolder: CryptoFolder): List { - val dirIdInfo = dirIdInfo(cryptoFolder) - val dirId = dirIdInfo(cryptoFolder).id + val dirIdInfo = getDirIdInfo(cryptoFolder) ?: throw NoDirFileException(cryptoFolder.name, cryptoFolder.dirFile?.path) + val dirId = dirIdInfo.id val lvl2Dir = dirIdInfo.cloudFolder return cloudContentRepository .list(lvl2Dir) @@ -198,7 +198,7 @@ internal class CryptoImplVaultFormatPre7( @Throws(BackendException::class) override fun symlink(cryptoParent: CryptoFolder, cleartextName: String, target: String): CryptoSymlink { val ciphertextName = encryptSymlinkName(cryptoParent, cleartextName) - val cloudFile = cloudContentRepository.file(dirIdInfo(cryptoParent).cloudFolder, ciphertextName) + val cloudFile = cloudContentRepository.file(getOrCreateCachingAwareDirIdInfo(cryptoParent).cloudFolder, ciphertextName) return CryptoSymlink(cryptoParent, cleartextName, path(cryptoParent, cleartextName), target, cloudFile) } @@ -237,9 +237,13 @@ internal class CryptoImplVaultFormatPre7( requireNotNull(node.dirFile) val cryptoSubfolders = deepCollectSubfolders(node) for (cryptoSubfolder in cryptoSubfolders) { - cloudContentRepository.delete(dirIdInfo(cryptoSubfolder).cloudFolder) + getCachingAwareDirIdInfo(cryptoSubfolder)?.let { + cloudContentRepository.delete(it.cloudFolder) + } ?: Timber.tag("CryptoFs").w("Dir file doesn't exists of a sub folder while deleting the parent, continue anyway") } - cloudContentRepository.delete(dirIdInfo(node).cloudFolder) + getCachingAwareDirIdInfo(node)?.let { + cloudContentRepository.delete(it.cloudFolder) + } ?: Timber.tag("CryptoFs").w("Dir file doesn't exists while deleting the folder, continue anyway") cloudContentRepository.delete(node.dirFile) evictFromCache(node) } else if (node is CryptoFile) { @@ -248,22 +252,28 @@ internal class CryptoImplVaultFormatPre7( } @Throws(BackendException::class, EmptyDirFileException::class) - override fun loadDirId(folder: CryptoFolder): String { + override fun loadDirId(folder: CryptoFolder): String? { return if (isRoot(folder)) { CryptoConstants.ROOT_DIR_ID } else if (folder.dirFile != null && cloudContentRepository.exists(folder.dirFile)) { String(loadContentsOfDirFile(folder), StandardCharsets.UTF_8) } else { - newDirId() + null } } @Throws(BackendException::class) - override fun createDirIdInfo(folder: CryptoFolder): DirIdInfo { - val dirId = loadDirId(folder) + override fun getOrCreateDirIdInfo(folder: CryptoFolder): DirIdInfo { + val dirId = loadDirId(folder) ?: newDirId() return dirIdCache.put(folder, createDirIdInfoFor(dirId)) } + override fun getDirIdInfo(folder: CryptoFolder): DirIdInfo? { + return loadDirId(folder)?.let { + dirIdCache.put(folder, createDirIdInfoFor(it)) + } + } + @Throws(BackendException::class) override fun write(cryptoFile: CryptoFile, data: DataSource, progressAware: ProgressAware, replace: Boolean, length: Long): CryptoFile { return writeShortNameFile(cryptoFile, data, progressAware, replace, length) diff --git a/data/src/test/java/org/cryptomator/data/cloud/crypto/CryptoImplVaultFormat7Test.kt b/data/src/test/java/org/cryptomator/data/cloud/crypto/CryptoImplVaultFormat7Test.kt index b210694b..e51ab1d9 100644 --- a/data/src/test/java/org/cryptomator/data/cloud/crypto/CryptoImplVaultFormat7Test.kt +++ b/data/src/test/java/org/cryptomator/data/cloud/crypto/CryptoImplVaultFormat7Test.kt @@ -42,7 +42,6 @@ import java.io.InputStreamReader import java.io.OutputStream import java.nio.ByteBuffer import java.nio.charset.StandardCharsets -import java.util.ArrayList import kotlin.io.path.createTempDirectory import kotlin.io.path.deleteExisting @@ -730,6 +729,7 @@ class CryptoImplVaultFormat7Test { whenever(cloudContentRepository.folder(aaFolder, shortenedFileName)).thenReturn(testDir3) whenever(cloudContentRepository.exists(testDir3)).thenReturn(false) whenever(dirIdCache.put(eq(cryptoFolder3), any())).thenReturn(DirIdInfo("dir3-id", ddFolder)) + whenever(dirIdCache[cryptoFolder3]).thenReturn(DirIdInfo("dir3-id", ddFolder)) whenever(cloudContentRepository.file(testDir3, "dir.c9r")).thenReturn(testDir3DirFile) whenever(cloudContentRepository.file(testDir3, "name.c9s", 257L)).thenReturn(testDir3NameFile) whenever>(cloudContentRepository.list(ddFolder)).thenReturn(ArrayList()) diff --git a/data/src/test/java/org/cryptomator/data/cloud/crypto/CryptoImplVaultFormatPre7Test.kt b/data/src/test/java/org/cryptomator/data/cloud/crypto/CryptoImplVaultFormatPre7Test.kt index 50fb9ecf..ad0a12fb 100644 --- a/data/src/test/java/org/cryptomator/data/cloud/crypto/CryptoImplVaultFormatPre7Test.kt +++ b/data/src/test/java/org/cryptomator/data/cloud/crypto/CryptoImplVaultFormatPre7Test.kt @@ -33,6 +33,7 @@ import org.mockito.AdditionalMatchers import org.mockito.Mockito import org.mockito.invocation.InvocationOnMock import org.mockito.kotlin.any +import org.mockito.kotlin.anyOrNull import org.mockito.kotlin.eq import org.mockito.kotlin.mock import org.mockito.kotlin.whenever @@ -43,7 +44,6 @@ import java.io.InputStreamReader import java.io.OutputStream import java.nio.ByteBuffer import java.nio.charset.StandardCharsets -import java.util.ArrayList import java.util.function.Supplier import kotlin.io.path.createTempDirectory import kotlin.io.path.deleteExisting @@ -138,11 +138,11 @@ internal class CryptoImplVaultFormatPre7Test { whenever(cloudContentRepository.folder(lvl2Dir, "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA")).thenReturn(aaFolder) whenever(cloudContentRepository.file(aaFolder, "0dir1")).thenReturn(testDir1) whenever(cloudContentRepository.exists(testDir1)).thenReturn(true) - Mockito.doAnswer { invocation: InvocationOnMock -> - val out = invocation.getArgument(2) + whenever(cloudContentRepository.read(eq(cryptoFolder1.dirFile!!), any(), any(), any())).thenAnswer { invocationOnMock: InvocationOnMock -> + val out = invocationOnMock.getArgument(2) copyStreamToStream(ByteArrayInputStream(dirId1.toByteArray()), out) null - }.`when`(cloudContentRepository).read(eq(cryptoFolder1.dirFile!!), any(), any(), any()) + } whenever>(cloudContentRepository.list(aaFolder)).thenReturn(rootItems) whenever(dirIdCache.put(eq(root), any())).thenReturn(DirIdInfo("", aaFolder)) } @@ -193,11 +193,11 @@ internal class CryptoImplVaultFormatPre7Test { val cryptoFolder3 = CryptoFolder(cryptoFolder1, dir3Name, "/Directory 1/$dir3Name", testDir3DirFile) - Mockito.doAnswer { invocation: InvocationOnMock -> - val out = invocation.getArgument(2) + whenever(cloudContentRepository.read(eq(cryptoFolder3.dirFile!!), anyOrNull(), any(), any())).thenAnswer { invocationOnMock: InvocationOnMock -> + val out = invocationOnMock.getArgument(2) copyStreamToStream(ByteArrayInputStream("dir3-id".toByteArray()), out) null - }.`when`(cloudContentRepository).read(eq(cryptoFolder3.dirFile!!), any(), any(), any()) + } /* * │ ├─ Directory 3x250 @@ -217,11 +217,11 @@ internal class CryptoImplVaultFormatPre7Test { whenever(cloudContentRepository.file(directory4x250, "name.c9s")).thenReturn(testDir4NameFile) whenever(fileNameCryptor.encryptFilename(BaseEncoding.base32(), dir4Name, "dir3-id".toByteArray())).thenReturn(dir4Cipher) whenever(fileNameCryptor.decryptFilename(BaseEncoding.base32(), dir4Cipher, "dir3-id".toByteArray())).thenReturn(dir4Name) - Mockito.doAnswer { invocation: InvocationOnMock -> - val out = invocation.getArgument(2) + whenever(cloudContentRepository.read(eq(testDir4NameFile), any(), any(), any())).thenAnswer { invocationOnMock: InvocationOnMock -> + val out = invocationOnMock.getArgument(2) copyStreamToStream(ByteArrayInputStream(dir4Cipher.toByteArray(charset("UTF-8"))), out) null - }.`when`(cloudContentRepository).read(eq(testDir4NameFile), any(), any(), any()) + } val dir4Files: ArrayList = object : ArrayList() { init { @@ -242,11 +242,12 @@ internal class CryptoImplVaultFormatPre7Test { whenever(cloudContentRepository.file(directory5x250, "name.c9s")).thenReturn(testFile5NameFile) whenever(fileNameCryptor.encryptFilename(BaseEncoding.base32(), file5Name, "dir3-id".toByteArray())).thenReturn(file5Cipher) whenever(fileNameCryptor.decryptFilename(BaseEncoding.base32(), file5Cipher, "dir3-id".toByteArray())).thenReturn(file5Name) - Mockito.doAnswer { invocation: InvocationOnMock -> - val out = invocation.getArgument(2) + whenever(cloudContentRepository.read(eq(testFile5NameFile), any(), any(), any())).thenAnswer { invocationOnMock: InvocationOnMock -> + val out = invocationOnMock.getArgument(2) copyStreamToStream(ByteArrayInputStream(file5Cipher.toByteArray(charset("UTF-8"))), out) null - }.`when`(cloudContentRepository).read(eq(testFile5NameFile), any(), any(), any()) + } + val dir5Files: ArrayList = object : ArrayList() { init { add(testFile5ContentFile) @@ -286,11 +287,11 @@ internal class CryptoImplVaultFormatPre7Test { whenever(fileHeaderCryptor.decryptHeader(StandardCharsets.UTF_8.encode("hhhhh"))).thenReturn(header) whenever(fileContentCryptor.decryptChunk(eq(StandardCharsets.UTF_8.encode("TOPSECRET!")), any(), eq(header), any())) .then { invocation: InvocationOnMock? -> StandardCharsets.UTF_8.encode("geheim!!") } - Mockito.doAnswer { invocation: InvocationOnMock -> - val out = invocation.getArgument(2) + whenever(cloudContentRepository.read(eq(cryptoFile1.cloudFile), any(), any(), any())).thenAnswer { invocationOnMock: InvocationOnMock -> + val out = invocationOnMock.getArgument(2) copyStreamToStream(ByteArrayInputStream(file1Content), out) null - }.`when`(cloudContentRepository).read(eq(cryptoFile1.cloudFile), any(), any(), any()) + } val outputStream = ByteArrayOutputStream(1000) inTest.read(cryptoFile1, outputStream, ProgressAware.NO_OP_PROGRESS_AWARE_DOWNLOAD) @@ -318,11 +319,11 @@ internal class CryptoImplVaultFormatPre7Test { whenever(fileContentCryptor.decryptChunk(eq(StandardCharsets.UTF_8.encode("TOPSECRET!")), any(), eq(header), any())) .then { invocation: InvocationOnMock? -> StandardCharsets.UTF_8.encode("geheim!!") } val cryptoFile15 = CryptoFile(root, file3Name, "/$file3Name", null, testFile3ContentFile) - Mockito.doAnswer { invocation: InvocationOnMock -> - val out = invocation.getArgument(2) + whenever(cloudContentRepository.read(eq(cryptoFile15.cloudFile), any(), any(), any())).thenAnswer { invocationOnMock: InvocationOnMock -> + val out = invocationOnMock.getArgument(2) copyStreamToStream(ByteArrayInputStream(file1Content), out) null - }.`when`(cloudContentRepository).read(eq(cryptoFile15.cloudFile), any(), any(), any()) + } val outputStream = ByteArrayOutputStream(1000) inTest.read(cryptoFile15, outputStream, ProgressAware.NO_OP_PROGRESS_AWARE_DOWNLOAD) @@ -593,11 +594,11 @@ internal class CryptoImplVaultFormatPre7Test { val testDir2DirFile = TestFile(bbFolder, "0dir2", "/d/11/BBBBBBBBBBBBBBBBBBBBBBBBBBBBBB/0dir2", null, null) val cryptoFolder2 = CryptoFolder(cryptoFolder1, "Directory 2", "/Directory 1/Directory 2", testDir2DirFile) - Mockito.doAnswer { invocation: InvocationOnMock -> - val out = invocation.getArgument(2) + whenever(cloudContentRepository.read(eq(cryptoFolder2.dirFile!!), anyOrNull(), any(), any())).thenAnswer { invocationOnMock: InvocationOnMock -> + val out = invocationOnMock.getArgument(2) copyStreamToStream(ByteArrayInputStream(dirId2.toByteArray()), out) null - }.`when`(cloudContentRepository).read(eq(cryptoFolder2.dirFile!!), any(), any(), any()) + } val dir1Items: ArrayList = object : ArrayList() { init { @@ -657,6 +658,7 @@ internal class CryptoImplVaultFormatPre7Test { whenever(cloudContentRepository.folder(d, "33")).thenReturn(ddLvl2Dir) whenever(cloudContentRepository.folder(lvl2Dir, "DDDDDDDDDDDDDDDDDDDDDDDDDDDDDD")).thenReturn(ddFolder) whenever(dirIdCache.put(eq(cryptoFolder3), any())).thenReturn(DirIdInfo("dir3-id", ddFolder)) + whenever(dirIdCache[cryptoFolder3]).thenReturn(DirIdInfo("dir3-id", ddFolder)) whenever(cloudContentRepository.file(aaFolder, shortenedFileName)).thenReturn(testDir3DirFile) whenever(cloudContentRepository.file(testDir3NameFile.parent!!, shortenedFileName, 257L)).thenReturn(testDir3NameFile) whenever>(cloudContentRepository.list(ddFolder)).thenReturn(ArrayList()) @@ -767,7 +769,7 @@ internal class CryptoImplVaultFormatPre7Test { val cryptoMovedFile4 = CryptoFile(cryptoFolder1, file4Name, "/Directory 1/$file4Name", null, testFile4ContentFile) whenever(cloudContentRepository.move(testFile4ContentFileOld, testFile4ContentFile)).thenReturn(testFile4ContentFile) - whenever(cloudContentRepository.create(testFile4NameFile.parent!!)).thenReturn(testFile4NameFile.parent) + whenever(cloudContentRepository.create(testFile4NameFile.parent)).thenReturn(testFile4NameFile.parent) whenever(cloudContentRepository.write(eq(testFile4NameFile), any(), any(), eq(true), any())).thenAnswer { invocationOnMock: InvocationOnMock -> val inputStream = invocationOnMock.getArgument(1) val dirContent = BufferedReader(InputStreamReader(inputStream.open(context)!!, StandardCharsets.UTF_8)).readLine()