Skip to content

Commit 1fe8036

Browse files
committed
Merge branch 'release/2.6.0'
2 parents ae19036 + 665ef9f commit 1fe8036

4 files changed

Lines changed: 116 additions & 6 deletions

File tree

pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
<modelVersion>4.0.0</modelVersion>
33
<groupId>org.cryptomator</groupId>
44
<artifactId>cryptofs</artifactId>
5-
<version>2.5.3</version>
5+
<version>2.6.0</version>
66
<name>Cryptomator Crypto Filesystem</name>
77
<description>This library provides the Java filesystem provider used by Cryptomator.</description>
88
<url>https://github.com/cryptomator/cryptofs</url>

src/main/java/org/cryptomator/cryptofs/CryptoFileSystem.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package org.cryptomator.cryptofs;
22

3+
import java.io.IOException;
34
import java.nio.file.FileSystem;
45
import java.nio.file.Files;
56
import java.nio.file.Path;
@@ -29,6 +30,17 @@ public abstract class CryptoFileSystem extends FileSystem {
2930
*/
3031
public abstract Path getPathToVault();
3132

33+
/**
34+
* Provides the {@link Path} to the (data) ciphertext from a given cleartext path.
35+
*
36+
* @param cleartextPath absolute path to the cleartext file or folder belonging to this {@link CryptoFileSystem}. Internally the path must be an instance of {@link CryptoPath}
37+
* @return the {@link Path} to ciphertext file or folder containing teh actual encrypted data
38+
* @throws java.nio.file.ProviderMismatchException if the cleartext path does not belong to this CryptoFileSystem
39+
* @throws java.nio.file.NoSuchFileException if for the cleartext path no ciphertext resource exists
40+
* @throws IOException if an I/O error occurs looking for the ciphertext resource
41+
*/
42+
public abstract Path getCiphertextPath(Path cleartextPath) throws IOException;
43+
3244
/**
3345
* Provides file system performance statistics.
3446
*

src/main/java/org/cryptomator/cryptofs/CryptoFileSystemImpl.java

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,20 @@ public Path getPathToVault() {
136136
return pathToVault;
137137
}
138138

139+
@Override
140+
public Path getCiphertextPath(Path cleartextPath) throws IOException {
141+
var p = CryptoPath.castAndAssertAbsolute(cleartextPath);
142+
var nodeType = cryptoPathMapper.getCiphertextFileType(p);
143+
var cipherFile = cryptoPathMapper.getCiphertextFilePath(p);
144+
if( nodeType == CiphertextFileType.DIRECTORY) {
145+
return cryptoPathMapper.getCiphertextDir(p).path;
146+
} else if( nodeType == CiphertextFileType.SYMLINK) {
147+
return cipherFile.getSymlinkFilePath();
148+
} else {
149+
return cipherFile.getFilePath();
150+
}
151+
}
152+
139153
@Override
140154
public CryptoFileSystemStats getStats() {
141155
return stats;

src/test/java/org/cryptomator/cryptofs/CryptoFileSystemImplTest.java

Lines changed: 89 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242
import java.nio.file.NoSuchFileException;
4343
import java.nio.file.Path;
4444
import java.nio.file.PathMatcher;
45+
import java.nio.file.ProviderMismatchException;
4546
import java.nio.file.StandardCopyOption;
4647
import java.nio.file.StandardOpenOption;
4748
import java.nio.file.attribute.BasicFileAttributeView;
@@ -119,11 +120,11 @@ public void setup() {
119120

120121
when(fileSystemProperties.maxCleartextNameLength()).thenReturn(32768);
121122

122-
inTest = new CryptoFileSystemImpl(provider, cryptoFileSystems, pathToVault, cryptor,
123-
fileStore, stats, cryptoPathMapper, cryptoPathFactory,
124-
pathMatcherFactory, directoryStreamFactory, dirIdProvider, dirIdBackup,
125-
fileAttributeProvider, fileAttributeByNameProvider, fileAttributeViewProvider,
126-
openCryptoFiles, symlinks, finallyUtil, ciphertextDirDeleter, readonlyFlag,
123+
inTest = new CryptoFileSystemImpl(provider, cryptoFileSystems, pathToVault, cryptor, //
124+
fileStore, stats, cryptoPathMapper, cryptoPathFactory, //
125+
pathMatcherFactory, directoryStreamFactory, dirIdProvider, dirIdBackup, //
126+
fileAttributeProvider, fileAttributeByNameProvider, fileAttributeViewProvider, //
127+
openCryptoFiles, symlinks, finallyUtil, ciphertextDirDeleter, readonlyFlag, //
127128
fileSystemProperties);
128129
}
129130

@@ -188,6 +189,89 @@ public void testGetFileStoresReturnsFileStore() {
188189
Assertions.assertSame(fileStore, inTest.getFileStore());
189190
}
190191

192+
@Nested
193+
public class PathToDataCiphertext {
194+
195+
@Test
196+
@DisplayName("Getting data ciphertext path of directory returns ciphertext content dir")
197+
public void testCleartextDirectory() throws IOException {
198+
Path ciphertext = Mockito.mock(Path.class, "/d/AB/CD...XYZ/");
199+
Path cleartext = inTest.getPath("/");
200+
try (var cryptoPathMock = Mockito.mockStatic(CryptoPath.class)) {
201+
cryptoPathMock.when(() -> CryptoPath.castAndAssertAbsolute(any())).thenReturn(cleartext);
202+
when(cryptoPathMapper.getCiphertextFileType(any())).thenReturn(CiphertextFileType.DIRECTORY);
203+
when(cryptoPathMapper.getCiphertextDir(any())).thenReturn(new CiphertextDirectory("foo", ciphertext));
204+
205+
Path result = inTest.getCiphertextPath(cleartext);
206+
Assertions.assertEquals(ciphertext, result);
207+
}
208+
}
209+
210+
@Test
211+
@DisplayName("Getting data ciphertext path of file returns ciphertext file")
212+
public void testCleartextFile() throws IOException {
213+
Path ciphertext = Mockito.mock(Path.class, "/d/AB/CD..XYZ/foo.c9r");
214+
Path cleartext = inTest.getPath("/foo.bar");
215+
try (var cryptoPathMock = Mockito.mockStatic(CryptoPath.class)) {
216+
CiphertextFilePath p = Mockito.mock(CiphertextFilePath.class);
217+
cryptoPathMock.when(() -> CryptoPath.castAndAssertAbsolute(any())).thenReturn(cleartext);
218+
when(cryptoPathMapper.getCiphertextFileType(any())).thenReturn(CiphertextFileType.FILE);
219+
when(cryptoPathMapper.getCiphertextFilePath(any())).thenReturn(p);
220+
when(p.getFilePath()).thenReturn(ciphertext);
221+
222+
Path result = inTest.getCiphertextPath(cleartext);
223+
Assertions.assertEquals(ciphertext, result);
224+
}
225+
}
226+
227+
@Test
228+
@DisplayName("Getting data ciphertext path of symlink returns ciphertext symlink.c9r")
229+
public void testCleartextSymlink() throws IOException {
230+
Path ciphertext = Mockito.mock(Path.class, "/d/AB/CD..XYZ/foo.c9s/symlink.c9r");
231+
Path cleartext = inTest.getPath("/foo.bar");
232+
try (var cryptoPathMock = Mockito.mockStatic(CryptoPath.class)) {
233+
CiphertextFilePath p = Mockito.mock(CiphertextFilePath.class);
234+
cryptoPathMock.when(() -> CryptoPath.castAndAssertAbsolute(any())).thenReturn(cleartext);
235+
when(cryptoPathMapper.getCiphertextFileType(any())).thenReturn(CiphertextFileType.SYMLINK);
236+
when(cryptoPathMapper.getCiphertextFilePath(any())).thenReturn(p);
237+
when(p.getSymlinkFilePath()).thenReturn(ciphertext);
238+
239+
Path result = inTest.getCiphertextPath(cleartext);
240+
Assertions.assertEquals(ciphertext, result);
241+
}
242+
}
243+
244+
@Test
245+
@DisplayName("Path not pointing into the vault throws exception")
246+
public void testForeignPathThrows() throws IOException {
247+
Path cleartext = Mockito.mock(Path.class, "/some.file");
248+
Assertions.assertThrows(ProviderMismatchException.class, () -> inTest.getCiphertextPath(cleartext));
249+
}
250+
251+
@Test
252+
@DisplayName("Not existing resource throws NoSuchFileException")
253+
public void testNoSuchFile() throws IOException {
254+
Path cleartext = inTest.getPath("/i-do-not-exist");
255+
try (var cryptoPathMock = Mockito.mockStatic(CryptoPath.class)) {
256+
cryptoPathMock.when(() -> CryptoPath.castAndAssertAbsolute(any())).thenReturn(cleartext);
257+
when(cryptoPathMapper.getCiphertextFileType(any())).thenThrow(new NoSuchFileException("no such file"));
258+
259+
Assertions.assertThrows(NoSuchFileException.class, () -> inTest.getCiphertextPath(cleartext));
260+
}
261+
}
262+
263+
@Test
264+
@DisplayName("Relative cleartext path throws exception")
265+
public void testRelativePathException() throws IOException {
266+
Path cleartext = inTest.getPath("relative/path");
267+
try (var cryptoPathMock = Mockito.mockStatic(CryptoPath.class)) {
268+
cryptoPathMock.when(() -> CryptoPath.castAndAssertAbsolute(any())).thenThrow(new IllegalArgumentException());
269+
270+
Assertions.assertThrows(IllegalArgumentException.class, () -> inTest.getCiphertextPath(cleartext));
271+
}
272+
}
273+
}
274+
191275
@Nested
192276
public class CloseAndIsOpen {
193277

0 commit comments

Comments
 (0)