Skip to content

Commit

Permalink
Merge branch 'release/2.5.3'
Browse files Browse the repository at this point in the history
  • Loading branch information
infeo committed Dec 6, 2022
2 parents e1e07f3 + 4b9c122 commit ae19036
Show file tree
Hide file tree
Showing 4 changed files with 65 additions and 10 deletions.
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
<modelVersion>4.0.0</modelVersion>
<groupId>org.cryptomator</groupId>
<artifactId>cryptofs</artifactId>
<version>2.5.2</version>
<version>2.5.3</version>
<name>Cryptomator Crypto Filesystem</name>
<description>This library provides the Java filesystem provider used by Cryptomator.</description>
<url>https://github.com/cryptomator/cryptofs</url>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,6 @@ public synchronized CryptoDirectoryStream newDirectoryStream(CryptoPath cleartex
throw new ClosedFileSystemException();
}
CiphertextDirectory ciphertextDir = cryptoPathMapper.getCiphertextDir(cleartextDir);
//TODO: use HealthCheck with warning and suggest fix to create one
DirectoryStream<Path> ciphertextDirStream = Files.newDirectoryStream(ciphertextDir.path, this::matchesEncryptedContentPattern);
CryptoDirectoryStream cleartextDirStream = directoryStreamComponentBuilder //
.dirId(ciphertextDir.dirId) //
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ private void fix(Path pathToVault, VaultConfig config, Cryptor cryptor) throws I
String longNameSuffix = createClearnameToBeShortened(config.getShorteningThreshold());
Optional<String> dirId = retrieveDirId(orphanedDir, cryptor);

try (var orphanedContentStream = Files.newDirectoryStream(orphanedDir, p -> !Constants.DIR_BACKUP_FILE_NAME.equals(p.getFileName().toString()))) {
try (var orphanedContentStream = Files.newDirectoryStream(orphanedDir, this::matchesEncryptedContentPattern)) {
for (Path orphanedResource : orphanedContentStream) {
boolean isShortened = orphanedResource.toString().endsWith(Constants.DEFLATED_FILE_SUFFIX);
//@formatter:off
Expand All @@ -112,11 +112,22 @@ private void fix(Path pathToVault, VaultConfig config, Cryptor cryptor) throws I
adoptOrphanedResource(orphanedResource, newClearName, isShortened, stepParentDir, cryptor.fileNameCryptor(), sha1);
}
}

Files.deleteIfExists(orphanedDir.resolve(Constants.DIR_BACKUP_FILE_NAME));
try (var nonCryptomatorFiles = Files.newDirectoryStream(orphanedDir)) {
for (Path p : nonCryptomatorFiles) {
Files.move(p, stepParentDir.path.resolve(p.getFileName()), LinkOption.NOFOLLOW_LINKS);
}
}
Files.delete(orphanedDir);
}

//see also DirectoryStreamFactory
private boolean matchesEncryptedContentPattern(Path path) {
var tmp = path.getFileName().toString();
return tmp.length() >= Constants.MIN_CIPHER_NAME_LENGTH //
&& (tmp.endsWith(Constants.CRYPTOMATOR_FILE_SUFFIX) || tmp.endsWith(Constants.DEFLATED_FILE_SUFFIX));
}

