Skip to content

Commit

Permalink
added test case hitting shortening threshold
Browse files Browse the repository at this point in the history
  • Loading branch information
overheadhunter committed Apr 16, 2021
1 parent bbc3c86 commit 9eba1d9
Show file tree
Hide file tree
Showing 2 changed files with 26 additions and 21 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -35,13 +35,15 @@ class C9rConflictResolver {

private final Cryptor cryptor;
private final byte[] dirId;
private final VaultConfig vaultConfig;
private final int maxC9rFileNameLength;
private final int maxCleartextFileNameLength;

@Inject
public C9rConflictResolver(Cryptor cryptor, @Named("dirId") String dirId, VaultConfig vaultConfig) {
this.cryptor = cryptor;
this.dirId = dirId.getBytes(StandardCharsets.US_ASCII);
this.vaultConfig = vaultConfig;
this.maxC9rFileNameLength = vaultConfig.getShorteningThreshold();
this.maxCleartextFileNameLength = (maxC9rFileNameLength - 4) / 4 * 3 - 16; // math from FileSystemCapabilityChecker.determineSupportedCleartextFileNameLength()
}

public Stream<Node> process(Node node) {
Expand Down Expand Up @@ -80,13 +82,6 @@ private Stream<Node> resolveConflict(Node conflicting, Path canonicalPath) throw
}
}

// visible for testing
int calcMaxCleartextNameLength(int maxCiphertextNameLength) {
// math explained in https://github.com/cryptomator/cryptofs/issues/60#issuecomment-523238303;
// subtract 4 for file extension, base64-decode, subtract 16 for IV
return (maxCiphertextNameLength - 4) / 4 * 3 - 16;
}

/**
* Resolves a conflict by renaming the conflicting file.
*
Expand All @@ -99,11 +94,9 @@ int calcMaxCleartextNameLength(int maxCiphertextNameLength) {
private Node renameConflictingFile(Path canonicalPath, Path conflictingPath, String cleartext) throws IOException {
assert Files.exists(canonicalPath);
final int beginOfFileExtension = cleartext.lastIndexOf('.');
final int maxCiphertextNameLength = vaultConfig.getShorteningThreshold();
final int maxCleartextNameLength = calcMaxCleartextNameLength(maxCiphertextNameLength);
final String fileExtension = (beginOfFileExtension > 0) ? cleartext.substring(beginOfFileExtension) : "";
final String basename = (beginOfFileExtension > 0) ? cleartext.substring(0, beginOfFileExtension) : cleartext;
final String lengthRestrictedBasename = basename.substring(0, Math.min(basename.length(), maxCleartextNameLength - fileExtension.length() - 5)); // 5 chars for conflict suffix " (42)"
final String lengthRestrictedBasename = basename.substring(0, Math.min(basename.length(), maxCleartextFileNameLength - fileExtension.length() - 5)); // 5 chars for conflict suffix " (42)"
String alternativeCleartext;
String alternativeCiphertext;
String alternativeCiphertextName;
Expand All @@ -115,7 +108,7 @@ private Node renameConflictingFile(Path canonicalPath, Path conflictingPath, Str
alternativeCiphertextName = alternativeCiphertext + Constants.CRYPTOMATOR_FILE_SUFFIX;
alternativePath = canonicalPath.resolveSibling(alternativeCiphertextName);
} while (Files.exists(alternativePath));
assert alternativeCiphertextName.length() <= maxCiphertextNameLength;
assert alternativeCiphertextName.length() <= maxC9rFileNameLength;
LOG.info("Moving conflicting file {} to {}", conflictingPath, alternativePath);
Files.move(conflictingPath, alternativePath, StandardCopyOption.ATOMIC_MOVE);
Node node = new Node(alternativePath);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ public void setup() {
fileNameCryptor = Mockito.mock(FileNameCryptor.class);
vaultConfig = Mockito.mock(VaultConfig.class);
Mockito.when(cryptor.fileNameCryptor()).thenReturn(fileNameCryptor);
Mockito.when(vaultConfig.getShorteningThreshold()).thenReturn(220);
Mockito.when(vaultConfig.getShorteningThreshold()).thenReturn(44); // results in max cleartext size = 14
conflictResolver = new C9rConflictResolver(cryptor, "foo", vaultConfig);
}

Expand Down Expand Up @@ -77,6 +77,25 @@ public void testResolveConflictingFileByChoosingNewName(@TempDir Path dir) throw
Assertions.assertFalse(Files.exists(unresolved.ciphertextPath));
}

@Test
public void testResolveConflictingFileByChoosingNewLengthLimitedName(@TempDir Path dir) throws IOException {
Files.createFile(dir.resolve("foo (1).c9r"));
Files.createFile(dir.resolve("foo.c9r"));
Mockito.when(fileNameCryptor.encryptFilename(Mockito.any(), Mockito.any(), Mockito.any())).thenReturn("baz");
Node unresolved = new Node(dir.resolve("foo (1).c9r"));
unresolved.cleartextName = "hello world.txt";
unresolved.extractedCiphertext = "foo";

Stream<Node> result = conflictResolver.process(unresolved);
Node resolved = result.findAny().get();

Assertions.assertNotEquals(unresolved, resolved);
Assertions.assertEquals("baz.c9r", resolved.fullCiphertextFileName);
Assertions.assertEquals("hello (1).txt", resolved.cleartextName);
Assertions.assertTrue(Files.exists(resolved.ciphertextPath));
Assertions.assertFalse(Files.exists(unresolved.ciphertextPath));
}

@Test
public void testResolveConflictingFileTrivially(@TempDir Path dir) throws IOException {
Files.createFile(dir.resolve("foo (1).c9r"));
Expand Down Expand Up @@ -131,11 +150,4 @@ public void testResolveConflictingSymlinkTrivially(@TempDir Path dir) throws IOE
Assertions.assertFalse(Files.exists(unresolved.ciphertextPath));
}

@ParameterizedTest
@CsvSource({"220, 146", "219, 143", "218, 143", "217, 143", "216, 143", "215, 140"})
public void testCalcMaxCleartextNameLength(int input, int expectedResult) {
int result = conflictResolver.calcMaxCleartextNameLength(input);
Assertions.assertEquals(expectedResult, result);
}

}

0 comments on commit 9eba1d9

Please sign in to comment.