From b40a9dbd9ee3c1bde1dcb43523f49339eeefcaf8 Mon Sep 17 00:00:00 2001 From: Sebastian Stenzel Date: Tue, 4 Apr 2017 17:58:53 +0200 Subject: [PATCH 1/5] Fixed warnings --- .../cryptofs/CryptoFileSystemImplTest.java | 25 +++++++++---------- .../cryptofs/MoveOperationTest.java | 5 ++-- ...iteFileWhileReadonlyChannelIsOpenTest.java | 2 +- 3 files changed, 15 insertions(+), 17 deletions(-) diff --git a/src/test/java/org/cryptomator/cryptofs/CryptoFileSystemImplTest.java b/src/test/java/org/cryptomator/cryptofs/CryptoFileSystemImplTest.java index bed8d5d1..f67d7cbc 100644 --- a/src/test/java/org/cryptomator/cryptofs/CryptoFileSystemImplTest.java +++ b/src/test/java/org/cryptomator/cryptofs/CryptoFileSystemImplTest.java @@ -9,7 +9,7 @@ import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertThat; import static org.junit.Assert.assertTrue; -import static org.mockito.Matchers.any; +import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.doThrow; import static org.mockito.Mockito.mock; @@ -493,7 +493,7 @@ public void moveDirectoryReplaceExistingNonEmpty() throws IOException { thrown.expect(DirectoryNotEmptyException.class); inTest.move(cleartextSource, cleartextTarget, StandardCopyOption.REPLACE_EXISTING); } finally { - verify(physicalFsProv, Mockito.never()).move(Mockito.any(), Mockito.any(), Mockito.anyVararg()); + verify(physicalFsProv, Mockito.never()).move(Mockito.any(), Mockito.any(), Mockito.any()); } } @@ -505,7 +505,7 @@ public void moveDirectoryReplaceExistingAtomically() throws IOException { thrown.expect(AtomicMoveNotSupportedException.class); inTest.move(cleartextSource, cleartextTarget, StandardCopyOption.REPLACE_EXISTING, StandardCopyOption.ATOMIC_MOVE); } finally { - verify(physicalFsProv, Mockito.never()).move(Mockito.any(), Mockito.any(), Mockito.anyVararg()); + verify(physicalFsProv, Mockito.never()).move(Mockito.any(), Mockito.any(), Mockito.any()); } } @@ -519,7 +519,6 @@ public class Copy { private final FileChannel ciphertextTargetDirFileChannel = mock(FileChannel.class); @Before - @SuppressWarnings("unchecked") public void setup() throws IOException, ReflectiveOperationException { when(cleartextTarget.getParent()).thenReturn(cleartextTargetParent); when(cryptoPathMapper.getCiphertextDirPath(cleartextTargetParent)).thenReturn(ciphertextTargetParent); @@ -528,7 +527,7 @@ public void setup() throws IOException, ReflectiveOperationException { when(ciphertextTargetDir.getFileSystem()).thenReturn(physicalFs); when(cryptoPathMapper.getCiphertextDir(cleartextTarget)).thenReturn(new Directory("42", ciphertextTargetDir)); - when(physicalFsProv.newFileChannel(Mockito.same(ciphertextTargetDirFile), Mockito.anySet(), Mockito.anyVararg())).thenReturn(ciphertextTargetDirFileChannel); + when(physicalFsProv.newFileChannel(Mockito.same(ciphertextTargetDirFile), Mockito.anySet(), Mockito.any())).thenReturn(ciphertextTargetDirFileChannel); Field closeLockField = AbstractInterruptibleChannel.class.getDeclaredField("closeLock"); closeLockField.setAccessible(true); closeLockField.set(ciphertextTargetDirFileChannel, new Object()); @@ -612,8 +611,8 @@ public void moveDirectoryCopyBasicAttributes() throws IOException { when(srcAttrs.lastModifiedTime()).thenReturn(lastModifiedTime); when(srcAttrs.lastAccessTime()).thenReturn(lastAccessTime); when(srcAttrs.creationTime()).thenReturn(createTime); - when(physicalFsProv.readAttributes(Mockito.same(ciphertextSourceDir), Mockito.same(BasicFileAttributes.class), Mockito.anyVararg())).thenReturn(srcAttrs); - when(physicalFsProv.getFileAttributeView(Mockito.same(ciphertextTargetDir), Mockito.same(BasicFileAttributeView.class), Mockito.anyVararg())).thenReturn(dstAttrView); + when(physicalFsProv.readAttributes(Mockito.same(ciphertextSourceDir), Mockito.same(BasicFileAttributes.class), Mockito.any())).thenReturn(srcAttrs); + when(physicalFsProv.getFileAttributeView(Mockito.same(ciphertextTargetDir), Mockito.same(BasicFileAttributeView.class), Mockito.any())).thenReturn(dstAttrView); inTest.copy(cleartextSource, cleartextTarget, StandardCopyOption.COPY_ATTRIBUTES); verify(dstAttrView).setTimes(lastModifiedTime, lastAccessTime, createTime); @@ -629,8 +628,8 @@ public void moveDirectoryCopyFileOwnerAttributes() throws IOException { FileOwnerAttributeView srcAttrsView = mock(FileOwnerAttributeView.class); FileOwnerAttributeView dstAttrView = mock(FileOwnerAttributeView.class); when(srcAttrsView.getOwner()).thenReturn(owner); - when(physicalFsProv.getFileAttributeView(Mockito.same(ciphertextSourceDir), Mockito.same(FileOwnerAttributeView.class), Mockito.anyVararg())).thenReturn(srcAttrsView); - when(physicalFsProv.getFileAttributeView(Mockito.same(ciphertextTargetDir), Mockito.same(FileOwnerAttributeView.class), Mockito.anyVararg())).thenReturn(dstAttrView); + when(physicalFsProv.getFileAttributeView(Mockito.same(ciphertextSourceDir), Mockito.same(FileOwnerAttributeView.class), Mockito.any())).thenReturn(srcAttrsView); + when(physicalFsProv.getFileAttributeView(Mockito.same(ciphertextTargetDir), Mockito.same(FileOwnerAttributeView.class), Mockito.any())).thenReturn(dstAttrView); inTest.copy(cleartextSource, cleartextTarget, StandardCopyOption.COPY_ATTRIBUTES); verify(dstAttrView).setOwner(owner); @@ -649,8 +648,8 @@ public void moveDirectoryCopyPosixAttributes() throws IOException { PosixFileAttributeView dstAttrView = mock(PosixFileAttributeView.class); when(srcAttrs.group()).thenReturn(group); when(srcAttrs.permissions()).thenReturn(permissions); - when(physicalFsProv.readAttributes(Mockito.same(ciphertextSourceDir), Mockito.same(PosixFileAttributes.class), Mockito.anyVararg())).thenReturn(srcAttrs); - when(physicalFsProv.getFileAttributeView(Mockito.same(ciphertextTargetDir), Mockito.same(PosixFileAttributeView.class), Mockito.anyVararg())).thenReturn(dstAttrView); + when(physicalFsProv.readAttributes(Mockito.same(ciphertextSourceDir), Mockito.same(PosixFileAttributes.class), Mockito.any())).thenReturn(srcAttrs); + when(physicalFsProv.getFileAttributeView(Mockito.same(ciphertextTargetDir), Mockito.same(PosixFileAttributeView.class), Mockito.any())).thenReturn(dstAttrView); inTest.copy(cleartextSource, cleartextTarget, StandardCopyOption.COPY_ATTRIBUTES); verify(dstAttrView).setGroup(group); @@ -669,8 +668,8 @@ public void moveDirectoryCopyDosAttributes() throws IOException { when(srcAttrs.isHidden()).thenReturn(true); when(srcAttrs.isReadOnly()).thenReturn(true); when(srcAttrs.isSystem()).thenReturn(true); - when(physicalFsProv.readAttributes(Mockito.same(ciphertextSourceDir), Mockito.same(DosFileAttributes.class), Mockito.anyVararg())).thenReturn(srcAttrs); - when(physicalFsProv.getFileAttributeView(Mockito.same(ciphertextTargetDir), Mockito.same(DosFileAttributeView.class), Mockito.anyVararg())).thenReturn(dstAttrView); + when(physicalFsProv.readAttributes(Mockito.same(ciphertextSourceDir), Mockito.same(DosFileAttributes.class), Mockito.any())).thenReturn(srcAttrs); + when(physicalFsProv.getFileAttributeView(Mockito.same(ciphertextTargetDir), Mockito.same(DosFileAttributeView.class), Mockito.any())).thenReturn(dstAttrView); inTest.copy(cleartextSource, cleartextTarget, StandardCopyOption.COPY_ATTRIBUTES); verify(dstAttrView).setArchive(true); diff --git a/src/test/java/org/cryptomator/cryptofs/MoveOperationTest.java b/src/test/java/org/cryptomator/cryptofs/MoveOperationTest.java index 6db0e83f..7544f8e2 100644 --- a/src/test/java/org/cryptomator/cryptofs/MoveOperationTest.java +++ b/src/test/java/org/cryptomator/cryptofs/MoveOperationTest.java @@ -5,8 +5,8 @@ import static java.nio.file.StandardCopyOption.REPLACE_EXISTING; import static org.hamcrest.CoreMatchers.is; import static org.junit.Assert.assertThat; -import static org.mockito.Matchers.any; -import static org.mockito.Matchers.same; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.same; import static org.mockito.Mockito.doThrow; import static org.mockito.Mockito.inOrder; import static org.mockito.Mockito.mock; @@ -133,7 +133,6 @@ public void testMoveThrowsIOExceptionIfInvokedWithNonEmptyDirectory() throws IOE } @Test - @SuppressWarnings("unchecked") public void testMoveDoesNotThrowIOExceptionIfFileAttributesOfSourceCanNotBeRead() throws IOException { when(provider.readAttributes(aPathFromFsA, BasicFileAttributes.class)).thenThrow(IOException.class); diff --git a/src/test/java/org/cryptomator/cryptofs/WriteFileWhileReadonlyChannelIsOpenTest.java b/src/test/java/org/cryptomator/cryptofs/WriteFileWhileReadonlyChannelIsOpenTest.java index fba9e643..9c3a90c9 100644 --- a/src/test/java/org/cryptomator/cryptofs/WriteFileWhileReadonlyChannelIsOpenTest.java +++ b/src/test/java/org/cryptomator/cryptofs/WriteFileWhileReadonlyChannelIsOpenTest.java @@ -19,7 +19,7 @@ import com.google.common.jimfs.Jimfs; /** - * @see https://github.com/cryptomator/cryptofs/issues/10 + * @see CryptoFS issue 10 */ public class WriteFileWhileReadonlyChannelIsOpenTest { From 6f2d8914adaa3bbb0ab8b6e0c82f37699570eaeb Mon Sep 17 00:00:00 2001 From: Markus Kreusch Date: Tue, 25 Apr 2017 13:54:57 +0200 Subject: [PATCH 2/5] Increased test coverage --- .../CryptoFileSystemProviderTest.java | 101 +++++++++++++++++- 1 file changed, 100 insertions(+), 1 deletion(-) diff --git a/src/test/java/org/cryptomator/cryptofs/CryptoFileSystemProviderTest.java b/src/test/java/org/cryptomator/cryptofs/CryptoFileSystemProviderTest.java index e192a0c1..e0a9804d 100644 --- a/src/test/java/org/cryptomator/cryptofs/CryptoFileSystemProviderTest.java +++ b/src/test/java/org/cryptomator/cryptofs/CryptoFileSystemProviderTest.java @@ -4,12 +4,14 @@ import static java.nio.file.StandardOpenOption.APPEND; import static java.util.Arrays.asList; import static org.cryptomator.cryptofs.CryptoFileSystemProperties.cryptoFileSystemProperties; +import static org.cryptomator.cryptofs.CryptoFileSystemProvider.containsVault; +import static org.cryptomator.cryptofs.CryptoFileSystemProvider.newFileSystem; import static org.hamcrest.Matchers.instanceOf; import static org.hamcrest.Matchers.is; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertThat; import static org.junit.Assert.assertTrue; -import static org.mockito.Matchers.eq; +import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -25,6 +27,7 @@ import java.nio.file.DirectoryStream.Filter; import java.nio.file.FileStore; import java.nio.file.FileSystem; +import java.nio.file.Files; import java.nio.file.LinkOption; import java.nio.file.OpenOption; import java.nio.file.Path; @@ -39,6 +42,7 @@ import java.util.Set; import java.util.concurrent.ExecutorService; +import org.cryptomator.cryptolib.api.InvalidPassphraseException; import org.junit.Before; import org.junit.Rule; import org.junit.Test; @@ -51,6 +55,9 @@ import org.mockito.junit.MockitoJUnit; import org.mockito.junit.MockitoRule; +import com.google.common.jimfs.Configuration; +import com.google.common.jimfs.Jimfs; + @RunWith(Theories.class) public class CryptoFileSystemProviderTest { @@ -174,6 +181,98 @@ public void testNewFileSystemInvokesFileSystemsCreate() throws IOException { assertThat(result, is(cryptoFileSystem)); } + @Test + public void testContainsVaultReturnsTrueIfDirectoryContainsMasterkeyFileAndDataDir() throws IOException { + FileSystem fs = Jimfs.newFileSystem(Configuration.unix()); + + String masterkeyFilename = "masterkey.foo.baz"; + Path pathToVault = fs.getPath("/vaultDir"); + + Path masterkeyFile = pathToVault.resolve(masterkeyFilename); + Path dataDir = pathToVault.resolve("d"); + Files.createDirectories(dataDir); + Files.write(masterkeyFile, new byte[0]); + + assertTrue(containsVault(pathToVault, masterkeyFilename)); + } + + @Test + public void testContainsVaultReturnsFalseIfDirectoryContainsNoMasterkeyFileButDataDir() throws IOException { + FileSystem fs = Jimfs.newFileSystem(Configuration.unix()); + + String masterkeyFilename = "masterkey.foo.baz"; + Path pathToVault = fs.getPath("/vaultDir"); + + Path dataDir = pathToVault.resolve("d"); + Files.createDirectories(dataDir); + + assertFalse(containsVault(pathToVault, masterkeyFilename)); + } + + @Test + public void testContainsVaultReturnsFalseIfDirectoryContainsMasterkeyFileButNoDataDir() throws IOException { + FileSystem fs = Jimfs.newFileSystem(Configuration.unix()); + + String masterkeyFilename = "masterkey.foo.baz"; + Path pathToVault = fs.getPath("/vaultDir"); + + Path masterkeyFile = pathToVault.resolve(masterkeyFilename); + Files.createDirectories(pathToVault); + Files.write(masterkeyFile, new byte[0]); + + assertFalse(containsVault(pathToVault, masterkeyFilename)); + } + + @Test + public void testVaultWithChangedPassphraseCanBeOpenedWithNewPassphrase() throws IOException { + String oldPassphrase = "oldPassphrase838283"; + String newPassphrase = "newPassphrase954810921"; + String masterkeyFilename = "masterkey.foo.baz"; + FileSystem fs = Jimfs.newFileSystem(Configuration.unix()); + Path pathToVault = fs.getPath("/vaultDir"); + newFileSystem( // + pathToVault, // + cryptoFileSystemProperties() // + .withMasterkeyFilename(masterkeyFilename) // + .withPassphrase(oldPassphrase) // + .build()).close(); + + CryptoFileSystemProvider.changePassphrase(pathToVault, masterkeyFilename, oldPassphrase, newPassphrase); + + newFileSystem( // + pathToVault, // + cryptoFileSystemProperties() // + .withMasterkeyFilename(masterkeyFilename) // + .withPassphrase(newPassphrase) // + .build()).close(); + } + + @Test + public void testVaultWithChangedPassphraseCanNotBeOpenedWithOldPassphrase() throws IOException { + String oldPassphrase = "oldPassphrase838283"; + String newPassphrase = "newPassphrase954810921"; + String masterkeyFilename = "masterkey.foo.baz"; + FileSystem fs = Jimfs.newFileSystem(Configuration.unix()); + Path pathToVault = fs.getPath("/vaultDir"); + newFileSystem( // + pathToVault, // + cryptoFileSystemProperties() // + .withMasterkeyFilename(masterkeyFilename) // + .withPassphrase(oldPassphrase) // + .build()).close(); + + CryptoFileSystemProvider.changePassphrase(pathToVault, masterkeyFilename, oldPassphrase, newPassphrase); + + thrown.expect(InvalidPassphraseException.class); + + newFileSystem( // + pathToVault, // + cryptoFileSystemProperties() // + .withMasterkeyFilename(masterkeyFilename) // + .withPassphrase(oldPassphrase) // + .build()); + } + @Test public void testGetFileSystemInvokesFileSystemsGetWithPathToVaultFromUri() { Path pathToVault = get("a").toAbsolutePath(); From 533cb781aeb8b53e490767237f8f29a45221f246 Mon Sep 17 00:00:00 2001 From: Sebastian Stenzel Date: Wed, 26 Apr 2017 12:13:06 +0200 Subject: [PATCH 3/5] Fixes #13 --- .../cryptofs/CryptoDirectoryStream.java | 30 +++++++++++++++++-- .../cryptofs/CryptoPathMapper.java | 10 +++++-- .../cryptofs/DirectoryStreamFactory.java | 1 + .../org/cryptomator/cryptofs/GlobToRegex.java | 2 -- .../cryptofs/CryptoDirectoryStreamTest.java | 26 +++++++++++++--- 5 files changed, 58 insertions(+), 11 deletions(-) diff --git a/src/main/java/org/cryptomator/cryptofs/CryptoDirectoryStream.java b/src/main/java/org/cryptomator/cryptofs/CryptoDirectoryStream.java index 4492cff2..4d590a5d 100644 --- a/src/main/java/org/cryptomator/cryptofs/CryptoDirectoryStream.java +++ b/src/main/java/org/cryptomator/cryptofs/CryptoDirectoryStream.java @@ -37,14 +37,15 @@ class CryptoDirectoryStream implements DirectoryStream { private final DirectoryStream ciphertextDirStream; private final Path cleartextDir; private final FileNameCryptor filenameCryptor; + private final CryptoPathMapper cryptoPathMapper; private final LongFileNameProvider longFileNameProvider; private final ConflictResolver conflictResolver; private final DirectoryStream.Filter filter; private final Consumer onClose; private final FinallyUtil finallyUtil; - public CryptoDirectoryStream(Directory ciphertextDir, Path cleartextDir, FileNameCryptor filenameCryptor, LongFileNameProvider longFileNameProvider, ConflictResolver conflictResolver, - DirectoryStream.Filter filter, Consumer onClose, FinallyUtil finallyUtil) throws IOException { + public CryptoDirectoryStream(Directory ciphertextDir, Path cleartextDir, FileNameCryptor filenameCryptor, CryptoPathMapper cryptoPathMapper, LongFileNameProvider longFileNameProvider, + ConflictResolver conflictResolver, DirectoryStream.Filter filter, Consumer onClose, FinallyUtil finallyUtil) throws IOException { this.onClose = onClose; this.finallyUtil = finallyUtil; this.directoryId = ciphertextDir.dirId; @@ -52,6 +53,7 @@ public CryptoDirectoryStream(Directory ciphertextDir, Path cleartextDir, FileNam LOG.trace("OPEN " + directoryId); this.cleartextDir = cleartextDir; this.filenameCryptor = filenameCryptor; + this.cryptoPathMapper = cryptoPathMapper; this.longFileNameProvider = longFileNameProvider; this.conflictResolver = conflictResolver; this.filter = filter; @@ -62,7 +64,8 @@ public Iterator iterator() { Stream pathIter = StreamSupport.stream(ciphertextDirStream.spliterator(), false); Stream resolved = pathIter.map(this::resolveConflictingFileIfNeeded).filter(Objects::nonNull); Stream inflated = resolved.map(this::inflateIfNeeded).filter(Objects::nonNull); - Stream decrypted = inflated.map(this::decrypt).filter(Objects::nonNull); + Stream sanitized = inflated.filter(this::passesPlausibilityChecks); + Stream decrypted = sanitized.map(this::decrypt).filter(Objects::nonNull); Stream filtered = decrypted.filter(this::isAcceptableByFilter); return filtered.iterator(); } @@ -91,6 +94,27 @@ private Path inflateIfNeeded(Path ciphertextPath) { } } + private boolean passesPlausibilityChecks(Path ciphertextPath) { + return !isBrokenDirectoryFile(ciphertextPath); + } + + private boolean isBrokenDirectoryFile(Path potentialDirectoryFile) { + if (potentialDirectoryFile.getFileName().toString().startsWith(Constants.DIR_PREFIX)) { + Path dirPath; + try { + dirPath = cryptoPathMapper.resolveDirectory(potentialDirectoryFile).path; + } catch (IOException e) { + LOG.warn("Broken directory file {}. Exception: {}", potentialDirectoryFile, e.getMessage()); + return true; + } + if (!Files.isDirectory(dirPath)) { + LOG.warn("Broken directory file {}. Directory {} does not exist.", potentialDirectoryFile, dirPath); + return true; + } + } + return false; + } + private Path decrypt(Path ciphertextPath) { String ciphertextFileName = ciphertextPath.getFileName().toString(); Matcher m = BASE32_PATTERN.matcher(ciphertextFileName); diff --git a/src/main/java/org/cryptomator/cryptofs/CryptoPathMapper.java b/src/main/java/org/cryptomator/cryptofs/CryptoPathMapper.java index 740f1288..39ed7e0d 100644 --- a/src/main/java/org/cryptomator/cryptofs/CryptoPathMapper.java +++ b/src/main/java/org/cryptomator/cryptofs/CryptoPathMapper.java @@ -85,11 +85,17 @@ public Directory getCiphertextDir(CryptoPath cleartextPath) throws IOException { Directory parent = getCiphertextDir(parentPath); String cleartextName = cleartextPath.getFileName().toString(); String ciphertextName = getCiphertextFileName(parent.dirId, cleartextName, CiphertextFileType.DIRECTORY); - String dirId = dirIdProvider.load(parent.path.resolve(ciphertextName)); - return new Directory(dirId, directoryPathCache.getUnchecked(dirId)); + Path dirIdFile = parent.path.resolve(ciphertextName); + return resolveDirectory(dirIdFile); } } + public Directory resolveDirectory(Path directoryFile) throws IOException { + String dirId = dirIdProvider.load(directoryFile); + Path dirPath = directoryPathCache.getUnchecked(dirId); + return new Directory(dirId, dirPath); + } + private Path resolveDirectory(String dirId) { String dirHash = cryptor.fileNameCryptor().hashDirectoryId(dirId); return dataRoot.resolve(dirHash.substring(0, 2)).resolve(dirHash.substring(2)); diff --git a/src/main/java/org/cryptomator/cryptofs/DirectoryStreamFactory.java b/src/main/java/org/cryptomator/cryptofs/DirectoryStreamFactory.java index bb5d52ee..e3f88c1b 100644 --- a/src/main/java/org/cryptomator/cryptofs/DirectoryStreamFactory.java +++ b/src/main/java/org/cryptomator/cryptofs/DirectoryStreamFactory.java @@ -41,6 +41,7 @@ public DirectoryStream newDirectoryStream(CryptoPath cleartextDir, Filter< ciphertextDir, // cleartextDir, // cryptor.fileNameCryptor(), // + cryptoPathMapper, // longFileNameProvider, // conflictResolver, // filter, // diff --git a/src/main/java/org/cryptomator/cryptofs/GlobToRegex.java b/src/main/java/org/cryptomator/cryptofs/GlobToRegex.java index a43e29a4..a19c254e 100644 --- a/src/main/java/org/cryptomator/cryptofs/GlobToRegex.java +++ b/src/main/java/org/cryptomator/cryptofs/GlobToRegex.java @@ -40,14 +40,12 @@ class GlobToRegex { * Basic conversions (assuming / as only separator): * *
-	 * {@code
 	 * ?        = [^/]
 	 * *        = [^/]*
 	 * **       = .*
 	 * [a-z]    = [[^/]&&[a-z]]
 	 * [!a-z]   = [[^/]&&[^a-z]]
 	 * {a,b,c}  = (a|b|c)
-	 * }
 	 * 
*/ public static String toRegex(String glob, char separator) { diff --git a/src/test/java/org/cryptomator/cryptofs/CryptoDirectoryStreamTest.java b/src/test/java/org/cryptomator/cryptofs/CryptoDirectoryStreamTest.java index 60009ba1..c2a306aa 100644 --- a/src/test/java/org/cryptomator/cryptofs/CryptoDirectoryStreamTest.java +++ b/src/test/java/org/cryptomator/cryptofs/CryptoDirectoryStreamTest.java @@ -19,6 +19,7 @@ import java.nio.file.FileSystem; import java.nio.file.Path; import java.nio.file.Paths; +import java.nio.file.attribute.BasicFileAttributes; import java.nio.file.spi.FileSystemProvider; import java.util.ArrayList; import java.util.Iterator; @@ -57,6 +58,7 @@ public static void setupClass() { private FileNameCryptor filenameCryptor; private Path ciphertextDirPath; private DirectoryStream dirStream; + private CryptoPathMapper cryptoPathMapper; private LongFileNameProvider longFileNameProvider; private ConflictResolver conflictResolver; private FinallyUtil finallyUtil; @@ -84,6 +86,20 @@ public void setup() throws IOException { return StringUtils.removeEnd(shortName, ".lng"); } }); + cryptoPathMapper = Mockito.mock(CryptoPathMapper.class); + Mockito.when(cryptoPathMapper.resolveDirectory(Mockito.any())).then(invocation -> { + Path dirFilePath = invocation.getArgument(0); + if (dirFilePath.toString().contains("invalid")) { + throw new IOException("Invalid directory."); + } + Path dirPath = Mockito.mock(Path.class); + BasicFileAttributes attrs = Mockito.mock(BasicFileAttributes.class); + Mockito.when(dirPath.getFileSystem()).thenReturn(fs); + Mockito.when(provider.readAttributes(dirPath, BasicFileAttributes.class)).thenReturn(attrs); + Mockito.when(attrs.isDirectory()).thenReturn(!dirFilePath.toString().contains("noDirectory")); + return new Directory("asdf", dirPath); + }); + Mockito.when(conflictResolver.resolveConflictsIfNecessary(Mockito.any(), Mockito.any())).then(returnsFirstArg()); doAnswer(invocation -> { @@ -102,14 +118,16 @@ public void testDirListing() throws IOException { ciphertextFileNames.add(filenameCryptor.encryptFilename("one", "foo".getBytes())); ciphertextFileNames.add(filenameCryptor.encryptFilename("two", "foo".getBytes()) + "_conflict"); ciphertextFileNames.add("0" + filenameCryptor.encryptFilename("three", "foo".getBytes())); + ciphertextFileNames.add("0invalidDirectory"); + ciphertextFileNames.add("0noDirectory"); ciphertextFileNames.add("invalidLongName.lng"); ciphertextFileNames.add(filenameCryptor.encryptFilename("four", "foo".getBytes()) + ".lng"); ciphertextFileNames.add(filenameCryptor.encryptFilename("invalid", "bar".getBytes())); ciphertextFileNames.add("alsoInvalid"); Mockito.when(dirStream.spliterator()).thenReturn(ciphertextFileNames.stream().map(cleartextPath::resolve).spliterator()); - try (CryptoDirectoryStream stream = new CryptoDirectoryStream(new Directory("foo", ciphertextDirPath), cleartextPath, filenameCryptor, longFileNameProvider, conflictResolver, ACCEPT_ALL, DO_NOTHING_ON_CLOSE, - finallyUtil)) { + try (CryptoDirectoryStream stream = new CryptoDirectoryStream(new Directory("foo", ciphertextDirPath), cleartextPath, filenameCryptor, cryptoPathMapper, longFileNameProvider, conflictResolver, ACCEPT_ALL, + DO_NOTHING_ON_CLOSE, finallyUtil)) { Iterator iter = stream.iterator(); Assert.assertTrue(iter.hasNext()); Assert.assertEquals(cleartextPath.resolve("one"), iter.next()); @@ -131,8 +149,8 @@ public void testDirListingForEmptyDir() throws IOException { Mockito.when(dirStream.spliterator()).thenReturn(Spliterators.emptySpliterator()); - try (CryptoDirectoryStream stream = new CryptoDirectoryStream(new Directory("foo", ciphertextDirPath), cleartextPath, filenameCryptor, longFileNameProvider, conflictResolver, ACCEPT_ALL, DO_NOTHING_ON_CLOSE, - finallyUtil)) { + try (CryptoDirectoryStream stream = new CryptoDirectoryStream(new Directory("foo", ciphertextDirPath), cleartextPath, filenameCryptor, cryptoPathMapper, longFileNameProvider, conflictResolver, ACCEPT_ALL, + DO_NOTHING_ON_CLOSE, finallyUtil)) { Iterator iter = stream.iterator(); Assert.assertFalse(iter.hasNext()); iter.next(); From e0a2e611caa7d94656aeb80cf843ab4d2b7d4549 Mon Sep 17 00:00:00 2001 From: Sebastian Stenzel Date: Wed, 26 Apr 2017 12:15:25 +0200 Subject: [PATCH 4/5] clearify, that variable can not be null [ci skip] --- .../java/org/cryptomator/cryptofs/CryptoDirectoryStream.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/cryptomator/cryptofs/CryptoDirectoryStream.java b/src/main/java/org/cryptomator/cryptofs/CryptoDirectoryStream.java index 4d590a5d..788a4b5f 100644 --- a/src/main/java/org/cryptomator/cryptofs/CryptoDirectoryStream.java +++ b/src/main/java/org/cryptomator/cryptofs/CryptoDirectoryStream.java @@ -100,7 +100,7 @@ private boolean passesPlausibilityChecks(Path ciphertextPath) { private boolean isBrokenDirectoryFile(Path potentialDirectoryFile) { if (potentialDirectoryFile.getFileName().toString().startsWith(Constants.DIR_PREFIX)) { - Path dirPath; + final Path dirPath; try { dirPath = cryptoPathMapper.resolveDirectory(potentialDirectoryFile).path; } catch (IOException e) { From 878a4a9d0670fed92ea4abfeac2cbaa6d012d224 Mon Sep 17 00:00:00 2001 From: Sebastian Stenzel Date: Wed, 26 Apr 2017 13:35:59 +0200 Subject: [PATCH 5/5] Preparing release 1.2.2 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index a58be596..e5d084a2 100644 --- a/pom.xml +++ b/pom.xml @@ -2,7 +2,7 @@ 4.0.0 org.cryptomator cryptofs - 1.3.0-SNAPSHOT + 1.2.2 Cryptomator Crypto Filesystem This library provides the Java filesystem provider used by Cryptomator. https://github.com/cryptomator/cryptofs