//visible for testing
Path prepareRecoveryDir(Path pathToVault, FileNameCryptor cryptor) throws IOException {
Path dataDir = pathToVault.resolve(Constants.DATA_DIR_NAME);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -405,8 +405,8 @@ public void testFixNoDirId() throws IOException {
result = new OrphanContentDir(dataDir.relativize(cipherOrphan));
var resultSpy = Mockito.spy(result);

Path orphan1 = cipherOrphan.resolve("orphan1.c9r");
Path orphan2 = cipherOrphan.resolve("orphan2.c9s");
Path orphan1 = cipherOrphan.resolve("orphan1_with_at_least_26chars.c9r");
Path orphan2 = cipherOrphan.resolve("orphan2_with_at_least_26chars.c9s");
Files.createFile(orphan1);
Files.createDirectories(orphan2);

Expand Down Expand Up @@ -435,8 +435,8 @@ public void testFixContinuesOnNotRecoverableFilename() throws IOException {
result = new OrphanContentDir(dataDir.relativize(cipherOrphan));
var resultSpy = Mockito.spy(result);

Path orphan1 = cipherOrphan.resolve("orphan1.c9r");
Path orphan2 = cipherOrphan.resolve("orphan2.c9s");
Path orphan1 = cipherOrphan.resolve("orphan1_with_at_least_26chars.c9r");
Path orphan2 = cipherOrphan.resolve("orphan2_with_at_least_26chars.c9s");
Files.createFile(orphan1);
Files.createDirectories(orphan2);
Files.createFile(cipherOrphan.resolve(Constants.DIR_BACKUP_FILE_NAME));
Expand Down Expand Up @@ -473,9 +473,9 @@ public void testFixWithDirId() throws IOException {
var resultSpy = Mockito.spy(result);

var lostName1 = "Brother.sibling";
Path orphan1 = cipherOrphan.resolve("orphan1.c9r");
Path orphan1 = cipherOrphan.resolve("orphan1_with_at_least_26chars.c9r");
var lostName2 = "Sister.sibling";
Path orphan2 = cipherOrphan.resolve("orphan2.c9s");
Path orphan2 = cipherOrphan.resolve("orphan2_with_at_least_26chars.c9s");
Files.createFile(orphan1);
Files.createDirectories(orphan2);
Files.createFile(cipherOrphan.resolve(Constants.DIR_BACKUP_FILE_NAME));
Expand Down Expand Up @@ -507,6 +507,51 @@ public void testFixWithDirId() throws IOException {
Assertions.assertTrue(Files.notExists(cipherOrphan));
}

@Test
@DisplayName("fix() prepares vault, process every Cryptomator resource in orphanDir, moves non-Cryptomator resources and deletes orphanDir")
public void testFixWithNonCryptomatorFiles() throws IOException {
result = new OrphanContentDir(dataDir.relativize(cipherOrphan));
var resultSpy = Mockito.spy(result);

var lostName1 = "Brother.sibling";
Path orphan1 = cipherOrphan.resolve("orphan1_with_at_least_26chars.c9r");
var lostName2 = "Sister.sibling";
Path orphan2 = cipherOrphan.resolve("orphan2_with_at_least_26chars.c9s");
Path unrelated = cipherOrphan.resolve("unrelated.file");
Files.createFile(orphan1);
Files.createDirectories(orphan2);
Files.createFile(unrelated);
Files.createFile(cipherOrphan.resolve(Constants.DIR_BACKUP_FILE_NAME));

var dirId = Optional.of("trololo-id");

CryptoPathMapper.CiphertextDirectory stepParentDir = new CryptoPathMapper.CiphertextDirectory("aaaaaa", dataDir.resolve("22/2222"));
Files.createDirectories(stepParentDir.path); //needs to be created here, otherwise the Files.move(non-crypto-resource, stepparent) will fail

VaultConfig config = Mockito.mock(VaultConfig.class);
Mockito.doReturn(170).when(config).getShorteningThreshold();
Masterkey masterkey = Mockito.mock(Masterkey.class);

Mockito.doReturn(cipherRecovery).when(resultSpy).prepareRecoveryDir(pathToVault, fileNameCryptor);
Mockito.doReturn(stepParentDir).when(resultSpy).prepareStepParent(Mockito.eq(dataDir), Mockito.eq(cipherRecovery), Mockito.eq(cryptor), Mockito.any());
Mockito.doReturn(dirId).when(resultSpy).retrieveDirId(cipherOrphan, cryptor);
Mockito.doReturn(lostName1).when(resultSpy).decryptFileName(Mockito.eq(orphan1), Mockito.anyBoolean(), Mockito.eq(dirId.get()), Mockito.eq(fileNameCryptor));
Mockito.doReturn(lostName2).when(resultSpy).decryptFileName(Mockito.eq(orphan2), Mockito.anyBoolean(), Mockito.eq(dirId.get()), Mockito.eq(fileNameCryptor));
Mockito.doAnswer(invocationOnMock -> {
Path orphanedResource = invocationOnMock.getArgument(0);
Files.delete(orphanedResource);
return null;
}).when(resultSpy).adoptOrphanedResource(Mockito.any(), Mockito.any(), Mockito.anyBoolean(), Mockito.eq(stepParentDir), Mockito.eq(fileNameCryptor), Mockito.any());

resultSpy.fix(pathToVault, config, masterkey, cryptor);

Mockito.verify(resultSpy, Mockito.never()).adoptOrphanedResource(Mockito.eq(unrelated), Mockito.any(), Mockito.anyBoolean(), Mockito.eq(stepParentDir), Mockito.eq(fileNameCryptor), Mockito.any());
Mockito.verify(resultSpy, Mockito.times(1)).adoptOrphanedResource(Mockito.eq(orphan1), Mockito.eq(lostName1), Mockito.anyBoolean(), Mockito.eq(stepParentDir), Mockito.eq(fileNameCryptor), Mockito.any());
Mockito.verify(resultSpy, Mockito.times(1)).adoptOrphanedResource(Mockito.eq(orphan2), Mockito.eq(lostName2), Mockito.anyBoolean(), Mockito.eq(stepParentDir), Mockito.eq(fileNameCryptor), Mockito.any());
Assertions.assertTrue(Files.exists(stepParentDir.path.resolve("unrelated.file")));
Assertions.assertTrue(Files.notExists(cipherOrphan));
}


@Test
@DisplayName("results with same orphan write to same cleartext stepparent")
Expand Down

0 comments on commit ae19036

Please sign in to comment.