From be369b480bf3feba3f71c3f77a2eb4ae79812cfd Mon Sep 17 00:00:00 2001 From: Sebastian Stenzel Date: Thu, 14 May 2015 21:48:02 +0200 Subject: [PATCH] some more destruction... --- .../jackrabbit/AbstractEncryptedNode.java | 7 +- .../jackrabbit/CleartextLocatorFactory.java | 112 +++++++++++ .../jackrabbit/CryptoResourceFactory.java | 179 +++++++++++++----- .../webdav/jackrabbit/EncryptedDir.java | 176 ++++++++--------- .../webdav/jackrabbit/EncryptedFile.java | 92 ++++----- .../webdav/jackrabbit/EncryptedFilePart.java | 64 +++---- .../webdav/jackrabbit/NonExistingNode.java | 3 +- .../webdav/jackrabbit/WebDavServlet.java | 4 +- .../crypto/aes256/Aes256Cryptor.java | 4 +- .../java/org/cryptomator/crypto/Cryptor.java | 4 +- 10 files changed, 411 insertions(+), 234 deletions(-) create mode 100644 main/core/src/main/java/org/cryptomator/webdav/jackrabbit/CleartextLocatorFactory.java diff --git a/main/core/src/main/java/org/cryptomator/webdav/jackrabbit/AbstractEncryptedNode.java b/main/core/src/main/java/org/cryptomator/webdav/jackrabbit/AbstractEncryptedNode.java index 1715ed810..d22e7a3bb 100644 --- a/main/core/src/main/java/org/cryptomator/webdav/jackrabbit/AbstractEncryptedNode.java +++ b/main/core/src/main/java/org/cryptomator/webdav/jackrabbit/AbstractEncryptedNode.java @@ -44,20 +44,19 @@ abstract class AbstractEncryptedNode implements DavResource { private static final String DAV_COMPLIANCE_CLASSES = "1, 2"; protected final CryptoResourceFactory factory; - protected final CryptoLocator locator; + protected final DavResourceLocator locator; protected final DavSession session; protected final LockManager lockManager; protected final Cryptor cryptor; protected final DavPropertySet properties; - protected AbstractEncryptedNode(CryptoResourceFactory factory, CryptoLocator locator, DavSession session, LockManager lockManager, Cryptor cryptor) { + protected AbstractEncryptedNode(CryptoResourceFactory factory, DavResourceLocator locator, DavSession session, LockManager lockManager, Cryptor cryptor) { this.factory = factory; this.locator = locator; this.session = session; this.lockManager = lockManager; this.cryptor = cryptor; this.properties = new DavPropertySet(); - this.determineProperties(); } protected abstract Path getPhysicalPath(); @@ -89,7 +88,7 @@ abstract class AbstractEncryptedNode implements DavResource { } @Override - public CryptoLocator getLocator() { + public DavResourceLocator getLocator() { return locator; } diff --git a/main/core/src/main/java/org/cryptomator/webdav/jackrabbit/CleartextLocatorFactory.java b/main/core/src/main/java/org/cryptomator/webdav/jackrabbit/CleartextLocatorFactory.java new file mode 100644 index 000000000..dc313c8d2 --- /dev/null +++ b/main/core/src/main/java/org/cryptomator/webdav/jackrabbit/CleartextLocatorFactory.java @@ -0,0 +1,112 @@ +package org.cryptomator.webdav.jackrabbit; + +import org.apache.commons.io.FilenameUtils; +import org.apache.commons.lang3.StringUtils; +import org.apache.jackrabbit.webdav.DavLocatorFactory; +import org.apache.jackrabbit.webdav.DavResourceLocator; +import org.apache.jackrabbit.webdav.util.EncodeUtil; +import org.apache.logging.log4j.util.Strings; + +public class CleartextLocatorFactory implements DavLocatorFactory { + + private final String pathPrefix; + + public CleartextLocatorFactory(String pathPrefix) { + this.pathPrefix = pathPrefix; + } + + // resourcePath == repositoryPath. No encryption here. + + @Override + public DavResourceLocator createResourceLocator(String prefix, String href) { + final String fullPrefix = prefix.endsWith("/") ? prefix : prefix + "/"; + final String relativeHref = StringUtils.removeStart(href, fullPrefix); + + final String relativeCleartextPath = EncodeUtil.unescape(StringUtils.removeStart(relativeHref, "/")); + return new CleartextLocator(relativeCleartextPath); + } + + @Override + public DavResourceLocator createResourceLocator(String prefix, String workspacePath, String resourcePath) { + return new CleartextLocator(resourcePath); + } + + @Override + public DavResourceLocator createResourceLocator(String prefix, String workspacePath, String path, boolean isResourcePath) { + return new CleartextLocator(path); + } + + private class CleartextLocator implements DavResourceLocator { + + private final String relativeCleartextPath; + + private CleartextLocator(String relativeCleartextPath) { + this.relativeCleartextPath = FilenameUtils.normalizeNoEndSeparator(relativeCleartextPath, true); + } + + @Override + public String getPrefix() { + return pathPrefix; + } + + @Override + public String getResourcePath() { + return relativeCleartextPath; + } + + @Override + public String getWorkspacePath() { + return null; + } + + @Override + public String getWorkspaceName() { + return null; + } + + @Override + public boolean isSameWorkspace(DavResourceLocator locator) { + return false; + } + + @Override + public boolean isSameWorkspace(String workspaceName) { + return false; + } + + @Override + public String getHref(boolean isCollection) { + final String encodedResourcePath = EncodeUtil.escapePath(getResourcePath()); + final String fullPrefix = pathPrefix.endsWith("/") ? pathPrefix : pathPrefix + "/"; + final String href = fullPrefix.concat(encodedResourcePath); + assert !href.endsWith("/"); + if (isCollection) { + return href.concat("/"); + } else { + return href; + } + } + + @Override + public boolean isRootLocation() { + return Strings.isEmpty(relativeCleartextPath); + } + + @Override + public DavLocatorFactory getFactory() { + return CleartextLocatorFactory.this; + } + + @Override + public String getRepositoryPath() { + return relativeCleartextPath; + } + + @Override + public String toString() { + return "Locator: " + relativeCleartextPath + " (Prefix: " + pathPrefix + ")"; + } + + } + +} diff --git a/main/core/src/main/java/org/cryptomator/webdav/jackrabbit/CryptoResourceFactory.java b/main/core/src/main/java/org/cryptomator/webdav/jackrabbit/CryptoResourceFactory.java index 990c9029d..44e85364f 100644 --- a/main/core/src/main/java/org/cryptomator/webdav/jackrabbit/CryptoResourceFactory.java +++ b/main/core/src/main/java/org/cryptomator/webdav/jackrabbit/CryptoResourceFactory.java @@ -1,13 +1,19 @@ package org.cryptomator.webdav.jackrabbit; -import java.io.FileNotFoundException; import java.io.IOException; +import java.nio.ByteBuffer; +import java.nio.channels.FileChannel; +import java.nio.channels.FileLock; +import java.nio.charset.StandardCharsets; import java.nio.file.FileSystems; import java.nio.file.Files; import java.nio.file.Path; +import java.nio.file.StandardOpenOption; +import java.util.UUID; import java.util.concurrent.ExecutorService; import org.apache.commons.httpclient.HttpStatus; +import org.apache.commons.io.FilenameUtils; import org.apache.jackrabbit.webdav.DavException; import org.apache.jackrabbit.webdav.DavMethods; import org.apache.jackrabbit.webdav.DavResource; @@ -18,99 +24,168 @@ import org.apache.jackrabbit.webdav.DavServletResponse; import org.apache.jackrabbit.webdav.DavSession; import org.apache.jackrabbit.webdav.lock.LockManager; import org.apache.jackrabbit.webdav.lock.SimpleLockManager; +import org.apache.logging.log4j.util.Strings; import org.cryptomator.crypto.Cryptor; -import org.cryptomator.webdav.exceptions.IORuntimeException; +import org.cryptomator.crypto.CryptorMetadataSupport; import org.eclipse.jetty.http.HttpHeader; -public class CryptoResourceFactory implements DavResourceFactory { +public class CryptoResourceFactory implements DavResourceFactory, CryptorMetadataSupport { private final LockManager lockManager = new SimpleLockManager(); private final Cryptor cryptor; private final CryptoWarningHandler cryptoWarningHandler; private final ExecutorService backgroundTaskExecutor; + private final Path dataRoot; + private final Path metadataRoot; - CryptoResourceFactory(Cryptor cryptor, CryptoWarningHandler cryptoWarningHandler, ExecutorService backgroundTaskExecutor) { + CryptoResourceFactory(Cryptor cryptor, CryptoWarningHandler cryptoWarningHandler, ExecutorService backgroundTaskExecutor, String fsRoot) { this.cryptor = cryptor; this.cryptoWarningHandler = cryptoWarningHandler; this.backgroundTaskExecutor = backgroundTaskExecutor; + this.dataRoot = FileSystems.getDefault().getPath(fsRoot).resolve("d"); + this.metadataRoot = FileSystems.getDefault().getPath(fsRoot).resolve("m"); } @Override public final DavResource createResource(DavResourceLocator locator, DavServletRequest request, DavServletResponse response) throws DavException { - if (locator instanceof CryptoLocator) { - return createResource((CryptoLocator) locator, request, response); - } else { - throw new IllegalArgumentException("Unsupported resource locator of type " + locator.getClass().getName()); + if (DavMethods.METHOD_MKCOL.equals(request.getMethod()) || locator.isRootLocation()) { + final Path dirpath = getEncryptedDirectoryPath(locator.getResourcePath()); + return createDirectory(locator, request.getDavSession(), dirpath); } - } - @Override - public final DavResource createResource(DavResourceLocator locator, DavSession session) throws DavException { - if (locator instanceof CryptoLocator) { - return createResource((CryptoLocator) locator, session); - } else { - throw new IllegalArgumentException("Unsupported resource locator of type " + locator.getClass().getName()); - } - } - - private DavResource createResource(CryptoLocator locator, DavServletRequest request, DavServletResponse response) throws DavException { - final Path filepath = FileSystems.getDefault().getPath(locator.getRepositoryPath()); - Path dirpath = null; - try { - dirpath = FileSystems.getDefault().getPath(locator.getDirectoryPath(DavMethods.METHOD_MKCOL.equals(request.getMethod()))); - } catch (FileNotFoundException e) { - // no-op - } catch (IOException e) { - throw new IORuntimeException(e); - } + final Path filepath = getEncryptedFilePath(locator.getResourcePath()); final String rangeHeader = request.getHeader(HttpHeader.RANGE.asString()); - - if (Files.isDirectory(dirpath)) { - return createDirectory(locator, request.getDavSession()); + if (filepath.getFileName().toString().endsWith(".dir")) { + final Path dirpath = getEncryptedDirectoryPath(locator.getResourcePath()); + return createDirectory(locator, request.getDavSession(), dirpath); } else if (Files.isRegularFile(filepath) && DavMethods.METHOD_GET.equals(request.getMethod()) && rangeHeader != null) { response.setStatus(HttpStatus.SC_PARTIAL_CONTENT); - return createFilePart(locator, request.getDavSession(), request); + return createFilePart(locator, request.getDavSession(), request, filepath); } else if (Files.isRegularFile(filepath) || DavMethods.METHOD_PUT.equals(request.getMethod())) { - return createFile(locator, request.getDavSession()); + return createFile(locator, request.getDavSession(), filepath); } else { return createNonExisting(locator, request.getDavSession()); } } - private DavResource createResource(CryptoLocator locator, DavSession session) throws DavException { - final Path filepath = FileSystems.getDefault().getPath(locator.getRepositoryPath()); - Path dirpath = null; - try { - dirpath = FileSystems.getDefault().getPath(locator.getDirectoryPath(false)); - } catch (FileNotFoundException e) { - // no-op - } catch (IOException e) { - throw new IORuntimeException(e); + @Override + public final DavResource createResource(DavResourceLocator locator, DavSession session) throws DavException { + if (locator.isRootLocation()) { + final Path dirpath = getEncryptedDirectoryPath(locator.getResourcePath()); + return createDirectory(locator, session, dirpath); } - if (Files.isDirectory(dirpath)) { - return createDirectory(locator, session); + final Path filepath = getEncryptedFilePath(locator.getResourcePath()); + if (filepath.getFileName().toString().endsWith(".dir")) { + final Path dirpath = getEncryptedDirectoryPath(locator.getResourcePath()); + return createDirectory(locator, session, dirpath); } else if (Files.isRegularFile(filepath)) { - return createFile(locator, session); + return createFile(locator, session, filepath); } else { return createNonExisting(locator, session); } } - private EncryptedFile createFilePart(CryptoLocator locator, DavSession session, DavServletRequest request) { - return new EncryptedFilePart(this, locator, session, request, lockManager, cryptor, cryptoWarningHandler, backgroundTaskExecutor); + /** + * @return Absolute file path for a given cleartext file resourcePath. + * @throws IOException + */ + Path getEncryptedFilePath(String relativeCleartextPath) throws DavException { + final String parentCleartextPath = FilenameUtils.getPathNoEndSeparator(relativeCleartextPath); + final Path parent = getEncryptedDirectoryPath(parentCleartextPath); + final String cleartextFilename = FilenameUtils.getName(relativeCleartextPath); + try { + final String encryptedFilename = cryptor.encryptFilename(cleartextFilename, this); + return parent.resolve(encryptedFilename); + } catch (IOException e) { + throw new DavException(DavServletResponse.SC_INTERNAL_SERVER_ERROR, e); + } } - private EncryptedFile createFile(CryptoLocator locator, DavSession session) { - return new EncryptedFile(this, locator, session, lockManager, cryptor, cryptoWarningHandler); + /** + * @return Absolute directory path for a given cleartext directory resourcePath. + * @throws IOException + */ + Path getEncryptedDirectoryPath(String relativeCleartextPath) throws DavException { + assert Strings.isEmpty(relativeCleartextPath) || !relativeCleartextPath.endsWith("/"); + try { + final Path result; + if (Strings.isEmpty(relativeCleartextPath)) { + // root level + final String fixedRootDirectory = cryptor.encryptDirectoryPath("", FileSystems.getDefault().getSeparator()); + result = dataRoot.resolve(fixedRootDirectory); + } else { + final String parentCleartextPath = FilenameUtils.getPathNoEndSeparator(relativeCleartextPath); + final Path parent = getEncryptedDirectoryPath(parentCleartextPath); + final String cleartextFilename = FilenameUtils.getName(relativeCleartextPath); + final String encryptedFilename = cryptor.encryptFilename(cleartextFilename, CryptoResourceFactory.this); + final Path directoryFile = parent.resolve(encryptedFilename); + final String directoryId; + if (Files.exists(directoryFile)) { + directoryId = new String(readAllBytesAtomically(directoryFile), StandardCharsets.UTF_8); + } else { + directoryId = UUID.randomUUID().toString(); + writeAllBytesAtomically(directoryFile, directoryId.getBytes(StandardCharsets.UTF_8)); + } + final String directory = cryptor.encryptDirectoryPath(directoryId, FileSystems.getDefault().getSeparator()); + result = dataRoot.resolve(directory); + } + Files.createDirectories(result); + return result; + } catch (IOException e) { + throw new DavException(DavServletResponse.SC_INTERNAL_SERVER_ERROR, e); + } } - private EncryptedDir createDirectory(CryptoLocator locator, DavSession session) { - return new EncryptedDir(this, locator, session, lockManager, cryptor); + private EncryptedFile createFilePart(DavResourceLocator locator, DavSession session, DavServletRequest request, Path filePath) { + return new EncryptedFilePart(this, locator, session, request, lockManager, cryptor, cryptoWarningHandler, backgroundTaskExecutor, filePath); } - private NonExistingNode createNonExisting(CryptoLocator locator, DavSession session) { + private EncryptedFile createFile(DavResourceLocator locator, DavSession session, Path filePath) { + return new EncryptedFile(this, locator, session, lockManager, cryptor, cryptoWarningHandler, filePath); + } + + private EncryptedDir createDirectory(DavResourceLocator locator, DavSession session, Path dirPath) { + return new EncryptedDir(this, locator, session, lockManager, cryptor, dirPath); + } + + private NonExistingNode createNonExisting(DavResourceLocator locator, DavSession session) { return new NonExistingNode(this, locator, session, lockManager, cryptor); } + /* IO support */ + + private void writeAllBytesAtomically(Path path, byte[] bytes) throws IOException { + try (final FileChannel c = FileChannel.open(path, StandardOpenOption.WRITE, StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING, StandardOpenOption.DSYNC); final FileLock lock = c.lock()) { + c.write(ByteBuffer.wrap(bytes)); + } + } + + private byte[] readAllBytesAtomically(Path path) throws IOException { + try (final FileChannel c = FileChannel.open(path, StandardOpenOption.READ, StandardOpenOption.DSYNC); final FileLock lock = c.lock(0L, Long.MAX_VALUE, true)) { + final ByteBuffer buffer = ByteBuffer.allocate((int) c.size()); + c.read(buffer); + return buffer.array(); + } + } + + @Override + public void writeMetadata(String metadataGroup, byte[] encryptedMetadata) throws IOException { + final Path metadataDir = metadataRoot.resolve(metadataGroup.substring(0, 2)); + Files.createDirectories(metadataDir); + final Path metadataFile = metadataDir.resolve(metadataGroup.substring(2)); + writeAllBytesAtomically(metadataFile, encryptedMetadata); + } + + @Override + public byte[] readMetadata(String metadataGroup) throws IOException { + final Path metadataDir = metadataRoot.resolve(metadataGroup.substring(0, 2)); + final Path metadataFile = metadataDir.resolve(metadataGroup.substring(2)); + if (!Files.isReadable(metadataFile)) { + return null; + } else { + return readAllBytesAtomically(metadataFile); + } + } + } diff --git a/main/core/src/main/java/org/cryptomator/webdav/jackrabbit/EncryptedDir.java b/main/core/src/main/java/org/cryptomator/webdav/jackrabbit/EncryptedDir.java index 7fbeb6202..6117bbb96 100644 --- a/main/core/src/main/java/org/cryptomator/webdav/jackrabbit/EncryptedDir.java +++ b/main/core/src/main/java/org/cryptomator/webdav/jackrabbit/EncryptedDir.java @@ -11,16 +11,16 @@ package org.cryptomator.webdav.jackrabbit; import java.io.FileNotFoundException; import java.io.IOException; import java.nio.channels.SeekableByteChannel; -import java.nio.file.AtomicMoveNotSupportedException; import java.nio.file.DirectoryStream; import java.nio.file.Files; import java.nio.file.Path; -import java.nio.file.StandardCopyOption; import java.nio.file.StandardOpenOption; import java.nio.file.attribute.BasicFileAttributes; import java.util.ArrayList; +import java.util.Iterator; import java.util.List; +import org.apache.commons.io.FilenameUtils; import org.apache.commons.io.IOUtils; import org.apache.jackrabbit.webdav.DavException; import org.apache.jackrabbit.webdav.DavResource; @@ -37,9 +37,9 @@ import org.apache.jackrabbit.webdav.property.DefaultDavProperty; import org.apache.jackrabbit.webdav.property.ResourceType; import org.cryptomator.crypto.Cryptor; import org.cryptomator.crypto.exceptions.CounterOverflowException; +import org.cryptomator.crypto.exceptions.DecryptFailedException; import org.cryptomator.crypto.exceptions.EncryptFailedException; import org.cryptomator.webdav.exceptions.DavRuntimeException; -import org.cryptomator.webdav.exceptions.DecryptFailedRuntimeException; import org.cryptomator.webdav.exceptions.IORuntimeException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -47,18 +47,20 @@ import org.slf4j.LoggerFactory; class EncryptedDir extends AbstractEncryptedNode { private static final Logger LOG = LoggerFactory.getLogger(EncryptedDir.class); + private final Path directoryPath; - public EncryptedDir(CryptoResourceFactory factory, CryptoLocator locator, DavSession session, LockManager lockManager, Cryptor cryptor) { + public EncryptedDir(CryptoResourceFactory factory, DavResourceLocator locator, DavSession session, LockManager lockManager, Cryptor cryptor, Path directoryPath) { super(factory, locator, session, lockManager, cryptor); + if (directoryPath == null || !Files.isDirectory(directoryPath)) { + throw new IllegalArgumentException("directoryPath must be an existing directory, but was " + directoryPath); + } + this.directoryPath = directoryPath; + determineProperties(); } @Override protected Path getPhysicalPath() { - try { - return locator.getEncryptedDirectoryPath(false); - } catch (IOException e) { - throw new IORuntimeException(e); - } + return directoryPath; } @Override @@ -68,17 +70,14 @@ class EncryptedDir extends AbstractEncryptedNode { @Override public boolean exists() { - try { - return Files.isDirectory(locator.getEncryptedDirectoryPath(false)); - } catch (IOException e) { - return false; - } + assert Files.isDirectory(directoryPath); + return true; } @Override public long getModificationTime() { try { - return Files.getLastModifiedTime(locator.getEncryptedDirectoryPath(false)).toMillis(); + return Files.getLastModifiedTime(directoryPath).toMillis(); } catch (IOException e) { return -1; } @@ -101,19 +100,18 @@ class EncryptedDir extends AbstractEncryptedNode { } } - private void addMemberDir(CryptoLocator childLocator, InputContext inputContext) throws DavException { + private void addMemberDir(DavResourceLocator childLocator, InputContext inputContext) throws DavException { try { - Files.createDirectories(childLocator.getEncryptedDirectoryPath(true)); + // the following invokation will create nonexisting directories: + factory.getEncryptedDirectoryPath(childLocator.getResourcePath()); } catch (SecurityException e) { throw new DavException(DavServletResponse.SC_FORBIDDEN, e); - } catch (IOException e) { - LOG.error("Failed to create subdirectory.", e); - throw new IORuntimeException(e); } } - private void addMemberFile(CryptoLocator childLocator, InputContext inputContext) throws DavException { - try (final SeekableByteChannel channel = Files.newByteChannel(childLocator.getEncryptedFilePath(), StandardOpenOption.WRITE, StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING)) { + private void addMemberFile(DavResourceLocator childLocator, InputContext inputContext) throws DavException { + final Path filePath = factory.getEncryptedFilePath(childLocator.getResourcePath()); + try (final SeekableByteChannel channel = Files.newByteChannel(filePath, StandardOpenOption.WRITE, StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING)) { cryptor.encryptFile(inputContext.getInputStream(), channel); } catch (SecurityException e) { throw new DavException(DavServletResponse.SC_FORBIDDEN, e); @@ -134,17 +132,17 @@ class EncryptedDir extends AbstractEncryptedNode { @Override public DavResourceIterator getMembers() { try { - final DirectoryStream directoryStream = Files.newDirectoryStream(locator.getEncryptedDirectoryPath(false), cryptor.getPayloadFilesFilter()); + final DirectoryStream directoryStream = Files.newDirectoryStream(directoryPath, cryptor.getPayloadFilesFilter()); final List result = new ArrayList<>(); for (final Path childPath : directoryStream) { try { - final DavResourceLocator childLocator = locator.getFactory().createSubresourceLocator(locator, childPath.getFileName().toString()); - // final DavResourceLocator childLocator = locator.getFactory().createResourceLocator(locator.getPrefix(), - // locator.getWorkspacePath(), childPath.toString(), false); + final String cleartextFilename = cryptor.decryptFilename(childPath.getFileName().toString(), factory); + final String cleartextFilepath = FilenameUtils.concat(getResourcePath(), cleartextFilename); + final DavResourceLocator childLocator = locator.getFactory().createResourceLocator(locator.getPrefix(), locator.getWorkspacePath(), cleartextFilepath); final DavResource resource = factory.createResource(childLocator, session); result.add(resource); - } catch (DecryptFailedRuntimeException e) { + } catch (DecryptFailedException e) { LOG.warn("Decryption of resource failed: " + childPath); continue; } @@ -160,7 +158,7 @@ class EncryptedDir extends AbstractEncryptedNode { } @Override - public void removeMember(DavResource member) { + public void removeMember(DavResource member) throws DavException { if (member instanceof AbstractEncryptedNode) { removeMember((AbstractEncryptedNode) member); } else { @@ -168,13 +166,19 @@ class EncryptedDir extends AbstractEncryptedNode { } } - private void removeMember(AbstractEncryptedNode member) { + private void removeMember(AbstractEncryptedNode member) throws DavException { try { - Files.deleteIfExists(member.getLocator().getEncryptedFilePath()); if (member.isCollection()) { - member.getMembers().forEachRemaining(m -> securelyRemoveMemberOfCollection(member, m)); - Files.deleteIfExists(member.getLocator().getEncryptedDirectoryPath(false)); + // remove sub-members recursively before deleting own directory + for (Iterator iterator = member.getMembers(); iterator.hasNext();) { + DavResource m = iterator.next(); + member.removeMember(m); + } + final Path memberDirectoryPath = factory.getEncryptedDirectoryPath(member.getResourcePath()); + Files.deleteIfExists(memberDirectoryPath); } + final Path memberPath = factory.getEncryptedFilePath(member.getResourcePath()); + Files.deleteIfExists(memberPath); } catch (FileNotFoundException e) { // no-op } catch (IOException e) { @@ -182,58 +186,52 @@ class EncryptedDir extends AbstractEncryptedNode { } } - private void securelyRemoveMemberOfCollection(DavResource collection, DavResource member) { - try { - collection.removeMember(member); - } catch (DavException e) { - throw new IllegalStateException("DavException should not be thrown by collections of type EncryptedDir. Collections is of type " + collection.getClass().getName()); - } - } - @Override public void move(AbstractEncryptedNode dest) throws DavException, IOException { - final Path srcDir = this.locator.getEncryptedDirectoryPath(false); - final Path dstDir = dest.locator.getEncryptedDirectoryPath(true); - final Path srcFile = this.locator.getEncryptedFilePath(); - final Path dstFile = dest.locator.getEncryptedFilePath(); - - // check for conflicts: - if (Files.exists(dstDir) && Files.getLastModifiedTime(dstDir).toMillis() > Files.getLastModifiedTime(dstDir).toMillis()) { - throw new DavException(DavServletResponse.SC_CONFLICT, "Directory at destination already exists: " + dstDir.toString()); - } - - // move: - Files.createDirectories(dstDir); - try { - Files.move(srcDir, dstDir, StandardCopyOption.REPLACE_EXISTING, StandardCopyOption.ATOMIC_MOVE); - Files.move(srcFile, dstFile, StandardCopyOption.REPLACE_EXISTING, StandardCopyOption.ATOMIC_MOVE); - } catch (AtomicMoveNotSupportedException e) { - Files.move(srcDir, dstDir, StandardCopyOption.REPLACE_EXISTING); - Files.move(srcFile, dstFile, StandardCopyOption.REPLACE_EXISTING); - } + throw new UnsupportedOperationException("not yet implemented"); + // final Path srcDir = this.locator.getEncryptedDirectoryPath(false); + // final Path dstDir = dest.locator.getEncryptedDirectoryPath(true); + // final Path srcFile = this.locator.getEncryptedFilePath(); + // final Path dstFile = dest.locator.getEncryptedFilePath(); + // + // // check for conflicts: + // if (Files.exists(dstDir) && Files.getLastModifiedTime(dstDir).toMillis() > Files.getLastModifiedTime(dstDir).toMillis()) { + // throw new DavException(DavServletResponse.SC_CONFLICT, "Directory at destination already exists: " + dstDir.toString()); + // } + // + // // move: + // Files.createDirectories(dstDir); + // try { + // Files.move(srcDir, dstDir, StandardCopyOption.REPLACE_EXISTING, StandardCopyOption.ATOMIC_MOVE); + // Files.move(srcFile, dstFile, StandardCopyOption.REPLACE_EXISTING, StandardCopyOption.ATOMIC_MOVE); + // } catch (AtomicMoveNotSupportedException e) { + // Files.move(srcDir, dstDir, StandardCopyOption.REPLACE_EXISTING); + // Files.move(srcFile, dstFile, StandardCopyOption.REPLACE_EXISTING); + // } } @Override public void copy(AbstractEncryptedNode dest, boolean shallow) throws DavException, IOException { - final Path srcDir = this.locator.getEncryptedDirectoryPath(false); - final Path dstDir = dest.locator.getEncryptedDirectoryPath(true); - final Path srcFile = this.locator.getEncryptedFilePath(); - final Path dstFile = dest.locator.getEncryptedFilePath(); - - // check for conflicts: - if (Files.exists(dstDir) && Files.getLastModifiedTime(dstDir).toMillis() > Files.getLastModifiedTime(dstDir).toMillis()) { - throw new DavException(DavServletResponse.SC_CONFLICT, "Directory at destination already exists: " + dstDir.toString()); - } - - // copy: - Files.createDirectories(dstDir); - try { - Files.copy(srcDir, dstDir, StandardCopyOption.COPY_ATTRIBUTES, StandardCopyOption.REPLACE_EXISTING, StandardCopyOption.ATOMIC_MOVE); - Files.copy(srcFile, dstFile, StandardCopyOption.COPY_ATTRIBUTES, StandardCopyOption.REPLACE_EXISTING, StandardCopyOption.ATOMIC_MOVE); - } catch (AtomicMoveNotSupportedException e) { - Files.copy(srcDir, dstDir, StandardCopyOption.COPY_ATTRIBUTES, StandardCopyOption.REPLACE_EXISTING); - Files.copy(srcFile, dstFile, StandardCopyOption.COPY_ATTRIBUTES, StandardCopyOption.REPLACE_EXISTING); - } + throw new UnsupportedOperationException("not yet implemented"); + // final Path srcDir = this.locator.getEncryptedDirectoryPath(false); + // final Path dstDir = dest.locator.getEncryptedDirectoryPath(true); + // final Path srcFile = this.locator.getEncryptedFilePath(); + // final Path dstFile = dest.locator.getEncryptedFilePath(); + // + // // check for conflicts: + // if (Files.exists(dstDir) && Files.getLastModifiedTime(dstDir).toMillis() > Files.getLastModifiedTime(dstDir).toMillis()) { + // throw new DavException(DavServletResponse.SC_CONFLICT, "Directory at destination already exists: " + dstDir.toString()); + // } + // + // // copy: + // Files.createDirectories(dstDir); + // try { + // Files.copy(srcDir, dstDir, StandardCopyOption.COPY_ATTRIBUTES, StandardCopyOption.REPLACE_EXISTING, StandardCopyOption.ATOMIC_MOVE); + // Files.copy(srcFile, dstFile, StandardCopyOption.COPY_ATTRIBUTES, StandardCopyOption.REPLACE_EXISTING, StandardCopyOption.ATOMIC_MOVE); + // } catch (AtomicMoveNotSupportedException e) { + // Files.copy(srcDir, dstDir, StandardCopyOption.COPY_ATTRIBUTES, StandardCopyOption.REPLACE_EXISTING); + // Files.copy(srcFile, dstFile, StandardCopyOption.COPY_ATTRIBUTES, StandardCopyOption.REPLACE_EXISTING); + // } } @Override @@ -243,23 +241,15 @@ class EncryptedDir extends AbstractEncryptedNode { @Override protected void determineProperties() { - Path path; - try { - path = locator.getEncryptedDirectoryPath(false); - } catch (IOException e) { - throw new IORuntimeException(e); - } properties.add(new ResourceType(ResourceType.COLLECTION)); properties.add(new DefaultDavProperty(DavPropertyName.ISCOLLECTION, 1)); - if (Files.exists(path)) { - try { - final BasicFileAttributes attrs = Files.readAttributes(path, BasicFileAttributes.class); - properties.add(new DefaultDavProperty(DavPropertyName.CREATIONDATE, FileTimeUtils.toRfc1123String(attrs.creationTime()))); - properties.add(new DefaultDavProperty(DavPropertyName.GETLASTMODIFIED, FileTimeUtils.toRfc1123String(attrs.lastModifiedTime()))); - } catch (IOException e) { - LOG.error("Error determining metadata " + path.toString(), e); - // don't add any further properties - } + try { + final BasicFileAttributes attrs = Files.readAttributes(directoryPath, BasicFileAttributes.class); + properties.add(new DefaultDavProperty(DavPropertyName.CREATIONDATE, FileTimeUtils.toRfc1123String(attrs.creationTime()))); + properties.add(new DefaultDavProperty(DavPropertyName.GETLASTMODIFIED, FileTimeUtils.toRfc1123String(attrs.lastModifiedTime()))); + } catch (IOException e) { + LOG.error("Error determining metadata " + directoryPath.toString(), e); + // don't add any further properties } } diff --git a/main/core/src/main/java/org/cryptomator/webdav/jackrabbit/EncryptedFile.java b/main/core/src/main/java/org/cryptomator/webdav/jackrabbit/EncryptedFile.java index 30a3cd160..d218db846 100644 --- a/main/core/src/main/java/org/cryptomator/webdav/jackrabbit/EncryptedFile.java +++ b/main/core/src/main/java/org/cryptomator/webdav/jackrabbit/EncryptedFile.java @@ -11,17 +11,15 @@ package org.cryptomator.webdav.jackrabbit; import java.io.EOFException; import java.io.IOException; import java.nio.channels.SeekableByteChannel; -import java.nio.file.AtomicMoveNotSupportedException; import java.nio.file.Files; import java.nio.file.Path; -import java.nio.file.StandardCopyOption; import java.nio.file.StandardOpenOption; import java.nio.file.attribute.BasicFileAttributes; import org.apache.jackrabbit.webdav.DavException; import org.apache.jackrabbit.webdav.DavResource; import org.apache.jackrabbit.webdav.DavResourceIterator; -import org.apache.jackrabbit.webdav.DavServletResponse; +import org.apache.jackrabbit.webdav.DavResourceLocator; import org.apache.jackrabbit.webdav.DavSession; import org.apache.jackrabbit.webdav.io.InputContext; import org.apache.jackrabbit.webdav.io.OutputContext; @@ -42,15 +40,21 @@ class EncryptedFile extends AbstractEncryptedNode { private static final Logger LOG = LoggerFactory.getLogger(EncryptedFile.class); protected final CryptoWarningHandler cryptoWarningHandler; + protected final Path filePath; - public EncryptedFile(CryptoResourceFactory factory, CryptoLocator locator, DavSession session, LockManager lockManager, Cryptor cryptor, CryptoWarningHandler cryptoWarningHandler) { + public EncryptedFile(CryptoResourceFactory factory, DavResourceLocator locator, DavSession session, LockManager lockManager, Cryptor cryptor, CryptoWarningHandler cryptoWarningHandler, Path filePath) { super(factory, locator, session, lockManager, cryptor); + if (filePath == null) { + throw new IllegalArgumentException("filePath must not be null"); + } this.cryptoWarningHandler = cryptoWarningHandler; + this.filePath = filePath; + this.determineProperties(); } @Override protected Path getPhysicalPath() { - return locator.getEncryptedFilePath(); + return filePath; } @Override @@ -75,11 +79,10 @@ class EncryptedFile extends AbstractEncryptedNode { @Override public void spool(OutputContext outputContext) throws IOException { - final Path path = locator.getEncryptedFilePath(); - if (Files.isRegularFile(path)) { - outputContext.setModificationTime(Files.getLastModifiedTime(path).toMillis()); + if (Files.isRegularFile(filePath)) { + outputContext.setModificationTime(Files.getLastModifiedTime(filePath).toMillis()); outputContext.setProperty(HttpHeader.ACCEPT_RANGES.asString(), HttpHeaderValue.BYTES.asString()); - try (final SeekableByteChannel channel = Files.newByteChannel(path, StandardOpenOption.READ)) { + try (final SeekableByteChannel channel = Files.newByteChannel(filePath, StandardOpenOption.READ)) { final Long contentLength = cryptor.decryptedContentLength(channel); if (contentLength != null) { outputContext.setContentLength(contentLength); @@ -92,20 +95,19 @@ class EncryptedFile extends AbstractEncryptedNode { } catch (MacAuthenticationFailedException e) { cryptoWarningHandler.macAuthFailed(getLocator().getResourcePath()); } catch (DecryptFailedException e) { - throw new IOException("Error decrypting file " + path.toString(), e); + throw new IOException("Error decrypting file " + filePath.toString(), e); } } } @Override protected void determineProperties() { - final Path path = locator.getEncryptedFilePath(); - if (Files.exists(path)) { - try (final SeekableByteChannel channel = Files.newByteChannel(path, StandardOpenOption.READ)) { + if (Files.isRegularFile(filePath)) { + try (final SeekableByteChannel channel = Files.newByteChannel(filePath, StandardOpenOption.READ)) { final Long contentLength = cryptor.decryptedContentLength(channel); properties.add(new DefaultDavProperty(DavPropertyName.GETCONTENTLENGTH, contentLength)); } catch (IOException e) { - LOG.error("Error reading filesize " + path.toString(), e); + LOG.error("Error reading filesize " + filePath.toString(), e); throw new IORuntimeException(e); } catch (MacAuthenticationFailedException e) { LOG.warn("Content length couldn't be determined due to MAC authentication violation."); @@ -113,12 +115,12 @@ class EncryptedFile extends AbstractEncryptedNode { } try { - final BasicFileAttributes attrs = Files.readAttributes(path, BasicFileAttributes.class); + final BasicFileAttributes attrs = Files.readAttributes(filePath, BasicFileAttributes.class); properties.add(new DefaultDavProperty(DavPropertyName.CREATIONDATE, FileTimeUtils.toRfc1123String(attrs.creationTime()))); properties.add(new DefaultDavProperty(DavPropertyName.GETLASTMODIFIED, FileTimeUtils.toRfc1123String(attrs.lastModifiedTime()))); properties.add(new HttpHeaderProperty(HttpHeader.ACCEPT_RANGES.asString(), HttpHeaderValue.BYTES.asString())); } catch (IOException e) { - LOG.error("Error determining metadata " + path.toString(), e); + LOG.error("Error determining metadata " + filePath.toString(), e); throw new IORuntimeException(e); } } @@ -126,38 +128,40 @@ class EncryptedFile extends AbstractEncryptedNode { @Override public void move(AbstractEncryptedNode dest) throws DavException, IOException { - final Path src = this.locator.getEncryptedFilePath(); - final Path dst = dest.locator.getEncryptedFilePath(); - - // check for conflicts: - if (Files.exists(dst) && Files.getLastModifiedTime(dst).toMillis() > Files.getLastModifiedTime(src).toMillis()) { - throw new DavException(DavServletResponse.SC_CONFLICT, "File at destination already exists: " + dst.toString()); - } - - // move: - try { - Files.move(src, dst, StandardCopyOption.REPLACE_EXISTING, StandardCopyOption.ATOMIC_MOVE); - } catch (AtomicMoveNotSupportedException e) { - Files.move(src, dst, StandardCopyOption.REPLACE_EXISTING); - } + throw new UnsupportedOperationException("not yet implemented"); + // final Path src = this.locator.getEncryptedFilePath(); + // final Path dst = dest.locator.getEncryptedFilePath(); + // + // // check for conflicts: + // if (Files.exists(dst) && Files.getLastModifiedTime(dst).toMillis() > Files.getLastModifiedTime(src).toMillis()) { + // throw new DavException(DavServletResponse.SC_CONFLICT, "File at destination already exists: " + dst.toString()); + // } + // + // // move: + // try { + // Files.move(src, dst, StandardCopyOption.REPLACE_EXISTING, StandardCopyOption.ATOMIC_MOVE); + // } catch (AtomicMoveNotSupportedException e) { + // Files.move(src, dst, StandardCopyOption.REPLACE_EXISTING); + // } } @Override public void copy(AbstractEncryptedNode dest, boolean shallow) throws DavException, IOException { - final Path src = this.locator.getEncryptedFilePath(); - final Path dst = dest.locator.getEncryptedFilePath(); - - // check for conflicts: - if (Files.exists(dst) && Files.getLastModifiedTime(dst).toMillis() > Files.getLastModifiedTime(src).toMillis()) { - throw new DavException(DavServletResponse.SC_CONFLICT, "File at destination already exists: " + dst.toString()); - } - - // copy: - try { - Files.copy(src, dst, StandardCopyOption.COPY_ATTRIBUTES, StandardCopyOption.REPLACE_EXISTING, StandardCopyOption.ATOMIC_MOVE); - } catch (AtomicMoveNotSupportedException e) { - Files.copy(src, dst, StandardCopyOption.COPY_ATTRIBUTES, StandardCopyOption.REPLACE_EXISTING); - } + throw new UnsupportedOperationException("not yet implemented"); + // final Path src = this.locator.getEncryptedFilePath(); + // final Path dst = dest.locator.getEncryptedFilePath(); + // + // // check for conflicts: + // if (Files.exists(dst) && Files.getLastModifiedTime(dst).toMillis() > Files.getLastModifiedTime(src).toMillis()) { + // throw new DavException(DavServletResponse.SC_CONFLICT, "File at destination already exists: " + dst.toString()); + // } + // + // // copy: + // try { + // Files.copy(src, dst, StandardCopyOption.COPY_ATTRIBUTES, StandardCopyOption.REPLACE_EXISTING, StandardCopyOption.ATOMIC_MOVE); + // } catch (AtomicMoveNotSupportedException e) { + // Files.copy(src, dst, StandardCopyOption.COPY_ATTRIBUTES, StandardCopyOption.REPLACE_EXISTING); + // } } } diff --git a/main/core/src/main/java/org/cryptomator/webdav/jackrabbit/EncryptedFilePart.java b/main/core/src/main/java/org/cryptomator/webdav/jackrabbit/EncryptedFilePart.java index 697a4422b..454bda21f 100644 --- a/main/core/src/main/java/org/cryptomator/webdav/jackrabbit/EncryptedFilePart.java +++ b/main/core/src/main/java/org/cryptomator/webdav/jackrabbit/EncryptedFilePart.java @@ -55,9 +55,9 @@ class EncryptedFilePart extends EncryptedFile { private final Set> requestedContentRanges = new HashSet>(); - public EncryptedFilePart(CryptoResourceFactory factory, CryptoLocator locator, DavSession session, DavServletRequest request, LockManager lockManager, Cryptor cryptor, CryptoWarningHandler cryptoWarningHandler, - ExecutorService backgroundTaskExecutor) { - super(factory, locator, session, lockManager, cryptor, cryptoWarningHandler); + public EncryptedFilePart(CryptoResourceFactory factory, DavResourceLocator locator, DavSession session, DavServletRequest request, LockManager lockManager, Cryptor cryptor, CryptoWarningHandler cryptoWarningHandler, + ExecutorService backgroundTaskExecutor, Path filePath) { + super(factory, locator, session, lockManager, cryptor, cryptoWarningHandler, filePath); final String rangeHeader = request.getHeader(HttpHeader.RANGE.asString()); if (rangeHeader == null) { throw new IllegalArgumentException("HTTP request doesn't contain a range header"); @@ -125,25 +125,23 @@ class EncryptedFilePart extends EncryptedFile { @Override public void spool(OutputContext outputContext) throws IOException { - final Path path = locator.getEncryptedFilePath(); - if (Files.isRegularFile(path)) { - outputContext.setModificationTime(Files.getLastModifiedTime(path).toMillis()); - try (final SeekableByteChannel channel = Files.newByteChannel(path, StandardOpenOption.READ)) { - final Long fileSize = cryptor.decryptedContentLength(channel); - final Pair range = getUnionRange(fileSize); - final Long rangeLength = range.getRight() - range.getLeft() + 1; - outputContext.setContentLength(rangeLength); - outputContext.setProperty(HttpHeader.CONTENT_RANGE.asString(), getContentRangeHeader(range.getLeft(), range.getRight(), fileSize)); - if (outputContext.hasStream()) { - cryptor.decryptRange(channel, outputContext.getOutputStream(), range.getLeft(), rangeLength); - } - } catch (EOFException e) { - if (LOG.isDebugEnabled()) { - LOG.debug("Unexpected end of stream during delivery of partial content (client hung up)."); - } - } catch (DecryptFailedException e) { - throw new IOException("Error decrypting file " + path.toString(), e); + assert Files.isRegularFile(filePath); + outputContext.setModificationTime(Files.getLastModifiedTime(filePath).toMillis()); + try (final SeekableByteChannel channel = Files.newByteChannel(filePath, StandardOpenOption.READ)) { + final Long fileSize = cryptor.decryptedContentLength(channel); + final Pair range = getUnionRange(fileSize); + final Long rangeLength = range.getRight() - range.getLeft() + 1; + outputContext.setContentLength(rangeLength); + outputContext.setProperty(HttpHeader.CONTENT_RANGE.asString(), getContentRangeHeader(range.getLeft(), range.getRight(), fileSize)); + if (outputContext.hasStream()) { + cryptor.decryptRange(channel, outputContext.getOutputStream(), range.getLeft(), rangeLength); } + } catch (EOFException e) { + if (LOG.isDebugEnabled()) { + LOG.debug("Unexpected end of stream during delivery of partial content (client hung up)."); + } + } catch (DecryptFailedException e) { + throw new IOException("Error decrypting file " + filePath.toString(), e); } } @@ -153,9 +151,9 @@ class EncryptedFilePart extends EncryptedFile { private class MacAuthenticationJob implements Runnable { - private final CryptoLocator locator; + private final DavResourceLocator locator; - public MacAuthenticationJob(final CryptoLocator locator) { + public MacAuthenticationJob(final DavResourceLocator locator) { if (locator == null) { throw new IllegalArgumentException("locator must not be null."); } @@ -164,18 +162,16 @@ class EncryptedFilePart extends EncryptedFile { @Override public void run() { - final Path path = locator.getEncryptedFilePath(); - if (Files.isRegularFile(path) && Files.isReadable(path)) { - try (final SeekableByteChannel channel = Files.newByteChannel(path, StandardOpenOption.READ)) { - final boolean authentic = cryptor.isAuthentic(channel); - if (!authentic) { - cryptoWarningHandler.macAuthFailed(locator.getResourcePath()); - } - } catch (ClosedByInterruptException ex) { - LOG.debug("Couldn't finish MAC verification due to interruption of worker thread."); - } catch (IOException e) { - LOG.error("IOException during MAC verification of " + path.toString(), e); + assert Files.isRegularFile(filePath); + try (final SeekableByteChannel channel = Files.newByteChannel(filePath, StandardOpenOption.READ)) { + final boolean authentic = cryptor.isAuthentic(channel); + if (!authentic) { + cryptoWarningHandler.macAuthFailed(locator.getResourcePath()); } + } catch (ClosedByInterruptException ex) { + LOG.debug("Couldn't finish MAC verification due to interruption of worker thread."); + } catch (IOException e) { + LOG.error("IOException during MAC verification of " + filePath.toString(), e); } } diff --git a/main/core/src/main/java/org/cryptomator/webdav/jackrabbit/NonExistingNode.java b/main/core/src/main/java/org/cryptomator/webdav/jackrabbit/NonExistingNode.java index 859cd943c..5a2e8e726 100644 --- a/main/core/src/main/java/org/cryptomator/webdav/jackrabbit/NonExistingNode.java +++ b/main/core/src/main/java/org/cryptomator/webdav/jackrabbit/NonExistingNode.java @@ -14,6 +14,7 @@ import java.nio.file.Path; import org.apache.jackrabbit.webdav.DavException; import org.apache.jackrabbit.webdav.DavResource; import org.apache.jackrabbit.webdav.DavResourceIterator; +import org.apache.jackrabbit.webdav.DavResourceLocator; import org.apache.jackrabbit.webdav.DavSession; import org.apache.jackrabbit.webdav.io.InputContext; import org.apache.jackrabbit.webdav.io.OutputContext; @@ -22,7 +23,7 @@ import org.cryptomator.crypto.Cryptor; class NonExistingNode extends AbstractEncryptedNode { - public NonExistingNode(CryptoResourceFactory factory, CryptoLocator locator, DavSession session, LockManager lockManager, Cryptor cryptor) { + public NonExistingNode(CryptoResourceFactory factory, DavResourceLocator locator, DavSession session, LockManager lockManager, Cryptor cryptor) { super(factory, locator, session, lockManager, cryptor); } diff --git a/main/core/src/main/java/org/cryptomator/webdav/jackrabbit/WebDavServlet.java b/main/core/src/main/java/org/cryptomator/webdav/jackrabbit/WebDavServlet.java index 8b5fbc86f..608606eb0 100644 --- a/main/core/src/main/java/org/cryptomator/webdav/jackrabbit/WebDavServlet.java +++ b/main/core/src/main/java/org/cryptomator/webdav/jackrabbit/WebDavServlet.java @@ -47,8 +47,8 @@ public class WebDavServlet extends AbstractWebdavServlet { final String fsRoot = config.getInitParameter(CFG_FS_ROOT); backgroundTaskExecutor = Executors.newCachedThreadPool(); davSessionProvider = new DavSessionProviderImpl(); - davLocatorFactory = new CryptoLocatorFactory(fsRoot, cryptor); - davResourceFactory = new CryptoResourceFactory(cryptor, cryptoWarningHandler, backgroundTaskExecutor); + davLocatorFactory = new CleartextLocatorFactory(config.getServletContext().getContextPath()); // CryptoLocatorFactory(fsRoot, cryptor); + davResourceFactory = new CryptoResourceFactory(cryptor, cryptoWarningHandler, backgroundTaskExecutor, fsRoot); } @Override diff --git a/main/crypto-aes/src/main/java/org/cryptomator/crypto/aes256/Aes256Cryptor.java b/main/crypto-aes/src/main/java/org/cryptomator/crypto/aes256/Aes256Cryptor.java index b33a344bc..2ec02b1fc 100644 --- a/main/crypto-aes/src/main/java/org/cryptomator/crypto/aes256/Aes256Cryptor.java +++ b/main/crypto-aes/src/main/java/org/cryptomator/crypto/aes256/Aes256Cryptor.java @@ -288,8 +288,8 @@ public class Aes256Cryptor implements Cryptor, AesCryptographicConfiguration, Fi } @Override - public String encryptDirectoryPath(String cleartextPath, String nativePathSep) { - final byte[] cleartextBytes = cleartextPath.getBytes(StandardCharsets.UTF_8); + public String encryptDirectoryPath(String cleartextDirectoryId, String nativePathSep) { + final byte[] cleartextBytes = cleartextDirectoryId.getBytes(StandardCharsets.UTF_8); byte[] encryptedBytes = AesSivCipherUtil.sivEncrypt(primaryMasterKey, hMacMasterKey, cleartextBytes); final byte[] hashed = sha256().digest(encryptedBytes); final String encryptedThenHashedPath = ENCRYPTED_FILENAME_CODEC.encodeAsString(hashed); diff --git a/main/crypto-api/src/main/java/org/cryptomator/crypto/Cryptor.java b/main/crypto-api/src/main/java/org/cryptomator/crypto/Cryptor.java index bf7a5f8ba..55c637e5d 100644 --- a/main/crypto-api/src/main/java/org/cryptomator/crypto/Cryptor.java +++ b/main/crypto-api/src/main/java/org/cryptomator/crypto/Cryptor.java @@ -47,11 +47,11 @@ public interface Cryptor extends Destroyable { /** * Encrypts a given plaintext path representing a directory structure. See {@link #encryptFilename(String, CryptorMetadataSupport)} for contents inside directories. * - * @param cleartextPath A relative path (UTF-8 encoded), whose path components are separated by '/' + * @param cleartextDirectoryId A relative path (UTF-8 encoded), whose path components are separated by '/' * @param nativePathSep Path separator like "/" used on local file system. Must not be null, even if cleartextPath is a sole file name without any path separators. * @return Encrypted path. */ - String encryptDirectoryPath(String cleartextPath, String nativePathSep); + String encryptDirectoryPath(String cleartextDirectoryId, String nativePathSep); /** * Encrypts the name of a file. See {@link #encryptDirectoryPath(String, char)} for parent dir.