diff --git a/main/filesystem-crypto/src/main/java/org/cryptomator/crypto/engine/impl/FileContentEncryptorImpl.java b/main/filesystem-crypto/src/main/java/org/cryptomator/crypto/engine/impl/FileContentEncryptorImpl.java index 88ea63c16..ab7d39893 100644 --- a/main/filesystem-crypto/src/main/java/org/cryptomator/crypto/engine/impl/FileContentEncryptorImpl.java +++ b/main/filesystem-crypto/src/main/java/org/cryptomator/crypto/engine/impl/FileContentEncryptorImpl.java @@ -28,7 +28,6 @@ import javax.crypto.SecretKey; import javax.crypto.ShortBufferException; import javax.crypto.spec.IvParameterSpec; -import org.apache.commons.codec.binary.Hex; import org.cryptomator.crypto.engine.FileContentCryptor; import org.cryptomator.crypto.engine.FileContentEncryptor; import org.cryptomator.io.ByteBuffers; @@ -165,7 +164,6 @@ class FileContentEncryptorImpl implements FileContentEncryptor { mac.update(nonce); mac.update(ciphertextBuf); byte[] authenticationCode = mac.doFinal(); - Hex.encodeHexString(authenticationCode); outBuf.put(authenticationCode); // flip and return: diff --git a/main/filesystem-crypto/src/main/java/org/cryptomator/filesystem/crypto/CryptoFile.java b/main/filesystem-crypto/src/main/java/org/cryptomator/filesystem/crypto/CryptoFile.java index 47250e1e0..9cdcecfbf 100644 --- a/main/filesystem-crypto/src/main/java/org/cryptomator/filesystem/crypto/CryptoFile.java +++ b/main/filesystem-crypto/src/main/java/org/cryptomator/filesystem/crypto/CryptoFile.java @@ -35,7 +35,11 @@ public class CryptoFile extends CryptoNode implements File { @Override public ReadableFile openReadable() { boolean authenticate = !fileSystem().delegate().shouldSkipAuthentication(toString()); - return new CryptoReadableFile(cryptor.getFileContentCryptor(), forceGetPhysicalFile().openReadable(), authenticate); + return new CryptoReadableFile(cryptor.getFileContentCryptor(), forceGetPhysicalFile().openReadable(), authenticate, this::reportAuthError); + } + + private void reportAuthError() { + fileSystem().delegate().authenticationFailed(this.toString()); } @Override diff --git a/main/filesystem-crypto/src/main/java/org/cryptomator/filesystem/crypto/CryptoReadableFile.java b/main/filesystem-crypto/src/main/java/org/cryptomator/filesystem/crypto/CryptoReadableFile.java index 1cddf06d6..4a4d13bbd 100644 --- a/main/filesystem-crypto/src/main/java/org/cryptomator/filesystem/crypto/CryptoReadableFile.java +++ b/main/filesystem-crypto/src/main/java/org/cryptomator/filesystem/crypto/CryptoReadableFile.java @@ -8,6 +8,7 @@ *******************************************************************************/ package org.cryptomator.filesystem.crypto; +import java.io.IOException; import java.io.InterruptedIOException; import java.io.UncheckedIOException; import java.nio.ByteBuffer; @@ -15,6 +16,7 @@ import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; +import org.cryptomator.crypto.engine.AuthenticationFailedException; import org.cryptomator.crypto.engine.FileContentCryptor; import org.cryptomator.crypto.engine.FileContentDecryptor; import org.cryptomator.filesystem.ReadableFile; @@ -29,15 +31,17 @@ class CryptoReadableFile implements ReadableFile { private final FileContentCryptor cryptor; private final ReadableFile file; private final boolean authenticate; + private final Runnable onAuthError; private FileContentDecryptor decryptor; private Future readAheadTask; private ByteBuffer bufferedCleartext = EMPTY_BUFFER; - public CryptoReadableFile(FileContentCryptor cryptor, ReadableFile file, boolean authenticate) { + public CryptoReadableFile(FileContentCryptor cryptor, ReadableFile file, boolean authenticate, Runnable onAuthError) { this.header = ByteBuffer.allocate(cryptor.getHeaderSize()); this.cryptor = cryptor; this.file = file; this.authenticate = authenticate; + this.onAuthError = onAuthError; file.position(0); file.read(header); header.flip(); @@ -58,6 +62,8 @@ class CryptoReadableFile implements ReadableFile { return bytesRead; } catch (InterruptedException e) { throw new UncheckedIOException(new InterruptedIOException("Task interrupted while waiting for cleartext")); + } catch (IOException e) { + throw new UncheckedIOException(e); } } @@ -78,9 +84,14 @@ class CryptoReadableFile implements ReadableFile { readAheadTask = executorService.submit(new CiphertextReader(file, decryptor, header.remaining() + ciphertextPos)); } - private void bufferCleartext() throws InterruptedException { + private void bufferCleartext() throws InterruptedException, IOException { if (!bufferedCleartext.hasRemaining()) { - bufferedCleartext = decryptor.cleartext(); + try { + bufferedCleartext = decryptor.cleartext(); + } catch (AuthenticationFailedException e) { + onAuthError.run(); + throw new IOException("Failed to decrypt file due to an authentication error.", e); + } } } diff --git a/main/filesystem-crypto/src/test/java/org/cryptomator/filesystem/crypto/CryptoReadableFileTest.java b/main/filesystem-crypto/src/test/java/org/cryptomator/filesystem/crypto/CryptoReadableFileTest.java index fc540e11e..a137f1145 100644 --- a/main/filesystem-crypto/src/test/java/org/cryptomator/filesystem/crypto/CryptoReadableFileTest.java +++ b/main/filesystem-crypto/src/test/java/org/cryptomator/filesystem/crypto/CryptoReadableFileTest.java @@ -37,8 +37,11 @@ public class CryptoReadableFileTest { } }).thenThrow(new UncheckedIOException(new IOException("failed."))); + Runnable noop = () -> { + }; + @SuppressWarnings("resource") - ReadableFile cryptoReadableFile = new CryptoReadableFile(fileContentCryptor, underlyingFile, true); + ReadableFile cryptoReadableFile = new CryptoReadableFile(fileContentCryptor, underlyingFile, true, noop); cryptoReadableFile.read(ByteBuffer.allocate(1)); } diff --git a/main/frontend-webdav/src/main/java/org/cryptomator/frontend/webdav/jackrabbitservlet/DavFileWithRange.java b/main/frontend-webdav/src/main/java/org/cryptomator/frontend/webdav/jackrabbitservlet/DavFileWithRange.java index 283a5ce59..ac14efa08 100644 --- a/main/frontend-webdav/src/main/java/org/cryptomator/frontend/webdav/jackrabbitservlet/DavFileWithRange.java +++ b/main/frontend-webdav/src/main/java/org/cryptomator/frontend/webdav/jackrabbitservlet/DavFileWithRange.java @@ -23,7 +23,7 @@ import com.google.common.io.ByteStreams; * * @see {@link https://tools.ietf.org/html/rfc7233#section-4} */ -public class DavFileWithRange extends DavFile { +class DavFileWithRange extends DavFile { private final Pair requestRange; diff --git a/main/frontend-webdav/src/main/java/org/cryptomator/frontend/webdav/jackrabbitservlet/DavFileWithUnsatisfiableRange.java b/main/frontend-webdav/src/main/java/org/cryptomator/frontend/webdav/jackrabbitservlet/DavFileWithUnsatisfiableRange.java index 9e9e24b4d..23d3e9b0f 100644 --- a/main/frontend-webdav/src/main/java/org/cryptomator/frontend/webdav/jackrabbitservlet/DavFileWithUnsatisfiableRange.java +++ b/main/frontend-webdav/src/main/java/org/cryptomator/frontend/webdav/jackrabbitservlet/DavFileWithUnsatisfiableRange.java @@ -19,7 +19,7 @@ import com.google.common.io.ByteStreams; * * @see {@link https://tools.ietf.org/html/rfc7233#section-4.2} */ -public class DavFileWithUnsatisfiableRange extends DavFile { +class DavFileWithUnsatisfiableRange extends DavFile { public DavFileWithUnsatisfiableRange(FilesystemResourceFactory factory, LockManager lockManager, DavSession session, FileLocator node) throws DavException { super(factory, lockManager, session, node); diff --git a/main/frontend-webdav/src/main/java/org/cryptomator/frontend/webdav/jackrabbitservlet/ExclusiveSharedLock.java b/main/frontend-webdav/src/main/java/org/cryptomator/frontend/webdav/jackrabbitservlet/ExclusiveSharedLock.java index d6dba5720..1b79afea6 100644 --- a/main/frontend-webdav/src/main/java/org/cryptomator/frontend/webdav/jackrabbitservlet/ExclusiveSharedLock.java +++ b/main/frontend-webdav/src/main/java/org/cryptomator/frontend/webdav/jackrabbitservlet/ExclusiveSharedLock.java @@ -14,7 +14,7 @@ import org.apache.jackrabbit.webdav.lock.LockInfo; import org.apache.jackrabbit.webdav.lock.Scope; import org.apache.jackrabbit.webdav.lock.Type; -public class ExclusiveSharedLock extends AbstractActiveLock { +class ExclusiveSharedLock extends AbstractActiveLock { private final String token; private final Type type; diff --git a/main/frontend-webdav/src/main/java/org/cryptomator/frontend/webdav/jackrabbitservlet/ExclusiveSharedLockManager.java b/main/frontend-webdav/src/main/java/org/cryptomator/frontend/webdav/jackrabbitservlet/ExclusiveSharedLockManager.java index fb7edc2fd..8737fa1eb 100644 --- a/main/frontend-webdav/src/main/java/org/cryptomator/frontend/webdav/jackrabbitservlet/ExclusiveSharedLockManager.java +++ b/main/frontend-webdav/src/main/java/org/cryptomator/frontend/webdav/jackrabbitservlet/ExclusiveSharedLockManager.java @@ -30,7 +30,7 @@ import org.apache.jackrabbit.webdav.lock.Type; import org.cryptomator.filesystem.jackrabbit.FileSystemResourceLocator; import org.cryptomator.filesystem.jackrabbit.FolderLocator; -public class ExclusiveSharedLockManager implements LockManager { +class ExclusiveSharedLockManager implements LockManager { private final ConcurrentMap> lockedResources = new ConcurrentHashMap<>(); diff --git a/main/frontend-webdav/src/main/java/org/cryptomator/frontend/webdav/jackrabbitservlet/WebDavServlet.java b/main/frontend-webdav/src/main/java/org/cryptomator/frontend/webdav/jackrabbitservlet/WebDavServlet.java index 7fd04ba7c..39fec4b8c 100644 --- a/main/frontend-webdav/src/main/java/org/cryptomator/frontend/webdav/jackrabbitservlet/WebDavServlet.java +++ b/main/frontend-webdav/src/main/java/org/cryptomator/frontend/webdav/jackrabbitservlet/WebDavServlet.java @@ -27,7 +27,6 @@ import org.apache.jackrabbit.webdav.lock.Type; import org.apache.jackrabbit.webdav.server.AbstractWebdavServlet; import org.cryptomator.filesystem.Folder; import org.cryptomator.filesystem.jackrabbit.FileSystemResourceLocatorFactory; -import org.eclipse.jetty.http.HttpHeader; import org.eclipse.jetty.io.EofException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -87,16 +86,14 @@ public class WebDavServlet extends AbstractWebdavServlet { @Override protected void doGet(WebdavRequest request, WebdavResponse response, DavResource resource) throws IOException, DavException { - if (request.getHeader(HttpHeader.RANGE.asString()) != null) { - try { - super.doGet(request, response, resource); - } catch (EofException e) { - if (LOG.isDebugEnabled()) { - LOG.trace("Unexpected end of stream during delivery of partial content (client hung up)."); - } - } - } else { + try { super.doGet(request, response, resource); + } catch (EofException e) { + // Jetty EOF (other than IO EOF) is thrown when the connection is closed by the client. + // If the client is no longer interested in further content, we don't care. + if (LOG.isDebugEnabled()) { + LOG.trace("Unexpected end of stream during GET (client hung up)."); + } } } diff --git a/main/frontend-webdav/src/test/java/org/cryptomator/frontend/webdav/InMemoryWebDavServer.java b/main/frontend-webdav/src/test/java/org/cryptomator/frontend/webdav/InMemoryWebDavServer.java index 7c649a6ac..35f12fd24 100644 --- a/main/frontend-webdav/src/test/java/org/cryptomator/frontend/webdav/InMemoryWebDavServer.java +++ b/main/frontend-webdav/src/test/java/org/cryptomator/frontend/webdav/InMemoryWebDavServer.java @@ -33,7 +33,7 @@ public class InMemoryWebDavServer { server.setPort(8080); server.start(); - FileSystem fileSystem = inMemoryFileSystem(); + FileSystem fileSystem = cryptoFileSystem(); ServletContextHandler servlet = server.addServlet(fileSystem, URI.create("http://localhost:8080/foo")); servlet.addFilter(LoggingHttpFilter.class, "/*", EnumSet.of(DispatcherType.REQUEST)); servlet.start();