From 4092e93cfff5a5dc6d8608503147a5a4d7e0b604 Mon Sep 17 00:00:00 2001 From: chenkins Date: Fri, 6 Dec 2024 16:43:55 +0100 Subject: [PATCH 01/12] Add UVF implementation. --- .../ch/cyberduck/core/PathAttributes.java | 8 +- cryptomator/pom.xml | 2 +- .../core/cryptomator/AbstractVault.java | 422 +++++++++++++++++ .../core/cryptomator/ContentReader.java | 15 + .../core/cryptomator/CryptoAclPermission.java | 5 +- .../core/cryptomator/CryptoDirectory.java | 15 +- .../cryptomator/CryptoTransferStatus.java | 4 +- .../core/cryptomator/CryptoVault.java | 445 +++--------------- .../core/cryptomator/CryptorCache.java | 12 +- .../cyberduck/core/cryptomator/UVFVault.java | 403 ++++++++++++++++ .../features/CryptoBulkFeature.java | 10 +- .../features/CryptoChecksumCompute.java | 8 +- .../features/CryptoCopyFeature.java | 6 +- .../features/CryptoDeleteV6Feature.java | 6 +- .../features/CryptoDeleteV7Feature.java | 14 +- .../features/CryptoDirectoryUVFFeature.java | 107 +++++ .../features/CryptoDirectoryV6Feature.java | 16 +- .../features/CryptoDirectoryV7Feature.java | 23 +- .../features/CryptoDownloadFeature.java | 7 +- .../features/CryptoEncryptionFeature.java | 3 +- .../features/CryptoMoveV6Feature.java | 6 +- .../features/CryptoMoveV7Feature.java | 13 +- .../features/CryptoMultipartWriteFeature.java | 6 +- .../features/CryptoReadFeature.java | 6 +- .../features/CryptoTimestampFeature.java | 6 +- .../features/CryptoTouchFeature.java | 6 +- .../features/CryptoUploadFeature.java | 6 +- .../features/CryptoWriteFeature.java | 6 +- .../impl/CryptoDirectoryUVFProvider.java | 190 ++++++++ .../impl/CryptoDirectoryV6Provider.java | 82 ++-- .../impl/CryptoDirectoryV7Provider.java | 45 +- .../core/cryptomator/CryptoVaultTest.java | 4 +- .../core/cryptomator/CryptorCacheTest.java | 11 +- .../features/CryptoBulkFeatureTest.java | 2 +- .../features/CryptoReadFeatureTest.java | 2 +- .../impl/CryptoDirectoryV6ProviderTest.java | 84 +--- .../impl/CryptoDirectoryV7ProviderTest.java | 87 +--- pom.xml | 4 + .../core/cryptomator/UVFIntegrationTest.java | 309 ++++++++++++ s3/src/test/resources/uvf/docker-compose.yml | 44 ++ .../5qTOPMA1BouBRhz_G7qfmKety92geI4=.uvf | Bin 0 -> 105 bytes .../6L/HPWBEU3OJP2EZUCP4CV3HHL47BXVEX/dir.uvf | Bin 0 -> 128 bytes .../GsMMTRvsuuP_6NjgRwopmWcuof-PyRQ=.uvf | Bin 0 -> 105 bytes .../RZ/K7ZH7KBXULNEKBMGX3CU42PGUIAIX4/dir.uvf | Bin 0 -> 128 bytes .../dir.uvf | Bin 0 -> 128 bytes .../SFTPCryptomatorInteroperabilityTest.java | 3 +- 46 files changed, 1794 insertions(+), 659 deletions(-) create mode 100644 cryptomator/src/main/java/ch/cyberduck/core/cryptomator/AbstractVault.java create mode 100644 cryptomator/src/main/java/ch/cyberduck/core/cryptomator/UVFVault.java create mode 100644 cryptomator/src/main/java/ch/cyberduck/core/cryptomator/features/CryptoDirectoryUVFFeature.java create mode 100644 cryptomator/src/main/java/ch/cyberduck/core/cryptomator/impl/CryptoDirectoryUVFProvider.java create mode 100644 s3/src/test/java/ch/cyberduck/core/cryptomator/UVFIntegrationTest.java create mode 100644 s3/src/test/resources/uvf/docker-compose.yml create mode 100644 s3/src/test/resources/uvf/first_vault/d/6L/HPWBEU3OJP2EZUCP4CV3HHL47BXVEX/5qTOPMA1BouBRhz_G7qfmKety92geI4=.uvf create mode 100644 s3/src/test/resources/uvf/first_vault/d/6L/HPWBEU3OJP2EZUCP4CV3HHL47BXVEX/dir.uvf create mode 100644 s3/src/test/resources/uvf/first_vault/d/RZ/K7ZH7KBXULNEKBMGX3CU42PGUIAIX4/GsMMTRvsuuP_6NjgRwopmWcuof-PyRQ=.uvf create mode 100644 s3/src/test/resources/uvf/first_vault/d/RZ/K7ZH7KBXULNEKBMGX3CU42PGUIAIX4/dir.uvf create mode 100644 s3/src/test/resources/uvf/first_vault/d/RZ/K7ZH7KBXULNEKBMGX3CU42PGUIAIX4/rExOms183v5evFwgIKiW0qvbsor1Hg==.uvf/dir.uvf diff --git a/core/src/main/java/ch/cyberduck/core/PathAttributes.java b/core/src/main/java/ch/cyberduck/core/PathAttributes.java index 69ae359ef2b..807a4c4b85e 100644 --- a/core/src/main/java/ch/cyberduck/core/PathAttributes.java +++ b/core/src/main/java/ch/cyberduck/core/PathAttributes.java @@ -156,7 +156,7 @@ public class PathAttributes extends Attributes implements Serializable { /** * Unique identifier for cryptomator */ - private String directoryId; + private byte[] directoryId; private Map custom = Collections.emptyMap(); @@ -480,11 +480,11 @@ public PathAttributes setLockId(final String lockId) { return this; } - public String getDirectoryId() { + public byte[] getDirectoryId() { return directoryId; } - public PathAttributes setDirectoryId(final String directoryId) { + public PathAttributes setDirectoryId(final byte[] directoryId) { this.directoryId = directoryId; return this; } @@ -803,7 +803,7 @@ public PathAttributes setLockId(final String lockId) { } @Override - public PathAttributes setDirectoryId(final String directoryId) { + public PathAttributes setDirectoryId(final byte[] directoryId) { return this; } diff --git a/cryptomator/pom.xml b/cryptomator/pom.xml index b51549a6c22..fa588993b71 100644 --- a/cryptomator/pom.xml +++ b/cryptomator/pom.xml @@ -25,7 +25,7 @@ jar - 2.1.2.1 + 2.3.0.uvfdraft-SNAPSHOT diff --git a/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/AbstractVault.java b/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/AbstractVault.java new file mode 100644 index 00000000000..4228f00040b --- /dev/null +++ b/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/AbstractVault.java @@ -0,0 +1,422 @@ +package ch.cyberduck.core.cryptomator; + +/* + * Copyright (c) 2002-2025 iterate GmbH. All rights reserved. + * https://cyberduck.io/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +import ch.cyberduck.core.ListService; +import ch.cyberduck.core.Path; +import ch.cyberduck.core.PathAttributes; +import ch.cyberduck.core.Permission; +import ch.cyberduck.core.Session; +import ch.cyberduck.core.SimplePathPredicate; +import ch.cyberduck.core.UrlProvider; +import ch.cyberduck.core.cryptomator.features.*; +import ch.cyberduck.core.exception.BackgroundException; +import ch.cyberduck.core.features.*; +import ch.cyberduck.core.preferences.PreferencesFactory; +import ch.cyberduck.core.shared.DefaultTouchFeature; +import ch.cyberduck.core.transfer.TransferStatus; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.cryptomator.cryptolib.api.AuthenticationFailedException; +import org.cryptomator.cryptolib.api.Cryptor; +import org.cryptomator.cryptolib.api.FileContentCryptor; +import org.cryptomator.cryptolib.api.FileHeaderCryptor; + +import java.util.EnumSet; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import com.google.common.io.BaseEncoding; + +public abstract class AbstractVault implements Vault { + + private static final Logger log = LogManager.getLogger(AbstractVault.class); + + public static final int VAULT_VERSION_DEPRECATED = 6; + public static final int VAULT_VERSION = PreferencesFactory.get().getInteger("cryptomator.vault.version"); + + public static final String DIR_PREFIX = "0"; + + private static final Pattern BASE32_PATTERN = Pattern.compile("^0?(([A-Z2-7]{8})*[A-Z2-7=]{8})"); + + public abstract Path getMasterkey(); + + public abstract Path getConfig(); + + public abstract int getVersion(); + + public abstract FileHeaderCryptor getFileHeaderCryptor(); + + public abstract FileContentCryptor getFileContentCryptor(); + + public abstract CryptorCache getFileNameCryptor(); + + public abstract CryptoFilename getFilenameProvider(); + + public abstract CryptoDirectory getDirectoryProvider(); + + public abstract Cryptor getCryptor(); + + public abstract int getNonceSize(); + + public int numberOfChunks(long cleartextFileSize) { + return (int) (cleartextFileSize / this.getFileContentCryptor().cleartextChunkSize() + + ((cleartextFileSize % this.getFileContentCryptor().cleartextChunkSize() > 0) ? 1 : 0)); + } + + public long toCleartextSize(final long cleartextFileOffset, final long ciphertextFileSize) throws CryptoInvalidFilesizeException { + if(TransferStatus.UNKNOWN_LENGTH == ciphertextFileSize) { + return TransferStatus.UNKNOWN_LENGTH; + } + final int headerSize; + if(0L == cleartextFileOffset) { + headerSize = this.getFileHeaderCryptor().headerSize(); + } + else { + headerSize = 0; + } + try { + return this.getFileContentCryptor().cleartextSize(ciphertextFileSize - headerSize); + } + catch(AssertionError e) { + throw new CryptoInvalidFilesizeException(String.format("Encrypted file size must be at least %d bytes", headerSize)); + } + catch(IllegalArgumentException e) { + throw new CryptoInvalidFilesizeException(String.format("Invalid file size. %s", e.getMessage())); + } + } + + @Override + public State getState() { + return this.isUnlocked() ? State.open : State.closed; + } + + @Override + public long toCiphertextSize(final long cleartextFileOffset, final long cleartextFileSize) { + if(TransferStatus.UNKNOWN_LENGTH == cleartextFileSize) { + return TransferStatus.UNKNOWN_LENGTH; + } + final int headerSize; + if(0L == cleartextFileOffset) { + headerSize = this.getCryptor().fileHeaderCryptor().headerSize(); + } + else { + headerSize = 0; + } + return headerSize + this.getCryptor().fileContentCryptor().ciphertextSize(cleartextFileSize); + } + + @Override + public Path encrypt(Session session, Path file) throws BackgroundException { + return this.encrypt(session, file, false); + } + + @Override + public Path encrypt(Session session, Path file, boolean metadata) throws BackgroundException { + final Path encrypted; + if(file.isFile() || metadata) { + if(file.getType().contains(Path.Type.vault)) { + log.warn("Skip file {} because it is marked as an internal vault path", file); + return file; + } + if(new SimplePathPredicate(file).test(this.getHome())) { + log.warn("Skip vault home {} because the root has no metadata file", file); + return file; + } + final Path parent; + final String filename; + if(file.getType().contains(Path.Type.encrypted)) { + final Path decrypted = file.attributes().getDecrypted(); + parent = this.getDirectoryProvider().toEncrypted(session, decrypted.getParent()); + filename = this.getDirectoryProvider().toEncrypted(session, decrypted.getParent(), decrypted.getName(), decrypted.getType()); + } + else { + parent = this.getDirectoryProvider().toEncrypted(session, file.getParent()); + filename = this.getDirectoryProvider().toEncrypted(session, file.getParent(), file.getName(), file.getType()); + } + final PathAttributes attributes = new PathAttributes(file.attributes()); + attributes.setDirectoryId(null); + if(!file.isFile() && !metadata) { + // The directory is different from the metadata file used to resolve the actual folder + attributes.setVersionId(null); + attributes.setFileId(null); + } + // Translate file size + attributes.setSize(this.toCiphertextSize(0L, file.attributes().getSize())); + final EnumSet type = EnumSet.copyOf(file.getType()); + if(metadata && this.getVersion() == VAULT_VERSION_DEPRECATED) { + type.remove(Path.Type.directory); + type.add(Path.Type.file); + } + type.remove(Path.Type.decrypted); + type.add(Path.Type.encrypted); + encrypted = new Path(parent, filename, type, attributes); + } + else { + if(file.getType().contains(Path.Type.encrypted)) { + log.warn("Skip file {} because it is already marked as an encrypted path", file); + return file; + } + if(file.getType().contains(Path.Type.vault)) { + return this.getDirectoryProvider().toEncrypted(session, this.getHome()); + } + encrypted = this.getDirectoryProvider().toEncrypted(session, file); + } + // Add reference to decrypted file + if(!file.getType().contains(Path.Type.encrypted)) { + encrypted.attributes().setDecrypted(file); + } + // Add reference for vault + file.attributes().setVault(this.getHome()); + encrypted.attributes().setVault(this.getHome()); + return encrypted; + } + + @Override + public Path decrypt(final Session session, final Path file) throws BackgroundException { + if(file.getType().contains(Path.Type.decrypted)) { + log.warn("Skip file {} because it is already marked as an decrypted path", file); + return file; + } + if(file.getType().contains(Path.Type.vault)) { + log.warn("Skip file {} because it is marked as an internal vault path", file); + return file; + } + final Path inflated = this.inflate(session, file); + final Pattern pattern = this.getVersion() == VAULT_VERSION_DEPRECATED ? BASE32_PATTERN : this.getBase64URLPattern(); + final Matcher m = pattern.matcher(inflated.getName()); + if(m.matches()) { + final String ciphertext = m.group(1); + try { + final String cleartextFilename = this.getFileNameCryptor().decryptFilename( + this.getVersion() == VAULT_VERSION_DEPRECATED ? BaseEncoding.base32() : BaseEncoding.base64Url(), + ciphertext, this.getDirectoryProvider().getOrCreateDirectoryId(session, file.getParent())); + final PathAttributes attributes = new PathAttributes(file.attributes()); + if(this.isDirectory(inflated)) { + if(Permission.EMPTY != attributes.getPermission()) { + final Permission permission = new Permission(attributes.getPermission()); + permission.setUser(permission.getUser().or(Permission.Action.execute)); + permission.setGroup(permission.getGroup().or(Permission.Action.execute)); + permission.setOther(permission.getOther().or(Permission.Action.execute)); + attributes.setPermission(permission); + } + // Reset size for folders + attributes.setSize(-1L); + attributes.setVersionId(null); + attributes.setFileId(null); + } + else { + // Translate file size + attributes.setSize(this.toCleartextSize(0L, file.attributes().getSize())); + } + // Add reference to encrypted file + attributes.setEncrypted(file); + // Add reference for vault + attributes.setVault(this.getHome()); + final EnumSet type = EnumSet.copyOf(file.getType()); + type.remove(this.isDirectory(inflated) ? Path.Type.file : Path.Type.directory); + type.add(this.isDirectory(inflated) ? Path.Type.directory : Path.Type.file); + type.remove(Path.Type.encrypted); + type.add(Path.Type.decrypted); + final Path decrypted = new Path(file.getParent().attributes().getDecrypted(), cleartextFilename, type, attributes); + if(type.contains(Path.Type.symboliclink)) { + decrypted.setSymlinkTarget(file.getSymlinkTarget()); + } + return decrypted; + } + catch(AuthenticationFailedException e) { + throw new CryptoAuthenticationException( + "Failure to decrypt due to an unauthentic ciphertext", e); + } + } + else { + throw new CryptoFilenameMismatchException( + String.format("Failure to decrypt %s due to missing pattern match for %s", inflated.getName(), pattern)); + } + } + + private boolean isDirectory(final Path p) { + if(this.getVersion() == VAULT_VERSION_DEPRECATED) { + return p.getName().startsWith(DIR_PREFIX); + } + return p.isDirectory(); + } + + private Path inflate(final Session session, final Path file) throws BackgroundException { + final String fileName = file.getName(); + if(this.getFilenameProvider().isDeflated(fileName)) { + final String filename = this.getFilenameProvider().inflate(session, fileName); + return new Path(file.getParent(), filename, EnumSet.of(Path.Type.file), file.attributes()); + } + return file; + } + + public synchronized boolean isUnlocked() { + return this.getCryptor() != null; + } + + @Override + public boolean contains(final Path file) { + if(this.isUnlocked()) { + return new SimplePathPredicate(file).test(this.getHome()) || file.isChild(this.getHome()); + } + return false; + } + + public abstract String getRegularFileExtension(); + + public abstract String getDirectoryMetadataFilename(); + + public abstract String getBackupDirectoryMetadataFilename(); + + public abstract Pattern getBase64URLPattern(); + + public abstract byte[] getRootDirId(); + + @Override + public synchronized void close() { + if(this.isUnlocked()) { + if(this.getCryptor() != null) { + getCryptor().destroy(); + } + if(this.getDirectoryProvider() != null) { + this.getDirectoryProvider().destroy(); + } + if(this.getFilenameProvider() != null) { + this.getFilenameProvider().destroy(); + } + } + } + + @Override + @SuppressWarnings("unchecked") + public T getFeature(final Session session, final Class type, final T delegate) { + if(this.isUnlocked()) { + if(type == ListService.class) { + return (T) new CryptoListService(session, (ListService) delegate, this); + } + if(type == Touch.class) { + // Use default touch feature because touch with remote implementation will not add encrypted file header + return (T) new CryptoTouchFeature(session, new DefaultTouchFeature(session), this); + } + if(type == Directory.class) { + return (T) (this.getVersion() == VAULT_VERSION_DEPRECATED ? + new CryptoDirectoryV6Feature(session, (Directory) delegate, this) : + new CryptoDirectoryV7Feature(session, (Directory) delegate, this) + ); + } + if(type == Upload.class) { + return (T) new CryptoUploadFeature(session, (Upload) delegate, this); + } + if(type == Download.class) { + return (T) new CryptoDownloadFeature(session, (Download) delegate, this); + } + if(type == Read.class) { + return (T) new CryptoReadFeature(session, (Read) delegate, this); + } + if(type == Write.class) { + return (T) new CryptoWriteFeature(session, (Write) delegate, this); + } + if(type == MultipartWrite.class) { + return (T) new CryptoMultipartWriteFeature(session, (Write) delegate, this); + } + if(type == Move.class) { + return (T) (this.getVersion() == VAULT_VERSION_DEPRECATED ? + new CryptoMoveV6Feature(session, (Move) delegate, this) : + new CryptoMoveV7Feature(session, (Move) delegate, this)); + + } + if(type == AttributesFinder.class) { + return (T) new CryptoAttributesFeature(session, (AttributesFinder) delegate, this); + } + if(type == Find.class) { + return (T) new CryptoFindFeature(session, (Find) delegate, this); + } + if(type == UrlProvider.class) { + return (T) new CryptoUrlProvider(session, (UrlProvider) delegate, this); + } + if(type == FileIdProvider.class) { + return (T) new CryptoFileIdProvider(session, (FileIdProvider) delegate, this); + } + if(type == VersionIdProvider.class) { + return (T) new CryptoVersionIdProvider(session, (VersionIdProvider) delegate, this); + } + if(type == Delete.class) { + return (T) (this.getVersion() == VAULT_VERSION_DEPRECATED ? + new CryptoDeleteV6Feature(session, (Delete) delegate, this) : + new CryptoDeleteV7Feature(session, (Delete) delegate, this)); + } + if(type == Trash.class) { + return (T) (this.getVersion() == VAULT_VERSION_DEPRECATED ? + new CryptoDeleteV6Feature(session, (Delete) delegate, this) : + new CryptoDeleteV7Feature(session, (Delete) delegate, this)); + } + if(type == Symlink.class) { + return (T) new CryptoSymlinkFeature(session, (Symlink) delegate, this); + } + if(type == Headers.class) { + return (T) new CryptoHeadersFeature(session, (Headers) delegate, this); + } + if(type == Compress.class) { + return (T) new CryptoCompressFeature(session, (Compress) delegate, this); + } + if(type == Bulk.class) { + return (T) new CryptoBulkFeature(session, (Bulk) delegate, this); + } + if(type == UnixPermission.class) { + return (T) new CryptoUnixPermission(session, (UnixPermission) delegate, this); + } + if(type == AclPermission.class) { + return (T) new CryptoAclPermission(session, (AclPermission) delegate, this); + } + if(type == Copy.class) { + return (T) new CryptoCopyFeature(session, (Copy) delegate, this); + } + if(type == Timestamp.class) { + return (T) new CryptoTimestampFeature(session, (Timestamp) delegate, this); + } + if(type == Encryption.class) { + return (T) new CryptoEncryptionFeature(session, (Encryption) delegate, this); + } + if(type == Lifecycle.class) { + return (T) new CryptoLifecycleFeature(session, (Lifecycle) delegate, this); + } + if(type == Location.class) { + return (T) new CryptoLocationFeature(session, (Location) delegate, this); + } + if(type == Lock.class) { + return (T) new CryptoLockFeature(session, (Lock) delegate, this); + } + if(type == Logging.class) { + return (T) new CryptoLoggingFeature(session, (Logging) delegate, this); + } + if(type == Redundancy.class) { + return (T) new CryptoRedundancyFeature(session, (Redundancy) delegate, this); + } + if(type == Search.class) { + return (T) new CryptoSearchFeature(session, (Search) delegate, this); + } + if(type == TransferAcceleration.class) { + return (T) new CryptoTransferAccelerationFeature<>(session, (TransferAcceleration) delegate, this); + } + if(type == Versioning.class) { + return (T) new CryptoVersioningFeature(session, (Versioning) delegate, this); + } + } + return delegate; + } +} diff --git a/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/ContentReader.java b/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/ContentReader.java index 21282729888..452af7e12b5 100644 --- a/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/ContentReader.java +++ b/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/ContentReader.java @@ -21,10 +21,12 @@ import ch.cyberduck.core.Session; import ch.cyberduck.core.exception.BackgroundException; import ch.cyberduck.core.features.Read; +import ch.cyberduck.core.io.StreamCopier; import ch.cyberduck.core.transfer.TransferStatus; import org.apache.commons.io.IOUtils; +import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; @@ -49,6 +51,19 @@ public String read(final Path file) throws BackgroundException { } } + public byte[] readBytes(final Path file) throws BackgroundException { + final Read read = session._getFeature(Read.class); + final TransferStatus status = new TransferStatus().setLength(file.attributes().getSize()); + try (final InputStream in = read.read(file, status, new DisabledConnectionCallback())) { + final ByteArrayOutputStream out = new ByteArrayOutputStream(); + new StreamCopier(status, status).transfer(in, out); + return out.toByteArray(); + } + catch(IOException e) { + throw new DefaultIOExceptionMappingService().map(e); + } + } + public Reader getReader(final Path file) throws BackgroundException { final Read read = session._getFeature(Read.class); return new InputStreamReader(read.read(file, new TransferStatus().setLength(file.attributes().getSize()), new DisabledConnectionCallback()), StandardCharsets.UTF_8); diff --git a/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/CryptoAclPermission.java b/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/CryptoAclPermission.java index 4b31674db9b..7bcac44e2f3 100644 --- a/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/CryptoAclPermission.java +++ b/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/CryptoAclPermission.java @@ -22,16 +22,15 @@ import ch.cyberduck.core.features.AclPermission; import ch.cyberduck.core.transfer.TransferStatus; -import java.util.EnumSet; import java.util.List; public class CryptoAclPermission implements AclPermission { private final Session session; private final AclPermission delegate; - private final CryptoVault cryptomator; + private final AbstractVault cryptomator; - public CryptoAclPermission(final Session session, final AclPermission delegate, final CryptoVault cryptomator) { + public CryptoAclPermission(final Session session, final AclPermission delegate, final AbstractVault cryptomator) { this.session = session; this.delegate = delegate; diff --git a/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/CryptoDirectory.java b/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/CryptoDirectory.java index 88ccb32e736..dd26c1c4a15 100644 --- a/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/CryptoDirectory.java +++ b/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/CryptoDirectory.java @@ -27,21 +27,20 @@ public interface CryptoDirectory { * Get encrypted filename for given clear text filename with id of parent encrypted directory. * * @param session Connection - * @param directoryId Parent folder directory id + * @param parent Parent folder * @param filename Clear text filename * @param type File type * @return Encrypted filename */ - String toEncrypted(Session session, String directoryId, String filename, EnumSet type) throws BackgroundException; + String toEncrypted(Session session, Path parent, String filename, EnumSet type) throws BackgroundException; /** * Get encrypted reference for clear text directory path. * - * @param session Connection - * @param directoryId Directory ID or null to read directory id from metadata file - * @param directory Clear text + * @param session Connection + * @param directory Clear text */ - Path toEncrypted(Session session, String directoryId, Path directory) throws BackgroundException; + Path toEncrypted(Session session, Path directory) throws BackgroundException; /** * Remove from cache @@ -49,4 +48,8 @@ public interface CryptoDirectory { void delete(Path directory); void destroy(); + + byte[] getOrCreateDirectoryId(Session session, Path directory) throws BackgroundException; + + byte[] createDirectoryId(final Path directory); } diff --git a/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/CryptoTransferStatus.java b/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/CryptoTransferStatus.java index bcb52f32f5f..0c63bdf7f48 100644 --- a/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/CryptoTransferStatus.java +++ b/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/CryptoTransferStatus.java @@ -27,9 +27,9 @@ public class CryptoTransferStatus extends ProxyTransferStatus implements StreamCancelation, StreamProgress { private static final Logger log = LogManager.getLogger(CryptoTransferStatus.class); - private final CryptoVault vault; + private final AbstractVault vault; - public CryptoTransferStatus(final CryptoVault vault, final TransferStatus proxy) { + public CryptoTransferStatus(final AbstractVault vault, final TransferStatus proxy) { super(proxy); this.vault = vault; this.setLength(vault.toCiphertextSize(proxy.getOffset(), proxy.getLength())) diff --git a/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/CryptoVault.java b/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/CryptoVault.java index 57c45623467..16d43db772b 100644 --- a/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/CryptoVault.java +++ b/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/CryptoVault.java @@ -15,8 +15,19 @@ * GNU General Public License for more details. */ -import ch.cyberduck.core.*; -import ch.cyberduck.core.cryptomator.features.*; +import ch.cyberduck.core.Credentials; +import ch.cyberduck.core.DescriptiveUrl; +import ch.cyberduck.core.Host; +import ch.cyberduck.core.LocaleFactory; +import ch.cyberduck.core.LoginOptions; +import ch.cyberduck.core.PasswordCallback; +import ch.cyberduck.core.PasswordStore; +import ch.cyberduck.core.PasswordStoreFactory; +import ch.cyberduck.core.Path; +import ch.cyberduck.core.PathAttributes; +import ch.cyberduck.core.Session; +import ch.cyberduck.core.SimplePathPredicate; +import ch.cyberduck.core.UUIDRandomStringService; import ch.cyberduck.core.cryptomator.impl.CryptoDirectoryV6Provider; import ch.cyberduck.core.cryptomator.impl.CryptoDirectoryV7Provider; import ch.cyberduck.core.cryptomator.impl.CryptoFilenameV6Provider; @@ -26,10 +37,11 @@ import ch.cyberduck.core.exception.LocalAccessDeniedException; import ch.cyberduck.core.exception.LoginCanceledException; import ch.cyberduck.core.exception.NotfoundException; -import ch.cyberduck.core.features.*; +import ch.cyberduck.core.features.Directory; +import ch.cyberduck.core.features.Encryption; +import ch.cyberduck.core.features.Write; import ch.cyberduck.core.preferences.Preferences; import ch.cyberduck.core.preferences.PreferencesFactory; -import ch.cyberduck.core.shared.DefaultTouchFeature; import ch.cyberduck.core.shared.DefaultUrlProvider; import ch.cyberduck.core.transfer.TransferStatus; import ch.cyberduck.core.vault.DefaultVaultRegistry; @@ -38,13 +50,13 @@ import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; -import org.cryptomator.cryptolib.api.AuthenticationFailedException; import org.cryptomator.cryptolib.api.Cryptor; import org.cryptomator.cryptolib.api.CryptorProvider; import org.cryptomator.cryptolib.api.FileContentCryptor; import org.cryptomator.cryptolib.api.FileHeaderCryptor; import org.cryptomator.cryptolib.api.InvalidPassphraseException; import org.cryptomator.cryptolib.api.Masterkey; +import org.cryptomator.cryptolib.api.PerpetualMasterkey; import org.cryptomator.cryptolib.common.MasterkeyFile; import org.cryptomator.cryptolib.common.MasterkeyFileAccess; @@ -58,7 +70,6 @@ import java.text.MessageFormat; import java.util.EnumSet; import java.util.Objects; -import java.util.regex.Matcher; import java.util.regex.Pattern; import com.auth0.jwt.JWT; @@ -68,7 +79,6 @@ import com.auth0.jwt.exceptions.JWTVerificationException; import com.auth0.jwt.exceptions.SignatureVerificationException; import com.auth0.jwt.interfaces.DecodedJWT; -import com.google.common.io.BaseEncoding; import com.google.gson.JsonParseException; import static ch.cyberduck.core.vault.DefaultVaultRegistry.DEFAULT_VAULTCONFIG_FILE_NAME; @@ -76,22 +86,23 @@ /** * Cryptomator vault implementation */ -public class CryptoVault implements Vault { +public class CryptoVault extends AbstractVault { private static final Logger log = LogManager.getLogger(CryptoVault.class); - public static final int VAULT_VERSION_DEPRECATED = 6; - public static final int VAULT_VERSION = PreferencesFactory.get().getInteger("cryptomator.vault.version"); public static final byte[] VAULT_PEPPER = PreferencesFactory.get().getProperty("cryptomator.vault.pepper").getBytes(StandardCharsets.UTF_8); - public static final String DIR_PREFIX = "0"; - - private static final Pattern BASE32_PATTERN = Pattern.compile("^0?(([A-Z2-7]{8})*[A-Z2-7=]{8})"); - private static final Pattern BASE64URL_PATTERN = Pattern.compile("^([A-Za-z0-9_=-]+).c9r"); - private static final String JSON_KEY_VAULTVERSION = "format"; private static final String JSON_KEY_CIPHERCONFIG = "cipherCombo"; private static final String JSON_KEY_SHORTENING_THRESHOLD = "shorteningThreshold"; + private static final String REGULAR_FILE_EXTENSION = ".c9r"; + private static final String FILENAME_DIRECTORYID = "dir"; + private static final String DIRECTORY_METADATA_FILENAME = String.format("%s%s", FILENAME_DIRECTORYID, REGULAR_FILE_EXTENSION); + private static final String BACKUP_FILENAME_DIRECTORYID = "dirid"; + private static final String BACKUP_DIRECTORY_METADATA_FILENAME = String.format("%s%s", BACKUP_FILENAME_DIRECTORYID, REGULAR_FILE_EXTENSION); + + private static final Pattern BASE64URL_PATTERN = Pattern.compile("^([A-Za-z0-9_=-]+)" + REGULAR_FILE_EXTENSION); + /** * Root of vault directory */ @@ -121,6 +132,7 @@ public CryptoVault(final Path home, final String masterkey, final String config, this.home = home; this.masterkey = new Path(home, masterkey, EnumSet.of(Path.Type.file, Path.Type.vault)); this.config = new Path(home, config, EnumSet.of(Path.Type.file, Path.Type.vault)); + this.pepper = pepper; // New vault home with vault flag set for internal use final EnumSet type = EnumSet.copyOf(home.getType()); @@ -150,7 +162,7 @@ public synchronized Path create(final Session session, final String region, f } final String passphrase = credentials.getPassword(); final ByteArrayOutputStream mkArray = new ByteArrayOutputStream(); - final Masterkey mk = Masterkey.generate(FastSecureRandomProvider.get().provide()); + final PerpetualMasterkey mk = Masterkey.generate(FastSecureRandomProvider.get().provide()); final MasterkeyFileAccess access = new MasterkeyFileAccess(pepper, FastSecureRandomProvider.get().provide()); final MasterkeyFile masterkeyFile; try { @@ -187,7 +199,7 @@ public synchronized Path create(final Session session, final String region, f this.open(new VaultConfig(version, CryptoFilenameV6Provider.DEFAULT_NAME_SHORTENING_THRESHOLD, CryptorProvider.Scheme.SIV_CTRMAC, null, null).withMasterkeyFile(masterkeyFile), passphrase); } - final Path secondLevel = directoryProvider.toEncrypted(session, home.attributes().getDirectoryId(), home); + final Path secondLevel = directoryProvider.toEncrypted(session, home); final Path firstLevel = secondLevel.getParent(); final Path dataDir = firstLevel.getParent(); log.debug("Create vault root directory at {}", secondLevel); @@ -240,8 +252,7 @@ private static VaultConfig parseVaultConfigFromMasterKey(final MasterkeyFile mas CryptorProvider.Scheme.SIV_CTRMAC, null, null); } - - private static VaultConfig parseVaultConfigFromJWT(final String token) { + public static VaultConfig parseVaultConfigFromJWT(final String token) { final DecodedJWT decoded = JWT.decode(token); return new VaultConfig( decoded.getClaim(JSON_KEY_VAULTVERSION).asInt(), @@ -305,18 +316,7 @@ public void unlock(final VaultConfig vaultConfig, final String passphrase, final @Override public synchronized void close() { - if(this.isUnlocked()) { - log.info("Close vault with cryptor {}", cryptor); - if(cryptor != null) { - cryptor.destroy(); - } - if(directoryProvider != null) { - directoryProvider.destroy(); - } - if(filenameProvider != null) { - filenameProvider.destroy(); - } - } + super.close(); cryptor = null; fileNameCryptor = null; } @@ -330,24 +330,19 @@ protected CryptoFilename createFilenameProvider(final VaultConfig vaultConfig) { } } - protected CryptoDirectory createDirectoryProvider(final VaultConfig vaultConfig) { + protected CryptoDirectory createDirectoryProvider(final VaultConfig vaultConfig, final CryptoFilename filenameProvider, final CryptorCache filenameCryptor) { switch(vaultConfig.version) { case VAULT_VERSION_DEPRECATED: - return new CryptoDirectoryV6Provider(vault, this); + return new CryptoDirectoryV6Provider(vault, filenameProvider, filenameCryptor); default: - return new CryptoDirectoryV7Provider(vault, this); + return new CryptoDirectoryV7Provider(this, filenameProvider, filenameCryptor); } } protected void open(final VaultConfig vaultConfig, final CharSequence passphrase) throws BackgroundException { - this.open(vaultConfig, passphrase, this.createFilenameProvider(vaultConfig), this.createDirectoryProvider(vaultConfig)); - } - - protected void open(final VaultConfig vaultConfig, final CharSequence passphrase, - final CryptoFilename filenameProvider, final CryptoDirectory directoryProvider) throws BackgroundException { try { - final Masterkey masterKey = this.getMasterKey(vaultConfig.getMkfile(), passphrase); - this.open(vaultConfig, masterKey, filenameProvider, directoryProvider); + final PerpetualMasterkey masterKey = this.getMasterKey(vaultConfig.getMkfile(), passphrase); + this.open(vaultConfig, masterKey); } catch(IllegalArgumentException | IOException e) { throw new VaultException("Failure reading key file", e); @@ -357,388 +352,102 @@ protected void open(final VaultConfig vaultConfig, final CharSequence passphrase } } - protected void open(final VaultConfig vaultConfig, final Masterkey masterKey) throws BackgroundException { - this.open(vaultConfig, masterKey, this.createFilenameProvider(vaultConfig), this.createDirectoryProvider(vaultConfig)); - } - - protected void open(final VaultConfig vaultConfig, final Masterkey masterKey, - final CryptoFilename filenameProvider, final CryptoDirectory directoryProvider) throws BackgroundException { + protected void open(final VaultConfig vaultConfig, final PerpetualMasterkey masterKey) throws BackgroundException { this.vaultVersion = vaultConfig.version; final CryptorProvider provider = CryptorProvider.forScheme(vaultConfig.getCipherCombo()); log.debug("Initialized crypto provider {}", provider); vaultConfig.verify(masterKey.getEncoded(), VAULT_VERSION); this.cryptor = provider.provide(masterKey, FastSecureRandomProvider.get().provide()); this.fileNameCryptor = new CryptorCache(cryptor.fileNameCryptor()); - this.filenameProvider = filenameProvider; - this.directoryProvider = directoryProvider; + this.filenameProvider = this.createFilenameProvider(vaultConfig); + this.directoryProvider = this.createDirectoryProvider(vaultConfig, this.filenameProvider, this.fileNameCryptor); this.nonceSize = vaultConfig.getNonceSize(); } - private Masterkey getMasterKey(final MasterkeyFile mkFile, final CharSequence passphrase) throws IOException { + private PerpetualMasterkey getMasterKey(final MasterkeyFile mkFile, final CharSequence passphrase) throws IOException { final StringWriter writer = new StringWriter(); mkFile.write(writer); return new MasterkeyFileAccess(pepper, FastSecureRandomProvider.get().provide()).load( new ByteArrayInputStream(writer.getBuffer().toString().getBytes(StandardCharsets.UTF_8)), passphrase); } - public synchronized boolean isUnlocked() { - return cryptor != null; - } - - @Override - public State getState() { - return this.isUnlocked() ? State.open : State.closed; - } - - @Override - public boolean contains(final Path file) { - return new SimplePathPredicate(file).test(home) || file.isChild(home); - } - - @Override - public Path encrypt(final Session session, final Path file) throws BackgroundException { - return this.encrypt(session, file, file.attributes().getDirectoryId(), false); - } - - @Override - public Path encrypt(final Session session, final Path file, boolean metadata) throws BackgroundException { - return this.encrypt(session, file, file.attributes().getDirectoryId(), metadata); - } - - public Path encrypt(final Session session, final Path file, final String directoryId, boolean metadata) throws BackgroundException { - final Path encrypted; - if(file.isFile() || metadata) { - if(file.getType().contains(Path.Type.vault)) { - log.warn("Skip file {} because it is marked as an internal vault path", file); - return file; - } - if(new SimplePathPredicate(file).test(home)) { - log.warn("Skip vault home {} because the root has no metadata file", file); - return file; - } - final Path parent; - final String filename; - if(file.getType().contains(Path.Type.encrypted)) { - final Path decrypted = file.attributes().getDecrypted(); - parent = directoryProvider.toEncrypted(session, decrypted.getParent().attributes().getDirectoryId(), decrypted.getParent()); - filename = directoryProvider.toEncrypted(session, parent.attributes().getDirectoryId(), decrypted.getName(), decrypted.getType()); - } - else { - parent = directoryProvider.toEncrypted(session, file.getParent().attributes().getDirectoryId(), file.getParent()); - filename = directoryProvider.toEncrypted(session, parent.attributes().getDirectoryId(), file.getName(), file.getType()); - } - final PathAttributes attributes = new PathAttributes(file.attributes()); - attributes.setDirectoryId(null); - if(!file.isFile() && !metadata) { - // The directory is different from the metadata file used to resolve the actual folder - attributes.setVersionId(null); - attributes.setFileId(null); - } - // Translate file size - attributes.setSize(this.toCiphertextSize(0L, file.attributes().getSize())); - final EnumSet type = EnumSet.copyOf(file.getType()); - if(metadata && vaultVersion == VAULT_VERSION_DEPRECATED) { - type.remove(Path.Type.directory); - type.add(Path.Type.file); - } - type.remove(Path.Type.decrypted); - type.add(Path.Type.encrypted); - encrypted = new Path(parent, filename, type, attributes); - } - else { - if(file.getType().contains(Path.Type.encrypted)) { - log.warn("Skip file {} because it is already marked as an encrypted path", file); - return file; - } - if(file.getType().contains(Path.Type.vault)) { - return directoryProvider.toEncrypted(session, home.attributes().getDirectoryId(), home); - } - encrypted = directoryProvider.toEncrypted(session, directoryId, file); - } - // Add reference to decrypted file - if(!file.getType().contains(Path.Type.encrypted)) { - encrypted.attributes().setDecrypted(file); - } - // Add reference for vault - file.attributes().setVault(home); - encrypted.attributes().setVault(home); - return encrypted; - } - - @Override - public Path decrypt(final Session session, final Path file) throws BackgroundException { - if(file.getType().contains(Path.Type.decrypted)) { - log.warn("Skip file {} because it is already marked as an decrypted path", file); - return file; - } - if(file.getType().contains(Path.Type.vault)) { - log.warn("Skip file {} because it is marked as an internal vault path", file); - return file; - } - final Path inflated = this.inflate(session, file); - final Pattern pattern = vaultVersion == VAULT_VERSION_DEPRECATED ? BASE32_PATTERN : BASE64URL_PATTERN; - final Matcher m = pattern.matcher(inflated.getName()); - if(m.matches()) { - final String ciphertext = m.group(1); - try { - final String cleartextFilename = fileNameCryptor.decryptFilename( - vaultVersion == VAULT_VERSION_DEPRECATED ? BaseEncoding.base32() : BaseEncoding.base64Url(), - ciphertext, file.getParent().attributes().getDirectoryId().getBytes(StandardCharsets.UTF_8)); - final PathAttributes attributes = new PathAttributes(file.attributes()); - if(this.isDirectory(inflated)) { - if(Permission.EMPTY != attributes.getPermission()) { - final Permission permission = new Permission(attributes.getPermission()); - permission.setUser(permission.getUser().or(Permission.Action.execute)); - permission.setGroup(permission.getGroup().or(Permission.Action.execute)); - permission.setOther(permission.getOther().or(Permission.Action.execute)); - attributes.setPermission(permission); - } - // Reset size for folders - attributes.setSize(-1L); - attributes.setVersionId(null); - attributes.setFileId(null); - } - else { - // Translate file size - attributes.setSize(this.toCleartextSize(0L, file.attributes().getSize())); - } - // Add reference to encrypted file - attributes.setEncrypted(file); - // Add reference for vault - attributes.setVault(home); - final EnumSet type = EnumSet.copyOf(file.getType()); - type.remove(this.isDirectory(inflated) ? Path.Type.file : Path.Type.directory); - type.add(this.isDirectory(inflated) ? Path.Type.directory : Path.Type.file); - type.remove(Path.Type.encrypted); - type.add(Path.Type.decrypted); - final Path decrypted = new Path(file.getParent().attributes().getDecrypted(), cleartextFilename, type, attributes); - if(type.contains(Path.Type.symboliclink)) { - decrypted.setSymlinkTarget(file.getSymlinkTarget()); - } - return decrypted; - } - catch(AuthenticationFailedException e) { - throw new CryptoAuthenticationException( - "Failure to decrypt due to an unauthentic ciphertext", e); - } - } - else { - throw new CryptoFilenameMismatchException( - String.format("Failure to decrypt %s due to missing pattern match for %s", inflated.getName(), pattern)); - } - } - - private boolean isDirectory(final Path p) { - if(vaultVersion == VAULT_VERSION_DEPRECATED) { - return p.getName().startsWith(DIR_PREFIX); - } - return p.isDirectory(); - } - - @Override - public long toCiphertextSize(final long cleartextFileOffset, final long cleartextFileSize) { - if(TransferStatus.UNKNOWN_LENGTH == cleartextFileSize) { - return TransferStatus.UNKNOWN_LENGTH; - } - final int headerSize; - if(0L == cleartextFileOffset) { - headerSize = cryptor.fileHeaderCryptor().headerSize(); - } - else { - headerSize = 0; - } - return headerSize + cryptor.fileContentCryptor().ciphertextSize(cleartextFileSize); - } - - @Override - public long toCleartextSize(final long cleartextFileOffset, final long ciphertextFileSize) throws CryptoInvalidFilesizeException { - if(TransferStatus.UNKNOWN_LENGTH == ciphertextFileSize) { - return TransferStatus.UNKNOWN_LENGTH; - } - final int headerSize; - if(0L == cleartextFileOffset) { - headerSize = cryptor.fileHeaderCryptor().headerSize(); - } - else { - headerSize = 0; - } - try { - return cryptor.fileContentCryptor().cleartextSize(ciphertextFileSize - headerSize); - } - catch(AssertionError e) { - throw new CryptoInvalidFilesizeException(String.format("Encrypted file size must be at least %d bytes", headerSize)); - } - catch(IllegalArgumentException e) { - throw new CryptoInvalidFilesizeException(String.format("Invalid file size. %s", e.getMessage())); - } - } - - private Path inflate(final Session session, final Path file) throws BackgroundException { - final String fileName = file.getName(); - if(filenameProvider.isDeflated(fileName)) { - final String filename = filenameProvider.inflate(session, fileName); - return new Path(file.getParent(), filename, EnumSet.of(Path.Type.file), file.attributes()); - } - return file; - } - public Path getHome() { return home; } + @Override public Path getMasterkey() { return masterkey; } + @Override public Path getConfig() { return config; } + @Override + public int getVersion() { + return vaultVersion; + } + + @Override public FileHeaderCryptor getFileHeaderCryptor() { return cryptor.fileHeaderCryptor(); } + @Override public FileContentCryptor getFileContentCryptor() { return cryptor.fileContentCryptor(); } + @Override public CryptorCache getFileNameCryptor() { return fileNameCryptor; } + @Override public CryptoFilename getFilenameProvider() { return filenameProvider; } + @Override public CryptoDirectory getDirectoryProvider() { return directoryProvider; } + @Override + public Cryptor getCryptor() { + return cryptor; + } + + @Override public int getNonceSize() { return nonceSize; } - public int numberOfChunks(final long cleartextFileSize) { - return (int) (cleartextFileSize / cryptor.fileContentCryptor().cleartextChunkSize() + - ((cleartextFileSize % cryptor.fileContentCryptor().cleartextChunkSize() > 0) ? 1 : 0)); + @Override + public String getRegularFileExtension() { + return REGULAR_FILE_EXTENSION; } @Override - @SuppressWarnings("unchecked") - public T getFeature(final Session session, final Class type, final T delegate) { - if(this.isUnlocked()) { - if(type == ListService.class) { - return (T) new CryptoListService(session, (ListService) delegate, this); - } - if(type == Touch.class) { - // Use default touch feature because touch with remote implementation will not add encrypted file header - return (T) new CryptoTouchFeature(session, new DefaultTouchFeature(session), this); - } - if(type == Directory.class) { - return (T) (vaultVersion == VAULT_VERSION_DEPRECATED ? - new CryptoDirectoryV6Feature(session, (Directory) delegate, this) : - new CryptoDirectoryV7Feature(session, (Directory) delegate, this) - ); - } - if(type == Upload.class) { - return (T) new CryptoUploadFeature(session, (Upload) delegate, this); - } - if(type == Download.class) { - return (T) new CryptoDownloadFeature(session, (Download) delegate, this); - } - if(type == Read.class) { - return (T) new CryptoReadFeature(session, (Read) delegate, this); - } - if(type == Write.class) { - return (T) new CryptoWriteFeature(session, (Write) delegate, this); - } - if(type == MultipartWrite.class) { - return (T) new CryptoMultipartWriteFeature(session, (Write) delegate, this); - } - if(type == Move.class) { - return (T) (vaultVersion == VAULT_VERSION_DEPRECATED ? - new CryptoMoveV6Feature(session, (Move) delegate, this) : - new CryptoMoveV7Feature(session, (Move) delegate, this)); + public String getDirectoryMetadataFilename() { + return DIRECTORY_METADATA_FILENAME; + } - } - if(type == AttributesFinder.class) { - return (T) new CryptoAttributesFeature(session, (AttributesFinder) delegate, this); - } - if(type == Find.class) { - return (T) new CryptoFindFeature(session, (Find) delegate, this); - } - if(type == UrlProvider.class) { - return (T) new CryptoUrlProvider(session, (UrlProvider) delegate, this); - } - if(type == FileIdProvider.class) { - return (T) new CryptoFileIdProvider(session, (FileIdProvider) delegate, this); - } - if(type == VersionIdProvider.class) { - return (T) new CryptoVersionIdProvider(session, (VersionIdProvider) delegate, this); - } - if(type == Delete.class) { - return (T) (vaultVersion == VAULT_VERSION_DEPRECATED ? - new CryptoDeleteV6Feature(session, (Delete) delegate, this) : - new CryptoDeleteV7Feature(session, (Delete) delegate, this)); - } - if(type == Trash.class) { - return (T) (vaultVersion == VAULT_VERSION_DEPRECATED ? - new CryptoDeleteV6Feature(session, (Delete) delegate, this) : - new CryptoDeleteV7Feature(session, (Delete) delegate, this)); - } - if(type == Symlink.class) { - return (T) new CryptoSymlinkFeature(session, (Symlink) delegate, this); - } - if(type == Headers.class) { - return (T) new CryptoHeadersFeature(session, (Headers) delegate, this); - } - if(type == Compress.class) { - return (T) new CryptoCompressFeature(session, (Compress) delegate, this); - } - if(type == Bulk.class) { - return (T) new CryptoBulkFeature(session, (Bulk) delegate, this); - } - if(type == UnixPermission.class) { - return (T) new CryptoUnixPermission(session, (UnixPermission) delegate, this); - } - if(type == AclPermission.class) { - return (T) new CryptoAclPermission(session, (AclPermission) delegate, this); - } - if(type == Copy.class) { - return (T) new CryptoCopyFeature(session, (Copy) delegate, this); - } - if(type == Timestamp.class) { - return (T) new CryptoTimestampFeature(session, (Timestamp) delegate, this); - } - if(type == Encryption.class) { - return (T) new CryptoEncryptionFeature(session, (Encryption) delegate, this); - } - if(type == Lifecycle.class) { - return (T) new CryptoLifecycleFeature(session, (Lifecycle) delegate, this); - } - if(type == Location.class) { - return (T) new CryptoLocationFeature(session, (Location) delegate, this); - } - if(type == Lock.class) { - return (T) new CryptoLockFeature(session, (Lock) delegate, this); - } - if(type == Logging.class) { - return (T) new CryptoLoggingFeature(session, (Logging) delegate, this); - } - if(type == Redundancy.class) { - return (T) new CryptoRedundancyFeature(session, (Redundancy) delegate, this); - } - if(type == Search.class) { - return (T) new CryptoSearchFeature(session, (Search) delegate, this); - } - if(type == TransferAcceleration.class) { - return (T) new CryptoTransferAccelerationFeature<>(session, (TransferAcceleration) delegate, this); - } - if(type == Versioning.class) { - return (T) new CryptoVersioningFeature(session, (Versioning) delegate, this); - } - } - return delegate; + @Override + public String getBackupDirectoryMetadataFilename() { + return BACKUP_DIRECTORY_METADATA_FILENAME; + } + + @Override + public Pattern getBase64URLPattern() { + return BASE64URL_PATTERN; + } + + @Override + public byte[] getRootDirId() { + return CryptoDirectoryV6Provider.ROOT_DIR_ID; } @Override diff --git a/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/CryptorCache.java b/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/CryptorCache.java index f62cf502146..96bc1893bbf 100644 --- a/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/CryptorCache.java +++ b/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/CryptorCache.java @@ -20,6 +20,7 @@ import org.cryptomator.cryptolib.api.AuthenticationFailedException; import org.cryptomator.cryptolib.api.FileNameCryptor; +import java.nio.ByteBuffer; import java.util.Arrays; import java.util.Objects; @@ -29,7 +30,7 @@ public class CryptorCache { public static final BaseEncoding BASE32 = BaseEncoding.base32(); - private final LRUCache directoryIdCache = LRUCache.build(250); + private final LRUCache directoryIdCache = LRUCache.build(250); private final LRUCache decryptCache = LRUCache.build(5000); private final LRUCache encryptCache = LRUCache.build(5000); @@ -39,11 +40,12 @@ public CryptorCache(final FileNameCryptor impl) { this.impl = impl; } - public String hashDirectoryId(final String cleartextDirectoryId) { - if(!directoryIdCache.contains(cleartextDirectoryId)) { - directoryIdCache.put(cleartextDirectoryId, impl.hashDirectoryId(cleartextDirectoryId)); + public String hashDirectoryId(final byte[] cleartextDirectoryId) { + final ByteBuffer wrap = ByteBuffer.wrap(cleartextDirectoryId); + if(!directoryIdCache.contains(wrap)) { + directoryIdCache.put(wrap, impl.hashDirectoryId(cleartextDirectoryId)); } - return directoryIdCache.get(cleartextDirectoryId); + return directoryIdCache.get(wrap); } public String encryptFilename(final BaseEncoding encoding, final String cleartextName, final byte[] associatedData) { diff --git a/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/UVFVault.java b/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/UVFVault.java new file mode 100644 index 00000000000..7d3f6c10894 --- /dev/null +++ b/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/UVFVault.java @@ -0,0 +1,403 @@ +package ch.cyberduck.core.cryptomator; + +/* + * Copyright (c) 2002-2025 iterate GmbH. All rights reserved. + * https://cyberduck.io/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +import ch.cyberduck.core.LocaleFactory; +import ch.cyberduck.core.LoginOptions; +import ch.cyberduck.core.PasswordCallback; +import ch.cyberduck.core.Path; +import ch.cyberduck.core.PathAttributes; +import ch.cyberduck.core.Permission; +import ch.cyberduck.core.Session; +import ch.cyberduck.core.SimplePathPredicate; +import ch.cyberduck.core.cryptomator.features.CryptoDirectoryUVFFeature; +import ch.cyberduck.core.cryptomator.impl.CryptoDirectoryUVFProvider; +import ch.cyberduck.core.cryptomator.impl.CryptoFilenameV7Provider; +import ch.cyberduck.core.cryptomator.random.FastSecureRandomProvider; +import ch.cyberduck.core.exception.BackgroundException; +import ch.cyberduck.core.features.Directory; +import ch.cyberduck.core.vault.VaultCredentials; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.cryptomator.cryptolib.api.AuthenticationFailedException; +import org.cryptomator.cryptolib.api.Cryptor; +import org.cryptomator.cryptolib.api.CryptorProvider; +import org.cryptomator.cryptolib.api.FileContentCryptor; +import org.cryptomator.cryptolib.api.FileHeaderCryptor; +import org.cryptomator.cryptolib.api.UVFMasterkey; + +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.text.MessageFormat; +import java.util.EnumSet; +import java.util.Objects; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import com.google.common.io.BaseEncoding; + +public class UVFVault extends AbstractVault { + + private static final Logger log = LogManager.getLogger(UVFVault.class); + + private static final String REGULAR_FILE_EXTENSION = ".uvf"; + private static final String FILENAME_DIRECTORYID = "dir"; + private static final String DIRECTORY_METADATA_FILENAME = String.format("%s%s", FILENAME_DIRECTORYID, REGULAR_FILE_EXTENSION); + private static final String BACKUP_FILENAME_DIRECTORYID = "dirid"; + private static final String BACKUP_DIRECTORY_METADATA_FILENAME = String.format("%s%s", BACKUP_FILENAME_DIRECTORYID, REGULAR_FILE_EXTENSION); + + private static final Pattern BASE64URL_PATTERN = Pattern.compile("^([A-Za-z0-9_=-]+)" + REGULAR_FILE_EXTENSION); + + // copied from AbstractVault + private static final Pattern BASE32_PATTERN = Pattern.compile("^0?(([A-Z2-7]{8})*[A-Z2-7=]{8})"); + + /** + * Root of vault directory + */ + private final Path home; + + private Cryptor cryptor; + private CryptorCache fileNameCryptor; + private CryptoFilename filenameProvider; + private CryptoDirectory directoryProvider; + + private int nonceSize; + private byte[] rootDirId; + + public UVFVault(final Path home) { + this.home = home; + } + + @Override + public Path create(final Session session, final String region, final VaultCredentials credentials) throws BackgroundException { + throw new UnsupportedOperationException(); + } + + // load -> unlock -> open + @Override + public UVFVault load(final Session session, final PasswordCallback prompt) throws BackgroundException { + final UVFMasterkey masterKey = UVFMasterkey.fromDecryptedPayload(prompt.prompt(session.getHost(), + LocaleFactory.localizedString("Unlock Vault", "Cryptomator"), + MessageFormat.format(LocaleFactory.localizedString("Provide your passphrase to unlock the Cryptomator Vault {0}", "Cryptomator"), home.getName()), + new LoginOptions() + .save(false) + .user(false) + .anonymous(false) + .icon("cryptomator.tiff") + .passwordPlaceholder(LocaleFactory.localizedString("Passphrase", "Cryptomator"))).getPassword()); + final CryptorProvider provider = CryptorProvider.forScheme(CryptorProvider.Scheme.UVF_DRAFT); + log.debug("Initialized crypto provider {}", provider); + this.cryptor = provider.provide(masterKey, FastSecureRandomProvider.get().provide()); + this.fileNameCryptor = new CryptorCache(cryptor.fileNameCryptor(masterKey.firstRevision())); // TODO revision eventually depends on location - safe? + this.filenameProvider = new CryptoFilenameV7Provider(Integer.MAX_VALUE); + this.directoryProvider = new CryptoDirectoryUVFProvider(this, filenameProvider, fileNameCryptor); + this.nonceSize = 12; + this.rootDirId = masterKey.rootDirId(); + return this; + } + + @Override + public Path decrypt(final Session session, final Path file) throws BackgroundException { + if(file.getType().contains(Path.Type.decrypted)) { + log.warn("Skip file {} because it is already marked as an defcrypted path", file); + return file; + } + if(file.getType().contains(Path.Type.vault)) { + log.warn("Skip file {} because it is marked as an internal vault path", file); + return file; + } + final Path inflated = this.inflate(session, file); + final Pattern pattern = this.getVersion() == VAULT_VERSION_DEPRECATED ? BASE32_PATTERN : this.getBase64URLPattern(); + final Matcher m = pattern.matcher(inflated.getName()); + if(m.matches()) { + final String ciphertext = m.group(1); + try { + final CryptorCache effectivefileNameCryptor; + // / diff to AbstractVault.decrypt + //TODO lädt das recovery metadaten file anstatt normales + final int revision = loadRevision(session, file); + effectivefileNameCryptor = new CryptorCache(this.getCryptor().fileNameCryptor(revision)); + // \ + final String cleartextFilename = effectivefileNameCryptor.decryptFilename( + this.getVersion() == VAULT_VERSION_DEPRECATED ? BaseEncoding.base32() : BaseEncoding.base64Url(), + ciphertext, directoryProvider.getOrCreateDirectoryId(session, file.getParent())); + final PathAttributes attributes = new PathAttributes(file.attributes()); + if(this.isDirectory(inflated)) { + if(Permission.EMPTY != attributes.getPermission()) { + final Permission permission = new Permission(attributes.getPermission()); + permission.setUser(permission.getUser().or(Permission.Action.execute)); + permission.setGroup(permission.getGroup().or(Permission.Action.execute)); + permission.setOther(permission.getOther().or(Permission.Action.execute)); + attributes.setPermission(permission); + } + // Reset size for folders + attributes.setSize(-1L); + attributes.setVersionId(null); + attributes.setFileId(null); + } + else { + // Translate file size + attributes.setSize(this.toCleartextSize(0L, file.attributes().getSize())); + } + // Add reference to encrypted file + attributes.setEncrypted(file); + // Add reference for vault + attributes.setVault(this.getHome()); + final EnumSet type = EnumSet.copyOf(file.getType()); + type.remove(this.isDirectory(inflated) ? Path.Type.file : Path.Type.directory); + type.add(this.isDirectory(inflated) ? Path.Type.directory : Path.Type.file); + type.remove(Path.Type.encrypted); + type.add(Path.Type.decrypted); + final Path decrypted = new Path(file.getParent().attributes().getDecrypted(), cleartextFilename, type, attributes); + if(type.contains(Path.Type.symboliclink)) { + decrypted.setSymlinkTarget(file.getSymlinkTarget()); + } + return decrypted; + } + catch(AuthenticationFailedException e) { + throw new CryptoAuthenticationException( + "Failure to decrypt due to an unauthentic ciphertext", e); + } + } + else { + throw new CryptoFilenameMismatchException( + String.format("Failure to decrypt %s due to missing pattern match for %s", inflated.getName(), pattern)); + } + } + + @Override + public Path encrypt(Session session, Path file, boolean metadata) throws BackgroundException { + final Path encrypted; + if(file.isFile() || metadata) { + if(file.getType().contains(Path.Type.vault)) { + log.warn("Skip file {} because it is marked as an internal vault path", file); + return file; + } + if(new SimplePathPredicate(file).test(this.getHome())) { + log.warn("Skip vault home {} because the root has no metadata file", file); + return file; + } + final Path parent; + final String filename; + if(file.getType().contains(Path.Type.encrypted)) { + final Path decrypted = file.attributes().getDecrypted(); + parent = this.getDirectoryProvider().toEncrypted(session, decrypted.getParent()); + filename = this.getDirectoryProvider().toEncrypted(session, decrypted.getParent(), decrypted.getName(), decrypted.getType()); + } + else { + parent = this.getDirectoryProvider().toEncrypted(session, file.getParent()); + // / diff to AbstractVault.encrypt + filename = this.getDirectoryProvider().toEncrypted(session, file.getParent(), file.getName(), file.getType()); + // \ diff to AbstractVault.decrypt + } + final PathAttributes attributes = new PathAttributes(file.attributes()); + if(!file.isFile() && !metadata) { + // The directory is different from the metadata file used to resolve the actual folder + attributes.setVersionId(null); + attributes.setFileId(null); + } + // Translate file size + attributes.setSize(this.toCiphertextSize(0L, file.attributes().getSize())); + final EnumSet type = EnumSet.copyOf(file.getType()); + if(metadata && this.getVersion() == VAULT_VERSION_DEPRECATED) { + type.remove(Path.Type.directory); + type.add(Path.Type.file); + } + type.remove(Path.Type.decrypted); + type.add(Path.Type.encrypted); + encrypted = new Path(parent, filename, type, attributes); + } + else { + if(file.getType().contains(Path.Type.encrypted)) { + log.warn("Skip file {} because it is already marked as an encrypted path", file); + return file; + } + if(file.getType().contains(Path.Type.vault)) { + return this.getDirectoryProvider().toEncrypted(session, this.getHome()); + } + encrypted = this.getDirectoryProvider().toEncrypted(session, file); + } + // Add reference to decrypted file + if(!file.getType().contains(Path.Type.encrypted)) { + encrypted.attributes().setDecrypted(file); + } + // Add reference for vault + file.attributes().setVault(this.getHome()); + encrypted.attributes().setVault(this.getHome()); + return encrypted; + } + + private int loadRevision(final Session session, final Path directory) throws BackgroundException { + // Read directory id from file + log.debug("Read directory ID from {}", directory); + final Path metadataFile = new Path(directory.getParent(), this.getDirectoryMetadataFilename(), EnumSet.of(Path.Type.file, Path.Type.encrypted)); + final byte[] ciphertext = new ContentReader(session).readBytes(metadataFile); + // https://github.com/encryption-alliance/unified-vault-format/blob/develop/file%20name%20encryption/AES-SIV-512-B64URL.md#format-of-diruvf-and-symlinkuvf + // TODO can we not use org.cryptomator.cryptolib.v3.DirectoryContentCryptorImpl.decryptDirectoryMetadata()? DirectoryMetadataImpl is not visible and DirectoryMetadata is empty interface, so we cannot access dirId attribute. + if(ciphertext.length != 128) { + throw new IllegalArgumentException("Invalid dir.uvf length: " + ciphertext.length); + } + int headerSize = this.getCryptor().fileHeaderCryptor().headerSize(); + ByteBuffer buffer = ByteBuffer.wrap(ciphertext); + ByteBuffer headerBuf = buffer.duplicate(); + headerBuf.position(4).limit(headerSize); + return headerBuf.order(ByteOrder.BIG_ENDIAN).getInt(); + } + + + // copied from AbstractVault + private boolean isDirectory(final Path p) { + if(this.getVersion() == VAULT_VERSION_DEPRECATED) { + return p.getName().startsWith(DIR_PREFIX); + } + return p.isDirectory(); + } + + // copied from AbstractVault + private Path inflate(final Session session, final Path file) throws BackgroundException { + final String fileName = file.getName(); + if(this.getFilenameProvider().isDeflated(fileName)) { + final String filename = this.getFilenameProvider().inflate(session, fileName); + return new Path(file.getParent(), filename, EnumSet.of(Path.Type.file), file.attributes()); + } + return file; + } + + @Override + public synchronized void close() { + super.close(); + cryptor.destroy(); + } + + @Override + public Path getMasterkey() { + //TODO: implement + return null; + } + + @Override + public Path getConfig() { + //TODO: implement + return null; + } + + @Override + public Path getHome() { + return home; + } + + @Override + public FileHeaderCryptor getFileHeaderCryptor() { + return cryptor.fileHeaderCryptor(); + } + + @Override + public FileContentCryptor getFileContentCryptor() { + return cryptor.fileContentCryptor(); + } + + @Override + public CryptorCache getFileNameCryptor() { + return fileNameCryptor; + } + + @Override + public CryptoFilename getFilenameProvider() { + return filenameProvider; + } + + @Override + public CryptoDirectory getDirectoryProvider() { + return directoryProvider; + } + + @Override + public Cryptor getCryptor() { + return cryptor; + } + + @Override + public int getNonceSize() { + return nonceSize; + } + + @Override + public int getVersion() { + return VAULT_VERSION; + } + + @Override + public String getRegularFileExtension() { + return REGULAR_FILE_EXTENSION; + } + + @Override + public String getDirectoryMetadataFilename() { + return DIRECTORY_METADATA_FILENAME; + } + + @Override + public String getBackupDirectoryMetadataFilename() { + return BACKUP_DIRECTORY_METADATA_FILENAME; + } + + @Override + public Pattern getBase64URLPattern() { + return BASE64URL_PATTERN; + } + + public byte[] getRootDirId() { + return rootDirId; + } + + @Override + public T getFeature(final Session session, final Class type, final T delegate) { + + if(type == Directory.class) { + return (T) new CryptoDirectoryUVFFeature(session, (Directory) delegate, this + ); + } + + return super.getFeature(session, type, delegate); + } + + @Override + public boolean equals(final Object o) { + if(this == o) { + return true; + } + if(!(o instanceof UVFVault)) { + return false; + } + final UVFVault that = (UVFVault) o; + return new SimplePathPredicate(home).test(that.home); + } + + @Override + public int hashCode() { + return Objects.hash(new SimplePathPredicate(home)); + } + + @Override + public String toString() { + final StringBuilder sb = new StringBuilder("UVFVault{"); + sb.append("home=").append(home); + sb.append(", cryptor=").append(cryptor); + sb.append('}'); + return sb.toString(); + } +} diff --git a/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/features/CryptoBulkFeature.java b/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/features/CryptoBulkFeature.java index 90f7be910c4..4817cf1a8d2 100644 --- a/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/features/CryptoBulkFeature.java +++ b/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/features/CryptoBulkFeature.java @@ -21,7 +21,7 @@ import ch.cyberduck.core.RandomStringService; import ch.cyberduck.core.Session; import ch.cyberduck.core.UUIDRandomStringService; -import ch.cyberduck.core.cryptomator.CryptoVault; +import ch.cyberduck.core.cryptomator.AbstractVault; import ch.cyberduck.core.cryptomator.random.RandomNonceGenerator; import ch.cyberduck.core.cryptomator.random.RotatingNonceGenerator; import ch.cyberduck.core.exception.BackgroundException; @@ -45,9 +45,9 @@ public class CryptoBulkFeature implements Bulk { private final Session session; private final Bulk delegate; - private final CryptoVault cryptomator; + private final AbstractVault cryptomator; - public CryptoBulkFeature(final Session session, final Bulk delegate, final CryptoVault cryptomator) { + public CryptoBulkFeature(final Session session, final Bulk delegate, final AbstractVault cryptomator) { this.session = session; this.delegate = delegate; this.cryptomator = cryptomator; @@ -82,9 +82,7 @@ public int compare(final Map.Entry o1, final Map.E if(!status.isExists()) { switch(type) { case upload: - // Preset directory ID for new folders to avert lookup with not found failure in directory ID provider - final String directoryId = random.random(); - encrypted.put(new TransferItem(cryptomator.encrypt(session, file, directoryId, false), local), status); + encrypted.put(new TransferItem(cryptomator.encrypt(session, file, false), local), status); break; default: encrypted.put(new TransferItem(cryptomator.encrypt(session, file), local), status); diff --git a/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/features/CryptoChecksumCompute.java b/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/features/CryptoChecksumCompute.java index c591b99d69c..41ae969b7fd 100644 --- a/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/features/CryptoChecksumCompute.java +++ b/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/features/CryptoChecksumCompute.java @@ -15,8 +15,8 @@ * GNU General Public License for more details. */ +import ch.cyberduck.core.cryptomator.AbstractVault; import ch.cyberduck.core.cryptomator.CryptoOutputStream; -import ch.cyberduck.core.cryptomator.CryptoVault; import ch.cyberduck.core.cryptomator.random.RandomNonceGenerator; import ch.cyberduck.core.cryptomator.random.RotatingNonceGenerator; import ch.cyberduck.core.exception.BackgroundException; @@ -55,11 +55,11 @@ public class CryptoChecksumCompute extends AbstractChecksumCompute { private static final Logger log = LogManager.getLogger(CryptoChecksumCompute.class); - private final CryptoVault cryptomator; + private final AbstractVault cryptomator; private final ChecksumCompute delegate; - public CryptoChecksumCompute(final ChecksumCompute delegate, final CryptoVault vault) { - this.cryptomator = vault; + public CryptoChecksumCompute(final ChecksumCompute delegate, final AbstractVault CryptoVaultInterface) { + this.cryptomator = CryptoVaultInterface; this.delegate = delegate; } diff --git a/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/features/CryptoCopyFeature.java b/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/features/CryptoCopyFeature.java index 83d536d17b2..cc172478978 100644 --- a/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/features/CryptoCopyFeature.java +++ b/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/features/CryptoCopyFeature.java @@ -19,7 +19,7 @@ import ch.cyberduck.core.Path; import ch.cyberduck.core.PathAttributes; import ch.cyberduck.core.Session; -import ch.cyberduck.core.cryptomator.CryptoVault; +import ch.cyberduck.core.cryptomator.AbstractVault; import ch.cyberduck.core.cryptomator.random.RandomNonceGenerator; import ch.cyberduck.core.cryptomator.random.RotatingNonceGenerator; import ch.cyberduck.core.exception.BackgroundException; @@ -37,11 +37,11 @@ public class CryptoCopyFeature implements Copy { private final Session session; private final Copy proxy; - private final CryptoVault vault; + private final AbstractVault vault; private Session target; - public CryptoCopyFeature(final Session session, final Copy proxy, final CryptoVault vault) { + public CryptoCopyFeature(final Session session, final Copy proxy, final AbstractVault vault) { this.session = session; this.target = session; this.proxy = proxy; diff --git a/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/features/CryptoDeleteV6Feature.java b/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/features/CryptoDeleteV6Feature.java index cbdda42cf13..5fcb7b07a5d 100644 --- a/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/features/CryptoDeleteV6Feature.java +++ b/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/features/CryptoDeleteV6Feature.java @@ -20,8 +20,8 @@ import ch.cyberduck.core.PasswordCallback; import ch.cyberduck.core.Path; import ch.cyberduck.core.Session; +import ch.cyberduck.core.cryptomator.AbstractVault; import ch.cyberduck.core.cryptomator.CryptoFilename; -import ch.cyberduck.core.cryptomator.CryptoVault; import ch.cyberduck.core.exception.AccessDeniedException; import ch.cyberduck.core.exception.BackgroundException; import ch.cyberduck.core.exception.NotfoundException; @@ -44,10 +44,10 @@ public class CryptoDeleteV6Feature implements Delete, Trash { private final Session session; private final Delete proxy; - private final CryptoVault vault; + private final AbstractVault vault; private final CryptoFilename filenameProvider; - public CryptoDeleteV6Feature(final Session session, final Delete proxy, final CryptoVault vault) { + public CryptoDeleteV6Feature(final Session session, final Delete proxy, final AbstractVault vault) { this.session = session; this.proxy = proxy; this.vault = vault; diff --git a/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/features/CryptoDeleteV7Feature.java b/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/features/CryptoDeleteV7Feature.java index ab1d6b34b73..310466c6696 100644 --- a/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/features/CryptoDeleteV7Feature.java +++ b/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/features/CryptoDeleteV7Feature.java @@ -15,14 +15,14 @@ * GNU General Public License for more details. */ +import ch.cyberduck.core.AbstractPath; import ch.cyberduck.core.DisabledListProgressListener; import ch.cyberduck.core.ListService; import ch.cyberduck.core.PasswordCallback; import ch.cyberduck.core.Path; import ch.cyberduck.core.Session; +import ch.cyberduck.core.cryptomator.AbstractVault; import ch.cyberduck.core.cryptomator.CryptoFilename; -import ch.cyberduck.core.cryptomator.CryptoVault; -import ch.cyberduck.core.cryptomator.impl.CryptoDirectoryV7Provider; import ch.cyberduck.core.exception.AccessDeniedException; import ch.cyberduck.core.exception.BackgroundException; import ch.cyberduck.core.exception.NotfoundException; @@ -45,10 +45,10 @@ public class CryptoDeleteV7Feature implements Delete, Trash { private final Session session; private final Delete proxy; - private final CryptoVault vault; + private final AbstractVault vault; private final CryptoFilename filenameProvider; - public CryptoDeleteV7Feature(final Session session, final Delete proxy, final CryptoVault vault) { + public CryptoDeleteV7Feature(final Session session, final Delete proxy, final AbstractVault vault) { this.session = session; this.proxy = proxy; this.vault = vault; @@ -62,8 +62,8 @@ public void delete(final Map files, final PasswordCallback if(!f.equals(vault.getHome())) { final Path encrypt = vault.encrypt(session, f); if(f.isDirectory()) { - final Path backup = new Path(encrypt, CryptoDirectoryV7Provider.BACKUP_DIRECTORY_METADATAFILE, - EnumSet.of(Path.Type.file)); + final Path backup = new Path(encrypt, vault.getBackupDirectoryMetadataFilename(), + EnumSet.of(AbstractPath.Type.file)); try { log.debug("Deleting directory id backup file {}", backup); proxy.delete(Collections.singletonList(backup), prompt, callback); @@ -87,7 +87,7 @@ public void delete(final Map files, final PasswordCallback } final Path metadata = vault.encrypt(session, f, true); if(f.isDirectory()) { - final Path metadataFile = new Path(metadata, CryptoDirectoryV7Provider.DIRECTORY_METADATAFILE, EnumSet.of(Path.Type.file)); + final Path metadataFile = new Path(metadata, vault.getDirectoryMetadataFilename(), EnumSet.of(Path.Type.file)); log.debug("Add metadata file {}", metadataFile); metadataFiles.add(metadataFile); metadataFiles.add(metadata); diff --git a/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/features/CryptoDirectoryUVFFeature.java b/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/features/CryptoDirectoryUVFFeature.java new file mode 100644 index 00000000000..35ecba509d0 --- /dev/null +++ b/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/features/CryptoDirectoryUVFFeature.java @@ -0,0 +1,107 @@ +package ch.cyberduck.core.cryptomator.features; + +/* + * Copyright (c) 2002-2025 iterate GmbH. All rights reserved. + * https://cyberduck.io/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +import ch.cyberduck.core.Path; +import ch.cyberduck.core.Session; +import ch.cyberduck.core.cryptomator.AbstractVault; +import ch.cyberduck.core.cryptomator.ContentWriter; +import ch.cyberduck.core.cryptomator.random.RandomNonceGenerator; +import ch.cyberduck.core.exception.BackgroundException; +import ch.cyberduck.core.features.Directory; +import ch.cyberduck.core.features.Find; +import ch.cyberduck.core.features.Write; +import ch.cyberduck.core.transfer.TransferStatus; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.cryptomator.cryptolib.api.FileHeader; + +import java.nio.ByteBuffer; +import java.util.EnumSet; + +public class CryptoDirectoryUVFFeature extends CryptoDirectoryV7Feature { + private static final Logger log = LogManager.getLogger(CryptoDirectoryUVFFeature.class); + + private final Session session; + private final Directory delegate; + private final AbstractVault vault; + + public CryptoDirectoryUVFFeature(final Session session, final Directory delegate, final AbstractVault vault) { + super(session, delegate, vault); + this.session = session; + this.delegate = delegate; + this.vault = vault; + } + + @Override + public Path mkdir(final Write writer, final Path folder, final TransferStatus status) throws BackgroundException { + final byte[] directoryId = vault.getDirectoryProvider().createDirectoryId(folder); + // Create metadata file for directory + final Path directoryMetadataFolder = session._getFeature(Directory.class).mkdir( + session._getFeature(Write.class), vault.encrypt(session, folder, true), new TransferStatus().setRegion(status.getRegion())); + final Path directoryMetadataFile = new Path(directoryMetadataFolder, + vault.getDirectoryMetadataFilename(), + EnumSet.of(Path.Type.file)); + log.debug("Write metadata {} for folder {}", directoryMetadataFile, folder); + new ContentWriter(session).write(directoryMetadataFile, this.encryptDirectoryMetadataWithCurrentRevision(directoryId)); + final Path encrypt = vault.encrypt(session, folder, false); + final Path intermediate = encrypt.getParent(); + if(!session._getFeature(Find.class).find(intermediate)) { + session._getFeature(Directory.class).mkdir( + session._getFeature(Write.class), intermediate, new TransferStatus().setRegion(status.getRegion())); + } + // Write metadata + final FileHeader header = vault.getFileHeaderCryptor().create(); + status.setHeader(vault.getFileHeaderCryptor().encryptHeader(header)); + status.setNonces(new RandomNonceGenerator(vault.getNonceSize())); + final Path target = delegate.mkdir(writer, encrypt, status); + final Path recoveryDirectoryMetadataFile = new Path(target, + vault.getDirectoryMetadataFilename(), + EnumSet.of(Path.Type.file)); + log.debug("Write recovery metadata {} for folder {}", recoveryDirectoryMetadataFile, folder); + new ContentWriter(session).write(recoveryDirectoryMetadataFile, this.encryptDirectoryMetadataWithCurrentRevision(directoryId)); + // Implementation may return new copy of attributes without encryption attributes + + target.attributes().setDirectoryId(directoryId); + target.attributes().setDecrypted(folder); + // Make reference of encrypted path in attributes of decrypted file point to metadata file + final Path decrypt = vault.decrypt(session, vault.encrypt(session, target, true)); + decrypt.attributes().setFileId(directoryMetadataFolder.attributes().getFileId()); + decrypt.attributes().setVersionId(directoryMetadataFolder.attributes().getVersionId()); + return decrypt; + } + + // TODO replace with DirectoryContentCryptor#encryptDirectoryMetadata once we have access to dirId + private byte[] encryptDirectoryMetadataWithCurrentRevision(final byte[] dirId) { + final ByteBuffer cleartextBuf = ByteBuffer.wrap(dirId); + final FileHeader header = vault.getCryptor().fileHeaderCryptor().create(); + final ByteBuffer headerBuf = vault.getCryptor().fileHeaderCryptor().encryptHeader(header); + final ByteBuffer contentBuf = vault.getCryptor().fileContentCryptor().encryptChunk(cleartextBuf, 0, header); + final byte[] result = new byte[headerBuf.remaining() + contentBuf.remaining()]; + headerBuf.get(result, 0, headerBuf.remaining()); + contentBuf.get(result, headerBuf.limit(), contentBuf.remaining()); + return result; + } + + @Override + public String toString() { + final StringBuilder sb = new StringBuilder("CryptoDirectoryUVFFeature{"); + sb.append("vault=").append(vault); + sb.append('}'); + return sb.toString(); + } +} diff --git a/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/features/CryptoDirectoryV6Feature.java b/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/features/CryptoDirectoryV6Feature.java index 1f92916e928..4a5520e6669 100644 --- a/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/features/CryptoDirectoryV6Feature.java +++ b/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/features/CryptoDirectoryV6Feature.java @@ -19,8 +19,8 @@ import ch.cyberduck.core.RandomStringService; import ch.cyberduck.core.Session; import ch.cyberduck.core.UUIDRandomStringService; +import ch.cyberduck.core.cryptomator.AbstractVault; import ch.cyberduck.core.cryptomator.ContentWriter; -import ch.cyberduck.core.cryptomator.CryptoVault; import ch.cyberduck.core.cryptomator.random.RandomNonceGenerator; import ch.cyberduck.core.exception.BackgroundException; import ch.cyberduck.core.features.Directory; @@ -32,17 +32,15 @@ import org.apache.logging.log4j.Logger; import org.cryptomator.cryptolib.api.FileHeader; -import java.nio.charset.StandardCharsets; - public class CryptoDirectoryV6Feature implements Directory { private static final Logger log = LogManager.getLogger(CryptoDirectoryV6Feature.class); private final Session session; private final Directory delegate; - private final CryptoVault vault; + private final AbstractVault vault; private final RandomStringService random = new UUIDRandomStringService(); - public CryptoDirectoryV6Feature(final Session session, final Directory delegate, final CryptoVault cryptomator) { + public CryptoDirectoryV6Feature(final Session session, final Directory delegate, final AbstractVault cryptomator) { this.session = session; this.delegate = delegate; this.vault = cryptomator; @@ -50,12 +48,12 @@ public CryptoDirectoryV6Feature(final Session session, final Directory @Override public Path mkdir(final Write writer, final Path folder, final TransferStatus status) throws BackgroundException { - final Path encrypt = vault.encrypt(session, folder, random.random(), false); - final String directoryId = encrypt.attributes().getDirectoryId(); + final byte[] directoryId = vault.getDirectoryProvider().createDirectoryId(folder); + final Path encrypt = vault.encrypt(session, folder, false); // Create metadata file for directory final Path directoryMetadataFile = vault.encrypt(session, folder, true); log.debug("Write metadata {} for folder {}", directoryMetadataFile, folder); - new ContentWriter(session).write(directoryMetadataFile, directoryId.getBytes(StandardCharsets.UTF_8)); + new ContentWriter(session).write(directoryMetadataFile, directoryId); final Path intermediate = encrypt.getParent(); if(!session._getFeature(Find.class).find(intermediate)) { session._getFeature(Directory.class).mkdir(session._getFeature(Write.class), intermediate, new TransferStatus().setRegion(status.getRegion())); @@ -87,7 +85,7 @@ public void preflight(final Path workdir, final String filename) throws Backgrou @Override public String toString() { - final StringBuilder sb = new StringBuilder("CryptoDirectoryFeature{"); + final StringBuilder sb = new StringBuilder("CryptoDirectoryV6Feature{"); sb.append("proxy=").append(delegate); sb.append('}'); return sb.toString(); diff --git a/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/features/CryptoDirectoryV7Feature.java b/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/features/CryptoDirectoryV7Feature.java index b32f8eb7733..a887acae6ea 100644 --- a/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/features/CryptoDirectoryV7Feature.java +++ b/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/features/CryptoDirectoryV7Feature.java @@ -16,12 +16,9 @@ */ import ch.cyberduck.core.Path; -import ch.cyberduck.core.RandomStringService; import ch.cyberduck.core.Session; -import ch.cyberduck.core.UUIDRandomStringService; +import ch.cyberduck.core.cryptomator.AbstractVault; import ch.cyberduck.core.cryptomator.ContentWriter; -import ch.cyberduck.core.cryptomator.CryptoVault; -import ch.cyberduck.core.cryptomator.impl.CryptoDirectoryV7Provider; import ch.cyberduck.core.cryptomator.random.RandomNonceGenerator; import ch.cyberduck.core.exception.BackgroundException; import ch.cyberduck.core.features.Directory; @@ -33,7 +30,6 @@ import org.apache.logging.log4j.Logger; import org.cryptomator.cryptolib.api.FileHeader; -import java.nio.charset.StandardCharsets; import java.util.EnumSet; public class CryptoDirectoryV7Feature implements Directory { @@ -41,28 +37,27 @@ public class CryptoDirectoryV7Feature implements Directory { private final Session session; private final Directory delegate; - private final CryptoVault vault; - private final RandomStringService random = new UUIDRandomStringService(); + private final AbstractVault vault; - public CryptoDirectoryV7Feature(final Session session, final Directory delegate, final CryptoVault cryptomator) { + public CryptoDirectoryV7Feature(final Session session, final Directory delegate, final AbstractVault vault) { this.session = session; this.delegate = delegate; - this.vault = cryptomator; + this.vault = vault; } @Override public Path mkdir(final Write writer, final Path folder, final TransferStatus status) throws BackgroundException { - final Path encrypt = vault.encrypt(session, folder, random.random(), false); - final String directoryId = encrypt.attributes().getDirectoryId(); + final byte[] directoryId = vault.getDirectoryProvider().createDirectoryId(folder); // Create metadata file for directory final Path directoryMetadataFolder = session._getFeature(Directory.class).mkdir( session._getFeature(Write.class), vault.encrypt(session, folder, true), new TransferStatus().setRegion(status.getRegion())); final Path directoryMetadataFile = new Path(directoryMetadataFolder, - CryptoDirectoryV7Provider.DIRECTORY_METADATAFILE, + vault.getDirectoryMetadataFilename(), EnumSet.of(Path.Type.file)); log.debug("Write metadata {} for folder {}", directoryMetadataFile, folder); - new ContentWriter(session).write(directoryMetadataFile, directoryId.getBytes(StandardCharsets.UTF_8)); + new ContentWriter(session).write(directoryMetadataFile, directoryId); + final Path encrypt = vault.encrypt(session, folder, false); final Path intermediate = encrypt.getParent(); if(!session._getFeature(Find.class).find(intermediate)) { session._getFeature(Directory.class).mkdir(session._getFeature(Write.class), intermediate, new TransferStatus().setRegion(status.getRegion())); @@ -94,7 +89,7 @@ public void preflight(final Path workdir, final String filename) throws Backgrou @Override public String toString() { - final StringBuilder sb = new StringBuilder("CryptoDirectoryFeature{"); + final StringBuilder sb = new StringBuilder("CryptoDirectoryV7Feature{"); sb.append("proxy=").append(delegate); sb.append('}'); return sb.toString(); diff --git a/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/features/CryptoDownloadFeature.java b/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/features/CryptoDownloadFeature.java index e3dceec4da6..ea0ab365a68 100644 --- a/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/features/CryptoDownloadFeature.java +++ b/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/features/CryptoDownloadFeature.java @@ -19,12 +19,11 @@ import ch.cyberduck.core.Local; import ch.cyberduck.core.Path; import ch.cyberduck.core.Session; -import ch.cyberduck.core.cryptomator.CryptoVault; +import ch.cyberduck.core.cryptomator.AbstractVault; import ch.cyberduck.core.exception.BackgroundException; import ch.cyberduck.core.exception.NotfoundException; import ch.cyberduck.core.features.Download; import ch.cyberduck.core.features.Read; -import ch.cyberduck.core.features.Vault; import ch.cyberduck.core.io.BandwidthThrottle; import ch.cyberduck.core.io.StreamListener; import ch.cyberduck.core.transfer.TransferStatus; @@ -33,9 +32,9 @@ public class CryptoDownloadFeature implements Download { private final Session session; private final Download proxy; - private final Vault vault; + private final AbstractVault vault; - public CryptoDownloadFeature(final Session session, final Download proxy, final CryptoVault vault) { + public CryptoDownloadFeature(final Session session, final Download proxy, final AbstractVault vault) { this.session = session; this.proxy = proxy; this.vault = vault; diff --git a/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/features/CryptoEncryptionFeature.java b/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/features/CryptoEncryptionFeature.java index 9f30a97b1be..6dc07f6edf2 100644 --- a/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/features/CryptoEncryptionFeature.java +++ b/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/features/CryptoEncryptionFeature.java @@ -18,7 +18,6 @@ import ch.cyberduck.core.LoginCallback; import ch.cyberduck.core.Path; import ch.cyberduck.core.Session; -import ch.cyberduck.core.cryptomator.CryptoVault; import ch.cyberduck.core.exception.BackgroundException; import ch.cyberduck.core.features.Encryption; import ch.cyberduck.core.features.Vault; @@ -31,7 +30,7 @@ public class CryptoEncryptionFeature implements Encryption { private final Encryption delegate; private final Vault vault; - public CryptoEncryptionFeature(final Session session, final Encryption delegate, final CryptoVault vault) { + public CryptoEncryptionFeature(final Session session, final Encryption delegate, final Vault vault) { this.session = session; this.delegate = delegate; this.vault = vault; diff --git a/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/features/CryptoMoveV6Feature.java b/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/features/CryptoMoveV6Feature.java index e43afc0965d..e6d80abba7c 100644 --- a/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/features/CryptoMoveV6Feature.java +++ b/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/features/CryptoMoveV6Feature.java @@ -19,7 +19,7 @@ import ch.cyberduck.core.LocaleFactory; import ch.cyberduck.core.Path; import ch.cyberduck.core.Session; -import ch.cyberduck.core.cryptomator.CryptoVault; +import ch.cyberduck.core.cryptomator.AbstractVault; import ch.cyberduck.core.exception.BackgroundException; import ch.cyberduck.core.exception.InvalidFilenameException; import ch.cyberduck.core.features.Delete; @@ -34,9 +34,9 @@ public class CryptoMoveV6Feature implements Move { private final Session session; private final Move proxy; - private final CryptoVault vault; + private final AbstractVault vault; - public CryptoMoveV6Feature(final Session session, final Move delegate, final CryptoVault cryptomator) { + public CryptoMoveV6Feature(final Session session, final Move delegate, final AbstractVault cryptomator) { this.session = session; this.proxy = delegate; this.vault = cryptomator; diff --git a/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/features/CryptoMoveV7Feature.java b/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/features/CryptoMoveV7Feature.java index a0bd1c8eb7f..ea1c2fd5659 100644 --- a/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/features/CryptoMoveV7Feature.java +++ b/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/features/CryptoMoveV7Feature.java @@ -19,8 +19,7 @@ import ch.cyberduck.core.LocaleFactory; import ch.cyberduck.core.Path; import ch.cyberduck.core.Session; -import ch.cyberduck.core.cryptomator.CryptoVault; -import ch.cyberduck.core.cryptomator.impl.CryptoDirectoryV7Provider; +import ch.cyberduck.core.cryptomator.AbstractVault; import ch.cyberduck.core.exception.BackgroundException; import ch.cyberduck.core.exception.InvalidFilenameException; import ch.cyberduck.core.features.Delete; @@ -35,12 +34,12 @@ public class CryptoMoveV7Feature implements Move { private final Session session; private final Move proxy; - private final CryptoVault vault; + private final AbstractVault vault; - public CryptoMoveV7Feature(final Session session, final Move delegate, final CryptoVault cryptomator) { + public CryptoMoveV7Feature(final Session session, final Move delegate, final AbstractVault vault) { this.session = session; this.proxy = delegate; - this.vault = cryptomator; + this.vault = vault; } @Override @@ -51,8 +50,8 @@ public Path move(final Path file, final Path renamed, final TransferStatus statu final Path target = proxy.move(sourceEncrypted, targetEncrypted, status, callback, connectionCallback); if(file.isDirectory()) { if(!proxy.isRecursive(file, renamed)) { - proxy.move(new Path(sourceEncrypted, CryptoDirectoryV7Provider.DIRECTORY_METADATAFILE, EnumSet.of(Path.Type.file)), - new Path(targetEncrypted, CryptoDirectoryV7Provider.DIRECTORY_METADATAFILE, EnumSet.of(Path.Type.file)), + proxy.move(new Path(sourceEncrypted, vault.getDirectoryMetadataFilename(), EnumSet.of(Path.Type.file)), + new Path(targetEncrypted, vault.getBackupDirectoryMetadataFilename(), EnumSet.of(Path.Type.file)), new TransferStatus(status), callback, connectionCallback); } vault.getDirectoryProvider().delete(file); diff --git a/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/features/CryptoMultipartWriteFeature.java b/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/features/CryptoMultipartWriteFeature.java index 4943f838a28..f5d6de84717 100644 --- a/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/features/CryptoMultipartWriteFeature.java +++ b/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/features/CryptoMultipartWriteFeature.java @@ -16,18 +16,18 @@ */ import ch.cyberduck.core.Session; -import ch.cyberduck.core.cryptomator.CryptoVault; +import ch.cyberduck.core.cryptomator.AbstractVault; import ch.cyberduck.core.features.AttributesFinder; import ch.cyberduck.core.features.Find; import ch.cyberduck.core.features.MultipartWrite; import ch.cyberduck.core.features.Write; public class CryptoMultipartWriteFeature extends CryptoWriteFeature implements MultipartWrite { - public CryptoMultipartWriteFeature(final Session session, final Write delegate, final CryptoVault vault) { + public CryptoMultipartWriteFeature(final Session session, final Write delegate, final AbstractVault vault) { super(session, delegate, vault); } - public CryptoMultipartWriteFeature(final Session session, final Write delegate, final Find finder, final AttributesFinder attributes, final CryptoVault vault) { + public CryptoMultipartWriteFeature(final Session session, final Write delegate, final Find finder, final AttributesFinder attributes, final AbstractVault vault) { super(session, delegate, vault); } } diff --git a/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/features/CryptoReadFeature.java b/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/features/CryptoReadFeature.java index ec8286a4624..45e499a7ed2 100644 --- a/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/features/CryptoReadFeature.java +++ b/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/features/CryptoReadFeature.java @@ -19,8 +19,8 @@ import ch.cyberduck.core.DefaultIOExceptionMappingService; import ch.cyberduck.core.Path; import ch.cyberduck.core.Session; +import ch.cyberduck.core.cryptomator.AbstractVault; import ch.cyberduck.core.cryptomator.CryptoInputStream; -import ch.cyberduck.core.cryptomator.CryptoVault; import ch.cyberduck.core.exception.BackgroundException; import ch.cyberduck.core.features.Read; import ch.cyberduck.core.transfer.TransferStatus; @@ -36,9 +36,9 @@ public class CryptoReadFeature implements Read { private final Session session; private final Read proxy; - private final CryptoVault vault; + private final AbstractVault vault; - public CryptoReadFeature(final Session session, final Read proxy, final CryptoVault vault) { + public CryptoReadFeature(final Session session, final Read proxy, final AbstractVault vault) { this.session = session; this.proxy = proxy; this.vault = vault; diff --git a/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/features/CryptoTimestampFeature.java b/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/features/CryptoTimestampFeature.java index 9db63f0ae3d..437a3c0697e 100644 --- a/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/features/CryptoTimestampFeature.java +++ b/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/features/CryptoTimestampFeature.java @@ -17,8 +17,8 @@ import ch.cyberduck.core.Path; import ch.cyberduck.core.Session; +import ch.cyberduck.core.cryptomator.AbstractVault; import ch.cyberduck.core.cryptomator.CryptoTransferStatus; -import ch.cyberduck.core.cryptomator.CryptoVault; import ch.cyberduck.core.exception.BackgroundException; import ch.cyberduck.core.features.Timestamp; import ch.cyberduck.core.transfer.TransferStatus; @@ -27,9 +27,9 @@ public class CryptoTimestampFeature implements Timestamp { private final Session session; private final Timestamp proxy; - private final CryptoVault vault; + private final AbstractVault vault; - public CryptoTimestampFeature(final Session session, final Timestamp proxy, final CryptoVault vault) { + public CryptoTimestampFeature(final Session session, final Timestamp proxy, final AbstractVault vault) { this.session = session; this.proxy = proxy; this.vault = vault; diff --git a/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/features/CryptoTouchFeature.java b/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/features/CryptoTouchFeature.java index e8864566a94..7a0493e49d3 100644 --- a/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/features/CryptoTouchFeature.java +++ b/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/features/CryptoTouchFeature.java @@ -19,7 +19,7 @@ import ch.cyberduck.core.Path; import ch.cyberduck.core.PathAttributes; import ch.cyberduck.core.Session; -import ch.cyberduck.core.cryptomator.CryptoVault; +import ch.cyberduck.core.cryptomator.AbstractVault; import ch.cyberduck.core.cryptomator.random.RandomNonceGenerator; import ch.cyberduck.core.exception.BackgroundException; import ch.cyberduck.core.exception.InvalidFilenameException; @@ -35,9 +35,9 @@ public class CryptoTouchFeature implements Touch { private final Session session; private final Touch proxy; - private final CryptoVault vault; + private final AbstractVault vault; - public CryptoTouchFeature(final Session session, final Touch proxy, final CryptoVault cryptomator) { + public CryptoTouchFeature(final Session session, final Touch proxy, final AbstractVault cryptomator) { this.session = session; this.proxy = proxy; this.vault = cryptomator; diff --git a/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/features/CryptoUploadFeature.java b/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/features/CryptoUploadFeature.java index 2f2c1317338..4d65ed8745d 100644 --- a/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/features/CryptoUploadFeature.java +++ b/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/features/CryptoUploadFeature.java @@ -20,8 +20,8 @@ import ch.cyberduck.core.Path; import ch.cyberduck.core.ProgressListener; import ch.cyberduck.core.Session; +import ch.cyberduck.core.cryptomator.AbstractVault; import ch.cyberduck.core.cryptomator.CryptoTransferStatus; -import ch.cyberduck.core.cryptomator.CryptoVault; import ch.cyberduck.core.exception.BackgroundException; import ch.cyberduck.core.features.Upload; import ch.cyberduck.core.features.Write; @@ -33,9 +33,9 @@ public class CryptoUploadFeature implements Upload { private final Session session; private final Upload proxy; - private final CryptoVault vault; + private final AbstractVault vault; - public CryptoUploadFeature(final Session session, final Upload delegate, final CryptoVault vault) { + public CryptoUploadFeature(final Session session, final Upload delegate, final AbstractVault vault) { this.session = session; this.proxy = delegate; this.vault = vault; diff --git a/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/features/CryptoWriteFeature.java b/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/features/CryptoWriteFeature.java index 7a8ea6f211b..7142146e0e1 100644 --- a/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/features/CryptoWriteFeature.java +++ b/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/features/CryptoWriteFeature.java @@ -19,9 +19,9 @@ import ch.cyberduck.core.DefaultIOExceptionMappingService; import ch.cyberduck.core.Path; import ch.cyberduck.core.Session; +import ch.cyberduck.core.cryptomator.AbstractVault; import ch.cyberduck.core.cryptomator.CryptoOutputStream; import ch.cyberduck.core.cryptomator.CryptoTransferStatus; -import ch.cyberduck.core.cryptomator.CryptoVault; import ch.cyberduck.core.cryptomator.random.RandomNonceGenerator; import ch.cyberduck.core.cryptomator.random.RotatingNonceGenerator; import ch.cyberduck.core.exception.BackgroundException; @@ -42,9 +42,9 @@ public class CryptoWriteFeature implements Write { private final Session session; private final Write proxy; - private final CryptoVault vault; + private final AbstractVault vault; - public CryptoWriteFeature(final Session session, final Write proxy, final CryptoVault vault) { + public CryptoWriteFeature(final Session session, final Write proxy, final AbstractVault vault) { this.session = session; this.proxy = proxy; this.vault = vault; diff --git a/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/impl/CryptoDirectoryUVFProvider.java b/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/impl/CryptoDirectoryUVFProvider.java new file mode 100644 index 00000000000..60a1e6297f7 --- /dev/null +++ b/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/impl/CryptoDirectoryUVFProvider.java @@ -0,0 +1,190 @@ +package ch.cyberduck.core.cryptomator.impl; + +/* + * Copyright (c) 2002-2025 iterate GmbH. All rights reserved. + * https://cyberduck.io/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +import ch.cyberduck.core.Path; +import ch.cyberduck.core.PathAttributes; +import ch.cyberduck.core.Session; +import ch.cyberduck.core.SimplePathPredicate; +import ch.cyberduck.core.cryptomator.AbstractVault; +import ch.cyberduck.core.cryptomator.ContentReader; +import ch.cyberduck.core.cryptomator.CryptoFilename; +import ch.cyberduck.core.cryptomator.CryptorCache; +import ch.cyberduck.core.cryptomator.random.FastSecureRandomProvider; +import ch.cyberduck.core.exception.BackgroundException; +import ch.cyberduck.core.exception.NotfoundException; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.cryptomator.cryptolib.api.FileHeader; + +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.security.SecureRandom; +import java.util.EnumSet; + +import com.google.common.io.BaseEncoding; + +public class CryptoDirectoryUVFProvider extends CryptoDirectoryV7Provider { + private static final Logger log = LogManager.getLogger(CryptoDirectoryUVFProvider.class); + + private final Path home; + private final AbstractVault vault; + + private final SecureRandom random + = FastSecureRandomProvider.get().provide(); + private final Path dataRoot; + private final CryptorCache filenameCryptor; + private final CryptoFilename filenameProvider; + + public CryptoDirectoryUVFProvider(final AbstractVault vault, final CryptoFilename filenameProvider, final CryptorCache filenameCryptor) { + super(vault, filenameProvider, filenameCryptor); + this.filenameCryptor = filenameCryptor; + this.filenameProvider = filenameProvider; + this.home = vault.getHome(); + this.vault = vault; + this.dataRoot = new Path(home, "d", home.getType()); + } + + @Override + protected byte[] toDirectoryId(final Session session, final Path directory) throws BackgroundException { + if(new SimplePathPredicate(home).test(directory)) { + return vault.getRootDirId(); + } + return super.toDirectoryId(session, directory); + } + + @Override + public String toEncrypted(final Session session, final Path parent, final String filename, final EnumSet type) throws BackgroundException { + if(new SimplePathPredicate(home).test(parent)) { + final String ciphertextName = filenameCryptor.encryptFilename(BaseEncoding.base64Url(), filename, vault.getRootDirId()) + vault.getRegularFileExtension(); + log.debug("Encrypted filename {} to {}", filename, ciphertextName); + return filenameProvider.deflate(session, ciphertextName); + + } + final byte[] directoryId = load(session, parent); + final String ciphertextName = vault.getCryptor().fileNameCryptor(loadRevision(session, parent)).encryptFilename(BaseEncoding.base64Url(), filename, directoryId) + vault.getRegularFileExtension(); + log.debug("Encrypted filename {} to {}", filename, ciphertextName); + return filenameProvider.deflate(session, ciphertextName); + } + + @Override + public Path toEncrypted(final Session session, final Path directory) throws BackgroundException { + if(!directory.isDirectory()) { + throw new NotfoundException(directory.getAbsolute()); + } + if(new SimplePathPredicate(directory).test(home) || directory.isChild(home)) { + final PathAttributes attributes = new PathAttributes(directory.attributes()); + // The root of the vault is a different target directory and file ids always correspond to the metadata file + attributes.setVersionId(null); + attributes.setFileId(null); + // Remember random directory id for use in vault + final byte[] id = this.getOrCreateDirectoryId(session, directory); + log.debug("Use directory ID '{}' for folder {}", id, directory); + attributes.setDirectoryId(id); + attributes.setDecrypted(directory); + final String directoryIdHash; + if(new SimplePathPredicate(home).test(directory)) { + // TODO hard-coded to initial seed in UVFVault + directoryIdHash = filenameCryptor.hashDirectoryId(id); + } + else { + directoryIdHash = vault.getCryptor().fileNameCryptor(loadRevision(session, directory)).hashDirectoryId(id); + } + // Intermediate directory + final Path intermediate = new Path(dataRoot, directoryIdHash.substring(0, 2), dataRoot.getType()); + // Add encrypted type + final EnumSet type = EnumSet.copyOf(directory.getType()); + type.add(Path.Type.encrypted); + type.remove(Path.Type.decrypted); + return new Path(intermediate, directoryIdHash.substring(2), type, attributes); + } + throw new NotfoundException(directory.getAbsolute()); + } + + protected byte[] load(final Session session, final Path directory) throws BackgroundException { + if(new SimplePathPredicate(home).test(directory)) { + return vault.getRootDirId(); + } + final Path parent = this.toEncrypted(session, directory.getParent()); + final String cleartextName = directory.getName(); + final String ciphertextName = this.toEncrypted(session, directory.getParent(), cleartextName, EnumSet.of(Path.Type.directory)); + final Path metadataParent = new Path(parent, ciphertextName, EnumSet.of(Path.Type.directory)); + // Read directory id from file + try { + log.debug("Read directory ID for folder {} from {}", directory, ciphertextName); + final Path metadataFile = new Path(metadataParent, vault.getDirectoryMetadataFilename(), EnumSet.of(Path.Type.file, Path.Type.encrypted)); + final byte[] ciphertext = new ContentReader(session).readBytes(metadataFile); + // https://github.com/encryption-alliance/unified-vault-format/blob/develop/file%20name%20encryption/AES-SIV-512-B64URL.md#format-of-diruvf-and-symlinkuvf + // TODO can we not use org.cryptomator.cryptolib.v3.DirectoryContentCryptorImpl.decryptDirectoryMetadata()? DirectoryMetadataImpl is not visible and DirectoryMetadata is empty interface, so we cannot access dirId attribute. + if(ciphertext.length != 128) { + throw new IllegalArgumentException("Invalid dir.uvf length: " + ciphertext.length); + } + int headerSize = vault.getCryptor().fileHeaderCryptor().headerSize(); + ByteBuffer buffer = ByteBuffer.wrap(ciphertext); + ByteBuffer headerBuf = buffer.duplicate(); + headerBuf.position(0).limit(headerSize); + ByteBuffer contentBuf = buffer.duplicate(); + contentBuf.position(headerSize); + + FileHeader header = vault.getCryptor().fileHeaderCryptor(loadRevision(session, directory)).decryptHeader(headerBuf); + ByteBuffer plaintext = vault.getCryptor().fileContentCryptor().decryptChunk(contentBuf, 0, header, true); + assert plaintext.remaining() == 32; + byte[] dirId = new byte[32]; + plaintext.get(dirId); + return dirId; + } + catch(NotfoundException e) { + log.warn("Missing directory ID for folder {}", directory); + return this.getOrCreateDirectoryId(session, directory); + } + } + + protected int loadRevision(final Session session, final Path directory) throws BackgroundException { + final Path parent = this.toEncrypted(session, directory.getParent()); + final String cleartextName = directory.getName(); + final String ciphertextName = this.toEncrypted(session, directory.getParent(), cleartextName, EnumSet.of(Path.Type.directory)); + final Path metadataParent = new Path(parent, ciphertextName, EnumSet.of(Path.Type.directory)); + // Read directory id from file + log.debug("Read directory ID for folder {} from {}", directory, ciphertextName); + final Path metadataFile = new Path(metadataParent, vault.getDirectoryMetadataFilename(), EnumSet.of(Path.Type.file, Path.Type.encrypted)); + final byte[] ciphertext = new ContentReader(session).readBytes(metadataFile); + // https://github.com/encryption-alliance/unified-vault-format/blob/develop/file%20name%20encryption/AES-SIV-512-B64URL.md#format-of-diruvf-and-symlinkuvf + // TODO can we not use org.cryptomator.cryptolib.v3.DirectoryContentCryptorImpl.decryptDirectoryMetadata()? DirectoryMetadataImpl is not visible and DirectoryMetadata is empty interface, so we cannot access dirId attribute. + if(ciphertext.length != 128) { + throw new IllegalArgumentException("Invalid dir.uvf length: " + ciphertext.length); + } + int headerSize = vault.getCryptor().fileHeaderCryptor().headerSize(); + ByteBuffer buffer = ByteBuffer.wrap(ciphertext); + ByteBuffer headerBuf = buffer.duplicate(); + headerBuf.position(4).limit(headerSize); + return headerBuf.order(ByteOrder.BIG_ENDIAN).getInt(); + } + + @Override + public byte[] createDirectoryId(final Path directory) { + lock.writeLock().lock(); + try { + final byte[] dirId = new byte[32]; + random.nextBytes(dirId); + cache.put(new SimplePathPredicate(directory), dirId); + return dirId; + } + finally { + lock.writeLock().unlock(); + } + } +} diff --git a/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/impl/CryptoDirectoryV6Provider.java b/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/impl/CryptoDirectoryV6Provider.java index 13b1323fb98..4113ad94afc 100644 --- a/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/impl/CryptoDirectoryV6Provider.java +++ b/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/impl/CryptoDirectoryV6Provider.java @@ -15,6 +15,7 @@ * GNU General Public License for more details. */ +import ch.cyberduck.core.AbstractPath; import ch.cyberduck.core.CacheReference; import ch.cyberduck.core.Path; import ch.cyberduck.core.PathAttributes; @@ -25,13 +26,13 @@ import ch.cyberduck.core.cache.LRUCache; import ch.cyberduck.core.cryptomator.ContentReader; import ch.cyberduck.core.cryptomator.CryptoDirectory; +import ch.cyberduck.core.cryptomator.CryptoFilename; import ch.cyberduck.core.cryptomator.CryptoVault; import ch.cyberduck.core.cryptomator.CryptorCache; import ch.cyberduck.core.exception.BackgroundException; import ch.cyberduck.core.exception.NotfoundException; import ch.cyberduck.core.preferences.PreferencesFactory; -import org.apache.commons.lang3.StringUtils; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -44,36 +45,39 @@ public class CryptoDirectoryV6Provider implements CryptoDirectory { private static final Logger log = LogManager.getLogger(CryptoDirectoryV6Provider.class); private static final String DATA_DIR_NAME = "d"; - private static final String ROOT_DIR_ID = StringUtils.EMPTY; private final Path dataRoot; private final Path home; - private final CryptoVault cryptomator; + private final CryptoFilename filenameProvider; + private final CryptorCache filenameCryptor; private final RandomStringService random = new UUIDRandomStringService(); - private final ReadWriteLock lock = new ReentrantReadWriteLock(); + protected final ReadWriteLock lock = new ReentrantReadWriteLock(); - private final LRUCache, String> cache = LRUCache.build( + protected final LRUCache, byte[]> cache = LRUCache.build( PreferencesFactory.get().getInteger("cryptomator.cache.size")); - public CryptoDirectoryV6Provider(final Path vault, final CryptoVault cryptomator) { + public static final byte[] ROOT_DIR_ID = new byte[0]; + + public CryptoDirectoryV6Provider(final Path vault, final CryptoFilename filenameProvider, final CryptorCache filenameCryptor) { this.home = vault; this.dataRoot = new Path(vault, DATA_DIR_NAME, vault.getType()); - this.cryptomator = cryptomator; + this.filenameProvider = filenameProvider; + this.filenameCryptor = filenameCryptor; } @Override - public String toEncrypted(final Session session, final String directoryId, final String filename, final EnumSet type) throws BackgroundException { + public String toEncrypted(final Session session, final Path parent, final String filename, final EnumSet type) throws BackgroundException { final String prefix = type.contains(Path.Type.directory) ? CryptoVault.DIR_PREFIX : ""; - final String ciphertextName = prefix + cryptomator.getFileNameCryptor().encryptFilename(CryptorCache.BASE32, filename, directoryId.getBytes(StandardCharsets.UTF_8)); + final String ciphertextName = prefix + filenameCryptor.encryptFilename(CryptorCache.BASE32, filename, this.getOrCreateDirectoryId(session, parent)); log.debug("Encrypted filename {} to {}", filename, ciphertextName); - return cryptomator.getFilenameProvider().deflate(session, ciphertextName); + return filenameProvider.deflate(session, ciphertextName); } @Override - public Path toEncrypted(final Session session, final String directoryId, final Path directory) throws BackgroundException { + public Path toEncrypted(final Session session, final Path directory) throws BackgroundException { if(!directory.isDirectory()) { throw new NotfoundException(directory.getAbsolute()); } @@ -83,11 +87,11 @@ public Path toEncrypted(final Session session, final String directoryId, fina attributes.setVersionId(null); attributes.setFileId(null); // Remember random directory id for use in vault - final String id = this.toDirectoryId(session, directory, directoryId); + final byte[] id = this.getOrCreateDirectoryId(session, directory); log.debug("Use directory ID '{}' for folder {}", id, directory); attributes.setDirectoryId(id); attributes.setDecrypted(directory); - final String directoryIdHash = cryptomator.getFileNameCryptor().hashDirectoryId(id); + final String directoryIdHash = filenameCryptor.hashDirectoryId(id); // Intermediate directory final Path intermediate = new Path(dataRoot, directoryIdHash.substring(0, 2), dataRoot.getType()); // Add encrypted type @@ -99,20 +103,14 @@ public Path toEncrypted(final Session session, final String directoryId, fina throw new NotfoundException(directory.getAbsolute()); } - private String toDirectoryId(final Session session, final Path directory, final String directoryId) throws BackgroundException { + protected byte[] toDirectoryId(final Session session, final Path directory) throws BackgroundException { if(new SimplePathPredicate(home).test(directory)) { return ROOT_DIR_ID; } + lock.readLock().lock(); try { - lock.readLock().lock(); if(cache.contains(new SimplePathPredicate(directory))) { - final String existing = cache.get(new SimplePathPredicate(directory)); - if(StringUtils.isNotBlank(directoryId)) { - if(!existing.equals(directoryId)) { - log.warn("Do not override already cached id {} with {}", existing, directoryId); - } - } - return existing; + return cache.get(new SimplePathPredicate(directory)); } } finally { @@ -121,7 +119,7 @@ private String toDirectoryId(final Session session, final Path directory, fin try { log.debug("Acquire lock for {}", directory); lock.writeLock().lock(); - final String id = StringUtils.isBlank(directoryId) ? this.load(session, directory) : directoryId; + final byte[] id = this.load(session, directory); cache.put(new SimplePathPredicate(directory), id); return id; } @@ -130,25 +128,25 @@ private String toDirectoryId(final Session session, final Path directory, fin } } - protected String load(final Session session, final Path directory) throws BackgroundException { - final Path parent = this.toEncrypted(session, directory.getParent().attributes().getDirectoryId(), directory.getParent()); + protected byte[] load(final Session session, final Path directory) throws BackgroundException { + Path encryptedParent = this.toEncrypted(session, directory.getParent()); final String cleartextName = directory.getName(); - final String ciphertextName = this.toEncrypted(session, parent.attributes().getDirectoryId(), cleartextName, EnumSet.of(Path.Type.directory)); + final String ciphertextName = this.toEncrypted(session, directory.getParent(), cleartextName, EnumSet.of(Path.Type.directory)); // Read directory id from file try { log.debug("Read directory ID for folder {} from {}", directory, ciphertextName); - final Path metadataFile = new Path(parent, ciphertextName, EnumSet.of(Path.Type.file, Path.Type.encrypted)); - return new ContentReader(session).read(metadataFile); + final Path metadataFile = new Path(encryptedParent, ciphertextName, EnumSet.of(Path.Type.file, Path.Type.encrypted)); + return new ContentReader(session).readBytes(metadataFile); } catch(NotfoundException e) { log.warn("Missing directory ID for folder {}", directory); - return random.random(); + return random.random().getBytes(StandardCharsets.US_ASCII); } } public void delete(final Path directory) { + lock.writeLock().lock(); try { - lock.writeLock().lock(); cache.remove(new SimplePathPredicate(directory)); } finally { @@ -158,12 +156,34 @@ public void delete(final Path directory) { @Override public void destroy() { + lock.writeLock().lock(); try { - lock.writeLock().lock(); cache.clear(); } finally { lock.writeLock().unlock(); } } + + @Override + public byte[] getOrCreateDirectoryId(final Session session, final Path file) throws BackgroundException { + if(file.attributes().getDirectoryId() != null) { + return file.attributes().getDirectoryId(); + } + final Path decrypted = file.getType().contains(AbstractPath.Type.encrypted) ? file.attributes().getDecrypted() : file; + return this.toDirectoryId(session, decrypted.getType().contains(AbstractPath.Type.file) ? decrypted.getParent() : decrypted); + } + + @Override + public byte[] createDirectoryId(final Path directory) { + lock.writeLock().lock(); + try { + final byte[] directoryId = random.random().getBytes(StandardCharsets.US_ASCII); + cache.put(new SimplePathPredicate(directory), directoryId); + return directoryId; + } + finally { + lock.writeLock().unlock(); + } + } } diff --git a/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/impl/CryptoDirectoryV7Provider.java b/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/impl/CryptoDirectoryV7Provider.java index 28b4bb6211d..bdf17923b62 100644 --- a/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/impl/CryptoDirectoryV7Provider.java +++ b/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/impl/CryptoDirectoryV7Provider.java @@ -19,8 +19,10 @@ import ch.cyberduck.core.RandomStringService; import ch.cyberduck.core.Session; import ch.cyberduck.core.UUIDRandomStringService; +import ch.cyberduck.core.cryptomator.AbstractVault; import ch.cyberduck.core.cryptomator.ContentReader; -import ch.cyberduck.core.cryptomator.CryptoVault; +import ch.cyberduck.core.cryptomator.CryptoFilename; +import ch.cyberduck.core.cryptomator.CryptorCache; import ch.cyberduck.core.exception.BackgroundException; import ch.cyberduck.core.exception.NotfoundException; @@ -35,44 +37,41 @@ public class CryptoDirectoryV7Provider extends CryptoDirectoryV6Provider { private static final Logger log = LogManager.getLogger(CryptoDirectoryV7Provider.class); - public static final String EXTENSION_REGULAR = ".c9r"; - public static final String FILENAME_DIRECTORYID = "dir"; - public static final String DIRECTORY_METADATAFILE = String.format("%s%s", FILENAME_DIRECTORYID, EXTENSION_REGULAR); - public static final String BACKUP_FILENAME_DIRECTORYID = "dirid"; - public static final String BACKUP_DIRECTORY_METADATAFILE = String.format("%s%s", BACKUP_FILENAME_DIRECTORYID, EXTENSION_REGULAR); - - private final CryptoVault cryptomator; + private final CryptoFilename filenameProvider; + private final CryptorCache filenameCryptor; + private final AbstractVault vault; private final RandomStringService random - = new UUIDRandomStringService(); + = new UUIDRandomStringService(); - public CryptoDirectoryV7Provider(final Path vault, final CryptoVault cryptomator) { - super(vault, cryptomator); - this.cryptomator = cryptomator; + public CryptoDirectoryV7Provider(final AbstractVault vault, final CryptoFilename filenameProvider, final CryptorCache filenameCryptor) { + super(vault.getHome(), filenameProvider, filenameCryptor); + this.filenameProvider = filenameProvider; + this.filenameCryptor = filenameCryptor; + this.vault = vault; } @Override - public String toEncrypted(final Session session, final String directoryId, final String filename, final EnumSet type) throws BackgroundException { - final String ciphertextName = cryptomator.getFileNameCryptor().encryptFilename(BaseEncoding.base64Url(), - filename, directoryId.getBytes(StandardCharsets.UTF_8)) + EXTENSION_REGULAR; + public String toEncrypted(final Session session, final Path parent, final String filename, final EnumSet type) throws BackgroundException { + final String ciphertextName = filenameCryptor.encryptFilename(BaseEncoding.base64Url(), filename, this.getOrCreateDirectoryId(session, parent)) + vault.getRegularFileExtension(); log.debug("Encrypted filename {} to {}", filename, ciphertextName); - return cryptomator.getFilenameProvider().deflate(session, ciphertextName); + return filenameProvider.deflate(session, ciphertextName); } - protected String load(final Session session, final Path directory) throws BackgroundException { - final Path parent = this.toEncrypted(session, directory.getParent().attributes().getDirectoryId(), directory.getParent()); + protected byte[] load(final Session session, final Path directory) throws BackgroundException { + final Path encryptedParent = this.toEncrypted(session, directory.getParent()); final String cleartextName = directory.getName(); - final String ciphertextName = this.toEncrypted(session, parent.attributes().getDirectoryId(), cleartextName, EnumSet.of(Path.Type.directory)); - final Path metadataParent = new Path(parent, ciphertextName, EnumSet.of(Path.Type.directory)); + final String ciphertextName = this.toEncrypted(session, directory.getParent(), cleartextName, EnumSet.of(Path.Type.directory)); + final Path metadataParent = new Path(encryptedParent, ciphertextName, EnumSet.of(Path.Type.directory)); // Read directory id from file try { log.debug("Read directory ID for folder {} from {}", directory, ciphertextName); - final Path metadataFile = new Path(metadataParent, CryptoDirectoryV7Provider.DIRECTORY_METADATAFILE, EnumSet.of(Path.Type.file, Path.Type.encrypted)); - return new ContentReader(session).read(metadataFile); + final Path metadataFile = new Path(metadataParent, vault.getDirectoryMetadataFilename(), EnumSet.of(Path.Type.file, Path.Type.encrypted)); + return new ContentReader(session).readBytes(metadataFile); } catch(NotfoundException e) { log.warn("Missing directory ID for folder {}", directory); - return random.random(); + return random.random().getBytes(StandardCharsets.US_ASCII); } } } diff --git a/cryptomator/src/test/java/ch/cyberduck/core/cryptomator/CryptoVaultTest.java b/cryptomator/src/test/java/ch/cyberduck/core/cryptomator/CryptoVaultTest.java index 0a9361a6de7..bbc7851cead 100644 --- a/cryptomator/src/test/java/ch/cyberduck/core/cryptomator/CryptoVaultTest.java +++ b/cryptomator/src/test/java/ch/cyberduck/core/cryptomator/CryptoVaultTest.java @@ -42,7 +42,7 @@ import org.apache.commons.io.IOUtils; import org.cryptomator.cryptolib.api.CryptorProvider; -import org.cryptomator.cryptolib.api.Masterkey; +import org.cryptomator.cryptolib.api.PerpetualMasterkey; import org.cryptomator.cryptolib.common.MasterkeyFile; import org.cryptomator.cryptolib.common.MasterkeyFileAccess; import org.junit.Test; @@ -564,7 +564,7 @@ public static String createJWT(final String masterkeyCryptomator, final MasterkeyFile mkFile = MasterkeyFile.read(new StringReader(masterkeyCryptomator)); final StringWriter writer = new StringWriter(); mkFile.write(writer); - final Masterkey masterkey = new MasterkeyFileAccess(PreferencesFactory.get().getProperty("cryptomator.vault.pepper").getBytes(StandardCharsets.UTF_8), + final PerpetualMasterkey masterkey = new MasterkeyFileAccess(PreferencesFactory.get().getProperty("cryptomator.vault.pepper").getBytes(StandardCharsets.UTF_8), FastSecureRandomProvider.get().provide()).load(new ByteArrayInputStream(writer.getBuffer().toString().getBytes(StandardCharsets.UTF_8)), passphrase); final Algorithm algorithm = Algorithm.HMAC256(masterkey.getEncoded()); return JWT.create() diff --git a/cryptomator/src/test/java/ch/cyberduck/core/cryptomator/CryptorCacheTest.java b/cryptomator/src/test/java/ch/cyberduck/core/cryptomator/CryptorCacheTest.java index f88038fc29e..94deb11d3d5 100644 --- a/cryptomator/src/test/java/ch/cyberduck/core/cryptomator/CryptorCacheTest.java +++ b/cryptomator/src/test/java/ch/cyberduck/core/cryptomator/CryptorCacheTest.java @@ -19,10 +19,11 @@ import org.cryptomator.cryptolib.api.FileNameCryptor; import org.junit.Test; +import java.nio.charset.StandardCharsets; + import com.google.common.io.BaseEncoding; import static org.junit.Assert.assertEquals; -import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Mockito.*; public class CryptorCacheTest { @@ -31,10 +32,10 @@ public class CryptorCacheTest { public void TestHashDirectoryId() { final FileNameCryptor mock = mock(FileNameCryptor.class); final CryptorCache cryptor = new CryptorCache(mock); - when(mock.hashDirectoryId(anyString())).thenReturn("hashed"); - assertEquals("hashed", cryptor.hashDirectoryId("id")); - assertEquals("hashed", cryptor.hashDirectoryId("id")); - verify(mock, times(1)).hashDirectoryId(anyString()); + when(mock.hashDirectoryId(any(byte[].class))).thenReturn("hashed"); + assertEquals("hashed", cryptor.hashDirectoryId("id".getBytes(StandardCharsets.US_ASCII))); + assertEquals("hashed", cryptor.hashDirectoryId("id".getBytes(StandardCharsets.US_ASCII))); + verify(mock, times(1)).hashDirectoryId(any(byte[].class)); verifyNoMoreInteractions(mock); } diff --git a/cryptomator/src/test/java/ch/cyberduck/core/cryptomator/features/CryptoBulkFeatureTest.java b/cryptomator/src/test/java/ch/cyberduck/core/cryptomator/features/CryptoBulkFeatureTest.java index 2bde499b600..86287502683 100644 --- a/cryptomator/src/test/java/ch/cyberduck/core/cryptomator/features/CryptoBulkFeatureTest.java +++ b/cryptomator/src/test/java/ch/cyberduck/core/cryptomator/features/CryptoBulkFeatureTest.java @@ -88,7 +88,7 @@ public boolean test(final TransferItem item) { return item.remote.isDirectory(); } }).findFirst().get().remote; - final String directoryId = encryptedDirectory.attributes().getDirectoryId(); + final byte[] directoryId = encryptedDirectory.attributes().getDirectoryId(); assertNotNull(directoryId); for(TransferItem file : pre.keySet().stream().filter(new Predicate() { @Override diff --git a/cryptomator/src/test/java/ch/cyberduck/core/cryptomator/features/CryptoReadFeatureTest.java b/cryptomator/src/test/java/ch/cyberduck/core/cryptomator/features/CryptoReadFeatureTest.java index b0f53977c41..65801444f38 100644 --- a/cryptomator/src/test/java/ch/cyberduck/core/cryptomator/features/CryptoReadFeatureTest.java +++ b/cryptomator/src/test/java/ch/cyberduck/core/cryptomator/features/CryptoReadFeatureTest.java @@ -90,7 +90,7 @@ public Credentials prompt(final Host bookmark, final String title, final String }). getHome()); - CryptoReadFeature read = new CryptoReadFeature(null, null, vault); + CryptoReadFeature read = new CryptoReadFeature(session, null, vault); { assertEquals(0, read.chunk(0)); diff --git a/cryptomator/src/test/java/ch/cyberduck/core/cryptomator/impl/CryptoDirectoryV6ProviderTest.java b/cryptomator/src/test/java/ch/cyberduck/core/cryptomator/impl/CryptoDirectoryV6ProviderTest.java index a2f78fa324e..8add334cd83 100644 --- a/cryptomator/src/test/java/ch/cyberduck/core/cryptomator/impl/CryptoDirectoryV6ProviderTest.java +++ b/cryptomator/src/test/java/ch/cyberduck/core/cryptomator/impl/CryptoDirectoryV6ProviderTest.java @@ -15,27 +15,20 @@ * GNU General Public License for more details. */ -import ch.cyberduck.core.ConnectionCallback; -import ch.cyberduck.core.Credentials; -import ch.cyberduck.core.DisabledPasswordCallback; import ch.cyberduck.core.Host; -import ch.cyberduck.core.LoginOptions; import ch.cyberduck.core.NullSession; import ch.cyberduck.core.Path; import ch.cyberduck.core.TestProtocol; import ch.cyberduck.core.cryptomator.CryptoDirectory; -import ch.cyberduck.core.cryptomator.CryptoVault; -import ch.cyberduck.core.exception.BackgroundException; +import ch.cyberduck.core.cryptomator.CryptorCache; import ch.cyberduck.core.exception.NotfoundException; -import ch.cyberduck.core.features.Read; -import ch.cyberduck.core.transfer.TransferStatus; -import ch.cyberduck.core.vault.VaultCredentials; -import org.apache.commons.io.IOUtils; +import org.cryptomator.cryptolib.api.Cryptor; +import org.cryptomator.cryptolib.api.CryptorProvider; +import org.cryptomator.cryptolib.api.PerpetualMasterkey; import org.junit.Test; -import java.io.InputStream; -import java.nio.charset.Charset; +import java.security.SecureRandom; import java.util.EnumSet; import static org.junit.Assert.assertEquals; @@ -46,65 +39,34 @@ public class CryptoDirectoryV6ProviderTest { @Test(expected = NotfoundException.class) public void testToEncryptedInvalidArgument() throws Exception { final Path home = new Path("/vault", EnumSet.of(Path.Type.directory)); - final CryptoVault vault = new CryptoVault(home); - final CryptoDirectory provider = new CryptoDirectoryV6Provider(home, vault); - provider.toEncrypted(new NullSession(new Host(new TestProtocol())), null, new Path("/vault/f", EnumSet.of(Path.Type.file))); + final CryptorProvider crypto = CryptorProvider.forScheme(CryptorProvider.Scheme.SIV_CTRMAC); + final SecureRandom random = new SecureRandom(); + final Cryptor cryptor = crypto.provide(PerpetualMasterkey.generate(random), random); + final CryptoDirectory provider = new CryptoDirectoryV6Provider(home, new CryptoFilenameV6Provider(home), new CryptorCache(cryptor.fileNameCryptor())); + provider.toEncrypted(new NullSession(new Host(new TestProtocol())), new Path("/vault/f", EnumSet.of(Path.Type.file))); } @Test(expected = NotfoundException.class) public void testToEncryptedInvalidPath() throws Exception { final Path home = new Path("/vault", EnumSet.of(Path.Type.directory)); - final CryptoVault vault = new CryptoVault(home); - final CryptoDirectory provider = new CryptoDirectoryV6Provider(home, vault); - provider.toEncrypted(new NullSession(new Host(new TestProtocol())), null, new Path("/", EnumSet.of(Path.Type.directory))); + final CryptorProvider crypto = CryptorProvider.forScheme(CryptorProvider.Scheme.SIV_CTRMAC); + final SecureRandom random = new SecureRandom(); + final Cryptor cryptor = crypto.provide(PerpetualMasterkey.generate(random), random); + final CryptoDirectory provider = new CryptoDirectoryV6Provider(home, new CryptoFilenameV6Provider(home), new CryptorCache(cryptor.fileNameCryptor())); + provider.toEncrypted(new NullSession(new Host(new TestProtocol())), new Path("/", EnumSet.of(Path.Type.directory))); } @Test public void testToEncryptedDirectory() throws Exception { final Path home = new Path("/vault", EnumSet.of(Path.Type.directory)); - final NullSession session = new NullSession(new Host(new TestProtocol())) { - @Override - @SuppressWarnings("unchecked") - public T _getFeature(final Class type) { - if(type == Read.class) { - return (T) new Read() { - @Override - public InputStream read(final Path file, final TransferStatus status, final ConnectionCallback callback) throws BackgroundException { - final String masterKey = "{\n" + - " \"scryptSalt\": \"NrC7QGG/ouc=\",\n" + - " \"scryptCostParam\": 16384,\n" + - " \"scryptBlockSize\": 8,\n" + - " \"primaryMasterKey\": \"Q7pGo1l0jmZssoQh9rXFPKJE9NIXvPbL+HcnVSR9CHdkeR8AwgFtcw==\",\n" + - " \"hmacMasterKey\": \"xzBqT4/7uEcQbhHFLC0YmMy4ykVKbuvJEA46p1Xm25mJNuTc20nCbw==\",\n" + - " \"versionMac\": \"hlNr3dz/CmuVajhaiGyCem9lcVIUjDfSMLhjppcXOrM=\",\n" + - " \"version\": 5\n" + - "}"; - if("masterkey.cryptomator".equals(file.getName())) { - return IOUtils.toInputStream(masterKey, Charset.defaultCharset()); - } - throw new NotfoundException(String.format("%s not found", file.getName())); - } - - @Override - public boolean offset(final Path file) { - return false; - } - }; - } - return super._getFeature(type); - } - }; - final CryptoVault vault = new CryptoVault(home); - vault.load(session, new DisabledPasswordCallback() { - @Override - public Credentials prompt(final Host bookmark, final String title, final String reason, final LoginOptions options) { - return new VaultCredentials("vault"); - } - }); - final CryptoDirectory provider = new CryptoDirectoryV6Provider(home, vault); - assertNotNull(provider.toEncrypted(session, null, home)); + final NullSession session = new NullSession(new Host(new TestProtocol())); + final CryptorProvider crypto = CryptorProvider.forScheme(CryptorProvider.Scheme.SIV_CTRMAC); + final SecureRandom csprng = new SecureRandom(); + final Cryptor cryptor = crypto.provide(PerpetualMasterkey.generate(csprng), csprng); + final CryptoDirectory provider = new CryptoDirectoryV6Provider(home, new CryptoFilenameV6Provider(home), new CryptorCache(cryptor.fileNameCryptor())); + assertNotNull(provider.toEncrypted(session, home)); final Path f = new Path("/vault/f", EnumSet.of(Path.Type.directory)); - assertNotNull(provider.toEncrypted(session, null, f)); - assertEquals(provider.toEncrypted(session, null, f), provider.toEncrypted(session, null, f)); + assertNotNull(provider.toEncrypted(session, f)); + assertEquals(provider.toEncrypted(session, f), provider.toEncrypted(session, f)); } } diff --git a/cryptomator/src/test/java/ch/cyberduck/core/cryptomator/impl/CryptoDirectoryV7ProviderTest.java b/cryptomator/src/test/java/ch/cyberduck/core/cryptomator/impl/CryptoDirectoryV7ProviderTest.java index ee372bed4d0..eab675ceb3b 100644 --- a/cryptomator/src/test/java/ch/cyberduck/core/cryptomator/impl/CryptoDirectoryV7ProviderTest.java +++ b/cryptomator/src/test/java/ch/cyberduck/core/cryptomator/impl/CryptoDirectoryV7ProviderTest.java @@ -15,32 +15,23 @@ * GNU General Public License for more details. */ -import ch.cyberduck.core.ConnectionCallback; -import ch.cyberduck.core.Credentials; -import ch.cyberduck.core.DisabledPasswordCallback; import ch.cyberduck.core.Host; -import ch.cyberduck.core.LoginOptions; import ch.cyberduck.core.NullSession; import ch.cyberduck.core.Path; import ch.cyberduck.core.TestProtocol; import ch.cyberduck.core.cryptomator.CryptoDirectory; import ch.cyberduck.core.cryptomator.CryptoVault; -import ch.cyberduck.core.exception.BackgroundException; +import ch.cyberduck.core.cryptomator.CryptorCache; import ch.cyberduck.core.exception.NotfoundException; -import ch.cyberduck.core.features.Read; -import ch.cyberduck.core.transfer.TransferStatus; -import ch.cyberduck.core.vault.VaultCredentials; -import org.apache.commons.io.IOUtils; +import org.cryptomator.cryptolib.api.Cryptor; import org.cryptomator.cryptolib.api.CryptorProvider; +import org.cryptomator.cryptolib.api.PerpetualMasterkey; import org.junit.Test; -import java.io.InputStream; -import java.nio.charset.Charset; +import java.security.SecureRandom; import java.util.EnumSet; -import static ch.cyberduck.core.cryptomator.CryptoVault.VAULT_VERSION; -import static ch.cyberduck.core.cryptomator.CryptoVaultTest.createJWT; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; @@ -49,68 +40,34 @@ public class CryptoDirectoryV7ProviderTest { @Test(expected = NotfoundException.class) public void testToEncryptedInvalidArgument() throws Exception { final Path home = new Path("/vault", EnumSet.of(Path.Type.directory)); - final CryptoVault vault = new CryptoVault(home); - final CryptoDirectory provider = new CryptoDirectoryV7Provider(home, vault); - provider.toEncrypted(new NullSession(new Host(new TestProtocol())), null, new Path("/vault/f", EnumSet.of(Path.Type.file))); + final CryptorProvider crypto = CryptorProvider.forScheme(CryptorProvider.Scheme.SIV_GCM); + final SecureRandom random = new SecureRandom(); + final Cryptor cryptor = crypto.provide(PerpetualMasterkey.generate(random), random); + final CryptoDirectory provider = new CryptoDirectoryV7Provider(new CryptoVault(home), new CryptoFilenameV7Provider(), new CryptorCache(cryptor.fileNameCryptor())); + provider.toEncrypted(new NullSession(new Host(new TestProtocol())), new Path("/vault/f", EnumSet.of(Path.Type.file))); } @Test(expected = NotfoundException.class) public void testToEncryptedInvalidPath() throws Exception { final Path home = new Path("/vault", EnumSet.of(Path.Type.directory)); - final CryptoVault vault = new CryptoVault(home); - final CryptoDirectory provider = new CryptoDirectoryV7Provider(home, vault); - provider.toEncrypted(new NullSession(new Host(new TestProtocol())), null, new Path("/", EnumSet.of(Path.Type.directory))); + final CryptorProvider crypto = CryptorProvider.forScheme(CryptorProvider.Scheme.SIV_GCM); + final SecureRandom random = new SecureRandom(); + final Cryptor cryptor = crypto.provide(PerpetualMasterkey.generate(random), random); + final CryptoDirectory provider = new CryptoDirectoryV7Provider(new CryptoVault(home), new CryptoFilenameV7Provider(), new CryptorCache(cryptor.fileNameCryptor())); + provider.toEncrypted(new NullSession(new Host(new TestProtocol())), new Path("/", EnumSet.of(Path.Type.directory))); } @Test public void testToEncryptedDirectory() throws Exception { final Path home = new Path("/vault", EnumSet.of(Path.Type.directory)); - final NullSession session = new NullSession(new Host(new TestProtocol())) { - @Override - @SuppressWarnings("unchecked") - public T _getFeature(final Class type) { - if(type == Read.class) { - return (T) new Read() { - @Override - public InputStream read(final Path file, final TransferStatus status, final ConnectionCallback callback) throws BackgroundException { - final String masterKey = "{\n" + - " \"scryptSalt\": \"NrC7QGG/ouc=\",\n" + - " \"scryptCostParam\": 16384,\n" + - " \"scryptBlockSize\": 8,\n" + - " \"primaryMasterKey\": \"Q7pGo1l0jmZssoQh9rXFPKJE9NIXvPbL+HcnVSR9CHdkeR8AwgFtcw==\",\n" + - " \"hmacMasterKey\": \"xzBqT4/7uEcQbhHFLC0YmMy4ykVKbuvJEA46p1Xm25mJNuTc20nCbw==\",\n" + - " \"versionMac\": \"hlNr3dz/CmuVajhaiGyCem9lcVIUjDfSMLhjppcXOrM=\",\n" + - " \"version\": 8\n" + - "}"; - if("masterkey.cryptomator".equals(file.getName())) { - return IOUtils.toInputStream(masterKey, Charset.defaultCharset()); - } - if("vault.cryptomator".equals(file.getName())) { - return IOUtils.toInputStream(createJWT(masterKey, VAULT_VERSION, CryptorProvider.Scheme.SIV_GCM, "vault"), Charset.defaultCharset()); - } - throw new NotfoundException(String.format("%s not found", file.getName())); - } - - @Override - public boolean offset(final Path file) { - return false; - } - }; - } - return super._getFeature(type); - } - }; - final CryptoVault vault = new CryptoVault(home); - vault.load(session, new DisabledPasswordCallback() { - @Override - public Credentials prompt(final Host bookmark, final String title, final String reason, final LoginOptions options) { - return new VaultCredentials("vault"); - } - }); - final CryptoDirectory provider = new CryptoDirectoryV7Provider(home, vault); - assertNotNull(provider.toEncrypted(session, null, home)); + final NullSession session = new NullSession(new Host(new TestProtocol())); + final CryptorProvider crypto = CryptorProvider.forScheme(CryptorProvider.Scheme.SIV_GCM); + final SecureRandom random = new SecureRandom(); + final Cryptor cryptor = crypto.provide(PerpetualMasterkey.generate(random), random); + final CryptoDirectory provider = new CryptoDirectoryV7Provider(new CryptoVault(home), new CryptoFilenameV7Provider(), new CryptorCache(cryptor.fileNameCryptor())); + assertNotNull(provider.toEncrypted(session, home)); final Path f = new Path("/vault/f", EnumSet.of(Path.Type.directory)); - assertNotNull(provider.toEncrypted(session, null, f)); - assertEquals(provider.toEncrypted(session, null, f), provider.toEncrypted(session, null, f)); + assertNotNull(provider.toEncrypted(session, f)); + assertEquals(provider.toEncrypted(session, f), provider.toEncrypted(session, f)); } } diff --git a/pom.xml b/pom.xml index 7b71fe976d9..156a6584f23 100644 --- a/pom.xml +++ b/pom.xml @@ -93,6 +93,7 @@ 8u312b07 0.10.0 ch.cyberduck.test.IntegrationTest + ch.cyberduck.core.cryptomator.SFTPCryptomatorInteroperabilityTest @@ -568,6 +569,9 @@ ${project.build.directory} ${surefire.group.excluded} + + ${surefire.exclude} + false diff --git a/s3/src/test/java/ch/cyberduck/core/cryptomator/UVFIntegrationTest.java b/s3/src/test/java/ch/cyberduck/core/cryptomator/UVFIntegrationTest.java new file mode 100644 index 00000000000..c4fd45bba1e --- /dev/null +++ b/s3/src/test/java/ch/cyberduck/core/cryptomator/UVFIntegrationTest.java @@ -0,0 +1,309 @@ +package ch.cyberduck.core.cryptomator; + +/* + * Copyright (c) 2002-2025 iterate GmbH. All rights reserved. + * https://cyberduck.io/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +import ch.cyberduck.core.*; +import ch.cyberduck.core.exception.BackgroundException; +import ch.cyberduck.core.features.AttributesFinder; +import ch.cyberduck.core.features.Bulk; +import ch.cyberduck.core.features.Delete; +import ch.cyberduck.core.features.Directory; +import ch.cyberduck.core.features.Move; +import ch.cyberduck.core.features.Read; +import ch.cyberduck.core.features.Write; +import ch.cyberduck.core.io.StatusOutputStream; +import ch.cyberduck.core.proxy.ProxyFactory; +import ch.cyberduck.core.s3.S3BucketCreateService; +import ch.cyberduck.core.s3.S3Protocol; +import ch.cyberduck.core.s3.S3Session; +import ch.cyberduck.core.shared.DefaultPathHomeFeature; +import ch.cyberduck.core.sts.AbstractAssumeRoleWithWebIdentityTest; +import ch.cyberduck.core.transfer.Transfer; +import ch.cyberduck.core.transfer.TransferItem; +import ch.cyberduck.core.transfer.TransferStatus; +import ch.cyberduck.core.vault.DefaultVaultRegistry; +import ch.cyberduck.core.vault.VaultRegistry; +import ch.cyberduck.core.worker.DeleteWorker; +import ch.cyberduck.test.TestcontainerTest; + +import org.apache.commons.io.IOUtils; +import org.apache.commons.lang3.RandomUtils; +import org.cryptomator.cryptolib.api.UVFMasterkey; +import org.jetbrains.annotations.NotNull; +import org.junit.Test; +import org.junit.experimental.categories.Category; +import org.testcontainers.containers.ComposeContainer; +import org.testcontainers.containers.wait.strategy.Wait; + +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.nio.charset.StandardCharsets; +import java.util.AbstractMap; +import java.util.Arrays; +import java.util.Collections; +import java.util.EnumSet; +import java.util.HashSet; +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import static org.junit.Assert.*; + +/** + * Test {@link UVFVault} implementation against test data from + * org.cryptomator.cryptolib.v3.UVFIntegrationTest + */ +@Category(TestcontainerTest.class) +public class UVFIntegrationTest { + + private static final ComposeContainer container = new ComposeContainer( + new File(AbstractAssumeRoleWithWebIdentityTest.class.getResource("/uvf/docker-compose.yml").getFile())) + .withPull(false) +// .withLocalCompose(true) + .withEnv( + Stream.of( + new AbstractMap.SimpleImmutableEntry<>("MINIO_PORT", "9000"), + new AbstractMap.SimpleImmutableEntry<>("MINIO_CONSOLE_PORT", "9001") + ).collect(Collectors.toMap(AbstractMap.SimpleImmutableEntry::getKey, AbstractMap.SimpleImmutableEntry::getValue))) + .withExposedService("minio-1", 9000, Wait.forListeningPort()); + + + @Test + public void listMinio() throws BackgroundException, IOException { + container.start(); + try { + final String bucketName = "cyberduckbucket"; + + final Host bookmark = getMinIOBookmark(); + final S3Session storage = getS3SessionForBookmark(bookmark); + + final Path bucket = new Path(bucketName, EnumSet.of(AbstractPath.Type.directory)); + new S3BucketCreateService(storage).create(bucket, "us-east-1"); + + final List files = Arrays.asList( + "/d/RZ/K7ZH7KBXULNEKBMGX3CU42PGUIAIX4/rExOms183v5evFwgIKiW0qvbsor1Hg==.uvf/dir.uvf", // -> /subir + "/d/RZ/K7ZH7KBXULNEKBMGX3CU42PGUIAIX4/dir.uvf", // -> / + "/d/RZ/K7ZH7KBXULNEKBMGX3CU42PGUIAIX4/GsMMTRvsuuP_6NjgRwopmWcuof-PyRQ=.uvf", // -> /foo.txt + "/d/6L/HPWBEU3OJP2EZUCP4CV3HHL47BXVEX/5qTOPMA1BouBRhz_G7qfmKety92geI4=.uvf", // -> /subdir/bar.txt + "/d/6L/HPWBEU3OJP2EZUCP4CV3HHL47BXVEX/dir.uvf" // /subdir + ); + final String jwe = "{\n" + + " \"fileFormat\": \"AES-256-GCM-32k\",\n" + + " \"nameFormat\": \"AES-SIV-512-B64URL\",\n" + + " \"seeds\": {\n" + + " \"HDm38g\": \"ypeBEsobvcr6wjGzmiPcTaeG7_gUfE5yuYB3ha_uSLs\",\n" + + " \"gBryKw\": \"PiPoFgA5WUoziU9lZOGxNIu9egCI1CxKy3PurtWcAJ0\",\n" + + " \"QBsJFg\": \"Ln0sA6lQeuJl7PW1NWiFpTOTogKdJBOUmXJloaJa78Y\"\n" + + " },\n" + + " \"initialSeed\": \"HDm38i\",\n" + + " \"latestSeed\": \"QBsJFo\",\n" + + " \"kdf\": \"HKDF-SHA512\",\n" + + " \"kdfSalt\": \"NIlr89R7FhochyP4yuXZmDqCnQ0dBB3UZ2D-6oiIjr8\",\n" + + " \"org.example.customfield\": 42\n" + + "}"; + + try { + for(final String fi : files) { + final Path file = new Path("/" + bucketName + "/" + fi, EnumSet.of(AbstractPath.Type.file)); + byte[] content = new byte[1000]; + final int size; + try(final InputStream in = UVFIntegrationTest.class.getResourceAsStream("/uvf/first_vault" + fi)) { + size = in.read(content); + } + final TransferStatus transferStatus = new TransferStatus().setLength(size); + transferStatus.setChecksum(storage.getFeature(Write.class).checksum(file, transferStatus).compute(new ByteArrayInputStream(content), transferStatus)); + storage.getFeature(Bulk.class).pre(Transfer.Type.upload, Collections.singletonMap(new TransferItem(file), transferStatus), new DisabledConnectionCallback()); + final StatusOutputStream out = storage.getFeature(Write.class).write(file, transferStatus, new DisabledConnectionCallback()); + IOUtils.copyLarge(UVFIntegrationTest.class.getResourceAsStream("/uvf/first_vault" + fi), out); + out.close(); + } + + final VaultRegistry vaults = new DefaultVaultRegistry(new DisabledPasswordCallback()); + bookmark.setDefaultPath("/" + bucketName); + final UVFVault vault = new UVFVault(new DefaultPathHomeFeature(bookmark).find()); + vaults.add(vault.load(storage, new DisabledPasswordCallback() { + @Override + public Credentials prompt(final Host bookmark, final String title, final String reason, final LoginOptions options) { + return new Credentials().withPassword(jwe); + } + })); + final PathAttributes attr = storage.getFeature(AttributesFinder.class).find(vault.getHome()); + storage.withRegistry(vaults); + try(final UVFMasterkey masterKey = UVFMasterkey.fromDecryptedPayload(jwe)) { + assertArrayEquals(masterKey.rootDirId(), vault.getRootDirId()); + } + + final Path home = vault.getHome().withAttributes(attr).withType(EnumSet.of(AbstractPath.Type.directory, AbstractPath.Type.vault)); + { + final AttributedList list = storage.getFeature(ListService.class).list(home, new DisabledListProgressListener()); + assertEquals( + new HashSet<>(Arrays.asList( + new Path("/cyberduckbucket/subdir", EnumSet.of(AbstractPath.Type.directory, AbstractPath.Type.placeholder, AbstractPath.Type.decrypted)), + new Path("/cyberduckbucket/foo.txt", EnumSet.of(AbstractPath.Type.file, AbstractPath.Type.decrypted))) + ), + new HashSet<>(list.toList())); + assertEquals("Hello Foo", readFile(storage, new Path("/cyberduckbucket/foo.txt", EnumSet.of(AbstractPath.Type.file, AbstractPath.Type.decrypted)))); + } + { + final byte[] expected = writeRandomFile(storage, new Path("/cyberduckbucket/alice.txt", EnumSet.of(AbstractPath.Type.file, AbstractPath.Type.decrypted)), 57); + final AttributedList list = storage.getFeature(ListService.class).list(home, new DisabledListProgressListener()); + assertEquals( + new HashSet<>(Arrays.asList( + new Path("/cyberduckbucket/subdir", EnumSet.of(AbstractPath.Type.directory, AbstractPath.Type.placeholder, AbstractPath.Type.decrypted)), + new Path("/cyberduckbucket/alice.txt", EnumSet.of(AbstractPath.Type.file, AbstractPath.Type.decrypted)), + new Path("/cyberduckbucket/foo.txt", EnumSet.of(AbstractPath.Type.file, AbstractPath.Type.decrypted)))), + new HashSet<>(list.toList())); + + assertEquals(new String(expected), readFile(storage, new Path("/cyberduckbucket/alice.txt", EnumSet.of(AbstractPath.Type.file, AbstractPath.Type.decrypted)))); + } + { + final PathAttributes subdir = storage.getFeature(AttributesFinder.class).find(new Path("/cyberduckbucket/subdir", EnumSet.of(AbstractPath.Type.directory, AbstractPath.Type.placeholder, AbstractPath.Type.decrypted))); + final AttributedList list = storage.getFeature(ListService.class).list(new Path("/cyberduckbucket/subdir", EnumSet.of(AbstractPath.Type.directory, AbstractPath.Type.placeholder, AbstractPath.Type.decrypted)).withAttributes(subdir), new DisabledListProgressListener()); + assertEquals( + new HashSet<>(Collections.singletonList( + new Path("/cyberduckbucket/subdir/bar.txt", EnumSet.of(AbstractPath.Type.file, AbstractPath.Type.decrypted))) + ), + new HashSet<>(list.toList())); + assertEquals("Hello Bar", readFile(storage, new Path("/cyberduckbucket/subdir/bar.txt", EnumSet.of(AbstractPath.Type.file, AbstractPath.Type.decrypted)))); + } + { + final byte[] expected = writeRandomFile(storage, new Path("/cyberduckbucket/subdir/alice.txt", EnumSet.of(AbstractPath.Type.file, AbstractPath.Type.decrypted)), 55); + final AttributedList list = storage.getFeature(ListService.class).list(new Path("/cyberduckbucket/subdir", EnumSet.of(AbstractPath.Type.directory, AbstractPath.Type.placeholder, AbstractPath.Type.decrypted)), new DisabledListProgressListener()); + assertEquals( + new HashSet<>(Arrays.asList( + new Path("/cyberduckbucket/subdir/alice.txt", EnumSet.of(AbstractPath.Type.file, AbstractPath.Type.decrypted)), + new Path("/cyberduckbucket/subdir/bar.txt", EnumSet.of(AbstractPath.Type.file, AbstractPath.Type.decrypted)))), + new HashSet<>(list.toList())); + assertEquals(new String(expected), readFile(storage, new Path("/cyberduckbucket/subdir/alice.txt", EnumSet.of(AbstractPath.Type.file, AbstractPath.Type.decrypted)))); + } + { + storage.getFeature(Directory.class).mkdir(storage.getFeature(Write.class), + new Path("/cyberduckbucket/subdir/subsubdir", EnumSet.of(AbstractPath.Type.directory, AbstractPath.Type.placeholder, AbstractPath.Type.decrypted)), new TransferStatus()); + final AttributedList list = storage.getFeature(ListService.class).list(new Path("/cyberduckbucket/subdir", EnumSet.of(AbstractPath.Type.directory, AbstractPath.Type.placeholder, AbstractPath.Type.decrypted)), new DisabledListProgressListener()); + storage.getFeature(ListService.class).list(bucket, new DisabledListProgressListener()); + assertEquals( + new HashSet<>(Arrays.asList( + new Path("/cyberduckbucket/subdir/alice.txt", EnumSet.of(AbstractPath.Type.file, AbstractPath.Type.decrypted)), + new Path("/cyberduckbucket/subdir/bar.txt", EnumSet.of(AbstractPath.Type.file, AbstractPath.Type.decrypted)), + new Path("/cyberduckbucket/subdir/subsubdir", EnumSet.of(AbstractPath.Type.directory, AbstractPath.Type.decrypted)))), + new HashSet<>(list.toList())); + } + { + final byte[] expected = writeRandomFile(storage, new Path("/cyberduckbucket/subdir/subsubdir/foo.txt", EnumSet.of(AbstractPath.Type.file, AbstractPath.Type.decrypted)), 5000); + final AttributedList list = storage.getFeature(ListService.class).list(new Path("/cyberduckbucket/subdir/subsubdir", EnumSet.of(AbstractPath.Type.directory, AbstractPath.Type.placeholder, AbstractPath.Type.decrypted)), new DisabledListProgressListener()); + assertEquals( + new HashSet<>(Collections.singletonList( + new Path("/cyberduckbucket/subdir/subsubdir/foo.txt", EnumSet.of(AbstractPath.Type.file, AbstractPath.Type.decrypted))) + ), + new HashSet<>(list.toList())); + assertEquals(new String(expected), readFile(storage, new Path("/cyberduckbucket/subdir/subsubdir/foo.txt", EnumSet.of(AbstractPath.Type.file, AbstractPath.Type.decrypted)))); + } + { + storage.getFeature(Delete.class).delete(Collections.singletonList(new Path("/cyberduckbucket/subdir/bar.txt", EnumSet.of(AbstractPath.Type.file, AbstractPath.Type.decrypted))), new DisabledPasswordCallback(), new Delete.DisabledCallback()); + final AttributedList list = storage.getFeature(ListService.class).list(new Path("/cyberduckbucket/subdir", EnumSet.of(AbstractPath.Type.directory, AbstractPath.Type.placeholder, AbstractPath.Type.decrypted)), new DisabledListProgressListener()); + assertEquals(2, list.size()); + assertTrue(Arrays.toString(list.toArray()), list.contains(new Path("/cyberduckbucket/subdir/alice.txt", EnumSet.of(AbstractPath.Type.file, AbstractPath.Type.decrypted)))); + assertEquals( + new HashSet<>(Arrays.asList( + new Path("/cyberduckbucket/subdir/alice.txt", EnumSet.of(AbstractPath.Type.file, AbstractPath.Type.decrypted)), + new Path("/cyberduckbucket/subdir/subsubdir", EnumSet.of(AbstractPath.Type.directory, AbstractPath.Type.decrypted))) + ), + new HashSet<>(list.toList())); + } + { + storage.getFeature(Move.class).move( + new Path("/cyberduckbucket/foo.txt", EnumSet.of(AbstractPath.Type.file, AbstractPath.Type.decrypted)), + new Path("/cyberduckbucket/subdir/Dave.txt", EnumSet.of(AbstractPath.Type.file, AbstractPath.Type.decrypted)), + new TransferStatus(), new Delete.DisabledCallback(), new DisabledConnectionCallback() + ); + + final AttributedList listSubDir = storage.getFeature(ListService.class).list(new Path("/cyberduckbucket/subdir", EnumSet.of(AbstractPath.Type.directory, AbstractPath.Type.placeholder, AbstractPath.Type.decrypted)), new DisabledListProgressListener()); + assertEquals( + new HashSet<>(Arrays.asList( + new Path("/cyberduckbucket/subdir/alice.txt", EnumSet.of(AbstractPath.Type.file, AbstractPath.Type.decrypted)), + new Path("/cyberduckbucket/subdir/Dave.txt", EnumSet.of(AbstractPath.Type.file, AbstractPath.Type.decrypted)), + new Path("/cyberduckbucket/subdir/subsubdir", EnumSet.of(AbstractPath.Type.directory, AbstractPath.Type.decrypted))) + ), + new HashSet<>(listSubDir.toList())); + final AttributedList listHome = storage.getFeature(ListService.class).list(new Path("/cyberduckbucket/", EnumSet.of(AbstractPath.Type.directory, AbstractPath.Type.placeholder, AbstractPath.Type.decrypted)), new DisabledListProgressListener()); + assertEquals( + new HashSet<>(Arrays.asList( + new Path("/cyberduckbucket/alice.txt", EnumSet.of(AbstractPath.Type.file, AbstractPath.Type.decrypted)), + new Path("/cyberduckbucket/subdir", EnumSet.of(AbstractPath.Type.directory, AbstractPath.Type.placeholder, AbstractPath.Type.decrypted))) + ), + new HashSet<>(listHome.toList())); + } + } + finally { + storage.withRegistry(new DefaultVaultRegistry(new DisabledPasswordCallback())); + new DeleteWorker(new DisabledLoginCallback(), + storage.getFeature(ListService.class).list(bucket, new DisabledListProgressListener()).toList().stream() + .filter(f -> storage.getFeature(Delete.class).isSupported(f)).collect(Collectors.toList()), + new DisabledProgressListener()).run(storage); + storage.getFeature(Delete.class).delete(Collections.singletonList(bucket), new DisabledPasswordCallback(), new Delete.DisabledCallback()); + } + } + finally { + container.stop(); + } + } + + private static @NotNull Host getMinIOBookmark() { + final Host bookmark = new Host(new S3Protocol() { + @Override + public Scheme getScheme() { + return Scheme.http; + } + }, "localhost", 9000).withCredentials(new Credentials("minioadmin", "minioadmin")); + bookmark.setProperty("s3.bucket.virtualhost.disable", "true"); + bookmark.setDefaultPath("/"); + return bookmark; + } + + private static @NotNull S3Session getS3SessionForBookmark(final Host bookmark) throws BackgroundException { + final S3Session storage = new S3Session(bookmark); + storage.open(ProxyFactory.get(), new DisabledHostKeyCallback(), new DisabledLoginCallback(), new DisabledCancelCallback()); + storage.login(new DisabledLoginCallback() { + @Override + public Credentials prompt(final Host bookmark, final String username, final String title, final String reason, + final LoginOptions options) { + return storage.getHost().getCredentials(); + } + }, + new DisabledCancelCallback()); + return storage; + } + + private static byte @NotNull [] writeRandomFile(final Session session, final Path file, int size) throws BackgroundException, IOException { + final byte[] content = RandomUtils.nextBytes(size); + final TransferStatus transferStatus = new TransferStatus().setLength(content.length); + transferStatus.setChecksum(session.getFeature(Write.class).checksum(file, transferStatus).compute(new ByteArrayInputStream(content), transferStatus)); + session.getFeature(Bulk.class).pre(Transfer.Type.upload, Collections.singletonMap(new TransferItem(file), transferStatus), new DisabledConnectionCallback()); + final StatusOutputStream out = session.getFeature(Write.class).write(file, transferStatus, new DisabledConnectionCallback()); + IOUtils.copyLarge(new ByteArrayInputStream(content), out); + out.close(); + return content; + } + + private static String readFile(final Session session, final Path file) throws IOException, BackgroundException { + final Read read = session.getFeature(Read.class); + try(final InputStream in = read.read(file, new TransferStatus().setLength(file.attributes().getSize()), new DisabledConnectionCallback())) { + return IOUtils.toString(in, StandardCharsets.UTF_8); + } + } +} diff --git a/s3/src/test/resources/uvf/docker-compose.yml b/s3/src/test/resources/uvf/docker-compose.yml new file mode 100644 index 00000000000..e739b4218cf --- /dev/null +++ b/s3/src/test/resources/uvf/docker-compose.yml @@ -0,0 +1,44 @@ +version: '3' + +services: + minio: + hostname: minio + image: minio/minio:latest + restart: on-failure + ports: + - "${MINIO_PORT}:${MINIO_PORT}" + - "${MINIO_CONSOLE_PORT}:${MINIO_CONSOLE_PORT}" + environment: + MINIO_ROOT_USER: minioadmin + MINIO_ROOT_PASSWORD: minioadmin + healthcheck: + test: [ "CMD", "bash", "-c", "curl -v --fail 127.0.0.1:${MINIO_PORT}/minio/health/ready" ] + interval: 5s + timeout: 1s + retries: 5 + command: server /data --console-address :9001 +# networks: +# - testContainerNetwork +# +# minio_setup: +# image: minio/mc:latest +# depends_on: +# minio: +# condition: service_healthy +# entrypoint: [ "/bin/sh","-c" ] +# command: +# - | +# set -x +# set -e +# /usr/bin/mc config host add myminio http://minio:${MINIO_PORT} minioadmin minioadmin +# +# # if container is restarted, the bucket already exists... +# /usr/bin/mc mb myminio/cyberduckbucket --with-versioning || true +# /usr/bin/mc rm --recursive --force myminio/cyberduckbucket +# +# echo "createbuckets successful" +# networks: +# - testContainerNetwork +# +#networks: +# testContainerNetwork: \ No newline at end of file diff --git a/s3/src/test/resources/uvf/first_vault/d/6L/HPWBEU3OJP2EZUCP4CV3HHL47BXVEX/5qTOPMA1BouBRhz_G7qfmKety92geI4=.uvf b/s3/src/test/resources/uvf/first_vault/d/6L/HPWBEU3OJP2EZUCP4CV3HHL47BXVEX/5qTOPMA1BouBRhz_G7qfmKety92geI4=.uvf new file mode 100644 index 0000000000000000000000000000000000000000..9df3310ef3fd4eaf10b822ba6d092d66f23b2bda GIT binary patch literal 105 zcmV-v0G9uCc4h!T8wnPgdJf(12P_XRpfW{f4R^CvNP`jNB{59313GMA;}3<$1g&l{ zbMpdCq&VnU;mA7lNw}2fiD8;@P@-nwR#Vq=C=W{tc*{uo6KN3tQV z%>oD10v|3}HX4VCxciG$HaC}tdSpFPF}UCG48uPBe8Z=KpCeCcCJ-Jsz&Ugy46>Q@ iK#|St7N=W`BD7s;bE;X!%$qtVrjtEjr8x@~iHe*_05-4y literal 0 HcmV?d00001 diff --git a/s3/src/test/resources/uvf/first_vault/d/RZ/K7ZH7KBXULNEKBMGX3CU42PGUIAIX4/GsMMTRvsuuP_6NjgRwopmWcuof-PyRQ=.uvf b/s3/src/test/resources/uvf/first_vault/d/RZ/K7ZH7KBXULNEKBMGX3CU42PGUIAIX4/GsMMTRvsuuP_6NjgRwopmWcuof-PyRQ=.uvf new file mode 100644 index 0000000000000000000000000000000000000000..d7fdea3faa41e9481f94c744f906cd22e832ab56 GIT binary patch literal 105 zcmV-v0G9uCc4h!T8wnQtDz3w1$M7%i6zmCzT0}|Ip*VX7BL!%F>~G-+c?7rAGmzMI--xzgVdqMQ9UgH literal 0 HcmV?d00001 diff --git a/s3/src/test/resources/uvf/first_vault/d/RZ/K7ZH7KBXULNEKBMGX3CU42PGUIAIX4/rExOms183v5evFwgIKiW0qvbsor1Hg==.uvf/dir.uvf b/s3/src/test/resources/uvf/first_vault/d/RZ/K7ZH7KBXULNEKBMGX3CU42PGUIAIX4/rExOms183v5evFwgIKiW0qvbsor1Hg==.uvf/dir.uvf new file mode 100644 index 0000000000000000000000000000000000000000..84ec139b177578a8cd5b4f7d01cb84185ef5915d GIT binary patch literal 128 zcmV-`0Du2=c4h!T8wnOI)_tFPMz8x_f;c71#1>rvwWswOvN2glN?q96NF8 zQ2*Fcied#iI~V?sYZ;6pC#{4qA1E=^T%k#?k4Tb8Ik07sih#K=?3?iIgjT?X%W1i+ iz+M9Fh0KmnAQ)-+D#n9JT=EUu7jX-|QX#C4io4$}DLXO% literal 0 HcmV?d00001 diff --git a/ssh/src/test/java/ch/cyberduck/core/cryptomator/SFTPCryptomatorInteroperabilityTest.java b/ssh/src/test/java/ch/cyberduck/core/cryptomator/SFTPCryptomatorInteroperabilityTest.java index 0dac54678ba..58a14ea9a7d 100644 --- a/ssh/src/test/java/ch/cyberduck/core/cryptomator/SFTPCryptomatorInteroperabilityTest.java +++ b/ssh/src/test/java/ch/cyberduck/core/cryptomator/SFTPCryptomatorInteroperabilityTest.java @@ -54,6 +54,7 @@ import org.cryptomator.cryptolib.api.Masterkey; import org.cryptomator.cryptolib.api.MasterkeyLoader; import org.cryptomator.cryptolib.api.MasterkeyLoadingFailedException; +import org.cryptomator.cryptolib.api.PerpetualMasterkey; import org.cryptomator.cryptolib.common.MasterkeyFileAccess; import org.cryptomator.cryptolib.common.ReseedingSecureRandom; import org.junit.After; @@ -99,7 +100,7 @@ public void startSerer() throws Exception { default: csprng = FastSecureRandomProvider.get().provide(); } - final Masterkey mk = Masterkey.generate(csprng); + final PerpetualMasterkey mk = Masterkey.generate(csprng); final MasterkeyFileAccess mkAccess = new MasterkeyFileAccess(CryptoVault.VAULT_PEPPER, csprng); final java.nio.file.Path mkPath = Paths.get(vault.toString(), DefaultVaultRegistry.DEFAULT_MASTERKEY_FILE_NAME); mkAccess.persist(mk, mkPath, passphrase); From 27f36afbd6595075ba3f3d5fa880e9f849f49737 Mon Sep 17 00:00:00 2001 From: David Kocher Date: Wed, 15 Oct 2025 16:39:18 +0200 Subject: [PATCH 02/12] Add missing exception to method signature. --- .../java/ch/cyberduck/core/cryptomator/AbstractVault.java | 3 ++- .../main/java/ch/cyberduck/core/cryptomator/UVFVault.java | 8 +++----- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/AbstractVault.java b/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/AbstractVault.java index 4228f00040b..e68e2586c45 100644 --- a/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/AbstractVault.java +++ b/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/AbstractVault.java @@ -24,6 +24,7 @@ import ch.cyberduck.core.UrlProvider; import ch.cyberduck.core.cryptomator.features.*; import ch.cyberduck.core.exception.BackgroundException; +import ch.cyberduck.core.exception.UnsupportedException; import ch.cyberduck.core.features.*; import ch.cyberduck.core.preferences.PreferencesFactory; import ch.cyberduck.core.shared.DefaultTouchFeature; @@ -304,7 +305,7 @@ public synchronized void close() { @Override @SuppressWarnings("unchecked") - public T getFeature(final Session session, final Class type, final T delegate) { + public T getFeature(final Session session, final Class type, final T delegate) throws UnsupportedException { if(this.isUnlocked()) { if(type == ListService.class) { return (T) new CryptoListService(session, (ListService) delegate, this); diff --git a/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/UVFVault.java b/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/UVFVault.java index 7d3f6c10894..7ad08be4cec 100644 --- a/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/UVFVault.java +++ b/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/UVFVault.java @@ -28,6 +28,7 @@ import ch.cyberduck.core.cryptomator.impl.CryptoFilenameV7Provider; import ch.cyberduck.core.cryptomator.random.FastSecureRandomProvider; import ch.cyberduck.core.exception.BackgroundException; +import ch.cyberduck.core.exception.UnsupportedException; import ch.cyberduck.core.features.Directory; import ch.cyberduck.core.vault.VaultCredentials; @@ -365,13 +366,10 @@ public byte[] getRootDirId() { } @Override - public T getFeature(final Session session, final Class type, final T delegate) { - + public T getFeature(final Session session, final Class type, final T delegate) throws UnsupportedException { if(type == Directory.class) { - return (T) new CryptoDirectoryUVFFeature(session, (Directory) delegate, this - ); + return (T) new CryptoDirectoryUVFFeature(session, (Directory) delegate, this); } - return super.getFeature(session, type, delegate); } From 430e19d6efa013957a567f2a003c40378794dc56 Mon Sep 17 00:00:00 2001 From: David Kocher Date: Thu, 16 Oct 2025 11:20:52 +0200 Subject: [PATCH 03/12] Allow override of destruction. --- .../java/ch/cyberduck/core/ExpiringObjectHolder.java | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/core/src/main/java/ch/cyberduck/core/ExpiringObjectHolder.java b/core/src/main/java/ch/cyberduck/core/ExpiringObjectHolder.java index 1a2b1aa52e3..6a7634caf49 100644 --- a/core/src/main/java/ch/cyberduck/core/ExpiringObjectHolder.java +++ b/core/src/main/java/ch/cyberduck/core/ExpiringObjectHolder.java @@ -40,6 +40,15 @@ public T get() { return object; } log.warn("Expired object {}", object); + return this.expire(); + } + + public T expire() { + this.destroy(object); return object = null; } + + protected void destroy(final Object object) { + // + } } From 1fa90873156ab1c9d725cb53f3d33da2ad4b732c Mon Sep 17 00:00:00 2001 From: David Kocher Date: Fri, 17 Oct 2025 16:56:37 +0200 Subject: [PATCH 04/12] Adopt interface changes. --- .../java/ch/cyberduck/core/cryptomator/UVFIntegrationTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/s3/src/test/java/ch/cyberduck/core/cryptomator/UVFIntegrationTest.java b/s3/src/test/java/ch/cyberduck/core/cryptomator/UVFIntegrationTest.java index c4fd45bba1e..89b14e95921 100644 --- a/s3/src/test/java/ch/cyberduck/core/cryptomator/UVFIntegrationTest.java +++ b/s3/src/test/java/ch/cyberduck/core/cryptomator/UVFIntegrationTest.java @@ -139,7 +139,7 @@ public void listMinio() throws BackgroundException, IOException { vaults.add(vault.load(storage, new DisabledPasswordCallback() { @Override public Credentials prompt(final Host bookmark, final String title, final String reason, final LoginOptions options) { - return new Credentials().withPassword(jwe); + return new Credentials().setPassword(jwe); } })); final PathAttributes attr = storage.getFeature(AttributesFinder.class).find(vault.getHome()); From e40c2fcb3392b62b22af0c8e6c9e1616b0ad6eb9 Mon Sep 17 00:00:00 2001 From: Yves Langisch Date: Fri, 29 Aug 2025 11:28:04 +0200 Subject: [PATCH 05/12] Generalize and use crypto library interfaces where possible. --- .../core/azure/AbstractAzureTest.java | 6 +- .../AzureDirectoryFeatureTest.java | 19 +- .../cryptomator/AzureListServiceTest.java | 8 +- .../cryptomator/AzureMoveFeatureTest.java | 7 +- .../cryptomator/AzureTouchFeatureTest.java | 21 +- .../cryptomator/AzureWriteFeatureTest.java | 7 +- .../core/cryptomator/CopyWorkerTest.java | 38 +- .../CryptoAzureSingleTransferWorkerTest.java | 6 +- .../ch/cyberduck/core/b2/AbstractB2Test.java | 6 +- .../cryptomator/B2DirectoryFeatureTest.java | 17 +- .../cryptomator/B2LargeUploadServiceTest.java | 13 +- .../B2LargeUploadWriteFeatureTest.java | 7 +- .../core/cryptomator/B2ListServiceTest.java | 7 +- .../core/cryptomator/B2TouchFeatureTest.java | 21 +- .../core/cryptomator/B2WriteFeatureTest.java | 7 +- .../core/cryptomator/CopyWorkerTest.java | 37 +- .../CryptoB2SingleTransferWorkerTest.java | 5 +- .../core/cryptomator/MoveWorkerTest.java | 17 +- .../cyberduck/core/box/AbstractBoxTest.java | 6 +- .../BoxThresholdUploadServiceTest.java | 5 +- .../core/cryptomator/BoxWriteFeatureTest.java | 9 +- .../cryptomator/BufferWriteFeatureTest.java | 5 +- .../core/brick/BrickCopyFeature.java | 2 +- .../core/brick/BrickMoveFeature.java | 2 +- .../core/brick/AbstractBrickTest.java | 6 +- .../cryptomator/BrickListServiceTest.java | 8 +- .../cryptomator/DefaultTouchFeatureTest.java | 21 +- .../main/java/ch/cyberduck/cli/Terminal.java | 3 +- .../ch/cyberduck/cli/TerminalPreferences.java | 5 +- .../ch/cyberduck/core/PathAttributes.java | 26 + .../ch/cyberduck/core/features/Vault.java | 5 +- .../serializer/PathAttributesDictionary.java | 5 + .../core/vault/DefaultVaultRegistry.java | 25 +- .../cyberduck/core/vault/DisabledVault.java | 6 +- .../vault/DisabledVaultLookupListener.java | 5 +- .../core/vault/DisabledVaultProvider.java | 50 ++ .../vault/LoadingVaultLookupListener.java | 16 +- .../VaultFinderListProgressListener.java | 16 +- .../core/vault/VaultLookupListener.java | 3 +- .../cyberduck/core/vault/VaultMetadata.java | 87 ++++ .../core/vault/VaultMetadataDictionary.java | 47 ++ .../cyberduck/core/vault/VaultProvider.java | 37 ++ .../core/vault/VaultProviderFactory.java | 55 +++ .../registry/VaultRegistryFindFeature.java | 15 +- .../core/worker/CreateVaultWorker.java | 26 +- .../core/worker/LoadVaultWorker.java | 21 +- .../core/cryptomator/AbstractVault.java | 91 ++-- .../core/cryptomator/CryptoDirectory.java | 6 +- .../cryptomator/CryptoTransferStatus.java | 2 +- .../core/cryptomator/CryptoVaultProvider.java | 107 +++++ .../features/CryptoAttributesFeature.java | 2 +- .../features/CryptoBulkFeature.java | 1 + .../features/CryptoDeleteV6Feature.java | 142 ------ .../features/CryptoDeleteV7Feature.java | 4 +- .../features/CryptoDirectoryUVFFeature.java | 26 +- .../features/CryptoDirectoryV6Feature.java | 93 ---- .../features/CryptoDirectoryV7Feature.java | 8 +- .../features/CryptoMoveV6Feature.java | 92 ---- .../impl/CryptoDirectoryUVFProvider.java | 133 +----- .../impl/CryptoDirectoryV7Provider.java | 77 --- ...er.java => CryptoDirectoryV8Provider.java} | 102 ++-- .../impl/CryptoFilenameV6Provider.java | 131 ----- .../uvf/CryptoVault.java} | 186 ++------ .../{ => impl/v8}/CryptoVault.java | 449 ++++++++---------- .../CryptoChecksumComputeTest.java | 2 +- .../cryptomator/CryptoOutputStreamTest.java | 1 + .../cryptomator/CryptoWriteFeatureTest.java | 40 +- .../features/CryptoBulkFeatureTest.java | 2 +- .../features/CryptoReadFeatureTest.java | 10 +- .../impl/CryptoDirectoryV6ProviderTest.java | 72 --- .../impl/CryptoDirectoryV7ProviderTest.java | 73 --- .../impl/CryptoDirectoryV8ProviderTest.java | 121 +++++ .../{ => impl/v8}/CryptoVaultTest.java | 72 +-- .../src/main/resources/default.properties | 3 +- defaults/src/main/resources/default/log4j.xml | 13 +- .../cyberduck/core/AbstractDropboxTest.java | 6 +- .../core/cryptomator/CopyWorkerTest.java | 38 +- ...CryptoDropboxSingleTransferWorkerTest.java | 5 +- .../DropboxDirectoryFeatureTest.java | 13 +- .../cryptomator/DropboxListServiceTest.java | 5 +- .../cryptomator/DropboxMoveFeatureTest.java | 5 +- .../cryptomator/DropboxTouchFeatureTest.java | 16 +- .../cryptomator/DropboxWriteFeatureTest.java | 5 +- .../core/cryptomator/MoveWorkerTest.java | 38 +- .../EueSingleUploadServiceTest.java | 102 ---- .../EueThresholdUploadServiceTest.java | 145 ------ .../cryptomator/EueUploadServiceTest.java | 145 ------ .../core/cryptomator/EueWriteFeatureTest.java | 97 ---- .../core/eue/AbstractEueSessionTest.java | 4 +- .../ch/cyberduck/core/ftp/FTPMoveFeature.java | 2 +- .../core/cryptomator/CopyWorkerTest.java | 37 +- .../CryptoFTPSingleTransferWorkerTest.java | 5 +- .../cryptomator/FTPDirectoryFeatureTest.java | 13 +- .../core/cryptomator/FTPListServiceTest.java | 5 +- .../core/cryptomator/FTPMoveFeatureTest.java | 5 +- .../core/cryptomator/FTPTouchFeatureTest.java | 19 +- .../core/cryptomator/FTPWriteFeatureTest.java | 5 +- .../core/cryptomator/MoveWorkerTest.java | 37 +- .../cyberduck/core/ftp/AbstractFTPTest.java | 6 +- .../core/cryptomator/CopyWorkerTest.java | 38 +- .../CryptoDriveTransferWorkerTest.java | 5 +- .../DriveAttributesFinderFeatureTest.java | 25 +- .../DriveDirectoryFeatureTest.java | 18 +- .../cryptomator/DriveListServiceTest.java | 7 +- .../cryptomator/DriveMoveFeatureTest.java | 7 +- .../cryptomator/DriveTouchFeatureTest.java | 26 +- .../cryptomator/DriveWriteFeatureTest.java | 11 +- .../core/cryptomator/MoveWorkerTest.java | 54 ++- .../core/googledrive/AbstractDriveTest.java | 6 +- .../GoogleStorageListServiceTest.java | 10 +- .../AbstractGoogleStorageTest.java | 6 +- i18n/src/main/resources/en.lproj/Bookmark.xib | 293 +++++++----- i18n/src/main/resources/en.lproj/Prompt.xib | 52 +- .../core/manta/MantaMoveFeature.java | 2 +- .../CryptoLocalSingleTransferWorkerTest.java | 11 +- .../core/cryptomator/CopyWorkerTest.java | 37 +- ...ryptoOneDriveSingleTransferWorkerTest.java | 5 +- .../GraphDirectoryFeatureTest.java | 13 +- .../cryptomator/GraphMoveFeatureTest.java | 5 +- .../cryptomator/GraphTouchFeatureTest.java | 15 +- .../cryptomator/GraphWriteFeatureTest.java | 5 +- .../core/cryptomator/MoveWorkerTest.java | 38 +- .../cryptomator/OneDriveListServiceTest.java | 5 +- .../core/onedrive/AbstractOneDriveTest.java | 6 +- .../core/cryptomator/CopyWorkerTest.java | 37 +- .../CryptoSwiftSingleTransferWorkerTest.java | 5 +- .../SwiftDirectoryFeatureTest.java | 13 +- .../SwiftLargeObjectUploadFeatureTest.java | 5 +- .../SwiftLargeUploadWriteFeatureTest.java | 5 +- .../cryptomator/SwiftListServiceTest.java | 5 +- .../cryptomator/SwiftMoveFeatureTest.java | 5 +- .../cryptomator/SwiftTouchFeatureTest.java | 17 +- .../cryptomator/SwiftWriteFeatureTest.java | 5 +- .../core/openstack/AbstractSwiftTest.java | 8 +- .../ApplicationUserDefaultsPreferences.java | 4 +- .../cocoa/controller/BrowserController.java | 19 +- .../toolbar/BrowserToolbarValidator.java | 2 +- .../cryptomator/OcisUploadFeatureTest.java | 7 +- .../core/owncloud/AbstractOcisTest.java | 6 +- .../core/cryptomator/CopyWorkerTest.java | 39 +- .../CryptoS3SingleTransferWorkerTest.java | 5 +- .../core/cryptomator/MoveWorkerTest.java | 37 +- .../cryptomator/S3DirectoryFeatureTest.java | 13 +- .../core/cryptomator/S3MoveFeatureTest.java | 5 +- .../S3MultipartUploadServiceTest.java | 13 +- .../S3MultipartWriteFeatureTest.java | 5 +- .../cryptomator/S3ObjectListServiceTest.java | 5 +- .../S3SingleUploadServiceTest.java | 5 +- .../core/cryptomator/S3TouchFeatureTest.java | 16 +- .../cryptomator/S3VersioningFeatureTest.java | 5 +- .../core/cryptomator/S3WriteFeatureTest.java | 5 +- .../core/cryptomator/UVFIntegrationTest.java | 7 +- .../ch/cyberduck/core/s3/AbstractS3Test.java | 6 +- .../cyberduck/core/sftp/SFTPMoveFeature.java | 2 +- .../core/cryptomator/CopyWorkerTest.java | 37 +- .../CryptoSFTPSingleTransferWorkerTest.java | 9 +- .../cryptomator/DefaultTouchFeatureTest.java | 5 +- .../core/cryptomator/MoveWorkerTest.java | 37 +- .../SFTPAttributesFinderFeatureTest.java | 15 +- .../SFTPCryptomatorInteroperabilityTest.java | 19 +- .../cryptomator/SFTPDirectoryFeatureTest.java | 13 +- .../core/cryptomator/SFTPFindFeatureTest.java | 13 +- .../core/cryptomator/SFTPListServiceTest.java | 5 +- .../core/cryptomator/SFTPMoveFeatureTest.java | 29 +- .../core/cryptomator/SFTPReadFeatureTest.java | 5 +- .../cryptomator/SFTPSymlinkFeatureTest.java | 9 +- .../cryptomator/SFTPWriteFeatureTest.java | 9 +- .../cyberduck/core/sftp/AbstractSFTPTest.java | 6 +- .../ch/cyberduck/core/dav/DAVMoveFeature.java | 2 +- .../core/cryptomator/CopyWorkerTest.java | 38 +- .../CryptoDAVSingleTransferWorkerTest.java | 15 +- .../cryptomator/DAVDirectoryFeatureTest.java | 13 +- .../core/cryptomator/DAVListServiceTest.java | 5 +- .../core/cryptomator/DAVMoveFeatureTest.java | 5 +- .../core/cryptomator/DAVReadFeatureTest.java | 5 +- .../core/cryptomator/DAVTouchFeatureTest.java | 21 +- .../core/cryptomator/DAVWriteFeatureTest.java | 10 +- .../cyberduck/core/dav/AbstractDAVTest.java | 6 +- .../dav/DAVAttributesFinderFeatureTest.java | 8 +- .../ui/controller/BrowserController.cs | 6 +- 180 files changed, 2082 insertions(+), 2859 deletions(-) create mode 100644 core/src/main/java/ch/cyberduck/core/vault/DisabledVaultProvider.java create mode 100644 core/src/main/java/ch/cyberduck/core/vault/VaultMetadata.java create mode 100644 core/src/main/java/ch/cyberduck/core/vault/VaultMetadataDictionary.java create mode 100644 core/src/main/java/ch/cyberduck/core/vault/VaultProvider.java create mode 100644 core/src/main/java/ch/cyberduck/core/vault/VaultProviderFactory.java create mode 100644 cryptomator/src/main/java/ch/cyberduck/core/cryptomator/CryptoVaultProvider.java delete mode 100644 cryptomator/src/main/java/ch/cyberduck/core/cryptomator/features/CryptoDeleteV6Feature.java delete mode 100644 cryptomator/src/main/java/ch/cyberduck/core/cryptomator/features/CryptoDirectoryV6Feature.java delete mode 100644 cryptomator/src/main/java/ch/cyberduck/core/cryptomator/features/CryptoMoveV6Feature.java delete mode 100644 cryptomator/src/main/java/ch/cyberduck/core/cryptomator/impl/CryptoDirectoryV7Provider.java rename cryptomator/src/main/java/ch/cyberduck/core/cryptomator/impl/{CryptoDirectoryV6Provider.java => CryptoDirectoryV8Provider.java} (59%) delete mode 100644 cryptomator/src/main/java/ch/cyberduck/core/cryptomator/impl/CryptoFilenameV6Provider.java rename cryptomator/src/main/java/ch/cyberduck/core/cryptomator/{UVFVault.java => impl/uvf/CryptoVault.java} (52%) rename cryptomator/src/main/java/ch/cyberduck/core/cryptomator/{ => impl/v8}/CryptoVault.java (69%) delete mode 100644 cryptomator/src/test/java/ch/cyberduck/core/cryptomator/impl/CryptoDirectoryV6ProviderTest.java delete mode 100644 cryptomator/src/test/java/ch/cyberduck/core/cryptomator/impl/CryptoDirectoryV7ProviderTest.java create mode 100644 cryptomator/src/test/java/ch/cyberduck/core/cryptomator/impl/CryptoDirectoryV8ProviderTest.java rename cryptomator/src/test/java/ch/cyberduck/core/cryptomator/{ => impl/v8}/CryptoVaultTest.java (90%) delete mode 100644 eue/src/test/java/ch/cyberduck/core/cryptomator/EueSingleUploadServiceTest.java delete mode 100644 eue/src/test/java/ch/cyberduck/core/cryptomator/EueThresholdUploadServiceTest.java delete mode 100644 eue/src/test/java/ch/cyberduck/core/cryptomator/EueUploadServiceTest.java delete mode 100644 eue/src/test/java/ch/cyberduck/core/cryptomator/EueWriteFeatureTest.java diff --git a/azure/src/test/java/ch/cyberduck/core/azure/AbstractAzureTest.java b/azure/src/test/java/ch/cyberduck/core/azure/AbstractAzureTest.java index cd7876e88ee..9e8af2507f4 100644 --- a/azure/src/test/java/ch/cyberduck/core/azure/AbstractAzureTest.java +++ b/azure/src/test/java/ch/cyberduck/core/azure/AbstractAzureTest.java @@ -21,7 +21,7 @@ import ch.cyberduck.core.DisabledProgressListener; import ch.cyberduck.core.Host; import ch.cyberduck.core.LoginConnectionService; -import ch.cyberduck.core.cryptomator.CryptoVault; +import ch.cyberduck.core.vault.VaultMetadata; import ch.cyberduck.test.VaultTest; import org.junit.After; @@ -34,11 +34,11 @@ public class AbstractAzureTest extends VaultTest { @Parameterized.Parameters(name = "vaultVersion = {0}") public static Object[] data() { - return new Object[]{CryptoVault.VAULT_VERSION_DEPRECATED, CryptoVault.VAULT_VERSION}; + return new Object[]{VaultMetadata.Type.V8, VaultMetadata.Type.UVF}; } @Parameterized.Parameter - public int vaultVersion; + public VaultMetadata.Type vaultVersion; @After public void disconnect() throws Exception { diff --git a/azure/src/test/java/ch/cyberduck/core/cryptomator/AzureDirectoryFeatureTest.java b/azure/src/test/java/ch/cyberduck/core/cryptomator/AzureDirectoryFeatureTest.java index 72f478660b3..eac1c2205c0 100644 --- a/azure/src/test/java/ch/cyberduck/core/cryptomator/AzureDirectoryFeatureTest.java +++ b/azure/src/test/java/ch/cyberduck/core/cryptomator/AzureDirectoryFeatureTest.java @@ -31,8 +31,10 @@ import ch.cyberduck.core.transfer.TransferStatus; import ch.cyberduck.core.vault.DefaultVaultRegistry; import ch.cyberduck.core.vault.VaultCredentials; +import ch.cyberduck.core.vault.VaultMetadata; import ch.cyberduck.test.IntegrationTest; +import org.junit.Ignore; import org.junit.Test; import org.junit.experimental.categories.Category; import org.junit.runner.RunWith; @@ -42,7 +44,6 @@ import java.util.EnumSet; import static org.junit.Assert.assertTrue; -import static org.junit.Assume.assumeTrue; @Category(IntegrationTest.class) @RunWith(value = Parameterized.class) @@ -51,9 +52,9 @@ public class AzureDirectoryFeatureTest extends AbstractAzureTest { @Test public void testMakeDirectoryEncrypted() throws Exception { final Path home = new Path("cyberduck", EnumSet.of(Path.Type.directory, Path.Type.volume)); - final CryptoVault cryptomator = new CryptoVault( - new Path(home, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory))); - final Path vault = cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final Path vault = new Path(home, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); session.withRegistry(new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator)); final Path test = cryptomator.getFeature(session, Directory.class, new AzureDirectoryFeature(session)).mkdir( cryptomator.getFeature(session, Write.class, new AzureWriteFeature(session)), new Path(vault, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)), new TransferStatus()); @@ -62,13 +63,15 @@ public void testMakeDirectoryEncrypted() throws Exception { cryptomator.getFeature(session, Delete.class, new AzureDeleteFeature(session)).delete(Arrays.asList(test, vault), new DisabledLoginCallback(), new Delete.DisabledCallback()); } + + //TODO enable @Test + @Ignore(value = "Filename shortening not yet implemented") public void testMakeDirectoryLongFilenameEncrypted() throws Exception { - assumeTrue(vaultVersion == CryptoVault.VAULT_VERSION_DEPRECATED); final Path home = new Path("cyberduck", EnumSet.of(Path.Type.directory, Path.Type.volume)); - final CryptoVault cryptomator = new CryptoVault( - new Path(home, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory))); - final Path vault = cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final Path vault = new Path(home, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); session.withRegistry(new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator)); final Path test = cryptomator.getFeature(session, Directory.class, new AzureDirectoryFeature(session)).mkdir( cryptomator.getFeature(session, Write.class, new AzureWriteFeature(session)), new Path(vault, new AlphanumericRandomStringService(130).random(), EnumSet.of(Path.Type.directory)), new TransferStatus()); diff --git a/azure/src/test/java/ch/cyberduck/core/cryptomator/AzureListServiceTest.java b/azure/src/test/java/ch/cyberduck/core/cryptomator/AzureListServiceTest.java index 174e34b2600..994d385f037 100644 --- a/azure/src/test/java/ch/cyberduck/core/cryptomator/AzureListServiceTest.java +++ b/azure/src/test/java/ch/cyberduck/core/cryptomator/AzureListServiceTest.java @@ -27,11 +27,13 @@ import ch.cyberduck.core.cryptomator.features.CryptoListService; import ch.cyberduck.core.cryptomator.features.CryptoTouchFeature; import ch.cyberduck.core.cryptomator.features.CryptoWriteFeature; +import ch.cyberduck.core.cryptomator.features.CryptoWriteFeature; import ch.cyberduck.core.features.Delete; import ch.cyberduck.core.shared.DefaultTouchFeature; import ch.cyberduck.core.transfer.TransferStatus; import ch.cyberduck.core.vault.DefaultVaultRegistry; import ch.cyberduck.core.vault.VaultCredentials; +import ch.cyberduck.core.vault.VaultMetadata; import ch.cyberduck.test.IntegrationTest; import org.junit.Test; @@ -52,9 +54,9 @@ public class AzureListServiceTest extends AbstractAzureTest { @Test public void testListCryptomator() throws Exception { final Path home = new Path("cyberduck", EnumSet.of(Path.Type.directory, Path.Type.volume)); - final CryptoVault cryptomator = new CryptoVault( - new Path(home, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory))); - final Path vault = cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final Path vault = new Path(home, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(new Path(home, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)), vaultVersion)); session.withRegistry(new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator)); final Path test = new Path(vault, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.file)); assertTrue(new CryptoListService(session, new AzureObjectListService(session), cryptomator).list(vault, new DisabledListProgressListener()).isEmpty()); diff --git a/azure/src/test/java/ch/cyberduck/core/cryptomator/AzureMoveFeatureTest.java b/azure/src/test/java/ch/cyberduck/core/cryptomator/AzureMoveFeatureTest.java index 3aa606d75fc..35a553bdf02 100644 --- a/azure/src/test/java/ch/cyberduck/core/cryptomator/AzureMoveFeatureTest.java +++ b/azure/src/test/java/ch/cyberduck/core/cryptomator/AzureMoveFeatureTest.java @@ -38,6 +38,7 @@ import ch.cyberduck.core.transfer.TransferStatus; import ch.cyberduck.core.vault.DefaultVaultRegistry; import ch.cyberduck.core.vault.VaultCredentials; +import ch.cyberduck.core.vault.VaultMetadata; import ch.cyberduck.test.IntegrationTest; import org.junit.Test; @@ -58,9 +59,9 @@ public class AzureMoveFeatureTest extends AbstractAzureTest { @Test public void testMove() throws Exception { final Path home = new Path("cyberduck", EnumSet.of(Path.Type.directory, Path.Type.volume)); - final CryptoVault cryptomator = new CryptoVault( - new Path(home, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory))); - final Path vault = cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final Path vault = new Path(home, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); session.withRegistry(new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator)); final Path folder = cryptomator.getFeature(session, Directory.class, new AzureDirectoryFeature(session)).mkdir( cryptomator.getFeature(session, Write.class, new AzureWriteFeature(session)), new Path(vault, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)), new TransferStatus()); diff --git a/azure/src/test/java/ch/cyberduck/core/cryptomator/AzureTouchFeatureTest.java b/azure/src/test/java/ch/cyberduck/core/cryptomator/AzureTouchFeatureTest.java index b8a257cd4df..a6952a94854 100644 --- a/azure/src/test/java/ch/cyberduck/core/cryptomator/AzureTouchFeatureTest.java +++ b/azure/src/test/java/ch/cyberduck/core/cryptomator/AzureTouchFeatureTest.java @@ -32,8 +32,10 @@ import ch.cyberduck.core.transfer.TransferStatus; import ch.cyberduck.core.vault.DefaultVaultRegistry; import ch.cyberduck.core.vault.VaultCredentials; +import ch.cyberduck.core.vault.VaultMetadata; import ch.cyberduck.test.IntegrationTest; +import org.junit.Ignore; import org.junit.Test; import org.junit.experimental.categories.Category; import org.junit.runner.RunWith; @@ -44,19 +46,20 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; -import static org.junit.Assume.assumeTrue; @Category(IntegrationTest.class) @RunWith(value = Parameterized.class) public class AzureTouchFeatureTest extends AbstractAzureTest { + //TODO + @Test + @Ignore(value = "Filename shortening not yet implemented") public void testTouchLongFilenameEncrypted() throws Exception { - assumeTrue(vaultVersion == CryptoVault.VAULT_VERSION_DEPRECATED); final Path home = new Path("cyberduck", EnumSet.of(Path.Type.volume, Path.Type.directory)); - final CryptoVault cryptomator = new CryptoVault( - new Path(home, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory))); - final Path vault = cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final Path vault = new Path(home, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); session.withRegistry(new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator)); final TransferStatus status = new TransferStatus(); final Path test = new CryptoTouchFeature<>(session, new AzureTouchFeature(session), cryptomator).touch( @@ -68,12 +71,12 @@ public void testTouchLongFilenameEncrypted() throws Exception { } @Test + @Ignore(value = "Filename shortening not yet implemented") public void testTouchLongFilenameEncryptedDefaultFeature() throws Exception { - assumeTrue(vaultVersion == CryptoVault.VAULT_VERSION_DEPRECATED); final Path home = new Path("cyberduck", EnumSet.of(Path.Type.volume, Path.Type.directory)); - final CryptoVault cryptomator = new CryptoVault( - new Path(home, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory))); - final Path vault = cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final Path vault = new Path(home, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); session.withRegistry(new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator)); final TransferStatus status = new TransferStatus(); final Path test = new CryptoTouchFeature<>(session, new AzureTouchFeature(session), cryptomator).touch( diff --git a/azure/src/test/java/ch/cyberduck/core/cryptomator/AzureWriteFeatureTest.java b/azure/src/test/java/ch/cyberduck/core/cryptomator/AzureWriteFeatureTest.java index a11d3355b97..11c66b56332 100644 --- a/azure/src/test/java/ch/cyberduck/core/cryptomator/AzureWriteFeatureTest.java +++ b/azure/src/test/java/ch/cyberduck/core/cryptomator/AzureWriteFeatureTest.java @@ -38,6 +38,7 @@ import ch.cyberduck.core.transfer.TransferStatus; import ch.cyberduck.core.vault.DefaultVaultRegistry; import ch.cyberduck.core.vault.VaultCredentials; +import ch.cyberduck.core.vault.VaultMetadata; import ch.cyberduck.test.IntegrationTest; import org.apache.commons.lang3.RandomUtils; @@ -66,9 +67,9 @@ public void testWrite() throws Exception { final byte[] content = RandomUtils.nextBytes(1048576); status.setLength(content.length); final Path home = new Path("cyberduck", EnumSet.of(Path.Type.volume, Path.Type.directory)); - final CryptoVault cryptomator = new CryptoVault( - new Path(home, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory))); - final Path vault = cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final Path vault = new Path(home, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); session.withRegistry(new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator)); final CryptoWriteFeature writer = new CryptoWriteFeature<>(session, new AzureWriteFeature(session), cryptomator); final FileHeader header = cryptomator.getFileHeaderCryptor().create(); diff --git a/azure/src/test/java/ch/cyberduck/core/cryptomator/CopyWorkerTest.java b/azure/src/test/java/ch/cyberduck/core/cryptomator/CopyWorkerTest.java index 1e3bc02b566..459a0c75a3b 100644 --- a/azure/src/test/java/ch/cyberduck/core/cryptomator/CopyWorkerTest.java +++ b/azure/src/test/java/ch/cyberduck/core/cryptomator/CopyWorkerTest.java @@ -47,12 +47,14 @@ import ch.cyberduck.core.transfer.TransferStatus; import ch.cyberduck.core.vault.DefaultVaultRegistry; import ch.cyberduck.core.vault.VaultCredentials; +import ch.cyberduck.core.vault.VaultMetadata; import ch.cyberduck.core.worker.CopyWorker; import ch.cyberduck.core.worker.DeleteWorker; import ch.cyberduck.test.IntegrationTest; import org.apache.commons.io.IOUtils; import org.apache.commons.lang3.RandomUtils; +import org.junit.Ignore; import org.junit.Test; import org.junit.experimental.categories.Category; import org.junit.runner.RunWith; @@ -76,8 +78,8 @@ public void testCopyFile() throws Exception { final Path vault = new Path(home, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); final Path source = new Path(vault, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.file)); final Path target = new Path(vault, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.file)); - final CryptoVault cryptomator = new CryptoVault(vault); - cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); final DefaultVaultRegistry registry = new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator); session.withRegistry(registry); final byte[] content = RandomUtils.nextBytes(40500); @@ -102,8 +104,8 @@ public void testCopyToDifferentFolderCryptomator() throws Exception { final Path source = new Path(vault, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.file)); final Path targetFolder = new Path(vault, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); final Path target = new Path(targetFolder, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.file)); - final CryptoVault cryptomator = new CryptoVault(vault); - cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); final DefaultVaultRegistry registry = new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator); session.withRegistry(registry); new CryptoTouchFeature<>(session, new DefaultTouchFeature(session), cryptomator).touch( @@ -120,11 +122,14 @@ public void testCopyToDifferentFolderCryptomator() throws Exception { new DeleteWorker(new DisabledLoginCallback(), Collections.singletonList(vault), new DisabledProgressListener()).run(session); } + //TODO @Test + @Ignore(value = "Filename shortening not yet implemented") public void testCopyToDifferentFolderLongFilenameCryptomator() throws Exception { final Path home = new Path("cyberduck", EnumSet.of(Path.Type.directory, Path.Type.volume)); - final CryptoVault cryptomator = new CryptoVault(new Path(home, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory))); - final Path vault = cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final Path vault = new Path(home, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); final Path source = new Path(vault, new AlphanumericRandomStringService(130).random(), EnumSet.of(Path.Type.file)); final Path targetFolder = new Path(vault, new AlphanumericRandomStringService(130).random(), EnumSet.of(Path.Type.directory)); final Path target = new Path(targetFolder, new AlphanumericRandomStringService(130).random(), EnumSet.of(Path.Type.file)); @@ -147,8 +152,9 @@ public void testCopyToDifferentFolderLongFilenameCryptomator() throws Exception @Test public void testCopyFolder() throws Exception { final Path home = new Path("cyberduck", EnumSet.of(Path.Type.directory, Path.Type.volume)); - final CryptoVault cryptomator = new CryptoVault(new Path(home, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory))); - final Path vault = cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final Path vault = new Path(home, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); final Path folder = new Path(vault, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); final Path file = new Path(folder, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.file)); final DefaultVaultRegistry registry = new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator); @@ -185,8 +191,8 @@ public void testCopyFileIntoVault() throws Exception { assertTrue(new AzureFindFeature(session).find(cleartextFile)); final Path encryptedFolder = new Path(vault, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); final Path encryptedFile = new Path(encryptedFolder, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.file)); - final CryptoVault cryptomator = new CryptoVault(vault); - cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); final DefaultVaultRegistry registry = new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator); session.withRegistry(registry); cryptomator.getFeature(session, Directory.class, new AzureDirectoryFeature(session)).mkdir( @@ -214,8 +220,8 @@ public void testCopyDirectoryIntoVault() throws Exception { new AzureTouchFeature(session).touch(new AzureWriteFeature(session), cleartextFile, new TransferStatus()); assertTrue(new AzureFindFeature(session).find(cleartextFolder)); assertTrue(new AzureFindFeature(session).find(cleartextFile)); - final CryptoVault cryptomator = new CryptoVault(vault); - cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); final DefaultVaultRegistry registry = new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator); session.withRegistry(registry); // move directory into vault @@ -239,8 +245,8 @@ public void testCopyFileOutsideVault() throws Exception { new AzureDirectoryFeature(session).mkdir(new AzureWriteFeature(session), clearFolder, new TransferStatus()); final Path encryptedFolder = new Path(vault, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); final Path encryptedFile = new Path(encryptedFolder, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.file)); - final CryptoVault cryptomator = new CryptoVault(vault); - cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); final DefaultVaultRegistry registry = new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator); session.withRegistry(registry); cryptomator.getFeature(session, Directory.class, new AzureDirectoryFeature(session)).mkdir( @@ -265,8 +271,8 @@ public void testCopyDirectoryOutsideVault() throws Exception { final Path vault = new Path(home, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); final Path encryptedFolder = new Path(vault, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); final Path encryptedFile = new Path(encryptedFolder, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.file)); - final CryptoVault cryptomator = new CryptoVault(vault); - cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); final DefaultVaultRegistry registry = new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator); session.withRegistry(registry); cryptomator.getFeature(session, Directory.class, new AzureDirectoryFeature(session)).mkdir( diff --git a/azure/src/test/java/ch/cyberduck/core/cryptomator/CryptoAzureSingleTransferWorkerTest.java b/azure/src/test/java/ch/cyberduck/core/cryptomator/CryptoAzureSingleTransferWorkerTest.java index 4ac361ed8c5..008e34a8fd6 100644 --- a/azure/src/test/java/ch/cyberduck/core/cryptomator/CryptoAzureSingleTransferWorkerTest.java +++ b/azure/src/test/java/ch/cyberduck/core/cryptomator/CryptoAzureSingleTransferWorkerTest.java @@ -51,6 +51,7 @@ import ch.cyberduck.core.transfer.UploadTransfer; import ch.cyberduck.core.vault.DefaultVaultRegistry; import ch.cyberduck.core.vault.VaultCredentials; +import ch.cyberduck.core.vault.VaultMetadata; import ch.cyberduck.core.worker.SingleTransferWorker; import ch.cyberduck.test.IntegrationTest; @@ -77,8 +78,9 @@ public class CryptoAzureSingleTransferWorkerTest extends AbstractAzureTest { @Test public void testUpload() throws Exception { final Path home = new Path("cyberduck", EnumSet.of(Path.Type.volume, Path.Type.directory)); - final CryptoVault cryptomator = new CryptoVault(new Path(home, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory))); - final Path vault = cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final Path vault = new Path(home, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); session.withRegistry(new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator)); final Path dir1 = new Path(vault, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory, Path.Type.placeholder)); final Local localDirectory1 = new Local(System.getProperty("java.io.tmpdir"), new AlphanumericRandomStringService().random()); diff --git a/backblaze/src/test/java/ch/cyberduck/core/b2/AbstractB2Test.java b/backblaze/src/test/java/ch/cyberduck/core/b2/AbstractB2Test.java index 898fdd7c710..fa8c3f533ed 100644 --- a/backblaze/src/test/java/ch/cyberduck/core/b2/AbstractB2Test.java +++ b/backblaze/src/test/java/ch/cyberduck/core/b2/AbstractB2Test.java @@ -26,10 +26,10 @@ import ch.cyberduck.core.LoginOptions; import ch.cyberduck.core.Profile; import ch.cyberduck.core.ProtocolFactory; -import ch.cyberduck.core.cryptomator.CryptoVault; import ch.cyberduck.core.serializer.impl.dd.ProfilePlistReader; import ch.cyberduck.core.ssl.DefaultX509KeyManager; import ch.cyberduck.core.ssl.DefaultX509TrustManager; +import ch.cyberduck.core.vault.VaultMetadata; import ch.cyberduck.test.VaultTest; import org.junit.After; @@ -47,11 +47,11 @@ public class AbstractB2Test extends VaultTest { @Parameterized.Parameters(name = "vaultVersion = {0}") public static Object[] data() { - return new Object[]{CryptoVault.VAULT_VERSION_DEPRECATED, CryptoVault.VAULT_VERSION}; + return new Object[]{VaultMetadata.Type.V8, VaultMetadata.Type.UVF}; } @Parameterized.Parameter - public int vaultVersion; + public VaultMetadata.Type vaultVersion; @After public void disconnect() throws Exception { diff --git a/backblaze/src/test/java/ch/cyberduck/core/cryptomator/B2DirectoryFeatureTest.java b/backblaze/src/test/java/ch/cyberduck/core/cryptomator/B2DirectoryFeatureTest.java index c3207396c44..5dd9b60c437 100644 --- a/backblaze/src/test/java/ch/cyberduck/core/cryptomator/B2DirectoryFeatureTest.java +++ b/backblaze/src/test/java/ch/cyberduck/core/cryptomator/B2DirectoryFeatureTest.java @@ -39,8 +39,10 @@ import ch.cyberduck.core.transfer.TransferStatus; import ch.cyberduck.core.vault.DefaultVaultRegistry; import ch.cyberduck.core.vault.VaultCredentials; +import ch.cyberduck.core.vault.VaultMetadata; import ch.cyberduck.test.IntegrationTest; +import org.junit.Ignore; import org.junit.Test; import org.junit.experimental.categories.Category; import org.junit.runner.RunWith; @@ -52,7 +54,6 @@ import java.util.stream.Collectors; import static org.junit.Assert.*; -import static org.junit.Assume.assumeTrue; @Category(IntegrationTest.class) @RunWith(value = Parameterized.class) @@ -61,9 +62,9 @@ public class B2DirectoryFeatureTest extends AbstractB2Test { @Test public void testMakeDirectoryEncrypted() throws Exception { final Path home = new Path("/test-cyberduck", EnumSet.of(Path.Type.directory, Path.Type.volume)); - final CryptoVault cryptomator = new CryptoVault( - new Path(home, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory))); - final Path vault = cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final Path vault = new Path(home, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); session.withRegistry(new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator)); final B2VersionIdProvider fileid = new B2VersionIdProvider(session); final Path test = cryptomator.getFeature(session, Directory.class, new B2DirectoryFeature(session, fileid)).mkdir( @@ -82,12 +83,12 @@ public void testMakeDirectoryEncrypted() throws Exception { } @Test + @Ignore("Filename shortening not yet implemented") public void testMakeDirectoryLongFilenameEncrypted() throws Exception { - assumeTrue(vaultVersion == CryptoVault.VAULT_VERSION_DEPRECATED); final Path home = new Path("/test-cyberduck", EnumSet.of(Path.Type.directory, Path.Type.volume)); - final CryptoVault cryptomator = new CryptoVault( - new Path(home, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory))); - final Path vault = cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final Path vault = new Path(home, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); session.withRegistry(new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator)); final B2VersionIdProvider fileid = new B2VersionIdProvider(session); final Path test = cryptomator.getFeature(session, Directory.class, new B2DirectoryFeature(session, fileid)).mkdir( diff --git a/backblaze/src/test/java/ch/cyberduck/core/cryptomator/B2LargeUploadServiceTest.java b/backblaze/src/test/java/ch/cyberduck/core/cryptomator/B2LargeUploadServiceTest.java index 868c5e95afb..197fa82e616 100644 --- a/backblaze/src/test/java/ch/cyberduck/core/cryptomator/B2LargeUploadServiceTest.java +++ b/backblaze/src/test/java/ch/cyberduck/core/cryptomator/B2LargeUploadServiceTest.java @@ -46,6 +46,7 @@ import ch.cyberduck.core.transfer.TransferStatus; import ch.cyberduck.core.vault.DefaultVaultRegistry; import ch.cyberduck.core.vault.VaultCredentials; +import ch.cyberduck.core.vault.VaultMetadata; import ch.cyberduck.test.IntegrationTest; import org.apache.commons.io.IOUtils; @@ -76,9 +77,9 @@ public class B2LargeUploadServiceTest extends AbstractB2Test { public void testWrite() throws Exception { // 5L * 1024L * 1024L final Path home = new Path("/test-cyberduck", EnumSet.of(Path.Type.volume, Path.Type.directory)); - final CryptoVault cryptomator = new CryptoVault( - new Path(home, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory))); - final Path vault = cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final Path vault = new Path(home, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); session.withRegistry(new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator)); final B2VersionIdProvider fileid = new B2VersionIdProvider(session); final CryptoUploadFeature service = new CryptoUploadFeature<>(session, @@ -111,9 +112,9 @@ public void testWrite() throws Exception { public void testUploadWithBulk() throws Exception { // 5L * 1024L * 1024L final Path home = new Path("/test-cyberduck", EnumSet.of(Path.Type.volume, Path.Type.directory)); - final CryptoVault cryptomator = new CryptoVault( - new Path(home, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory))); - final Path vault = cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final Path vault = new Path(home, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); final Path test = new Path(vault, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.file)); session.withRegistry(new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator)); final TransferStatus writeStatus = new TransferStatus(); diff --git a/backblaze/src/test/java/ch/cyberduck/core/cryptomator/B2LargeUploadWriteFeatureTest.java b/backblaze/src/test/java/ch/cyberduck/core/cryptomator/B2LargeUploadWriteFeatureTest.java index 664d372a3f5..1a332aba815 100644 --- a/backblaze/src/test/java/ch/cyberduck/core/cryptomator/B2LargeUploadWriteFeatureTest.java +++ b/backblaze/src/test/java/ch/cyberduck/core/cryptomator/B2LargeUploadWriteFeatureTest.java @@ -35,6 +35,7 @@ import ch.cyberduck.core.transfer.TransferStatus; import ch.cyberduck.core.vault.DefaultVaultRegistry; import ch.cyberduck.core.vault.VaultCredentials; +import ch.cyberduck.core.vault.VaultMetadata; import ch.cyberduck.test.IntegrationTest; import org.apache.commons.io.IOUtils; @@ -61,9 +62,9 @@ public class B2LargeUploadWriteFeatureTest extends AbstractB2Test { @Test public void testWrite() throws Exception { final Path container = new Path("test-cyberduck", EnumSet.of(Path.Type.volume, Path.Type.directory)); - final CryptoVault cryptomator = new CryptoVault( - new Path(container, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory))); - final Path vault = cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final Path vault = new Path(container, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); session.withRegistry(new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator)); final B2VersionIdProvider fileid = new B2VersionIdProvider(session); final CryptoWriteFeature feature = new CryptoWriteFeature<>(session, new B2LargeUploadWriteFeature(session, fileid), cryptomator); diff --git a/backblaze/src/test/java/ch/cyberduck/core/cryptomator/B2ListServiceTest.java b/backblaze/src/test/java/ch/cyberduck/core/cryptomator/B2ListServiceTest.java index 4e67fcf8ad0..9b5c0987f7b 100644 --- a/backblaze/src/test/java/ch/cyberduck/core/cryptomator/B2ListServiceTest.java +++ b/backblaze/src/test/java/ch/cyberduck/core/cryptomator/B2ListServiceTest.java @@ -34,6 +34,7 @@ import ch.cyberduck.core.transfer.TransferStatus; import ch.cyberduck.core.vault.DefaultVaultRegistry; import ch.cyberduck.core.vault.VaultCredentials; +import ch.cyberduck.core.vault.VaultMetadata; import ch.cyberduck.test.IntegrationTest; import org.junit.Test; @@ -56,9 +57,9 @@ public class B2ListServiceTest extends AbstractB2Test { @Test public void testListCryptomator() throws Exception { final Path home = new Path("test-cyberduck", EnumSet.of(Path.Type.volume, Path.Type.directory)); - final CryptoVault cryptomator = new CryptoVault( - new Path(home, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory))); - final Path vault = cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final Path vault = new Path(home, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); session.withRegistry(new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator)); final B2VersionIdProvider fileid = new B2VersionIdProvider(session); assertTrue(new CryptoListService(session, new B2ListService(session, fileid), cryptomator).list(vault, new DisabledListProgressListener()).isEmpty()); diff --git a/backblaze/src/test/java/ch/cyberduck/core/cryptomator/B2TouchFeatureTest.java b/backblaze/src/test/java/ch/cyberduck/core/cryptomator/B2TouchFeatureTest.java index c2744bcfc23..a8fa2ab5208 100644 --- a/backblaze/src/test/java/ch/cyberduck/core/cryptomator/B2TouchFeatureTest.java +++ b/backblaze/src/test/java/ch/cyberduck/core/cryptomator/B2TouchFeatureTest.java @@ -36,8 +36,10 @@ import ch.cyberduck.core.transfer.TransferStatus; import ch.cyberduck.core.vault.DefaultVaultRegistry; import ch.cyberduck.core.vault.VaultCredentials; +import ch.cyberduck.core.vault.VaultMetadata; import ch.cyberduck.test.IntegrationTest; +import org.junit.Ignore; import org.junit.Test; import org.junit.experimental.categories.Category; import org.junit.runner.RunWith; @@ -50,7 +52,6 @@ import synapticloop.b2.response.BaseB2Response; import static org.junit.Assert.*; -import static org.junit.Assume.assumeTrue; @Category(IntegrationTest.class) @RunWith(value = Parameterized.class) @@ -59,9 +60,9 @@ public class B2TouchFeatureTest extends AbstractB2Test { @Test public void testTouchEncrypted() throws Exception { final Path home = new Path("/test-cyberduck", EnumSet.of(Path.Type.directory, Path.Type.volume)); - final CryptoVault cryptomator = new CryptoVault( - new Path(home, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory))); - final Path vault = cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final Path vault = new Path(home, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); session.withRegistry(new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator)); final B2VersionIdProvider fileid = new B2VersionIdProvider(session); final TransferStatus status = new TransferStatus(); @@ -76,12 +77,12 @@ public void testTouchEncrypted() throws Exception { } @Test + @Ignore("Filename shortening not implemented yet") public void testTouchLongFilenameEncrypted() throws Exception { - assumeTrue(vaultVersion == CryptoVault.VAULT_VERSION_DEPRECATED); final Path home = new Path("/test-cyberduck", EnumSet.of(Path.Type.directory, Path.Type.volume)); final Path vault = new Path(home, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); - final CryptoVault cryptomator = new CryptoVault(vault); - cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); session.withRegistry(new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator)); final B2VersionIdProvider fileid = new B2VersionIdProvider(session); final TransferStatus status = new TransferStatus(); @@ -96,9 +97,9 @@ public void testTouchLongFilenameEncrypted() throws Exception { @Test public void testTouchEncryptedDefaultFeature() throws Exception { final Path home = new Path("/test-cyberduck", EnumSet.of(Path.Type.directory, Path.Type.volume)); - final CryptoVault cryptomator = new CryptoVault( - new Path(home, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory))); - final Path vault = cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final Path vault = new Path(home, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); session.withRegistry(new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator)); final B2VersionIdProvider fileid = new B2VersionIdProvider(session); final TransferStatus status = new TransferStatus(); diff --git a/backblaze/src/test/java/ch/cyberduck/core/cryptomator/B2WriteFeatureTest.java b/backblaze/src/test/java/ch/cyberduck/core/cryptomator/B2WriteFeatureTest.java index 7713007577b..b955c1c504f 100644 --- a/backblaze/src/test/java/ch/cyberduck/core/cryptomator/B2WriteFeatureTest.java +++ b/backblaze/src/test/java/ch/cyberduck/core/cryptomator/B2WriteFeatureTest.java @@ -38,6 +38,7 @@ import ch.cyberduck.core.transfer.TransferStatus; import ch.cyberduck.core.vault.DefaultVaultRegistry; import ch.cyberduck.core.vault.VaultCredentials; +import ch.cyberduck.core.vault.VaultMetadata; import ch.cyberduck.test.IntegrationTest; import org.apache.commons.lang3.RandomUtils; @@ -69,9 +70,9 @@ public void testWrite() throws Exception { final byte[] content = RandomUtils.nextBytes(length); status.setLength(content.length); final Path home = new Path("/test-cyberduck", EnumSet.of(Path.Type.directory, Path.Type.volume)); - final CryptoVault cryptomator = new CryptoVault( - new Path(home, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory))); - final Path vault = cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final Path vault = new Path(home, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); final Path test = new Path(vault, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.file)); session.withRegistry(new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator)); final B2VersionIdProvider fileid = new B2VersionIdProvider(session); diff --git a/backblaze/src/test/java/ch/cyberduck/core/cryptomator/CopyWorkerTest.java b/backblaze/src/test/java/ch/cyberduck/core/cryptomator/CopyWorkerTest.java index d54dede8408..a00d8c836e7 100644 --- a/backblaze/src/test/java/ch/cyberduck/core/cryptomator/CopyWorkerTest.java +++ b/backblaze/src/test/java/ch/cyberduck/core/cryptomator/CopyWorkerTest.java @@ -46,12 +46,14 @@ import ch.cyberduck.core.transfer.TransferStatus; import ch.cyberduck.core.vault.DefaultVaultRegistry; import ch.cyberduck.core.vault.VaultCredentials; +import ch.cyberduck.core.vault.VaultMetadata; import ch.cyberduck.core.worker.CopyWorker; import ch.cyberduck.core.worker.DeleteWorker; import ch.cyberduck.test.IntegrationTest; import org.apache.commons.io.IOUtils; import org.apache.commons.lang3.RandomUtils; +import org.junit.Ignore; import org.junit.Test; import org.junit.experimental.categories.Category; import org.junit.runner.RunWith; @@ -66,7 +68,6 @@ import synapticloop.b2.response.BaseB2Response; import static org.junit.Assert.*; -import static org.junit.Assume.assumeTrue; @Category(IntegrationTest.class) @RunWith(value = Parameterized.class) @@ -78,8 +79,8 @@ public void testCopyFile() throws Exception { final Path vault = new Path(home, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); final Path source = new Path(vault, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.file)); final Path target = new Path(vault, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.file)); - final CryptoVault cryptomator = new CryptoVault(vault); - cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); final DefaultVaultRegistry registry = new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator); session.withRegistry(registry); final byte[] content = RandomUtils.nextBytes(40500); @@ -105,8 +106,8 @@ public void testCopyToDifferentFolderCryptomator() throws Exception { final Path source = new Path(vault, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.file)); final Path targetFolder = new Path(vault, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); final Path target = new Path(targetFolder, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.file)); - final CryptoVault cryptomator = new CryptoVault(vault); - cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); final DefaultVaultRegistry registry = new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator); session.withRegistry(registry); final B2VersionIdProvider fileid = new B2VersionIdProvider(session); @@ -125,15 +126,15 @@ public void testCopyToDifferentFolderCryptomator() throws Exception { } @Test + @Ignore("Filename shortening not implemented yet") public void testCopyToDifferentFolderLongFilenameCryptomator() throws Exception { - assumeTrue(vaultVersion == CryptoVault.VAULT_VERSION_DEPRECATED); final Path home = new Path("/test-cyberduck", EnumSet.of(Path.Type.directory, Path.Type.volume)); final Path vault = new Path(home, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); final Path source = new Path(vault, new AlphanumericRandomStringService(130).random(), EnumSet.of(Path.Type.file)); final Path targetFolder = new Path(vault, new AlphanumericRandomStringService(130).random(), EnumSet.of(Path.Type.directory)); final Path target = new Path(targetFolder, new AlphanumericRandomStringService(130).random(), EnumSet.of(Path.Type.file)); - final CryptoVault cryptomator = new CryptoVault(vault); - cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); final DefaultVaultRegistry registry = new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator); session.withRegistry(registry); final B2VersionIdProvider fileid = new B2VersionIdProvider(session); @@ -157,8 +158,8 @@ public void testCopyFolder() throws Exception { final Path vault = new Path(home, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); final Path folder = new Path(vault, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); final Path file = new Path(folder, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.file)); - final CryptoVault cryptomator = new CryptoVault(vault); - cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); final DefaultVaultRegistry registry = new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator); session.withRegistry(registry); final B2VersionIdProvider fileid = new B2VersionIdProvider(session); @@ -194,8 +195,8 @@ public void testCopyFileIntoVault() throws Exception { assertTrue(new B2FindFeature(session, fileid).find(cleartextFile)); final Path encryptedFolder = new Path(vault, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); final Path encryptedFile = new Path(encryptedFolder, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.file)); - final CryptoVault cryptomator = new CryptoVault(vault); - cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); final DefaultVaultRegistry registry = new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator); session.withRegistry(registry); cryptomator.getFeature(session, Directory.class, new B2DirectoryFeature(session, fileid)).mkdir( @@ -221,8 +222,8 @@ public void testCopyDirectoryIntoVault() throws Exception { new B2TouchFeature(session, fileid).touch(new B2WriteFeature(session, fileid), cleartextFile, new TransferStatus()); assertTrue(new B2FindFeature(session, fileid).find(cleartextFolder)); assertTrue(new B2FindFeature(session, fileid).find(cleartextFile)); - final CryptoVault cryptomator = new CryptoVault(vault); - cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); final DefaultVaultRegistry registry = new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator); session.withRegistry(registry); // move directory into vault @@ -247,8 +248,8 @@ public void testCopyFileOutsideVault() throws Exception { new B2DirectoryFeature(session, fileid).mkdir(new B2WriteFeature(session, fileid), clearFolder, new TransferStatus()); final Path encryptedFolder = new Path(vault, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); final Path encryptedFile = new Path(encryptedFolder, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.file)); - final CryptoVault cryptomator = new CryptoVault(vault); - cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); final DefaultVaultRegistry registry = new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator); session.withRegistry(registry); cryptomator.getFeature(session, Directory.class, new B2DirectoryFeature(session, fileid)).mkdir( @@ -273,8 +274,8 @@ public void testCopyDirectoryOutsideVault() throws Exception { final Path vault = new Path(home, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); final Path encryptedFolder = new Path(vault, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); final Path encryptedFile = new Path(encryptedFolder, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.file)); - final CryptoVault cryptomator = new CryptoVault(vault); - cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); final DefaultVaultRegistry registry = new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator); session.withRegistry(registry); final B2VersionIdProvider fileid = new B2VersionIdProvider(session); diff --git a/backblaze/src/test/java/ch/cyberduck/core/cryptomator/CryptoB2SingleTransferWorkerTest.java b/backblaze/src/test/java/ch/cyberduck/core/cryptomator/CryptoB2SingleTransferWorkerTest.java index a061a4203d2..64df31ff4ae 100644 --- a/backblaze/src/test/java/ch/cyberduck/core/cryptomator/CryptoB2SingleTransferWorkerTest.java +++ b/backblaze/src/test/java/ch/cyberduck/core/cryptomator/CryptoB2SingleTransferWorkerTest.java @@ -50,6 +50,7 @@ import ch.cyberduck.core.transfer.UploadTransfer; import ch.cyberduck.core.vault.DefaultVaultRegistry; import ch.cyberduck.core.vault.VaultCredentials; +import ch.cyberduck.core.vault.VaultMetadata; import ch.cyberduck.core.worker.SingleTransferWorker; import ch.cyberduck.test.IntegrationTest; @@ -91,8 +92,8 @@ public void testUpload() throws Exception { final OutputStream out2 = localFile2.getOutputStream(false); IOUtils.write(content, out2); out2.close(); - final CryptoVault cryptomator = new CryptoVault(vault); - cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); session.withRegistry(new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator)); final Transfer t = new UploadTransfer(new Host(new TestProtocol()), Collections.singletonList(new TransferItem(dir1, localDirectory1)), new NullFilter<>()); assertTrue(new SingleTransferWorker(session, session, t, new TransferOptions(), new TransferSpeedometer(t), new DisabledTransferPrompt() { diff --git a/backblaze/src/test/java/ch/cyberduck/core/cryptomator/MoveWorkerTest.java b/backblaze/src/test/java/ch/cyberduck/core/cryptomator/MoveWorkerTest.java index 031bac4fa1c..ccdcf6cba2f 100644 --- a/backblaze/src/test/java/ch/cyberduck/core/cryptomator/MoveWorkerTest.java +++ b/backblaze/src/test/java/ch/cyberduck/core/cryptomator/MoveWorkerTest.java @@ -40,6 +40,7 @@ import ch.cyberduck.core.transfer.TransferStatus; import ch.cyberduck.core.vault.DefaultVaultRegistry; import ch.cyberduck.core.vault.VaultCredentials; +import ch.cyberduck.core.vault.VaultMetadata; import ch.cyberduck.core.worker.MoveWorker; import ch.cyberduck.test.IntegrationTest; @@ -68,8 +69,8 @@ public void testMoveFileIntoVault() throws Exception { assertTrue(new DefaultFindFeature(session).find(clearFile)); final Path encryptedFolder = new Path(vault, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); final Path encryptedFile = new Path(encryptedFolder, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.file)); - final CryptoVault cryptomator = new CryptoVault(vault); - cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); final DefaultVaultRegistry registry = new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator); session.withRegistry(registry); cryptomator.getFeature(session, Directory.class, new B2DirectoryFeature(session, fileid)).mkdir( @@ -95,8 +96,8 @@ public void testMoveDirectoryIntoVault() throws Exception { new B2TouchFeature(session, fileid).touch(new B2WriteFeature(session, fileid), clearFile, new TransferStatus()); assertTrue(new DefaultFindFeature(session).find(clearFolder)); assertTrue(new DefaultFindFeature(session).find(clearFile)); - final CryptoVault cryptomator = new CryptoVault(vault); - cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); final DefaultVaultRegistry registry = new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator); session.withRegistry(registry); // move directory into vault @@ -121,8 +122,8 @@ public void testMoveFileOutsideVault() throws Exception { new B2DirectoryFeature(session, fileid).mkdir(new B2WriteFeature(session, fileid), clearFolder, new TransferStatus()); final Path encryptedFolder = new Path(vault, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); final Path encryptedFile = new Path(encryptedFolder, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.file)); - final CryptoVault cryptomator = new CryptoVault(vault); - cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); final DefaultVaultRegistry registry = new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator); session.withRegistry(registry); cryptomator.getFeature(session, Directory.class, new B2DirectoryFeature(session, fileid)).mkdir( @@ -148,8 +149,8 @@ public void testMoveDirectoryOutsideVault() throws Exception { final Path vault = new Path(home, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); final Path encryptedFolder = new Path(vault, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); final Path encryptedFile = new Path(encryptedFolder, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.file)); - final CryptoVault cryptomator = new CryptoVault(vault); - cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); final DefaultVaultRegistry registry = new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator); session.withRegistry(registry); final B2VersionIdProvider fileid = new B2VersionIdProvider(session); diff --git a/box/src/test/java/ch/cyberduck/core/box/AbstractBoxTest.java b/box/src/test/java/ch/cyberduck/core/box/AbstractBoxTest.java index 5ece290f673..d3ba73eb22f 100644 --- a/box/src/test/java/ch/cyberduck/core/box/AbstractBoxTest.java +++ b/box/src/test/java/ch/cyberduck/core/box/AbstractBoxTest.java @@ -27,10 +27,10 @@ import ch.cyberduck.core.Profile; import ch.cyberduck.core.ProtocolFactory; import ch.cyberduck.core.Scheme; -import ch.cyberduck.core.cryptomator.CryptoVault; import ch.cyberduck.core.serializer.impl.dd.ProfilePlistReader; import ch.cyberduck.core.ssl.DefaultX509KeyManager; import ch.cyberduck.core.ssl.DefaultX509TrustManager; +import ch.cyberduck.core.vault.VaultMetadata; import ch.cyberduck.test.VaultTest; import org.junit.After; @@ -48,11 +48,11 @@ public class AbstractBoxTest extends VaultTest { @Parameterized.Parameters(name = "vaultVersion = {0}") public static Object[] data() { - return new Object[]{CryptoVault.VAULT_VERSION_DEPRECATED, CryptoVault.VAULT_VERSION}; + return new Object[]{VaultMetadata.Type.V8, VaultMetadata.Type.UVF}; } @Parameterized.Parameter - public int vaultVersion; + public VaultMetadata.Type vaultVersion; @After public void disconnect() throws Exception { diff --git a/box/src/test/java/ch/cyberduck/core/cryptomator/BoxThresholdUploadServiceTest.java b/box/src/test/java/ch/cyberduck/core/cryptomator/BoxThresholdUploadServiceTest.java index 1c604e5f503..e83b706d8af 100644 --- a/box/src/test/java/ch/cyberduck/core/cryptomator/BoxThresholdUploadServiceTest.java +++ b/box/src/test/java/ch/cyberduck/core/cryptomator/BoxThresholdUploadServiceTest.java @@ -47,6 +47,7 @@ import ch.cyberduck.core.transfer.TransferStatus; import ch.cyberduck.core.vault.DefaultVaultRegistry; import ch.cyberduck.core.vault.VaultCredentials; +import ch.cyberduck.core.vault.VaultMetadata; import ch.cyberduck.test.IntegrationTest; import org.apache.commons.io.IOUtils; @@ -77,8 +78,8 @@ public void testUploadVaultWithBulkFeature() throws Exception { final Path container = new BoxDirectoryFeature(session, fileid).mkdir(new BoxWriteFeature(session, fileid), new Path(new AlphanumericRandomStringService().random(), EnumSet.of(AbstractPath.Type.directory)), new TransferStatus().setLength(0L)); final Path vault = new Path(container, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); final Path test = new Path(vault, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.file)); - final CryptoVault cryptomator = new CryptoVault(vault); - cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); final DefaultVaultRegistry registry = new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator); session.withRegistry(registry); final Local local = new Local(System.getProperty("java.io.tmpdir"), UUID.randomUUID().toString()); diff --git a/box/src/test/java/ch/cyberduck/core/cryptomator/BoxWriteFeatureTest.java b/box/src/test/java/ch/cyberduck/core/cryptomator/BoxWriteFeatureTest.java index daa3c8cec1a..eceb543152e 100644 --- a/box/src/test/java/ch/cyberduck/core/cryptomator/BoxWriteFeatureTest.java +++ b/box/src/test/java/ch/cyberduck/core/cryptomator/BoxWriteFeatureTest.java @@ -38,6 +38,7 @@ import ch.cyberduck.core.transfer.TransferStatus; import ch.cyberduck.core.vault.DefaultVaultRegistry; import ch.cyberduck.core.vault.VaultCredentials; +import ch.cyberduck.core.vault.VaultMetadata; import ch.cyberduck.test.IntegrationTest; import org.apache.commons.io.IOUtils; @@ -66,8 +67,8 @@ public void testWriteVault() throws Exception { final Path container = new BoxDirectoryFeature(session, fileid).mkdir(new BoxWriteFeature(session, fileid), new Path(new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)), new TransferStatus()); final Path vault = new Path(container, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); final Path test = new Path(vault, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.file)); - final CryptoVault cryptomator = new CryptoVault(vault); - cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); session.withRegistry(new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator)); final CryptoWriteFeature feature = new CryptoWriteFeature<>(session, new BoxWriteFeature(session, fileid), cryptomator); final byte[] content = RandomUtils.nextBytes(6 * 1024 * 1024); @@ -99,8 +100,8 @@ public void testWriteVaultWithTimeStamp() throws Exception { final Path container = new BoxDirectoryFeature(session, fileid).mkdir(new BoxWriteFeature(session, fileid), new Path(new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)), new TransferStatus()); final Path vault = new Path(container, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); final Path test = new Path(vault, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.file)); - final CryptoVault cryptomator = new CryptoVault(vault); - cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); session.withRegistry(new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator)); final CryptoWriteFeature feature = new CryptoWriteFeature<>(session, new BoxWriteFeature(session, fileid), cryptomator); final byte[] content = RandomUtils.nextBytes(6 * 1024 * 1024); diff --git a/box/src/test/java/ch/cyberduck/core/cryptomator/BufferWriteFeatureTest.java b/box/src/test/java/ch/cyberduck/core/cryptomator/BufferWriteFeatureTest.java index 0f36353221c..4eedbd39489 100644 --- a/box/src/test/java/ch/cyberduck/core/cryptomator/BufferWriteFeatureTest.java +++ b/box/src/test/java/ch/cyberduck/core/cryptomator/BufferWriteFeatureTest.java @@ -39,6 +39,7 @@ import ch.cyberduck.core.transfer.TransferStatus; import ch.cyberduck.core.vault.DefaultVaultRegistry; import ch.cyberduck.core.vault.VaultCredentials; +import ch.cyberduck.core.vault.VaultMetadata; import ch.cyberduck.test.IntegrationTest; import org.apache.commons.io.IOUtils; @@ -66,8 +67,8 @@ public void testWriteVault() throws Exception { final Path container = new BoxDirectoryFeature(session, fileid).mkdir(new BoxWriteFeature(session, fileid), new Path(new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)), new TransferStatus()); final Path vault = new Path(container, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); final Path test = new Path(vault, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.file)); - final CryptoVault cryptomator = new CryptoVault(vault); - cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); session.withRegistry(new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator)); final CryptoWriteFeature feature = new CryptoWriteFeature<>(session, new BufferWriteFeature(session), cryptomator); final byte[] content = RandomUtils.nextBytes(1024 * 1024); diff --git a/brick/src/main/java/ch/cyberduck/core/brick/BrickCopyFeature.java b/brick/src/main/java/ch/cyberduck/core/brick/BrickCopyFeature.java index b1ea3afff2c..394d54f73a6 100644 --- a/brick/src/main/java/ch/cyberduck/core/brick/BrickCopyFeature.java +++ b/brick/src/main/java/ch/cyberduck/core/brick/BrickCopyFeature.java @@ -62,7 +62,7 @@ public Path copy(final Path file, final Path target, final TransferStatus status if(entity.getFileMigrationId() != null) { this.poll(client, entity); } - return new Path(target).withAttributes(new PathAttributes(file.attributes()).setVault(null)); + return new Path(target).withAttributes(new PathAttributes(file.attributes()).setVaultMetadata(null)); } catch(ApiException e) { throw new BrickExceptionMappingService().map("Cannot copy {0}", e, file); diff --git a/brick/src/main/java/ch/cyberduck/core/brick/BrickMoveFeature.java b/brick/src/main/java/ch/cyberduck/core/brick/BrickMoveFeature.java index c4d356a8c6c..aa7d48d8183 100644 --- a/brick/src/main/java/ch/cyberduck/core/brick/BrickMoveFeature.java +++ b/brick/src/main/java/ch/cyberduck/core/brick/BrickMoveFeature.java @@ -60,7 +60,7 @@ public Path move(final Path file, final Path target, final TransferStatus status if(entity.getFileMigrationId() != null) { this.poll(client, entity); } - return new Path(target).withAttributes(new PathAttributes(file.attributes()).setVault(null)); + return new Path(target).withAttributes(new PathAttributes(file.attributes()).setVaultMetadata(null)); } catch(ApiException e) { throw new BrickExceptionMappingService().map("Cannot rename {0}", e, file); diff --git a/brick/src/test/java/ch/cyberduck/core/brick/AbstractBrickTest.java b/brick/src/test/java/ch/cyberduck/core/brick/AbstractBrickTest.java index 119ddc004c6..7f5ac86fdfb 100644 --- a/brick/src/test/java/ch/cyberduck/core/brick/AbstractBrickTest.java +++ b/brick/src/test/java/ch/cyberduck/core/brick/AbstractBrickTest.java @@ -26,10 +26,10 @@ import ch.cyberduck.core.LoginOptions; import ch.cyberduck.core.Profile; import ch.cyberduck.core.ProtocolFactory; -import ch.cyberduck.core.cryptomator.CryptoVault; import ch.cyberduck.core.serializer.impl.dd.ProfilePlistReader; import ch.cyberduck.core.ssl.DefaultX509KeyManager; import ch.cyberduck.core.ssl.DefaultX509TrustManager; +import ch.cyberduck.core.vault.VaultMetadata; import ch.cyberduck.test.VaultTest; import org.junit.After; @@ -47,11 +47,11 @@ public class AbstractBrickTest extends VaultTest { @Parameterized.Parameters(name = "vaultVersion = {0}") public static Object[] data() { - return new Object[]{CryptoVault.VAULT_VERSION_DEPRECATED, CryptoVault.VAULT_VERSION}; + return new Object[]{VaultMetadata.Type.V8, VaultMetadata.Type.UVF}; } @Parameterized.Parameter - public int vaultVersion; + public VaultMetadata.Type vaultVersion; @After public void disconnect() throws Exception { diff --git a/brick/src/test/java/ch/cyberduck/core/brick/cryptomator/BrickListServiceTest.java b/brick/src/test/java/ch/cyberduck/core/brick/cryptomator/BrickListServiceTest.java index 54f85e1b235..7c63c8e6176 100644 --- a/brick/src/test/java/ch/cyberduck/core/brick/cryptomator/BrickListServiceTest.java +++ b/brick/src/test/java/ch/cyberduck/core/brick/cryptomator/BrickListServiceTest.java @@ -26,7 +26,8 @@ import ch.cyberduck.core.brick.BrickListService; import ch.cyberduck.core.brick.BrickWriteFeature; import ch.cyberduck.core.brick.io.swagger.client.model.FileEntity; -import ch.cyberduck.core.cryptomator.CryptoVault; +import ch.cyberduck.core.cryptomator.AbstractVault; +import ch.cyberduck.core.cryptomator.CryptoVaultProvider; import ch.cyberduck.core.cryptomator.features.CryptoListService; import ch.cyberduck.core.cryptomator.features.CryptoTouchFeature; import ch.cyberduck.core.cryptomator.features.CryptoWriteFeature; @@ -35,6 +36,7 @@ import ch.cyberduck.core.transfer.TransferStatus; import ch.cyberduck.core.vault.DefaultVaultRegistry; import ch.cyberduck.core.vault.VaultCredentials; +import ch.cyberduck.core.vault.VaultMetadata; import ch.cyberduck.test.IntegrationTest; import org.junit.Assert; @@ -58,8 +60,8 @@ public void testListCryptomator() throws Exception { EnumSet.of(Path.Type.directory, Path.Type.volume)), new TransferStatus()); final Path vault = new Path(home, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); final Path test = new Path(vault, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.file)); - final CryptoVault cryptomator = new CryptoVault(vault); - cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); session.withRegistry(new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator)); assertTrue(new CryptoListService(session, new BrickListService(session), cryptomator).list(vault, new DisabledListProgressListener()).isEmpty()); new CryptoTouchFeature<>(session, new DefaultTouchFeature(session), cryptomator).touch( diff --git a/brick/src/test/java/ch/cyberduck/core/cryptomator/DefaultTouchFeatureTest.java b/brick/src/test/java/ch/cyberduck/core/cryptomator/DefaultTouchFeatureTest.java index 6e518e70b37..3d96f051ce2 100644 --- a/brick/src/test/java/ch/cyberduck/core/cryptomator/DefaultTouchFeatureTest.java +++ b/brick/src/test/java/ch/cyberduck/core/cryptomator/DefaultTouchFeatureTest.java @@ -33,8 +33,10 @@ import ch.cyberduck.core.transfer.TransferStatus; import ch.cyberduck.core.vault.DefaultVaultRegistry; import ch.cyberduck.core.vault.VaultCredentials; +import ch.cyberduck.core.vault.VaultMetadata; import ch.cyberduck.test.IntegrationTest; +import org.junit.Ignore; import org.junit.Test; import org.junit.experimental.categories.Category; import org.junit.runner.RunWith; @@ -45,19 +47,20 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; -import static org.junit.Assume.assumeTrue; @Category(IntegrationTest.class) @RunWith(value = Parameterized.class) public class DefaultTouchFeatureTest extends AbstractBrickTest { + //TODO + @Test + @Ignore(value = "Filename shortening not yet implemented") public void testTouchLongFilenameEncrypted() throws Exception { - assumeTrue(vaultVersion == CryptoVault.VAULT_VERSION_DEPRECATED); final Path home = new Path("/", EnumSet.of(Path.Type.directory, Path.Type.volume)); - final CryptoVault cryptomator = new CryptoVault( - new Path(home, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory))); - final Path vault = cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final Path vault = new Path(home, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); session.withRegistry(new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator)); final TransferStatus status = new TransferStatus(); final Path test = new CryptoTouchFeature<>(session, new DefaultTouchFeature(session), cryptomator).touch( @@ -68,12 +71,12 @@ public void testTouchLongFilenameEncrypted() throws Exception { } @Test + @Ignore(value = "Filename shortening not yet implemented") public void testTouchLongFilenameEncryptedDefaultFeature() throws Exception { - assumeTrue(vaultVersion == CryptoVault.VAULT_VERSION_DEPRECATED); final Path home = new Path("/", EnumSet.of(Path.Type.directory, Path.Type.volume)); - final CryptoVault cryptomator = new CryptoVault( - new Path(home, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory))); - final Path vault = cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final Path vault = new Path(home, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); session.withRegistry(new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator)); final TransferStatus status = new TransferStatus(); final Path test = new CryptoTouchFeature<>(session, new DefaultTouchFeature(session), cryptomator).touch( diff --git a/cli/src/main/java/ch/cyberduck/cli/Terminal.java b/cli/src/main/java/ch/cyberduck/cli/Terminal.java index c7f002840c8..486be082873 100644 --- a/cli/src/main/java/ch/cyberduck/cli/Terminal.java +++ b/cli/src/main/java/ch/cyberduck/cli/Terminal.java @@ -48,6 +48,7 @@ import ch.cyberduck.core.transfer.TransferPrompt; import ch.cyberduck.core.transfer.TransferSpeedometer; import ch.cyberduck.core.vault.LoadingVaultLookupListener; +import ch.cyberduck.core.vault.VaultMetadata; import ch.cyberduck.core.vault.VaultRegistry; import ch.cyberduck.core.vault.VaultRegistryFactory; import ch.cyberduck.core.worker.AttributesWorker; @@ -247,7 +248,7 @@ public void uncaughtException(final Thread t, final Throwable e) { log.debug("Attempting to load vault from {}", vault); try { this.execute(new TerminalBackgroundAction<>(controller, source, new LoadVaultWorker(new LoadingVaultLookupListener(source.getVaultRegistry(), - new TerminalPasswordCallback()), vault))); + new TerminalPasswordCallback()), new VaultMetadata(vault, VaultMetadata.Type.valueOf(preferences.getProperty("cryptomator.vault.default")))))); } catch(TerminalBackgroundException e) { return Exit.failure; diff --git a/cli/src/main/java/ch/cyberduck/cli/TerminalPreferences.java b/cli/src/main/java/ch/cyberduck/cli/TerminalPreferences.java index dd13d2bfc4f..9e33bd55c60 100644 --- a/cli/src/main/java/ch/cyberduck/cli/TerminalPreferences.java +++ b/cli/src/main/java/ch/cyberduck/cli/TerminalPreferences.java @@ -17,7 +17,8 @@ import ch.cyberduck.core.DisabledConnectionTimeout; import ch.cyberduck.core.Local; import ch.cyberduck.core.Permission; -import ch.cyberduck.core.cryptomator.CryptoVault; +import ch.cyberduck.core.cryptomator.CryptoVaultProvider; +import ch.cyberduck.core.cryptomator.impl.v8.CryptoVault; import ch.cyberduck.core.cryptomator.random.FastSecureRandomProvider; import ch.cyberduck.core.preferences.Preferences; import ch.cyberduck.core.transfer.Transfer; @@ -58,7 +59,9 @@ protected void setFactories() { for(Transfer.Type t : Transfer.Type.values()) { this.setDefault(String.format("factory.transferpromptcallback.%s.class", t.name()), TerminalTransferPrompt.class.getName()); } + //TODO braucht es diesen eintrag noch? this.setDefault("factory.vault.class", CryptoVault.class.getName()); + this.setDefault("factory.vaultprovider.class", CryptoVaultProvider.class.getName()); this.setDefault("factory.securerandom.class", FastSecureRandomProvider.class.getName()); this.setDefault("factory.connectiontimeout.class", DisabledConnectionTimeout.class.getName()); } diff --git a/core/src/main/java/ch/cyberduck/core/PathAttributes.java b/core/src/main/java/ch/cyberduck/core/PathAttributes.java index 807a4c4b85e..78811ae4a0d 100644 --- a/core/src/main/java/ch/cyberduck/core/PathAttributes.java +++ b/core/src/main/java/ch/cyberduck/core/PathAttributes.java @@ -23,6 +23,7 @@ import ch.cyberduck.core.io.Checksum; import ch.cyberduck.core.serializer.Serializer; import ch.cyberduck.core.transfer.TransferStatus; +import ch.cyberduck.core.vault.VaultMetadata; import org.apache.commons.lang3.StringUtils; import org.apache.logging.log4j.LogManager; @@ -145,6 +146,11 @@ public class PathAttributes extends Attributes implements Serializable { * Cryptomator vault */ private Path vault; + + /** + * Cryptomator vault metadata + */ + private VaultMetadata vaultMetadata; /** * Cryptomator decrypted path */ @@ -199,6 +205,7 @@ public PathAttributes(final PathAttributes copy) { custom = new HashMap<>(copy.custom); verdict = copy.verdict; vault = copy.vault; + vaultMetadata = copy.vaultMetadata; decrypted = copy.decrypted; encrypted = copy.encrypted; directoryId = copy.directoryId; @@ -287,6 +294,16 @@ public T serialize(final Serializer dict) { dict.setObjectForKey(vault, "Vault"); } } + if(vaultMetadata != null) { + if(vaultMetadata.root != null) { + if(vaultMetadata.root.attributes() == this) { + log.debug("Skip serializing vault metadata root attribute {} to avoid recursion", vaultMetadata.root); + } + else { + dict.setObjectForKey(vaultMetadata, "Vault Metadata"); + } + } + } if(!custom.isEmpty()) { dict.setMapForKey(custom, "Custom"); } @@ -534,6 +551,15 @@ public Path getVault() { return vault; } + public PathAttributes setVaultMetadata(final VaultMetadata vaultMetadata) { + this.vaultMetadata = vaultMetadata; + return this; + } + + public VaultMetadata getVaultMetadata() { + return vaultMetadata; + } + /** * If the path should not be displayed in a browser by default unless the user explicitly chooses to show hidden * files. diff --git a/core/src/main/java/ch/cyberduck/core/features/Vault.java b/core/src/main/java/ch/cyberduck/core/features/Vault.java index 23243500404..1267d61d4ca 100644 --- a/core/src/main/java/ch/cyberduck/core/features/Vault.java +++ b/core/src/main/java/ch/cyberduck/core/features/Vault.java @@ -24,6 +24,7 @@ import ch.cyberduck.core.exception.UnsupportedException; import ch.cyberduck.core.vault.DisabledVault; import ch.cyberduck.core.vault.VaultCredentials; +import ch.cyberduck.core.vault.VaultMetadata; public interface Vault { @@ -35,7 +36,7 @@ public interface Vault { * @throws BackgroundException Failure reading master key from server * @throws NotfoundException No master key file in home */ - Path create(Session session, String region, VaultCredentials credentials) throws BackgroundException; + Vault create(Session session, String region, VaultCredentials credentials) throws BackgroundException; /** * Open existing vault @@ -102,6 +103,8 @@ public interface Vault { */ Path getHome(); + VaultMetadata getMetadata(); + enum State { open, closed diff --git a/core/src/main/java/ch/cyberduck/core/serializer/PathAttributesDictionary.java b/core/src/main/java/ch/cyberduck/core/serializer/PathAttributesDictionary.java index 0ad7f805a2b..a54bfed364f 100644 --- a/core/src/main/java/ch/cyberduck/core/serializer/PathAttributesDictionary.java +++ b/core/src/main/java/ch/cyberduck/core/serializer/PathAttributesDictionary.java @@ -24,6 +24,7 @@ import ch.cyberduck.core.features.Quota; import ch.cyberduck.core.io.Checksum; import ch.cyberduck.core.io.HashAlgorithm; +import ch.cyberduck.core.vault.VaultMetadataDictionary; import java.util.Collections; import java.util.Map; @@ -117,6 +118,10 @@ public PathAttributes deserialize(final T serialized) { if(vaultObj != null) { attributes.setVault(new PathDictionary<>(factory).deserialize(vaultObj)); } + final T vaultMetadataObj = dict.objectForKey("Vault Metadata"); + if(vaultMetadataObj != null) { + attributes.setVaultMetadata(new VaultMetadataDictionary<>(factory).deserialize(vaultMetadataObj)); + } final Map customObj = dict.mapForKey("Custom"); if(customObj != null) { attributes.setCustom(customObj); diff --git a/core/src/main/java/ch/cyberduck/core/vault/DefaultVaultRegistry.java b/core/src/main/java/ch/cyberduck/core/vault/DefaultVaultRegistry.java index 9550e607bbe..6787da34a05 100644 --- a/core/src/main/java/ch/cyberduck/core/vault/DefaultVaultRegistry.java +++ b/core/src/main/java/ch/cyberduck/core/vault/DefaultVaultRegistry.java @@ -23,14 +23,12 @@ import ch.cyberduck.core.SimplePathPredicate; import ch.cyberduck.core.UrlProvider; import ch.cyberduck.core.features.*; -import ch.cyberduck.core.preferences.HostPreferencesFactory; import ch.cyberduck.core.preferences.PreferencesFactory; import ch.cyberduck.core.vault.registry.*; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; -import java.nio.charset.StandardCharsets; import java.util.Arrays; import java.util.concurrent.CopyOnWriteArraySet; @@ -41,9 +39,14 @@ public class DefaultVaultRegistry extends CopyOnWriteArraySet implements PreferencesFactory.get().getProperty("cryptomator.vault.masterkey.filename"); public static final String DEFAULT_BACKUPKEY_FILE_NAME = String.format("%s.bkup", PreferencesFactory.get().getProperty("cryptomator.vault.masterkey.filename")); + + // TODO können die weg? wird z.b. weiter unten via hostpreferences geholt public static final String DEFAULT_VAULTCONFIG_FILE_NAME = PreferencesFactory.get().getProperty("cryptomator.vault.config.filename"); + public static final String DEFAULT_VAULTCONFIGUVF_FILE_NAME = + PreferencesFactory.get().getProperty("cryptomator.vault.config.filename.uvf"); + private final PasswordCallback prompt; public DefaultVaultRegistry(final PasswordCallback prompt) { @@ -73,7 +76,7 @@ public boolean close(final Path directory) { }); } finally { - directory.attributes().setVault(null); + directory.attributes().setVaultMetadata(null); } } @@ -107,18 +110,14 @@ public Vault find(final Session session, final Path file, final boolean autol } if(autoload) { final LoadingVaultLookupListener listener = new LoadingVaultLookupListener(this, prompt); - if(file.attributes().getVault() != null) { - return listener.load(session, file.attributes().getVault(), - HostPreferencesFactory.get(session.getHost()).getProperty("cryptomator.vault.masterkey.filename"), - HostPreferencesFactory.get(session.getHost()).getProperty("cryptomator.vault.config.filename"), - HostPreferencesFactory.get(session.getHost()).getProperty("cryptomator.vault.pepper").getBytes(StandardCharsets.UTF_8)); + if(file.attributes().getVaultMetadata() != null) { + return listener.load(session, file.attributes().getVaultMetadata() + ); } final Path directory = file.getParent(); - if(directory.attributes().getVault() != null) { - return listener.load(session, directory.attributes().getVault(), - HostPreferencesFactory.get(session.getHost()).getProperty("cryptomator.vault.masterkey.filename"), - HostPreferencesFactory.get(session.getHost()).getProperty("cryptomator.vault.config.filename"), - HostPreferencesFactory.get(session.getHost()).getProperty("cryptomator.vault.pepper").getBytes(StandardCharsets.UTF_8)); + if(directory.attributes().getVaultMetadata() != null) { + return listener.load(session, directory.attributes().getVaultMetadata() + ); } } return Vault.DISABLED; diff --git a/core/src/main/java/ch/cyberduck/core/vault/DisabledVault.java b/core/src/main/java/ch/cyberduck/core/vault/DisabledVault.java index 70d119aede1..76b7d0541f2 100644 --- a/core/src/main/java/ch/cyberduck/core/vault/DisabledVault.java +++ b/core/src/main/java/ch/cyberduck/core/vault/DisabledVault.java @@ -36,7 +36,7 @@ public DisabledVault(final Path home) { } @Override - public Path create(final Session session, final String region, final VaultCredentials credentials) { + public Vault create(final Session session, final String region, final VaultCredentials credentials) { return null; } @@ -96,6 +96,10 @@ public Path getHome() { return home; } + @Override + public VaultMetadata getMetadata() { + return null; + } @Override public boolean equals(final Object o) { diff --git a/core/src/main/java/ch/cyberduck/core/vault/DisabledVaultLookupListener.java b/core/src/main/java/ch/cyberduck/core/vault/DisabledVaultLookupListener.java index f1cd16e3f11..2eff02bead2 100644 --- a/core/src/main/java/ch/cyberduck/core/vault/DisabledVaultLookupListener.java +++ b/core/src/main/java/ch/cyberduck/core/vault/DisabledVaultLookupListener.java @@ -15,7 +15,6 @@ * GNU General Public License for more details. */ -import ch.cyberduck.core.Path; import ch.cyberduck.core.Session; import ch.cyberduck.core.features.Vault; @@ -26,8 +25,8 @@ public final class DisabledVaultLookupListener implements VaultLookupListener { private static final Logger log = LogManager.getLogger(DisabledVaultLookupListener.class); @Override - public Vault load(final Session session, final Path directory, final String masterkey, final String config, final byte[] pepper) { - log.warn("Ignore vault {}", directory); + public Vault load(final Session session, final VaultMetadata metadata) { + log.warn("Ignore vault {}", metadata); return Vault.DISABLED; } } diff --git a/core/src/main/java/ch/cyberduck/core/vault/DisabledVaultProvider.java b/core/src/main/java/ch/cyberduck/core/vault/DisabledVaultProvider.java new file mode 100644 index 00000000000..e096580ac26 --- /dev/null +++ b/core/src/main/java/ch/cyberduck/core/vault/DisabledVaultProvider.java @@ -0,0 +1,50 @@ +package ch.cyberduck.core.vault; + +/* + * Copyright (c) 2002-2025 iterate GmbH. All rights reserved. + * https://cyberduck.io/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +import ch.cyberduck.core.ListProgressListener; +import ch.cyberduck.core.Path; +import ch.cyberduck.core.Session; +import ch.cyberduck.core.exception.BackgroundException; +import ch.cyberduck.core.features.Find; +import ch.cyberduck.core.features.Vault; + +public class DisabledVaultProvider implements VaultProvider { + @Override + public boolean isVault(final Path path) { + return false; + } + + @Override + public VaultMetadata metadata(final Path path) { + return null; + } + + @Override + public VaultMetadata find(final Path directory, final Find find, final ListProgressListener listener) throws BackgroundException { + return null; + } + + @Override + public Vault provide(final Session session, final VaultMetadata metadata) { + return Vault.DISABLED; + } + + @Override + public Vault create(final Session session, final String region, final VaultCredentials credentials, final VaultMetadata metadata) throws BackgroundException { + return Vault.DISABLED; + } +} diff --git a/core/src/main/java/ch/cyberduck/core/vault/LoadingVaultLookupListener.java b/core/src/main/java/ch/cyberduck/core/vault/LoadingVaultLookupListener.java index 242f903b8d5..49ed4fb9d3d 100644 --- a/core/src/main/java/ch/cyberduck/core/vault/LoadingVaultLookupListener.java +++ b/core/src/main/java/ch/cyberduck/core/vault/LoadingVaultLookupListener.java @@ -16,8 +16,6 @@ */ import ch.cyberduck.core.PasswordCallback; -import ch.cyberduck.core.PasswordStore; -import ch.cyberduck.core.Path; import ch.cyberduck.core.Session; import ch.cyberduck.core.exception.BackgroundException; import ch.cyberduck.core.features.Vault; @@ -37,21 +35,21 @@ public LoadingVaultLookupListener(final VaultRegistry registry, final PasswordCa } @Override - public Vault load(final Session session, final Path directory, final String masterkey, final String config, final byte[] pepper) throws VaultUnlockCancelException { + public Vault load(final Session session, final VaultMetadata metadata) throws VaultUnlockCancelException { synchronized(registry) { - if(registry.contains(directory)) { - return registry.find(session, directory); + if(registry.contains(metadata.root)) { + return registry.find(session, metadata.root); } - final Vault vault = VaultFactory.get(directory, masterkey, config, pepper); - log.info("Loading vault {} for session {}", vault, session); + log.info("Loading vault for session {}", session); + final Vault vault = VaultProviderFactory.get(session).provide(session, metadata); try { registry.add(vault.load(session, prompt)); + return vault; } catch(BackgroundException e) { - log.warn("Failure {} loading vault {}", e, vault); + log.warn("Failure {} loading vault", e); throw new VaultUnlockCancelException(vault, e); } - return vault; } } } diff --git a/core/src/main/java/ch/cyberduck/core/vault/VaultFinderListProgressListener.java b/core/src/main/java/ch/cyberduck/core/vault/VaultFinderListProgressListener.java index 4f9eb821ce2..4c0249678e9 100644 --- a/core/src/main/java/ch/cyberduck/core/vault/VaultFinderListProgressListener.java +++ b/core/src/main/java/ch/cyberduck/core/vault/VaultFinderListProgressListener.java @@ -23,12 +23,10 @@ import ch.cyberduck.core.exception.BackgroundException; import ch.cyberduck.core.exception.ConnectionCanceledException; import ch.cyberduck.core.features.Vault; -import ch.cyberduck.core.preferences.HostPreferencesFactory; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; -import java.nio.charset.StandardCharsets; import java.util.Optional; import java.util.concurrent.atomic.AtomicBoolean; @@ -38,21 +36,17 @@ public class VaultFinderListProgressListener extends IndexedListProgressListener private final Session session; private final VaultLookupListener lookup; private final ListProgressListener proxy; - private final String config; - private final String masterkey; - private final byte[] pepper; // Number of files to wait for until proxy is notified of files private final int filecount; private final AtomicBoolean canceled = new AtomicBoolean(); + private final VaultProvider provider; public VaultFinderListProgressListener(final Session session, final VaultLookupListener lookup, final ListProgressListener proxy, final int filecount) { this.session = session; this.lookup = lookup; this.proxy = proxy; - this.config = HostPreferencesFactory.get(session.getHost()).getProperty("cryptomator.vault.config.filename"); - this.masterkey = HostPreferencesFactory.get(session.getHost()).getProperty("cryptomator.vault.masterkey.filename"); - this.pepper = HostPreferencesFactory.get(session.getHost()).getProperty("cryptomator.vault.pepper").getBytes(StandardCharsets.UTF_8); this.filecount = filecount; + this.provider = VaultProviderFactory.get(session); } @Override @@ -83,10 +77,10 @@ public void chunk(final Path folder, final AttributedList list) throws Con @Override public void visit(final AttributedList list, final int index, final Path file) throws ConnectionCanceledException { - final Path directory = file.getParent(); - if(config.equals(file.getName()) || masterkey.equals(file.getName())) { + final VaultMetadata metadata = provider.metadata(file); + if(metadata != null) { log.info("Found vault config or masterkey file {}", file); - final Vault vault = lookup.load(session, directory, masterkey, config, pepper); + final Vault vault = lookup.load(session, metadata); if(vault.equals(Vault.DISABLED)) { return; } diff --git a/core/src/main/java/ch/cyberduck/core/vault/VaultLookupListener.java b/core/src/main/java/ch/cyberduck/core/vault/VaultLookupListener.java index 7e4f12cbbb2..56782de4096 100644 --- a/core/src/main/java/ch/cyberduck/core/vault/VaultLookupListener.java +++ b/core/src/main/java/ch/cyberduck/core/vault/VaultLookupListener.java @@ -15,10 +15,9 @@ * GNU General Public License for more details. */ -import ch.cyberduck.core.Path; import ch.cyberduck.core.Session; import ch.cyberduck.core.features.Vault; public interface VaultLookupListener { - Vault load(final Session session, Path directory, String masterkey, final String config, byte[] pepper) throws VaultUnlockCancelException; + Vault load(final Session session, VaultMetadata metadata) throws VaultUnlockCancelException; } diff --git a/core/src/main/java/ch/cyberduck/core/vault/VaultMetadata.java b/core/src/main/java/ch/cyberduck/core/vault/VaultMetadata.java new file mode 100644 index 00000000000..468b609d344 --- /dev/null +++ b/core/src/main/java/ch/cyberduck/core/vault/VaultMetadata.java @@ -0,0 +1,87 @@ +package ch.cyberduck.core.vault; + +/* + * Copyright (c) 2002-2025 iterate GmbH. All rights reserved. + * https://cyberduck.io/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +import ch.cyberduck.core.Path; +import ch.cyberduck.core.Serializable; +import ch.cyberduck.core.serializer.Serializer; + +import java.util.Objects; + +public class VaultMetadata implements Serializable { + + public Path root; + public Type type; + + public enum Type { + V8, UVF + } + + public VaultMetadata() { + } + + public VaultMetadata(final Path path, final Type type) { + this.root = path; + this.type = type; + } + + @Override + public T serialize(final Serializer dict) { + if(root != null) { + dict.setObjectForKey(root, "Root"); + } + if(type != null) { + dict.setStringForKey(type.name(), "Type"); + } + return dict.getSerialized(); + } + + @Override + public final boolean equals(final Object o) { + if(o == this) { + return true; + } + if(!(o instanceof VaultMetadata)) { + return false; + } + + VaultMetadata that = (VaultMetadata) o; + if(!Objects.equals(root, that.root)) { + return false; + } + if(type != that.type) { + return false; + } + return true; + } + + @Override + public int hashCode() { + int result = Objects.hashCode(root); + result = 31 * result + Objects.hashCode(type); + return result; + } + + @Override + public String toString() { + final StringBuilder sb = new StringBuilder("VaultMetadata{"); + sb.append("root=").append(root); + sb.append(", type=").append(type); + sb.append('}'); + return sb.toString(); + } +} + diff --git a/core/src/main/java/ch/cyberduck/core/vault/VaultMetadataDictionary.java b/core/src/main/java/ch/cyberduck/core/vault/VaultMetadataDictionary.java new file mode 100644 index 00000000000..e3bd813a80e --- /dev/null +++ b/core/src/main/java/ch/cyberduck/core/vault/VaultMetadataDictionary.java @@ -0,0 +1,47 @@ +package ch.cyberduck.core.vault; + +/* + * Copyright (c) 2002-2025 iterate GmbH. All rights reserved. + * https://cyberduck.io/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +import ch.cyberduck.core.DeserializerFactory; +import ch.cyberduck.core.serializer.Deserializer; +import ch.cyberduck.core.serializer.PathDictionary; + +public class VaultMetadataDictionary { + + private final DeserializerFactory factory; + + public VaultMetadataDictionary() { + this.factory = new DeserializerFactory<>(); + } + + public VaultMetadataDictionary(final DeserializerFactory factory) { + this.factory = factory; + } + + public VaultMetadata deserialize(final T serialized) { + final Deserializer dict = factory.create(serialized); + final VaultMetadata vaultMetadata = new VaultMetadata(); + final T vaultObj = dict.objectForKey("Root"); + if(vaultObj != null) { + vaultMetadata.root = new PathDictionary<>(factory).deserialize(vaultObj); + } + final String type = dict.stringForKey("Type"); + if(type != null) { + vaultMetadata.type = VaultMetadata.Type.valueOf(type); + } + return vaultMetadata; + } +} diff --git a/core/src/main/java/ch/cyberduck/core/vault/VaultProvider.java b/core/src/main/java/ch/cyberduck/core/vault/VaultProvider.java new file mode 100644 index 00000000000..7415052e739 --- /dev/null +++ b/core/src/main/java/ch/cyberduck/core/vault/VaultProvider.java @@ -0,0 +1,37 @@ +package ch.cyberduck.core.vault; + +/* + * Copyright (c) 2002-2025 iterate GmbH. All rights reserved. + * https://cyberduck.io/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +import ch.cyberduck.core.ListProgressListener; +import ch.cyberduck.core.Path; +import ch.cyberduck.core.Session; +import ch.cyberduck.core.exception.BackgroundException; +import ch.cyberduck.core.features.Find; +import ch.cyberduck.core.features.Vault; + +public interface VaultProvider { + boolean isVault(Path path); + + VaultMetadata metadata(Path path); + + VaultMetadata find(Path directory, Find find, ListProgressListener listener) throws BackgroundException; + + Vault provide(Session session, VaultMetadata metadata); + + Vault create(Session session, String region, VaultCredentials credentials, VaultMetadata metadata) throws BackgroundException; + + VaultProvider DISABLED = new DisabledVaultProvider(); +} diff --git a/core/src/main/java/ch/cyberduck/core/vault/VaultProviderFactory.java b/core/src/main/java/ch/cyberduck/core/vault/VaultProviderFactory.java new file mode 100644 index 00000000000..172fc59d255 --- /dev/null +++ b/core/src/main/java/ch/cyberduck/core/vault/VaultProviderFactory.java @@ -0,0 +1,55 @@ +package ch.cyberduck.core.vault; + +/* + * Copyright (c) 2002-2025 iterate GmbH. All rights reserved. + * https://cyberduck.io/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +import ch.cyberduck.core.Factory; +import ch.cyberduck.core.Session; + +import org.apache.commons.lang3.reflect.ConstructorUtils; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; + +public class VaultProviderFactory extends Factory { + private static final Logger log = LogManager.getLogger(VaultProviderFactory.class); + + private VaultProviderFactory() { + super("factory.vaultprovider.class"); + } + + public static VaultProvider get(final Session session) { + return new VaultProviderFactory().create(session); + } + + private VaultProvider create(final Session session) { + try { + final Constructor constructor = ConstructorUtils.getMatchingAccessibleConstructor(clazz, + session.getClass()); + if(null == constructor) { + log.warn("No matching constructor for parameter {}", session.getClass()); + // Call default constructor for disabled implementations + return clazz.getDeclaredConstructor().newInstance(); + } + return constructor.newInstance(session); + } + catch(InstantiationException | InvocationTargetException | IllegalAccessException | NoSuchMethodException e) { + log.error("Failure loading callback class {}. {}", clazz, e.getMessage()); + return VaultProvider.DISABLED; + } + } +} diff --git a/core/src/main/java/ch/cyberduck/core/vault/registry/VaultRegistryFindFeature.java b/core/src/main/java/ch/cyberduck/core/vault/registry/VaultRegistryFindFeature.java index 90570bc7c35..c05b9d2a0c5 100644 --- a/core/src/main/java/ch/cyberduck/core/vault/registry/VaultRegistryFindFeature.java +++ b/core/src/main/java/ch/cyberduck/core/vault/registry/VaultRegistryFindFeature.java @@ -23,13 +23,15 @@ import ch.cyberduck.core.features.Vault; import ch.cyberduck.core.preferences.HostPreferencesFactory; import ch.cyberduck.core.vault.VaultLookupListener; +import ch.cyberduck.core.vault.VaultMetadata; +import ch.cyberduck.core.vault.VaultProvider; +import ch.cyberduck.core.vault.VaultProviderFactory; import ch.cyberduck.core.vault.VaultRegistry; import ch.cyberduck.core.vault.VaultUnlockCancelException; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; -import java.nio.charset.StandardCharsets; import java.util.EnumSet; public class VaultRegistryFindFeature implements Find { @@ -40,6 +42,7 @@ public class VaultRegistryFindFeature implements Find { private final VaultRegistry registry; private final VaultLookupListener lookup; private final boolean autodetect; + private final VaultProvider provider; public VaultRegistryFindFeature(final Session session, final Find proxy, final VaultRegistry registry, final VaultLookupListener lookup) { this.session = session; @@ -48,6 +51,7 @@ public VaultRegistryFindFeature(final Session session, final Find proxy, fina this.lookup = lookup; this.autodetect = HostPreferencesFactory.get(session.getHost()).getBoolean("cryptomator.vault.autodetect") && HostPreferencesFactory.get(session.getHost()).getBoolean("cryptomator.enable"); + this.provider = VaultProviderFactory.get(session); } @Override @@ -60,14 +64,13 @@ public boolean find(final Path file, final ListProgressListener listener) throws HostPreferencesFactory.get(session.getHost()).getProperty("cryptomator.vault.config.filename"), EnumSet.of(Path.Type.file)); final Path key = new Path(directory, HostPreferencesFactory.get(session.getHost()).getProperty("cryptomator.vault.masterkey.filename"), EnumSet.of(Path.Type.file)); - if(proxy.find(vaultConfig, listener) || proxy.find(key, listener)) { + + final VaultMetadata metadata = provider.find(directory, proxy, listener); + if(metadata != null) { log.info("Found vault config {} or masterkey {}", vaultConfig, key); try { log.info("Found vault {}", directory); - return lookup.load(session, directory, - HostPreferencesFactory.get(session.getHost()).getProperty("cryptomator.vault.masterkey.filename"), - HostPreferencesFactory.get(session.getHost()).getProperty("cryptomator.vault.config.filename"), - HostPreferencesFactory.get(session.getHost()).getProperty("cryptomator.vault.pepper").getBytes(StandardCharsets.UTF_8)) + return lookup.load(session, metadata) .getFeature(session, Find.class, proxy) .find(file, listener); } diff --git a/core/src/main/java/ch/cyberduck/core/worker/CreateVaultWorker.java b/core/src/main/java/ch/cyberduck/core/worker/CreateVaultWorker.java index 85d274acccf..7dedd68669b 100644 --- a/core/src/main/java/ch/cyberduck/core/worker/CreateVaultWorker.java +++ b/core/src/main/java/ch/cyberduck/core/worker/CreateVaultWorker.java @@ -16,38 +16,38 @@ */ import ch.cyberduck.core.LocaleFactory; -import ch.cyberduck.core.PasswordStore; -import ch.cyberduck.core.Path; import ch.cyberduck.core.Session; import ch.cyberduck.core.exception.BackgroundException; import ch.cyberduck.core.features.Vault; import ch.cyberduck.core.vault.VaultCredentials; +import ch.cyberduck.core.vault.VaultMetadata; +import ch.cyberduck.core.vault.VaultProviderFactory; import java.text.MessageFormat; import java.util.Objects; -public class CreateVaultWorker extends Worker { +public class CreateVaultWorker extends Worker { private final String region; private final VaultCredentials passphrase; - private final Vault vault; + private final VaultMetadata metadata; - public CreateVaultWorker(final String region, final VaultCredentials passphrase, final Vault vault) { + public CreateVaultWorker(final String region, final VaultCredentials passphrase, final VaultMetadata metadata) { this.region = region; this.passphrase = passphrase; - this.vault = vault; + this.metadata = metadata; } @Override - public Path run(final Session session) throws BackgroundException { - final Path home = vault.create(session, region, passphrase); + public Vault run(final Session session) throws BackgroundException { + final Vault vault = VaultProviderFactory.get(session).create(session, region, passphrase, metadata); vault.close(); - return home; + return vault; } @Override public String getActivity() { - return MessageFormat.format(LocaleFactory.localizedString("Making directory {0}", "Status"), vault.getHome().getName()); + return MessageFormat.format(LocaleFactory.localizedString("Making directory {0}", "Status"), metadata.root.getName()); } @Override @@ -59,18 +59,18 @@ public boolean equals(final Object o) { return false; } final CreateVaultWorker that = (CreateVaultWorker) o; - return Objects.equals(vault, that.vault); + return Objects.equals(metadata, that.metadata); } @Override public int hashCode() { - return Objects.hash(vault); + return Objects.hash(metadata); } @Override public String toString() { final StringBuilder sb = new StringBuilder("CreateVaultWorker{"); - sb.append("vault=").append(vault); + sb.append("metadata=").append(metadata); sb.append('}'); return sb.toString(); } diff --git a/core/src/main/java/ch/cyberduck/core/worker/LoadVaultWorker.java b/core/src/main/java/ch/cyberduck/core/worker/LoadVaultWorker.java index 334d3b2c189..1b56778c45e 100644 --- a/core/src/main/java/ch/cyberduck/core/worker/LoadVaultWorker.java +++ b/core/src/main/java/ch/cyberduck/core/worker/LoadVaultWorker.java @@ -16,32 +16,27 @@ */ import ch.cyberduck.core.LocaleFactory; -import ch.cyberduck.core.Path; import ch.cyberduck.core.Session; import ch.cyberduck.core.exception.BackgroundException; import ch.cyberduck.core.features.Vault; -import ch.cyberduck.core.preferences.HostPreferencesFactory; import ch.cyberduck.core.vault.VaultLookupListener; +import ch.cyberduck.core.vault.VaultMetadata; -import java.nio.charset.StandardCharsets; import java.util.Objects; public class LoadVaultWorker extends Worker { private final VaultLookupListener listener; - private final Path directory; + private final VaultMetadata metadata; - public LoadVaultWorker(final VaultLookupListener listener, final Path directory) { + public LoadVaultWorker(final VaultLookupListener listener, final VaultMetadata metadata) { this.listener = listener; - this.directory = directory; + this.metadata = metadata; } @Override public Vault run(final Session session) throws BackgroundException { - return listener.load(session, directory, - HostPreferencesFactory.get(session.getHost()).getProperty("cryptomator.vault.masterkey.filename"), - HostPreferencesFactory.get(session.getHost()).getProperty("cryptomator.vault.config.filename"), - HostPreferencesFactory.get(session.getHost()).getProperty("cryptomator.vault.pepper").getBytes(StandardCharsets.UTF_8)); + return listener.load(session, metadata); } @Override @@ -58,18 +53,18 @@ public boolean equals(final Object o) { return false; } final LoadVaultWorker that = (LoadVaultWorker) o; - return Objects.equals(directory, that.directory); + return Objects.equals(metadata, that.metadata); } @Override public int hashCode() { - return Objects.hash(directory); + return Objects.hash(metadata); } @Override public String toString() { final StringBuilder sb = new StringBuilder("LoadVaultWorker{"); - sb.append("directory=").append(directory); + sb.append("metadata=").append(metadata); sb.append('}'); return sb.toString(); } diff --git a/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/AbstractVault.java b/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/AbstractVault.java index e68e2586c45..a5334503d3a 100644 --- a/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/AbstractVault.java +++ b/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/AbstractVault.java @@ -26,7 +26,6 @@ import ch.cyberduck.core.exception.BackgroundException; import ch.cyberduck.core.exception.UnsupportedException; import ch.cyberduck.core.features.*; -import ch.cyberduck.core.preferences.PreferencesFactory; import ch.cyberduck.core.shared.DefaultTouchFeature; import ch.cyberduck.core.transfer.TransferStatus; @@ -34,38 +33,30 @@ import org.apache.logging.log4j.Logger; import org.cryptomator.cryptolib.api.AuthenticationFailedException; import org.cryptomator.cryptolib.api.Cryptor; +import org.cryptomator.cryptolib.api.DirectoryContentCryptor; +import org.cryptomator.cryptolib.api.DirectoryMetadata; import org.cryptomator.cryptolib.api.FileContentCryptor; import org.cryptomator.cryptolib.api.FileHeaderCryptor; +import org.cryptomator.cryptolib.api.Masterkey; import java.util.EnumSet; import java.util.regex.Matcher; import java.util.regex.Pattern; -import com.google.common.io.BaseEncoding; - public abstract class AbstractVault implements Vault { private static final Logger log = LogManager.getLogger(AbstractVault.class); - public static final int VAULT_VERSION_DEPRECATED = 6; - public static final int VAULT_VERSION = PreferencesFactory.get().getInteger("cryptomator.vault.version"); - - public static final String DIR_PREFIX = "0"; - - private static final Pattern BASE32_PATTERN = Pattern.compile("^0?(([A-Z2-7]{8})*[A-Z2-7=]{8})"); + public abstract Path getMasterkeyPath(); - public abstract Path getMasterkey(); + public abstract Masterkey getMasterkey(); public abstract Path getConfig(); - public abstract int getVersion(); - public abstract FileHeaderCryptor getFileHeaderCryptor(); public abstract FileContentCryptor getFileContentCryptor(); - public abstract CryptorCache getFileNameCryptor(); - public abstract CryptoFilename getFilenameProvider(); public abstract CryptoDirectory getDirectoryProvider(); @@ -74,6 +65,8 @@ public abstract class AbstractVault implements Vault { public abstract int getNonceSize(); + public abstract Pattern getFilenamePattern(); + public int numberOfChunks(long cleartextFileSize) { return (int) (cleartextFileSize / this.getFileContentCryptor().cleartextChunkSize() + ((cleartextFileSize % this.getFileContentCryptor().cleartextChunkSize() > 0) ? 1 : 0)); @@ -159,10 +152,6 @@ public Path encrypt(Session session, Path file, boolean metadata) throws Back // Translate file size attributes.setSize(this.toCiphertextSize(0L, file.attributes().getSize())); final EnumSet type = EnumSet.copyOf(file.getType()); - if(metadata && this.getVersion() == VAULT_VERSION_DEPRECATED) { - type.remove(Path.Type.directory); - type.add(Path.Type.file); - } type.remove(Path.Type.decrypted); type.add(Path.Type.encrypted); encrypted = new Path(parent, filename, type, attributes); @@ -182,15 +171,15 @@ public Path encrypt(Session session, Path file, boolean metadata) throws Back encrypted.attributes().setDecrypted(file); } // Add reference for vault - file.attributes().setVault(this.getHome()); - encrypted.attributes().setVault(this.getHome()); + file.attributes().setVaultMetadata(this.getMetadata()); + encrypted.attributes().setVaultMetadata(this.getMetadata()); return encrypted; } @Override public Path decrypt(final Session session, final Path file) throws BackgroundException { if(file.getType().contains(Path.Type.decrypted)) { - log.warn("Skip file {} because it is already marked as an decrypted path", file); + log.warn("Skip file {} because it is already marked as a decrypted path", file); return file; } if(file.getType().contains(Path.Type.vault)) { @@ -198,14 +187,14 @@ public Path decrypt(final Session session, final Path file) throws Background return file; } final Path inflated = this.inflate(session, file); - final Pattern pattern = this.getVersion() == VAULT_VERSION_DEPRECATED ? BASE32_PATTERN : this.getBase64URLPattern(); + final Pattern pattern = this.getFilenamePattern(); final Matcher m = pattern.matcher(inflated.getName()); if(m.matches()) { - final String ciphertext = m.group(1); try { - final String cleartextFilename = this.getFileNameCryptor().decryptFilename( - this.getVersion() == VAULT_VERSION_DEPRECATED ? BaseEncoding.base32() : BaseEncoding.base64Url(), - ciphertext, this.getDirectoryProvider().getOrCreateDirectoryId(session, file.getParent())); + //TODO lädt das recovery metadaten file anstatt normales + final DirectoryContentCryptor.Decrypting decrypting = this.getFilenameDecryptor(session, file); + //TODO hier hatten wir caching via CryptorCache + final String cleartextFilename = decrypting.decrypt(inflated.getName()); final PathAttributes attributes = new PathAttributes(file.attributes()); if(this.isDirectory(inflated)) { if(Permission.EMPTY != attributes.getPermission()) { @@ -227,7 +216,7 @@ public Path decrypt(final Session session, final Path file) throws Background // Add reference to encrypted file attributes.setEncrypted(file); // Add reference for vault - attributes.setVault(this.getHome()); + attributes.setVaultMetadata(this.getMetadata()); final EnumSet type = EnumSet.copyOf(file.getType()); type.remove(this.isDirectory(inflated) ? Path.Type.file : Path.Type.directory); type.add(this.isDirectory(inflated) ? Path.Type.directory : Path.Type.file); @@ -250,10 +239,14 @@ public Path decrypt(final Session session, final Path file) throws Background } } + private DirectoryContentCryptor.Decrypting getFilenameDecryptor(final Session session, final Path directory) throws BackgroundException { + // Read directory id from file + log.debug("Read directory ID from {}", directory); + final DirectoryMetadata metadata = this.getDirectoryProvider().getOrCreateDirectoryId(session, directory.getParent()); + return this.getCryptor().directoryContentCryptor().fileNameDecryptor(metadata); + } + private boolean isDirectory(final Path p) { - if(this.getVersion() == VAULT_VERSION_DEPRECATED) { - return p.getName().startsWith(DIR_PREFIX); - } return p.isDirectory(); } @@ -284,9 +277,7 @@ public boolean contains(final Path file) { public abstract String getBackupDirectoryMetadataFilename(); - public abstract Pattern getBase64URLPattern(); - - public abstract byte[] getRootDirId(); + public abstract DirectoryMetadata getRootDirId(); @Override public synchronized void close() { @@ -315,10 +306,12 @@ public T getFeature(final Session session, final Class type, final T d return (T) new CryptoTouchFeature(session, new DefaultTouchFeature(session), this); } if(type == Directory.class) { - return (T) (this.getVersion() == VAULT_VERSION_DEPRECATED ? - new CryptoDirectoryV6Feature(session, (Directory) delegate, this) : - new CryptoDirectoryV7Feature(session, (Directory) delegate, this) - ); + //TODO + return (T) new CryptoDirectoryV7Feature(session, (Directory) delegate, this); +// return (T) (this.getVersion() == VAULT_VERSION_DEPRECATED ? +// new CryptoDirectoryV6Feature(session, (Directory) delegate, this) : +// new CryptoDirectoryV7Feature(session, (Directory) delegate, this) +// ); } if(type == Upload.class) { return (T) new CryptoUploadFeature(session, (Upload) delegate, this); @@ -336,9 +329,11 @@ public T getFeature(final Session session, final Class type, final T d return (T) new CryptoMultipartWriteFeature(session, (Write) delegate, this); } if(type == Move.class) { - return (T) (this.getVersion() == VAULT_VERSION_DEPRECATED ? - new CryptoMoveV6Feature(session, (Move) delegate, this) : - new CryptoMoveV7Feature(session, (Move) delegate, this)); + //TODO + return (T) new CryptoMoveV7Feature(session, (Move) delegate, this); +// return (T) (this.getVersion() == VAULT_VERSION_DEPRECATED ? +// new CryptoMoveV6Feature(session, (Move) delegate, this) : +// new CryptoMoveV7Feature(session, (Move) delegate, this)); } if(type == AttributesFinder.class) { @@ -357,14 +352,18 @@ public T getFeature(final Session session, final Class type, final T d return (T) new CryptoVersionIdProvider(session, (VersionIdProvider) delegate, this); } if(type == Delete.class) { - return (T) (this.getVersion() == VAULT_VERSION_DEPRECATED ? - new CryptoDeleteV6Feature(session, (Delete) delegate, this) : - new CryptoDeleteV7Feature(session, (Delete) delegate, this)); + return (T) new CryptoDeleteV7Feature(session, (Delete) delegate, this); + //TODO +// return (T) (this.getVersion() == VAULT_VERSION_DEPRECATED ? +// new CryptoDeleteV6Feature(session, (Delete) delegate, this) : +// new CryptoDeleteV7Feature(session, (Delete) delegate, this)); } if(type == Trash.class) { - return (T) (this.getVersion() == VAULT_VERSION_DEPRECATED ? - new CryptoDeleteV6Feature(session, (Delete) delegate, this) : - new CryptoDeleteV7Feature(session, (Delete) delegate, this)); + //TODO + return (T) new CryptoDeleteV7Feature(session, (Delete) delegate, this); +// return (T) (this.getVersion() == VAULT_VERSION_DEPRECATED ? +// new CryptoDeleteV6Feature(session, (Delete) delegate, this) : +// new CryptoDeleteV7Feature(session, (Delete) delegate, this)); } if(type == Symlink.class) { return (T) new CryptoSymlinkFeature(session, (Symlink) delegate, this); diff --git a/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/CryptoDirectory.java b/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/CryptoDirectory.java index dd26c1c4a15..b61023a58d5 100644 --- a/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/CryptoDirectory.java +++ b/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/CryptoDirectory.java @@ -19,6 +19,8 @@ import ch.cyberduck.core.Session; import ch.cyberduck.core.exception.BackgroundException; +import org.cryptomator.cryptolib.api.DirectoryMetadata; + import java.util.EnumSet; public interface CryptoDirectory { @@ -49,7 +51,7 @@ public interface CryptoDirectory { void destroy(); - byte[] getOrCreateDirectoryId(Session session, Path directory) throws BackgroundException; + DirectoryMetadata getOrCreateDirectoryId(Session session, Path directory) throws BackgroundException; - byte[] createDirectoryId(final Path directory); + DirectoryMetadata createDirectoryId(final Path directory); } diff --git a/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/CryptoTransferStatus.java b/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/CryptoTransferStatus.java index 0c63bdf7f48..8cc455558bc 100644 --- a/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/CryptoTransferStatus.java +++ b/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/CryptoTransferStatus.java @@ -42,7 +42,7 @@ public CryptoTransferStatus(final AbstractVault vault, final TransferStatus prox public TransferStatus setResponse(final PathAttributes attributes) { try { attributes.setSize(vault.toCleartextSize(0L, attributes.getSize())); - attributes.setVault(vault.getHome()); + attributes.setVaultMetadata(vault.getMetadata()); super.setResponse(attributes); } catch(CryptoInvalidFilesizeException e) { diff --git a/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/CryptoVaultProvider.java b/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/CryptoVaultProvider.java new file mode 100644 index 00000000000..aff3414203e --- /dev/null +++ b/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/CryptoVaultProvider.java @@ -0,0 +1,107 @@ +package ch.cyberduck.core.cryptomator; + +/* + * Copyright (c) 2002-2025 iterate GmbH. All rights reserved. + * https://cyberduck.io/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +import ch.cyberduck.core.ListProgressListener; +import ch.cyberduck.core.Path; +import ch.cyberduck.core.Session; +import ch.cyberduck.core.exception.BackgroundException; +import ch.cyberduck.core.features.Find; +import ch.cyberduck.core.preferences.HostPreferencesFactory; +import ch.cyberduck.core.vault.VaultCredentials; +import ch.cyberduck.core.vault.VaultMetadata; +import ch.cyberduck.core.vault.VaultProvider; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import java.util.EnumSet; +import java.util.Map; + +import com.google.common.collect.ImmutableMap; + +/** + * Cryptomator vault implementation + */ +public class CryptoVaultProvider implements VaultProvider { + private static final Logger log = LogManager.getLogger(CryptoVaultProvider.class); + + private final Map markers; + + public CryptoVaultProvider(final Session session) { + this.markers = ImmutableMap.of( + HostPreferencesFactory.get(session.getHost()).getProperty("cryptomator.vault.masterkey.filename"), VaultMetadata.Type.V8, + HostPreferencesFactory.get(session.getHost()).getProperty("cryptomator.vault.config.filename.uvf"), VaultMetadata.Type.UVF + ); + } + + @Override + public boolean isVault(final Path path) { + return markers.keySet().stream().anyMatch(marker -> path.getName().equals(marker)); + } + + @Override + public VaultMetadata metadata(final Path path) { + if(this.isVault(path)) { + return new VaultMetadata(path.getParent(), markers.get(path.getName())); + } + return null; + } + + @Override + public VaultMetadata find(final Path directory, final Find find, final ListProgressListener listener) throws BackgroundException { + for(String marker : markers.keySet()) { + final Path m = new Path(directory, marker, EnumSet.of(Path.Type.file)); + if(find.find(m, listener)) { + return new VaultMetadata(m.getParent(), markers.get(marker)); + } + } + return null; + } + + //TODO prompt parameter wegnehmen? + @Override + public synchronized AbstractVault provide(final Session session, final VaultMetadata metadata) { + switch(metadata.type) { + case V8: + return new ch.cyberduck.core.cryptomator.impl.v8.CryptoVault(metadata.root); + case UVF: + return new ch.cyberduck.core.cryptomator.impl.uvf.CryptoVault(metadata.root); + default: + log.error("Unknown vault type {}", metadata.type); + // TODO schmeissen, DISABLED zurück geben geht nicht weil kein AbstractVault + // throw new ... + return null; + } + } + + //TODO create methode braucht es glaube ich nicht unbedingt + + @Override + public AbstractVault create(final Session session, final String region, final VaultCredentials credentials, final VaultMetadata metadata) throws BackgroundException { + switch(metadata.type) { + case V8: + return new ch.cyberduck.core.cryptomator.impl.v8.CryptoVault(metadata.root).create(session, region, credentials); + case UVF: + return new ch.cyberduck.core.cryptomator.impl.uvf.CryptoVault(metadata.root).create(session, region, credentials); + default: + log.error("Unknown vault type {}", metadata.type); + // TODO schmeissen, DISABLED zurück geben geht nicht weil kein AbstractVault + // throw new ... + return null; + } + } +} \ No newline at end of file diff --git a/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/features/CryptoAttributesFeature.java b/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/features/CryptoAttributesFeature.java index 5276d3e3d03..3b66ca2b21a 100644 --- a/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/features/CryptoAttributesFeature.java +++ b/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/features/CryptoAttributesFeature.java @@ -51,7 +51,7 @@ public PathAttributes find(final Path file, final ListProgressListener listener) if(file.isDirectory()) { attributes.setSize(-1L); } - attributes.setVault(vault.getHome()); + attributes.setVaultMetadata(vault.getMetadata()); return attributes; } diff --git a/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/features/CryptoBulkFeature.java b/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/features/CryptoBulkFeature.java index 4817cf1a8d2..2aa4f98ff72 100644 --- a/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/features/CryptoBulkFeature.java +++ b/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/features/CryptoBulkFeature.java @@ -82,6 +82,7 @@ public int compare(final Map.Entry o1, final Map.E if(!status.isExists()) { switch(type) { case upload: + cryptomator.getDirectoryProvider().createDirectoryId(file); encrypted.put(new TransferItem(cryptomator.encrypt(session, file, false), local), status); break; default: diff --git a/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/features/CryptoDeleteV6Feature.java b/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/features/CryptoDeleteV6Feature.java deleted file mode 100644 index 5fcb7b07a5d..00000000000 --- a/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/features/CryptoDeleteV6Feature.java +++ /dev/null @@ -1,142 +0,0 @@ -package ch.cyberduck.core.cryptomator.features; - -/* - * Copyright (c) 2002-2020 iterate GmbH. All rights reserved. - * https://cyberduck.io/ - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -import ch.cyberduck.core.DisabledListProgressListener; -import ch.cyberduck.core.ListService; -import ch.cyberduck.core.PasswordCallback; -import ch.cyberduck.core.Path; -import ch.cyberduck.core.Session; -import ch.cyberduck.core.cryptomator.AbstractVault; -import ch.cyberduck.core.cryptomator.CryptoFilename; -import ch.cyberduck.core.exception.AccessDeniedException; -import ch.cyberduck.core.exception.BackgroundException; -import ch.cyberduck.core.exception.NotfoundException; -import ch.cyberduck.core.features.Delete; -import ch.cyberduck.core.features.Find; -import ch.cyberduck.core.features.Trash; -import ch.cyberduck.core.transfer.TransferStatus; - -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.EnumSet; -import java.util.List; -import java.util.Map; - -public class CryptoDeleteV6Feature implements Delete, Trash { - private static final Logger log = LogManager.getLogger(CryptoDeleteV6Feature.class); - - private final Session session; - private final Delete proxy; - private final AbstractVault vault; - private final CryptoFilename filenameProvider; - - public CryptoDeleteV6Feature(final Session session, final Delete proxy, final AbstractVault vault) { - this.session = session; - this.proxy = proxy; - this.vault = vault; - this.filenameProvider = vault.getFilenameProvider(); - } - - @Override - public void delete(final Map files, final PasswordCallback prompt, final Callback callback) throws BackgroundException { - for(Path f : files.keySet()) { - final List metadataFiles = new ArrayList<>(); - if(!f.equals(vault.getHome())) { - final Path encrypt = vault.encrypt(session, f); - try { - proxy.delete(Collections.singletonList(encrypt), prompt, callback); - } - catch(NotfoundException | AccessDeniedException e) { - if(f.isDirectory()) { - log.error("Failure {} deleting directory {}", e, encrypt); - } - else { - throw e; - } - } - final Path metadata = vault.encrypt(session, f, true); - if(f.isDirectory()) { - // Delete metadata file for directory - log.debug("Add metadata file {}", metadata); - metadataFiles.add(metadata); - vault.getDirectoryProvider().delete(f); - } - if(filenameProvider.isDeflated(metadata.getName())) { - filenameProvider.invalidate(filenameProvider.inflate(session, metadata.getName())); - final Path metadataFile = filenameProvider.resolve(metadata.getName()); - log.debug("Add metadata file {}", metadata); - metadataFiles.add(metadataFile); - } - } - if(!metadataFiles.isEmpty()) { - proxy.delete(metadataFiles, prompt, callback); - } - } - for(Path f : files.keySet()) { - if(f.equals(vault.getHome())) { - log.warn("Recursively delete vault {}", f); - final List metadata = new ArrayList<>(); - if(!proxy.features(f).contains(Delete.Flags.recursive)) { - final Find find = session._getFeature(Find.class); - final Path dataRoot = new Path(f, "d", f.getType()); - if(find.find(dataRoot)) { - for(Path d : session._getFeature(ListService.class).list(dataRoot, new DisabledListProgressListener()).toList()) { - metadata.addAll(session._getFeature(ListService.class).list(d, new DisabledListProgressListener()).toList()); - metadata.add(d); - } - metadata.add(dataRoot); - } - final Path metaRoot = new Path(f, "m", f.getType()); - if(find.find(metaRoot)) { - for(Path m : session._getFeature(ListService.class).list(metaRoot, new DisabledListProgressListener()).toList()) { - for(Path m2 : session._getFeature(ListService.class).list(m, new DisabledListProgressListener()).toList()) { - metadata.addAll(session._getFeature(ListService.class).list(m2, new DisabledListProgressListener()).toList()); - metadata.add(m2); - } - metadata.add(m); - } - metadata.add(metaRoot); - } - metadata.add(vault.getMasterkey()); - } - metadata.add(f); - proxy.delete(metadata, prompt, callback); - } - } - } - - @Override - public void preflight(final Path file) throws BackgroundException { - proxy.preflight(vault.encrypt(session, file)); - } - - @Override - public EnumSet features(final Path file) { - return proxy.features(file); - } - - @Override - public String toString() { - final StringBuilder sb = new StringBuilder("CryptoDeleteV6Feature{"); - sb.append("proxy=").append(proxy); - sb.append('}'); - return sb.toString(); - } -} diff --git a/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/features/CryptoDeleteV7Feature.java b/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/features/CryptoDeleteV7Feature.java index 310466c6696..1c8c02c26bd 100644 --- a/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/features/CryptoDeleteV7Feature.java +++ b/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/features/CryptoDeleteV7Feature.java @@ -124,8 +124,8 @@ public void delete(final Map files, final PasswordCallback } metadata.add(dataRoot); } - if(vault.getMasterkey() != null) { - metadata.add(vault.getMasterkey()); + if(vault.getMasterkeyPath() != null) { + metadata.add(vault.getMasterkeyPath()); } if(find.find(vault.getConfig())) { metadata.add(vault.getConfig()); diff --git a/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/features/CryptoDirectoryUVFFeature.java b/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/features/CryptoDirectoryUVFFeature.java index 35ecba509d0..82c920466db 100644 --- a/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/features/CryptoDirectoryUVFFeature.java +++ b/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/features/CryptoDirectoryUVFFeature.java @@ -28,9 +28,9 @@ import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; +import org.cryptomator.cryptolib.api.DirectoryMetadata; import org.cryptomator.cryptolib.api.FileHeader; -import java.nio.ByteBuffer; import java.util.EnumSet; public class CryptoDirectoryUVFFeature extends CryptoDirectoryV7Feature { @@ -47,9 +47,10 @@ public CryptoDirectoryUVFFeature(final Session session, final Directory writer, final Path folder, final TransferStatus status) throws BackgroundException { - final byte[] directoryId = vault.getDirectoryProvider().createDirectoryId(folder); + final DirectoryMetadata dirMetadata = vault.getDirectoryProvider().createDirectoryId(folder); // Create metadata file for directory final Path directoryMetadataFolder = session._getFeature(Directory.class).mkdir( session._getFeature(Write.class), vault.encrypt(session, folder, true), new TransferStatus().setRegion(status.getRegion())); @@ -57,13 +58,15 @@ public Path mkdir(final Write writer, final Path folder, final TransferSt vault.getDirectoryMetadataFilename(), EnumSet.of(Path.Type.file)); log.debug("Write metadata {} for folder {}", directoryMetadataFile, folder); - new ContentWriter(session).write(directoryMetadataFile, this.encryptDirectoryMetadataWithCurrentRevision(directoryId)); + final byte[] encryptedMetadata = this.vault.getCryptor().directoryContentCryptor().encryptDirectoryMetadata(dirMetadata); + new ContentWriter(session).write(directoryMetadataFile, encryptedMetadata); final Path encrypt = vault.encrypt(session, folder, false); final Path intermediate = encrypt.getParent(); if(!session._getFeature(Find.class).find(intermediate)) { session._getFeature(Directory.class).mkdir( session._getFeature(Write.class), intermediate, new TransferStatus().setRegion(status.getRegion())); } + // Write metadata final FileHeader header = vault.getFileHeaderCryptor().create(); status.setHeader(vault.getFileHeaderCryptor().encryptHeader(header)); @@ -73,10 +76,9 @@ public Path mkdir(final Write writer, final Path folder, final TransferSt vault.getDirectoryMetadataFilename(), EnumSet.of(Path.Type.file)); log.debug("Write recovery metadata {} for folder {}", recoveryDirectoryMetadataFile, folder); - new ContentWriter(session).write(recoveryDirectoryMetadataFile, this.encryptDirectoryMetadataWithCurrentRevision(directoryId)); + new ContentWriter(session).write(recoveryDirectoryMetadataFile, this.vault.getCryptor().directoryContentCryptor().encryptDirectoryMetadata(dirMetadata)); // Implementation may return new copy of attributes without encryption attributes - - target.attributes().setDirectoryId(directoryId); + target.attributes().setDirectoryId(encryptedMetadata); target.attributes().setDecrypted(folder); // Make reference of encrypted path in attributes of decrypted file point to metadata file final Path decrypt = vault.decrypt(session, vault.encrypt(session, target, true)); @@ -85,18 +87,6 @@ public Path mkdir(final Write writer, final Path folder, final TransferSt return decrypt; } - // TODO replace with DirectoryContentCryptor#encryptDirectoryMetadata once we have access to dirId - private byte[] encryptDirectoryMetadataWithCurrentRevision(final byte[] dirId) { - final ByteBuffer cleartextBuf = ByteBuffer.wrap(dirId); - final FileHeader header = vault.getCryptor().fileHeaderCryptor().create(); - final ByteBuffer headerBuf = vault.getCryptor().fileHeaderCryptor().encryptHeader(header); - final ByteBuffer contentBuf = vault.getCryptor().fileContentCryptor().encryptChunk(cleartextBuf, 0, header); - final byte[] result = new byte[headerBuf.remaining() + contentBuf.remaining()]; - headerBuf.get(result, 0, headerBuf.remaining()); - contentBuf.get(result, headerBuf.limit(), contentBuf.remaining()); - return result; - } - @Override public String toString() { final StringBuilder sb = new StringBuilder("CryptoDirectoryUVFFeature{"); diff --git a/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/features/CryptoDirectoryV6Feature.java b/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/features/CryptoDirectoryV6Feature.java deleted file mode 100644 index 4a5520e6669..00000000000 --- a/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/features/CryptoDirectoryV6Feature.java +++ /dev/null @@ -1,93 +0,0 @@ -package ch.cyberduck.core.cryptomator.features; - -/* - * Copyright (c) 2002-2020 iterate GmbH. All rights reserved. - * https://cyberduck.io/ - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -import ch.cyberduck.core.Path; -import ch.cyberduck.core.RandomStringService; -import ch.cyberduck.core.Session; -import ch.cyberduck.core.UUIDRandomStringService; -import ch.cyberduck.core.cryptomator.AbstractVault; -import ch.cyberduck.core.cryptomator.ContentWriter; -import ch.cyberduck.core.cryptomator.random.RandomNonceGenerator; -import ch.cyberduck.core.exception.BackgroundException; -import ch.cyberduck.core.features.Directory; -import ch.cyberduck.core.features.Find; -import ch.cyberduck.core.features.Write; -import ch.cyberduck.core.transfer.TransferStatus; - -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; -import org.cryptomator.cryptolib.api.FileHeader; - -public class CryptoDirectoryV6Feature implements Directory { - private static final Logger log = LogManager.getLogger(CryptoDirectoryV6Feature.class); - - private final Session session; - private final Directory delegate; - private final AbstractVault vault; - private final RandomStringService random = new UUIDRandomStringService(); - - public CryptoDirectoryV6Feature(final Session session, final Directory delegate, final AbstractVault cryptomator) { - this.session = session; - this.delegate = delegate; - this.vault = cryptomator; - } - - @Override - public Path mkdir(final Write writer, final Path folder, final TransferStatus status) throws BackgroundException { - final byte[] directoryId = vault.getDirectoryProvider().createDirectoryId(folder); - final Path encrypt = vault.encrypt(session, folder, false); - // Create metadata file for directory - final Path directoryMetadataFile = vault.encrypt(session, folder, true); - log.debug("Write metadata {} for folder {}", directoryMetadataFile, folder); - new ContentWriter(session).write(directoryMetadataFile, directoryId); - final Path intermediate = encrypt.getParent(); - if(!session._getFeature(Find.class).find(intermediate)) { - session._getFeature(Directory.class).mkdir(session._getFeature(Write.class), intermediate, new TransferStatus().setRegion(status.getRegion())); - } - // Write header - final FileHeader header = vault.getFileHeaderCryptor().create(); - status.setHeader(vault.getFileHeaderCryptor().encryptHeader(header)); - status.setNonces(new RandomNonceGenerator(vault.getNonceSize())); - final Path target = delegate.mkdir(writer, encrypt, status); - // Implementation may return new copy of attributes without encryption attributes - target.attributes().setDirectoryId(directoryId); - target.attributes().setDecrypted(folder); - // Make reference of encrypted path in attributes of decrypted file point to metadata file - final Path decrypt = vault.decrypt(session, vault.encrypt(session, target, true)); - decrypt.attributes().setFileId(directoryMetadataFile.attributes().getFileId()); - decrypt.attributes().setVersionId(directoryMetadataFile.attributes().getVersionId()); - return decrypt; - } - - @Override - public boolean isSupported(final Path workdir, final String name) { - return delegate.isSupported(workdir, name); - } - - @Override - public void preflight(final Path workdir, final String filename) throws BackgroundException { - delegate.preflight(vault.encrypt(session, workdir), filename); - } - - @Override - public String toString() { - final StringBuilder sb = new StringBuilder("CryptoDirectoryV6Feature{"); - sb.append("proxy=").append(delegate); - sb.append('}'); - return sb.toString(); - } -} diff --git a/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/features/CryptoDirectoryV7Feature.java b/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/features/CryptoDirectoryV7Feature.java index a887acae6ea..20ed3259674 100644 --- a/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/features/CryptoDirectoryV7Feature.java +++ b/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/features/CryptoDirectoryV7Feature.java @@ -28,6 +28,7 @@ import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; +import org.cryptomator.cryptolib.api.DirectoryMetadata; import org.cryptomator.cryptolib.api.FileHeader; import java.util.EnumSet; @@ -47,7 +48,7 @@ public CryptoDirectoryV7Feature(final Session session, final Directory @Override public Path mkdir(final Write writer, final Path folder, final TransferStatus status) throws BackgroundException { - final byte[] directoryId = vault.getDirectoryProvider().createDirectoryId(folder); + final DirectoryMetadata dirMetadata = vault.getDirectoryProvider().createDirectoryId(folder); // Create metadata file for directory final Path directoryMetadataFolder = session._getFeature(Directory.class).mkdir( session._getFeature(Write.class), vault.encrypt(session, folder, true), @@ -56,7 +57,8 @@ public Path mkdir(final Write writer, final Path folder, final TransferSt vault.getDirectoryMetadataFilename(), EnumSet.of(Path.Type.file)); log.debug("Write metadata {} for folder {}", directoryMetadataFile, folder); - new ContentWriter(session).write(directoryMetadataFile, directoryId); + final byte[] encryptedMetadata = this.vault.getCryptor().directoryContentCryptor().encryptDirectoryMetadata(dirMetadata); + new ContentWriter(session).write(directoryMetadataFile, encryptedMetadata); final Path encrypt = vault.encrypt(session, folder, false); final Path intermediate = encrypt.getParent(); if(!session._getFeature(Find.class).find(intermediate)) { @@ -68,7 +70,7 @@ public Path mkdir(final Write writer, final Path folder, final TransferSt status.setNonces(new RandomNonceGenerator(vault.getNonceSize())); final Path target = delegate.mkdir(writer, encrypt, status); // Implementation may return new copy of attributes without encryption attributes - target.attributes().setDirectoryId(directoryId); + target.attributes().setDirectoryId(encryptedMetadata); target.attributes().setDecrypted(folder); // Make reference of encrypted path in attributes of decrypted file point to metadata file final Path decrypt = vault.decrypt(session, vault.encrypt(session, target, true)); diff --git a/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/features/CryptoMoveV6Feature.java b/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/features/CryptoMoveV6Feature.java deleted file mode 100644 index e6d80abba7c..00000000000 --- a/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/features/CryptoMoveV6Feature.java +++ /dev/null @@ -1,92 +0,0 @@ -package ch.cyberduck.core.cryptomator.features; - -/* - * Copyright (c) 2002-2017 iterate GmbH. All rights reserved. - * https://cyberduck.io/ - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -import ch.cyberduck.core.ConnectionCallback; -import ch.cyberduck.core.LocaleFactory; -import ch.cyberduck.core.Path; -import ch.cyberduck.core.Session; -import ch.cyberduck.core.cryptomator.AbstractVault; -import ch.cyberduck.core.exception.BackgroundException; -import ch.cyberduck.core.exception.InvalidFilenameException; -import ch.cyberduck.core.features.Delete; -import ch.cyberduck.core.features.Move; -import ch.cyberduck.core.transfer.TransferStatus; - -import java.text.MessageFormat; -import java.util.EnumSet; -import java.util.Optional; - -public class CryptoMoveV6Feature implements Move { - - private final Session session; - private final Move proxy; - private final AbstractVault vault; - - public CryptoMoveV6Feature(final Session session, final Move delegate, final AbstractVault cryptomator) { - this.session = session; - this.proxy = delegate; - this.vault = cryptomator; - } - - @Override - public Path move(final Path file, final Path renamed, final TransferStatus status, final Delete.Callback callback, final ConnectionCallback connectionCallback) throws BackgroundException { - // Move inside vault moves actual files and only metadata files for directories but not the actual directories - final Path target = proxy.move( - vault.encrypt(session, file, file.isDirectory()), - vault.encrypt(session, renamed, file.isDirectory()), status, callback, connectionCallback); - if(file.isDirectory()) { - vault.getDirectoryProvider().delete(file); - } - if(vault.contains(target)) { - return vault.decrypt(session, target); - } - return target; - } - - @Override - public EnumSet features(final Path source, final Path target) { - // No need to handle recursion with encrypted filenames - return EnumSet.of(Flags.recursive); - } - - @Override - public void preflight(final Path source, final Optional target) throws BackgroundException { - if(target.isPresent()) { - if(!vault.getFilenameProvider().isValid(target.get().getName())) { - throw new InvalidFilenameException(MessageFormat.format(LocaleFactory.localizedString("Cannot create {0}", "Error"), target.get().getName())).withFile(source); - } - proxy.preflight(vault.encrypt(session, source, source.isDirectory()), Optional.of(vault.encrypt(session, target.get(), source.isDirectory()))); - } - else { - proxy.preflight(vault.encrypt(session, source, source.isDirectory()), target); - } - } - - @Override - public Move withTarget(final Session session) { - proxy.withTarget(session); - return this; - } - - @Override - public String toString() { - final StringBuilder sb = new StringBuilder("CryptoMoveFeature{"); - sb.append("proxy=").append(proxy); - sb.append('}'); - return sb.toString(); - } -} diff --git a/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/impl/CryptoDirectoryUVFProvider.java b/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/impl/CryptoDirectoryUVFProvider.java index 60a1e6297f7..4ea8fa352ee 100644 --- a/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/impl/CryptoDirectoryUVFProvider.java +++ b/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/impl/CryptoDirectoryUVFProvider.java @@ -16,106 +16,45 @@ */ import ch.cyberduck.core.Path; -import ch.cyberduck.core.PathAttributes; import ch.cyberduck.core.Session; import ch.cyberduck.core.SimplePathPredicate; import ch.cyberduck.core.cryptomator.AbstractVault; import ch.cyberduck.core.cryptomator.ContentReader; import ch.cyberduck.core.cryptomator.CryptoFilename; -import ch.cyberduck.core.cryptomator.CryptorCache; -import ch.cyberduck.core.cryptomator.random.FastSecureRandomProvider; import ch.cyberduck.core.exception.BackgroundException; import ch.cyberduck.core.exception.NotfoundException; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; -import org.cryptomator.cryptolib.api.FileHeader; +import org.cryptomator.cryptolib.api.DirectoryMetadata; -import java.nio.ByteBuffer; -import java.nio.ByteOrder; -import java.security.SecureRandom; import java.util.EnumSet; -import com.google.common.io.BaseEncoding; - -public class CryptoDirectoryUVFProvider extends CryptoDirectoryV7Provider { +public class CryptoDirectoryUVFProvider extends CryptoDirectoryV8Provider { private static final Logger log = LogManager.getLogger(CryptoDirectoryUVFProvider.class); private final Path home; private final AbstractVault vault; - - private final SecureRandom random - = FastSecureRandomProvider.get().provide(); - private final Path dataRoot; - private final CryptorCache filenameCryptor; private final CryptoFilename filenameProvider; - public CryptoDirectoryUVFProvider(final AbstractVault vault, final CryptoFilename filenameProvider, final CryptorCache filenameCryptor) { - super(vault, filenameProvider, filenameCryptor); - this.filenameCryptor = filenameCryptor; + public CryptoDirectoryUVFProvider(final AbstractVault vault, final CryptoFilename filenameProvider) { + super(vault, filenameProvider); this.filenameProvider = filenameProvider; this.home = vault.getHome(); this.vault = vault; - this.dataRoot = new Path(home, "d", home.getType()); - } - - @Override - protected byte[] toDirectoryId(final Session session, final Path directory) throws BackgroundException { - if(new SimplePathPredicate(home).test(directory)) { - return vault.getRootDirId(); - } - return super.toDirectoryId(session, directory); } + //TODO kann das auch ersetzt werden mit der impl der superklasse? hier wird load verwendet? nötig? @Override public String toEncrypted(final Session session, final Path parent, final String filename, final EnumSet type) throws BackgroundException { - if(new SimplePathPredicate(home).test(parent)) { - final String ciphertextName = filenameCryptor.encryptFilename(BaseEncoding.base64Url(), filename, vault.getRootDirId()) + vault.getRegularFileExtension(); - log.debug("Encrypted filename {} to {}", filename, ciphertextName); - return filenameProvider.deflate(session, ciphertextName); - - } - final byte[] directoryId = load(session, parent); - final String ciphertextName = vault.getCryptor().fileNameCryptor(loadRevision(session, parent)).encryptFilename(BaseEncoding.base64Url(), filename, directoryId) + vault.getRegularFileExtension(); + final DirectoryMetadata dirMetadata = load(session, parent); + this.vault.getCryptor().directoryContentCryptor().fileNameEncryptor(dirMetadata).encrypt(filename); + final String ciphertextName = this.vault.getCryptor().directoryContentCryptor().fileNameEncryptor(dirMetadata).encrypt(filename) + vault.getRegularFileExtension(); log.debug("Encrypted filename {} to {}", filename, ciphertextName); return filenameProvider.deflate(session, ciphertextName); } - @Override - public Path toEncrypted(final Session session, final Path directory) throws BackgroundException { - if(!directory.isDirectory()) { - throw new NotfoundException(directory.getAbsolute()); - } - if(new SimplePathPredicate(directory).test(home) || directory.isChild(home)) { - final PathAttributes attributes = new PathAttributes(directory.attributes()); - // The root of the vault is a different target directory and file ids always correspond to the metadata file - attributes.setVersionId(null); - attributes.setFileId(null); - // Remember random directory id for use in vault - final byte[] id = this.getOrCreateDirectoryId(session, directory); - log.debug("Use directory ID '{}' for folder {}", id, directory); - attributes.setDirectoryId(id); - attributes.setDecrypted(directory); - final String directoryIdHash; - if(new SimplePathPredicate(home).test(directory)) { - // TODO hard-coded to initial seed in UVFVault - directoryIdHash = filenameCryptor.hashDirectoryId(id); - } - else { - directoryIdHash = vault.getCryptor().fileNameCryptor(loadRevision(session, directory)).hashDirectoryId(id); - } - // Intermediate directory - final Path intermediate = new Path(dataRoot, directoryIdHash.substring(0, 2), dataRoot.getType()); - // Add encrypted type - final EnumSet type = EnumSet.copyOf(directory.getType()); - type.add(Path.Type.encrypted); - type.remove(Path.Type.decrypted); - return new Path(intermediate, directoryIdHash.substring(2), type, attributes); - } - throw new NotfoundException(directory.getAbsolute()); - } - - protected byte[] load(final Session session, final Path directory) throws BackgroundException { + protected DirectoryMetadata load(final Session session, final Path directory) throws BackgroundException { if(new SimplePathPredicate(home).test(directory)) { return vault.getRootDirId(); } @@ -128,63 +67,11 @@ protected byte[] load(final Session session, final Path directory) throws Bac log.debug("Read directory ID for folder {} from {}", directory, ciphertextName); final Path metadataFile = new Path(metadataParent, vault.getDirectoryMetadataFilename(), EnumSet.of(Path.Type.file, Path.Type.encrypted)); final byte[] ciphertext = new ContentReader(session).readBytes(metadataFile); - // https://github.com/encryption-alliance/unified-vault-format/blob/develop/file%20name%20encryption/AES-SIV-512-B64URL.md#format-of-diruvf-and-symlinkuvf - // TODO can we not use org.cryptomator.cryptolib.v3.DirectoryContentCryptorImpl.decryptDirectoryMetadata()? DirectoryMetadataImpl is not visible and DirectoryMetadata is empty interface, so we cannot access dirId attribute. - if(ciphertext.length != 128) { - throw new IllegalArgumentException("Invalid dir.uvf length: " + ciphertext.length); - } - int headerSize = vault.getCryptor().fileHeaderCryptor().headerSize(); - ByteBuffer buffer = ByteBuffer.wrap(ciphertext); - ByteBuffer headerBuf = buffer.duplicate(); - headerBuf.position(0).limit(headerSize); - ByteBuffer contentBuf = buffer.duplicate(); - contentBuf.position(headerSize); - - FileHeader header = vault.getCryptor().fileHeaderCryptor(loadRevision(session, directory)).decryptHeader(headerBuf); - ByteBuffer plaintext = vault.getCryptor().fileContentCryptor().decryptChunk(contentBuf, 0, header, true); - assert plaintext.remaining() == 32; - byte[] dirId = new byte[32]; - plaintext.get(dirId); - return dirId; + return this.vault.getCryptor().directoryContentCryptor().decryptDirectoryMetadata(ciphertext); } catch(NotfoundException e) { log.warn("Missing directory ID for folder {}", directory); return this.getOrCreateDirectoryId(session, directory); } } - - protected int loadRevision(final Session session, final Path directory) throws BackgroundException { - final Path parent = this.toEncrypted(session, directory.getParent()); - final String cleartextName = directory.getName(); - final String ciphertextName = this.toEncrypted(session, directory.getParent(), cleartextName, EnumSet.of(Path.Type.directory)); - final Path metadataParent = new Path(parent, ciphertextName, EnumSet.of(Path.Type.directory)); - // Read directory id from file - log.debug("Read directory ID for folder {} from {}", directory, ciphertextName); - final Path metadataFile = new Path(metadataParent, vault.getDirectoryMetadataFilename(), EnumSet.of(Path.Type.file, Path.Type.encrypted)); - final byte[] ciphertext = new ContentReader(session).readBytes(metadataFile); - // https://github.com/encryption-alliance/unified-vault-format/blob/develop/file%20name%20encryption/AES-SIV-512-B64URL.md#format-of-diruvf-and-symlinkuvf - // TODO can we not use org.cryptomator.cryptolib.v3.DirectoryContentCryptorImpl.decryptDirectoryMetadata()? DirectoryMetadataImpl is not visible and DirectoryMetadata is empty interface, so we cannot access dirId attribute. - if(ciphertext.length != 128) { - throw new IllegalArgumentException("Invalid dir.uvf length: " + ciphertext.length); - } - int headerSize = vault.getCryptor().fileHeaderCryptor().headerSize(); - ByteBuffer buffer = ByteBuffer.wrap(ciphertext); - ByteBuffer headerBuf = buffer.duplicate(); - headerBuf.position(4).limit(headerSize); - return headerBuf.order(ByteOrder.BIG_ENDIAN).getInt(); - } - - @Override - public byte[] createDirectoryId(final Path directory) { - lock.writeLock().lock(); - try { - final byte[] dirId = new byte[32]; - random.nextBytes(dirId); - cache.put(new SimplePathPredicate(directory), dirId); - return dirId; - } - finally { - lock.writeLock().unlock(); - } - } } diff --git a/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/impl/CryptoDirectoryV7Provider.java b/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/impl/CryptoDirectoryV7Provider.java deleted file mode 100644 index bdf17923b62..00000000000 --- a/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/impl/CryptoDirectoryV7Provider.java +++ /dev/null @@ -1,77 +0,0 @@ -package ch.cyberduck.core.cryptomator.impl; - -/* - * Copyright (c) 2002-2020 iterate GmbH. All rights reserved. - * https://cyberduck.io/ - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -import ch.cyberduck.core.Path; -import ch.cyberduck.core.RandomStringService; -import ch.cyberduck.core.Session; -import ch.cyberduck.core.UUIDRandomStringService; -import ch.cyberduck.core.cryptomator.AbstractVault; -import ch.cyberduck.core.cryptomator.ContentReader; -import ch.cyberduck.core.cryptomator.CryptoFilename; -import ch.cyberduck.core.cryptomator.CryptorCache; -import ch.cyberduck.core.exception.BackgroundException; -import ch.cyberduck.core.exception.NotfoundException; - -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; - -import java.nio.charset.StandardCharsets; -import java.util.EnumSet; - -import com.google.common.io.BaseEncoding; - -public class CryptoDirectoryV7Provider extends CryptoDirectoryV6Provider { - private static final Logger log = LogManager.getLogger(CryptoDirectoryV7Provider.class); - - private final CryptoFilename filenameProvider; - private final CryptorCache filenameCryptor; - private final AbstractVault vault; - - private final RandomStringService random - = new UUIDRandomStringService(); - - public CryptoDirectoryV7Provider(final AbstractVault vault, final CryptoFilename filenameProvider, final CryptorCache filenameCryptor) { - super(vault.getHome(), filenameProvider, filenameCryptor); - this.filenameProvider = filenameProvider; - this.filenameCryptor = filenameCryptor; - this.vault = vault; - } - - @Override - public String toEncrypted(final Session session, final Path parent, final String filename, final EnumSet type) throws BackgroundException { - final String ciphertextName = filenameCryptor.encryptFilename(BaseEncoding.base64Url(), filename, this.getOrCreateDirectoryId(session, parent)) + vault.getRegularFileExtension(); - log.debug("Encrypted filename {} to {}", filename, ciphertextName); - return filenameProvider.deflate(session, ciphertextName); - } - - protected byte[] load(final Session session, final Path directory) throws BackgroundException { - final Path encryptedParent = this.toEncrypted(session, directory.getParent()); - final String cleartextName = directory.getName(); - final String ciphertextName = this.toEncrypted(session, directory.getParent(), cleartextName, EnumSet.of(Path.Type.directory)); - final Path metadataParent = new Path(encryptedParent, ciphertextName, EnumSet.of(Path.Type.directory)); - // Read directory id from file - try { - log.debug("Read directory ID for folder {} from {}", directory, ciphertextName); - final Path metadataFile = new Path(metadataParent, vault.getDirectoryMetadataFilename(), EnumSet.of(Path.Type.file, Path.Type.encrypted)); - return new ContentReader(session).readBytes(metadataFile); - } - catch(NotfoundException e) { - log.warn("Missing directory ID for folder {}", directory); - return random.random().getBytes(StandardCharsets.US_ASCII); - } - } -} diff --git a/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/impl/CryptoDirectoryV6Provider.java b/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/impl/CryptoDirectoryV8Provider.java similarity index 59% rename from cryptomator/src/main/java/ch/cyberduck/core/cryptomator/impl/CryptoDirectoryV6Provider.java rename to cryptomator/src/main/java/ch/cyberduck/core/cryptomator/impl/CryptoDirectoryV8Provider.java index 4113ad94afc..04faac5007b 100644 --- a/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/impl/CryptoDirectoryV6Provider.java +++ b/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/impl/CryptoDirectoryV8Provider.java @@ -24,54 +24,53 @@ import ch.cyberduck.core.SimplePathPredicate; import ch.cyberduck.core.UUIDRandomStringService; import ch.cyberduck.core.cache.LRUCache; +import ch.cyberduck.core.cryptomator.AbstractVault; import ch.cyberduck.core.cryptomator.ContentReader; import ch.cyberduck.core.cryptomator.CryptoDirectory; import ch.cyberduck.core.cryptomator.CryptoFilename; -import ch.cyberduck.core.cryptomator.CryptoVault; -import ch.cyberduck.core.cryptomator.CryptorCache; import ch.cyberduck.core.exception.BackgroundException; import ch.cyberduck.core.exception.NotfoundException; import ch.cyberduck.core.preferences.PreferencesFactory; +import org.apache.commons.lang3.StringUtils; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; +import org.cryptomator.cryptolib.api.DirectoryMetadata; -import java.nio.charset.StandardCharsets; import java.util.EnumSet; import java.util.concurrent.locks.ReadWriteLock; import java.util.concurrent.locks.ReentrantReadWriteLock; -public class CryptoDirectoryV6Provider implements CryptoDirectory { - private static final Logger log = LogManager.getLogger(CryptoDirectoryV6Provider.class); +public class CryptoDirectoryV8Provider implements CryptoDirectory { + private static final Logger log = LogManager.getLogger(CryptoDirectoryV8Provider.class); private static final String DATA_DIR_NAME = "d"; + private final AbstractVault vault; private final Path dataRoot; private final Path home; private final CryptoFilename filenameProvider; - private final CryptorCache filenameCryptor; private final RandomStringService random = new UUIDRandomStringService(); protected final ReadWriteLock lock = new ReentrantReadWriteLock(); - protected final LRUCache, byte[]> cache = LRUCache.build( PreferencesFactory.get().getInteger("cryptomator.cache.size")); - public static final byte[] ROOT_DIR_ID = new byte[0]; - public CryptoDirectoryV6Provider(final Path vault, final CryptoFilename filenameProvider, final CryptorCache filenameCryptor) { - this.home = vault; - this.dataRoot = new Path(vault, DATA_DIR_NAME, vault.getType()); + public CryptoDirectoryV8Provider(final AbstractVault vault, final CryptoFilename filenameProvider) { + this.home = vault.getHome(); + this.dataRoot = new Path(vault.getHome(), DATA_DIR_NAME, vault.getHome().getType()); this.filenameProvider = filenameProvider; - this.filenameCryptor = filenameCryptor; + this.vault = vault; } @Override public String toEncrypted(final Session session, final Path parent, final String filename, final EnumSet type) throws BackgroundException { - final String prefix = type.contains(Path.Type.directory) ? CryptoVault.DIR_PREFIX : ""; - final String ciphertextName = prefix + filenameCryptor.encryptFilename(CryptorCache.BASE32, filename, this.getOrCreateDirectoryId(session, parent)); + final DirectoryMetadata dirMetadata = this.getOrCreateDirectoryId(session, parent); + this.vault.getCryptor().directoryContentCryptor().fileNameEncryptor(dirMetadata).encrypt(filename); + final String ciphertextName = this.vault.getCryptor().directoryContentCryptor().fileNameEncryptor(dirMetadata).encrypt(filename); log.debug("Encrypted filename {} to {}", filename, ciphertextName); return filenameProvider.deflate(session, ciphertextName); } @@ -86,31 +85,32 @@ public Path toEncrypted(final Session session, final Path directory) throws B // The root of the vault is a different target directory and file ids always correspond to the metadata file attributes.setVersionId(null); attributes.setFileId(null); - // Remember random directory id for use in vault - final byte[] id = this.getOrCreateDirectoryId(session, directory); - log.debug("Use directory ID '{}' for folder {}", id, directory); - attributes.setDirectoryId(id); + // Remember random directory metadata for use in vault + final DirectoryMetadata dirMetadata = this.getOrCreateDirectoryId(session, directory); + log.debug("Use directory ID '{}' for folder {}", dirMetadata, directory); + attributes.setDirectoryId(this.vault.getCryptor().directoryContentCryptor().encryptDirectoryMetadata(dirMetadata)); attributes.setDecrypted(directory); - final String directoryIdHash = filenameCryptor.hashDirectoryId(id); + final String dirPath = this.vault.getCryptor().directoryContentCryptor().dirPath(dirMetadata); + final String[] segments = StringUtils.split(dirPath, '/'); // Intermediate directory - final Path intermediate = new Path(dataRoot, directoryIdHash.substring(0, 2), dataRoot.getType()); + final Path intermediate = new Path(dataRoot, segments[1], dataRoot.getType()); // Add encrypted type final EnumSet type = EnumSet.copyOf(directory.getType()); type.add(Path.Type.encrypted); type.remove(Path.Type.decrypted); - return new Path(intermediate, directoryIdHash.substring(2), type, attributes); + return new Path(intermediate, segments[2], type, attributes); } throw new NotfoundException(directory.getAbsolute()); } - protected byte[] toDirectoryId(final Session session, final Path directory) throws BackgroundException { + protected DirectoryMetadata toDirectoryId(final Session session, final Path directory) throws BackgroundException { if(new SimplePathPredicate(home).test(directory)) { - return ROOT_DIR_ID; + return this.vault.getRootDirId(); } lock.readLock().lock(); try { if(cache.contains(new SimplePathPredicate(directory))) { - return cache.get(new SimplePathPredicate(directory)); + return this.vault.getCryptor().directoryContentCryptor().decryptDirectoryMetadata(cache.get(new SimplePathPredicate(directory))); } } finally { @@ -119,8 +119,8 @@ protected byte[] toDirectoryId(final Session session, final Path directory) t try { log.debug("Acquire lock for {}", directory); lock.writeLock().lock(); - final byte[] id = this.load(session, directory); - cache.put(new SimplePathPredicate(directory), id); + final DirectoryMetadata id = this.load(session, directory); + cache.put(new SimplePathPredicate(directory), this.vault.getCryptor().directoryContentCryptor().encryptDirectoryMetadata(id)); return id; } finally { @@ -128,22 +128,6 @@ protected byte[] toDirectoryId(final Session session, final Path directory) t } } - protected byte[] load(final Session session, final Path directory) throws BackgroundException { - Path encryptedParent = this.toEncrypted(session, directory.getParent()); - final String cleartextName = directory.getName(); - final String ciphertextName = this.toEncrypted(session, directory.getParent(), cleartextName, EnumSet.of(Path.Type.directory)); - // Read directory id from file - try { - log.debug("Read directory ID for folder {} from {}", directory, ciphertextName); - final Path metadataFile = new Path(encryptedParent, ciphertextName, EnumSet.of(Path.Type.file, Path.Type.encrypted)); - return new ContentReader(session).readBytes(metadataFile); - } - catch(NotfoundException e) { - log.warn("Missing directory ID for folder {}", directory); - return random.random().getBytes(StandardCharsets.US_ASCII); - } - } - public void delete(final Path directory) { lock.writeLock().lock(); try { @@ -166,24 +150,46 @@ public void destroy() { } @Override - public byte[] getOrCreateDirectoryId(final Session session, final Path file) throws BackgroundException { + public DirectoryMetadata getOrCreateDirectoryId(final Session session, final Path file) throws BackgroundException { if(file.attributes().getDirectoryId() != null) { - return file.attributes().getDirectoryId(); + return this.vault.getCryptor().directoryContentCryptor().decryptDirectoryMetadata(file.attributes().getDirectoryId()); } final Path decrypted = file.getType().contains(AbstractPath.Type.encrypted) ? file.attributes().getDecrypted() : file; return this.toDirectoryId(session, decrypted.getType().contains(AbstractPath.Type.file) ? decrypted.getParent() : decrypted); } @Override - public byte[] createDirectoryId(final Path directory) { + public DirectoryMetadata createDirectoryId(final Path directory) { lock.writeLock().lock(); try { - final byte[] directoryId = random.random().getBytes(StandardCharsets.US_ASCII); - cache.put(new SimplePathPredicate(directory), directoryId); - return directoryId; + final DirectoryMetadata metadata = vault.getCryptor().directoryContentCryptor().newDirectoryMetadata(); + final byte[] encrypted = vault.getCryptor().directoryContentCryptor().encryptDirectoryMetadata(metadata); + cache.put(new SimplePathPredicate(directory), encrypted); + return metadata; } finally { lock.writeLock().unlock(); } } + + protected DirectoryMetadata load(final Session session, final Path directory) throws BackgroundException { + final Path encryptedParent = this.toEncrypted(session, directory.getParent()); + final String cleartextName = directory.getName(); + final String ciphertextName = this.toEncrypted(session, directory.getParent(), cleartextName, EnumSet.of(Path.Type.directory)); + final Path metadataParent = new Path(encryptedParent, ciphertextName, EnumSet.of(Path.Type.directory)); + // Read directory id from file + try { + log.debug("Read directory ID for folder {} from {}", directory, ciphertextName); + final Path metadataFile = new Path(metadataParent, vault.getDirectoryMetadataFilename(), EnumSet.of(Path.Type.file, Path.Type.encrypted)); + final byte[] bytes = new ContentReader(session).readBytes(metadataFile); + return this.vault.getCryptor().directoryContentCryptor().decryptDirectoryMetadata(bytes); + } + catch(NotfoundException e) { + log.warn("Missing directory ID for folder {}", directory); + return this.createDirectoryId(directory); + //TODO check if we need to propagtae exception instead? + // throw e; + + } + } } diff --git a/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/impl/CryptoFilenameV6Provider.java b/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/impl/CryptoFilenameV6Provider.java deleted file mode 100644 index 6cb8efa9160..00000000000 --- a/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/impl/CryptoFilenameV6Provider.java +++ /dev/null @@ -1,131 +0,0 @@ -package ch.cyberduck.core.cryptomator.impl; - -/* - * Copyright (c) 2002-2020 iterate GmbH. All rights reserved. - * https://cyberduck.io/ - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -import ch.cyberduck.core.Path; -import ch.cyberduck.core.Session; -import ch.cyberduck.core.cache.LRUCache; -import ch.cyberduck.core.cryptomator.ContentReader; -import ch.cyberduck.core.cryptomator.ContentWriter; -import ch.cyberduck.core.cryptomator.CryptoFilename; -import ch.cyberduck.core.exception.BackgroundException; -import ch.cyberduck.core.features.Directory; -import ch.cyberduck.core.features.Find; -import ch.cyberduck.core.features.Write; -import ch.cyberduck.core.preferences.PreferencesFactory; -import ch.cyberduck.core.transfer.TransferStatus; - -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; -import org.cryptomator.cryptolib.common.MessageDigestSupplier; - -import java.util.EnumSet; - -import com.google.common.io.BaseEncoding; - -import static java.nio.charset.StandardCharsets.UTF_8; - -public class CryptoFilenameV6Provider implements CryptoFilename { - private static final Logger log = LogManager.getLogger(CryptoFilenameV6Provider.class); - - private static final BaseEncoding BASE32 = BaseEncoding.base32(); - private static final String LONG_NAME_FILE_EXT = ".lng"; - private static final String METADATA_DIR_NAME = "m"; - - public static final int DEFAULT_NAME_SHORTENING_THRESHOLD = 130; - - private final int shorteningThreshold; - private final Path metadataRoot; - - private final LRUCache cache = LRUCache.build( - PreferencesFactory.get().getLong("cryptomator.cache.size")); - - public CryptoFilenameV6Provider(final Path vault) { - this(vault, DEFAULT_NAME_SHORTENING_THRESHOLD); - } - - public CryptoFilenameV6Provider(final Path vault, final int shorteningThreshold) { - this.metadataRoot = new Path(vault, METADATA_DIR_NAME, vault.getType()); - this.shorteningThreshold = shorteningThreshold; - } - - @Override - public boolean isDeflated(final String filename) { - return filename.endsWith(LONG_NAME_FILE_EXT); - } - - @Override - public boolean isValid(final String filename) { - return true; - } - - @Override - public String inflate(final Session session, final String shortName) throws BackgroundException { - return new ContentReader(session).read(this.resolve(shortName)); - } - - @Override - public String deflate(final Session session, final String filename) throws BackgroundException { - if(filename.length() < shorteningThreshold) { - return filename; - } - if(cache.contains(filename)) { - return cache.get(filename); - } - final byte[] longFileNameBytes = filename.getBytes(UTF_8); - final byte[] hash = MessageDigestSupplier.SHA1.get().digest(longFileNameBytes); - final String shortName = BASE32.encode(hash) + LONG_NAME_FILE_EXT; - final Path metadataFile = this.resolve(shortName); - final Path secondLevel = metadataFile.getParent(); - final Path firstLevel = secondLevel.getParent(); - final Directory mkdir = session._getFeature(Directory.class); - final Find find = session._getFeature(Find.class); - if(!find.find(metadataRoot)) { - mkdir.mkdir(session._getFeature(Write.class), metadataRoot, new TransferStatus()); - } - if(!find.find(firstLevel)) { - mkdir.mkdir(session._getFeature(Write.class), firstLevel, new TransferStatus()); - } - if(!find.find(secondLevel)) { - mkdir.mkdir(session._getFeature(Write.class), secondLevel, new TransferStatus()); - } - if(!find.find(metadataFile)) { - new ContentWriter(session).write(metadataFile, longFileNameBytes); - } - log.info("Deflated {} to {}", filename, shortName); - cache.put(filename, shortName); - return shortName; - } - - @Override - public Path resolve(final String filename) { - // Intermediate directory - final Path first = new Path(metadataRoot, filename.substring(0, 2), metadataRoot.getType()); - // Intermediate directory - final Path second = new Path(first, filename.substring(2, 4), metadataRoot.getType()); - return new Path(second, filename, EnumSet.of(Path.Type.file, Path.Type.encrypted, Path.Type.vault)); - } - - @Override - public void invalidate(final String filename) { - cache.remove(filename); - } - - @Override - public void destroy() { - cache.clear(); - } -} diff --git a/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/UVFVault.java b/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/impl/uvf/CryptoVault.java similarity index 52% rename from cryptomator/src/main/java/ch/cyberduck/core/cryptomator/UVFVault.java rename to cryptomator/src/main/java/ch/cyberduck/core/cryptomator/impl/uvf/CryptoVault.java index 7ad08be4cec..dc3f86ca87a 100644 --- a/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/UVFVault.java +++ b/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/impl/uvf/CryptoVault.java @@ -1,4 +1,4 @@ -package ch.cyberduck.core.cryptomator; +package ch.cyberduck.core.cryptomator.impl.uvf; /* * Copyright (c) 2002-2025 iterate GmbH. All rights reserved. @@ -20,9 +20,11 @@ import ch.cyberduck.core.PasswordCallback; import ch.cyberduck.core.Path; import ch.cyberduck.core.PathAttributes; -import ch.cyberduck.core.Permission; import ch.cyberduck.core.Session; import ch.cyberduck.core.SimplePathPredicate; +import ch.cyberduck.core.cryptomator.AbstractVault; +import ch.cyberduck.core.cryptomator.CryptoDirectory; +import ch.cyberduck.core.cryptomator.CryptoFilename; import ch.cyberduck.core.cryptomator.features.CryptoDirectoryUVFFeature; import ch.cyberduck.core.cryptomator.impl.CryptoDirectoryUVFProvider; import ch.cyberduck.core.cryptomator.impl.CryptoFilenameV7Provider; @@ -30,30 +32,30 @@ import ch.cyberduck.core.exception.BackgroundException; import ch.cyberduck.core.exception.UnsupportedException; import ch.cyberduck.core.features.Directory; +import ch.cyberduck.core.features.Vault; import ch.cyberduck.core.vault.VaultCredentials; +import ch.cyberduck.core.vault.VaultMetadata; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; -import org.cryptomator.cryptolib.api.AuthenticationFailedException; import org.cryptomator.cryptolib.api.Cryptor; import org.cryptomator.cryptolib.api.CryptorProvider; +import org.cryptomator.cryptolib.api.DirectoryMetadata; import org.cryptomator.cryptolib.api.FileContentCryptor; import org.cryptomator.cryptolib.api.FileHeaderCryptor; +import org.cryptomator.cryptolib.api.RevolvingMasterkey; import org.cryptomator.cryptolib.api.UVFMasterkey; -import java.nio.ByteBuffer; -import java.nio.ByteOrder; import java.text.MessageFormat; import java.util.EnumSet; import java.util.Objects; -import java.util.regex.Matcher; import java.util.regex.Pattern; -import com.google.common.io.BaseEncoding; +import com.google.auto.service.AutoService; -public class UVFVault extends AbstractVault { - - private static final Logger log = LogManager.getLogger(UVFVault.class); +@AutoService(Vault.class) +public class CryptoVault extends AbstractVault { + private static final Logger log = LogManager.getLogger(CryptoVault.class); private static final String REGULAR_FILE_EXTENSION = ".uvf"; private static final String FILENAME_DIRECTORYID = "dir"; @@ -61,37 +63,34 @@ public class UVFVault extends AbstractVault { private static final String BACKUP_FILENAME_DIRECTORYID = "dirid"; private static final String BACKUP_DIRECTORY_METADATA_FILENAME = String.format("%s%s", BACKUP_FILENAME_DIRECTORYID, REGULAR_FILE_EXTENSION); - private static final Pattern BASE64URL_PATTERN = Pattern.compile("^([A-Za-z0-9_=-]+)" + REGULAR_FILE_EXTENSION); - - // copied from AbstractVault - private static final Pattern BASE32_PATTERN = Pattern.compile("^0?(([A-Z2-7]{8})*[A-Z2-7=]{8})"); + private static final Pattern FILENAME_PATTERN = Pattern.compile("^([A-Za-z0-9_=-]+)" + REGULAR_FILE_EXTENSION); /** * Root of vault directory */ private final Path home; + private RevolvingMasterkey masterKey; + private Cryptor cryptor; - private CryptorCache fileNameCryptor; private CryptoFilename filenameProvider; private CryptoDirectory directoryProvider; private int nonceSize; - private byte[] rootDirId; - public UVFVault(final Path home) { + public CryptoVault(final Path home) { this.home = home; } @Override - public Path create(final Session session, final String region, final VaultCredentials credentials) throws BackgroundException { + public AbstractVault create(final Session session, final String region, final VaultCredentials credentials) throws BackgroundException { throw new UnsupportedOperationException(); } // load -> unlock -> open @Override - public UVFVault load(final Session session, final PasswordCallback prompt) throws BackgroundException { - final UVFMasterkey masterKey = UVFMasterkey.fromDecryptedPayload(prompt.prompt(session.getHost(), + public CryptoVault load(final Session session, final PasswordCallback prompt) throws BackgroundException { + masterKey = UVFMasterkey.fromDecryptedPayload(prompt.prompt(session.getHost(), LocaleFactory.localizedString("Unlock Vault", "Cryptomator"), MessageFormat.format(LocaleFactory.localizedString("Provide your passphrase to unlock the Cryptomator Vault {0}", "Cryptomator"), home.getName()), new LoginOptions() @@ -103,83 +102,12 @@ public UVFVault load(final Session session, final PasswordCallback prompt) th final CryptorProvider provider = CryptorProvider.forScheme(CryptorProvider.Scheme.UVF_DRAFT); log.debug("Initialized crypto provider {}", provider); this.cryptor = provider.provide(masterKey, FastSecureRandomProvider.get().provide()); - this.fileNameCryptor = new CryptorCache(cryptor.fileNameCryptor(masterKey.firstRevision())); // TODO revision eventually depends on location - safe? this.filenameProvider = new CryptoFilenameV7Provider(Integer.MAX_VALUE); - this.directoryProvider = new CryptoDirectoryUVFProvider(this, filenameProvider, fileNameCryptor); + this.directoryProvider = new CryptoDirectoryUVFProvider(this, filenameProvider); this.nonceSize = 12; - this.rootDirId = masterKey.rootDirId(); return this; } - @Override - public Path decrypt(final Session session, final Path file) throws BackgroundException { - if(file.getType().contains(Path.Type.decrypted)) { - log.warn("Skip file {} because it is already marked as an defcrypted path", file); - return file; - } - if(file.getType().contains(Path.Type.vault)) { - log.warn("Skip file {} because it is marked as an internal vault path", file); - return file; - } - final Path inflated = this.inflate(session, file); - final Pattern pattern = this.getVersion() == VAULT_VERSION_DEPRECATED ? BASE32_PATTERN : this.getBase64URLPattern(); - final Matcher m = pattern.matcher(inflated.getName()); - if(m.matches()) { - final String ciphertext = m.group(1); - try { - final CryptorCache effectivefileNameCryptor; - // / diff to AbstractVault.decrypt - //TODO lädt das recovery metadaten file anstatt normales - final int revision = loadRevision(session, file); - effectivefileNameCryptor = new CryptorCache(this.getCryptor().fileNameCryptor(revision)); - // \ - final String cleartextFilename = effectivefileNameCryptor.decryptFilename( - this.getVersion() == VAULT_VERSION_DEPRECATED ? BaseEncoding.base32() : BaseEncoding.base64Url(), - ciphertext, directoryProvider.getOrCreateDirectoryId(session, file.getParent())); - final PathAttributes attributes = new PathAttributes(file.attributes()); - if(this.isDirectory(inflated)) { - if(Permission.EMPTY != attributes.getPermission()) { - final Permission permission = new Permission(attributes.getPermission()); - permission.setUser(permission.getUser().or(Permission.Action.execute)); - permission.setGroup(permission.getGroup().or(Permission.Action.execute)); - permission.setOther(permission.getOther().or(Permission.Action.execute)); - attributes.setPermission(permission); - } - // Reset size for folders - attributes.setSize(-1L); - attributes.setVersionId(null); - attributes.setFileId(null); - } - else { - // Translate file size - attributes.setSize(this.toCleartextSize(0L, file.attributes().getSize())); - } - // Add reference to encrypted file - attributes.setEncrypted(file); - // Add reference for vault - attributes.setVault(this.getHome()); - final EnumSet type = EnumSet.copyOf(file.getType()); - type.remove(this.isDirectory(inflated) ? Path.Type.file : Path.Type.directory); - type.add(this.isDirectory(inflated) ? Path.Type.directory : Path.Type.file); - type.remove(Path.Type.encrypted); - type.add(Path.Type.decrypted); - final Path decrypted = new Path(file.getParent().attributes().getDecrypted(), cleartextFilename, type, attributes); - if(type.contains(Path.Type.symboliclink)) { - decrypted.setSymlinkTarget(file.getSymlinkTarget()); - } - return decrypted; - } - catch(AuthenticationFailedException e) { - throw new CryptoAuthenticationException( - "Failure to decrypt due to an unauthentic ciphertext", e); - } - } - else { - throw new CryptoFilenameMismatchException( - String.format("Failure to decrypt %s due to missing pattern match for %s", inflated.getName(), pattern)); - } - } - @Override public Path encrypt(Session session, Path file, boolean metadata) throws BackgroundException { final Path encrypted; @@ -214,10 +142,6 @@ public Path encrypt(Session session, Path file, boolean metadata) throws Back // Translate file size attributes.setSize(this.toCiphertextSize(0L, file.attributes().getSize())); final EnumSet type = EnumSet.copyOf(file.getType()); - if(metadata && this.getVersion() == VAULT_VERSION_DEPRECATED) { - type.remove(Path.Type.directory); - type.add(Path.Type.file); - } type.remove(Path.Type.decrypted); type.add(Path.Type.encrypted); encrypted = new Path(parent, filename, type, attributes); @@ -237,47 +161,11 @@ public Path encrypt(Session session, Path file, boolean metadata) throws Back encrypted.attributes().setDecrypted(file); } // Add reference for vault - file.attributes().setVault(this.getHome()); - encrypted.attributes().setVault(this.getHome()); + file.attributes().setVaultMetadata(this.getMetadata()); + encrypted.attributes().setVaultMetadata(this.getMetadata()); return encrypted; } - private int loadRevision(final Session session, final Path directory) throws BackgroundException { - // Read directory id from file - log.debug("Read directory ID from {}", directory); - final Path metadataFile = new Path(directory.getParent(), this.getDirectoryMetadataFilename(), EnumSet.of(Path.Type.file, Path.Type.encrypted)); - final byte[] ciphertext = new ContentReader(session).readBytes(metadataFile); - // https://github.com/encryption-alliance/unified-vault-format/blob/develop/file%20name%20encryption/AES-SIV-512-B64URL.md#format-of-diruvf-and-symlinkuvf - // TODO can we not use org.cryptomator.cryptolib.v3.DirectoryContentCryptorImpl.decryptDirectoryMetadata()? DirectoryMetadataImpl is not visible and DirectoryMetadata is empty interface, so we cannot access dirId attribute. - if(ciphertext.length != 128) { - throw new IllegalArgumentException("Invalid dir.uvf length: " + ciphertext.length); - } - int headerSize = this.getCryptor().fileHeaderCryptor().headerSize(); - ByteBuffer buffer = ByteBuffer.wrap(ciphertext); - ByteBuffer headerBuf = buffer.duplicate(); - headerBuf.position(4).limit(headerSize); - return headerBuf.order(ByteOrder.BIG_ENDIAN).getInt(); - } - - - // copied from AbstractVault - private boolean isDirectory(final Path p) { - if(this.getVersion() == VAULT_VERSION_DEPRECATED) { - return p.getName().startsWith(DIR_PREFIX); - } - return p.isDirectory(); - } - - // copied from AbstractVault - private Path inflate(final Session session, final Path file) throws BackgroundException { - final String fileName = file.getName(); - if(this.getFilenameProvider().isDeflated(fileName)) { - final String filename = this.getFilenameProvider().inflate(session, fileName); - return new Path(file.getParent(), filename, EnumSet.of(Path.Type.file), file.attributes()); - } - return file; - } - @Override public synchronized void close() { super.close(); @@ -285,11 +173,16 @@ public synchronized void close() { } @Override - public Path getMasterkey() { + public Path getMasterkeyPath() { //TODO: implement return null; } + @Override + public RevolvingMasterkey getMasterkey() { + return masterKey; + } + @Override public Path getConfig() { //TODO: implement @@ -311,11 +204,6 @@ public FileContentCryptor getFileContentCryptor() { return cryptor.fileContentCryptor(); } - @Override - public CryptorCache getFileNameCryptor() { - return fileNameCryptor; - } - @Override public CryptoFilename getFilenameProvider() { return filenameProvider; @@ -337,8 +225,8 @@ public int getNonceSize() { } @Override - public int getVersion() { - return VAULT_VERSION; + public Pattern getFilenamePattern() { + return FILENAME_PATTERN; } @Override @@ -356,13 +244,13 @@ public String getBackupDirectoryMetadataFilename() { return BACKUP_DIRECTORY_METADATA_FILENAME; } - @Override - public Pattern getBase64URLPattern() { - return BASE64URL_PATTERN; + public DirectoryMetadata getRootDirId() { + return this.cryptor.directoryContentCryptor().rootDirectoryMetadata(); } - public byte[] getRootDirId() { - return rootDirId; + @Override + public VaultMetadata getMetadata() { + return new VaultMetadata(this.getHome(), VaultMetadata.Type.UVF); } @Override @@ -378,10 +266,10 @@ public boolean equals(final Object o) { if(this == o) { return true; } - if(!(o instanceof UVFVault)) { + if(!(o instanceof CryptoVault)) { return false; } - final UVFVault that = (UVFVault) o; + final CryptoVault that = (CryptoVault) o; return new SimplePathPredicate(home).test(that.home); } diff --git a/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/CryptoVault.java b/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/impl/v8/CryptoVault.java similarity index 69% rename from cryptomator/src/main/java/ch/cyberduck/core/cryptomator/CryptoVault.java rename to cryptomator/src/main/java/ch/cyberduck/core/cryptomator/impl/v8/CryptoVault.java index 16d43db772b..45f4609c4f1 100644 --- a/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/CryptoVault.java +++ b/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/impl/v8/CryptoVault.java @@ -1,12 +1,12 @@ -package ch.cyberduck.core.cryptomator; +package ch.cyberduck.core.cryptomator.impl.v8; /* - * Copyright (c) 2002-2016 iterate GmbH. All rights reserved. + * Copyright (c) 2002-2025 iterate GmbH. All rights reserved. * https://cyberduck.io/ * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or + * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, @@ -24,13 +24,16 @@ import ch.cyberduck.core.PasswordStore; import ch.cyberduck.core.PasswordStoreFactory; import ch.cyberduck.core.Path; -import ch.cyberduck.core.PathAttributes; import ch.cyberduck.core.Session; import ch.cyberduck.core.SimplePathPredicate; import ch.cyberduck.core.UUIDRandomStringService; -import ch.cyberduck.core.cryptomator.impl.CryptoDirectoryV6Provider; -import ch.cyberduck.core.cryptomator.impl.CryptoDirectoryV7Provider; -import ch.cyberduck.core.cryptomator.impl.CryptoFilenameV6Provider; +import ch.cyberduck.core.cryptomator.AbstractVault; +import ch.cyberduck.core.cryptomator.ContentReader; +import ch.cyberduck.core.cryptomator.ContentWriter; +import ch.cyberduck.core.cryptomator.CryptoAuthenticationException; +import ch.cyberduck.core.cryptomator.CryptoDirectory; +import ch.cyberduck.core.cryptomator.CryptoFilename; +import ch.cyberduck.core.cryptomator.impl.CryptoDirectoryV8Provider; import ch.cyberduck.core.cryptomator.impl.CryptoFilenameV7Provider; import ch.cyberduck.core.cryptomator.random.FastSecureRandomProvider; import ch.cyberduck.core.exception.BackgroundException; @@ -40,18 +43,21 @@ import ch.cyberduck.core.features.Directory; import ch.cyberduck.core.features.Encryption; import ch.cyberduck.core.features.Write; +import ch.cyberduck.core.features.Vault; +import ch.cyberduck.core.features.Write; import ch.cyberduck.core.preferences.Preferences; import ch.cyberduck.core.preferences.PreferencesFactory; import ch.cyberduck.core.shared.DefaultUrlProvider; import ch.cyberduck.core.transfer.TransferStatus; -import ch.cyberduck.core.vault.DefaultVaultRegistry; import ch.cyberduck.core.vault.VaultCredentials; import ch.cyberduck.core.vault.VaultException; +import ch.cyberduck.core.vault.VaultMetadata; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.cryptomator.cryptolib.api.Cryptor; import org.cryptomator.cryptolib.api.CryptorProvider; +import org.cryptomator.cryptolib.api.DirectoryMetadata; import org.cryptomator.cryptolib.api.FileContentCryptor; import org.cryptomator.cryptolib.api.FileHeaderCryptor; import org.cryptomator.cryptolib.api.InvalidPassphraseException; @@ -68,7 +74,9 @@ import java.io.StringWriter; import java.nio.charset.StandardCharsets; import java.text.MessageFormat; +import java.util.Arrays; import java.util.EnumSet; +import java.util.List; import java.util.Objects; import java.util.regex.Pattern; @@ -79,82 +87,138 @@ import com.auth0.jwt.exceptions.JWTVerificationException; import com.auth0.jwt.exceptions.SignatureVerificationException; import com.auth0.jwt.interfaces.DecodedJWT; +import com.google.auto.service.AutoService; import com.google.gson.JsonParseException; -import static ch.cyberduck.core.vault.DefaultVaultRegistry.DEFAULT_VAULTCONFIG_FILE_NAME; - -/** - * Cryptomator vault implementation - */ +@AutoService(Vault.class) public class CryptoVault extends AbstractVault { + private static final Logger log = LogManager.getLogger(CryptoVault.class); - public static final byte[] VAULT_PEPPER = PreferencesFactory.get().getProperty("cryptomator.vault.pepper").getBytes(StandardCharsets.UTF_8); - private static final String JSON_KEY_VAULTVERSION = "format"; - private static final String JSON_KEY_CIPHERCONFIG = "cipherCombo"; - private static final String JSON_KEY_SHORTENING_THRESHOLD = "shorteningThreshold"; + public static final String REGULAR_FILE_EXTENSION = ".c9r"; + public static final int VAULT_VERSION = 8; - private static final String REGULAR_FILE_EXTENSION = ".c9r"; private static final String FILENAME_DIRECTORYID = "dir"; private static final String DIRECTORY_METADATA_FILENAME = String.format("%s%s", FILENAME_DIRECTORYID, REGULAR_FILE_EXTENSION); private static final String BACKUP_FILENAME_DIRECTORYID = "dirid"; private static final String BACKUP_DIRECTORY_METADATA_FILENAME = String.format("%s%s", BACKUP_FILENAME_DIRECTORYID, REGULAR_FILE_EXTENSION); + private static final Pattern FILENAME_PATTERN = Pattern.compile("^([A-Za-z0-9_=-]+)" + REGULAR_FILE_EXTENSION); - private static final Pattern BASE64URL_PATTERN = Pattern.compile("^([A-Za-z0-9_=-]+)" + REGULAR_FILE_EXTENSION); + private static final List SUPPORTED_VERSIONS = Arrays.asList(7, 8); - /** - * Root of vault directory - */ - private final Path home; - private final Path masterkey; + private static final String JSON_KEY_VAULTVERSION = "format"; + private static final String JSON_KEY_CIPHERCONFIG = "cipherCombo"; + private static final String JSON_KEY_SHORTENING_THRESHOLD = "shorteningThreshold"; - private final Path config; - private final Path vault; - private int vaultVersion; - private int nonceSize; + private final Path home; + private Masterkey masterkey; + private final Path masterkeyPath; + private final byte[] pepper; private final PasswordStore keychain = PasswordStoreFactory.get(); private final Preferences preferences = PreferencesFactory.get(); + + private final Path config; + + private int nonceSize; private Cryptor cryptor; - private CryptorCache fileNameCryptor; private CryptoFilename filenameProvider; private CryptoDirectory directoryProvider; - private final byte[] pepper; - public CryptoVault(final Path home) { - this(home, DefaultVaultRegistry.DEFAULT_MASTERKEY_FILE_NAME, DEFAULT_VAULTCONFIG_FILE_NAME, VAULT_PEPPER); - } - - public CryptoVault(final Path home, final String masterkey, final String config, final byte[] pepper) { this.home = home; - this.masterkey = new Path(home, masterkey, EnumSet.of(Path.Type.file, Path.Type.vault)); - this.config = new Path(home, config, EnumSet.of(Path.Type.file, Path.Type.vault)); + this.masterkeyPath = new Path(home, preferences.getProperty("cryptomator.vault.masterkey.filename"), EnumSet.of(Path.Type.file, Path.Type.vault)); + this.config = new Path(home, preferences.getProperty("cryptomator.vault.config.filename"), EnumSet.of(Path.Type.file, Path.Type.vault)); + this.pepper = preferences.getProperty("cryptomator.vault.pepper").getBytes(StandardCharsets.UTF_8); - this.pepper = pepper; + //TODO nötig? // New vault home with vault flag set for internal use final EnumSet type = EnumSet.copyOf(home.getType()); type.add(Path.Type.vault); - if(home.isRoot()) { - this.vault = new Path(home.getAbsolute(), type, new PathAttributes(home.attributes())); - } - else { - this.vault = new Path(home.getParent(), home.getName(), type, new PathAttributes(home.attributes())); - } } - public synchronized Path create(final Session session, final VaultCredentials credentials, final int version) throws BackgroundException { - return this.create(session, null, credentials, version); + public Path getHome() { + return home; + } + + @Override + public Path getMasterkeyPath() { + return masterkeyPath; + } + + public Masterkey getMasterkey() { + return masterkey; + } + + @Override + public Path getConfig() { + return config; + } + + @Override + public FileHeaderCryptor getFileHeaderCryptor() { + return cryptor.fileHeaderCryptor(); + } + + @Override + public FileContentCryptor getFileContentCryptor() { + return cryptor.fileContentCryptor(); + } + + @Override + public CryptoFilename getFilenameProvider() { + return filenameProvider; } - public synchronized Path create(final Session session, final String region, final VaultCredentials credentials, final int version) throws BackgroundException { + @Override + public CryptoDirectory getDirectoryProvider() { + return directoryProvider; + } + + @Override + public Cryptor getCryptor() { + return cryptor; + } + + @Override + public int getNonceSize() { + return nonceSize; + } + + @Override + public String getRegularFileExtension() { + return REGULAR_FILE_EXTENSION; + } + + @Override + public String getDirectoryMetadataFilename() { + return DIRECTORY_METADATA_FILENAME; + } + + @Override + public String getBackupDirectoryMetadataFilename() { + return BACKUP_DIRECTORY_METADATA_FILENAME; + } + + @Override + public DirectoryMetadata getRootDirId() { + return this.cryptor.directoryContentCryptor().rootDirectoryMetadata(); + } + + @Override + public Pattern getFilenamePattern() { + return FILENAME_PATTERN; + } + + @Override + public synchronized AbstractVault create(final Session session, final String region, final VaultCredentials credentials) throws BackgroundException { final Host bookmark = session.getHost(); if(credentials.isSaved()) { try { keychain.addPassword(String.format("Cryptomator Passphrase (%s)", bookmark.getCredentials().getUsername()), - new DefaultUrlProvider(bookmark).toUrl(masterkey, EnumSet.of(DescriptiveUrl.Type.provider)).find(DescriptiveUrl.Type.provider).getUrl(), credentials.getPassword()); + new DefaultUrlProvider(bookmark).toUrl(masterkeyPath, EnumSet.of(DescriptiveUrl.Type.provider)).find(DescriptiveUrl.Type.provider).getUrl(), credentials.getPassword()); } catch(LocalAccessDeniedException e) { log.error("Failure {} saving credentials for {} in password store", e, bookmark); @@ -166,13 +230,13 @@ public synchronized Path create(final Session session, final String region, f final MasterkeyFileAccess access = new MasterkeyFileAccess(pepper, FastSecureRandomProvider.get().provide()); final MasterkeyFile masterkeyFile; try { - access.persist(mk, mkArray, passphrase, version); + access.persist(mk, mkArray, passphrase, VAULT_VERSION); masterkeyFile = MasterkeyFile.read(new StringReader(new String(mkArray.toByteArray(), StandardCharsets.UTF_8))); } catch(IOException e) { throw new VaultException("Failure creating master key", e); } - log.debug("Write master key to {}", masterkey); + log.debug("Write master key to {}", masterkeyPath); // Obtain non encrypted directory writer final Directory directory = session._getFeature(Directory.class); final TransferStatus status = new TransferStatus().setRegion(region); @@ -181,24 +245,18 @@ public synchronized Path create(final Session session, final String region, f status.setEncryption(encryption.getDefault(home)); } final Path vault = directory.mkdir(session._getFeature(Write.class), home, status); - new ContentWriter(session).write(masterkey, mkArray.toByteArray()); - if(VAULT_VERSION == version) { - // Create vaultconfig.cryptomator - final Algorithm algorithm = Algorithm.HMAC256(mk.getEncoded()); - final String conf = JWT.create() - .withJWTId(new UUIDRandomStringService().random()) - .withKeyId(String.format("masterkeyfile:%s", masterkey.getName())) - .withClaim(JSON_KEY_VAULTVERSION, version) - .withClaim(JSON_KEY_CIPHERCONFIG, CryptorProvider.Scheme.SIV_GCM.toString()) - .withClaim(JSON_KEY_SHORTENING_THRESHOLD, CryptoFilenameV7Provider.DEFAULT_NAME_SHORTENING_THRESHOLD) - .sign(algorithm); - new ContentWriter(session).write(config, conf.getBytes(StandardCharsets.US_ASCII)); - this.open(parseVaultConfigFromJWT(conf).withMasterkeyFile(masterkeyFile), passphrase); - } - else { - this.open(new VaultConfig(version, CryptoFilenameV6Provider.DEFAULT_NAME_SHORTENING_THRESHOLD, - CryptorProvider.Scheme.SIV_CTRMAC, null, null).withMasterkeyFile(masterkeyFile), passphrase); - } + new ContentWriter(session).write(masterkeyPath, mkArray.toByteArray()); + // Create vaultconfig.cryptomator + final Algorithm algorithm = Algorithm.HMAC256(mk.getEncoded()); + final String conf = JWT.create() + .withJWTId(new UUIDRandomStringService().random()) + .withKeyId(String.format("masterkeyfile:%s", masterkeyPath.getName())) + .withClaim(JSON_KEY_VAULTVERSION, VAULT_VERSION) + .withClaim(JSON_KEY_CIPHERCONFIG, CryptorProvider.Scheme.SIV_GCM.toString()) + .withClaim(JSON_KEY_SHORTENING_THRESHOLD, CryptoFilenameV7Provider.DEFAULT_NAME_SHORTENING_THRESHOLD) + .sign(algorithm); + new ContentWriter(session).write(config, conf.getBytes(StandardCharsets.US_ASCII)); + this.open(parseVaultConfigFromJWT(conf).withMasterkeyFile(masterkeyFile), passphrase); final Path secondLevel = directoryProvider.toEncrypted(session, home); final Path firstLevel = secondLevel.getParent(); final Path dataDir = firstLevel.getParent(); @@ -206,80 +264,36 @@ public synchronized Path create(final Session session, final String region, f directory.mkdir(session._getFeature(Write.class), dataDir, status); directory.mkdir(session._getFeature(Write.class), firstLevel, status); directory.mkdir(session._getFeature(Write.class), secondLevel, status); - return vault; + return this; } - @Override - public synchronized Path create(final Session session, final String region, final VaultCredentials credentials) throws BackgroundException { - return this.create(session, region, credentials, VAULT_VERSION); + private static VaultConfig parseVaultConfigFromMasterKey(final MasterkeyFile masterkeyFile) { + return new VaultConfig(masterkeyFile.version, CryptoFilenameV7Provider.DEFAULT_NAME_SHORTENING_THRESHOLD, + CryptorProvider.Scheme.SIV_CTRMAC, null, null); } @Override - public synchronized CryptoVault load(final Session session, final PasswordCallback prompt) throws BackgroundException { - if(this.isUnlocked()) { - log.warn("Skip unlock of open vault {}", this); - return this; - } + public Vault load(final Session session, final PasswordCallback prompt) throws BackgroundException { final Host bookmark = session.getHost(); String passphrase = keychain.getPassword(String.format("Cryptomator Passphrase (%s)", bookmark.getCredentials().getUsername()), - new DefaultUrlProvider(bookmark).toUrl(masterkey, EnumSet.of(DescriptiveUrl.Type.provider)).find(DescriptiveUrl.Type.provider).getUrl()); + new DefaultUrlProvider(bookmark).toUrl(masterkeyPath, EnumSet.of(DescriptiveUrl.Type.provider)).find(DescriptiveUrl.Type.provider).getUrl()); if(null == passphrase) { // Legacy passphrase = keychain.getPassword(String.format("Cryptomator Passphrase %s", bookmark.getHostname()), - new DefaultUrlProvider(bookmark).toUrl(masterkey, EnumSet.of(DescriptiveUrl.Type.provider)).find(DescriptiveUrl.Type.provider).getUrl()); + new DefaultUrlProvider(bookmark).toUrl(masterkeyPath, EnumSet.of(DescriptiveUrl.Type.provider)).find(DescriptiveUrl.Type.provider).getUrl()); } return this.unlock(session, prompt, bookmark, passphrase); } - private VaultConfig readVaultConfig(final Session session) throws BackgroundException { - final MasterkeyFile masterkeyFile = this.readMasterkeyFile(session, masterkey); - try { - return parseVaultConfigFromJWT(new ContentReader(session).read(config)) - .withMasterkeyFile(masterkeyFile); - } - catch(NotfoundException e) { - log.debug("Ignore failure reading vault configuration {}", config); - return parseVaultConfigFromMasterKey(masterkeyFile) - .withMasterkeyFile(masterkeyFile); - } - } - - private static VaultConfig parseVaultConfigFromMasterKey(final MasterkeyFile masterkeyFile) { - return new VaultConfig(masterkeyFile.version, - masterkeyFile.version == VAULT_VERSION_DEPRECATED ? - CryptoFilenameV6Provider.DEFAULT_NAME_SHORTENING_THRESHOLD : - CryptoFilenameV7Provider.DEFAULT_NAME_SHORTENING_THRESHOLD, - CryptorProvider.Scheme.SIV_CTRMAC, null, null); - } - - public static VaultConfig parseVaultConfigFromJWT(final String token) { - final DecodedJWT decoded = JWT.decode(token); - return new VaultConfig( - decoded.getClaim(JSON_KEY_VAULTVERSION).asInt(), - decoded.getClaim(JSON_KEY_SHORTENING_THRESHOLD).asInt(), - CryptorProvider.Scheme.valueOf(decoded.getClaim(JSON_KEY_CIPHERCONFIG).asString()), - decoded.getAlgorithm(), decoded); - } - - private MasterkeyFile readMasterkeyFile(final Session session, final Path file) throws BackgroundException { - log.debug("Read master key {}", file); - try(Reader reader = new ContentReader(session).getReader(file)) { - return MasterkeyFile.read(reader); - } - catch(JsonParseException | IllegalArgumentException | IllegalStateException | IOException e) { - throw new VaultException(String.format("Failure reading vault master key file %s", file.getName()), e); - } - } - - public CryptoVault unlock(final Session session, final PasswordCallback prompt, final Host bookmark, final String passphrase) throws BackgroundException { - final VaultConfig vaultConfig = this.readVaultConfig(session); + public Vault unlock(final Session session, final PasswordCallback prompt, final Host bookmark, final String passphrase) throws BackgroundException { + final ch.cyberduck.core.cryptomator.impl.v8.CryptoVault.VaultConfig vaultConfig = this.readVaultConfig(session); this.unlock(vaultConfig, passphrase, bookmark, prompt, MessageFormat.format(LocaleFactory.localizedString("Provide your passphrase to unlock the Cryptomator Vault {0}", "Cryptomator"), home.getName()) ); return this; } - public void unlock(final VaultConfig vaultConfig, final String passphrase, final Host bookmark, final PasswordCallback prompt, + public void unlock(final ch.cyberduck.core.cryptomator.impl.v8.CryptoVault.VaultConfig vaultConfig, final String passphrase, final Host bookmark, final PasswordCallback prompt, final String message) throws BackgroundException { final Credentials credentials; if(null == passphrase) { @@ -302,10 +316,10 @@ public void unlock(final VaultConfig vaultConfig, final String passphrase, final try { this.open(vaultConfig, credentials.getPassword()); if(credentials.isSaved()) { - log.info("Save passphrase for {}", masterkey); + log.info("Save passphrase for {}", masterkeyPath); // Save password with hostname and path to masterkey.cryptomator in keychain keychain.addPassword(String.format("Cryptomator Passphrase (%s)", bookmark.getCredentials().getUsername()), - new DefaultUrlProvider(bookmark).toUrl(masterkey, EnumSet.of(DescriptiveUrl.Type.provider)).find(DescriptiveUrl.Type.provider).getUrl(), credentials.getPassword()); + new DefaultUrlProvider(bookmark).toUrl(masterkeyPath, EnumSet.of(DescriptiveUrl.Type.provider)).find(DescriptiveUrl.Type.provider).getUrl(), credentials.getPassword()); } } catch(CryptoAuthenticationException e) { @@ -314,32 +328,37 @@ public void unlock(final VaultConfig vaultConfig, final String passphrase, final } } - @Override - public synchronized void close() { - super.close(); - cryptor = null; - fileNameCryptor = null; + private ch.cyberduck.core.cryptomator.impl.v8.CryptoVault.VaultConfig readVaultConfig(final Session session) throws BackgroundException { + final MasterkeyFile masterkeyFile = this.readMasterkeyFile(session, masterkeyPath); + try { + return parseVaultConfigFromJWT(new ContentReader(session).read(config)).withMasterkeyFile(masterkeyFile); + } + catch(NotfoundException e) { + log.debug("Ignore failure reading vault configuration {}", config); + return parseVaultConfigFromMasterKey(masterkeyFile).withMasterkeyFile(masterkeyFile); + } } - protected CryptoFilename createFilenameProvider(final VaultConfig vaultConfig) { - switch(vaultConfig.version) { - case VAULT_VERSION_DEPRECATED: - return new CryptoFilenameV6Provider(vault); - default: - return new CryptoFilenameV7Provider(vaultConfig.getShorteningThreshold()); - } + public static ch.cyberduck.core.cryptomator.impl.v8.CryptoVault.VaultConfig parseVaultConfigFromJWT(final String token) { + final DecodedJWT decoded = JWT.decode(token); + return new ch.cyberduck.core.cryptomator.impl.v8.CryptoVault.VaultConfig( + decoded.getClaim(JSON_KEY_VAULTVERSION).asInt(), + decoded.getClaim(JSON_KEY_SHORTENING_THRESHOLD).asInt(), + CryptorProvider.Scheme.valueOf(decoded.getClaim(JSON_KEY_CIPHERCONFIG).asString()), + decoded.getAlgorithm(), decoded); } - protected CryptoDirectory createDirectoryProvider(final VaultConfig vaultConfig, final CryptoFilename filenameProvider, final CryptorCache filenameCryptor) { - switch(vaultConfig.version) { - case VAULT_VERSION_DEPRECATED: - return new CryptoDirectoryV6Provider(vault, filenameProvider, filenameCryptor); - default: - return new CryptoDirectoryV7Provider(this, filenameProvider, filenameCryptor); + private MasterkeyFile readMasterkeyFile(final Session session, final Path file) throws BackgroundException { + log.debug("Read master key {}", file); + try(Reader reader = new ContentReader(session).getReader(file)) { + return MasterkeyFile.read(reader); + } + catch(JsonParseException | IllegalArgumentException | IllegalStateException | IOException e) { + throw new VaultException(String.format("Failure reading vault master key file %s", file.getName()), e); } } - protected void open(final VaultConfig vaultConfig, final CharSequence passphrase) throws BackgroundException { + protected void open(final ch.cyberduck.core.cryptomator.impl.v8.CryptoVault.VaultConfig vaultConfig, final CharSequence passphrase) throws BackgroundException { try { final PerpetualMasterkey masterKey = this.getMasterKey(vaultConfig.getMkfile(), passphrase); this.open(vaultConfig, masterKey); @@ -352,15 +371,17 @@ protected void open(final VaultConfig vaultConfig, final CharSequence passphrase } } - protected void open(final VaultConfig vaultConfig, final PerpetualMasterkey masterKey) throws BackgroundException { - this.vaultVersion = vaultConfig.version; + protected void open(final ch.cyberduck.core.cryptomator.impl.v8.CryptoVault.VaultConfig vaultConfig, final PerpetualMasterkey masterKey) throws BackgroundException { + if(!SUPPORTED_VERSIONS.contains(vaultConfig.vaultVersion())) { + throw new VaultException(String.format("Unsupported vault version %d", vaultConfig.vaultVersion())); + } final CryptorProvider provider = CryptorProvider.forScheme(vaultConfig.getCipherCombo()); log.debug("Initialized crypto provider {}", provider); vaultConfig.verify(masterKey.getEncoded(), VAULT_VERSION); + this.masterkey = masterKey; this.cryptor = provider.provide(masterKey, FastSecureRandomProvider.get().provide()); - this.fileNameCryptor = new CryptorCache(cryptor.fileNameCryptor()); - this.filenameProvider = this.createFilenameProvider(vaultConfig); - this.directoryProvider = this.createDirectoryProvider(vaultConfig, this.filenameProvider, this.fileNameCryptor); + this.filenameProvider = new CryptoFilenameV7Provider(vaultConfig.getShorteningThreshold()); + this.directoryProvider = new CryptoDirectoryV8Provider(this, this.filenameProvider); this.nonceSize = vaultConfig.getNonceSize(); } @@ -371,109 +392,15 @@ private PerpetualMasterkey getMasterKey(final MasterkeyFile mkFile, final CharSe new ByteArrayInputStream(writer.getBuffer().toString().getBytes(StandardCharsets.UTF_8)), passphrase); } - public Path getHome() { - return home; - } - - @Override - public Path getMasterkey() { - return masterkey; - } - - @Override - public Path getConfig() { - return config; - } - - @Override - public int getVersion() { - return vaultVersion; - } - - @Override - public FileHeaderCryptor getFileHeaderCryptor() { - return cryptor.fileHeaderCryptor(); - } - - @Override - public FileContentCryptor getFileContentCryptor() { - return cryptor.fileContentCryptor(); - } - - @Override - public CryptorCache getFileNameCryptor() { - return fileNameCryptor; - } - - @Override - public CryptoFilename getFilenameProvider() { - return filenameProvider; - } - - @Override - public CryptoDirectory getDirectoryProvider() { - return directoryProvider; - } - @Override - public Cryptor getCryptor() { - return cryptor; + public VaultMetadata getMetadata() { + return new VaultMetadata(this.getHome(), VaultMetadata.Type.V8); } @Override - public int getNonceSize() { - return nonceSize; - } - - @Override - public String getRegularFileExtension() { - return REGULAR_FILE_EXTENSION; - } - - @Override - public String getDirectoryMetadataFilename() { - return DIRECTORY_METADATA_FILENAME; - } - - @Override - public String getBackupDirectoryMetadataFilename() { - return BACKUP_DIRECTORY_METADATA_FILENAME; - } - - @Override - public Pattern getBase64URLPattern() { - return BASE64URL_PATTERN; - } - - @Override - public byte[] getRootDirId() { - return CryptoDirectoryV6Provider.ROOT_DIR_ID; - } - - @Override - public boolean equals(final Object o) { - if(this == o) { - return true; - } - if(!(o instanceof CryptoVault)) { - return false; - } - final CryptoVault that = (CryptoVault) o; - return new SimplePathPredicate(home).test(that.home); - } - - @Override - public int hashCode() { - return Objects.hash(new SimplePathPredicate(home)); - } - - @Override - public String toString() { - final StringBuilder sb = new StringBuilder("CryptoVault{"); - sb.append("home=").append(home); - sb.append(", cryptor=").append(cryptor); - sb.append('}'); - return sb.toString(); + public synchronized void close() { + super.close(); + cryptor = null; } public static class VaultConfig { @@ -559,4 +486,30 @@ public void verify(byte[] rawKey, int expectedVaultVersion) throws VaultExceptio } } } -} \ No newline at end of file + + @Override + public boolean equals(final Object o) { + if(this == o) { + return true; + } + if(!(o instanceof CryptoVault)) { + return false; + } + final CryptoVault that = (CryptoVault) o; + return new SimplePathPredicate(home).test(that.home); + } + + @Override + public int hashCode() { + return Objects.hash(new SimplePathPredicate(home)); + } + + @Override + public String toString() { + final StringBuilder sb = new StringBuilder("CryptoVault{"); + sb.append("home=").append(home); + sb.append(", cryptor=").append(cryptor); + sb.append('}'); + return sb.toString(); + } +} diff --git a/cryptomator/src/test/java/ch/cyberduck/core/cryptomator/CryptoChecksumComputeTest.java b/cryptomator/src/test/java/ch/cyberduck/core/cryptomator/CryptoChecksumComputeTest.java index a539352f90f..4935d094072 100644 --- a/cryptomator/src/test/java/ch/cyberduck/core/cryptomator/CryptoChecksumComputeTest.java +++ b/cryptomator/src/test/java/ch/cyberduck/core/cryptomator/CryptoChecksumComputeTest.java @@ -20,6 +20,7 @@ import ch.cyberduck.core.Path; import ch.cyberduck.core.TestProtocol; import ch.cyberduck.core.cryptomator.features.CryptoChecksumCompute; +import ch.cyberduck.core.cryptomator.impl.v8.CryptoVault; import ch.cyberduck.core.cryptomator.random.RandomNonceGenerator; import ch.cyberduck.core.features.Directory; import ch.cyberduck.core.features.Write; @@ -61,7 +62,6 @@ public Path mkdir(final Write writer, final Path folder, final TransferStatus st cryptomator.create(session, null, new VaultCredentials("test")); final ByteBuffer header = cryptomator.getFileHeaderCryptor().encryptHeader(cryptomator.getFileHeaderCryptor().create()); // DEFAULT_PIPE_SIZE=1024 - final Path file = new Path(vault, "f", EnumSet.of(Path.Type.file)); final SHA256ChecksumCompute sha = new SHA256ChecksumCompute(); final CryptoChecksumCompute compute = new CryptoChecksumCompute(sha, cryptomator); final RandomNonceGenerator nonces = new RandomNonceGenerator(cryptomator.getNonceSize()); diff --git a/cryptomator/src/test/java/ch/cyberduck/core/cryptomator/CryptoOutputStreamTest.java b/cryptomator/src/test/java/ch/cyberduck/core/cryptomator/CryptoOutputStreamTest.java index eff5c2e279a..a5f848ade45 100644 --- a/cryptomator/src/test/java/ch/cyberduck/core/cryptomator/CryptoOutputStreamTest.java +++ b/cryptomator/src/test/java/ch/cyberduck/core/cryptomator/CryptoOutputStreamTest.java @@ -19,6 +19,7 @@ import ch.cyberduck.core.NullSession; import ch.cyberduck.core.Path; import ch.cyberduck.core.TestProtocol; +import ch.cyberduck.core.cryptomator.impl.v8.CryptoVault; import ch.cyberduck.core.cryptomator.random.RandomNonceGenerator; import ch.cyberduck.core.features.Directory; import ch.cyberduck.core.features.Write; diff --git a/cryptomator/src/test/java/ch/cyberduck/core/cryptomator/CryptoWriteFeatureTest.java b/cryptomator/src/test/java/ch/cyberduck/core/cryptomator/CryptoWriteFeatureTest.java index ecacf7650c8..3c2d81679a3 100644 --- a/cryptomator/src/test/java/ch/cyberduck/core/cryptomator/CryptoWriteFeatureTest.java +++ b/cryptomator/src/test/java/ch/cyberduck/core/cryptomator/CryptoWriteFeatureTest.java @@ -19,6 +19,7 @@ import ch.cyberduck.core.NullSession; import ch.cyberduck.core.Path; import ch.cyberduck.core.TestProtocol; +import ch.cyberduck.core.cryptomator.impl.v8.CryptoVault; import ch.cyberduck.core.features.Directory; import ch.cyberduck.core.features.Write; import ch.cyberduck.core.transfer.TransferStatus; @@ -33,43 +34,6 @@ public class CryptoWriteFeatureTest { - @Test - public void testCiphertextSize_CTR() throws Exception { - final Path home = new Path("/vault", EnumSet.of(Path.Type.directory)); - final NullSession session = new NullSession(new Host(new TestProtocol())) { - @Override - @SuppressWarnings("unchecked") - public T _getFeature(final Class type) { - if(type == Directory.class) { - return (T) new Directory() { - - @Override - public Path mkdir(final Write writer, final Path folder, final TransferStatus status) { - assertTrue(folder.equals(home) || folder.isChild(home)); - return folder; - } - }; - } - return super._getFeature(type); - } - }; - final CryptoVault vault = new CryptoVault(home); - vault.create(session, null, new VaultCredentials("test"), CryptoVault.VAULT_VERSION_DEPRECATED); - int headerSize = vault.getFileHeaderCryptor().headerSize(); - // zero file size - assertEquals(headerSize, vault.toCiphertextSize(0L, 0)); - // one-byte file - assertEquals(headerSize + 48 + 1, vault.toCiphertextSize(0L, 1)); - // file with chunk size length - assertEquals(headerSize + vault.getFileContentCryptor().ciphertextChunkSize(), vault.toCiphertextSize(0L, vault.getFileContentCryptor().cleartextChunkSize())); - // file with chunk size length + 1 - assertEquals(headerSize + vault.getFileContentCryptor().ciphertextChunkSize() + 48 + 1, vault.toCiphertextSize(0L, vault.getFileContentCryptor().cleartextChunkSize() + 1)); - // file with 2 * chunk size length - assertEquals(headerSize + 2 * vault.getFileContentCryptor().ciphertextChunkSize(), vault.toCiphertextSize(0L, 2 * vault.getFileContentCryptor().cleartextChunkSize())); - // file with 2 * chunk size length + 100 - assertEquals(headerSize + 2 * vault.getFileContentCryptor().ciphertextChunkSize() + 48 + 100, vault.toCiphertextSize(0L, 2 * vault.getFileContentCryptor().cleartextChunkSize() + 100)); - } - @Test public void testCiphertextSize_GCM() throws Exception { final Path home = new Path("/vault", EnumSet.of(Path.Type.directory)); @@ -91,7 +55,7 @@ public Path mkdir(final Write writer, final Path folder, final TransferStatus st } }; final CryptoVault vault = new CryptoVault(home); - vault.create(session, null, new VaultCredentials("test"), CryptoVault.VAULT_VERSION); + vault.create(session, null, new VaultCredentials("test")); int headerSize = vault.getFileHeaderCryptor().headerSize(); // zero file size assertEquals(headerSize, vault.toCiphertextSize(0L, 0)); diff --git a/cryptomator/src/test/java/ch/cyberduck/core/cryptomator/features/CryptoBulkFeatureTest.java b/cryptomator/src/test/java/ch/cyberduck/core/cryptomator/features/CryptoBulkFeatureTest.java index 86287502683..bcc398e2bd5 100644 --- a/cryptomator/src/test/java/ch/cyberduck/core/cryptomator/features/CryptoBulkFeatureTest.java +++ b/cryptomator/src/test/java/ch/cyberduck/core/cryptomator/features/CryptoBulkFeatureTest.java @@ -22,7 +22,7 @@ import ch.cyberduck.core.NullSession; import ch.cyberduck.core.Path; import ch.cyberduck.core.TestProtocol; -import ch.cyberduck.core.cryptomator.CryptoVault; +import ch.cyberduck.core.cryptomator.impl.v8.CryptoVault; import ch.cyberduck.core.features.Bulk; import ch.cyberduck.core.features.Directory; import ch.cyberduck.core.features.Write; diff --git a/cryptomator/src/test/java/ch/cyberduck/core/cryptomator/features/CryptoReadFeatureTest.java b/cryptomator/src/test/java/ch/cyberduck/core/cryptomator/features/CryptoReadFeatureTest.java index 65801444f38..74863a1eaf3 100644 --- a/cryptomator/src/test/java/ch/cyberduck/core/cryptomator/features/CryptoReadFeatureTest.java +++ b/cryptomator/src/test/java/ch/cyberduck/core/cryptomator/features/CryptoReadFeatureTest.java @@ -23,7 +23,7 @@ import ch.cyberduck.core.NullSession; import ch.cyberduck.core.Path; import ch.cyberduck.core.TestProtocol; -import ch.cyberduck.core.cryptomator.CryptoVault; +import ch.cyberduck.core.cryptomator.impl.v8.CryptoVault; import ch.cyberduck.core.exception.BackgroundException; import ch.cyberduck.core.exception.NotfoundException; import ch.cyberduck.core.features.Read; @@ -38,12 +38,12 @@ import java.nio.charset.Charset; import java.util.EnumSet; -import static ch.cyberduck.core.cryptomator.CryptoVault.VAULT_VERSION; -import static ch.cyberduck.core.cryptomator.CryptoVaultTest.createJWT; +import static ch.cyberduck.core.cryptomator.impl.v8.CryptoVaultTest.createJWT; import static org.junit.Assert.assertEquals; public class CryptoReadFeatureTest { + //TODO prüfen, ob CTR in 7 vorkommen kann. oder nur GCM @Test public void testCalculations_CTR() throws Exception { final NullSession session = new NullSession(new Host(new TestProtocol())) { @@ -61,7 +61,7 @@ public InputStream read(final Path file, final TransferStatus status, final Conn " \"primaryMasterKey\": \"Q7pGo1l0jmZssoQh9rXFPKJE9NIXvPbL+HcnVSR9CHdkeR8AwgFtcw==\",\n" + " \"hmacMasterKey\": \"xzBqT4/7uEcQbhHFLC0YmMy4ykVKbuvJEA46p1Xm25mJNuTc20nCbw==\",\n" + " \"versionMac\": \"hlNr3dz/CmuVajhaiGyCem9lcVIUjDfSMLhjppcXOrM=\",\n" + - " \"version\": 6\n" + + " \"version\": 7\n" + "}"; if("masterkey.cryptomator".equals(file.getName())) { return IOUtils.toInputStream(masterKey, Charset.defaultCharset()); @@ -141,7 +141,7 @@ public InputStream read(final Path file, final TransferStatus status, final Conn return IOUtils.toInputStream(masterKey, Charset.defaultCharset()); } if("vault.cryptomator".equals(file.getName())) { - return IOUtils.toInputStream(createJWT(masterKey, VAULT_VERSION, CryptorProvider.Scheme.SIV_GCM, "vault"), Charset.defaultCharset()); + return IOUtils.toInputStream(createJWT(masterKey, CryptoVault.VAULT_VERSION, CryptorProvider.Scheme.SIV_GCM, "vault"), Charset.defaultCharset()); } throw new NotfoundException(String.format("%s not found", file.getName())); } diff --git a/cryptomator/src/test/java/ch/cyberduck/core/cryptomator/impl/CryptoDirectoryV6ProviderTest.java b/cryptomator/src/test/java/ch/cyberduck/core/cryptomator/impl/CryptoDirectoryV6ProviderTest.java deleted file mode 100644 index 8add334cd83..00000000000 --- a/cryptomator/src/test/java/ch/cyberduck/core/cryptomator/impl/CryptoDirectoryV6ProviderTest.java +++ /dev/null @@ -1,72 +0,0 @@ -package ch.cyberduck.core.cryptomator.impl; - -/* - * Copyright (c) 2002-2020 iterate GmbH. All rights reserved. - * https://cyberduck.io/ - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -import ch.cyberduck.core.Host; -import ch.cyberduck.core.NullSession; -import ch.cyberduck.core.Path; -import ch.cyberduck.core.TestProtocol; -import ch.cyberduck.core.cryptomator.CryptoDirectory; -import ch.cyberduck.core.cryptomator.CryptorCache; -import ch.cyberduck.core.exception.NotfoundException; - -import org.cryptomator.cryptolib.api.Cryptor; -import org.cryptomator.cryptolib.api.CryptorProvider; -import org.cryptomator.cryptolib.api.PerpetualMasterkey; -import org.junit.Test; - -import java.security.SecureRandom; -import java.util.EnumSet; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; - -public class CryptoDirectoryV6ProviderTest { - - @Test(expected = NotfoundException.class) - public void testToEncryptedInvalidArgument() throws Exception { - final Path home = new Path("/vault", EnumSet.of(Path.Type.directory)); - final CryptorProvider crypto = CryptorProvider.forScheme(CryptorProvider.Scheme.SIV_CTRMAC); - final SecureRandom random = new SecureRandom(); - final Cryptor cryptor = crypto.provide(PerpetualMasterkey.generate(random), random); - final CryptoDirectory provider = new CryptoDirectoryV6Provider(home, new CryptoFilenameV6Provider(home), new CryptorCache(cryptor.fileNameCryptor())); - provider.toEncrypted(new NullSession(new Host(new TestProtocol())), new Path("/vault/f", EnumSet.of(Path.Type.file))); - } - - @Test(expected = NotfoundException.class) - public void testToEncryptedInvalidPath() throws Exception { - final Path home = new Path("/vault", EnumSet.of(Path.Type.directory)); - final CryptorProvider crypto = CryptorProvider.forScheme(CryptorProvider.Scheme.SIV_CTRMAC); - final SecureRandom random = new SecureRandom(); - final Cryptor cryptor = crypto.provide(PerpetualMasterkey.generate(random), random); - final CryptoDirectory provider = new CryptoDirectoryV6Provider(home, new CryptoFilenameV6Provider(home), new CryptorCache(cryptor.fileNameCryptor())); - provider.toEncrypted(new NullSession(new Host(new TestProtocol())), new Path("/", EnumSet.of(Path.Type.directory))); - } - - @Test - public void testToEncryptedDirectory() throws Exception { - final Path home = new Path("/vault", EnumSet.of(Path.Type.directory)); - final NullSession session = new NullSession(new Host(new TestProtocol())); - final CryptorProvider crypto = CryptorProvider.forScheme(CryptorProvider.Scheme.SIV_CTRMAC); - final SecureRandom csprng = new SecureRandom(); - final Cryptor cryptor = crypto.provide(PerpetualMasterkey.generate(csprng), csprng); - final CryptoDirectory provider = new CryptoDirectoryV6Provider(home, new CryptoFilenameV6Provider(home), new CryptorCache(cryptor.fileNameCryptor())); - assertNotNull(provider.toEncrypted(session, home)); - final Path f = new Path("/vault/f", EnumSet.of(Path.Type.directory)); - assertNotNull(provider.toEncrypted(session, f)); - assertEquals(provider.toEncrypted(session, f), provider.toEncrypted(session, f)); - } -} diff --git a/cryptomator/src/test/java/ch/cyberduck/core/cryptomator/impl/CryptoDirectoryV7ProviderTest.java b/cryptomator/src/test/java/ch/cyberduck/core/cryptomator/impl/CryptoDirectoryV7ProviderTest.java deleted file mode 100644 index eab675ceb3b..00000000000 --- a/cryptomator/src/test/java/ch/cyberduck/core/cryptomator/impl/CryptoDirectoryV7ProviderTest.java +++ /dev/null @@ -1,73 +0,0 @@ -package ch.cyberduck.core.cryptomator.impl; - -/* - * Copyright (c) 2002-2020 iterate GmbH. All rights reserved. - * https://cyberduck.io/ - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -import ch.cyberduck.core.Host; -import ch.cyberduck.core.NullSession; -import ch.cyberduck.core.Path; -import ch.cyberduck.core.TestProtocol; -import ch.cyberduck.core.cryptomator.CryptoDirectory; -import ch.cyberduck.core.cryptomator.CryptoVault; -import ch.cyberduck.core.cryptomator.CryptorCache; -import ch.cyberduck.core.exception.NotfoundException; - -import org.cryptomator.cryptolib.api.Cryptor; -import org.cryptomator.cryptolib.api.CryptorProvider; -import org.cryptomator.cryptolib.api.PerpetualMasterkey; -import org.junit.Test; - -import java.security.SecureRandom; -import java.util.EnumSet; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; - -public class CryptoDirectoryV7ProviderTest { - - @Test(expected = NotfoundException.class) - public void testToEncryptedInvalidArgument() throws Exception { - final Path home = new Path("/vault", EnumSet.of(Path.Type.directory)); - final CryptorProvider crypto = CryptorProvider.forScheme(CryptorProvider.Scheme.SIV_GCM); - final SecureRandom random = new SecureRandom(); - final Cryptor cryptor = crypto.provide(PerpetualMasterkey.generate(random), random); - final CryptoDirectory provider = new CryptoDirectoryV7Provider(new CryptoVault(home), new CryptoFilenameV7Provider(), new CryptorCache(cryptor.fileNameCryptor())); - provider.toEncrypted(new NullSession(new Host(new TestProtocol())), new Path("/vault/f", EnumSet.of(Path.Type.file))); - } - - @Test(expected = NotfoundException.class) - public void testToEncryptedInvalidPath() throws Exception { - final Path home = new Path("/vault", EnumSet.of(Path.Type.directory)); - final CryptorProvider crypto = CryptorProvider.forScheme(CryptorProvider.Scheme.SIV_GCM); - final SecureRandom random = new SecureRandom(); - final Cryptor cryptor = crypto.provide(PerpetualMasterkey.generate(random), random); - final CryptoDirectory provider = new CryptoDirectoryV7Provider(new CryptoVault(home), new CryptoFilenameV7Provider(), new CryptorCache(cryptor.fileNameCryptor())); - provider.toEncrypted(new NullSession(new Host(new TestProtocol())), new Path("/", EnumSet.of(Path.Type.directory))); - } - - @Test - public void testToEncryptedDirectory() throws Exception { - final Path home = new Path("/vault", EnumSet.of(Path.Type.directory)); - final NullSession session = new NullSession(new Host(new TestProtocol())); - final CryptorProvider crypto = CryptorProvider.forScheme(CryptorProvider.Scheme.SIV_GCM); - final SecureRandom random = new SecureRandom(); - final Cryptor cryptor = crypto.provide(PerpetualMasterkey.generate(random), random); - final CryptoDirectory provider = new CryptoDirectoryV7Provider(new CryptoVault(home), new CryptoFilenameV7Provider(), new CryptorCache(cryptor.fileNameCryptor())); - assertNotNull(provider.toEncrypted(session, home)); - final Path f = new Path("/vault/f", EnumSet.of(Path.Type.directory)); - assertNotNull(provider.toEncrypted(session, f)); - assertEquals(provider.toEncrypted(session, f), provider.toEncrypted(session, f)); - } -} diff --git a/cryptomator/src/test/java/ch/cyberduck/core/cryptomator/impl/CryptoDirectoryV8ProviderTest.java b/cryptomator/src/test/java/ch/cyberduck/core/cryptomator/impl/CryptoDirectoryV8ProviderTest.java new file mode 100644 index 00000000000..866d98a1a0f --- /dev/null +++ b/cryptomator/src/test/java/ch/cyberduck/core/cryptomator/impl/CryptoDirectoryV8ProviderTest.java @@ -0,0 +1,121 @@ +package ch.cyberduck.core.cryptomator.impl; + +/* + * Copyright (c) 2002-2020 iterate GmbH. All rights reserved. + * https://cyberduck.io/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +import ch.cyberduck.core.ConnectionCallback; +import ch.cyberduck.core.Credentials; +import ch.cyberduck.core.DisabledPasswordCallback; +import ch.cyberduck.core.Host; +import ch.cyberduck.core.LoginOptions; +import ch.cyberduck.core.NullSession; +import ch.cyberduck.core.Path; +import ch.cyberduck.core.TestProtocol; +import ch.cyberduck.core.cryptomator.CryptoDirectory; +import ch.cyberduck.core.cryptomator.impl.v8.CryptoVault; +import ch.cyberduck.core.cryptomator.impl.v8.CryptoVaultTest; +import ch.cyberduck.core.exception.BackgroundException; +import ch.cyberduck.core.exception.NotfoundException; +import ch.cyberduck.core.features.Read; +import ch.cyberduck.core.transfer.TransferStatus; +import ch.cyberduck.core.vault.VaultCredentials; + +import org.apache.commons.io.IOUtils; +import org.cryptomator.cryptolib.api.CryptorProvider; +import org.junit.Test; + +import java.io.InputStream; +import java.nio.charset.Charset; +import java.security.SecureRandom; +import java.util.EnumSet; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; + +public class CryptoDirectoryV8ProviderTest { + + @Test(expected = NotfoundException.class) + public void testToEncryptedInvalidArgument() throws Exception { + final Path home = new Path("/vault", EnumSet.of(Path.Type.directory)); + final CryptorProvider crypto = CryptorProvider.forScheme(CryptorProvider.Scheme.SIV_GCM); + final SecureRandom random = new SecureRandom(); + final NullSession session = new NullSession(new Host(new TestProtocol())); + final CryptoDirectory provider = new CryptoDirectoryV8Provider(new CryptoVault(home), new CryptoFilenameV7Provider()); + provider.toEncrypted(session, new Path("/vault/f", EnumSet.of(Path.Type.file))); + } + + @Test(expected = NotfoundException.class) + public void testToEncryptedInvalidPath() throws Exception { + final Path home = new Path("/vault", EnumSet.of(Path.Type.directory)); + final CryptorProvider crypto = CryptorProvider.forScheme(CryptorProvider.Scheme.SIV_GCM); + final SecureRandom random = new SecureRandom(); + final NullSession session = new NullSession(new Host(new TestProtocol())); + final CryptoDirectory provider = new CryptoDirectoryV8Provider(new CryptoVault(home), new CryptoFilenameV7Provider()); + provider.toEncrypted(session, new Path("/", EnumSet.of(Path.Type.directory))); + } + + @Test + public void testToEncryptedDirectory() throws Exception { + final NullSession session = new NullSession(new Host(new TestProtocol())) { + @Override + @SuppressWarnings("unchecked") + public T _getFeature(final Class type) { + if(type == Read.class) { + return (T) new Read() { + @Override + public InputStream read(final Path file, final TransferStatus status, final ConnectionCallback callback) throws BackgroundException { + final String masterKey = "{\n" + + " \"version\": 8,\n" + + " \"scryptSalt\": \"RVAAirkArDU=\",\n" + + " \"scryptCostParam\": 32768,\n" + + " \"scryptBlockSize\": 8,\n" + + " \"primaryMasterKey\": \"+03NkJNWVsJ9Tb1CTpKhXyfINzjDirFFI+iJLOWIOySyxB+abpx34Q==\",\n" + + " \"hmacMasterKey\": \"aMoDtn7Y6kIXxyHo2zl47p5jCYTlRnfx3l3AMgULmIDSYAxVAraSgg==\",\n" + + " \"versionMac\": \"FzirA8UhwCmS5RsC4JvxbO+ZBxaCbIkzqD2Ocagd+A8=\"\n" + + "}"; + + if("masterkey.cryptomator".equals(file.getName())) { + return IOUtils.toInputStream(masterKey, Charset.defaultCharset()); + } + if("vault.cryptomator".equals(file.getName())) { + return IOUtils.toInputStream(CryptoVaultTest.createJWT(masterKey, CryptoVault.VAULT_VERSION, CryptorProvider.Scheme.SIV_GCM, "vault123"), Charset.defaultCharset()); + } + throw new NotfoundException(String.format("%s not found", file.getName())); + } + + @Override + public boolean offset(final Path file) { + return false; + } + }; + } + return super._getFeature(type); + } + }; + final Path home = new Path("/vault", EnumSet.of((Path.Type.directory))); + final CryptoVault vault = new CryptoVault(home); + vault.load(session, new DisabledPasswordCallback() { + @Override + public Credentials prompt(final Host bookmark, final String title, final String reason, final LoginOptions options) { + return new VaultCredentials("vault123"); + } + }); + final CryptoDirectory provider = new CryptoDirectoryV8Provider(vault, new CryptoFilenameV7Provider()); + assertNotNull(provider.toEncrypted(session, home)); + final Path f = new Path("/vault/f", EnumSet.of(Path.Type.directory)); + assertNotNull(provider.toEncrypted(session, f)); + assertEquals(provider.toEncrypted(session, f), provider.toEncrypted(session, f)); + } +} diff --git a/cryptomator/src/test/java/ch/cyberduck/core/cryptomator/CryptoVaultTest.java b/cryptomator/src/test/java/ch/cyberduck/core/cryptomator/impl/v8/CryptoVaultTest.java similarity index 90% rename from cryptomator/src/test/java/ch/cyberduck/core/cryptomator/CryptoVaultTest.java rename to cryptomator/src/test/java/ch/cyberduck/core/cryptomator/impl/v8/CryptoVaultTest.java index bbc7851cead..494dbf8b510 100644 --- a/cryptomator/src/test/java/ch/cyberduck/core/cryptomator/CryptoVaultTest.java +++ b/cryptomator/src/test/java/ch/cyberduck/core/cryptomator/impl/v8/CryptoVaultTest.java @@ -1,7 +1,7 @@ -package ch.cyberduck.core.cryptomator; +package ch.cyberduck.core.cryptomator.impl.v8; /* - * Copyright (c) 2002-2020 iterate GmbH. All rights reserved. + * Copyright (c) 2002-2025 iterate GmbH. All rights reserved. * https://cyberduck.io/ * * This program is free software; you can redistribute it and/or modify @@ -25,6 +25,7 @@ import ch.cyberduck.core.SerializerFactory; import ch.cyberduck.core.TestProtocol; import ch.cyberduck.core.UUIDRandomStringService; +import ch.cyberduck.core.cryptomator.CryptoInvalidFilesizeException; import ch.cyberduck.core.cryptomator.impl.CryptoFilenameV7Provider; import ch.cyberduck.core.cryptomator.random.FastSecureRandomProvider; import ch.cyberduck.core.exception.BackgroundException; @@ -39,6 +40,7 @@ import ch.cyberduck.core.transfer.TransferStatus; import ch.cyberduck.core.vault.DefaultVaultRegistry; import ch.cyberduck.core.vault.VaultCredentials; +import ch.cyberduck.core.vault.VaultMetadata; import org.apache.commons.io.IOUtils; import org.cryptomator.cryptolib.api.CryptorProvider; @@ -60,7 +62,6 @@ import com.auth0.jwt.JWT; import com.auth0.jwt.algorithms.Algorithm; -import static ch.cyberduck.core.cryptomator.CryptoVault.VAULT_VERSION; import static org.junit.Assert.*; public class CryptoVaultTest { @@ -89,7 +90,7 @@ public InputStream read(final Path file, final TransferStatus status, final Conn return IOUtils.toInputStream(masterKey, Charset.defaultCharset()); } if("vault.cryptomator".equals(file.getName())) { - return IOUtils.toInputStream(createJWT(masterKey, VAULT_VERSION, CryptorProvider.Scheme.SIV_GCM, "vault123"), Charset.defaultCharset()); + return IOUtils.toInputStream(createJWT(masterKey, CryptoVault.VAULT_VERSION, CryptorProvider.Scheme.SIV_GCM, "vault123"), Charset.defaultCharset()); } throw new NotfoundException(String.format("%s not found", file.getName())); } @@ -118,8 +119,10 @@ public Credentials prompt(final Host bookmark, final String title, final String assertEquals(vault.encrypt(session, home), vault.encrypt(session, home)); final Path directory = new Path(home, "dir", EnumSet.of(Path.Type.directory)); assertNull(directory.attributes().getVault()); - assertEquals(home, vault.encrypt(session, directory).attributes().getVault()); - assertEquals(home, directory.attributes().getVault()); + assertEquals(home, vault.encrypt(session, directory).attributes().getVaultMetadata().root); + assertEquals(VaultMetadata.Type.V8, vault.encrypt(session, directory).attributes().getVaultMetadata().type); + assertEquals(home, directory.attributes().getVaultMetadata().root); + assertEquals(VaultMetadata.Type.V8, directory.attributes().getVaultMetadata().type); assertEquals(vault.encrypt(session, directory), vault.encrypt(session, directory)); assertEquals(new Path(home, directory.getName(), EnumSet.of(Path.Type.directory, Path.Type.decrypted)), vault.decrypt(session, vault.encrypt(session, directory, true))); final Path placeholder = new Path(home, "placeholder", EnumSet.of(Path.Type.directory, Path.Type.placeholder)); @@ -171,7 +174,7 @@ public InputStream read(final Path file, final TransferStatus status, final Conn return IOUtils.toInputStream(masterKey, Charset.defaultCharset()); } if("vault.cryptomator".equals(file.getName())) { - return IOUtils.toInputStream(createJWT(masterKey, VAULT_VERSION, CryptorProvider.Scheme.SIV_GCM, "vault123"), Charset.defaultCharset()); + return IOUtils.toInputStream(createJWT(masterKey, CryptoVault.VAULT_VERSION, CryptorProvider.Scheme.SIV_GCM, "vault123"), Charset.defaultCharset()); } throw new NotfoundException(String.format("%s not found", file.getName())); } @@ -222,7 +225,7 @@ public InputStream read(final Path file, final TransferStatus status, final Conn return IOUtils.toInputStream(masterKey, Charset.defaultCharset()); } if("vault.cryptomator".equals(file.getName())) { - return IOUtils.toInputStream(createJWT(masterKey, VAULT_VERSION, CryptorProvider.Scheme.SIV_GCM, "vault123"), Charset.defaultCharset()); + return IOUtils.toInputStream(createJWT(masterKey, CryptoVault.VAULT_VERSION, CryptorProvider.Scheme.SIV_GCM, "vault123"), Charset.defaultCharset()); } throw new NotfoundException(String.format("%s not found", file.getName())); } @@ -272,7 +275,7 @@ public InputStream read(final Path file, final TransferStatus status, final Conn return IOUtils.toInputStream(masterKey, Charset.defaultCharset()); } if("vault.cryptomator".equals(file.getName())) { - return IOUtils.toInputStream(createJWT(masterKey, VAULT_VERSION, CryptorProvider.Scheme.SIV_GCM, "vault123"), Charset.defaultCharset()); + return IOUtils.toInputStream(createJWT(masterKey, CryptoVault.VAULT_VERSION, CryptorProvider.Scheme.SIV_GCM, "vault123"), Charset.defaultCharset()); } throw new NotfoundException(String.format("%s not found", file.getName())); } @@ -433,51 +436,6 @@ public Path mkdir(final Write writer, final Path folder, final TransferStatus st vault.create(session, null, new VaultCredentials("test")); } - @Test - public void testCleartextSizeV6() throws Exception { - final Path home = new Path("/vault", EnumSet.of(Path.Type.directory)); - final NullSession session = new NullSession(new Host(new TestProtocol())) { - @Override - @SuppressWarnings("unchecked") - public T _getFeature(final Class type) { - if(type == Directory.class) { - return (T) new Directory() { - - @Override - public Path mkdir(final Write writer, final Path folder, final TransferStatus status) { - assertTrue(folder.equals(home) || folder.isChild(home)); - return folder; - } - }; - } - return super._getFeature(type); - } - }; - final CryptoVault vault = new CryptoVault( - home); - vault.create(session, null, new VaultCredentials("test"), 6); - // zero ciphertextFileSize - try { - vault.toCleartextSize(0L, 0); - fail(); - } - catch(CryptoInvalidFilesizeException e) { - } - // ciphertextFileSize == headerSize - assertEquals(0L, vault.toCleartextSize(0L, vault.getFileHeaderCryptor().headerSize())); - // ciphertextFileSize == headerSize + 1 - try { - vault.toCleartextSize(0L, vault.toCleartextSize(0L, vault.getFileHeaderCryptor().headerSize()) + 1); - fail(); - } - catch(CryptoInvalidFilesizeException e) { - } - // ciphertextFileSize == headerSize + chunkHeaderSize + 1 - assertEquals(1L, vault.toCleartextSize(0L, vault.getFileHeaderCryptor().headerSize() + 48 + 1)); - // ciphertextFileSize == headerSize + (32768 + chunkHeaderSize) + (1 + chunkHeaderSize) + 1 - assertEquals(32769L, vault.toCleartextSize(0L, vault.getFileHeaderCryptor().headerSize() + (32768 + 48) + (1 + 48))); - } - @Test public void testCleartextSizeV8() throws Exception { final Path home = new Path("/vault", EnumSet.of(Path.Type.directory)); @@ -498,8 +456,7 @@ public Path mkdir(final Write writer, final Path folder, final TransferStatus st return super._getFeature(type); } }; - final CryptoVault vault = new CryptoVault( - home); + final CryptoVault vault = new CryptoVault(home); vault.create(session, null, new VaultCredentials("test")); // zero ciphertextFileSize try { @@ -548,8 +505,7 @@ public boolean isSupported(final Path workdir, final String name) { return super._getFeature(type); } }; - final CryptoVault vault = new CryptoVault( - home); + final CryptoVault vault = new CryptoVault(home); vault.create(session, null, new VaultCredentials("test")); for(int i = 0; i < 26000000; i++) { assertEquals(i, vault.toCleartextSize(0L, vault.toCiphertextSize(0L, i))); diff --git a/defaults/src/main/resources/default.properties b/defaults/src/main/resources/default.properties index f1ef70f9a72..795f929637c 100644 --- a/defaults/src/main/resources/default.properties +++ b/defaults/src/main/resources/default.properties @@ -709,13 +709,14 @@ terminal.command.ssh=ssh -t {0} {1}@{2} -p {3} \"cd {4} && exec \\$SHELL -l\" threading.pool.size.max=20 threading.pool.keepalive.seconds=60 cryptomator.enable=true -cryptomator.vault.version=8 +cryptomator.vault.default=v8 cryptomator.vault.autodetect=true cryptomator.vault.autodetect.filecount=10 # Load and add to registry when vault is referenced in file attributes cryptomator.vault.autoload=true cryptomator.vault.masterkey.filename=masterkey.cryptomator cryptomator.vault.config.filename=vault.cryptomator +cryptomator.vault.config.filename.uvf=vault.uvf cryptomator.vault.pepper= cryptomator.vault.skip.regex=dirid.c9r cryptomator.cache.size=1000 diff --git a/defaults/src/main/resources/default/log4j.xml b/defaults/src/main/resources/default/log4j.xml index a02f90d3f10..ce4787cd17e 100644 --- a/defaults/src/main/resources/default/log4j.xml +++ b/defaults/src/main/resources/default/log4j.xml @@ -1,11 +1,11 @@ - + + + - - + + + diff --git a/dropbox/src/test/java/ch/cyberduck/core/AbstractDropboxTest.java b/dropbox/src/test/java/ch/cyberduck/core/AbstractDropboxTest.java index 361a6586246..552af6ebe8c 100644 --- a/dropbox/src/test/java/ch/cyberduck/core/AbstractDropboxTest.java +++ b/dropbox/src/test/java/ch/cyberduck/core/AbstractDropboxTest.java @@ -15,12 +15,12 @@ * GNU General Public License for more details. */ -import ch.cyberduck.core.cryptomator.CryptoVault; import ch.cyberduck.core.dropbox.DropboxProtocol; import ch.cyberduck.core.dropbox.DropboxSession; import ch.cyberduck.core.serializer.impl.dd.ProfilePlistReader; import ch.cyberduck.core.ssl.DefaultX509KeyManager; import ch.cyberduck.core.ssl.DefaultX509TrustManager; +import ch.cyberduck.core.vault.VaultMetadata; import ch.cyberduck.test.VaultTest; import org.junit.After; @@ -38,11 +38,11 @@ public class AbstractDropboxTest extends VaultTest { @Parameterized.Parameters(name = "vaultVersion = {0}") public static Object[] data() { - return new Object[]{CryptoVault.VAULT_VERSION_DEPRECATED, CryptoVault.VAULT_VERSION}; + return new Object[]{VaultMetadata.Type.V8, VaultMetadata.Type.UVF}; } @Parameterized.Parameter - public int vaultVersion; + public VaultMetadata.Type vaultVersion; @After public void disconnect() throws Exception { diff --git a/dropbox/src/test/java/ch/cyberduck/core/cryptomator/CopyWorkerTest.java b/dropbox/src/test/java/ch/cyberduck/core/cryptomator/CopyWorkerTest.java index 84f25f9340d..1060e833a55 100644 --- a/dropbox/src/test/java/ch/cyberduck/core/cryptomator/CopyWorkerTest.java +++ b/dropbox/src/test/java/ch/cyberduck/core/cryptomator/CopyWorkerTest.java @@ -46,12 +46,14 @@ import ch.cyberduck.core.transfer.TransferStatus; import ch.cyberduck.core.vault.DefaultVaultRegistry; import ch.cyberduck.core.vault.VaultCredentials; +import ch.cyberduck.core.vault.VaultMetadata; import ch.cyberduck.core.worker.CopyWorker; import ch.cyberduck.core.worker.DeleteWorker; import ch.cyberduck.test.IntegrationTest; import org.apache.commons.io.IOUtils; import org.apache.commons.lang3.RandomUtils; +import org.junit.Ignore; import org.junit.Test; import org.junit.experimental.categories.Category; import org.junit.runner.RunWith; @@ -66,7 +68,6 @@ import com.dropbox.core.v2.files.Metadata; import static org.junit.Assert.*; -import static org.junit.Assume.assumeTrue; @Category(IntegrationTest.class) @RunWith(value = Parameterized.class) @@ -78,8 +79,8 @@ public void testCopyFile() throws Exception { final Path vault = new Path(home, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); final Path source = new Path(vault, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.file)); final Path target = new Path(vault, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.file)); - final CryptoVault cryptomator = new CryptoVault(vault); - cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); final DefaultVaultRegistry registry = new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator); session.withRegistry(registry); final byte[] content = RandomUtils.nextBytes(40500); @@ -104,8 +105,8 @@ public void testCopyToDifferentFolderCryptomator() throws Exception { final Path source = new Path(vault, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.file)); final Path targetFolder = new Path(vault, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); final Path target = new Path(targetFolder, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.file)); - final CryptoVault cryptomator = new CryptoVault(vault); - cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); final DefaultVaultRegistry registry = new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator); session.withRegistry(registry); new CryptoTouchFeature<>(session, new DefaultTouchFeature( @@ -121,16 +122,17 @@ public void testCopyToDifferentFolderCryptomator() throws Exception { new DeleteWorker(new DisabledLoginCallback(), Collections.singletonList(vault), new DisabledProgressListener()).run(session); } + //TODO @Test + @Ignore(value = "Filename shortening not yet implemented") public void testCopyToDifferentFolderLongFilenameCryptomator() throws Exception { - assumeTrue(vaultVersion == CryptoVault.VAULT_VERSION_DEPRECATED); final Path home = new DefaultHomeFinderService(session).find(); final Path vault = new Path(home, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); final Path source = new Path(vault, new AlphanumericRandomStringService(130).random(), EnumSet.of(Path.Type.file)); final Path targetFolder = new Path(vault, new AlphanumericRandomStringService(130).random(), EnumSet.of(Path.Type.directory)); final Path target = new Path(targetFolder, new AlphanumericRandomStringService(130).random(), EnumSet.of(Path.Type.file)); - final CryptoVault cryptomator = new CryptoVault(vault); - cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); final DefaultVaultRegistry registry = new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator); session.withRegistry(registry); new CryptoTouchFeature<>(session, new DefaultTouchFeature( @@ -152,8 +154,8 @@ public void testCopyFolder() throws Exception { final Path vault = new Path(home, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); final Path folder = new Path(vault, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); final Path file = new Path(folder, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.file)); - final CryptoVault cryptomator = new CryptoVault(vault); - cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); final DefaultVaultRegistry registry = new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator); session.withRegistry(registry); cryptomator.getFeature(session, Directory.class, new DropboxDirectoryFeature(session)).mkdir( @@ -187,8 +189,8 @@ public void testCopyFileIntoVault() throws Exception { assertTrue(new DropboxFindFeature(session).find(cleartextFile)); final Path encryptedFolder = new Path(vault, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); final Path encryptedFile = new Path(encryptedFolder, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.file)); - final CryptoVault cryptomator = new CryptoVault(vault); - cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); final DefaultVaultRegistry registry = new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator); session.withRegistry(registry); cryptomator.getFeature(session, Directory.class, new DropboxDirectoryFeature(session)).mkdir( @@ -213,8 +215,8 @@ public void testCopyDirectoryIntoVault() throws Exception { new DropboxTouchFeature(session).touch(new DropboxWriteFeature(session), cleartextFile, new TransferStatus()); assertTrue(new DropboxFindFeature(session).find(cleartextFolder)); assertTrue(new DropboxFindFeature(session).find(cleartextFile)); - final CryptoVault cryptomator = new CryptoVault(vault); - cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); final DefaultVaultRegistry registry = new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator); session.withRegistry(registry); // move directory into vault @@ -238,8 +240,8 @@ public void testCopyFileOutsideVault() throws Exception { new DropboxDirectoryFeature(session).mkdir(new DropboxWriteFeature(session), clearFolder, new TransferStatus()); final Path encryptedFolder = new Path(vault, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); final Path encryptedFile = new Path(encryptedFolder, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.file)); - final CryptoVault cryptomator = new CryptoVault(vault); - cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); final DefaultVaultRegistry registry = new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator); session.withRegistry(registry); cryptomator.getFeature(session, Directory.class, new DropboxDirectoryFeature(session)).mkdir( @@ -264,8 +266,8 @@ public void testCopyDirectoryOutsideVault() throws Exception { final Path vault = new Path(home, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); final Path encryptedFolder = new Path(vault, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); final Path encryptedFile = new Path(encryptedFolder, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.file)); - final CryptoVault cryptomator = new CryptoVault(vault); - cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); final DefaultVaultRegistry registry = new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator); session.withRegistry(registry); cryptomator.getFeature(session, Directory.class, new DropboxDirectoryFeature(session)).mkdir( diff --git a/dropbox/src/test/java/ch/cyberduck/core/cryptomator/CryptoDropboxSingleTransferWorkerTest.java b/dropbox/src/test/java/ch/cyberduck/core/cryptomator/CryptoDropboxSingleTransferWorkerTest.java index ac5582d36aa..b91cc053ab9 100644 --- a/dropbox/src/test/java/ch/cyberduck/core/cryptomator/CryptoDropboxSingleTransferWorkerTest.java +++ b/dropbox/src/test/java/ch/cyberduck/core/cryptomator/CryptoDropboxSingleTransferWorkerTest.java @@ -50,6 +50,7 @@ import ch.cyberduck.core.transfer.UploadTransfer; import ch.cyberduck.core.vault.DefaultVaultRegistry; import ch.cyberduck.core.vault.VaultCredentials; +import ch.cyberduck.core.vault.VaultMetadata; import ch.cyberduck.core.worker.SingleTransferWorker; import ch.cyberduck.test.IntegrationTest; @@ -91,8 +92,8 @@ public void testUpload() throws Exception { final OutputStream out2 = localFile2.getOutputStream(false); IOUtils.write(content, out2); out2.close(); - final CryptoVault cryptomator = new CryptoVault(vault); - cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); session.withRegistry(new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator)); final Transfer t = new UploadTransfer(new Host(new TestProtocol()), Collections.singletonList(new TransferItem(dir1, localDirectory1)), new NullFilter<>()); assertTrue(new SingleTransferWorker(session, session, t, new TransferOptions(), new TransferSpeedometer(t), new DisabledTransferPrompt() { diff --git a/dropbox/src/test/java/ch/cyberduck/core/cryptomator/DropboxDirectoryFeatureTest.java b/dropbox/src/test/java/ch/cyberduck/core/cryptomator/DropboxDirectoryFeatureTest.java index 3b6fa9869fd..f322ba2ef5d 100644 --- a/dropbox/src/test/java/ch/cyberduck/core/cryptomator/DropboxDirectoryFeatureTest.java +++ b/dropbox/src/test/java/ch/cyberduck/core/cryptomator/DropboxDirectoryFeatureTest.java @@ -35,8 +35,10 @@ import ch.cyberduck.core.transfer.TransferStatus; import ch.cyberduck.core.vault.DefaultVaultRegistry; import ch.cyberduck.core.vault.VaultCredentials; +import ch.cyberduck.core.vault.VaultMetadata; import ch.cyberduck.test.IntegrationTest; +import org.junit.Ignore; import org.junit.Test; import org.junit.experimental.categories.Category; import org.junit.runner.RunWith; @@ -47,7 +49,6 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; -import static org.junit.Assume.assumeTrue; @Category(IntegrationTest.class) @RunWith(value = Parameterized.class) @@ -57,8 +58,8 @@ public class DropboxDirectoryFeatureTest extends AbstractDropboxTest { public void testMakeDirectoryEncrypted() throws Exception { final Path home = new DefaultHomeFinderService(session).find(); final Path vault = new Path(home, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); - final CryptoVault cryptomator = new CryptoVault(vault); - cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); session.withRegistry(new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator)); final Path test = cryptomator.getFeature(session, Directory.class, new DropboxDirectoryFeature(session)).mkdir( cryptomator.getFeature(session, Write.class, new DropboxWriteFeature(session)), new Path(vault, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)), new TransferStatus()); @@ -69,13 +70,13 @@ public void testMakeDirectoryEncrypted() throws Exception { } @Test + @Ignore(value = "Filename shortening not yet implemented") public void testMakeDirectoryLongFilenameEncrypted() throws Exception { - assumeTrue(vaultVersion == CryptoVault.VAULT_VERSION_DEPRECATED); final Path home = new DefaultHomeFinderService(session).find(); final Path vault = new Path(home, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); final Path test = new Path(vault, new AlphanumericRandomStringService(130).random(), EnumSet.of(Path.Type.directory)); - final CryptoVault cryptomator = new CryptoVault(vault); - cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); session.withRegistry(new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator)); cryptomator.getFeature(session, Directory.class, new DropboxDirectoryFeature(session)).mkdir( cryptomator.getFeature(session, Write.class, new DropboxWriteFeature(session)), test, new TransferStatus()); diff --git a/dropbox/src/test/java/ch/cyberduck/core/cryptomator/DropboxListServiceTest.java b/dropbox/src/test/java/ch/cyberduck/core/cryptomator/DropboxListServiceTest.java index ef2ce97f56a..46d80a19ac0 100644 --- a/dropbox/src/test/java/ch/cyberduck/core/cryptomator/DropboxListServiceTest.java +++ b/dropbox/src/test/java/ch/cyberduck/core/cryptomator/DropboxListServiceTest.java @@ -33,6 +33,7 @@ import ch.cyberduck.core.transfer.TransferStatus; import ch.cyberduck.core.vault.DefaultVaultRegistry; import ch.cyberduck.core.vault.VaultCredentials; +import ch.cyberduck.core.vault.VaultMetadata; import ch.cyberduck.test.IntegrationTest; import org.junit.Test; @@ -56,8 +57,8 @@ public class DropboxListServiceTest extends AbstractDropboxTest { public void testListCryptomator() throws Exception { final Path home = new DefaultHomeFinderService(session).find(); final Path vault = new Path(home, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); - final CryptoVault cryptomator = new CryptoVault(vault); - cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); session.withRegistry(new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator)); assertTrue(new CryptoListService(session, new DropboxListService(session), cryptomator).list(vault, new DisabledListProgressListener()).isEmpty()); final Path test = new CryptoTouchFeature<>(session, new DefaultTouchFeature( diff --git a/dropbox/src/test/java/ch/cyberduck/core/cryptomator/DropboxMoveFeatureTest.java b/dropbox/src/test/java/ch/cyberduck/core/cryptomator/DropboxMoveFeatureTest.java index d40ecf497ab..d5efcce3615 100644 --- a/dropbox/src/test/java/ch/cyberduck/core/cryptomator/DropboxMoveFeatureTest.java +++ b/dropbox/src/test/java/ch/cyberduck/core/cryptomator/DropboxMoveFeatureTest.java @@ -39,6 +39,7 @@ import ch.cyberduck.core.transfer.TransferStatus; import ch.cyberduck.core.vault.DefaultVaultRegistry; import ch.cyberduck.core.vault.VaultCredentials; +import ch.cyberduck.core.vault.VaultMetadata; import ch.cyberduck.test.IntegrationTest; import org.junit.Test; @@ -64,8 +65,8 @@ public void testMove() throws Exception { final Path vault = new Path(home, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); final Path folder = new Path(vault, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); final Path file = new Path(folder, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.file)); - final CryptoVault cryptomator = new CryptoVault(vault); - cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); session.withRegistry(new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator)); cryptomator.getFeature(session, Directory.class, new DropboxDirectoryFeature(session)).mkdir( cryptomator.getFeature(session, Write.class, new DropboxWriteFeature(session)), folder, new TransferStatus()); diff --git a/dropbox/src/test/java/ch/cyberduck/core/cryptomator/DropboxTouchFeatureTest.java b/dropbox/src/test/java/ch/cyberduck/core/cryptomator/DropboxTouchFeatureTest.java index 1c7bfd7cc38..99bf044b0e9 100644 --- a/dropbox/src/test/java/ch/cyberduck/core/cryptomator/DropboxTouchFeatureTest.java +++ b/dropbox/src/test/java/ch/cyberduck/core/cryptomator/DropboxTouchFeatureTest.java @@ -35,8 +35,10 @@ import ch.cyberduck.core.transfer.TransferStatus; import ch.cyberduck.core.vault.DefaultVaultRegistry; import ch.cyberduck.core.vault.VaultCredentials; +import ch.cyberduck.core.vault.VaultMetadata; import ch.cyberduck.test.IntegrationTest; +import org.junit.Ignore; import org.junit.Test; import org.junit.experimental.categories.Category; import org.junit.runner.RunWith; @@ -49,19 +51,19 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; -import static org.junit.Assume.assumeTrue; @Category(IntegrationTest.class) @RunWith(value = Parameterized.class) public class DropboxTouchFeatureTest extends AbstractDropboxTest { + //TODO @Test + @Ignore(value = "Filename shortening not yet implemented") public void testTouchLongFilenameEncrypted() throws Exception { - assumeTrue(vaultVersion == CryptoVault.VAULT_VERSION_DEPRECATED); final Path home = new DefaultHomeFinderService(session).find(); final Path vault = new Path(home, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); - final CryptoVault cryptomator = new CryptoVault(vault); - cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); session.withRegistry(new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator)); final TransferStatus status = new TransferStatus(); final Path test = new CryptoTouchFeature<>(session, new DefaultTouchFeature(session), cryptomator).touch( @@ -74,12 +76,12 @@ public void testTouchLongFilenameEncrypted() throws Exception { } @Test + @Ignore(value = "Filename shortening not yet implemented") public void testTouchLongFilenameEncryptedDefaultFeature() throws Exception { - assumeTrue(vaultVersion == CryptoVault.VAULT_VERSION_DEPRECATED); final Path home = new DefaultHomeFinderService(session).find(); final Path vault = new Path(home, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); - final CryptoVault cryptomator = new CryptoVault(vault); - cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); session.withRegistry(new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator)); final TransferStatus status = new TransferStatus(); final Path test = new CryptoTouchFeature<>(session, new DefaultTouchFeature(session), cryptomator).touch( diff --git a/dropbox/src/test/java/ch/cyberduck/core/cryptomator/DropboxWriteFeatureTest.java b/dropbox/src/test/java/ch/cyberduck/core/cryptomator/DropboxWriteFeatureTest.java index 13545619d4c..bb942fd195b 100644 --- a/dropbox/src/test/java/ch/cyberduck/core/cryptomator/DropboxWriteFeatureTest.java +++ b/dropbox/src/test/java/ch/cyberduck/core/cryptomator/DropboxWriteFeatureTest.java @@ -40,6 +40,7 @@ import ch.cyberduck.core.transfer.TransferStatus; import ch.cyberduck.core.vault.DefaultVaultRegistry; import ch.cyberduck.core.vault.VaultCredentials; +import ch.cyberduck.core.vault.VaultMetadata; import ch.cyberduck.test.IntegrationTest; import org.apache.commons.lang3.RandomUtils; @@ -72,8 +73,8 @@ public void testWrite() throws Exception { final Path home = new DefaultHomeFinderService(session).find(); final Path vault = new Path(home, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); final Path test = new Path(vault, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.file)); - final CryptoVault cryptomator = new CryptoVault(vault); - cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); session.withRegistry(new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator)); final CryptoWriteFeature writer = new CryptoWriteFeature<>(session, new DropboxWriteFeature(session), cryptomator); final FileHeader header = cryptomator.getFileHeaderCryptor().create(); diff --git a/dropbox/src/test/java/ch/cyberduck/core/cryptomator/MoveWorkerTest.java b/dropbox/src/test/java/ch/cyberduck/core/cryptomator/MoveWorkerTest.java index 47f1208e211..e71563b8795 100644 --- a/dropbox/src/test/java/ch/cyberduck/core/cryptomator/MoveWorkerTest.java +++ b/dropbox/src/test/java/ch/cyberduck/core/cryptomator/MoveWorkerTest.java @@ -42,9 +42,11 @@ import ch.cyberduck.core.transfer.TransferStatus; import ch.cyberduck.core.vault.DefaultVaultRegistry; import ch.cyberduck.core.vault.VaultCredentials; +import ch.cyberduck.core.vault.VaultMetadata; import ch.cyberduck.core.worker.MoveWorker; import ch.cyberduck.test.IntegrationTest; +import org.junit.Ignore; import org.junit.Test; import org.junit.experimental.categories.Category; import org.junit.runner.RunWith; @@ -55,7 +57,6 @@ import java.util.EnumSet; import static org.junit.Assert.*; -import static org.junit.Assume.assumeTrue; @Category(IntegrationTest.class) @RunWith(value = Parameterized.class) @@ -67,8 +68,8 @@ public void testMoveSameFolderCryptomator() throws Exception { final Path vault = new Path(home, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); final Path source = new Path(vault, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.file)); final Path target = new Path(vault, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.file)); - final CryptoVault cryptomator = new CryptoVault(vault); - cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); session.withRegistry(new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator)); new CryptoTouchFeature<>(session, new DropboxTouchFeature(session), cryptomator).touch( new CryptoWriteFeature<>(session, new DropboxWriteFeature(session), cryptomator), source, new TransferStatus()); @@ -87,8 +88,8 @@ public void testMoveToDifferentFolderCryptomator() throws Exception { final Path source = new Path(vault, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.file)); final Path targetFolder = new Path(vault, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); final Path target = new Path(targetFolder, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.file)); - final CryptoVault cryptomator = new CryptoVault(vault); - cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); session.withRegistry(new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator)); new CryptoTouchFeature<>(session, new DropboxTouchFeature(session), cryptomator).touch( new CryptoWriteFeature<>(session, new DropboxWriteFeature(session), cryptomator), source, new TransferStatus()); @@ -103,16 +104,17 @@ public void testMoveToDifferentFolderCryptomator() throws Exception { cryptomator.getFeature(session, Delete.class, new DropboxDeleteFeature(session)).delete(Arrays.asList(target, targetFolder, vault), new DisabledLoginCallback(), new Delete.DisabledCallback()); } + //TODO @Test + @Ignore(value = "Filename shortening not yet implemented") public void testMoveToDifferentFolderLongFilenameCryptomator() throws Exception { - assumeTrue(vaultVersion == CryptoVault.VAULT_VERSION_DEPRECATED); final Path home = new DefaultHomeFinderService(session).find(); final Path vault = new Path(home, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); final Path source = new Path(vault, new AlphanumericRandomStringService(130).random(), EnumSet.of(Path.Type.file)); final Path targetFolder = new Path(vault, new AlphanumericRandomStringService(130).random(), EnumSet.of(Path.Type.directory)); final Path target = new Path(targetFolder, new AlphanumericRandomStringService(130).random(), EnumSet.of(Path.Type.file)); - final CryptoVault cryptomator = new CryptoVault(vault); - cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); session.withRegistry(new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator)); new CryptoTouchFeature<>(session, new DropboxTouchFeature(session), cryptomator).touch( new CryptoWriteFeature<>(session, new DropboxWriteFeature(session), cryptomator), source, new TransferStatus()); @@ -133,8 +135,8 @@ public void testMoveFolder() throws Exception { final Path vault = new Path(home, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); final Path folder = new Path(vault, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); final Path file = new Path(folder, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.file)); - final CryptoVault cryptomator = new CryptoVault(vault); - cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); session.withRegistry(new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator)); cryptomator.getFeature(session, Directory.class, new DropboxDirectoryFeature(session)).mkdir( cryptomator.getFeature(session, Write.class, new DropboxWriteFeature(session)), folder, new TransferStatus()); @@ -173,8 +175,8 @@ public void testMoveFileIntoVault() throws Exception { assertTrue(new DefaultFindFeature(session).find(clearFile)); final Path encryptedFolder = new Path(vault, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); final Path encryptedFile = new Path(encryptedFolder, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.file)); - final CryptoVault cryptomator = new CryptoVault(vault); - cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); final DefaultVaultRegistry registry = new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator); session.withRegistry(registry); cryptomator.getFeature(session, Directory.class, new DropboxDirectoryFeature(session)).mkdir( @@ -199,8 +201,8 @@ public void testMoveDirectoryIntoVault() throws Exception { new DropboxTouchFeature(session).touch(new DropboxWriteFeature(session), clearFile, new TransferStatus()); assertTrue(new DefaultFindFeature(session).find(clearFolder)); assertTrue(new DefaultFindFeature(session).find(clearFile)); - final CryptoVault cryptomator = new CryptoVault(vault); - cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); final DefaultVaultRegistry registry = new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator); session.withRegistry(registry); // move directory into vault @@ -224,8 +226,8 @@ public void testMoveFileOutsideVault() throws Exception { new DropboxDirectoryFeature(session).mkdir(new DropboxWriteFeature(session), clearFolder, new TransferStatus()); final Path encryptedFolder = new Path(vault, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); final Path encryptedFile = new Path(encryptedFolder, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.file)); - final CryptoVault cryptomator = new CryptoVault(vault); - cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); final DefaultVaultRegistry registry = new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator); session.withRegistry(registry); cryptomator.getFeature(session, Directory.class, new DropboxDirectoryFeature(session)).mkdir( @@ -251,8 +253,8 @@ public void testMoveDirectoryOutsideVault() throws Exception { final Path vault = new Path(home, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); final Path encryptedFolder = new Path(vault, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); final Path encryptedFile = new Path(encryptedFolder, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.file)); - final CryptoVault cryptomator = new CryptoVault(vault); - cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); final DefaultVaultRegistry registry = new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator); session.withRegistry(registry); cryptomator.getFeature(session, Directory.class, new DropboxDirectoryFeature(session)).mkdir( diff --git a/eue/src/test/java/ch/cyberduck/core/cryptomator/EueSingleUploadServiceTest.java b/eue/src/test/java/ch/cyberduck/core/cryptomator/EueSingleUploadServiceTest.java deleted file mode 100644 index 883a1996c04..00000000000 --- a/eue/src/test/java/ch/cyberduck/core/cryptomator/EueSingleUploadServiceTest.java +++ /dev/null @@ -1,102 +0,0 @@ -package ch.cyberduck.core.cryptomator; - -/* - * Copyright (c) 2002-2021 iterate GmbH. All rights reserved. - * https://cyberduck.io/ - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -import ch.cyberduck.core.AbstractPath; -import ch.cyberduck.core.AlphanumericRandomStringService; -import ch.cyberduck.core.BytecountStreamListener; -import ch.cyberduck.core.DisabledConnectionCallback; -import ch.cyberduck.core.DisabledLoginCallback; -import ch.cyberduck.core.DisabledPasswordCallback; -import ch.cyberduck.core.DisabledProgressListener; -import ch.cyberduck.core.Local; -import ch.cyberduck.core.Path; -import ch.cyberduck.core.cryptomator.features.CryptoReadFeature; -import ch.cyberduck.core.cryptomator.features.CryptoUploadFeature; -import ch.cyberduck.core.cryptomator.features.CryptoWriteFeature; -import ch.cyberduck.core.eue.AbstractEueSessionTest; -import ch.cyberduck.core.eue.EueAttributesFinderFeature; -import ch.cyberduck.core.eue.EueDeleteFeature; -import ch.cyberduck.core.eue.EueDirectoryFeature; -import ch.cyberduck.core.eue.EueFindFeature; -import ch.cyberduck.core.eue.EueReadFeature; -import ch.cyberduck.core.eue.EueResourceIdProvider; -import ch.cyberduck.core.eue.EueSingleUploadService; -import ch.cyberduck.core.eue.EueWriteFeature; -import ch.cyberduck.core.features.AttributesFinder; -import ch.cyberduck.core.features.Delete; -import ch.cyberduck.core.features.Find; -import ch.cyberduck.core.io.BandwidthThrottle; -import ch.cyberduck.core.io.StreamCopier; -import ch.cyberduck.core.transfer.TransferStatus; -import ch.cyberduck.core.vault.DefaultVaultRegistry; -import ch.cyberduck.core.vault.VaultCredentials; -import ch.cyberduck.test.IntegrationTest; - -import org.apache.commons.io.IOUtils; -import org.apache.commons.lang3.RandomUtils; -import org.cryptomator.cryptolib.api.FileHeader; -import org.junit.Test; -import org.junit.experimental.categories.Category; -import org.junit.runner.RunWith; -import org.junit.runners.Parameterized; - -import java.io.ByteArrayOutputStream; -import java.io.InputStream; -import java.util.Arrays; -import java.util.EnumSet; -import java.util.UUID; - -import static org.junit.Assert.*; - -@Category(IntegrationTest.class) -@RunWith(value = Parameterized.class) -public class EueSingleUploadServiceTest extends AbstractEueSessionTest { - - @Test - public void testUploadVault() throws Exception { - final EueResourceIdProvider fileid = new EueResourceIdProvider(session); - final Path container = new EueDirectoryFeature(session, fileid).mkdir(new EueWriteFeature(session, fileid), new Path(new AlphanumericRandomStringService().random(), EnumSet.of(AbstractPath.Type.directory)), new TransferStatus().setLength(0L)); - final Path vault = new Path(container, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); - final Path test = new Path(vault, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.file)); - final CryptoVault cryptomator = new CryptoVault(vault); - cryptomator.create(session, new VaultCredentials("test"), vaultVersion); - session.withRegistry(new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator)); - final Local local = new Local(System.getProperty("java.io.tmpdir"), UUID.randomUUID().toString()); - final byte[] content = RandomUtils.nextBytes(502400); - IOUtils.write(content, local.getOutputStream(false)); - final TransferStatus writeStatus = new TransferStatus(); - final FileHeader header = cryptomator.getFileHeaderCryptor().create(); - writeStatus.setHeader(cryptomator.getFileHeaderCryptor().encryptHeader(header)); - writeStatus.setLength(content.length); - final BytecountStreamListener count = new BytecountStreamListener(); - final CryptoUploadFeature feature = new CryptoUploadFeature<>(session, - new EueSingleUploadService(session, fileid), - cryptomator); - feature.upload(new CryptoWriteFeature<>(session, new EueWriteFeature(session, fileid), cryptomator), test, local, new BandwidthThrottle(BandwidthThrottle.UNLIMITED), new DisabledProgressListener(), count, writeStatus, null); - assertEquals(content.length, count.getSent()); - assertTrue(writeStatus.isComplete()); - assertTrue(cryptomator.getFeature(session, Find.class, new EueFindFeature(session, fileid)).find(test)); - assertEquals(content.length, cryptomator.getFeature(session, AttributesFinder.class, new EueAttributesFinderFeature(session, fileid)).find(test).getSize()); - final ByteArrayOutputStream buffer = new ByteArrayOutputStream(content.length); - final TransferStatus readStatus = new TransferStatus().setLength(content.length); - final InputStream in = new CryptoReadFeature(session, new EueReadFeature(session, fileid), cryptomator).read(test, readStatus, new DisabledConnectionCallback()); - new StreamCopier(readStatus, readStatus).transfer(in, buffer); - assertArrayEquals(content, buffer.toByteArray()); - cryptomator.getFeature(session, Delete.class, new EueDeleteFeature(session, fileid)).delete(Arrays.asList(test, vault), new DisabledLoginCallback(), new Delete.DisabledCallback()); - local.delete(); - } -} diff --git a/eue/src/test/java/ch/cyberduck/core/cryptomator/EueThresholdUploadServiceTest.java b/eue/src/test/java/ch/cyberduck/core/cryptomator/EueThresholdUploadServiceTest.java deleted file mode 100644 index 9855b7e9cd1..00000000000 --- a/eue/src/test/java/ch/cyberduck/core/cryptomator/EueThresholdUploadServiceTest.java +++ /dev/null @@ -1,145 +0,0 @@ -package ch.cyberduck.core.cryptomator; - -/* - * Copyright (c) 2002-2021 iterate GmbH. All rights reserved. - * https://cyberduck.io/ - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -import ch.cyberduck.core.AlphanumericRandomStringService; -import ch.cyberduck.core.BytecountStreamListener; -import ch.cyberduck.core.DisabledConnectionCallback; -import ch.cyberduck.core.DisabledLoginCallback; -import ch.cyberduck.core.DisabledPasswordCallback; -import ch.cyberduck.core.DisabledProgressListener; -import ch.cyberduck.core.Local; -import ch.cyberduck.core.Path; -import ch.cyberduck.core.cryptomator.features.CryptoBulkFeature; -import ch.cyberduck.core.cryptomator.features.CryptoReadFeature; -import ch.cyberduck.core.cryptomator.features.CryptoUploadFeature; -import ch.cyberduck.core.cryptomator.features.CryptoWriteFeature; -import ch.cyberduck.core.eue.AbstractEueSessionTest; -import ch.cyberduck.core.eue.EueAttributesFinderFeature; -import ch.cyberduck.core.eue.EueDeleteFeature; -import ch.cyberduck.core.eue.EueDirectoryFeature; -import ch.cyberduck.core.eue.EueFindFeature; -import ch.cyberduck.core.eue.EueReadFeature; -import ch.cyberduck.core.eue.EueResourceIdProvider; -import ch.cyberduck.core.eue.EueThresholdUploadService; -import ch.cyberduck.core.eue.EueWriteFeature; -import ch.cyberduck.core.features.AttributesFinder; -import ch.cyberduck.core.features.Delete; -import ch.cyberduck.core.features.Find; -import ch.cyberduck.core.io.BandwidthThrottle; -import ch.cyberduck.core.io.StreamCopier; -import ch.cyberduck.core.shared.DisabledBulkFeature; -import ch.cyberduck.core.transfer.Transfer; -import ch.cyberduck.core.transfer.TransferItem; -import ch.cyberduck.core.transfer.TransferStatus; -import ch.cyberduck.core.vault.DefaultVaultRegistry; -import ch.cyberduck.core.vault.VaultCredentials; -import ch.cyberduck.test.IntegrationTest; - -import org.apache.commons.io.IOUtils; -import org.apache.commons.lang3.RandomUtils; -import org.cryptomator.cryptolib.api.FileHeader; -import org.junit.Test; -import org.junit.experimental.categories.Category; -import org.junit.runner.RunWith; -import org.junit.runners.Parameterized; - -import java.io.ByteArrayOutputStream; -import java.io.InputStream; -import java.util.Arrays; -import java.util.Collections; -import java.util.EnumSet; -import java.util.Map; -import java.util.UUID; - -import static org.junit.Assert.*; - -@Category(IntegrationTest.class) -@RunWith(value = Parameterized.class) -public class EueThresholdUploadServiceTest extends AbstractEueSessionTest { - - @Test - public void testUploadVault() throws Exception { - final EueResourceIdProvider fileid = new EueResourceIdProvider(session); - final Path container = new EueDirectoryFeature(session, fileid).mkdir(new EueWriteFeature(session, fileid), new Path(new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)), new TransferStatus().setLength(0L)); - final Path vault = new Path(container, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); - final Path test = new Path(vault, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.file)); - final CryptoVault cryptomator = new CryptoVault(vault); - cryptomator.create(session, new VaultCredentials("test"), vaultVersion); - final DefaultVaultRegistry registry = new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator); - session.withRegistry(registry); - final Local local = new Local(System.getProperty("java.io.tmpdir"), UUID.randomUUID().toString()); - final byte[] content = RandomUtils.nextBytes(8840780); - IOUtils.write(content, local.getOutputStream(false)); - final TransferStatus writeStatus = new TransferStatus(); - final FileHeader header = cryptomator.getFileHeaderCryptor().create(); - writeStatus.setHeader(cryptomator.getFileHeaderCryptor().encryptHeader(header)); - writeStatus.setLength(content.length); - final BytecountStreamListener count = new BytecountStreamListener(); - final CryptoUploadFeature feature = new CryptoUploadFeature<>(session, - new EueThresholdUploadService(session, fileid, registry), - cryptomator); - feature.upload(new CryptoWriteFeature<>(session, new EueWriteFeature(session, fileid), cryptomator), test, local, new BandwidthThrottle(BandwidthThrottle.UNLIMITED), new DisabledProgressListener(), count, writeStatus, new DisabledConnectionCallback()); - assertEquals(content.length, count.getSent()); - assertTrue(writeStatus.isComplete()); - assertTrue(cryptomator.getFeature(session, Find.class, new EueFindFeature(session, fileid)).find(test)); - assertEquals(content.length, cryptomator.getFeature(session, AttributesFinder.class, new EueAttributesFinderFeature(session, fileid)).find(test).getSize()); - final ByteArrayOutputStream buffer = new ByteArrayOutputStream(content.length); - final TransferStatus readStatus = new TransferStatus().setLength(content.length); - final InputStream in = new CryptoReadFeature(session, new EueReadFeature(session, fileid), cryptomator).read(test, readStatus, new DisabledConnectionCallback()); - new StreamCopier(readStatus, readStatus).transfer(in, buffer); - assertArrayEquals(content, buffer.toByteArray()); - cryptomator.getFeature(session, Delete.class, new EueDeleteFeature(session, fileid)).delete(Arrays.asList(test, vault), new DisabledLoginCallback(), new Delete.DisabledCallback()); - local.delete(); - } - - @Test - public void testUploadVaultWithBulkFeature() throws Exception { - final EueResourceIdProvider fileid = new EueResourceIdProvider(session); - final Path container = new EueDirectoryFeature(session, fileid).mkdir(new EueWriteFeature(session, fileid), new Path(new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)), new TransferStatus().setLength(0L)); - final Path vault = new Path(container, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); - final Path test = new Path(vault, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.file)); - final CryptoVault cryptomator = new CryptoVault(vault); - cryptomator.create(session, new VaultCredentials("test"), vaultVersion); - final DefaultVaultRegistry registry = new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator); - session.withRegistry(registry); - final Local local = new Local(System.getProperty("java.io.tmpdir"), UUID.randomUUID().toString()); - final byte[] content = RandomUtils.nextBytes(50240000); - IOUtils.write(content, local.getOutputStream(false)); - final TransferStatus writeStatus = new TransferStatus(); - final FileHeader header = cryptomator.getFileHeaderCryptor().create(); - writeStatus.setHeader(cryptomator.getFileHeaderCryptor().encryptHeader(header)); - writeStatus.setLength(content.length); - final CryptoBulkFeature> bulk = new CryptoBulkFeature<>(session, new DisabledBulkFeature(), cryptomator); - bulk.pre(Transfer.Type.upload, Collections.singletonMap(new TransferItem(test), writeStatus), new DisabledConnectionCallback()); - final BytecountStreamListener count = new BytecountStreamListener(); - final CryptoUploadFeature feature = new CryptoUploadFeature<>(session, - new EueThresholdUploadService(session, fileid, registry), - cryptomator); - feature.upload(new CryptoWriteFeature<>(session, new EueWriteFeature(session, fileid), cryptomator), test, local, new BandwidthThrottle(BandwidthThrottle.UNLIMITED), new DisabledProgressListener(), count, writeStatus, new DisabledConnectionCallback()); - assertEquals(content.length, count.getSent()); - assertTrue(writeStatus.isComplete()); - assertTrue(cryptomator.getFeature(session, Find.class, new EueFindFeature(session, fileid)).find(test)); - assertEquals(content.length, cryptomator.getFeature(session, AttributesFinder.class, new EueAttributesFinderFeature(session, fileid)).find(test).getSize()); - final ByteArrayOutputStream buffer = new ByteArrayOutputStream(content.length); - final TransferStatus readStatus = new TransferStatus().setLength(content.length); - final InputStream in = new CryptoReadFeature(session, new EueReadFeature(session, fileid), cryptomator).read(test, readStatus, new DisabledConnectionCallback()); - new StreamCopier(readStatus, readStatus).transfer(in, buffer); - assertArrayEquals(content, buffer.toByteArray()); - cryptomator.getFeature(session, Delete.class, new EueDeleteFeature(session, fileid)).delete(Arrays.asList(test, vault), new DisabledLoginCallback(), new Delete.DisabledCallback()); - local.delete(); - } -} diff --git a/eue/src/test/java/ch/cyberduck/core/cryptomator/EueUploadServiceTest.java b/eue/src/test/java/ch/cyberduck/core/cryptomator/EueUploadServiceTest.java deleted file mode 100644 index 27ecf049804..00000000000 --- a/eue/src/test/java/ch/cyberduck/core/cryptomator/EueUploadServiceTest.java +++ /dev/null @@ -1,145 +0,0 @@ -package ch.cyberduck.core.cryptomator; - -/* - * Copyright (c) 2002-2021 iterate GmbH. All rights reserved. - * https://cyberduck.io/ - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -import ch.cyberduck.core.AbstractPath; -import ch.cyberduck.core.AlphanumericRandomStringService; -import ch.cyberduck.core.BytecountStreamListener; -import ch.cyberduck.core.DisabledConnectionCallback; -import ch.cyberduck.core.DisabledLoginCallback; -import ch.cyberduck.core.DisabledPasswordCallback; -import ch.cyberduck.core.DisabledProgressListener; -import ch.cyberduck.core.Local; -import ch.cyberduck.core.Path; -import ch.cyberduck.core.cryptomator.features.CryptoBulkFeature; -import ch.cyberduck.core.cryptomator.features.CryptoReadFeature; -import ch.cyberduck.core.cryptomator.features.CryptoUploadFeature; -import ch.cyberduck.core.cryptomator.features.CryptoWriteFeature; -import ch.cyberduck.core.eue.AbstractEueSessionTest; -import ch.cyberduck.core.eue.EueAttributesFinderFeature; -import ch.cyberduck.core.eue.EueDeleteFeature; -import ch.cyberduck.core.eue.EueDirectoryFeature; -import ch.cyberduck.core.eue.EueFindFeature; -import ch.cyberduck.core.eue.EueMultipartWriteFeature; -import ch.cyberduck.core.eue.EueReadFeature; -import ch.cyberduck.core.eue.EueResourceIdProvider; -import ch.cyberduck.core.eue.EueUploadService; -import ch.cyberduck.core.eue.EueWriteFeature; -import ch.cyberduck.core.features.AttributesFinder; -import ch.cyberduck.core.features.Delete; -import ch.cyberduck.core.features.Find; -import ch.cyberduck.core.io.BandwidthThrottle; -import ch.cyberduck.core.io.StreamCopier; -import ch.cyberduck.core.shared.DisabledBulkFeature; -import ch.cyberduck.core.transfer.Transfer; -import ch.cyberduck.core.transfer.TransferItem; -import ch.cyberduck.core.transfer.TransferStatus; -import ch.cyberduck.core.vault.DefaultVaultRegistry; -import ch.cyberduck.core.vault.VaultCredentials; -import ch.cyberduck.test.IntegrationTest; - -import org.apache.commons.io.IOUtils; -import org.apache.commons.lang3.RandomUtils; -import org.cryptomator.cryptolib.api.FileHeader; -import org.junit.Test; -import org.junit.experimental.categories.Category; -import org.junit.runner.RunWith; -import org.junit.runners.Parameterized; - -import java.io.ByteArrayOutputStream; -import java.io.InputStream; -import java.util.Arrays; -import java.util.Collections; -import java.util.EnumSet; -import java.util.Map; -import java.util.UUID; - -import static org.junit.Assert.*; - -@Category(IntegrationTest.class) -@RunWith(value = Parameterized.class) -public class EueUploadServiceTest extends AbstractEueSessionTest { - - @Test - public void testUploadVault() throws Exception { - final EueResourceIdProvider fileid = new EueResourceIdProvider(session); - final Path container = new EueDirectoryFeature(session, fileid).mkdir(new EueWriteFeature(session, fileid), new Path(new AlphanumericRandomStringService().random(), EnumSet.of(AbstractPath.Type.directory)), new TransferStatus().setLength(0L)); - final Path vault = new Path(container, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); - final Path test = new Path(vault, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.file)); - final CryptoVault cryptomator = new CryptoVault(vault); - cryptomator.create(session, new VaultCredentials("test"), vaultVersion); - session.withRegistry(new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator)); - final Local local = new Local(System.getProperty("java.io.tmpdir"), UUID.randomUUID().toString()); - final byte[] content = RandomUtils.nextBytes(50240000); - IOUtils.write(content, local.getOutputStream(false)); - final TransferStatus writeStatus = new TransferStatus(); - final FileHeader header = cryptomator.getFileHeaderCryptor().create(); - writeStatus.setHeader(cryptomator.getFileHeaderCryptor().encryptHeader(header)); - writeStatus.setLength(content.length); - final BytecountStreamListener count = new BytecountStreamListener(); - final CryptoUploadFeature feature = new CryptoUploadFeature<>(session, - new EueUploadService(session), - cryptomator); - feature.upload(new CryptoWriteFeature<>(session, new EueMultipartWriteFeature(session, fileid), cryptomator), test, local, new BandwidthThrottle(BandwidthThrottle.UNLIMITED), new DisabledProgressListener(), count, writeStatus, new DisabledConnectionCallback()); - assertEquals(content.length, count.getSent()); - assertTrue(writeStatus.isComplete()); - assertTrue(cryptomator.getFeature(session, Find.class, new EueFindFeature(session, fileid)).find(test)); - assertEquals(content.length, cryptomator.getFeature(session, AttributesFinder.class, new EueAttributesFinderFeature(session, fileid)).find(test).getSize()); - final ByteArrayOutputStream buffer = new ByteArrayOutputStream(content.length); - final TransferStatus readStatus = new TransferStatus().setLength(content.length); - final InputStream in = new CryptoReadFeature(session, new EueReadFeature(session, fileid), cryptomator).read(test, readStatus, new DisabledConnectionCallback()); - new StreamCopier(readStatus, readStatus).transfer(in, buffer); - assertArrayEquals(content, buffer.toByteArray()); - cryptomator.getFeature(session, Delete.class, new EueDeleteFeature(session, fileid)).delete(Arrays.asList(test, vault), new DisabledLoginCallback(), new Delete.DisabledCallback()); - local.delete(); - } - - @Test - public void testUploadVaultWithBulkFeature() throws Exception { - final EueResourceIdProvider fileid = new EueResourceIdProvider(session); - final Path container = new EueDirectoryFeature(session, fileid).mkdir(new EueWriteFeature(session, fileid), new Path(new AlphanumericRandomStringService().random(), EnumSet.of(AbstractPath.Type.directory)), new TransferStatus().setLength(0L)); - final Path vault = new Path(container, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); - final Path test = new Path(vault, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.file)); - final CryptoVault cryptomator = new CryptoVault(vault); - cryptomator.create(session, new VaultCredentials("test"), vaultVersion); - session.withRegistry(new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator)); - final Local local = new Local(System.getProperty("java.io.tmpdir"), UUID.randomUUID().toString()); - final byte[] content = RandomUtils.nextBytes(50240000); - IOUtils.write(content, local.getOutputStream(false)); - final TransferStatus writeStatus = new TransferStatus(); - final FileHeader header = cryptomator.getFileHeaderCryptor().create(); - writeStatus.setHeader(cryptomator.getFileHeaderCryptor().encryptHeader(header)); - writeStatus.setLength(content.length); - final CryptoBulkFeature> bulk = new CryptoBulkFeature<>(session, new DisabledBulkFeature(), cryptomator); - bulk.pre(Transfer.Type.upload, Collections.singletonMap(new TransferItem(test), writeStatus), new DisabledConnectionCallback()); - final BytecountStreamListener count = new BytecountStreamListener(); - final CryptoUploadFeature feature = new CryptoUploadFeature<>(session, - new EueUploadService(session), - cryptomator); - feature.upload(new CryptoWriteFeature<>(session, new EueMultipartWriteFeature(session, fileid), cryptomator), test, local, new BandwidthThrottle(BandwidthThrottle.UNLIMITED), new DisabledProgressListener(), count, writeStatus, new DisabledConnectionCallback()); - assertEquals(content.length, count.getSent()); - assertTrue(writeStatus.isComplete()); - assertTrue(cryptomator.getFeature(session, Find.class, new EueFindFeature(session, fileid)).find(test)); - assertEquals(content.length, cryptomator.getFeature(session, AttributesFinder.class, new EueAttributesFinderFeature(session, fileid)).find(test).getSize()); - final ByteArrayOutputStream buffer = new ByteArrayOutputStream(content.length); - final TransferStatus readStatus = new TransferStatus().setLength(content.length); - final InputStream in = new CryptoReadFeature(session, new EueReadFeature(session, fileid), cryptomator).read(test, readStatus, new DisabledConnectionCallback()); - new StreamCopier(readStatus, readStatus).transfer(in, buffer); - assertArrayEquals(content, buffer.toByteArray()); - cryptomator.getFeature(session, Delete.class, new EueDeleteFeature(session, fileid)).delete(Arrays.asList(test, vault), new DisabledLoginCallback(), new Delete.DisabledCallback()); - local.delete(); - } -} diff --git a/eue/src/test/java/ch/cyberduck/core/cryptomator/EueWriteFeatureTest.java b/eue/src/test/java/ch/cyberduck/core/cryptomator/EueWriteFeatureTest.java deleted file mode 100644 index ee7f0729570..00000000000 --- a/eue/src/test/java/ch/cyberduck/core/cryptomator/EueWriteFeatureTest.java +++ /dev/null @@ -1,97 +0,0 @@ -package ch.cyberduck.core.cryptomator; - -/* - * Copyright (c) 2002-2017 iterate GmbH. All rights reserved. - * https://cyberduck.io/ - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -import ch.cyberduck.core.AlphanumericRandomStringService; -import ch.cyberduck.core.DisabledConnectionCallback; -import ch.cyberduck.core.DisabledLoginCallback; -import ch.cyberduck.core.DisabledPasswordCallback; -import ch.cyberduck.core.Path; -import ch.cyberduck.core.PathAttributes; -import ch.cyberduck.core.cryptomator.features.CryptoReadFeature; -import ch.cyberduck.core.cryptomator.features.CryptoWriteFeature; -import ch.cyberduck.core.cryptomator.random.RotatingNonceGenerator; -import ch.cyberduck.core.eue.AbstractEueSessionTest; -import ch.cyberduck.core.eue.EueDeleteFeature; -import ch.cyberduck.core.eue.EueFindFeature; -import ch.cyberduck.core.eue.EueReadFeature; -import ch.cyberduck.core.eue.EueResourceIdProvider; -import ch.cyberduck.core.eue.EueWriteFeature; -import ch.cyberduck.core.features.Delete; -import ch.cyberduck.core.features.Find; -import ch.cyberduck.core.io.StreamCopier; -import ch.cyberduck.core.preferences.HostPreferencesFactory; -import ch.cyberduck.core.shared.DefaultHomeFinderService; -import ch.cyberduck.core.transfer.TransferStatus; -import ch.cyberduck.core.vault.DefaultVaultRegistry; -import ch.cyberduck.core.vault.VaultCredentials; -import ch.cyberduck.test.IntegrationTest; - -import org.apache.commons.lang3.RandomUtils; -import org.cryptomator.cryptolib.api.FileHeader; -import org.junit.Test; -import org.junit.experimental.categories.Category; -import org.junit.runner.RunWith; -import org.junit.runners.Parameterized; - -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.InputStream; -import java.io.OutputStream; -import java.nio.charset.StandardCharsets; -import java.util.Arrays; -import java.util.EnumSet; - -import static org.junit.Assert.*; - -@Category(IntegrationTest.class) -@RunWith(value = Parameterized.class) -public class EueWriteFeatureTest extends AbstractEueSessionTest { - - @Test - public void testWrite() throws Exception { - final TransferStatus status = new TransferStatus(); - final int length = 1048576; - final byte[] content = RandomUtils.nextBytes(length); - status.setLength(content.length); - final Path home = new DefaultHomeFinderService(session).find(); - final Path vault = new Path(home, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); - final Path test = new Path(vault, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.file)); - final CryptoVault cryptomator = new CryptoVault(vault, - HostPreferencesFactory.get(session.getHost()).getProperty("cryptomator.vault.masterkey.filename"), - HostPreferencesFactory.get(session.getHost()).getProperty("cryptomator.vault.config.filename"), - HostPreferencesFactory.get(session.getHost()).getProperty("cryptomator.vault.pepper").getBytes(StandardCharsets.UTF_8)); - cryptomator.create(session, new VaultCredentials("test"), vaultVersion); - session.withRegistry(new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator)); - final EueResourceIdProvider fileid = new EueResourceIdProvider(session); - final CryptoWriteFeature writer = new CryptoWriteFeature(session, new EueWriteFeature(session, fileid), cryptomator); - final FileHeader header = cryptomator.getFileHeaderCryptor().create(); - status.setHeader(cryptomator.getFileHeaderCryptor().encryptHeader(header)); - status.setNonces(new RotatingNonceGenerator(cryptomator.getNonceSize(), cryptomator.numberOfChunks(content.length))); - status.setChecksum(writer.checksum(test, status).compute(new ByteArrayInputStream(content), status)); - final OutputStream out = writer.write(test, status, new DisabledConnectionCallback()); - assertNotNull(out); - new StreamCopier(status, status).transfer(new ByteArrayInputStream(content), out); - out.close(); - assertEquals(PathAttributes.EMPTY, status.getResponse()); - assertTrue(cryptomator.getFeature(session, Find.class, new EueFindFeature(session, fileid)).find(test)); - final ByteArrayOutputStream buffer = new ByteArrayOutputStream(content.length); - final InputStream in = new CryptoReadFeature(session, new EueReadFeature(session, fileid), cryptomator).read(test, new TransferStatus().setLength(content.length), new DisabledConnectionCallback()); - new StreamCopier(status, status).transfer(in, buffer); - assertArrayEquals(content, buffer.toByteArray()); - cryptomator.getFeature(session, Delete.class, new EueDeleteFeature(session, fileid)).delete(Arrays.asList(test, vault), new DisabledLoginCallback(), new Delete.DisabledCallback()); - } -} diff --git a/eue/src/test/java/ch/cyberduck/core/eue/AbstractEueSessionTest.java b/eue/src/test/java/ch/cyberduck/core/eue/AbstractEueSessionTest.java index 61e9963eb82..fbb0ecd92c5 100644 --- a/eue/src/test/java/ch/cyberduck/core/eue/AbstractEueSessionTest.java +++ b/eue/src/test/java/ch/cyberduck/core/eue/AbstractEueSessionTest.java @@ -16,7 +16,6 @@ */ import ch.cyberduck.core.*; -import ch.cyberduck.core.cryptomator.CryptoVault; import ch.cyberduck.core.eue.io.swagger.client.ApiException; import ch.cyberduck.core.eue.io.swagger.client.api.CreateShareApi; import ch.cyberduck.core.eue.io.swagger.client.model.ShareCreationRequestModel; @@ -29,6 +28,7 @@ import ch.cyberduck.core.ssl.DefaultX509KeyManager; import ch.cyberduck.core.ssl.DisabledX509TrustManager; import ch.cyberduck.core.transfer.TransferStatus; +import ch.cyberduck.core.vault.VaultMetadata; import ch.cyberduck.test.VaultTest; import org.junit.After; @@ -48,7 +48,7 @@ public class AbstractEueSessionTest extends VaultTest { @Parameterized.Parameters(name = "vaultVersion = {0}") public static Object[] data() { - return new Object[]{CryptoVault.VAULT_VERSION_DEPRECATED, CryptoVault.VAULT_VERSION}; + return new Object[]{VaultMetadata.Type.V8, VaultMetadata.Type.UVF}; } @Parameterized.Parameter diff --git a/ftp/src/main/java/ch/cyberduck/core/ftp/FTPMoveFeature.java b/ftp/src/main/java/ch/cyberduck/core/ftp/FTPMoveFeature.java index 4918708ac78..bc1292d5998 100644 --- a/ftp/src/main/java/ch/cyberduck/core/ftp/FTPMoveFeature.java +++ b/ftp/src/main/java/ch/cyberduck/core/ftp/FTPMoveFeature.java @@ -51,7 +51,7 @@ public Path move(final Path file, final Path renamed, final TransferStatus statu throw new FTPException(session.getClient().getReplyCode(), session.getClient().getReplyString()); } // Copy original file attributes - return new Path(renamed).withAttributes(new PathAttributes(file.attributes()).setVault(null)); + return new Path(renamed).withAttributes(new PathAttributes(file.attributes()).setVaultMetadata(null)); } catch(IOException e) { throw new FTPExceptionMappingService().map("Cannot rename {0}", e, file); diff --git a/ftp/src/test/java/ch/cyberduck/core/cryptomator/CopyWorkerTest.java b/ftp/src/test/java/ch/cyberduck/core/cryptomator/CopyWorkerTest.java index a6606753f84..a252b7ee0a9 100644 --- a/ftp/src/test/java/ch/cyberduck/core/cryptomator/CopyWorkerTest.java +++ b/ftp/src/test/java/ch/cyberduck/core/cryptomator/CopyWorkerTest.java @@ -50,12 +50,14 @@ import ch.cyberduck.core.transfer.TransferStatus; import ch.cyberduck.core.vault.DefaultVaultRegistry; import ch.cyberduck.core.vault.VaultCredentials; +import ch.cyberduck.core.vault.VaultMetadata; import ch.cyberduck.core.worker.CopyWorker; import ch.cyberduck.core.worker.DeleteWorker; import ch.cyberduck.test.IntegrationTest; import org.apache.commons.io.IOUtils; import org.apache.commons.lang3.RandomUtils; +import org.junit.Ignore; import org.junit.Test; import org.junit.experimental.categories.Category; import org.junit.runner.RunWith; @@ -69,7 +71,6 @@ import java.util.EnumSet; import static org.junit.Assert.*; -import static org.junit.Assume.assumeTrue; @Category(IntegrationTest.class) @RunWith(value = Parameterized.class) @@ -81,8 +82,8 @@ public void testCopyFile() throws Exception { final Path vault = new Path(home, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); final Path source = new Path(vault, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.file)); final Path target = new Path(vault, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.file)); - final CryptoVault cryptomator = new CryptoVault(vault); - cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); final DefaultVaultRegistry registry = new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator); session.withRegistry(registry); final byte[] content = RandomUtils.nextBytes(40500); @@ -112,8 +113,8 @@ public void testCopyToDifferentFolderCryptomator() throws Exception { final Path source = new Path(vault, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.file)); final Path targetFolder = new Path(vault, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); final Path target = new Path(targetFolder, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.file)); - final CryptoVault cryptomator = new CryptoVault(vault); - cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); final DefaultVaultRegistry registry = new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator); session.withRegistry(registry); new CryptoTouchFeature<>(session, new DefaultTouchFeature( @@ -134,15 +135,15 @@ public void testCopyToDifferentFolderCryptomator() throws Exception { } @Test + @Ignore("Filename shortening not implemented yet") public void testCopyToDifferentFolderLongFilenameCryptomator() throws Exception { - assumeTrue(vaultVersion == CryptoVault.VAULT_VERSION_DEPRECATED); final Path home = new DefaultHomeFinderService(session).find(); final Path vault = new Path(home, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); final Path source = new Path(vault, new AlphanumericRandomStringService(130).random(), EnumSet.of(Path.Type.file)); final Path targetFolder = new Path(vault, new AlphanumericRandomStringService(130).random(), EnumSet.of(Path.Type.directory)); final Path target = new Path(targetFolder, new AlphanumericRandomStringService(130).random(), EnumSet.of(Path.Type.file)); - final CryptoVault cryptomator = new CryptoVault(vault); - cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); final DefaultVaultRegistry registry = new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator); session.withRegistry(registry); new CryptoTouchFeature<>(session, new DefaultTouchFeature( @@ -168,8 +169,8 @@ public void testCopyFolder() throws Exception { final Path vault = new Path(home, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); final Path folder = new Path(vault, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); final Path file = new Path(folder, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.file)); - final CryptoVault cryptomator = new CryptoVault(vault); - cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); final DefaultVaultRegistry registry = new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator); session.withRegistry(registry); cryptomator.getFeature(session, Directory.class, new FTPDirectoryFeature(session)).mkdir( @@ -207,8 +208,8 @@ public void testCopyFileIntoVault() throws Exception { assertTrue(new DefaultFindFeature(session).find(cleartextFile)); final Path encryptedFolder = new Path(vault, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); final Path encryptedFile = new Path(encryptedFolder, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.file)); - final CryptoVault cryptomator = new CryptoVault(vault); - cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); final DefaultVaultRegistry registry = new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator); session.withRegistry(registry); cryptomator.getFeature(session, Directory.class, new FTPDirectoryFeature(session)).mkdir( @@ -237,8 +238,8 @@ public void testCopyDirectoryIntoVault() throws Exception { session).touch(new FTPWriteFeature(session), cleartextFile, new TransferStatus()); assertTrue(new DefaultFindFeature(session).find(cleartextFolder)); assertTrue(new DefaultFindFeature(session).find(cleartextFile)); - final CryptoVault cryptomator = new CryptoVault(vault); - cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); final DefaultVaultRegistry registry = new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator); session.withRegistry(registry); // move directory into vault @@ -265,8 +266,8 @@ public void testCopyFileOutsideVault() throws Exception { new FTPDirectoryFeature(session).mkdir(new FTPWriteFeature(session), clearFolder, new TransferStatus()); final Path encryptedFolder = new Path(vault, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); final Path encryptedFile = new Path(encryptedFolder, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.file)); - final CryptoVault cryptomator = new CryptoVault(vault); - cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); final DefaultVaultRegistry registry = new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator); session.withRegistry(registry); cryptomator.getFeature(session, Directory.class, new FTPDirectoryFeature(session)).mkdir( @@ -294,8 +295,8 @@ public void testCopyDirectoryOutsideVault() throws Exception { final Path vault = new Path(home, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); final Path encryptedFolder = new Path(vault, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); final Path encryptedFile = new Path(encryptedFolder, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.file)); - final CryptoVault cryptomator = new CryptoVault(vault); - cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); final DefaultVaultRegistry registry = new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator); session.withRegistry(registry); cryptomator.getFeature(session, Directory.class, new FTPDirectoryFeature(session)).mkdir( diff --git a/ftp/src/test/java/ch/cyberduck/core/cryptomator/CryptoFTPSingleTransferWorkerTest.java b/ftp/src/test/java/ch/cyberduck/core/cryptomator/CryptoFTPSingleTransferWorkerTest.java index 4f0bb490a8a..ea7a7ad32c4 100644 --- a/ftp/src/test/java/ch/cyberduck/core/cryptomator/CryptoFTPSingleTransferWorkerTest.java +++ b/ftp/src/test/java/ch/cyberduck/core/cryptomator/CryptoFTPSingleTransferWorkerTest.java @@ -50,6 +50,7 @@ import ch.cyberduck.core.transfer.UploadTransfer; import ch.cyberduck.core.vault.DefaultVaultRegistry; import ch.cyberduck.core.vault.VaultCredentials; +import ch.cyberduck.core.vault.VaultMetadata; import ch.cyberduck.core.worker.SingleTransferWorker; import ch.cyberduck.test.IntegrationTest; @@ -91,8 +92,8 @@ public void testUpload() throws Exception { final OutputStream out2 = localFile2.getOutputStream(false); IOUtils.write(content, out2); out2.close(); - final CryptoVault cryptomator = new CryptoVault(vault); - cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); session.withRegistry(new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator)); final Transfer t = new UploadTransfer(new Host(new TestProtocol()), Collections.singletonList(new TransferItem(dir1, localDirectory1)), new NullFilter<>()); assertTrue(new SingleTransferWorker(session, session, t, new TransferOptions(), new TransferSpeedometer(t), new DisabledTransferPrompt() { diff --git a/ftp/src/test/java/ch/cyberduck/core/cryptomator/FTPDirectoryFeatureTest.java b/ftp/src/test/java/ch/cyberduck/core/cryptomator/FTPDirectoryFeatureTest.java index ea4c791fddb..e4d716462ff 100644 --- a/ftp/src/test/java/ch/cyberduck/core/cryptomator/FTPDirectoryFeatureTest.java +++ b/ftp/src/test/java/ch/cyberduck/core/cryptomator/FTPDirectoryFeatureTest.java @@ -32,8 +32,10 @@ import ch.cyberduck.core.transfer.TransferStatus; import ch.cyberduck.core.vault.DefaultVaultRegistry; import ch.cyberduck.core.vault.VaultCredentials; +import ch.cyberduck.core.vault.VaultMetadata; import ch.cyberduck.test.IntegrationTest; +import org.junit.Ignore; import org.junit.Test; import org.junit.experimental.categories.Category; import org.junit.runner.RunWith; @@ -44,7 +46,6 @@ import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; -import static org.junit.Assume.assumeTrue; @Category(IntegrationTest.class) @RunWith(value = Parameterized.class) @@ -57,8 +58,8 @@ public void testMakeDirectoryEncrypted() throws Exception { final Path testdirectory = new Path(vault, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); final Path testdirectory2 = new Path(testdirectory, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); final Path testfile2 = new Path(testdirectory2, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.file)); - final CryptoVault cryptomator = new CryptoVault(vault); - cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); session.withRegistry(new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator)); cryptomator.getFeature(session, Directory.class, new FTPDirectoryFeature(session)).mkdir( cryptomator.getFeature(session, Write.class, new FTPWriteFeature(session)), testdirectory, new TransferStatus()); @@ -71,13 +72,13 @@ public void testMakeDirectoryEncrypted() throws Exception { } @Test + @Ignore("Filename shortening not implemented yet") public void testMakeDirectoryLongFilenameEncrypted() throws Exception { - assumeTrue(vaultVersion == CryptoVault.VAULT_VERSION_DEPRECATED); final Path home = new DefaultHomeFinderService(session).find(); final Path vault = new Path(home, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); final Path test = new Path(vault, new AlphanumericRandomStringService(130).random(), EnumSet.of(Path.Type.directory)); - final CryptoVault cryptomator = new CryptoVault(vault); - cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); session.withRegistry(new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator)); cryptomator.getFeature(session, Directory.class, new FTPDirectoryFeature(session)).mkdir( cryptomator.getFeature(session, Write.class, new FTPWriteFeature(session)), test, new TransferStatus()); diff --git a/ftp/src/test/java/ch/cyberduck/core/cryptomator/FTPListServiceTest.java b/ftp/src/test/java/ch/cyberduck/core/cryptomator/FTPListServiceTest.java index 8eefa271447..175910e52a2 100644 --- a/ftp/src/test/java/ch/cyberduck/core/cryptomator/FTPListServiceTest.java +++ b/ftp/src/test/java/ch/cyberduck/core/cryptomator/FTPListServiceTest.java @@ -41,6 +41,7 @@ import ch.cyberduck.core.transfer.TransferStatus; import ch.cyberduck.core.vault.DefaultVaultRegistry; import ch.cyberduck.core.vault.VaultCredentials; +import ch.cyberduck.core.vault.VaultMetadata; import ch.cyberduck.test.IntegrationTest; import org.junit.Test; @@ -63,8 +64,8 @@ public void testListCryptomator() throws Exception { final Path home = new DefaultHomeFinderService(session).find(); final Path vault = new Path(home, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); final Path test = new Path(vault, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.file)); - final CryptoVault cryptomator = new CryptoVault(vault); - cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); session.withRegistry(new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator)); assertTrue(new CryptoListService(session, new FTPListService(session), cryptomator).list(vault).isEmpty()); new CryptoTouchFeature<>(session, new DefaultTouchFeature( diff --git a/ftp/src/test/java/ch/cyberduck/core/cryptomator/FTPMoveFeatureTest.java b/ftp/src/test/java/ch/cyberduck/core/cryptomator/FTPMoveFeatureTest.java index b5f00a980b4..a67efa3c849 100644 --- a/ftp/src/test/java/ch/cyberduck/core/cryptomator/FTPMoveFeatureTest.java +++ b/ftp/src/test/java/ch/cyberduck/core/cryptomator/FTPMoveFeatureTest.java @@ -37,6 +37,7 @@ import ch.cyberduck.core.transfer.TransferStatus; import ch.cyberduck.core.vault.DefaultVaultRegistry; import ch.cyberduck.core.vault.VaultCredentials; +import ch.cyberduck.core.vault.VaultMetadata; import ch.cyberduck.test.IntegrationTest; import org.junit.Test; @@ -60,8 +61,8 @@ public void testMove() throws Exception { final Path vault = new Path(home, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); final Path folder = new Path(vault, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); final Path file = new Path(folder, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.file)); - final CryptoVault cryptomator = new CryptoVault(vault); - cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); session.withRegistry(new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator)); cryptomator.getFeature(session, Directory.class, new FTPDirectoryFeature(session)).mkdir( new CryptoWriteFeature<>(session, new FTPWriteFeature(session), cryptomator), folder, new TransferStatus()); diff --git a/ftp/src/test/java/ch/cyberduck/core/cryptomator/FTPTouchFeatureTest.java b/ftp/src/test/java/ch/cyberduck/core/cryptomator/FTPTouchFeatureTest.java index 64d7d458c06..1fc469ac17b 100644 --- a/ftp/src/test/java/ch/cyberduck/core/cryptomator/FTPTouchFeatureTest.java +++ b/ftp/src/test/java/ch/cyberduck/core/cryptomator/FTPTouchFeatureTest.java @@ -35,8 +35,10 @@ import ch.cyberduck.core.transfer.TransferStatus; import ch.cyberduck.core.vault.DefaultVaultRegistry; import ch.cyberduck.core.vault.VaultCredentials; +import ch.cyberduck.core.vault.VaultMetadata; import ch.cyberduck.test.IntegrationTest; +import org.junit.Ignore; import org.junit.Test; import org.junit.experimental.categories.Category; import org.junit.runner.RunWith; @@ -47,7 +49,6 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; -import static org.junit.Assume.assumeTrue; @Category(IntegrationTest.class) @RunWith(value = Parameterized.class) @@ -57,8 +58,8 @@ public class FTPTouchFeatureTest extends AbstractFTPTest { public void testTouchEncrypted() throws Exception { final Path home = new DefaultHomeFinderService(session).find(); final Path vault = new Path(home, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); - final CryptoVault cryptomator = new CryptoVault(vault); - cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); session.withRegistry(new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator)); final TransferStatus status = new TransferStatus().setLength(0L); final Path test = new CryptoTouchFeature<>(session, new DefaultTouchFeature(session), cryptomator).touch( @@ -72,12 +73,12 @@ public void testTouchEncrypted() throws Exception { } @Test + @Ignore("Filename shortening not implemented yet") public void testTouchLongFilenameEncrypted() throws Exception { - assumeTrue(vaultVersion == CryptoVault.VAULT_VERSION_DEPRECATED); final Path home = new DefaultHomeFinderService(session).find(); final Path vault = new Path(home, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); - final CryptoVault cryptomator = new CryptoVault(vault); - cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); session.withRegistry(new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator)); final TransferStatus status = new TransferStatus(); final Path test = new CryptoTouchFeature<>(session, new DefaultTouchFeature(session), cryptomator).touch( @@ -88,12 +89,12 @@ public void testTouchLongFilenameEncrypted() throws Exception { } @Test + @Ignore("Filename shortening not implemented yet") public void testTouchLongFilenameEncryptedDefaultFeature() throws Exception { - assumeTrue(vaultVersion == CryptoVault.VAULT_VERSION_DEPRECATED); final Path home = new DefaultHomeFinderService(session).find(); final Path vault = new Path(home, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); - final CryptoVault cryptomator = new CryptoVault(vault); - cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); session.withRegistry(new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator)); final TransferStatus status = new TransferStatus(); final Path test = new CryptoTouchFeature<>(session, new DefaultTouchFeature(session), cryptomator).touch( diff --git a/ftp/src/test/java/ch/cyberduck/core/cryptomator/FTPWriteFeatureTest.java b/ftp/src/test/java/ch/cyberduck/core/cryptomator/FTPWriteFeatureTest.java index 0af02eaf7a8..98488d5f8d6 100644 --- a/ftp/src/test/java/ch/cyberduck/core/cryptomator/FTPWriteFeatureTest.java +++ b/ftp/src/test/java/ch/cyberduck/core/cryptomator/FTPWriteFeatureTest.java @@ -41,6 +41,7 @@ import ch.cyberduck.core.transfer.TransferStatus; import ch.cyberduck.core.vault.DefaultVaultRegistry; import ch.cyberduck.core.vault.VaultCredentials; +import ch.cyberduck.core.vault.VaultMetadata; import ch.cyberduck.test.IntegrationTest; import org.apache.commons.lang3.RandomUtils; @@ -72,8 +73,8 @@ public void testWrite() throws Exception { final Path home = new DefaultHomeFinderService(session).find(); final Path vault = new Path(home, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); final Path test = new Path(vault, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.file)); - final CryptoVault cryptomator = new CryptoVault(vault); - cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); session.withRegistry(new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator)); final CryptoWriteFeature writer = new CryptoWriteFeature<>(session, new FTPWriteFeature(session), cryptomator); final FileHeader header = cryptomator.getFileHeaderCryptor().create(); diff --git a/ftp/src/test/java/ch/cyberduck/core/cryptomator/MoveWorkerTest.java b/ftp/src/test/java/ch/cyberduck/core/cryptomator/MoveWorkerTest.java index e12337a030d..d66becd2149 100644 --- a/ftp/src/test/java/ch/cyberduck/core/cryptomator/MoveWorkerTest.java +++ b/ftp/src/test/java/ch/cyberduck/core/cryptomator/MoveWorkerTest.java @@ -47,9 +47,11 @@ import ch.cyberduck.core.transfer.TransferStatus; import ch.cyberduck.core.vault.DefaultVaultRegistry; import ch.cyberduck.core.vault.VaultCredentials; +import ch.cyberduck.core.vault.VaultMetadata; import ch.cyberduck.core.worker.MoveWorker; import ch.cyberduck.test.IntegrationTest; +import org.junit.Ignore; import org.junit.Test; import org.junit.experimental.categories.Category; import org.junit.runner.RunWith; @@ -61,7 +63,6 @@ import java.util.UUID; import static org.junit.Assert.*; -import static org.junit.Assume.assumeTrue; @Category(IntegrationTest.class) @RunWith(value = Parameterized.class) @@ -73,8 +74,8 @@ public void testMoveSameFolderCryptomator() throws Exception { final Path vault = new Path(home, UUID.randomUUID().toString(), EnumSet.of(Path.Type.directory)); final Path source = new Path(vault, UUID.randomUUID().toString(), EnumSet.of(Path.Type.file)); final Path target = new Path(vault, UUID.randomUUID().toString(), EnumSet.of(Path.Type.file)); - final CryptoVault cryptomator = new CryptoVault(vault); - cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); session.withRegistry(new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator)); new CryptoTouchFeature<>(session, new DefaultTouchFeature( session), cryptomator).touch(new FTPWriteFeature(session), source, new TransferStatus()); @@ -93,8 +94,8 @@ public void testMoveToDifferentFolderCryptomator() throws Exception { final Path source = new Path(vault, UUID.randomUUID().toString(), EnumSet.of(Path.Type.file)); final Path targetFolder = new Path(vault, UUID.randomUUID().toString(), EnumSet.of(Path.Type.directory)); final Path target = new Path(targetFolder, UUID.randomUUID().toString(), EnumSet.of(Path.Type.file)); - final CryptoVault cryptomator = new CryptoVault(vault); - cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); session.withRegistry(new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator)); new CryptoTouchFeature<>(session, new DefaultTouchFeature( session), cryptomator).touch(new FTPWriteFeature(session), source, new TransferStatus()); @@ -111,16 +112,16 @@ public void testMoveToDifferentFolderCryptomator() throws Exception { } @Test + @Ignore("Filename shortening not implemented yet") public void testMoveToDifferentFolderLongFilenameCryptomator() throws Exception { - assumeTrue(vaultVersion == CryptoVault.VAULT_VERSION_DEPRECATED); final Path home = new DefaultHomeFinderService(session).find(); final Path vault = new Path(home, UUID.randomUUID().toString(), EnumSet.of(Path.Type.directory)); final Path sourceFolder = new Path(vault, new AlphanumericRandomStringService(130).random(), EnumSet.of(Path.Type.directory)); final Path source = new Path(sourceFolder, new AlphanumericRandomStringService(130).random(), EnumSet.of(Path.Type.file)); final Path targetFolder = new Path(vault, new AlphanumericRandomStringService(130).random(), EnumSet.of(Path.Type.directory)); final Path target = new Path(targetFolder, new AlphanumericRandomStringService(130).random(), EnumSet.of(Path.Type.file)); - final CryptoVault cryptomator = new CryptoVault(vault); - cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); session.withRegistry(new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator)); cryptomator.getFeature(session, Directory.class, new FTPDirectoryFeature(session)).mkdir(cryptomator.getFeature(session, Write.class, new FTPWriteFeature(session)), sourceFolder, new TransferStatus()); new CryptoTouchFeature<>(session, new DefaultTouchFeature( @@ -142,8 +143,8 @@ public void testMoveFolder() throws Exception { final Path vault = new Path(home, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); final Path folder = new Path(vault, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); final Path file = new Path(folder, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.file)); - final CryptoVault cryptomator = new CryptoVault(vault); - cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); session.withRegistry(new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator)); cryptomator.getFeature(session, Directory.class, new FTPDirectoryFeature(session)).mkdir( cryptomator.getFeature(session, Write.class, new FTPWriteFeature(session)), folder, new TransferStatus()); @@ -182,8 +183,8 @@ public void testMoveFileIntoVault() throws Exception { assertTrue(new DefaultFindFeature(session).find(clearFile)); final Path encryptedFolder = new Path(vault, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); final Path encryptedFile = new Path(encryptedFolder, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.file)); - final CryptoVault cryptomator = new CryptoVault(vault); - cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); final DefaultVaultRegistry registry = new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator); session.withRegistry(registry); cryptomator.getFeature(session, Directory.class, new FTPDirectoryFeature(session)).mkdir( @@ -211,8 +212,8 @@ public void testMoveDirectoryIntoVault() throws Exception { new DefaultTouchFeature(session).touch(new FTPWriteFeature(session), clearFile, new TransferStatus()); assertTrue(new DefaultFindFeature(session).find(clearFolder)); assertTrue(new DefaultFindFeature(session).find(clearFile)); - final CryptoVault cryptomator = new CryptoVault(vault); - cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); final DefaultVaultRegistry registry = new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator); session.withRegistry(registry); // move directory into vault @@ -239,8 +240,8 @@ public void testMoveFileOutsideVault() throws Exception { new FTPDirectoryFeature(session).mkdir(new FTPWriteFeature(session), clearFolder, new TransferStatus()); final Path encryptedFolder = new Path(vault, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); final Path encryptedFile = new Path(encryptedFolder, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.file)); - final CryptoVault cryptomator = new CryptoVault(vault); - cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); final DefaultVaultRegistry registry = new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator); session.withRegistry(registry); cryptomator.getFeature(session, Directory.class, new FTPDirectoryFeature(session)).mkdir( @@ -269,8 +270,8 @@ public void testMoveDirectoryOutsideVault() throws Exception { final Path vault = new Path(home, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); final Path encryptedFolder = new Path(vault, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); final Path encryptedFile = new Path(encryptedFolder, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.file)); - final CryptoVault cryptomator = new CryptoVault(vault); - cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); final DefaultVaultRegistry registry = new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator); session.withRegistry(registry); cryptomator.getFeature(session, Directory.class, new FTPDirectoryFeature(session)).mkdir( diff --git a/ftp/src/test/java/ch/cyberduck/core/ftp/AbstractFTPTest.java b/ftp/src/test/java/ch/cyberduck/core/ftp/AbstractFTPTest.java index c10c44305cc..b5347ae05c0 100644 --- a/ftp/src/test/java/ch/cyberduck/core/ftp/AbstractFTPTest.java +++ b/ftp/src/test/java/ch/cyberduck/core/ftp/AbstractFTPTest.java @@ -29,7 +29,6 @@ import ch.cyberduck.core.Profile; import ch.cyberduck.core.ProtocolFactory; import ch.cyberduck.core.Scheme; -import ch.cyberduck.core.cryptomator.CryptoVault; import ch.cyberduck.core.exception.AccessDeniedException; import ch.cyberduck.core.exception.BackgroundException; import ch.cyberduck.core.exception.NotfoundException; @@ -37,6 +36,7 @@ import ch.cyberduck.core.serializer.impl.dd.ProfilePlistReader; import ch.cyberduck.core.ssl.DefaultX509KeyManager; import ch.cyberduck.core.ssl.DefaultX509TrustManager; +import ch.cyberduck.core.vault.VaultMetadata; import org.apache.ftpserver.FtpServer; import org.apache.ftpserver.FtpServerFactory; @@ -69,11 +69,11 @@ public class AbstractFTPTest { @Parameterized.Parameters(name = "vaultVersion = {0}") public static Object[] data() { - return new Object[]{CryptoVault.VAULT_VERSION_DEPRECATED, CryptoVault.VAULT_VERSION}; + return new Object[]{VaultMetadata.Type.V8, VaultMetadata.Type.UVF}; } @Parameterized.Parameter - public int vaultVersion; + public VaultMetadata.Type vaultVersion; @After public void disconnect() { diff --git a/googledrive/src/test/java/ch/cyberduck/core/cryptomator/CopyWorkerTest.java b/googledrive/src/test/java/ch/cyberduck/core/cryptomator/CopyWorkerTest.java index 91df747da3d..4fafe93594b 100644 --- a/googledrive/src/test/java/ch/cyberduck/core/cryptomator/CopyWorkerTest.java +++ b/googledrive/src/test/java/ch/cyberduck/core/cryptomator/CopyWorkerTest.java @@ -47,12 +47,14 @@ import ch.cyberduck.core.transfer.TransferStatus; import ch.cyberduck.core.vault.DefaultVaultRegistry; import ch.cyberduck.core.vault.VaultCredentials; +import ch.cyberduck.core.vault.VaultMetadata; import ch.cyberduck.core.worker.CopyWorker; import ch.cyberduck.core.worker.DeleteWorker; import ch.cyberduck.test.IntegrationTest; import org.apache.commons.io.IOUtils; import org.apache.commons.lang3.RandomUtils; +import org.junit.Ignore; import org.junit.Test; import org.junit.experimental.categories.Category; import org.junit.runner.RunWith; @@ -67,7 +69,6 @@ import com.google.api.services.drive.model.File; import static org.junit.Assert.*; -import static org.junit.Assume.assumeTrue; @Category(IntegrationTest.class) @RunWith(value = Parameterized.class) @@ -79,8 +80,8 @@ public void testCopyFile() throws Exception { final Path vault = new Path(home, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); final Path source = new Path(vault, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.file)); final Path target = new Path(vault, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.file)); - final CryptoVault cryptomator = new CryptoVault(vault); - cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); final DefaultVaultRegistry registry = new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator); session.withRegistry(registry); final byte[] content = RandomUtils.nextBytes(40500); @@ -106,8 +107,8 @@ public void testCopyToDifferentFolderCryptomator() throws Exception { final Path source = new Path(vault, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.file)); final Path targetFolder = new Path(vault, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); final Path target = new Path(targetFolder, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.file)); - final CryptoVault cryptomator = new CryptoVault(vault); - cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); final DefaultVaultRegistry registry = new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator); session.withRegistry(registry); final DriveFileIdProvider fileid = new DriveFileIdProvider(session); @@ -125,16 +126,17 @@ public void testCopyToDifferentFolderCryptomator() throws Exception { new DeleteWorker(new DisabledLoginCallback(), Collections.singletonList(vault), new DisabledProgressListener()).run(session); } + //TODO @Test + @Ignore("File name shortening not implemented yet") public void testCopyToDifferentFolderLongFilenameCryptomator() throws Exception { - assumeTrue(vaultVersion == CryptoVault.VAULT_VERSION_DEPRECATED); final Path home = DriveHomeFinderService.MYDRIVE_FOLDER; final Path vault = new Path(home, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); final Path source = new Path(vault, new AlphanumericRandomStringService(130).random(), EnumSet.of(Path.Type.file)); final Path targetFolder = new Path(vault, new AlphanumericRandomStringService(130).random(), EnumSet.of(Path.Type.directory)); final Path target = new Path(targetFolder, new AlphanumericRandomStringService(130).random(), EnumSet.of(Path.Type.file)); - final CryptoVault cryptomator = new CryptoVault(vault); - cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); final DefaultVaultRegistry registry = new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator); session.withRegistry(registry); final DriveFileIdProvider fileid = new DriveFileIdProvider(session); @@ -158,8 +160,8 @@ public void testCopyFolder() throws Exception { final Path vault = new Path(home, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); final Path folder = new Path(vault, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); final Path file = new Path(folder, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.file)); - final CryptoVault cryptomator = new CryptoVault(vault); - cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); final DefaultVaultRegistry registry = new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator); session.withRegistry(registry); final DriveFileIdProvider fileid = new DriveFileIdProvider(session); @@ -195,8 +197,8 @@ public void testCopyFileIntoVault() throws Exception { assertTrue(new DriveFindFeature(session, fileid).find(cleartextFile)); final Path encryptedFolder = new Path(vault, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); final Path encryptedFile = new Path(encryptedFolder, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.file)); - final CryptoVault cryptomator = new CryptoVault(vault); - cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); final DefaultVaultRegistry registry = new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator); session.withRegistry(registry); cryptomator.getFeature(session, Directory.class, new DriveDirectoryFeature(session, fileid)).mkdir( @@ -222,8 +224,8 @@ public void testCopyDirectoryIntoVault() throws Exception { new DriveTouchFeature(session, fileid).touch(new DriveWriteFeature(session, fileid), cleartextFile, new TransferStatus()); assertTrue(new DriveFindFeature(session, fileid).find(cleartextFolder)); assertTrue(new DriveFindFeature(session, fileid).find(cleartextFile)); - final CryptoVault cryptomator = new CryptoVault(vault); - cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); final DefaultVaultRegistry registry = new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator); session.withRegistry(registry); // move directory into vault @@ -248,8 +250,8 @@ public void testCopyFileOutsideVault() throws Exception { new DriveDirectoryFeature(session, fileid).mkdir(new DriveWriteFeature(session, fileid), clearFolder, new TransferStatus()); final Path encryptedFolder = new Path(vault, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); final Path encryptedFile = new Path(encryptedFolder, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.file)); - final CryptoVault cryptomator = new CryptoVault(vault); - cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); final DefaultVaultRegistry registry = new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator); session.withRegistry(registry); cryptomator.getFeature(session, Directory.class, new DriveDirectoryFeature(session, fileid)).mkdir( @@ -273,8 +275,8 @@ public void testCopyDirectoryOutsideVault() throws Exception { final Path vault = new Path(home, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); final Path encryptedFolder = new Path(vault, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); final Path encryptedFile = new Path(encryptedFolder, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.file)); - final CryptoVault cryptomator = new CryptoVault(vault); - cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); final DefaultVaultRegistry registry = new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator); session.withRegistry(registry); final DriveFileIdProvider fileid = new DriveFileIdProvider(session); diff --git a/googledrive/src/test/java/ch/cyberduck/core/cryptomator/CryptoDriveTransferWorkerTest.java b/googledrive/src/test/java/ch/cyberduck/core/cryptomator/CryptoDriveTransferWorkerTest.java index 353798ef0a4..c245faeaca2 100644 --- a/googledrive/src/test/java/ch/cyberduck/core/cryptomator/CryptoDriveTransferWorkerTest.java +++ b/googledrive/src/test/java/ch/cyberduck/core/cryptomator/CryptoDriveTransferWorkerTest.java @@ -51,6 +51,7 @@ import ch.cyberduck.core.transfer.UploadTransfer; import ch.cyberduck.core.vault.DefaultVaultRegistry; import ch.cyberduck.core.vault.VaultCredentials; +import ch.cyberduck.core.vault.VaultMetadata; import ch.cyberduck.core.worker.SingleTransferWorker; import ch.cyberduck.test.IntegrationTest; @@ -91,8 +92,8 @@ public void testUpload() throws Exception { final OutputStream out2 = localFile2.getOutputStream(false); IOUtils.write(content, out2); out2.close(); - final CryptoVault cryptomator = new CryptoVault(vault); - cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); session.withRegistry(new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator)); final Transfer t = new UploadTransfer(new Host(new TestProtocol()), Collections.singletonList(new TransferItem(dir1, localDirectory1)), new NullFilter<>()); Assert.assertTrue(new SingleTransferWorker(session, session, t, new TransferOptions(), new TransferSpeedometer(t), new DisabledTransferPrompt() { diff --git a/googledrive/src/test/java/ch/cyberduck/core/cryptomator/DriveAttributesFinderFeatureTest.java b/googledrive/src/test/java/ch/cyberduck/core/cryptomator/DriveAttributesFinderFeatureTest.java index 9b0915f23ce..1b3ca1a3a74 100644 --- a/googledrive/src/test/java/ch/cyberduck/core/cryptomator/DriveAttributesFinderFeatureTest.java +++ b/googledrive/src/test/java/ch/cyberduck/core/cryptomator/DriveAttributesFinderFeatureTest.java @@ -46,6 +46,7 @@ import ch.cyberduck.core.transfer.TransferStatus; import ch.cyberduck.core.vault.DefaultVaultRegistry; import ch.cyberduck.core.vault.VaultCredentials; +import ch.cyberduck.core.vault.VaultMetadata; import ch.cyberduck.test.IntegrationTest; import org.junit.Test; @@ -68,8 +69,8 @@ public class DriveAttributesFinderFeatureTest extends AbstractDriveTest { public void testFindCustomAttributesFinderCryptomator() throws Exception { final Path home = DriveHomeFinderService.MYDRIVE_FOLDER; final Path vault = new Path(home, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); - final CryptoVault cryptomator = new CryptoVault(vault); - cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); session.withRegistry(new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator)); final DriveFileIdProvider fileid = new DriveFileIdProvider(session); final Path test = new CryptoTouchFeature<>(session, new DefaultTouchFeature(session), cryptomator).touch( @@ -85,8 +86,8 @@ public void testFindCustomAttributesFinderCryptomator() throws Exception { public void testFindDefaultAttributesFinderCryptomator() throws Exception { final Path home = DriveHomeFinderService.MYDRIVE_FOLDER; final Path vault = new Path(home, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); - final CryptoVault cryptomator = new CryptoVault(vault); - cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); session.withRegistry(new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator)); final DriveFileIdProvider fileid = new DriveFileIdProvider(session); final Path test = new CryptoTouchFeature<>(session, new DefaultTouchFeature(session), cryptomator).touch( @@ -102,8 +103,8 @@ public void testFindDefaultAttributesFinderCryptomator() throws Exception { public void testFindDirectoryDefaultAttributesFinderCryptomator() throws Exception { final Path home = DriveHomeFinderService.MYDRIVE_FOLDER; final Path vault = new Path(home, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); - final CryptoVault cryptomator = new CryptoVault(vault); - cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); session.withRegistry(new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator)); final DriveFileIdProvider fileid = new DriveFileIdProvider(session); final Path test = cryptomator.getFeature(session, Directory.class, new DriveDirectoryFeature(session, fileid)).mkdir( @@ -120,8 +121,8 @@ public void testFindDirectoryDefaultAttributesFinderCryptomator() throws Excepti public void testFindDefaultAttributesFinderWithCacheCryptomator() throws Exception { final Path home = DriveHomeFinderService.MYDRIVE_FOLDER; final Path vault = new Path(home, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); - final CryptoVault cryptomator = new CryptoVault(vault); - cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); session.withRegistry(new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator)); final DriveFileIdProvider fileid = new DriveFileIdProvider(session); final Path test = new CryptoTouchFeature<>(session, new DefaultTouchFeature(session), cryptomator).touch( @@ -142,8 +143,8 @@ public void testFindDefaultAttributesFinderWithCacheCryptomator() throws Excepti public void testFindAttributesFinderWithCacheCryptomator() throws Exception { final Path home = DriveHomeFinderService.MYDRIVE_FOLDER; final Path vault = new Path(home, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); - final CryptoVault cryptomator = new CryptoVault(vault); - cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); session.withRegistry(new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator)); final DriveFileIdProvider fileid = new DriveFileIdProvider(session); final Path test = new CryptoTouchFeature<>(session, new DefaultTouchFeature(session), cryptomator).touch( @@ -164,8 +165,8 @@ public void testFindAttributesFinderWithCacheCryptomator() throws Exception { public void testFindDirectoryDefaultAttributesFinderWithCacheCryptomator() throws Exception { final Path home = DriveHomeFinderService.MYDRIVE_FOLDER; final Path vault = new Path(home, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); - final CryptoVault cryptomator = new CryptoVault(vault); - cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); session.withRegistry(new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator)); final DriveFileIdProvider fileid = new DriveFileIdProvider(session); assertEquals(new CryptoFileIdProvider(session, fileid, cryptomator).getFileId(vault), diff --git a/googledrive/src/test/java/ch/cyberduck/core/cryptomator/DriveDirectoryFeatureTest.java b/googledrive/src/test/java/ch/cyberduck/core/cryptomator/DriveDirectoryFeatureTest.java index b16f19d3489..68ba389b26c 100644 --- a/googledrive/src/test/java/ch/cyberduck/core/cryptomator/DriveDirectoryFeatureTest.java +++ b/googledrive/src/test/java/ch/cyberduck/core/cryptomator/DriveDirectoryFeatureTest.java @@ -41,8 +41,10 @@ import ch.cyberduck.core.transfer.TransferStatus; import ch.cyberduck.core.vault.DefaultVaultRegistry; import ch.cyberduck.core.vault.VaultCredentials; +import ch.cyberduck.core.vault.VaultMetadata; import ch.cyberduck.test.IntegrationTest; +import org.junit.Ignore; import org.junit.Test; import org.junit.experimental.categories.Category; import org.junit.runner.RunWith; @@ -54,7 +56,6 @@ import java.util.stream.Collectors; import static org.junit.Assert.*; -import static org.junit.Assume.assumeTrue; @Category(IntegrationTest.class) @RunWith(value = Parameterized.class) @@ -63,9 +64,9 @@ public class DriveDirectoryFeatureTest extends AbstractDriveTest { @Test public void testMakeDirectoryEncrypted() throws Exception { final Path home = DriveHomeFinderService.MYDRIVE_FOLDER; - final CryptoVault cryptomator = new CryptoVault( - new Path(home, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory))); - final Path vault = cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final Path vault = new Path(home, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); session.withRegistry(new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator)); final DriveFileIdProvider fileid = new DriveFileIdProvider(session); final Path test = cryptomator.getFeature(session, Directory.class, new DriveDirectoryFeature(session, fileid)).mkdir( @@ -84,13 +85,14 @@ public void testMakeDirectoryEncrypted() throws Exception { cryptomator.getFeature(session, Delete.class, new DriveDeleteFeature(session, fileid)).delete(Collections.singletonList(vault), new DisabledLoginCallback(), new Delete.DisabledCallback()); } + //TODO @Test + @Ignore("File name shortening not implemented yet") public void testMakeDirectoryLongFilenameEncrypted() throws Exception { - assumeTrue(vaultVersion == CryptoVault.VAULT_VERSION_DEPRECATED); final Path home = DriveHomeFinderService.MYDRIVE_FOLDER; - final CryptoVault cryptomator = new CryptoVault( - new Path(home, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory))); - final Path vault = cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final Path vault = new Path(home, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); session.withRegistry(new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator)); final DriveFileIdProvider fileid = new DriveFileIdProvider(session); final Path test = cryptomator.getFeature(session, Directory.class, new DriveDirectoryFeature(session, fileid)).mkdir( diff --git a/googledrive/src/test/java/ch/cyberduck/core/cryptomator/DriveListServiceTest.java b/googledrive/src/test/java/ch/cyberduck/core/cryptomator/DriveListServiceTest.java index 8737f0f2518..b70030439f9 100644 --- a/googledrive/src/test/java/ch/cyberduck/core/cryptomator/DriveListServiceTest.java +++ b/googledrive/src/test/java/ch/cyberduck/core/cryptomator/DriveListServiceTest.java @@ -38,6 +38,7 @@ import ch.cyberduck.core.transfer.TransferStatus; import ch.cyberduck.core.vault.DefaultVaultRegistry; import ch.cyberduck.core.vault.VaultCredentials; +import ch.cyberduck.core.vault.VaultMetadata; import ch.cyberduck.test.IntegrationTest; import org.junit.Test; @@ -60,9 +61,9 @@ public class DriveListServiceTest extends AbstractDriveTest { @Test public void testListCryptomator() throws Exception { final Path home = DriveHomeFinderService.MYDRIVE_FOLDER; - final CryptoVault cryptomator = new CryptoVault( - new Path(home, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory))); - final Path vault = cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final Path vault = new Path(home, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); session.withRegistry(new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator)); final DriveFileIdProvider fileid = new DriveFileIdProvider(session); assertTrue(new CryptoListService(session, new DriveDefaultListService(session, fileid), cryptomator).list(vault, new DisabledListProgressListener()).isEmpty()); diff --git a/googledrive/src/test/java/ch/cyberduck/core/cryptomator/DriveMoveFeatureTest.java b/googledrive/src/test/java/ch/cyberduck/core/cryptomator/DriveMoveFeatureTest.java index 9ee2e402f34..7f6e3519eeb 100644 --- a/googledrive/src/test/java/ch/cyberduck/core/cryptomator/DriveMoveFeatureTest.java +++ b/googledrive/src/test/java/ch/cyberduck/core/cryptomator/DriveMoveFeatureTest.java @@ -40,6 +40,7 @@ import ch.cyberduck.core.transfer.TransferStatus; import ch.cyberduck.core.vault.DefaultVaultRegistry; import ch.cyberduck.core.vault.VaultCredentials; +import ch.cyberduck.core.vault.VaultMetadata; import ch.cyberduck.test.IntegrationTest; import org.junit.Test; @@ -61,9 +62,9 @@ public class DriveMoveFeatureTest extends AbstractDriveTest { @Test public void testMove() throws Exception { final Path home = DriveHomeFinderService.MYDRIVE_FOLDER; - final CryptoVault cryptomator = new CryptoVault( - new Path(home, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory))); - final Path vault = cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final Path vault = new Path(home, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); session.withRegistry(new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator)); final DriveFileIdProvider fileid = new DriveFileIdProvider(session); final Path folder = cryptomator.getFeature(session, Directory.class, new DriveDirectoryFeature(session, fileid)).mkdir( diff --git a/googledrive/src/test/java/ch/cyberduck/core/cryptomator/DriveTouchFeatureTest.java b/googledrive/src/test/java/ch/cyberduck/core/cryptomator/DriveTouchFeatureTest.java index 65276bcddab..35b8f363b6c 100644 --- a/googledrive/src/test/java/ch/cyberduck/core/cryptomator/DriveTouchFeatureTest.java +++ b/googledrive/src/test/java/ch/cyberduck/core/cryptomator/DriveTouchFeatureTest.java @@ -37,8 +37,10 @@ import ch.cyberduck.core.transfer.TransferStatus; import ch.cyberduck.core.vault.DefaultVaultRegistry; import ch.cyberduck.core.vault.VaultCredentials; +import ch.cyberduck.core.vault.VaultMetadata; import ch.cyberduck.test.IntegrationTest; +import org.junit.Ignore; import org.junit.Test; import org.junit.experimental.categories.Category; import org.junit.runner.RunWith; @@ -51,7 +53,6 @@ import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; -import static org.junit.Assume.assumeTrue; @Category(IntegrationTest.class) @RunWith(value = Parameterized.class) @@ -60,9 +61,9 @@ public class DriveTouchFeatureTest extends AbstractDriveTest { @Test public void testTouch() throws Exception { final Path home = DriveHomeFinderService.MYDRIVE_FOLDER; - final CryptoVault cryptomator = new CryptoVault( - new Path(home, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory))); - final Path vault = cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final Path vault = new Path(home, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); session.withRegistry(new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator)); final DriveFileIdProvider fileid = new DriveFileIdProvider(session); final Path test = new CryptoTouchFeature<>(session, new DefaultTouchFeature(session), cryptomator).touch( @@ -74,13 +75,14 @@ public void testTouch() throws Exception { cryptomator.getFeature(session, Delete.class, new DriveDeleteFeature(session, fileid)).delete(Arrays.asList(test, vault), new DisabledLoginCallback(), new Delete.DisabledCallback()); } + //TODO @Test + @Ignore("Filename shorterning not implemented yet") public void testTouchLongFilenameEncrypted() throws Exception { - assumeTrue(vaultVersion == CryptoVault.VAULT_VERSION_DEPRECATED); final Path home = DriveHomeFinderService.MYDRIVE_FOLDER; - final CryptoVault cryptomator = new CryptoVault( - new Path(home, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory))); - final Path vault = cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final Path vault = new Path(home, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); session.withRegistry(new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator)); final DriveFileIdProvider fileid = new DriveFileIdProvider(session); final Path test = new CryptoTouchFeature<>(session, new DefaultTouchFeature(session), cryptomator).touch( @@ -93,12 +95,12 @@ public void testTouchLongFilenameEncrypted() throws Exception { } @Test + @Ignore("Filename shorterning not implemented yet") public void testTouchLongFilenameEncryptedDefaultFeature() throws Exception { - assumeTrue(vaultVersion == CryptoVault.VAULT_VERSION_DEPRECATED); final Path home = DriveHomeFinderService.MYDRIVE_FOLDER; - final CryptoVault cryptomator = new CryptoVault( - new Path(home, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory))); - final Path vault = cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final Path vault = new Path(home, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); session.withRegistry(new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator)); final DriveFileIdProvider fileid = new DriveFileIdProvider(session); final Path test = new CryptoTouchFeature<>(session, new DefaultTouchFeature(session), cryptomator).touch( diff --git a/googledrive/src/test/java/ch/cyberduck/core/cryptomator/DriveWriteFeatureTest.java b/googledrive/src/test/java/ch/cyberduck/core/cryptomator/DriveWriteFeatureTest.java index 64a7b77aa27..32df51d3f15 100644 --- a/googledrive/src/test/java/ch/cyberduck/core/cryptomator/DriveWriteFeatureTest.java +++ b/googledrive/src/test/java/ch/cyberduck/core/cryptomator/DriveWriteFeatureTest.java @@ -51,6 +51,7 @@ import ch.cyberduck.core.transfer.TransferStatus; import ch.cyberduck.core.vault.DefaultVaultRegistry; import ch.cyberduck.core.vault.VaultCredentials; +import ch.cyberduck.core.vault.VaultMetadata; import ch.cyberduck.test.IntegrationTest; import org.apache.commons.lang3.RandomUtils; @@ -82,9 +83,9 @@ public void testWrite() throws Exception { final byte[] content = RandomUtils.nextBytes(length); status.setLength(content.length); final Path home = DriveHomeFinderService.MYDRIVE_FOLDER; - final CryptoVault cryptomator = new CryptoVault( - new Path(home, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory))); - final Path vault = cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final Path vault = new Path(home, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); final Path test = new Path(vault, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.file)); session.withRegistry(new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator)); final DriveFileIdProvider fileid = new DriveFileIdProvider(session); @@ -117,8 +118,8 @@ public void testWriteWithCache() throws Exception { final Path home = DriveHomeFinderService.MYDRIVE_FOLDER; final Path vault = new Path(home, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); final Path test = new Path(vault, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.file)); - final CryptoVault cryptomator = new CryptoVault(vault); - cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); session.withRegistry(new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator)); final DriveFileIdProvider fileid = new DriveFileIdProvider(session); final CryptoWriteFeature writer = new CryptoWriteFeature<>(session, new DriveWriteFeature(session, fileid), cryptomator); diff --git a/googledrive/src/test/java/ch/cyberduck/core/cryptomator/MoveWorkerTest.java b/googledrive/src/test/java/ch/cyberduck/core/cryptomator/MoveWorkerTest.java index 959a53c3dfb..7956127a6a8 100644 --- a/googledrive/src/test/java/ch/cyberduck/core/cryptomator/MoveWorkerTest.java +++ b/googledrive/src/test/java/ch/cyberduck/core/cryptomator/MoveWorkerTest.java @@ -51,12 +51,14 @@ import ch.cyberduck.core.transfer.TransferStatus; import ch.cyberduck.core.vault.DefaultVaultRegistry; import ch.cyberduck.core.vault.VaultCredentials; +import ch.cyberduck.core.vault.VaultMetadata; import ch.cyberduck.core.worker.CopyWorker; import ch.cyberduck.core.worker.MoveWorker; import ch.cyberduck.test.IntegrationTest; import org.apache.commons.io.IOUtils; import org.apache.commons.lang3.RandomUtils; +import org.junit.Ignore; import org.junit.Test; import org.junit.experimental.categories.Category; import org.junit.runner.RunWith; @@ -72,7 +74,6 @@ import com.google.api.services.drive.model.File; import static org.junit.Assert.*; -import static org.junit.Assume.assumeTrue; @Category(IntegrationTest.class) @RunWith(value = Parameterized.class) @@ -81,9 +82,9 @@ public class MoveWorkerTest extends AbstractDriveTest { @Test public void testMoveSameFolderCryptomator() throws Exception { final Path home = DriveHomeFinderService.MYDRIVE_FOLDER; - final CryptoVault cryptomator = new CryptoVault( - new Path(home, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory))); - final Path vault = cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final Path vault = new Path(home, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); final Path source = new Path(vault, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.file)); final Path target = new Path(vault, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.file)); session.withRegistry(new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator)); @@ -106,9 +107,9 @@ public void testMoveSameFolderCryptomator() throws Exception { @Test public void testMoveToDifferentFolderCryptomator() throws Exception { final Path home = DriveHomeFinderService.MYDRIVE_FOLDER; - final CryptoVault cryptomator = new CryptoVault( - new Path(home, UUID.randomUUID().toString(), EnumSet.of(Path.Type.directory))); - final Path vault = cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final Path vault = new Path(home, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); final Path source = new Path(vault, UUID.randomUUID().toString(), EnumSet.of(Path.Type.file)); session.withRegistry(new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator)); final DriveFileIdProvider fileid = new DriveFileIdProvider(session); @@ -125,13 +126,14 @@ public void testMoveToDifferentFolderCryptomator() throws Exception { cryptomator.getFeature(session, Delete.class, new DriveDeleteFeature(session, fileid)).delete(Arrays.asList(target, targetFolder, vault), new DisabledLoginCallback(), new Delete.DisabledCallback()); } + //TODO @Test + @Ignore("File name shortening not implemented yet") public void testMoveToDifferentFolderLongFilenameCryptomator() throws Exception { - assumeTrue(vaultVersion == CryptoVault.VAULT_VERSION_DEPRECATED); final Path home = DriveHomeFinderService.MYDRIVE_FOLDER; - final CryptoVault cryptomator = new CryptoVault( - new Path(home, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory))); - final Path vault = cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final Path vault = new Path(home, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); final Path source = new Path(vault, new AlphanumericRandomStringService(130).random(), EnumSet.of(Path.Type.file)); session.withRegistry(new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator)); final DriveFileIdProvider fileid = new DriveFileIdProvider(session); @@ -152,9 +154,9 @@ public void testMoveToDifferentFolderLongFilenameCryptomator() throws Exception @Test public void testMoveFolder() throws Exception { final Path home = DriveHomeFinderService.MYDRIVE_FOLDER; - final CryptoVault cryptomator = new CryptoVault( - new Path(home, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory))); - final Path vault = cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final Path vault = new Path(home, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); session.withRegistry(new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator)); final DriveFileIdProvider fileid = new DriveFileIdProvider(session); final Path folder = cryptomator.getFeature(session, Directory.class, new DriveDirectoryFeature(session, fileid)).mkdir( @@ -192,9 +194,9 @@ public void testMoveFileIntoVault() throws Exception { final DriveFileIdProvider fileid = new DriveFileIdProvider(session); new DriveTouchFeature(session, fileid).touch(new DriveWriteFeature(session, fileid), clearFile, new TransferStatus()); assertTrue(new DefaultFindFeature(session).find(clearFile)); - final CryptoVault cryptomator = new CryptoVault( - new Path(home, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory))); - final Path vault = cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final Path vault = new Path(home, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); final DefaultVaultRegistry registry = new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator); session.withRegistry(registry); final Path encryptedFolder = cryptomator.getFeature(session, Directory.class, new DriveDirectoryFeature(session, fileid)).mkdir( @@ -219,9 +221,9 @@ public void testMoveDirectoryIntoVault() throws Exception { new DriveTouchFeature(session, fileid).touch(new DriveWriteFeature(session, fileid), clearFile, new TransferStatus()); assertTrue(new DefaultFindFeature(session).find(clearFolder)); assertTrue(new DefaultFindFeature(session).find(clearFile)); - final CryptoVault cryptomator = new CryptoVault( - new Path(home, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory))); - final Path vault = cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final Path vault = new Path(home, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); final DefaultVaultRegistry registry = new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator); session.withRegistry(registry); // move directory into vault @@ -241,9 +243,9 @@ public void testMoveFileOutsideVault() throws Exception { final Path clearFolder = new Path(home, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); final DriveFileIdProvider fileid = new DriveFileIdProvider(session); new DriveDirectoryFeature(session, fileid).mkdir(new DriveWriteFeature(session, fileid), clearFolder, new TransferStatus()); - final CryptoVault cryptomator = new CryptoVault( - new Path(home, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory))); - final Path vault = cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final Path vault = new Path(home, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); final DefaultVaultRegistry registry = new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator); session.withRegistry(registry); final Path encryptedFolder = cryptomator.getFeature(session, Directory.class, new DriveDirectoryFeature(session, fileid)).mkdir( @@ -265,9 +267,9 @@ public void testMoveFileOutsideVault() throws Exception { @Test public void testMoveDirectoryOutsideVault() throws Exception { final Path home = DriveHomeFinderService.MYDRIVE_FOLDER; - final CryptoVault cryptomator = new CryptoVault( - new Path(home, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory))); - final Path vault = cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final Path vault = new Path(home, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); final DefaultVaultRegistry registry = new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator); session.withRegistry(registry); final DriveFileIdProvider fileid = new DriveFileIdProvider(session); diff --git a/googledrive/src/test/java/ch/cyberduck/core/googledrive/AbstractDriveTest.java b/googledrive/src/test/java/ch/cyberduck/core/googledrive/AbstractDriveTest.java index ddbddb5b41b..11dc8aa92f8 100644 --- a/googledrive/src/test/java/ch/cyberduck/core/googledrive/AbstractDriveTest.java +++ b/googledrive/src/test/java/ch/cyberduck/core/googledrive/AbstractDriveTest.java @@ -27,10 +27,10 @@ import ch.cyberduck.core.Profile; import ch.cyberduck.core.ProtocolFactory; import ch.cyberduck.core.Scheme; -import ch.cyberduck.core.cryptomator.CryptoVault; import ch.cyberduck.core.serializer.impl.dd.ProfilePlistReader; import ch.cyberduck.core.ssl.DefaultX509KeyManager; import ch.cyberduck.core.ssl.DefaultX509TrustManager; +import ch.cyberduck.core.vault.VaultMetadata; import ch.cyberduck.test.VaultTest; import org.junit.After; @@ -48,11 +48,11 @@ public class AbstractDriveTest extends VaultTest { @Parameterized.Parameters(name = "vaultVersion = {0}") public static Object[] data() { - return new Object[]{CryptoVault.VAULT_VERSION_DEPRECATED, CryptoVault.VAULT_VERSION}; + return new Object[]{VaultMetadata.Type.V8, VaultMetadata.Type.UVF}; } @Parameterized.Parameter - public int vaultVersion; + public VaultMetadata.Type vaultVersion; @After public void disconnect() throws Exception { diff --git a/googlestorage/src/test/java/ch/cyberduck/core/cryptomator/GoogleStorageListServiceTest.java b/googlestorage/src/test/java/ch/cyberduck/core/cryptomator/GoogleStorageListServiceTest.java index 27615928310..21236f58d16 100644 --- a/googlestorage/src/test/java/ch/cyberduck/core/cryptomator/GoogleStorageListServiceTest.java +++ b/googlestorage/src/test/java/ch/cyberduck/core/cryptomator/GoogleStorageListServiceTest.java @@ -34,6 +34,7 @@ import ch.cyberduck.core.transfer.TransferStatus; import ch.cyberduck.core.vault.DefaultVaultRegistry; import ch.cyberduck.core.vault.VaultCredentials; +import ch.cyberduck.core.vault.VaultMetadata; import ch.cyberduck.test.IntegrationTest; import org.junit.Test; @@ -53,12 +54,13 @@ public class GoogleStorageListServiceTest extends AbstractGoogleStorageTest { @Test public void testListCryptomator() throws Exception { final Path container = new Path("cyberduck-test-eu", EnumSet.of(Path.Type.directory, Path.Type.volume)); - final CryptoVault cryptomator = new CryptoVault( - new Path(container, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory))); - final Path vault = cryptomator.create(session, new VaultCredentials("test"), CryptoVault.VAULT_VERSION); + final Path vault = new Path(container, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); session.withRegistry(new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator)); assertTrue(new CryptoListService(session, new GoogleStorageObjectListService(session), cryptomator).list(vault).isEmpty()); - final CryptoDirectoryV7Feature mkdir = new CryptoDirectoryV7Feature<>(session, new GoogleStorageDirectoryFeature(session), cryptomator); + final CryptoDirectoryV7Feature mkdir = new CryptoDirectoryV7Feature<>(session, new GoogleStorageDirectoryFeature(session), + cryptomator); final Path directory1 = mkdir.mkdir( cryptomator.getFeature(session, Write.class, new GoogleStorageWriteFeature(session)), new Path(vault, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)), new TransferStatus()); assertNotNull(new CryptoListService(session, new GoogleStorageObjectListService(session), cryptomator).list(vault) diff --git a/googlestorage/src/test/java/ch/cyberduck/core/googlestorage/AbstractGoogleStorageTest.java b/googlestorage/src/test/java/ch/cyberduck/core/googlestorage/AbstractGoogleStorageTest.java index 34b09d61604..0bee72dc5cd 100644 --- a/googlestorage/src/test/java/ch/cyberduck/core/googlestorage/AbstractGoogleStorageTest.java +++ b/googlestorage/src/test/java/ch/cyberduck/core/googlestorage/AbstractGoogleStorageTest.java @@ -27,10 +27,10 @@ import ch.cyberduck.core.Profile; import ch.cyberduck.core.ProtocolFactory; import ch.cyberduck.core.Scheme; -import ch.cyberduck.core.cryptomator.CryptoVault; import ch.cyberduck.core.serializer.impl.dd.ProfilePlistReader; import ch.cyberduck.core.ssl.DefaultX509KeyManager; import ch.cyberduck.core.ssl.DefaultX509TrustManager; +import ch.cyberduck.core.vault.VaultMetadata; import ch.cyberduck.test.VaultTest; import org.junit.After; @@ -48,11 +48,11 @@ public class AbstractGoogleStorageTest extends VaultTest { @Parameterized.Parameters(name = "vaultVersion = {0}") public static Object[] data() { - return new Object[]{CryptoVault.VAULT_VERSION_DEPRECATED, CryptoVault.VAULT_VERSION}; + return new Object[]{VaultMetadata.Type.V8, VaultMetadata.Type.UVF}; } @Parameterized.Parameter - public int vaultVersion; + public VaultMetadata.Type vaultVersion; @After public void disconnect() throws Exception { diff --git a/i18n/src/main/resources/en.lproj/Bookmark.xib b/i18n/src/main/resources/en.lproj/Bookmark.xib index d9fc8aa0225..17100f04297 100644 --- a/i18n/src/main/resources/en.lproj/Bookmark.xib +++ b/i18n/src/main/resources/en.lproj/Bookmark.xib @@ -1,7 +1,8 @@ - + - + @@ -40,12 +41,14 @@ - + - + @@ -54,7 +57,9 @@ - + @@ -66,7 +71,9 @@ - + @@ -75,7 +82,9 @@ - + @@ -92,7 +101,7 @@ - + @@ -107,7 +116,9 @@ - + @@ -116,7 +127,9 @@ - + @@ -128,7 +141,9 @@ - + @@ -137,7 +152,9 @@ - + @@ -149,7 +166,9 @@ - + @@ -158,7 +177,9 @@ - + @@ -167,7 +188,9 @@ - + @@ -176,7 +199,9 @@ - + @@ -188,7 +213,10 @@ - + @@ -205,7 +233,9 @@ - + @@ -250,7 +280,9 @@ - + @@ -259,7 +291,9 @@ - + @@ -272,7 +306,10 @@ - + @@ -285,7 +322,9 @@ - + @@ -294,7 +333,9 @@ - + @@ -315,7 +356,9 @@ - + @@ -333,7 +376,9 @@ - + @@ -350,7 +395,9 @@ - + @@ -359,7 +406,9 @@ - + @@ -401,7 +450,9 @@ - + @@ -419,7 +470,9 @@ - + @@ -437,7 +490,9 @@ - + @@ -446,7 +501,9 @@ - + @@ -489,93 +546,95 @@ YnBsaXN0MDDUAQIDBAUGBwpYJHZlcnNpb25ZJGFyY2hpdmVyVCR0b3BYJG9iamVjdHMSAAGGoF8QD05T -S2V5ZWRBcmNoaXZlctEICVRyb290gAGuCwwZGh8UJCgpMDM2PD9VJG51bGzWDQ4PEBESExQVFhcYVk5T -U2l6ZV5OU1Jlc2l6aW5nTW9kZVYkY2xhc3NcTlNJbWFnZUZsYWdzVk5TUmVwc1dOU0NvbG9ygAIQAIAN -EiDDAACAA4ALVnsxLCAxfdIbDxweWk5TLm9iamVjdHOhHYAEgArSGw8gI6IhIoAFgAaACdIlDyYnXxAU -TlNUSUZGUmVwcmVzZW50YXRpb26AB4AITxESOE1NACoAAAAKAAAAEAEAAAMAAAABAAEAAAEBAAMAAAAB -AAEAAAECAAMAAAACAAgACAEDAAMAAAABAAEAAAEGAAMAAAABAAEAAAEKAAMAAAABAAEAAAERAAQAAAAB -AAAACAESAAMAAAABAAEAAAEVAAMAAAABAAIAAAEWAAMAAAABAAEAAAEXAAQAAAABAAAAAgEcAAMAAAAB -AAEAAAEoAAMAAAABAAIAAAFSAAMAAAABAAEAAAFTAAMAAAACAAEAAYdzAAcAABFoAAAA0AAAAAAAABFo -YXBwbAIAAABtbnRyR1JBWVhZWiAH3AAIABcADwAuAA9hY3NwQVBQTAAAAABub25lAAAAAAAAAAAAAAAA -AAAAAAAA9tYAAQAAAADTLWFwcGwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA -AAAAAAAAAAVkZXNjAAAAwAAAAHlkc2NtAAABPAAAB+hjcHJ0AAAJJAAAACN3dHB0AAAJSAAAABRrVFJD -AAAJXAAACAxkZXNjAAAAAAAAAB9HZW5lcmljIEdyYXkgR2FtbWEgMi4yIFByb2ZpbGUAAAAAAAAAAAAA -AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA -AAAAAAAAAAAAAAAAbWx1YwAAAAAAAAAfAAAADHNrU0sAAAAuAAABhGRhREsAAAA4AAABsmNhRVMAAAA4 -AAAB6nZpVk4AAABAAAACInB0QlIAAABKAAACYnVrVUEAAAAsAAACrGZyRlUAAAA+AAAC2Gh1SFUAAAA0 -AAADFnpoVFcAAAAeAAADSm5iTk8AAAA6AAADaGNzQ1oAAAAoAAADomhlSUwAAAAkAAADyml0SVQAAABO -AAAD7nJvUk8AAAAqAAAEPGRlREUAAABOAAAEZmtvS1IAAAAiAAAEtHN2U0UAAAA4AAABsnpoQ04AAAAe -AAAE1mphSlAAAAAmAAAE9GVsR1IAAAAqAAAFGnB0UE8AAABSAAAFRG5sTkwAAABAAAAFlmVzRVMAAABM -AAAF1nRoVEgAAAAyAAAGInRyVFIAAAAkAAAGVGZpRkkAAABGAAAGeGhySFIAAAA+AAAGvnBsUEwAAABK -AAAG/HJ1UlUAAAA6AAAHRmVuVVMAAAA8AAAHgGFyRUcAAAAsAAAHvABWAWEAZQBvAGIAZQBjAG4A4QAg -AHMAaQB2AOEAIABnAGEAbQBhACAAMgAsADIARwBlAG4AZQByAGkAcwBrACAAZwByAOUAIAAyACwAMgAg -AGcAYQBtAG0AYQBwAHIAbwBmAGkAbABHAGEAbQBtAGEAIABkAGUAIABnAHIAaQBzAG8AcwAgAGcAZQBu -AOgAcgBpAGMAYQAgADIALgAyAEMepQB1ACAAaADsAG4AaAAgAE0A4AB1ACAAeADhAG0AIABDAGgAdQBu -AGcAIABHAGEAbQBtAGEAIAAyAC4AMgBQAGUAcgBmAGkAbAAgAEcAZQBuAOkAcgBpAGMAbwAgAGQAYQAg -AEcAYQBtAGEAIABkAGUAIABDAGkAbgB6AGEAcwAgADIALAAyBBcEMAQzBDAEOwRMBD0EMAAgAEcAcgBh -AHkALQQzBDAEPAQwACAAMgAuADIAUAByAG8AZgBpAGwAIABnAOkAbgDpAHIAaQBxAHUAZQAgAGcAcgBp -AHMAIABnAGEAbQBtAGEAIAAyACwAMgDBAGwAdABhAGwA4QBuAG8AcwAgAHMAegD8AHIAawBlACAAZwBh -AG0AbQBhACAAMgAuADKQGnUocHCWjlFJXqYAIAAyAC4AMgAggnJfaWPPj/AARwBlAG4AZQByAGkAcwBr -ACAAZwByAOUAIABnAGEAbQBtAGEAIAAyACwAMgAtAHAAcgBvAGYAaQBsAE8AYgBlAGMAbgDhACABYQBl -AGQA4QAgAGcAYQBtAGEAIAAyAC4AMgXSBdAF3gXUACAF0AXkBdUF6AAgBdsF3AXcBdkAIAAyAC4AMgBQ -AHIAbwBmAGkAbABvACAAZwByAGkAZwBpAG8AIABnAGUAbgBlAHIAaQBjAG8AIABkAGUAbABsAGEAIABn -AGEAbQBtAGEAIAAyACwAMgBHAGEAbQBhACAAZwByAGkAIABnAGUAbgBlAHIAaQBjAQMAIAAyACwAMgBB + S2V5ZWRBcmNoaXZlctEICVRyb290gAGuCwwbHCEaJissMzY5P0JVJG51bGzXDQ4PEBESExQVFhcYGRpW + TlNTaXplViRjbGFzc1xOU0ltYWdlRmxhZ3NWTlNSZXBzW05TVGludENvbG9yV05TQ29sb3JeTlNSZXNp + emluZ01vZGWAAoANEiDDAACAA4AAgAsQAFZ7MSwgMX3SHQ4eIFpOUy5vYmplY3RzoR+ABIAK0h0OIiWi + IySABYAGgAnTDicoKSoaXxAUTlNUSUZGUmVwcmVzZW50YXRpb25fEBlOU0ludGVybmFsTGF5b3V0RGly + ZWN0aW9ugAiAB08REmxNTQAqAAAACgAAABABAAADAAAAAQABAAABAQADAAAAAQABAAABAgADAAAAAgAI + AAgBAwADAAAAAQABAAABBgADAAAAAQABAAABCgADAAAAAQABAAABEQAEAAAAAQAAAAgBEgADAAAAAQAB + AAABFQADAAAAAQACAAABFgADAAAAAQABAAABFwAEAAAAAQAAAAIBHAADAAAAAQABAAABKAADAAAAAQAC + AAABUgADAAAAAQABAAABUwADAAAAAgABAAGHcwAHAAARnAAAANAAAAAAAAARnGFwcGwCAAAAbW50ckdS + QVlYWVogB9wACAAXAA8ALgAPYWNzcEFQUEwAAAAAbm9uZQAAAAAAAAAAAAAAAAAAAAAAAPbWAAEAAAAA + 0y1hcHBsAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFZGVzYwAA + AMAAAAB5ZHNjbQAAATwAAAgaY3BydAAACVgAAAAjd3RwdAAACXwAAAAUa1RSQwAACZAAAAgMZGVzYwAA + AAAAAAAfR2VuZXJpYyBHcmF5IEdhbW1hIDIuMiBQcm9maWxlAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAG1s + dWMAAAAAAAAAHwAAAAxza1NLAAAALgAAAYRkYURLAAAAOgAAAbJjYUVTAAAAOAAAAex2aVZOAAAAQAAA + AiRwdEJSAAAASgAAAmR1a1VBAAAALAAAAq5mckZVAAAAPgAAAtpodUhVAAAANAAAAxh6aFRXAAAAGgAA + A0xrb0tSAAAAIgAAA2ZuYk5PAAAAOgAAA4hjc0NaAAAAKAAAA8JoZUlMAAAAJAAAA+pyb1JPAAAAKgAA + BA5kZURFAAAATgAABDhpdElUAAAATgAABIZzdlNFAAAAOAAABNR6aENOAAAAGgAABQxqYUpQAAAAJgAA + BSZlbEdSAAAAKgAABUxwdFBPAAAAUgAABXZubE5MAAAAQAAABchlc0VTAAAATAAABgh0aFRIAAAAMgAA + BlR0clRSAAAAJAAABoZmaUZJAAAARgAABqpockhSAAAAPgAABvBwbFBMAAAASgAABy5hckVHAAAALAAA + B3hydVJVAAAAOgAAB6RlblVTAAAAPAAAB94AVgFhAGUAbwBiAGUAYwBuAOEAIABzAGkAdgDhACAAZwBh + AG0AYQAgADIALAAyAEcAZQBuAGUAcgBpAHMAawAgAGcAcgDlACAAMgAsADIAIABnAGEAbQBtAGEALQBw + AHIAbwBmAGkAbABHAGEAbQBtAGEAIABkAGUAIABnAHIAaQBzAG8AcwAgAGcAZQBuAOgAcgBpAGMAYQAg + ADIALgAyAEMepQB1ACAAaADsAG4AaAAgAE0A4AB1ACAAeADhAG0AIABDAGgAdQBuAGcAIABHAGEAbQBt + AGEAIAAyAC4AMgBQAGUAcgBmAGkAbAAgAEcAZQBuAOkAcgBpAGMAbwAgAGQAYQAgAEcAYQBtAGEAIABk + AGUAIABDAGkAbgB6AGEAcwAgADIALAAyBBcEMAQzBDAEOwRMBD0EMAAgAEcAcgBhAHkALQQzBDAEPAQw + ACAAMgAuADIAUAByAG8AZgBpAGwAIABnAOkAbgDpAHIAaQBxAHUAZQAgAGcAcgBpAHMAIABnAGEAbQBt + AGEAIAAyACwAMgDBAGwAdABhAGwA4QBuAG8AcwAgAHMAegD8AHIAawBlACAAZwBhAG0AbQBhACAAMgAu + ADKQGnUocHCWjlFJXqYAMgAuADKCcl9pY8+P8Md8vBgAINaMwMkAIKwQucgAIAAyAC4AMgAg1QS4XNMM + x3wARwBlAG4AZQByAGkAcwBrACAAZwByAOUAIABnAGEAbQBtAGEAIAAyACwAMgAtAHAAcgBvAGYAaQBs + AE8AYgBlAGMAbgDhACABYQBlAGQA4QAgAGcAYQBtAGEAIAAyAC4AMgXSBdAF3gXUACAF0AXkBdUF6AAg + BdsF3AXcBdkAIAAyAC4AMgBHAGEAbQBhACAAZwByAGkAIABnAGUAbgBlAHIAaQBjAQMAIAAyACwAMgBB AGwAbABnAGUAbQBlAGkAbgBlAHMAIABHAHIAYQB1AHMAdAB1AGYAZQBuAC0AUAByAG8AZgBpAGwAIABH -AGEAbQBtAGEAIAAyACwAMsd8vBgAINaMwMkAIKwQucgAIAAyAC4AMgAg1QS4XNMMx3xmbpAacHBepnz7 -ZXAAIAAyAC4AMgAgY8+P8GWHTvZOAIIsMLAw7DCkMKww8zDeACAAMgAuADIAIDDXMO0w1TChMKQw6wOT -A7UDvQO5A7oDzAAgA5MDugPBA7kAIAOTA6wDvAO8A7EAIAAyAC4AMgBQAGUAcgBmAGkAbAAgAGcAZQBu -AOkAcgBpAGMAbwAgAGQAZQAgAGMAaQBuAHoAZQBuAHQAbwBzACAAZABhACAARwBhAG0AbQBhACAAMgAs -ADIAQQBsAGcAZQBtAGUAZQBuACAAZwByAGkAagBzACAAZwBhAG0AbQBhACAAMgAsADIALQBwAHIAbwBm -AGkAZQBsAFAAZQByAGYAaQBsACAAZwBlAG4A6QByAGkAYwBvACAAZABlACAAZwBhAG0AbQBhACAAZABl -ACAAZwByAGkAcwBlAHMAIAAyACwAMg4jDjEOBw4qDjUOQQ4BDiEOIQ4yDkAOAQ4jDiIOTA4XDjEOSA4n -DkQOGwAgADIALgAyAEcAZQBuAGUAbAAgAEcAcgBpACAARwBhAG0AYQAgADIALAAyAFkAbABlAGkAbgBl -AG4AIABoAGEAcgBtAGEAYQBuACAAZwBhAG0AbQBhACAAMgAsADIAIAAtAHAAcgBvAGYAaQBpAGwAaQBH -AGUAbgBlAHIAaQENAGsAaQAgAEcAcgBhAHkAIABHAGEAbQBtAGEAIAAyAC4AMgAgAHAAcgBvAGYAaQBs -AFUAbgBpAHcAZQByAHMAYQBsAG4AeQAgAHAAcgBvAGYAaQBsACAAcwB6AGEAcgBvAVsAYwBpACAAZwBh -AG0AbQBhACAAMgAsADIEHgQxBEkEMARPACAEQQQ1BEAEMARPACAEMwQwBDwEPAQwACAAMgAsADIALQQ/ -BEAEPgREBDgEOwRMAEcAZQBuAGUAcgBpAGMAIABHAHIAYQB5ACAARwBhAG0AbQBhACAAMgAuADIAIABQ -AHIAbwBmAGkAbABlBjoGJwZFBicAIAAyAC4AMgAgBkQGSAZGACAGMQZFBicGLwZKACAGOQYnBkV0ZXh0 -AAAAAENvcHlyaWdodCBBcHBsZSBJbmMuLCAyMDEyAABYWVogAAAAAAAA81EAAQAAAAEWzGN1cnYAAAAA -AAAEAAAAAAUACgAPABQAGQAeACMAKAAtADIANwA7AEAARQBKAE8AVABZAF4AYwBoAG0AcgB3AHwAgQCG -AIsAkACVAJoAnwCkAKkArgCyALcAvADBAMYAywDQANUA2wDgAOUA6wDwAPYA+wEBAQcBDQETARkBHwEl -ASsBMgE4AT4BRQFMAVIBWQFgAWcBbgF1AXwBgwGLAZIBmgGhAakBsQG5AcEByQHRAdkB4QHpAfIB+gID -AgwCFAIdAiYCLwI4AkECSwJUAl0CZwJxAnoChAKOApgCogKsArYCwQLLAtUC4ALrAvUDAAMLAxYDIQMt -AzgDQwNPA1oDZgNyA34DigOWA6IDrgO6A8cD0wPgA+wD+QQGBBMEIAQtBDsESARVBGMEcQR+BIwEmgSo -BLYExATTBOEE8AT+BQ0FHAUrBToFSQVYBWcFdwWGBZYFpgW1BcUF1QXlBfYGBgYWBicGNwZIBlkGagZ7 -BowGnQavBsAG0QbjBvUHBwcZBysHPQdPB2EHdAeGB5kHrAe/B9IH5Qf4CAsIHwgyCEYIWghuCIIIlgiq -CL4I0gjnCPsJEAklCToJTwlkCXkJjwmkCboJzwnlCfsKEQonCj0KVApqCoEKmAquCsUK3ArzCwsLIgs5 -C1ELaQuAC5gLsAvIC+EL+QwSDCoMQwxcDHUMjgynDMAM2QzzDQ0NJg1ADVoNdA2ODakNww3eDfgOEw4u -DkkOZA5/DpsOtg7SDu4PCQ8lD0EPXg96D5YPsw/PD+wQCRAmEEMQYRB+EJsQuRDXEPURExExEU8RbRGM -EaoRyRHoEgcSJhJFEmQShBKjEsMS4xMDEyMTQxNjE4MTpBPFE+UUBhQnFEkUahSLFK0UzhTwFRIVNBVW -FXgVmxW9FeAWAxYmFkkWbBaPFrIW1hb6Fx0XQRdlF4kXrhfSF/cYGxhAGGUYihivGNUY+hkgGUUZaxmR -GbcZ3RoEGioaURp3Gp4axRrsGxQbOxtjG4obshvaHAIcKhxSHHscoxzMHPUdHh1HHXAdmR3DHeweFh5A -HmoelB6+HukfEx8+H2kflB+/H+ogFSBBIGwgmCDEIPAhHCFIIXUhoSHOIfsiJyJVIoIiryLdIwojOCNm -I5QjwiPwJB8kTSR8JKsk2iUJJTglaCWXJccl9yYnJlcmhya3JugnGCdJJ3onqyfcKA0oPyhxKKIo1CkG -KTgpaymdKdAqAio1KmgqmyrPKwIrNitpK50r0SwFLDksbiyiLNctDC1BLXYtqy3hLhYuTC6CLrcu7i8k -L1ovkS/HL/4wNTBsMKQw2zESMUoxgjG6MfIyKjJjMpsy1DMNM0YzfzO4M/E0KzRlNJ402DUTNU01hzXC -Nf02NzZyNq426TckN2A3nDfXOBQ4UDiMOMg5BTlCOX85vDn5OjY6dDqyOu87LTtrO6o76DwnPGU8pDzj -PSI9YT2hPeA+ID5gPqA+4D8hP2E/oj/iQCNAZECmQOdBKUFqQaxB7kIwQnJCtUL3QzpDfUPARANER0SK -RM5FEkVVRZpF3kYiRmdGq0bwRzVHe0fASAVIS0iRSNdJHUljSalJ8Eo3Sn1KxEsMS1NLmkviTCpMcky6 -TQJNSk2TTdxOJU5uTrdPAE9JT5NP3VAnUHFQu1EGUVBRm1HmUjFSfFLHUxNTX1OqU/ZUQlSPVNtVKFV1 -VcJWD1ZcVqlW91dEV5JX4FgvWH1Yy1kaWWlZuFoHWlZaplr1W0VblVvlXDVchlzWXSddeF3JXhpebF69 -Xw9fYV+zYAVgV2CqYPxhT2GiYfViSWKcYvBjQ2OXY+tkQGSUZOllPWWSZedmPWaSZuhnPWeTZ+loP2iW -aOxpQ2maafFqSGqfavdrT2una/9sV2yvbQhtYG25bhJua27Ebx5veG/RcCtwhnDgcTpxlXHwcktypnMB -c11zuHQUdHB0zHUodYV14XY+dpt2+HdWd7N4EXhueMx5KnmJeed6RnqlewR7Y3vCfCF8gXzhfUF9oX4B -fmJ+wn8jf4R/5YBHgKiBCoFrgc2CMIKSgvSDV4O6hB2EgITjhUeFq4YOhnKG14c7h5+IBIhpiM6JM4mZ -if6KZIrKizCLlov8jGOMyo0xjZiN/45mjs6PNo+ekAaQbpDWkT+RqJIRknqS45NNk7aUIJSKlPSVX5XJ -ljSWn5cKl3WX4JhMmLiZJJmQmfyaaJrVm0Kbr5wcnImc951kndKeQJ6unx2fi5/6oGmg2KFHobaiJqKW -owajdqPmpFakx6U4pammGqaLpv2nbqfgqFKoxKk3qamqHKqPqwKrdavprFys0K1ErbiuLa6hrxavi7AA -sHWw6rFgsdayS7LCszizrrQltJy1E7WKtgG2ebbwt2i34LhZuNG5SrnCuju6tbsuu6e8IbybvRW9j74K -voS+/796v/XAcMDswWfB48JfwtvDWMPUxFHEzsVLxcjGRsbDx0HHv8g9yLzJOsm5yjjKt8s2y7bMNcy1 -zTXNtc42zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp22vvbgNwF -3IrdEN2W3hzeot8p36/gNuC94UThzOJT4tvjY+Pr5HPk/OWE5g3mlucf56noMui86Ubp0Opb6uXrcOv7 -7IbtEe2c7ijutO9A78zwWPDl8XLx//KM8xnzp/Q09ML1UPXe9m32+/eK+Bn4qPk4+cf6V/rn+3f8B/yY -/Sn9uv5L/tz/bf//0iorLC1aJGNsYXNzbmFtZVgkY2xhc3Nlc18QEE5TQml0bWFwSW1hZ2VSZXCjLC4v -Wk5TSW1hZ2VSZXBYTlNPYmplY3TSKisxMldOU0FycmF5ojEv0iorNDVeTlNNdXRhYmxlQXJyYXmjNDEv -0zc4Dzk6O1dOU1doaXRlXE5TQ29sb3JTcGFjZUQwIDAAEAOADNIqKz0+V05TQ29sb3KiPS/SKitAQVdO -U0ltYWdlokAvAAgAEQAaACQAKQAyADcASQBMAFEAUwBiAGgAdQB8AIsAkgCfAKYArgCwALIAtAC5ALsA -vQDEAMkA1ADWANgA2gDfAOIA5ADmAOgA7QEEAQYBCBNEE0kTVBNdE3ATdBN/E4gTjROVE5gTnROsE7AT -txO/E8wT0RPTE9UT2hPiE+UT6hPyAAAAAAAAAgEAAAAAAAAAQgAAAAAAAAAAAAAAAAAAE/U + AGEAbQBtAGEAIAAyACwAMgBQAHIAbwBmAGkAbABvACAAZwByAGkAZwBpAG8AIABnAGUAbgBlAHIAaQBj + AG8AIABkAGUAbABsAGEAIABnAGEAbQBtAGEAIAAyACwAMgBHAGUAbgBlAHIAaQBzAGsAIABnAHIA5QAg + ADIALAAyACAAZwBhAG0AbQBhAHAAcgBvAGYAaQBsZm6QGnBwXqZ8+2VwADIALgAyY8+P8GWHTvZOAIIs + MLAw7DCkMKww8zDeACAAMgAuADIAIDDXMO0w1TChMKQw6wOTA7UDvQO5A7oDzAAgA5MDugPBA7kAIAOT + A6wDvAO8A7EAIAAyAC4AMgBQAGUAcgBmAGkAbAAgAGcAZQBuAOkAcgBpAGMAbwAgAGQAZQAgAGMAaQBu + AHoAZQBuAHQAbwBzACAAZABhACAARwBhAG0AbQBhACAAMgAsADIAQQBsAGcAZQBtAGUAZQBuACAAZwBy + AGkAagBzACAAZwBhAG0AbQBhACAAMgAsADIALQBwAHIAbwBmAGkAZQBsAFAAZQByAGYAaQBsACAAZwBl + AG4A6QByAGkAYwBvACAAZABlACAAZwBhAG0AbQBhACAAZABlACAAZwByAGkAcwBlAHMAIAAyACwAMg4j + DjEOBw4qDjUOQQ4BDiEOIQ4yDkAOAQ4jDiIOTA4XDjEOSA4nDkQOGwAgADIALgAyAEcAZQBuAGUAbAAg + AEcAcgBpACAARwBhAG0AYQAgADIALAAyAFkAbABlAGkAbgBlAG4AIABoAGEAcgBtAGEAYQBuACAAZwBh + AG0AbQBhACAAMgAsADIAIAAtAHAAcgBvAGYAaQBpAGwAaQBHAGUAbgBlAHIAaQENAGsAaQAgAEcAcgBh + AHkAIABHAGEAbQBtAGEAIAAyAC4AMgAgAHAAcgBvAGYAaQBsAFUAbgBpAHcAZQByAHMAYQBsAG4AeQAg + AHAAcgBvAGYAaQBsACAAcwB6AGEAcgBvAVsAYwBpACAAZwBhAG0AbQBhACAAMgAsADIGOgYnBkUGJwAg + ADIALgAyACAGRAZIBkYAIAYxBkUGJwYvBkoAIAY5BicGRQQeBDEESQQwBE8AIARBBDUEQAQwBE8AIAQz + BDAEPAQ8BDAAIAAyACwAMgAtBD8EQAQ+BEQEOAQ7BEwARwBlAG4AZQByAGkAYwAgAEcAcgBhAHkAIABH + AGEAbQBtAGEAIAAyAC4AMgAgAFAAcgBvAGYAaQBsAGUAAHRleHQAAAAAQ29weXJpZ2h0IEFwcGxlIElu + Yy4sIDIwMTIAAFhZWiAAAAAAAADzUQABAAAAARbMY3VydgAAAAAAAAQAAAAABQAKAA8AFAAZAB4AIwAo + AC0AMgA3ADsAQABFAEoATwBUAFkAXgBjAGgAbQByAHcAfACBAIYAiwCQAJUAmgCfAKQAqQCuALIAtwC8 + AMEAxgDLANAA1QDbAOAA5QDrAPAA9gD7AQEBBwENARMBGQEfASUBKwEyATgBPgFFAUwBUgFZAWABZwFu + AXUBfAGDAYsBkgGaAaEBqQGxAbkBwQHJAdEB2QHhAekB8gH6AgMCDAIUAh0CJgIvAjgCQQJLAlQCXQJn + AnECegKEAo4CmAKiAqwCtgLBAssC1QLgAusC9QMAAwsDFgMhAy0DOANDA08DWgNmA3IDfgOKA5YDogOu + A7oDxwPTA+AD7AP5BAYEEwQgBC0EOwRIBFUEYwRxBH4EjASaBKgEtgTEBNME4QTwBP4FDQUcBSsFOgVJ + BVgFZwV3BYYFlgWmBbUFxQXVBeUF9gYGBhYGJwY3BkgGWQZqBnsGjAadBq8GwAbRBuMG9QcHBxkHKwc9 + B08HYQd0B4YHmQesB78H0gflB/gICwgfCDIIRghaCG4IggiWCKoIvgjSCOcI+wkQCSUJOglPCWQJeQmP + CaQJugnPCeUJ+woRCicKPQpUCmoKgQqYCq4KxQrcCvMLCwsiCzkLUQtpC4ALmAuwC8gL4Qv5DBIMKgxD + DFwMdQyODKcMwAzZDPMNDQ0mDUANWg10DY4NqQ3DDd4N+A4TDi4OSQ5kDn8Omw62DtIO7g8JDyUPQQ9e + D3oPlg+zD88P7BAJECYQQxBhEH4QmxC5ENcQ9RETETERTxFtEYwRqhHJEegSBxImEkUSZBKEEqMSwxLj + EwMTIxNDE2MTgxOkE8UT5RQGFCcUSRRqFIsUrRTOFPAVEhU0FVYVeBWbFb0V4BYDFiYWSRZsFo8WshbW + FvoXHRdBF2UXiReuF9IX9xgbGEAYZRiKGK8Y1Rj6GSAZRRlrGZEZtxndGgQaKhpRGncanhrFGuwbFBs7 + G2MbihuyG9ocAhwqHFIcexyjHMwc9R0eHUcdcB2ZHcMd7B4WHkAeah6UHr4e6R8THz4faR+UH78f6iAV + IEEgbCCYIMQg8CEcIUghdSGhIc4h+yInIlUigiKvIt0jCiM4I2YjlCPCI/AkHyRNJHwkqyTaJQklOCVo + JZclxyX3JicmVyaHJrcm6CcYJ0kneierJ9woDSg/KHEooijUKQYpOClrKZ0p0CoCKjUqaCqbKs8rAis2 + K2krnSvRLAUsOSxuLKIs1y0MLUEtdi2rLeEuFi5MLoIuty7uLyQvWi+RL8cv/jA1MGwwpDDbMRIxSjGC + Mbox8jIqMmMymzLUMw0zRjN/M7gz8TQrNGU0njTYNRM1TTWHNcI1/TY3NnI2rjbpNyQ3YDecN9c4FDhQ + OIw4yDkFOUI5fzm8Ofk6Njp0OrI67zstO2s7qjvoPCc8ZTykPOM9Ij1hPaE94D4gPmA+oD7gPyE/YT+i + P+JAI0BkQKZA50EpQWpBrEHuQjBCckK1QvdDOkN9Q8BEA0RHRIpEzkUSRVVFmkXeRiJGZ0arRvBHNUd7 + R8BIBUhLSJFI10kdSWNJqUnwSjdKfUrESwxLU0uaS+JMKkxyTLpNAk1KTZNN3E4lTm5Ot08AT0lPk0/d + UCdQcVC7UQZRUFGbUeZSMVJ8UsdTE1NfU6pT9lRCVI9U21UoVXVVwlYPVlxWqVb3V0RXklfgWC9YfVjL + WRpZaVm4WgdaVlqmWvVbRVuVW+VcNVyGXNZdJ114XcleGl5sXr1fD19hX7NgBWBXYKpg/GFPYaJh9WJJ + Ypxi8GNDY5dj62RAZJRk6WU9ZZJl52Y9ZpJm6Gc9Z5Nn6Wg/aJZo7GlDaZpp8WpIap9q92tPa6dr/2xX + bK9tCG1gbbluEm5rbsRvHm94b9FwK3CGcOBxOnGVcfByS3KmcwFzXXO4dBR0cHTMdSh1hXXhdj52m3b4 + d1Z3s3gReG54zHkqeYl553pGeqV7BHtje8J8IXyBfOF9QX2hfgF+Yn7CfyN/hH/lgEeAqIEKgWuBzYIw + gpKC9INXg7qEHYSAhOOFR4Wrhg6GcobXhzuHn4gEiGmIzokziZmJ/opkisqLMIuWi/yMY4zKjTGNmI3/ + jmaOzo82j56QBpBukNaRP5GokhGSepLjk02TtpQglIqU9JVflcmWNJaflwqXdZfgmEyYuJkkmZCZ/Jpo + mtWbQpuvnByciZz3nWSd0p5Anq6fHZ+Ln/qgaaDYoUehtqImopajBqN2o+akVqTHpTilqaYapoum/adu + p+CoUqjEqTepqaocqo+rAqt1q+msXKzQrUStuK4trqGvFq+LsACwdbDqsWCx1rJLssKzOLOutCW0nLUT + tYq2AbZ5tvC3aLfguFm40blKucK6O7q1uy67p7whvJu9Fb2Pvgq+hL7/v3q/9cBwwOzBZ8Hjwl/C28NY + w9TEUcTOxUvFyMZGxsPHQce/yD3IvMk6ybnKOMq3yzbLtsw1zLXNNc21zjbOts83z7jQOdC60TzRvtI/ + 0sHTRNPG1EnUy9VO1dHWVdbY11zX4Nhk2OjZbNnx2nba+9uA3AXcit0Q3ZbeHN6i3ynfr+A24L3hROHM + 4lPi2+Nj4+vkc+T85YTmDeaW5x/nqegy6LzpRunQ6lvq5etw6/vshu0R7ZzuKO6070DvzPBY8OXxcvH/ + 8ozzGfOn9DT0wvVQ9d72bfb794r4Gfio+Tj5x/pX+uf7d/wH/Jj9Kf26/kv+3P9t///SLS4vMFokY2xh + c3NuYW1lWCRjbGFzc2VzXxAQTlNCaXRtYXBJbWFnZVJlcKMvMTJaTlNJbWFnZVJlcFhOU09iamVjdNIt + LjQ1V05TQXJyYXmiNDLSLS43OF5OU011dGFibGVBcnJheaM3NDLTOjsOPD0+V05TV2hpdGVcTlNDb2xv + clNwYWNlRDAgMAAQA4AM0i0uQEFXTlNDb2xvcqJAMtItLkNEV05TSW1hZ2WiQzIACAARABoAJAApADIA + NwBJAEwAUQBTAGIAaAB3AH4AhQCSAJkApQCtALwAvgDAAMUAxwDJAMsAzQDUANkA5ADmAOgA6gDvAPIA + 9AD2APgA/wEWATIBNAE2E6YTqxO2E78T0hPWE+ET6hPvE/cT+hP/FA4UEhQZFCEULhQzFDUUNxQ8FEQU + RxRMFFQAAAAAAAACAQAAAAAAAABFAAAAAAAAAAAAAAAAAAAUVw diff --git a/i18n/src/main/resources/en.lproj/Prompt.xib b/i18n/src/main/resources/en.lproj/Prompt.xib index 2d32fe1d0f3..bfabcbc7523 100644 --- a/i18n/src/main/resources/en.lproj/Prompt.xib +++ b/i18n/src/main/resources/en.lproj/Prompt.xib @@ -1,7 +1,8 @@ - + - + @@ -28,12 +29,13 @@ - + - - + @@ -140,7 +146,9 @@ Gw - + @@ -149,7 +157,9 @@ Gw - + @@ -158,7 +168,9 @@ Gw - + @@ -167,7 +179,9 @@ Gw - + @@ -176,7 +190,9 @@ Gw - + @@ -185,7 +201,9 @@ Gw - + @@ -194,7 +212,9 @@ Gw - + @@ -203,7 +223,9 @@ Gw - + diff --git a/manta/src/main/java/ch/cyberduck/core/manta/MantaMoveFeature.java b/manta/src/main/java/ch/cyberduck/core/manta/MantaMoveFeature.java index d8efbf4d722..c1dde0b4eab 100644 --- a/manta/src/main/java/ch/cyberduck/core/manta/MantaMoveFeature.java +++ b/manta/src/main/java/ch/cyberduck/core/manta/MantaMoveFeature.java @@ -48,7 +48,7 @@ public Path move(final Path file, final Path renamed, final TransferStatus statu try { session.getClient().move(file.getAbsolute(), renamed.getAbsolute()); // Copy original file attributes - return new Path(renamed).withAttributes(new PathAttributes(file.attributes()).setVault(null)); + return new Path(renamed).withAttributes(new PathAttributes(file.attributes()).setVaultMetadata(null)); } catch(MantaException e) { throw new MantaExceptionMappingService().map("Cannot rename {0}", e, file); diff --git a/nio/src/test/java/ch/cyberduck/core/cryptomator/CryptoLocalSingleTransferWorkerTest.java b/nio/src/test/java/ch/cyberduck/core/cryptomator/CryptoLocalSingleTransferWorkerTest.java index c000350effb..cd5920e5371 100644 --- a/nio/src/test/java/ch/cyberduck/core/cryptomator/CryptoLocalSingleTransferWorkerTest.java +++ b/nio/src/test/java/ch/cyberduck/core/cryptomator/CryptoLocalSingleTransferWorkerTest.java @@ -44,7 +44,6 @@ import ch.cyberduck.core.nio.LocalReadFeature; import ch.cyberduck.core.nio.LocalSession; import ch.cyberduck.core.notification.DisabledNotificationService; -import ch.cyberduck.core.preferences.PreferencesFactory; import ch.cyberduck.core.proxy.DisabledProxyFinder; import ch.cyberduck.core.transfer.DisabledTransferErrorCallback; import ch.cyberduck.core.transfer.DisabledTransferPrompt; @@ -57,6 +56,7 @@ import ch.cyberduck.core.transfer.UploadTransfer; import ch.cyberduck.core.vault.DefaultVaultRegistry; import ch.cyberduck.core.vault.VaultCredentials; +import ch.cyberduck.core.vault.VaultMetadata; import ch.cyberduck.core.worker.SingleTransferWorker; import ch.cyberduck.test.IntegrationTest; @@ -82,11 +82,11 @@ public class CryptoLocalSingleTransferWorkerTest { @Parameterized.Parameters(name = "vaultVersion = {0}") public static Object[] data() { - return new Object[]{CryptoVault.VAULT_VERSION_DEPRECATED, CryptoVault.VAULT_VERSION}; + return new Object[]{VaultMetadata.Type.V8, VaultMetadata.Type.UVF}; } @Parameterized.Parameter - public int vaultVersion; + public VaultMetadata.Type vaultVersion; @Test public void testUpload() throws Exception { @@ -113,15 +113,14 @@ public void testUpload() throws Exception { final OutputStream out2 = localFile2.getOutputStream(false); IOUtils.write(content, out2); out2.close(); - final CryptoVault cryptomator = new CryptoVault(vault); - cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); session.withRegistry(new DefaultVaultRegistry(new DisabledPasswordCallback() { @Override public Credentials prompt(final Host bookmark, final String title, final String reason, final LoginOptions options) { return new VaultCredentials("test"); } })); - PreferencesFactory.get().setProperty("factory.vault.class", CryptoVault.class.getName()); final Transfer t = new UploadTransfer(new Host(new TestProtocol()), Collections.singletonList(new TransferItem(dir1, localDirectory1)), new NullFilter<>()); assertTrue(new SingleTransferWorker(session, session, t, new TransferOptions(), new TransferSpeedometer(t), new DisabledTransferPrompt() { @Override diff --git a/onedrive/src/test/java/ch/cyberduck/core/cryptomator/CopyWorkerTest.java b/onedrive/src/test/java/ch/cyberduck/core/cryptomator/CopyWorkerTest.java index b48b7f32d91..57fe57cbb64 100644 --- a/onedrive/src/test/java/ch/cyberduck/core/cryptomator/CopyWorkerTest.java +++ b/onedrive/src/test/java/ch/cyberduck/core/cryptomator/CopyWorkerTest.java @@ -47,12 +47,14 @@ import ch.cyberduck.core.transfer.TransferStatus; import ch.cyberduck.core.vault.DefaultVaultRegistry; import ch.cyberduck.core.vault.VaultCredentials; +import ch.cyberduck.core.vault.VaultMetadata; import ch.cyberduck.core.worker.CopyWorker; import ch.cyberduck.core.worker.DeleteWorker; import ch.cyberduck.test.IntegrationTest; import org.apache.commons.io.IOUtils; import org.apache.commons.lang3.RandomUtils; +import org.junit.Ignore; import org.junit.Test; import org.junit.experimental.categories.Category; import org.junit.runner.RunWith; @@ -66,7 +68,6 @@ import java.util.EnumSet; import static org.junit.Assert.*; -import static org.junit.Assume.assumeTrue; @Category(IntegrationTest.class) @RunWith(value = Parameterized.class) @@ -78,8 +79,8 @@ public void testCopyFile() throws Exception { final Path vault = new Path(home, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); final Path source = new Path(vault, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.file)); final Path target = new Path(vault, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.file)); - final CryptoVault cryptomator = new CryptoVault(vault); - cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); final DefaultVaultRegistry registry = new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator); session.withRegistry(registry); final byte[] content = RandomUtils.nextBytes(40500); @@ -105,8 +106,8 @@ public void testCopyToDifferentFolderCryptomator() throws Exception { final Path source = new Path(vault, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.file)); final Path targetFolder = new Path(vault, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); final Path target = new Path(targetFolder, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.file)); - final CryptoVault cryptomator = new CryptoVault(vault); - cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); final DefaultVaultRegistry registry = new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator); session.withRegistry(registry); new CryptoTouchFeature<>(session, new DefaultTouchFeature( @@ -123,15 +124,15 @@ public void testCopyToDifferentFolderCryptomator() throws Exception { } @Test + @Ignore("Filename shortening not implemented yet") public void testCopyToDifferentFolderLongFilenameCryptomator() throws Exception { - assumeTrue(vaultVersion == CryptoVault.VAULT_VERSION_DEPRECATED); final Path home = new OneDriveHomeFinderService().find(); final Path vault = new Path(home, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); final Path source = new Path(vault, new AlphanumericRandomStringService(130).random(), EnumSet.of(Path.Type.file)); final Path targetFolder = new Path(vault, new AlphanumericRandomStringService(130).random(), EnumSet.of(Path.Type.directory)); final Path target = new Path(targetFolder, new AlphanumericRandomStringService(130).random(), EnumSet.of(Path.Type.file)); - final CryptoVault cryptomator = new CryptoVault(vault); - cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); final DefaultVaultRegistry registry = new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator); session.withRegistry(registry); new CryptoTouchFeature<>(session, new DefaultTouchFeature( @@ -153,8 +154,8 @@ public void testCopyFolder() throws Exception { final Path vault = new Path(home, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); final Path folder = new Path(vault, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); final Path file = new Path(folder, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.file)); - final CryptoVault cryptomator = new CryptoVault(vault); - cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); final DefaultVaultRegistry registry = new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator); session.withRegistry(registry); cryptomator.getFeature(session, Directory.class, new GraphDirectoryFeature(session, fileid)).mkdir( @@ -190,8 +191,8 @@ public void testCopyFileIntoVault() throws Exception { assertTrue(new GraphFindFeature(session, fileid).find(cleartextFile)); final Path encryptedFolder = new Path(vault, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); final Path encryptedFile = new Path(encryptedFolder, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.file)); - final CryptoVault cryptomator = new CryptoVault(vault); - cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); final DefaultVaultRegistry registry = new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator); session.withRegistry(registry); cryptomator.getFeature(session, Directory.class, new GraphDirectoryFeature(session, fileid)).mkdir( @@ -221,8 +222,8 @@ public void testCopyDirectoryIntoVault() throws Exception { session).touch(new GraphWriteFeature(session, fileid), cleartextFile, new TransferStatus()); assertTrue(new GraphFindFeature(session, fileid).find(cleartextFolder)); assertTrue(new GraphFindFeature(session, fileid).find(cleartextFile)); - final CryptoVault cryptomator = new CryptoVault(vault); - cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); final DefaultVaultRegistry registry = new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator); session.withRegistry(registry); // move directory into vault @@ -246,8 +247,8 @@ public void testCopyFileOutsideVault() throws Exception { new GraphDirectoryFeature(session, fileid).mkdir(new GraphWriteFeature(session, fileid), clearFolder, new TransferStatus()); final Path encryptedFolder = new Path(vault, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); final Path encryptedFile = new Path(encryptedFolder, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.file)); - final CryptoVault cryptomator = new CryptoVault(vault); - cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); final DefaultVaultRegistry registry = new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator); session.withRegistry(registry); cryptomator.getFeature(session, Directory.class, new GraphDirectoryFeature(session, fileid)).mkdir( @@ -272,8 +273,8 @@ public void testCopyDirectoryOutsideVault() throws Exception { final Path vault = new Path(home, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); final Path encryptedFolder = new Path(vault, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); final Path encryptedFile = new Path(encryptedFolder, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.file)); - final CryptoVault cryptomator = new CryptoVault(vault); - cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); final DefaultVaultRegistry registry = new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator); session.withRegistry(registry); cryptomator.getFeature(session, Directory.class, new GraphDirectoryFeature(session, fileid)).mkdir( diff --git a/onedrive/src/test/java/ch/cyberduck/core/cryptomator/CryptoOneDriveSingleTransferWorkerTest.java b/onedrive/src/test/java/ch/cyberduck/core/cryptomator/CryptoOneDriveSingleTransferWorkerTest.java index dcbb526d07f..1ef3e24ab06 100644 --- a/onedrive/src/test/java/ch/cyberduck/core/cryptomator/CryptoOneDriveSingleTransferWorkerTest.java +++ b/onedrive/src/test/java/ch/cyberduck/core/cryptomator/CryptoOneDriveSingleTransferWorkerTest.java @@ -50,6 +50,7 @@ import ch.cyberduck.core.transfer.UploadTransfer; import ch.cyberduck.core.vault.DefaultVaultRegistry; import ch.cyberduck.core.vault.VaultCredentials; +import ch.cyberduck.core.vault.VaultMetadata; import ch.cyberduck.core.worker.SingleTransferWorker; import ch.cyberduck.test.IntegrationTest; @@ -91,8 +92,8 @@ public void testUpload() throws Exception { final OutputStream out2 = localFile2.getOutputStream(false); IOUtils.write(content, out2); out2.close(); - final CryptoVault cryptomator = new CryptoVault(vault); - cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); session.withRegistry(new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator)); final Transfer t = new UploadTransfer(new Host(new TestProtocol()), Collections.singletonList(new TransferItem(dir1, localDirectory1)), new NullFilter<>()); assertTrue(new SingleTransferWorker(session, session, t, new TransferOptions(), new TransferSpeedometer(t), new DisabledTransferPrompt() { diff --git a/onedrive/src/test/java/ch/cyberduck/core/cryptomator/GraphDirectoryFeatureTest.java b/onedrive/src/test/java/ch/cyberduck/core/cryptomator/GraphDirectoryFeatureTest.java index 9fdc54709f3..ae3907b16ab 100644 --- a/onedrive/src/test/java/ch/cyberduck/core/cryptomator/GraphDirectoryFeatureTest.java +++ b/onedrive/src/test/java/ch/cyberduck/core/cryptomator/GraphDirectoryFeatureTest.java @@ -40,8 +40,10 @@ import ch.cyberduck.core.transfer.TransferStatus; import ch.cyberduck.core.vault.DefaultVaultRegistry; import ch.cyberduck.core.vault.VaultCredentials; +import ch.cyberduck.core.vault.VaultMetadata; import ch.cyberduck.test.IntegrationTest; +import org.junit.Ignore; import org.junit.Test; import org.junit.experimental.categories.Category; import org.junit.runner.RunWith; @@ -53,7 +55,6 @@ import java.util.stream.Collectors; import static org.junit.Assert.*; -import static org.junit.Assume.assumeTrue; @Category(IntegrationTest.class) @RunWith(value = Parameterized.class) @@ -63,8 +64,8 @@ public class GraphDirectoryFeatureTest extends AbstractOneDriveTest { public void testMakeDirectoryEncrypted() throws Exception { final Path home = new OneDriveHomeFinderService().find(); final Path vault = new Path(home, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); - final CryptoVault cryptomator = new CryptoVault(vault); - cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); session.withRegistry(new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator)); final Path test = cryptomator.getFeature(session, Directory.class, new GraphDirectoryFeature(session, fileid)).mkdir( cryptomator.getFeature(session, Write.class, new GraphWriteFeature(session, fileid)), new Path(vault, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)), new TransferStatus()); @@ -84,12 +85,12 @@ public void testMakeDirectoryEncrypted() throws Exception { } @Test + @Ignore(value = "Filename shortening not yet implemented") public void testMakeDirectoryLongFilenameEncrypted() throws Exception { - assumeTrue(vaultVersion == CryptoVault.VAULT_VERSION_DEPRECATED); final Path home = new OneDriveHomeFinderService().find(); final Path vault = new Path(home, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); - final CryptoVault cryptomator = new CryptoVault(vault); - cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); session.withRegistry(new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator)); final Path test = cryptomator.getFeature(session, Directory.class, new GraphDirectoryFeature(session, fileid)).mkdir( cryptomator.getFeature(session, Write.class, new GraphWriteFeature(session, fileid)), new Path(vault, new AlphanumericRandomStringService(130).random(), EnumSet.of(Path.Type.directory)), new TransferStatus()); diff --git a/onedrive/src/test/java/ch/cyberduck/core/cryptomator/GraphMoveFeatureTest.java b/onedrive/src/test/java/ch/cyberduck/core/cryptomator/GraphMoveFeatureTest.java index 12de9fca06c..2dbaf874da5 100644 --- a/onedrive/src/test/java/ch/cyberduck/core/cryptomator/GraphMoveFeatureTest.java +++ b/onedrive/src/test/java/ch/cyberduck/core/cryptomator/GraphMoveFeatureTest.java @@ -40,6 +40,7 @@ import ch.cyberduck.core.transfer.TransferStatus; import ch.cyberduck.core.vault.DefaultVaultRegistry; import ch.cyberduck.core.vault.VaultCredentials; +import ch.cyberduck.core.vault.VaultMetadata; import ch.cyberduck.test.IntegrationTest; import org.junit.Test; @@ -62,8 +63,8 @@ public void testMove() throws Exception { final Path home = new OneDriveHomeFinderService().find(); final Path vault = new Path(home, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); final Path folder = new Path(vault, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); - final CryptoVault cryptomator = new CryptoVault(vault); - cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); session.withRegistry(new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator)); cryptomator.getFeature(session, Directory.class, new GraphDirectoryFeature(session, fileid)).mkdir( cryptomator.getFeature(session, Write.class, new GraphWriteFeature(session, fileid)), folder, new TransferStatus()); diff --git a/onedrive/src/test/java/ch/cyberduck/core/cryptomator/GraphTouchFeatureTest.java b/onedrive/src/test/java/ch/cyberduck/core/cryptomator/GraphTouchFeatureTest.java index be98c69d2fc..0aeaaf9a83c 100644 --- a/onedrive/src/test/java/ch/cyberduck/core/cryptomator/GraphTouchFeatureTest.java +++ b/onedrive/src/test/java/ch/cyberduck/core/cryptomator/GraphTouchFeatureTest.java @@ -36,8 +36,10 @@ import ch.cyberduck.core.transfer.TransferStatus; import ch.cyberduck.core.vault.DefaultVaultRegistry; import ch.cyberduck.core.vault.VaultCredentials; +import ch.cyberduck.core.vault.VaultMetadata; import ch.cyberduck.test.IntegrationTest; +import org.junit.Ignore; import org.junit.Test; import org.junit.experimental.categories.Category; import org.junit.runner.RunWith; @@ -48,19 +50,18 @@ import java.util.EnumSet; import static org.junit.Assert.*; -import static org.junit.Assume.assumeTrue; @Category(IntegrationTest.class) @RunWith(value = Parameterized.class) public class GraphTouchFeatureTest extends AbstractOneDriveTest { @Test + @Ignore(value = "Filename shortening not yet implemented") public void testTouchLongFilenameEncrypted() throws Exception { - assumeTrue(vaultVersion == CryptoVault.VAULT_VERSION_DEPRECATED); final Path home = new OneDriveHomeFinderService().find(); final Path vault = new Path(home, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); - final CryptoVault cryptomator = new CryptoVault(vault); - cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); session.withRegistry(new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator)); final TransferStatus status = new TransferStatus(); final Path test = new CryptoTouchFeature<>(session, new DefaultTouchFeature(session), cryptomator).touch( @@ -76,12 +77,12 @@ public void testTouchLongFilenameEncrypted() throws Exception { } @Test + @Ignore(value = "Filename shortening not yet implemented") public void testTouchLongFilenameEncryptedDefaultFeature() throws Exception { - assumeTrue(vaultVersion == CryptoVault.VAULT_VERSION_DEPRECATED); final Path home = new OneDriveHomeFinderService().find(); final Path vault = new Path(home, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); - final CryptoVault cryptomator = new CryptoVault(vault); - cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); session.withRegistry(new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator)); final TransferStatus status = new TransferStatus(); final Path test = new CryptoTouchFeature<>(session, new DefaultTouchFeature(session), cryptomator).touch( diff --git a/onedrive/src/test/java/ch/cyberduck/core/cryptomator/GraphWriteFeatureTest.java b/onedrive/src/test/java/ch/cyberduck/core/cryptomator/GraphWriteFeatureTest.java index 875948c1662..98bd4a30524 100644 --- a/onedrive/src/test/java/ch/cyberduck/core/cryptomator/GraphWriteFeatureTest.java +++ b/onedrive/src/test/java/ch/cyberduck/core/cryptomator/GraphWriteFeatureTest.java @@ -40,6 +40,7 @@ import ch.cyberduck.core.transfer.TransferStatus; import ch.cyberduck.core.vault.DefaultVaultRegistry; import ch.cyberduck.core.vault.VaultCredentials; +import ch.cyberduck.core.vault.VaultMetadata; import ch.cyberduck.test.IntegrationTest; import org.apache.commons.lang3.RandomUtils; @@ -72,8 +73,8 @@ public void testWrite() throws Exception { final Path home = new OneDriveHomeFinderService().find(); final Path vault = new Path(home, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); final Path test = new Path(vault, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.file)); - final CryptoVault cryptomator = new CryptoVault(vault); - cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); session.withRegistry(new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator)); final CryptoWriteFeature writer = new CryptoWriteFeature<>(session, new GraphWriteFeature(session, fileid), cryptomator); final FileHeader header = cryptomator.getFileHeaderCryptor().create(); diff --git a/onedrive/src/test/java/ch/cyberduck/core/cryptomator/MoveWorkerTest.java b/onedrive/src/test/java/ch/cyberduck/core/cryptomator/MoveWorkerTest.java index 13ac904b2aa..b0e995662af 100644 --- a/onedrive/src/test/java/ch/cyberduck/core/cryptomator/MoveWorkerTest.java +++ b/onedrive/src/test/java/ch/cyberduck/core/cryptomator/MoveWorkerTest.java @@ -52,11 +52,13 @@ import ch.cyberduck.core.transfer.TransferStatus; import ch.cyberduck.core.vault.DefaultVaultRegistry; import ch.cyberduck.core.vault.VaultCredentials; +import ch.cyberduck.core.vault.VaultMetadata; import ch.cyberduck.core.worker.MoveWorker; import ch.cyberduck.test.IntegrationTest; import org.apache.commons.io.IOUtils; import org.apache.commons.lang3.RandomUtils; +import org.junit.Ignore; import org.junit.Test; import org.junit.experimental.categories.Category; import org.junit.runner.RunWith; @@ -70,7 +72,6 @@ import java.util.EnumSet; import static org.junit.Assert.*; -import static org.junit.Assume.assumeTrue; @Category(IntegrationTest.class) @RunWith(value = Parameterized.class) @@ -82,8 +83,8 @@ public void testMoveSameFolderCryptomator() throws Exception { final Path vault = new Path(home, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); final Path source = new Path(vault, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.file)); final Path target = new Path(vault, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.file)); - final CryptoVault cryptomator = new CryptoVault(vault); - cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); session.withRegistry(new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator)); final byte[] content = RandomUtils.nextBytes(40500); final TransferStatus status = new TransferStatus(); @@ -107,8 +108,8 @@ public void testMoveToDifferentFolderCryptomator() throws Exception { final Path source = new Path(vault, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.file)); final Path targetFolder = new Path(vault, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); final Path target = new Path(targetFolder, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.file)); - final CryptoVault cryptomator = new CryptoVault(vault); - cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); session.withRegistry(new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator)); new CryptoTouchFeature<>(session, new DefaultTouchFeature( session), cryptomator).touch(cryptomator.getFeature(session, Write.class, new GraphWriteFeature(session, fileid)), source, new TransferStatus()); @@ -123,16 +124,17 @@ public void testMoveToDifferentFolderCryptomator() throws Exception { cryptomator.getFeature(session, Delete.class, new GraphDeleteFeature(session, fileid)).delete(Arrays.asList(target, targetFolder, vault), new DisabledLoginCallback(), new Delete.DisabledCallback()); } + //TODO @Test + @Ignore("Filename shortening not yet implemented") public void testMoveToDifferentFolderLongFilenameCryptomator() throws Exception { - assumeTrue(vaultVersion == CryptoVault.VAULT_VERSION_DEPRECATED); final Path home = new OneDriveHomeFinderService().find(); final Path vault = new Path(home, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); final Path source = new Path(vault, new AlphanumericRandomStringService(130).random(), EnumSet.of(Path.Type.file)); final Path targetFolder = new Path(vault, new AlphanumericRandomStringService(130).random(), EnumSet.of(Path.Type.directory)); final Path target = new Path(targetFolder, new AlphanumericRandomStringService(130).random(), EnumSet.of(Path.Type.file)); - final CryptoVault cryptomator = new CryptoVault(vault); - cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); session.withRegistry(new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator)); new CryptoTouchFeature<>(session, new DefaultTouchFeature( session), cryptomator).touch(cryptomator.getFeature(session, Write.class, new GraphWriteFeature(session, fileid)), source, new TransferStatus()); @@ -153,8 +155,8 @@ public void testMoveFolder() throws Exception { final Path vault = new Path(home, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); final Path folder = new Path(vault, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); final Path file = new Path(folder, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.file)); - final CryptoVault cryptomator = new CryptoVault(vault); - cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); session.withRegistry(new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator)); cryptomator.getFeature(session, Directory.class, new GraphDirectoryFeature(session, fileid)).mkdir( cryptomator.getFeature(session, Write.class, new GraphWriteFeature(session, fileid)), folder, new TransferStatus()); @@ -187,8 +189,8 @@ public void testMoveFileIntoVault() throws Exception { assertTrue(new DefaultFindFeature(session).find(clearFile)); final Path encryptedFolder = new Path(vault, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); final Path encryptedFile = new Path(encryptedFolder, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.file)); - final CryptoVault cryptomator = new CryptoVault(vault); - cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); final DefaultVaultRegistry registry = new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator); session.withRegistry(registry); cryptomator.getFeature(session, Directory.class, new GraphDirectoryFeature(session, fileid)).mkdir( @@ -214,8 +216,8 @@ public void testMoveDirectoryIntoVault() throws Exception { session).touch(new GraphWriteFeature(session, fileid), clearFile, new TransferStatus()); assertTrue(new DefaultFindFeature(session).find(clearFolder)); assertTrue(new DefaultFindFeature(session).find(clearFile)); - final CryptoVault cryptomator = new CryptoVault(vault); - cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); final DefaultVaultRegistry registry = new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator); session.withRegistry(registry); // move directory into vault @@ -239,8 +241,8 @@ public void testMoveFileOutsideVault() throws Exception { new GraphDirectoryFeature(session, fileid).mkdir(new GraphWriteFeature(session, fileid), clearFolder, new TransferStatus()); final Path encryptedFolder = new Path(vault, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); final Path encryptedFile = new Path(encryptedFolder, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.file)); - final CryptoVault cryptomator = new CryptoVault(vault); - cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); final DefaultVaultRegistry registry = new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator); session.withRegistry(registry); cryptomator.getFeature(session, Directory.class, new GraphDirectoryFeature(session, fileid)).mkdir( @@ -267,8 +269,8 @@ public void testMoveDirectoryOutsideVault() throws Exception { final Path vault = new Path(home, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); final Path encryptedFolder = new Path(vault, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); final Path encryptedFile = new Path(encryptedFolder, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.file)); - final CryptoVault cryptomator = new CryptoVault(vault); - cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); final DefaultVaultRegistry registry = new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator); session.withRegistry(registry); cryptomator.getFeature(session, Directory.class, new GraphDirectoryFeature(session, fileid)).mkdir( diff --git a/onedrive/src/test/java/ch/cyberduck/core/cryptomator/OneDriveListServiceTest.java b/onedrive/src/test/java/ch/cyberduck/core/cryptomator/OneDriveListServiceTest.java index b7a15b186eb..48ac0dbb726 100644 --- a/onedrive/src/test/java/ch/cyberduck/core/cryptomator/OneDriveListServiceTest.java +++ b/onedrive/src/test/java/ch/cyberduck/core/cryptomator/OneDriveListServiceTest.java @@ -34,6 +34,7 @@ import ch.cyberduck.core.transfer.TransferStatus; import ch.cyberduck.core.vault.DefaultVaultRegistry; import ch.cyberduck.core.vault.VaultCredentials; +import ch.cyberduck.core.vault.VaultMetadata; import ch.cyberduck.test.IntegrationTest; import org.junit.Test; @@ -57,8 +58,8 @@ public void testListCryptomator() throws Exception { final Path home = new OneDriveHomeFinderService().find(); final Path vault = new Path(home, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); final Path test = new Path(vault, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.file)); - final CryptoVault cryptomator = new CryptoVault(vault); - cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); session.withRegistry(new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator)); assertTrue(new CryptoListService(session, new GraphItemListService(session, fileid), cryptomator).list(vault, new DisabledListProgressListener()).isEmpty()); new CryptoTouchFeature<>(session, new DefaultTouchFeature( diff --git a/onedrive/src/test/java/ch/cyberduck/core/onedrive/AbstractOneDriveTest.java b/onedrive/src/test/java/ch/cyberduck/core/onedrive/AbstractOneDriveTest.java index 26e9e131eb9..bb01fa9da76 100644 --- a/onedrive/src/test/java/ch/cyberduck/core/onedrive/AbstractOneDriveTest.java +++ b/onedrive/src/test/java/ch/cyberduck/core/onedrive/AbstractOneDriveTest.java @@ -20,9 +20,9 @@ import ch.cyberduck.core.HostPasswordStore; import ch.cyberduck.core.Protocol; import ch.cyberduck.core.Scheme; -import ch.cyberduck.core.cryptomator.CryptoVault; import ch.cyberduck.core.ssl.X509KeyManager; import ch.cyberduck.core.ssl.X509TrustManager; +import ch.cyberduck.core.vault.VaultMetadata; import ch.cyberduck.test.VaultTest; import org.junit.runners.Parameterized; @@ -34,11 +34,11 @@ public abstract class AbstractOneDriveTest extends AbstractGraphTest { @Parameterized.Parameters(name = "vaultVersion = {0}") public static Object[] data() { - return new Object[]{CryptoVault.VAULT_VERSION_DEPRECATED, CryptoVault.VAULT_VERSION}; + return new Object[]{VaultMetadata.Type.V8, VaultMetadata.Type.UVF}; } @Parameterized.Parameter - public int vaultVersion; + public VaultMetadata.Type vaultVersion; @Override protected Protocol protocol() { diff --git a/openstack/src/test/java/ch/cyberduck/core/cryptomator/CopyWorkerTest.java b/openstack/src/test/java/ch/cyberduck/core/cryptomator/CopyWorkerTest.java index bb939ea9231..3feb8e8103e 100644 --- a/openstack/src/test/java/ch/cyberduck/core/cryptomator/CopyWorkerTest.java +++ b/openstack/src/test/java/ch/cyberduck/core/cryptomator/CopyWorkerTest.java @@ -46,12 +46,14 @@ import ch.cyberduck.core.transfer.TransferStatus; import ch.cyberduck.core.vault.DefaultVaultRegistry; import ch.cyberduck.core.vault.VaultCredentials; +import ch.cyberduck.core.vault.VaultMetadata; import ch.cyberduck.core.worker.CopyWorker; import ch.cyberduck.core.worker.DeleteWorker; import ch.cyberduck.test.IntegrationTest; import org.apache.commons.io.IOUtils; import org.apache.commons.lang3.RandomUtils; +import org.junit.Ignore; import org.junit.Test; import org.junit.experimental.categories.Category; import org.junit.runner.RunWith; @@ -66,7 +68,6 @@ import ch.iterate.openstack.swift.model.StorageObject; import static org.junit.Assert.*; -import static org.junit.Assume.assumeTrue; @Category(IntegrationTest.class) @RunWith(value = Parameterized.class) @@ -78,8 +79,8 @@ public void testCopyFile() throws Exception { final Path vault = new Path(home, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); final Path source = new Path(vault, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.file)); final Path target = new Path(vault, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.file)); - final CryptoVault cryptomator = new CryptoVault(vault); - cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); final DefaultVaultRegistry registry = new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator); session.withRegistry(registry); final byte[] content = RandomUtils.nextBytes(40500); @@ -104,8 +105,8 @@ public void testCopyToDifferentFolderCryptomator() throws Exception { final Path source = new Path(vault, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.file)); final Path targetFolder = new Path(vault, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); final Path target = new Path(targetFolder, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.file)); - final CryptoVault cryptomator = new CryptoVault(vault); - cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); final DefaultVaultRegistry registry = new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator); session.withRegistry(registry); new CryptoTouchFeature<>(session, new DefaultTouchFeature( @@ -122,15 +123,15 @@ public void testCopyToDifferentFolderCryptomator() throws Exception { } @Test + @Ignore("Filename shortening not implemented yet") public void testCopyToDifferentFolderLongFilenameCryptomator() throws Exception { - assumeTrue(vaultVersion == CryptoVault.VAULT_VERSION_DEPRECATED); final Path home = new Path("test.cyberduck.ch", EnumSet.of(Path.Type.volume, Path.Type.directory)); final Path vault = new Path(home, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); final Path source = new Path(vault, new AlphanumericRandomStringService(130).random(), EnumSet.of(Path.Type.file)); final Path targetFolder = new Path(vault, new AlphanumericRandomStringService(130).random(), EnumSet.of(Path.Type.directory)); final Path target = new Path(targetFolder, new AlphanumericRandomStringService(130).random(), EnumSet.of(Path.Type.file)); - final CryptoVault cryptomator = new CryptoVault(vault); - cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); final DefaultVaultRegistry registry = new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator); session.withRegistry(registry); new CryptoTouchFeature<>(session, new DefaultTouchFeature( @@ -152,8 +153,8 @@ public void testCopyFolder() throws Exception { final Path vault = new Path(home, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); final Path folder = new Path(vault, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); final Path file = new Path(folder, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.file)); - final CryptoVault cryptomator = new CryptoVault(vault); - cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); final DefaultVaultRegistry registry = new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator); session.withRegistry(registry); cryptomator.getFeature(session, Directory.class, new SwiftDirectoryFeature(session)).mkdir( @@ -189,8 +190,8 @@ public void testCopyFileIntoVault() throws Exception { assertTrue(new SwiftFindFeature(session).find(cleartextFile)); final Path encryptedFolder = new Path(vault, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); final Path encryptedFile = new Path(encryptedFolder, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.file)); - final CryptoVault cryptomator = new CryptoVault(vault); - cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); final DefaultVaultRegistry registry = new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator); session.withRegistry(registry); cryptomator.getFeature(session, Directory.class, new SwiftDirectoryFeature(session)).mkdir( @@ -218,8 +219,8 @@ public void testCopyDirectoryIntoVault() throws Exception { new SwiftTouchFeature(session, new SwiftRegionService(session)).touch(new SwiftWriteFeature(session, new SwiftRegionService(session)), cleartextFile, new TransferStatus()); assertTrue(new SwiftFindFeature(session).find(cleartextFolder)); assertTrue(new SwiftFindFeature(session).find(cleartextFile)); - final CryptoVault cryptomator = new CryptoVault(vault); - cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); final DefaultVaultRegistry registry = new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator); session.withRegistry(registry); // move directory into vault @@ -243,8 +244,8 @@ public void testCopyFileOutsideVault() throws Exception { new SwiftDirectoryFeature(session).mkdir(new SwiftWriteFeature(session, new SwiftRegionService(session)), clearFolder, new TransferStatus()); final Path encryptedFolder = new Path(vault, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); final Path encryptedFile = new Path(encryptedFolder, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.file)); - final CryptoVault cryptomator = new CryptoVault(vault); - cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); final DefaultVaultRegistry registry = new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator); session.withRegistry(registry); cryptomator.getFeature(session, Directory.class, new SwiftDirectoryFeature(session)).mkdir( @@ -269,8 +270,8 @@ public void testCopyDirectoryOutsideVault() throws Exception { final Path vault = new Path(home, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); final Path encryptedFolder = new Path(vault, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); final Path encryptedFile = new Path(encryptedFolder, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.file)); - final CryptoVault cryptomator = new CryptoVault(vault); - cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); final DefaultVaultRegistry registry = new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator); session.withRegistry(registry); cryptomator.getFeature(session, Directory.class, new SwiftDirectoryFeature(session)).mkdir( diff --git a/openstack/src/test/java/ch/cyberduck/core/cryptomator/CryptoSwiftSingleTransferWorkerTest.java b/openstack/src/test/java/ch/cyberduck/core/cryptomator/CryptoSwiftSingleTransferWorkerTest.java index 67e32df7521..0a1660cfd7d 100644 --- a/openstack/src/test/java/ch/cyberduck/core/cryptomator/CryptoSwiftSingleTransferWorkerTest.java +++ b/openstack/src/test/java/ch/cyberduck/core/cryptomator/CryptoSwiftSingleTransferWorkerTest.java @@ -50,6 +50,7 @@ import ch.cyberduck.core.transfer.UploadTransfer; import ch.cyberduck.core.vault.DefaultVaultRegistry; import ch.cyberduck.core.vault.VaultCredentials; +import ch.cyberduck.core.vault.VaultMetadata; import ch.cyberduck.core.worker.SingleTransferWorker; import ch.cyberduck.test.IntegrationTest; @@ -91,8 +92,8 @@ public void testUpload() throws Exception { final OutputStream out2 = localFile2.getOutputStream(false); IOUtils.write(content, out2); out2.close(); - final CryptoVault cryptomator = new CryptoVault(vault); - cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); session.withRegistry(new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator)); final Transfer t = new UploadTransfer(new Host(new TestProtocol()), Collections.singletonList(new TransferItem(dir1, localDirectory1)), new NullFilter<>()); assertTrue(new SingleTransferWorker(session, session, t, new TransferOptions(), new TransferSpeedometer(t), new DisabledTransferPrompt() { diff --git a/openstack/src/test/java/ch/cyberduck/core/cryptomator/SwiftDirectoryFeatureTest.java b/openstack/src/test/java/ch/cyberduck/core/cryptomator/SwiftDirectoryFeatureTest.java index 16a9a6f0218..4e4bb919cd1 100644 --- a/openstack/src/test/java/ch/cyberduck/core/cryptomator/SwiftDirectoryFeatureTest.java +++ b/openstack/src/test/java/ch/cyberduck/core/cryptomator/SwiftDirectoryFeatureTest.java @@ -32,8 +32,10 @@ import ch.cyberduck.core.transfer.TransferStatus; import ch.cyberduck.core.vault.DefaultVaultRegistry; import ch.cyberduck.core.vault.VaultCredentials; +import ch.cyberduck.core.vault.VaultMetadata; import ch.cyberduck.test.IntegrationTest; +import org.junit.Ignore; import org.junit.Test; import org.junit.experimental.categories.Category; import org.junit.runner.RunWith; @@ -43,7 +45,6 @@ import java.util.EnumSet; import static org.junit.Assert.assertTrue; -import static org.junit.Assume.assumeTrue; @Category(IntegrationTest.class) @RunWith(value = Parameterized.class) @@ -54,8 +55,8 @@ public void testMakeDirectoryEncrypted() throws Exception { final Path home = new Path("/test.cyberduck.ch", EnumSet.of(Path.Type.volume, Path.Type.directory)); final Path vault = new Path(home, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); final Path test = new Path(vault, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); - final CryptoVault cryptomator = new CryptoVault(vault); - cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); session.withRegistry(new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator)); cryptomator.getFeature(session, Directory.class, new SwiftDirectoryFeature(session)).mkdir( cryptomator.getFeature(session, Write.class, new SwiftWriteFeature(session, new SwiftRegionService(session))), test, new TransferStatus()); @@ -64,13 +65,13 @@ public void testMakeDirectoryEncrypted() throws Exception { } @Test + @Ignore("Filename shortening not yet implemented") public void testMakeDirectoryLongFilenameEncrypted() throws Exception { - assumeTrue(vaultVersion == CryptoVault.VAULT_VERSION_DEPRECATED); final Path home = new Path("/test.cyberduck.ch", EnumSet.of(Path.Type.volume, Path.Type.directory)); final Path vault = new Path(home, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); final Path test = new Path(vault, new AlphanumericRandomStringService(130).random(), EnumSet.of(Path.Type.directory)); - final CryptoVault cryptomator = new CryptoVault(vault); - cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); session.withRegistry(new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator)); cryptomator.getFeature(session, Directory.class, new SwiftDirectoryFeature(session)).mkdir( cryptomator.getFeature(session, Write.class, new SwiftWriteFeature(session, new SwiftRegionService(session))), test, new TransferStatus()); diff --git a/openstack/src/test/java/ch/cyberduck/core/cryptomator/SwiftLargeObjectUploadFeatureTest.java b/openstack/src/test/java/ch/cyberduck/core/cryptomator/SwiftLargeObjectUploadFeatureTest.java index 3044112839d..cfd30588f7d 100644 --- a/openstack/src/test/java/ch/cyberduck/core/cryptomator/SwiftLargeObjectUploadFeatureTest.java +++ b/openstack/src/test/java/ch/cyberduck/core/cryptomator/SwiftLargeObjectUploadFeatureTest.java @@ -43,6 +43,7 @@ import ch.cyberduck.core.transfer.TransferStatus; import ch.cyberduck.core.vault.DefaultVaultRegistry; import ch.cyberduck.core.vault.VaultCredentials; +import ch.cyberduck.core.vault.VaultMetadata; import ch.cyberduck.test.IntegrationTest; import org.apache.commons.io.IOUtils; @@ -74,8 +75,8 @@ public void testLargeObjectUpload() throws Exception { home.attributes().setRegion("IAD"); final Path vault = new Path(home, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); final Path test = new Path(vault, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.file)); - final CryptoVault cryptomator = new CryptoVault(vault); - cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); session.withRegistry(new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator)); final SwiftRegionService regionService = new SwiftRegionService(session); final CryptoUploadFeature service = new CryptoUploadFeature<>(session, diff --git a/openstack/src/test/java/ch/cyberduck/core/cryptomator/SwiftLargeUploadWriteFeatureTest.java b/openstack/src/test/java/ch/cyberduck/core/cryptomator/SwiftLargeUploadWriteFeatureTest.java index 3d3d54518c0..d2ec933a8da 100644 --- a/openstack/src/test/java/ch/cyberduck/core/cryptomator/SwiftLargeUploadWriteFeatureTest.java +++ b/openstack/src/test/java/ch/cyberduck/core/cryptomator/SwiftLargeUploadWriteFeatureTest.java @@ -37,6 +37,7 @@ import ch.cyberduck.core.transfer.TransferStatus; import ch.cyberduck.core.vault.DefaultVaultRegistry; import ch.cyberduck.core.vault.VaultCredentials; +import ch.cyberduck.core.vault.VaultMetadata; import ch.cyberduck.test.IntegrationTest; import org.apache.commons.io.IOUtils; @@ -65,8 +66,8 @@ public void testWrite() throws Exception { home.attributes().setRegion("IAD"); final Path vault = new Path(home, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); final Path test = new Path(vault, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.file)); - final CryptoVault cryptomator = new CryptoVault(vault); - cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); session.withRegistry(new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator)); final SwiftRegionService regionService = new SwiftRegionService(session); final CryptoWriteFeature feature = new CryptoWriteFeature<>(session, new SwiftLargeUploadWriteFeature(session, regionService, diff --git a/openstack/src/test/java/ch/cyberduck/core/cryptomator/SwiftListServiceTest.java b/openstack/src/test/java/ch/cyberduck/core/cryptomator/SwiftListServiceTest.java index eb7c9e2507d..6a6adc0a1a4 100644 --- a/openstack/src/test/java/ch/cyberduck/core/cryptomator/SwiftListServiceTest.java +++ b/openstack/src/test/java/ch/cyberduck/core/cryptomator/SwiftListServiceTest.java @@ -33,6 +33,7 @@ import ch.cyberduck.core.transfer.TransferStatus; import ch.cyberduck.core.vault.DefaultVaultRegistry; import ch.cyberduck.core.vault.VaultCredentials; +import ch.cyberduck.core.vault.VaultMetadata; import ch.cyberduck.test.IntegrationTest; import org.junit.Test; @@ -58,8 +59,8 @@ public void testListCryptomator() throws Exception { home.attributes().setRegion("IAD"); final Path vault = new Path(home, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); final Path test = new Path(vault, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.file)); - final CryptoVault cryptomator = new CryptoVault(vault); - cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); session.withRegistry(new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator)); assertTrue(new CryptoListService(session, new SwiftObjectListService(session), cryptomator).list(vault, new DisabledListProgressListener()).isEmpty()); final SwiftRegionService regionService = new SwiftRegionService(session); diff --git a/openstack/src/test/java/ch/cyberduck/core/cryptomator/SwiftMoveFeatureTest.java b/openstack/src/test/java/ch/cyberduck/core/cryptomator/SwiftMoveFeatureTest.java index 4d55f73a363..ed5abfda566 100644 --- a/openstack/src/test/java/ch/cyberduck/core/cryptomator/SwiftMoveFeatureTest.java +++ b/openstack/src/test/java/ch/cyberduck/core/cryptomator/SwiftMoveFeatureTest.java @@ -38,6 +38,7 @@ import ch.cyberduck.core.transfer.TransferStatus; import ch.cyberduck.core.vault.DefaultVaultRegistry; import ch.cyberduck.core.vault.VaultCredentials; +import ch.cyberduck.core.vault.VaultMetadata; import ch.cyberduck.test.IntegrationTest; import org.junit.Test; @@ -61,8 +62,8 @@ public void testMove() throws Exception { final Path vault = new Path(home, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); final Path folder = new Path(vault, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); final Path file = new Path(folder, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.file)); - final CryptoVault cryptomator = new CryptoVault(vault); - cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); final SwiftRegionService regionService = new SwiftRegionService(session); session.withRegistry(new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator)); cryptomator.getFeature(session, Directory.class, new SwiftDirectoryFeature(session, regionService)).mkdir( diff --git a/openstack/src/test/java/ch/cyberduck/core/cryptomator/SwiftTouchFeatureTest.java b/openstack/src/test/java/ch/cyberduck/core/cryptomator/SwiftTouchFeatureTest.java index b1e15592eca..1552d6512f5 100644 --- a/openstack/src/test/java/ch/cyberduck/core/cryptomator/SwiftTouchFeatureTest.java +++ b/openstack/src/test/java/ch/cyberduck/core/cryptomator/SwiftTouchFeatureTest.java @@ -34,8 +34,10 @@ import ch.cyberduck.core.transfer.TransferStatus; import ch.cyberduck.core.vault.DefaultVaultRegistry; import ch.cyberduck.core.vault.VaultCredentials; +import ch.cyberduck.core.vault.VaultMetadata; import ch.cyberduck.test.IntegrationTest; +import org.junit.Ignore; import org.junit.Test; import org.junit.experimental.categories.Category; import org.junit.runner.RunWith; @@ -48,19 +50,20 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; -import static org.junit.Assume.assumeTrue; @Category(IntegrationTest.class) @RunWith(value = Parameterized.class) public class SwiftTouchFeatureTest extends AbstractSwiftTest { + //TODO + @Test + @Ignore(value = "Filename shortening not yet implemented") public void testTouchLongFilenameEncrypted() throws Exception { - assumeTrue(vaultVersion == CryptoVault.VAULT_VERSION_DEPRECATED); final Path home = new Path("/test.cyberduck.ch", EnumSet.of(Path.Type.volume, Path.Type.directory)); final Path vault = new Path(home, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); - final CryptoVault cryptomator = new CryptoVault(vault); - cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); session.withRegistry(new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator)); final SwiftRegionService regionService = new SwiftRegionService(session); final TransferStatus status = new TransferStatus(); @@ -73,12 +76,12 @@ public void testTouchLongFilenameEncrypted() throws Exception { } @Test + @Ignore(value = "Filename shortening not yet implemented") public void testTouchLongFilenameEncryptedDefaultFeature() throws Exception { - assumeTrue(vaultVersion == CryptoVault.VAULT_VERSION_DEPRECATED); final Path home = new Path("/test.cyberduck.ch", EnumSet.of(Path.Type.volume, Path.Type.directory)); final Path vault = new Path(home, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); - final CryptoVault cryptomator = new CryptoVault(vault); - cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); session.withRegistry(new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator)); final TransferStatus status = new TransferStatus(); final Path test = new CryptoTouchFeature(session, new DefaultTouchFeature<>(session), cryptomator).touch( diff --git a/openstack/src/test/java/ch/cyberduck/core/cryptomator/SwiftWriteFeatureTest.java b/openstack/src/test/java/ch/cyberduck/core/cryptomator/SwiftWriteFeatureTest.java index f9efdbf7c60..add35c21d6a 100644 --- a/openstack/src/test/java/ch/cyberduck/core/cryptomator/SwiftWriteFeatureTest.java +++ b/openstack/src/test/java/ch/cyberduck/core/cryptomator/SwiftWriteFeatureTest.java @@ -38,6 +38,7 @@ import ch.cyberduck.core.transfer.TransferStatus; import ch.cyberduck.core.vault.DefaultVaultRegistry; import ch.cyberduck.core.vault.VaultCredentials; +import ch.cyberduck.core.vault.VaultMetadata; import ch.cyberduck.test.IntegrationTest; import org.apache.commons.lang3.RandomUtils; @@ -72,8 +73,8 @@ public void testWrite() throws Exception { home.attributes().setRegion("IAD"); final Path vault = new Path(home, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); final Path test = new Path(vault, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.file)); - final CryptoVault cryptomator = new CryptoVault(vault); - cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); session.withRegistry(new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator)); final SwiftRegionService regionService = new SwiftRegionService(session); final CryptoWriteFeature writer = new CryptoWriteFeature(session, new SwiftWriteFeature(session, regionService), cryptomator); diff --git a/openstack/src/test/java/ch/cyberduck/core/openstack/AbstractSwiftTest.java b/openstack/src/test/java/ch/cyberduck/core/openstack/AbstractSwiftTest.java index fed502ac0eb..d4ce50d6f93 100644 --- a/openstack/src/test/java/ch/cyberduck/core/openstack/AbstractSwiftTest.java +++ b/openstack/src/test/java/ch/cyberduck/core/openstack/AbstractSwiftTest.java @@ -24,9 +24,9 @@ import ch.cyberduck.core.Host; import ch.cyberduck.core.LoginConnectionService; import ch.cyberduck.core.LoginOptions; -import ch.cyberduck.core.cryptomator.CryptoVault; import ch.cyberduck.core.ssl.DefaultX509KeyManager; import ch.cyberduck.core.ssl.DisabledX509TrustManager; +import ch.cyberduck.core.vault.VaultMetadata; import ch.cyberduck.test.VaultTest; import org.junit.After; @@ -41,11 +41,11 @@ public abstract class AbstractSwiftTest extends VaultTest { @Parameterized.Parameters(name = "vaultVersion = {0}") public static Object[] data() { - return new Object[]{CryptoVault.VAULT_VERSION_DEPRECATED, CryptoVault.VAULT_VERSION}; + return new Object[]{VaultMetadata.Type.V8, VaultMetadata.Type.UVF}; } @Parameterized.Parameter - public int vaultVersion; + public VaultMetadata.Type vaultVersion; @After public void disconnect() throws Exception { @@ -64,7 +64,7 @@ public Credentials prompt(final Host bookmark, final String title, final String return null; } }, new DisabledHostKeyCallback(), - new DisabledPasswordStore(), new DisabledProgressListener()); + new DisabledPasswordStore(), new DisabledProgressListener()); login.check(session, new DisabledCancelCallback()); } } diff --git a/osx/src/main/java/ch/cyberduck/ui/cocoa/ApplicationUserDefaultsPreferences.java b/osx/src/main/java/ch/cyberduck/ui/cocoa/ApplicationUserDefaultsPreferences.java index bbac4a1fc1c..311746e7144 100644 --- a/osx/src/main/java/ch/cyberduck/ui/cocoa/ApplicationUserDefaultsPreferences.java +++ b/osx/src/main/java/ch/cyberduck/ui/cocoa/ApplicationUserDefaultsPreferences.java @@ -19,7 +19,7 @@ */ import ch.cyberduck.core.bonjour.RendezvousResponder; -import ch.cyberduck.core.cryptomator.CryptoVault; +import ch.cyberduck.core.cryptomator.CryptoVaultProvider; import ch.cyberduck.core.cryptomator.random.FastSecureRandomProvider; import ch.cyberduck.core.local.FinderLocal; import ch.cyberduck.core.preferences.ApplicationPreferences; @@ -104,7 +104,7 @@ protected void setFactories() { this.setDefault("factory.transferpromptcallback.copy.class", CopyPromptController.class.getName()); this.setDefault("factory.transferpromptcallback.sync.class", SyncPromptController.class.getName()); this.setDefault("factory.rendezvous.class", RendezvousResponder.class.getName()); - this.setDefault("factory.vault.class", CryptoVault.class.getName()); + this.setDefault("factory.vault.class", CryptoVaultProvider.class.getName()); this.setDefault("factory.securerandom.class", FastSecureRandomProvider.class.getName()); } } diff --git a/osx/src/main/java/ch/cyberduck/ui/cocoa/controller/BrowserController.java b/osx/src/main/java/ch/cyberduck/ui/cocoa/controller/BrowserController.java index 5c479548bcb..f47ff2724a2 100644 --- a/osx/src/main/java/ch/cyberduck/ui/cocoa/controller/BrowserController.java +++ b/osx/src/main/java/ch/cyberduck/ui/cocoa/controller/BrowserController.java @@ -64,7 +64,6 @@ import ch.cyberduck.core.pasteboard.PathPasteboard; import ch.cyberduck.core.pasteboard.PathPasteboardFactory; import ch.cyberduck.core.pool.SessionPool; -import ch.cyberduck.core.preferences.HostPreferencesFactory; import ch.cyberduck.core.preferences.Preferences; import ch.cyberduck.core.preferences.PreferencesFactory; import ch.cyberduck.core.resources.IconCacheFactory; @@ -88,7 +87,7 @@ import ch.cyberduck.core.transfer.UploadTransfer; import ch.cyberduck.core.vault.LoadingVaultLookupListener; import ch.cyberduck.core.vault.VaultCredentials; -import ch.cyberduck.core.vault.VaultFactory; +import ch.cyberduck.core.vault.VaultMetadata; import ch.cyberduck.core.vault.VaultRegistry; import ch.cyberduck.core.worker.CopyWorker; import ch.cyberduck.core.worker.CreateDirectoryWorker; @@ -142,7 +141,6 @@ import org.rococoa.cocoa.foundation.NSSize; import org.rococoa.cocoa.foundation.NSUInteger; -import java.nio.charset.StandardCharsets; import java.security.cert.CertificateException; import java.security.cert.X509Certificate; import java.text.MessageFormat; @@ -2432,12 +2430,10 @@ public void createEncryptedVaultButtonClicked(final ID sender) { @Override public void callback(final Path folder, final String region, final VaultCredentials passphrase) { background(new WorkerBackgroundAction<>(BrowserController.this, pool, - new CreateVaultWorker(region, passphrase, VaultFactory.get(folder, - HostPreferencesFactory.get(pool.getHost()).getProperty("cryptomator.vault.masterkey.filename"), - HostPreferencesFactory.get(pool.getHost()).getProperty("cryptomator.vault.config.filename"), - HostPreferencesFactory.get(pool.getHost()).getProperty("cryptomator.vault.pepper").getBytes(StandardCharsets.UTF_8))) { + new CreateVaultWorker(region, passphrase, + new VaultMetadata(folder, VaultMetadata.Type.valueOf(preferences.getProperty("cryptomator.vault.default")))) { @Override - public void cleanup(final Path vault) { + public void cleanup(final Vault vault) { reload(BrowserController.this.workdir, Collections.singletonList(folder), Collections.singletonList(folder)); } }) @@ -2450,9 +2446,9 @@ public void cleanup(final Path vault) { @Action public void lockUnlockEncryptedVaultButtonClicked(final ID sender) { final Path directory = new UploadTargetFinder(workdir).find(this.getSelectedPath()); - if(directory.attributes().getVault() != null) { + if(directory.attributes().getVaultMetadata() != null) { // Lock and remove all open vaults - this.background(new WorkerBackgroundAction<>(this, pool, new LockVaultWorker(pool.getVaultRegistry(), directory.attributes().getVault()) { + this.background(new WorkerBackgroundAction<>(this, pool, new LockVaultWorker(pool.getVaultRegistry(), directory.attributes().getVaultMetadata().root) { @Override public void cleanup(final Path vault) { if(vault != null) { @@ -2464,7 +2460,8 @@ public void cleanup(final Path vault) { else { // Unlock vault this.background(new WorkerBackgroundAction<>(this, pool, new LoadVaultWorker(new LoadingVaultLookupListener(pool.getVaultRegistry(), - PasswordCallbackFactory.get(this)), directory) { + PasswordCallbackFactory.get(this)), + new VaultMetadata(directory, VaultMetadata.Type.valueOf(preferences.getProperty("cryptomator.vault.default")))) { @Override public void cleanup(final Vault vault) { if(vault != null) { diff --git a/osx/src/main/java/ch/cyberduck/ui/cocoa/toolbar/BrowserToolbarValidator.java b/osx/src/main/java/ch/cyberduck/ui/cocoa/toolbar/BrowserToolbarValidator.java index 4b1e73af4c3..b0a71df8f03 100644 --- a/osx/src/main/java/ch/cyberduck/ui/cocoa/toolbar/BrowserToolbarValidator.java +++ b/osx/src/main/java/ch/cyberduck/ui/cocoa/toolbar/BrowserToolbarValidator.java @@ -241,7 +241,7 @@ else if(action.equals(newfolder.action())) { } else if(action.equals(Foundation.selector("createEncryptedVaultButtonClicked:"))) { return this.isBrowser() && controller.isMounted() && controller.getSession().getVaultRegistry() != VaultRegistry.DISABLED && - null == controller.workdir().attributes().getVault() && + null == controller.workdir().attributes().getVaultMetadata() && controller.getSession().getFeature(Directory.class).isSupported( new UploadTargetFinder(controller.workdir()).find(controller.getSelectedPath()), StringUtils.EMPTY ); diff --git a/owncloud/src/test/java/ch/cyberduck/core/cryptomator/OcisUploadFeatureTest.java b/owncloud/src/test/java/ch/cyberduck/core/cryptomator/OcisUploadFeatureTest.java index 8d697d3e176..b8d8139ca90 100644 --- a/owncloud/src/test/java/ch/cyberduck/core/cryptomator/OcisUploadFeatureTest.java +++ b/owncloud/src/test/java/ch/cyberduck/core/cryptomator/OcisUploadFeatureTest.java @@ -46,6 +46,7 @@ import ch.cyberduck.core.tus.TusWriteFeature; import ch.cyberduck.core.vault.DefaultVaultRegistry; import ch.cyberduck.core.vault.VaultCredentials; +import ch.cyberduck.core.vault.VaultMetadata; import ch.cyberduck.test.IntegrationTest; import org.apache.commons.io.IOUtils; @@ -75,9 +76,9 @@ public void testUploadVault() throws Exception { // 5L * 1024L * 1024L final Path directory = new DAVDirectoryFeature(session).mkdir(new NextcloudWriteFeature(session), new Path(new OwncloudHomeFeature(session.getHost()).find(), new AlphanumericRandomStringService().random(), EnumSet.of(AbstractPath.Type.directory)), new TransferStatus()); - final CryptoVault cryptomator = new CryptoVault( - new Path(directory, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory))); - final Path vault = cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final Path vault = new Path(directory, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); session.withRegistry(new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator)); final TusCapabilities capabilities = new TusCapabilities().withHashAlgorithm(HashAlgorithm.sha1); final CryptoUploadFeature service = new CryptoUploadFeature<>(session, diff --git a/owncloud/src/test/java/ch/cyberduck/core/owncloud/AbstractOcisTest.java b/owncloud/src/test/java/ch/cyberduck/core/owncloud/AbstractOcisTest.java index a585766e9a9..7de91c8efd3 100644 --- a/owncloud/src/test/java/ch/cyberduck/core/owncloud/AbstractOcisTest.java +++ b/owncloud/src/test/java/ch/cyberduck/core/owncloud/AbstractOcisTest.java @@ -27,10 +27,10 @@ import ch.cyberduck.core.Profile; import ch.cyberduck.core.ProtocolFactory; import ch.cyberduck.core.Scheme; -import ch.cyberduck.core.cryptomator.CryptoVault; import ch.cyberduck.core.serializer.impl.dd.ProfilePlistReader; import ch.cyberduck.core.ssl.DefaultX509KeyManager; import ch.cyberduck.core.ssl.DefaultX509TrustManager; +import ch.cyberduck.core.vault.VaultMetadata; import ch.cyberduck.test.VaultTest; import org.junit.After; @@ -48,11 +48,11 @@ public class AbstractOcisTest extends VaultTest { @Parameterized.Parameters(name = "vaultVersion = {0}") public static Object[] data() { - return new Object[]{CryptoVault.VAULT_VERSION_DEPRECATED, CryptoVault.VAULT_VERSION}; + return new Object[]{VaultMetadata.Type.V8, VaultMetadata.Type.UVF}; } @Parameterized.Parameter - public int vaultVersion; + public VaultMetadata.Type vaultVersion; @After public void disconnect() throws Exception { diff --git a/s3/src/test/java/ch/cyberduck/core/cryptomator/CopyWorkerTest.java b/s3/src/test/java/ch/cyberduck/core/cryptomator/CopyWorkerTest.java index ec59a84f522..1e5d59186af 100644 --- a/s3/src/test/java/ch/cyberduck/core/cryptomator/CopyWorkerTest.java +++ b/s3/src/test/java/ch/cyberduck/core/cryptomator/CopyWorkerTest.java @@ -46,12 +46,14 @@ import ch.cyberduck.core.transfer.TransferStatus; import ch.cyberduck.core.vault.DefaultVaultRegistry; import ch.cyberduck.core.vault.VaultCredentials; +import ch.cyberduck.core.vault.VaultMetadata; import ch.cyberduck.core.worker.CopyWorker; import ch.cyberduck.core.worker.DeleteWorker; import ch.cyberduck.test.IntegrationTest; import org.apache.commons.io.IOUtils; import org.apache.commons.lang3.RandomUtils; +import org.junit.Ignore; import org.junit.Test; import org.junit.experimental.categories.Category; import org.junit.runner.RunWith; @@ -64,7 +66,6 @@ import java.util.EnumSet; import static org.junit.Assert.*; -import static org.junit.Assume.assumeTrue; @Category(IntegrationTest.class) @RunWith(value = Parameterized.class) @@ -76,8 +77,8 @@ public void testCopyFile() throws Exception { final Path vault = new Path(home, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); final Path source = new Path(vault, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.file)); final Path target = new Path(vault, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.file)); - final CryptoVault cryptomator = new CryptoVault(vault); - cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); final DefaultVaultRegistry registry = new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator); session.withRegistry(registry); final byte[] content = RandomUtils.nextBytes(40500); @@ -103,8 +104,8 @@ public void testCopyToDifferentFolderCryptomator() throws Exception { final Path source = new Path(vault, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.file)); final Path targetFolder = new Path(vault, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); final Path target = new Path(targetFolder, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.file)); - final CryptoVault cryptomator = new CryptoVault(vault); - cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); final DefaultVaultRegistry registry = new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator); session.withRegistry(registry); final S3AccessControlListFeature acl = new S3AccessControlListFeature(session); @@ -123,11 +124,12 @@ public void testCopyToDifferentFolderCryptomator() throws Exception { } @Test + @Ignore("Filename shortening not implemented yet") public void testCopyToDifferentFolderLongFilenameCryptomator() throws Exception { - assumeTrue(vaultVersion == CryptoVault.VAULT_VERSION_DEPRECATED); final Path home = new Path("test-eu-central-1-cyberduck", EnumSet.of(Path.Type.directory, Path.Type.volume)); - final CryptoVault cryptomator = new CryptoVault(new Path(home, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory))); - final Path vault = cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final Path vault = new Path(home, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); final Path source = new Path(vault, new AlphanumericRandomStringService(130).random(), EnumSet.of(Path.Type.file)); final Path targetFolder = new Path(vault, new AlphanumericRandomStringService(130).random(), EnumSet.of(Path.Type.directory)); final Path target = new Path(targetFolder, new AlphanumericRandomStringService(130).random(), EnumSet.of(Path.Type.file)); @@ -151,8 +153,9 @@ public void testCopyToDifferentFolderLongFilenameCryptomator() throws Exception @Test public void testCopyFolder() throws Exception { final Path home = new Path("test-eu-central-1-cyberduck", EnumSet.of(Path.Type.directory, Path.Type.volume)); - final CryptoVault cryptomator = new CryptoVault(new Path(home, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory))); - final Path vault = cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final Path vault = new Path(home, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); final Path folder = new Path(vault, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); final Path file = new Path(folder, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.file)); final DefaultVaultRegistry registry = new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator); @@ -191,8 +194,8 @@ public void testCopyFileIntoVault() throws Exception { assertTrue(new S3FindFeature(session, acl).find(cleartextFile)); final Path encryptedFolder = new Path(vault, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); final Path encryptedFile = new Path(encryptedFolder, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.file)); - final CryptoVault cryptomator = new CryptoVault(vault); - cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); final DefaultVaultRegistry registry = new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator); session.withRegistry(registry); cryptomator.getFeature(session, Directory.class, new S3DirectoryFeature(session, acl)).mkdir( @@ -221,8 +224,8 @@ public void testCopyDirectoryIntoVault() throws Exception { new S3TouchFeature(session, acl).touch(new S3WriteFeature(session, acl), cleartextFile, new TransferStatus()); assertTrue(new S3FindFeature(session, acl).find(cleartextFolder)); assertTrue(new S3FindFeature(session, acl).find(cleartextFile)); - final CryptoVault cryptomator = new CryptoVault(vault); - cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); final DefaultVaultRegistry registry = new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator); session.withRegistry(registry); // move directory into vault @@ -247,8 +250,8 @@ public void testCopyFileOutsideVault() throws Exception { new S3DirectoryFeature(session, acl).mkdir(new S3WriteFeature(session, acl), clearFolder, new TransferStatus()); final Path encryptedFolder = new Path(vault, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); final Path encryptedFile = new Path(encryptedFolder, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.file)); - final CryptoVault cryptomator = new CryptoVault(vault); - cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); final DefaultVaultRegistry registry = new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator); session.withRegistry(registry); cryptomator.getFeature(session, Directory.class, new S3DirectoryFeature(session, acl)).mkdir( @@ -273,8 +276,8 @@ public void testCopyDirectoryOutsideVault() throws Exception { final Path vault = new Path(home, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); final Path encryptedFolder = new Path(vault, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); final Path encryptedFile = new Path(encryptedFolder, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.file)); - final CryptoVault cryptomator = new CryptoVault(vault); - cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); final DefaultVaultRegistry registry = new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator); session.withRegistry(registry); final S3AccessControlListFeature acl = new S3AccessControlListFeature(session); diff --git a/s3/src/test/java/ch/cyberduck/core/cryptomator/CryptoS3SingleTransferWorkerTest.java b/s3/src/test/java/ch/cyberduck/core/cryptomator/CryptoS3SingleTransferWorkerTest.java index 76dc330b928..e19b7d0f1e6 100644 --- a/s3/src/test/java/ch/cyberduck/core/cryptomator/CryptoS3SingleTransferWorkerTest.java +++ b/s3/src/test/java/ch/cyberduck/core/cryptomator/CryptoS3SingleTransferWorkerTest.java @@ -50,6 +50,7 @@ import ch.cyberduck.core.transfer.UploadTransfer; import ch.cyberduck.core.vault.DefaultVaultRegistry; import ch.cyberduck.core.vault.VaultCredentials; +import ch.cyberduck.core.vault.VaultMetadata; import ch.cyberduck.core.worker.SingleTransferWorker; import ch.cyberduck.test.IntegrationTest; @@ -91,8 +92,8 @@ public void testUpload() throws Exception { final OutputStream out2 = localFile2.getOutputStream(false); IOUtils.write(content, out2); out2.close(); - final CryptoVault cryptomator = new CryptoVault(vault); - cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); session.withRegistry(new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator)); final Transfer t = new UploadTransfer(new Host(new TestProtocol()), Collections.singletonList(new TransferItem(dir1, localDirectory1)), new NullFilter<>()); assertTrue(new SingleTransferWorker(session, session, t, new TransferOptions(), new TransferSpeedometer(t), new DisabledTransferPrompt() { diff --git a/s3/src/test/java/ch/cyberduck/core/cryptomator/MoveWorkerTest.java b/s3/src/test/java/ch/cyberduck/core/cryptomator/MoveWorkerTest.java index 7f1010f3417..6fbae9cd21a 100644 --- a/s3/src/test/java/ch/cyberduck/core/cryptomator/MoveWorkerTest.java +++ b/s3/src/test/java/ch/cyberduck/core/cryptomator/MoveWorkerTest.java @@ -52,11 +52,13 @@ import ch.cyberduck.core.transfer.TransferStatus; import ch.cyberduck.core.vault.DefaultVaultRegistry; import ch.cyberduck.core.vault.VaultCredentials; +import ch.cyberduck.core.vault.VaultMetadata; import ch.cyberduck.core.worker.MoveWorker; import ch.cyberduck.test.IntegrationTest; import org.apache.commons.io.IOUtils; import org.apache.commons.lang3.RandomUtils; +import org.junit.Ignore; import org.junit.Test; import org.junit.experimental.categories.Category; import org.junit.runner.RunWith; @@ -70,7 +72,6 @@ import java.util.UUID; import static org.junit.Assert.*; -import static org.junit.Assume.assumeTrue; @Category(IntegrationTest.class) @RunWith(value = Parameterized.class) @@ -82,8 +83,8 @@ public void testMoveSameFolderCryptomator() throws Exception { final Path vault = new Path(home, UUID.randomUUID().toString(), EnumSet.of(Path.Type.directory)); final Path source = new Path(vault, UUID.randomUUID().toString(), EnumSet.of(Path.Type.file)); final Path target = new Path(vault, UUID.randomUUID().toString(), EnumSet.of(Path.Type.file)); - final CryptoVault cryptomator = new CryptoVault(vault); - cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); session.withRegistry(new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator)); final byte[] content = RandomUtils.nextBytes(40500); final TransferStatus status = new TransferStatus(); @@ -106,8 +107,8 @@ public void testMoveToDifferentFolderCryptomator() throws Exception { final Path home = new Path("test-eu-central-1-cyberduck", EnumSet.of(Path.Type.directory, Path.Type.volume)); final Path vault = new Path(home, UUID.randomUUID().toString(), EnumSet.of(Path.Type.directory)); final Path source = new Path(vault, UUID.randomUUID().toString(), EnumSet.of(Path.Type.file)); - final CryptoVault cryptomator = new CryptoVault(vault); - cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); session.withRegistry(new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator)); final S3AccessControlListFeature acl = new S3AccessControlListFeature(session); new CryptoTouchFeature<>(session, new S3TouchFeature(session, acl), cryptomator).touch( @@ -125,13 +126,13 @@ public void testMoveToDifferentFolderCryptomator() throws Exception { } @Test + @Ignore("Filename shortening not implemented yet") public void testMoveToDifferentFolderLongFilenameCryptomator() throws Exception { - assumeTrue(vaultVersion == CryptoVault.VAULT_VERSION_DEPRECATED); final Path home = new Path("test-eu-central-1-cyberduck", EnumSet.of(Path.Type.directory, Path.Type.volume)); final Path vault = new Path(home, UUID.randomUUID().toString(), EnumSet.of(Path.Type.directory)); final Path source = new Path(vault, new AlphanumericRandomStringService(130).random(), EnumSet.of(Path.Type.file)); - final CryptoVault cryptomator = new CryptoVault(vault); - cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); session.withRegistry(new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator)); final S3AccessControlListFeature acl = new S3AccessControlListFeature(session); new CryptoTouchFeature<>(session, new S3TouchFeature(session, acl), cryptomator).touch( @@ -152,8 +153,8 @@ public void testMoveToDifferentFolderLongFilenameCryptomator() throws Exception public void testMoveFolder() throws Exception { final Path home = new Path("test-eu-central-1-cyberduck", EnumSet.of(Path.Type.directory, Path.Type.volume)); final Path vault = new Path(home, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); - final CryptoVault cryptomator = new CryptoVault(vault); - cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); session.withRegistry(new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator)); final S3AccessControlListFeature acl = new S3AccessControlListFeature(session); final Path folder = cryptomator.getFeature(session, Directory.class, new S3DirectoryFeature(session, acl)).mkdir( @@ -193,8 +194,8 @@ public void testMoveFileIntoVault() throws Exception { final S3AccessControlListFeature acl = new S3AccessControlListFeature(session); new S3TouchFeature(session, acl).touch(new S3WriteFeature(session, new S3AccessControlListFeature(session)), clearFile, new TransferStatus()); assertTrue(new S3FindFeature(session, acl).find(clearFile)); - final CryptoVault cryptomator = new CryptoVault(vault); - cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); final DefaultVaultRegistry registry = new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator); session.withRegistry(registry); final Path encryptedFolder = cryptomator.getFeature(session, Directory.class, new S3DirectoryFeature(session, acl)).mkdir( @@ -220,8 +221,8 @@ public void testMoveDirectoryIntoVault() throws Exception { new S3TouchFeature(session, acl).touch(new S3WriteFeature(session, new S3AccessControlListFeature(session)), clearFile, new TransferStatus()); assertTrue(new S3FindFeature(session, acl).find(clearFolder)); assertTrue(new S3FindFeature(session, acl).find(clearFile)); - final CryptoVault cryptomator = new CryptoVault(vault); - cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); final DefaultVaultRegistry registry = new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator); session.withRegistry(registry); // move directory into vault @@ -244,8 +245,8 @@ public void testMoveFileOutsideVault() throws Exception { final S3AccessControlListFeature acl = new S3AccessControlListFeature(session); final Path clearFolder = new S3DirectoryFeature(session, acl).mkdir( new S3WriteFeature(session, acl), new Path(home, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)), new TransferStatus()); - final CryptoVault cryptomator = new CryptoVault(vault); - cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); final DefaultVaultRegistry registry = new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator); session.withRegistry(registry); final Path encryptedFolder = cryptomator.getFeature(session, Directory.class, new S3DirectoryFeature(session, acl)).mkdir( @@ -270,8 +271,8 @@ public void testMoveFileOutsideVault() throws Exception { public void testMoveDirectoryOutsideVault() throws Exception { final Path home = new Path("test-eu-central-1-cyberduck", EnumSet.of(Path.Type.directory, Path.Type.volume)); final Path vault = new Path(home, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); - final CryptoVault cryptomator = new CryptoVault(vault); - cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); final DefaultVaultRegistry registry = new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator); session.withRegistry(registry); final S3AccessControlListFeature acl = new S3AccessControlListFeature(session); diff --git a/s3/src/test/java/ch/cyberduck/core/cryptomator/S3DirectoryFeatureTest.java b/s3/src/test/java/ch/cyberduck/core/cryptomator/S3DirectoryFeatureTest.java index 0a39e12db47..47dca475d8a 100644 --- a/s3/src/test/java/ch/cyberduck/core/cryptomator/S3DirectoryFeatureTest.java +++ b/s3/src/test/java/ch/cyberduck/core/cryptomator/S3DirectoryFeatureTest.java @@ -38,8 +38,10 @@ import ch.cyberduck.core.transfer.TransferStatus; import ch.cyberduck.core.vault.DefaultVaultRegistry; import ch.cyberduck.core.vault.VaultCredentials; +import ch.cyberduck.core.vault.VaultMetadata; import ch.cyberduck.test.IntegrationTest; +import org.junit.Ignore; import org.junit.Test; import org.junit.experimental.categories.Category; import org.junit.runner.RunWith; @@ -51,7 +53,6 @@ import java.util.stream.Collectors; import static org.junit.Assert.*; -import static org.junit.Assume.assumeTrue; @Category(IntegrationTest.class) @RunWith(value = Parameterized.class) @@ -61,8 +62,8 @@ public class S3DirectoryFeatureTest extends AbstractS3Test { public void testMakeDirectoryEncrypted() throws Exception { final Path home = new Path("versioning-test-eu-central-1-cyberduck", EnumSet.of(Path.Type.directory, Path.Type.volume)); final Path vault = new Path(home, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); - final CryptoVault cryptomator = new CryptoVault(vault); - cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); session.withRegistry(new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator)); final S3AccessControlListFeature acl = new S3AccessControlListFeature(session); final Path test = cryptomator.getFeature(session, Directory.class, new S3DirectoryFeature(session, acl)).mkdir( @@ -79,12 +80,12 @@ public void testMakeDirectoryEncrypted() throws Exception { } @Test + @Ignore("Filename shortening not implemented yet") public void testMakeDirectoryLongFilenameEncrypted() throws Exception { - assumeTrue(vaultVersion == CryptoVault.VAULT_VERSION_DEPRECATED); final Path home = new Path("test-eu-central-1-cyberduck", EnumSet.of(Path.Type.directory, Path.Type.volume)); final Path vault = new Path(home, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); - final CryptoVault cryptomator = new CryptoVault(vault); - cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); session.withRegistry(new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator)); final S3AccessControlListFeature acl = new S3AccessControlListFeature(session); final Path test = cryptomator.getFeature(session, Directory.class, new S3DirectoryFeature(session, acl)).mkdir( diff --git a/s3/src/test/java/ch/cyberduck/core/cryptomator/S3MoveFeatureTest.java b/s3/src/test/java/ch/cyberduck/core/cryptomator/S3MoveFeatureTest.java index 7d3a0a6bd8e..1949acfa711 100644 --- a/s3/src/test/java/ch/cyberduck/core/cryptomator/S3MoveFeatureTest.java +++ b/s3/src/test/java/ch/cyberduck/core/cryptomator/S3MoveFeatureTest.java @@ -38,6 +38,7 @@ import ch.cyberduck.core.transfer.TransferStatus; import ch.cyberduck.core.vault.DefaultVaultRegistry; import ch.cyberduck.core.vault.VaultCredentials; +import ch.cyberduck.core.vault.VaultMetadata; import ch.cyberduck.test.IntegrationTest; import org.junit.Test; @@ -61,8 +62,8 @@ public void testMove() throws Exception { final Path vault = new Path(home, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); final Path folder = new Path(vault, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); final Path file = new Path(folder, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.file)); - final CryptoVault cryptomator = new CryptoVault(vault); - cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); session.withRegistry(new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator)); final S3AccessControlListFeature acl = new S3AccessControlListFeature(session); cryptomator.getFeature(session, Directory.class, new S3DirectoryFeature(session, acl)).mkdir( diff --git a/s3/src/test/java/ch/cyberduck/core/cryptomator/S3MultipartUploadServiceTest.java b/s3/src/test/java/ch/cyberduck/core/cryptomator/S3MultipartUploadServiceTest.java index c53c19e2b46..6ba72e2526e 100644 --- a/s3/src/test/java/ch/cyberduck/core/cryptomator/S3MultipartUploadServiceTest.java +++ b/s3/src/test/java/ch/cyberduck/core/cryptomator/S3MultipartUploadServiceTest.java @@ -47,6 +47,7 @@ import ch.cyberduck.core.transfer.TransferStatus; import ch.cyberduck.core.vault.DefaultVaultRegistry; import ch.cyberduck.core.vault.VaultCredentials; +import ch.cyberduck.core.vault.VaultMetadata; import ch.cyberduck.test.IntegrationTest; import org.apache.commons.io.IOUtils; @@ -78,8 +79,8 @@ public void testUploadSinglePart() throws Exception { final Path home = new Path("test-eu-central-1-cyberduck", EnumSet.of(Path.Type.volume, Path.Type.directory)); final Path vault = new Path(home, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); final Path test = new Path(vault, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.file)); - final CryptoVault cryptomator = new CryptoVault(vault); - cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); session.withRegistry(new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator)); final S3AccessControlListFeature acl = new S3AccessControlListFeature(session); final CryptoUploadFeature m = new CryptoUploadFeature<>(session, @@ -114,8 +115,8 @@ public void testUpload() throws Exception { final Path home = new Path("test-eu-central-1-cyberduck", EnumSet.of(Path.Type.volume, Path.Type.directory)); final Path vault = new Path(home, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); final Path test = new Path(vault, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.file)); - final CryptoVault cryptomator = new CryptoVault(vault); - cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); session.withRegistry(new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator)); final S3AccessControlListFeature acl = new S3AccessControlListFeature(session); final CryptoUploadFeature m = new CryptoUploadFeature<>(session, @@ -147,8 +148,8 @@ public void testUploadWithBulk() throws Exception { final Path home = new Path("test-eu-central-1-cyberduck", EnumSet.of(Path.Type.volume, Path.Type.directory)); final Path vault = new Path(home, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); final Path test = new Path(vault, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.file)); - final CryptoVault cryptomator = new CryptoVault(vault); - cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); session.withRegistry(new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator)); final TransferStatus writeStatus = new TransferStatus(); final byte[] content = RandomUtils.nextBytes(6 * 1024 * 1024); diff --git a/s3/src/test/java/ch/cyberduck/core/cryptomator/S3MultipartWriteFeatureTest.java b/s3/src/test/java/ch/cyberduck/core/cryptomator/S3MultipartWriteFeatureTest.java index e2429a530ed..04b2bef6aec 100644 --- a/s3/src/test/java/ch/cyberduck/core/cryptomator/S3MultipartWriteFeatureTest.java +++ b/s3/src/test/java/ch/cyberduck/core/cryptomator/S3MultipartWriteFeatureTest.java @@ -37,6 +37,7 @@ import ch.cyberduck.core.transfer.TransferStatus; import ch.cyberduck.core.vault.DefaultVaultRegistry; import ch.cyberduck.core.vault.VaultCredentials; +import ch.cyberduck.core.vault.VaultMetadata; import ch.cyberduck.test.IntegrationTest; import org.apache.commons.io.IOUtils; @@ -63,8 +64,8 @@ public void testWrite() throws Exception { final Path home = new Path("test-eu-central-1-cyberduck", EnumSet.of(Path.Type.volume, Path.Type.directory)); final Path vault = new Path(home, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); final Path test = new Path(vault, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.file)); - final CryptoVault cryptomator = new CryptoVault(vault); - cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); session.withRegistry(new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator)); final S3AccessControlListFeature acl = new S3AccessControlListFeature(session); final CryptoWriteFeature feature = new CryptoWriteFeature<>(session, new S3MultipartWriteFeature(session, acl), cryptomator); diff --git a/s3/src/test/java/ch/cyberduck/core/cryptomator/S3ObjectListServiceTest.java b/s3/src/test/java/ch/cyberduck/core/cryptomator/S3ObjectListServiceTest.java index 9ab29fa168f..d327f99d877 100644 --- a/s3/src/test/java/ch/cyberduck/core/cryptomator/S3ObjectListServiceTest.java +++ b/s3/src/test/java/ch/cyberduck/core/cryptomator/S3ObjectListServiceTest.java @@ -33,6 +33,7 @@ import ch.cyberduck.core.transfer.TransferStatus; import ch.cyberduck.core.vault.DefaultVaultRegistry; import ch.cyberduck.core.vault.VaultCredentials; +import ch.cyberduck.core.vault.VaultMetadata; import ch.cyberduck.test.IntegrationTest; import org.junit.Test; @@ -55,8 +56,8 @@ public void testListCryptomator() throws Exception { final Path home = new Path("test-eu-central-1-cyberduck", EnumSet.of(Path.Type.directory, Path.Type.volume)); final Path vault = new Path(home, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); final Path test = new Path(vault, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.file)); - final CryptoVault cryptomator = new CryptoVault(vault); - cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); session.withRegistry(new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator)); final S3AccessControlListFeature acl = new S3AccessControlListFeature(session); assertTrue(new CryptoListService(session, new S3ObjectListService(session, acl), cryptomator).list(vault, new DisabledListProgressListener()).isEmpty()); diff --git a/s3/src/test/java/ch/cyberduck/core/cryptomator/S3SingleUploadServiceTest.java b/s3/src/test/java/ch/cyberduck/core/cryptomator/S3SingleUploadServiceTest.java index 9a5395beac7..aa5098b29d8 100644 --- a/s3/src/test/java/ch/cyberduck/core/cryptomator/S3SingleUploadServiceTest.java +++ b/s3/src/test/java/ch/cyberduck/core/cryptomator/S3SingleUploadServiceTest.java @@ -42,6 +42,7 @@ import ch.cyberduck.core.transfer.TransferStatus; import ch.cyberduck.core.vault.DefaultVaultRegistry; import ch.cyberduck.core.vault.VaultCredentials; +import ch.cyberduck.core.vault.VaultMetadata; import ch.cyberduck.test.IntegrationTest; import org.apache.commons.io.IOUtils; @@ -70,8 +71,8 @@ public void testUploadVault() throws Exception { final Path home = new Path("test-eu-central-1-cyberduck", EnumSet.of(Path.Type.volume, Path.Type.directory)); final Path vault = new Path(home, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); final Path test = new Path(vault, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.file)); - final CryptoVault cryptomator = new CryptoVault(vault); - cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); session.withRegistry(new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator)); final Local local = new Local(System.getProperty("java.io.tmpdir"), UUID.randomUUID().toString()); final int length = 5242880; diff --git a/s3/src/test/java/ch/cyberduck/core/cryptomator/S3TouchFeatureTest.java b/s3/src/test/java/ch/cyberduck/core/cryptomator/S3TouchFeatureTest.java index 6ff42ecdb32..beec3ffc61f 100644 --- a/s3/src/test/java/ch/cyberduck/core/cryptomator/S3TouchFeatureTest.java +++ b/s3/src/test/java/ch/cyberduck/core/cryptomator/S3TouchFeatureTest.java @@ -36,6 +36,7 @@ import ch.cyberduck.core.transfer.TransferStatus; import ch.cyberduck.core.vault.DefaultVaultRegistry; import ch.cyberduck.core.vault.VaultCredentials; +import ch.cyberduck.core.vault.VaultMetadata; import ch.cyberduck.test.IntegrationTest; import org.jets3t.service.model.StorageObject; @@ -50,7 +51,6 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; -import static org.junit.Assume.assumeTrue; @Category(IntegrationTest.class) @RunWith(value = Parameterized.class) @@ -60,8 +60,8 @@ public class S3TouchFeatureTest extends AbstractS3Test { public void testTouchEncrypted() throws Exception { final Path home = new Path("test-eu-central-1-cyberduck", EnumSet.of(Path.Type.directory, Path.Type.volume)); final Path vault = new Path(home, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); - final CryptoVault cryptomator = new CryptoVault(vault); - cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); session.withRegistry(new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator)); final TransferStatus status = new TransferStatus(); final S3AccessControlListFeature acl = new S3AccessControlListFeature(session); @@ -75,12 +75,12 @@ public void testTouchEncrypted() throws Exception { } @Test + @Ignore("Filename shortening not implemented yet") public void testTouchLongFilenameEncrypted() throws Exception { - assumeTrue(vaultVersion == CryptoVault.VAULT_VERSION_DEPRECATED); final Path home = new Path("test-eu-central-1-cyberduck", EnumSet.of(Path.Type.directory, Path.Type.volume)); final Path vault = new Path(home, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); - final CryptoVault cryptomator = new CryptoVault(vault); - cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); session.withRegistry(new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator)); final TransferStatus status = new TransferStatus(); final S3AccessControlListFeature acl = new S3AccessControlListFeature(session); @@ -97,8 +97,8 @@ public void testTouchLongFilenameEncrypted() throws Exception { public void testTouchEncryptedDefaultFeature() throws Exception { final Path home = new Path("test-eu-central-1-cyberduck", EnumSet.of(Path.Type.directory, Path.Type.volume)); final Path vault = new Path(home, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); - final CryptoVault cryptomator = new CryptoVault(vault); - cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); session.withRegistry(new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator)); final TransferStatus status = new TransferStatus(); final S3AccessControlListFeature acl = new S3AccessControlListFeature(session); diff --git a/s3/src/test/java/ch/cyberduck/core/cryptomator/S3VersioningFeatureTest.java b/s3/src/test/java/ch/cyberduck/core/cryptomator/S3VersioningFeatureTest.java index 1b41ddf177c..099db4e9e75 100644 --- a/s3/src/test/java/ch/cyberduck/core/cryptomator/S3VersioningFeatureTest.java +++ b/s3/src/test/java/ch/cyberduck/core/cryptomator/S3VersioningFeatureTest.java @@ -47,6 +47,7 @@ import ch.cyberduck.core.transfer.TransferStatus; import ch.cyberduck.core.vault.DefaultVaultRegistry; import ch.cyberduck.core.vault.VaultCredentials; +import ch.cyberduck.core.vault.VaultMetadata; import ch.cyberduck.test.IntegrationTest; import org.apache.commons.lang3.RandomUtils; @@ -71,8 +72,8 @@ public class S3VersioningFeatureTest extends AbstractS3Test { public void testRevert() throws Exception { final Path bucket = new Path("versioning-test-eu-central-1-cyberduck", EnumSet.of(Path.Type.directory, Path.Type.volume)); final Path vault = new Path(bucket, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); - final CryptoVault cryptomator = new CryptoVault(vault); - cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); session.withRegistry(new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator)); final S3AccessControlListFeature acl = new S3AccessControlListFeature(session); final AttributesFinder f = cryptomator.getFeature(session, AttributesFinder.class, new S3AttributesFinderFeature(session, acl)); diff --git a/s3/src/test/java/ch/cyberduck/core/cryptomator/S3WriteFeatureTest.java b/s3/src/test/java/ch/cyberduck/core/cryptomator/S3WriteFeatureTest.java index 7a0cdb56a5e..9ef6f1d54dc 100644 --- a/s3/src/test/java/ch/cyberduck/core/cryptomator/S3WriteFeatureTest.java +++ b/s3/src/test/java/ch/cyberduck/core/cryptomator/S3WriteFeatureTest.java @@ -38,6 +38,7 @@ import ch.cyberduck.core.transfer.TransferStatus; import ch.cyberduck.core.vault.DefaultVaultRegistry; import ch.cyberduck.core.vault.VaultCredentials; +import ch.cyberduck.core.vault.VaultMetadata; import ch.cyberduck.test.IntegrationTest; import org.apache.commons.lang3.RandomUtils; @@ -70,8 +71,8 @@ public void testWrite() throws Exception { final Path home = new Path("test-eu-central-1-cyberduck", EnumSet.of(Path.Type.volume, Path.Type.directory)); final Path vault = new Path(home, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); final Path test = new Path(vault, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.file)); - final CryptoVault cryptomator = new CryptoVault(vault); - cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); session.withRegistry(new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator)); final S3AccessControlListFeature acl = new S3AccessControlListFeature(session); final CryptoWriteFeature writer = new CryptoWriteFeature<>(session, new S3WriteFeature(session, acl), cryptomator); diff --git a/s3/src/test/java/ch/cyberduck/core/cryptomator/UVFIntegrationTest.java b/s3/src/test/java/ch/cyberduck/core/cryptomator/UVFIntegrationTest.java index 89b14e95921..58cd2dec3a6 100644 --- a/s3/src/test/java/ch/cyberduck/core/cryptomator/UVFIntegrationTest.java +++ b/s3/src/test/java/ch/cyberduck/core/cryptomator/UVFIntegrationTest.java @@ -16,6 +16,7 @@ */ import ch.cyberduck.core.*; +import ch.cyberduck.core.cryptomator.impl.uvf.CryptoVault; import ch.cyberduck.core.exception.BackgroundException; import ch.cyberduck.core.features.AttributesFinder; import ch.cyberduck.core.features.Bulk; @@ -65,7 +66,7 @@ import static org.junit.Assert.*; /** - * Test {@link UVFVault} implementation against test data from + * Test {@link CryptoVault} implementation against test data from * org.cryptomator.cryptolib.v3.UVFIntegrationTest */ @Category(TestcontainerTest.class) @@ -135,7 +136,7 @@ public void listMinio() throws BackgroundException, IOException { final VaultRegistry vaults = new DefaultVaultRegistry(new DisabledPasswordCallback()); bookmark.setDefaultPath("/" + bucketName); - final UVFVault vault = new UVFVault(new DefaultPathHomeFeature(bookmark).find()); + final CryptoVault vault = new CryptoVault(new DefaultPathHomeFeature(bookmark).find()); vaults.add(vault.load(storage, new DisabledPasswordCallback() { @Override public Credentials prompt(final Host bookmark, final String title, final String reason, final LoginOptions options) { @@ -145,7 +146,7 @@ public Credentials prompt(final Host bookmark, final String title, final String final PathAttributes attr = storage.getFeature(AttributesFinder.class).find(vault.getHome()); storage.withRegistry(vaults); try(final UVFMasterkey masterKey = UVFMasterkey.fromDecryptedPayload(jwe)) { - assertArrayEquals(masterKey.rootDirId(), vault.getRootDirId()); + assertArrayEquals(masterKey.rootDirId(), vault.getMasterkey().rootDirId()); } final Path home = vault.getHome().withAttributes(attr).withType(EnumSet.of(AbstractPath.Type.directory, AbstractPath.Type.vault)); diff --git a/s3/src/test/java/ch/cyberduck/core/s3/AbstractS3Test.java b/s3/src/test/java/ch/cyberduck/core/s3/AbstractS3Test.java index 0a7ea787e4e..94801f37a04 100644 --- a/s3/src/test/java/ch/cyberduck/core/s3/AbstractS3Test.java +++ b/s3/src/test/java/ch/cyberduck/core/s3/AbstractS3Test.java @@ -26,10 +26,10 @@ import ch.cyberduck.core.LoginOptions; import ch.cyberduck.core.Profile; import ch.cyberduck.core.ProtocolFactory; -import ch.cyberduck.core.cryptomator.CryptoVault; import ch.cyberduck.core.serializer.impl.dd.ProfilePlistReader; import ch.cyberduck.core.ssl.DefaultX509KeyManager; import ch.cyberduck.core.ssl.DefaultX509TrustManager; +import ch.cyberduck.core.vault.VaultMetadata; import ch.cyberduck.test.VaultTest; import org.junit.After; @@ -57,11 +57,11 @@ public abstract class AbstractS3Test extends VaultTest { @Parameterized.Parameters(name = "vaultVersion = {0}") public static Object[] data() { - return new Object[]{CryptoVault.VAULT_VERSION_DEPRECATED, CryptoVault.VAULT_VERSION}; + return new Object[]{VaultMetadata.Type.V8, VaultMetadata.Type.UVF}; } @Parameterized.Parameter - public int vaultVersion; + public VaultMetadata.Type vaultVersion; @After public void disconnect() throws Exception { diff --git a/ssh/src/main/java/ch/cyberduck/core/sftp/SFTPMoveFeature.java b/ssh/src/main/java/ch/cyberduck/core/sftp/SFTPMoveFeature.java index de5bd0f3991..e4ccca5f0ec 100644 --- a/ssh/src/main/java/ch/cyberduck/core/sftp/SFTPMoveFeature.java +++ b/ssh/src/main/java/ch/cyberduck/core/sftp/SFTPMoveFeature.java @@ -47,7 +47,7 @@ public Path move(final Path file, final Path renamed, final TransferStatus statu session.sftp().rename(file.getAbsolute(), renamed.getAbsolute(), status.isExists() ? new HashSet<>(Arrays.asList(RenameFlags.OVERWRITE, RenameFlags.NATIVE)) : Collections.singleton(RenameFlags.NATIVE)); // Copy original file attributes - return new Path(renamed).withAttributes(new PathAttributes(file.attributes()).setVault(null)); + return new Path(renamed).withAttributes(new PathAttributes(file.attributes()).setVaultMetadata(null)); } catch(IOException e) { throw new SFTPExceptionMappingService().map("Cannot rename {0}", e, file); diff --git a/ssh/src/test/java/ch/cyberduck/core/cryptomator/CopyWorkerTest.java b/ssh/src/test/java/ch/cyberduck/core/cryptomator/CopyWorkerTest.java index 3466e20d78f..b00052bfcfc 100644 --- a/ssh/src/test/java/ch/cyberduck/core/cryptomator/CopyWorkerTest.java +++ b/ssh/src/test/java/ch/cyberduck/core/cryptomator/CopyWorkerTest.java @@ -48,12 +48,14 @@ import ch.cyberduck.core.transfer.TransferStatus; import ch.cyberduck.core.vault.DefaultVaultRegistry; import ch.cyberduck.core.vault.VaultCredentials; +import ch.cyberduck.core.vault.VaultMetadata; import ch.cyberduck.core.worker.CopyWorker; import ch.cyberduck.core.worker.DeleteWorker; import ch.cyberduck.test.IntegrationTest; import org.apache.commons.io.IOUtils; import org.apache.commons.lang3.RandomUtils; +import org.junit.Ignore; import org.junit.Test; import org.junit.experimental.categories.Category; import org.junit.runner.RunWith; @@ -66,7 +68,6 @@ import java.util.EnumSet; import static org.junit.Assert.*; -import static org.junit.Assume.assumeTrue; @Category(IntegrationTest.class) @RunWith(value = Parameterized.class) @@ -78,8 +79,8 @@ public void testCopyFile() throws Exception { final Path vault = new Path(home, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); final Path source = new Path(vault, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.file)); final Path target = new Path(vault, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.file)); - final CryptoVault cryptomator = new CryptoVault(vault); - cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); final DefaultVaultRegistry registry = new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator); session.withRegistry(registry); final byte[] content = RandomUtils.nextBytes(40500); @@ -105,8 +106,8 @@ public void testCopyToDifferentFolderCryptomator() throws Exception { final Path source = new Path(vault, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.file)); final Path targetFolder = new Path(vault, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); final Path target = new Path(targetFolder, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.file)); - final CryptoVault cryptomator = new CryptoVault(vault); - cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); final DefaultVaultRegistry registry = new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator); session.withRegistry(registry); new CryptoTouchFeature<>(session, new DefaultTouchFeature( @@ -123,15 +124,15 @@ public void testCopyToDifferentFolderCryptomator() throws Exception { } @Test + @Ignore("Filename shortening not implemented yet") public void testCopyToDifferentFolderLongFilenameCryptomator() throws Exception { - assumeTrue(vaultVersion == CryptoVault.VAULT_VERSION_DEPRECATED); final Path home = new SFTPHomeDirectoryService(session).find(); final Path vault = new Path(home, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); final Path source = new Path(vault, new AlphanumericRandomStringService(130).random(), EnumSet.of(Path.Type.file)); final Path targetFolder = new Path(vault, new AlphanumericRandomStringService(130).random(), EnumSet.of(Path.Type.directory)); final Path target = new Path(targetFolder, new AlphanumericRandomStringService(130).random(), EnumSet.of(Path.Type.file)); - final CryptoVault cryptomator = new CryptoVault(vault); - cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); final DefaultVaultRegistry registry = new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator); session.withRegistry(registry); new CryptoTouchFeature<>(session, new DefaultTouchFeature( @@ -153,8 +154,8 @@ public void testCopyFolder() throws Exception { final Path vault = new Path(home, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); final Path folder = new Path(vault, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); final Path file = new Path(folder, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.file)); - final CryptoVault cryptomator = new CryptoVault(vault); - cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); final DefaultVaultRegistry registry = new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator); session.withRegistry(registry); cryptomator.getFeature(session, Directory.class, new SFTPDirectoryFeature(session)).mkdir( @@ -188,8 +189,8 @@ public void testCopyFileIntoVault() throws Exception { assertTrue(new SFTPFindFeature(session).find(cleartextFile)); final Path encryptedFolder = new Path(vault, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); final Path encryptedFile = new Path(encryptedFolder, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.file)); - final CryptoVault cryptomator = new CryptoVault(vault); - cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); final DefaultVaultRegistry registry = new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator); session.withRegistry(registry); cryptomator.getFeature(session, Directory.class, new SFTPDirectoryFeature(session)).mkdir( @@ -214,8 +215,8 @@ public void testCopyDirectoryIntoVault() throws Exception { new SFTPTouchFeature(session).touch(new SFTPWriteFeature(session), cleartextFile, new TransferStatus()); assertTrue(new SFTPFindFeature(session).find(cleartextFolder)); assertTrue(new SFTPFindFeature(session).find(cleartextFile)); - final CryptoVault cryptomator = new CryptoVault(vault); - cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); final DefaultVaultRegistry registry = new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator); session.withRegistry(registry); // move directory into vault @@ -239,8 +240,8 @@ public void testCopyFileOutsideVault() throws Exception { new SFTPDirectoryFeature(session).mkdir(new SFTPWriteFeature(session), clearFolder, new TransferStatus()); final Path encryptedFolder = new Path(vault, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); final Path encryptedFile = new Path(encryptedFolder, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.file)); - final CryptoVault cryptomator = new CryptoVault(vault); - cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); final DefaultVaultRegistry registry = new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator); session.withRegistry(registry); cryptomator.getFeature(session, Directory.class, new SFTPDirectoryFeature(session)).mkdir( @@ -265,8 +266,8 @@ public void testCopyDirectoryOutsideVault() throws Exception { final Path vault = new Path(home, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); final Path encryptedFolder = new Path(vault, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); final Path encryptedFile = new Path(encryptedFolder, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.file)); - final CryptoVault cryptomator = new CryptoVault(vault); - cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); final DefaultVaultRegistry registry = new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator); session.withRegistry(registry); cryptomator.getFeature(session, Directory.class, new SFTPDirectoryFeature(session)).mkdir( diff --git a/ssh/src/test/java/ch/cyberduck/core/cryptomator/CryptoSFTPSingleTransferWorkerTest.java b/ssh/src/test/java/ch/cyberduck/core/cryptomator/CryptoSFTPSingleTransferWorkerTest.java index b0c0c4dbb14..8b1335a42dd 100644 --- a/ssh/src/test/java/ch/cyberduck/core/cryptomator/CryptoSFTPSingleTransferWorkerTest.java +++ b/ssh/src/test/java/ch/cyberduck/core/cryptomator/CryptoSFTPSingleTransferWorkerTest.java @@ -38,7 +38,6 @@ import ch.cyberduck.core.io.StreamCopier; import ch.cyberduck.core.local.DefaultLocalDirectoryFeature; import ch.cyberduck.core.notification.DisabledNotificationService; -import ch.cyberduck.core.preferences.PreferencesFactory; import ch.cyberduck.core.sftp.AbstractSFTPTest; import ch.cyberduck.core.sftp.SFTPAttributesFinderFeature; import ch.cyberduck.core.sftp.SFTPDeleteFeature; @@ -58,6 +57,7 @@ import ch.cyberduck.core.transfer.upload.UploadFilterOptions; import ch.cyberduck.core.vault.DefaultVaultRegistry; import ch.cyberduck.core.vault.VaultCredentials; +import ch.cyberduck.core.vault.VaultMetadata; import ch.cyberduck.core.worker.SingleTransferWorker; import ch.cyberduck.test.IntegrationTest; @@ -104,18 +104,17 @@ public void testUpload() throws Exception { final OutputStream out2 = localFile2.getOutputStream(false); IOUtils.write(content, out2); out2.close(); - final CryptoVault cryptomator = new CryptoVault(vault); - cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); session.withRegistry(new DefaultVaultRegistry(new DisabledPasswordCallback() { @Override public Credentials prompt(final Host bookmark, final String title, final String reason, final LoginOptions options) { return new VaultCredentials("test"); } })); - PreferencesFactory.get().setProperty("factory.vault.class", CryptoVault.class.getName()); final Host host = new Host(new TestProtocol()); final Transfer t = new UploadTransfer(host, Collections.singletonList(new TransferItem(dir1, localDirectory1)), new NullFilter<>()) - .withOptions(new UploadFilterOptions(host).withTimestamp(true)); + .withOptions(new UploadFilterOptions(host).withTimestamp(true)); assertTrue(new SingleTransferWorker(session, session, t, new TransferOptions(), new TransferSpeedometer(t), new DisabledTransferPrompt() { @Override public TransferAction prompt(final TransferItem file) { diff --git a/ssh/src/test/java/ch/cyberduck/core/cryptomator/DefaultTouchFeatureTest.java b/ssh/src/test/java/ch/cyberduck/core/cryptomator/DefaultTouchFeatureTest.java index 3e94c89b214..6a6273c4e1b 100644 --- a/ssh/src/test/java/ch/cyberduck/core/cryptomator/DefaultTouchFeatureTest.java +++ b/ssh/src/test/java/ch/cyberduck/core/cryptomator/DefaultTouchFeatureTest.java @@ -31,6 +31,7 @@ import ch.cyberduck.core.transfer.TransferStatus; import ch.cyberduck.core.vault.DefaultVaultRegistry; import ch.cyberduck.core.vault.VaultCredentials; +import ch.cyberduck.core.vault.VaultMetadata; import ch.cyberduck.test.IntegrationTest; import org.junit.Test; @@ -53,8 +54,8 @@ public void testTouchEncrypted() throws Exception { final Path home = new SFTPHomeDirectoryService(session).find(); final Path vault = new Path(home, UUID.randomUUID().toString(), EnumSet.of(Path.Type.directory)); final Path test = new Path(vault, UUID.randomUUID().toString(), EnumSet.of(Path.Type.file)); - final CryptoVault cryptomator = new CryptoVault(vault); - cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); session.withRegistry(new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator)); new CryptoTouchFeature<>(session, new DefaultTouchFeature( session), cryptomator).touch(new CryptoWriteFeature<>(session, new SFTPWriteFeature(session), cryptomator), test, new TransferStatus()); diff --git a/ssh/src/test/java/ch/cyberduck/core/cryptomator/MoveWorkerTest.java b/ssh/src/test/java/ch/cyberduck/core/cryptomator/MoveWorkerTest.java index 57ca0de2b57..635d7f69ebe 100644 --- a/ssh/src/test/java/ch/cyberduck/core/cryptomator/MoveWorkerTest.java +++ b/ssh/src/test/java/ch/cyberduck/core/cryptomator/MoveWorkerTest.java @@ -52,11 +52,13 @@ import ch.cyberduck.core.transfer.TransferStatus; import ch.cyberduck.core.vault.DefaultVaultRegistry; import ch.cyberduck.core.vault.VaultCredentials; +import ch.cyberduck.core.vault.VaultMetadata; import ch.cyberduck.core.worker.MoveWorker; import ch.cyberduck.test.IntegrationTest; import org.apache.commons.io.IOUtils; import org.apache.commons.lang3.RandomUtils; +import org.junit.Ignore; import org.junit.Test; import org.junit.experimental.categories.Category; import org.junit.runner.RunWith; @@ -70,7 +72,6 @@ import java.util.UUID; import static org.junit.Assert.*; -import static org.junit.Assume.assumeTrue; @Category(IntegrationTest.class) @RunWith(value = Parameterized.class) @@ -82,8 +83,8 @@ public void testMoveSameFolderCryptomator() throws Exception { final Path vault = new Path(home, UUID.randomUUID().toString(), EnumSet.of(Path.Type.directory)); final Path source = new Path(vault, UUID.randomUUID().toString(), EnumSet.of(Path.Type.file)); final Path target = new Path(vault, UUID.randomUUID().toString(), EnumSet.of(Path.Type.file)); - final CryptoVault cryptomator = new CryptoVault(vault); - cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); session.withRegistry(new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator)); final byte[] content = RandomUtils.nextBytes(40500); final TransferStatus status = new TransferStatus(); @@ -107,8 +108,8 @@ public void testMoveToDifferentFolderCryptomator() throws Exception { final Path source = new Path(vault, UUID.randomUUID().toString(), EnumSet.of(Path.Type.file)); final Path targetFolder = new Path(vault, UUID.randomUUID().toString(), EnumSet.of(Path.Type.directory)); final Path target = new Path(targetFolder, UUID.randomUUID().toString(), EnumSet.of(Path.Type.file)); - final CryptoVault cryptomator = new CryptoVault(vault); - cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); session.withRegistry(new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator)); new CryptoTouchFeature<>(session, new DefaultTouchFeature( session), cryptomator).touch(new CryptoWriteFeature<>(session, new SFTPWriteFeature(session), cryptomator), source, new TransferStatus()); @@ -124,15 +125,15 @@ public void testMoveToDifferentFolderCryptomator() throws Exception { } @Test + @Ignore("Filename shortening not implemented yet") public void testMoveToDifferentFolderLongFilenameCryptomator() throws Exception { - assumeTrue(vaultVersion == CryptoVault.VAULT_VERSION_DEPRECATED); final Path home = new SFTPHomeDirectoryService(session).find(); final Path vault = new Path(home, UUID.randomUUID().toString(), EnumSet.of(Path.Type.directory)); final Path source = new Path(vault, new AlphanumericRandomStringService(130).random(), EnumSet.of(Path.Type.file)); final Path targetFolder = new Path(vault, new AlphanumericRandomStringService(130).random(), EnumSet.of(Path.Type.directory)); final Path target = new Path(targetFolder, new AlphanumericRandomStringService(130).random(), EnumSet.of(Path.Type.file)); - final CryptoVault cryptomator = new CryptoVault(vault); - cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); session.withRegistry(new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator)); new CryptoTouchFeature<>(session, new DefaultTouchFeature( session), cryptomator).touch(new CryptoWriteFeature<>(session, new SFTPWriteFeature(session), cryptomator), source, new TransferStatus()); @@ -153,8 +154,8 @@ public void testMoveFolder() throws Exception { final Path vault = new Path(home, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); final Path folder = new Path(vault, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); final Path file = new Path(folder, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.file)); - final CryptoVault cryptomator = new CryptoVault(vault); - cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); session.withRegistry(new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator)); cryptomator.getFeature(session, Directory.class, new SFTPDirectoryFeature(session)).mkdir( cryptomator.getFeature(session, Write.class, new SFTPWriteFeature(session)), folder, new TransferStatus()); @@ -193,8 +194,8 @@ public void testMoveFileIntoVault() throws Exception { assertTrue(new SFTPFindFeature(session).find(clearFile)); final Path encryptedFolder = new Path(vault, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); final Path encryptedFile = new Path(encryptedFolder, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.file)); - final CryptoVault cryptomator = new CryptoVault(vault); - cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); final DefaultVaultRegistry registry = new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator); session.withRegistry(registry); cryptomator.getFeature(session, Directory.class, new SFTPDirectoryFeature(session)).mkdir( @@ -219,8 +220,8 @@ public void testMoveDirectoryIntoVault() throws Exception { new SFTPTouchFeature(session).touch(new SFTPWriteFeature(session), clearFile, new TransferStatus()); assertTrue(new SFTPFindFeature(session).find(clearFolder)); assertTrue(new SFTPFindFeature(session).find(clearFile)); - final CryptoVault cryptomator = new CryptoVault(vault); - cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); final DefaultVaultRegistry registry = new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator); session.withRegistry(registry); // move directory into vault @@ -244,8 +245,8 @@ public void testMoveFileOutsideVault() throws Exception { new SFTPDirectoryFeature(session).mkdir(new SFTPWriteFeature(session), clearFolder, new TransferStatus()); final Path encryptedFolder = new Path(vault, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); final Path encryptedFile = new Path(encryptedFolder, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.file)); - final CryptoVault cryptomator = new CryptoVault(vault); - cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); final DefaultVaultRegistry registry = new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator); session.withRegistry(registry); cryptomator.getFeature(session, Directory.class, new SFTPDirectoryFeature(session)).mkdir( @@ -271,8 +272,8 @@ public void testMoveDirectoryOutsideVault() throws Exception { final Path vault = new Path(home, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); final Path encryptedFolder = new Path(vault, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); final Path encryptedFile = new Path(encryptedFolder, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.file)); - final CryptoVault cryptomator = new CryptoVault(vault); - cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); final DefaultVaultRegistry registry = new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator); session.withRegistry(registry); cryptomator.getFeature(session, Directory.class, new SFTPDirectoryFeature(session)).mkdir( diff --git a/ssh/src/test/java/ch/cyberduck/core/cryptomator/SFTPAttributesFinderFeatureTest.java b/ssh/src/test/java/ch/cyberduck/core/cryptomator/SFTPAttributesFinderFeatureTest.java index 0e48ecafaab..a834f72d7c8 100644 --- a/ssh/src/test/java/ch/cyberduck/core/cryptomator/SFTPAttributesFinderFeatureTest.java +++ b/ssh/src/test/java/ch/cyberduck/core/cryptomator/SFTPAttributesFinderFeatureTest.java @@ -41,6 +41,7 @@ import ch.cyberduck.core.transfer.TransferStatus; import ch.cyberduck.core.vault.DefaultVaultRegistry; import ch.cyberduck.core.vault.VaultCredentials; +import ch.cyberduck.core.vault.VaultMetadata; import ch.cyberduck.test.IntegrationTest; import org.junit.Test; @@ -61,8 +62,8 @@ public class SFTPAttributesFinderFeatureTest extends AbstractSFTPTest { public void testFindCryptomator() throws Exception { final Path home = new SFTPHomeDirectoryService(session).find(); final Path vault = new Path(home, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); - final CryptoVault cryptomator = new CryptoVault(vault); - cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); session.withRegistry(new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator)); final Path test = new CryptoTouchFeature<>(session, new DefaultTouchFeature( session), cryptomator).touch( @@ -74,7 +75,7 @@ public void testFindCryptomator() throws Exception { cryptomator.getFeature(session, Delete.class, new SFTPDeleteFeature(session)).delete(Arrays.asList(test, vault), new DisabledLoginCallback(), new Delete.DisabledCallback()); assertFalse(new SFTPFindFeature(session).find(vault)); assertFalse(new SFTPFindFeature(session).find(cryptomator.getHome())); - assertFalse(new SFTPFindFeature(session).find(cryptomator.getMasterkey())); + assertFalse(new SFTPFindFeature(session).find(cryptomator.getMasterkeyPath())); assertFalse(new SFTPFindFeature(session).find(cryptomator.getConfig())); } @@ -82,8 +83,8 @@ public void testFindCryptomator() throws Exception { public void testFindDefaultAttributesFinderCryptomator() throws Exception { final Path home = new SFTPHomeDirectoryService(session).find(); final Path vault = new Path(home, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); - final CryptoVault cryptomator = new CryptoVault(vault); - cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); session.withRegistry(new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator)); final Path test = new CryptoTouchFeature<>(session, new DefaultTouchFeature( session), cryptomator).touch( @@ -99,8 +100,8 @@ public void testFindDefaultAttributesFinderCryptomator() throws Exception { public void testFindDefaultAttributesFinderWithCacheCryptomator() throws Exception { final Path home = new SFTPHomeDirectoryService(session).find(); final Path vault = new Path(home, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); - final CryptoVault cryptomator = new CryptoVault(vault); - cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); session.withRegistry(new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator)); final Path test = new CryptoTouchFeature<>(session, new DefaultTouchFeature( session), cryptomator).touch( diff --git a/ssh/src/test/java/ch/cyberduck/core/cryptomator/SFTPCryptomatorInteroperabilityTest.java b/ssh/src/test/java/ch/cyberduck/core/cryptomator/SFTPCryptomatorInteroperabilityTest.java index 58a14ea9a7d..ad2b72444ad 100644 --- a/ssh/src/test/java/ch/cyberduck/core/cryptomator/SFTPCryptomatorInteroperabilityTest.java +++ b/ssh/src/test/java/ch/cyberduck/core/cryptomator/SFTPCryptomatorInteroperabilityTest.java @@ -28,6 +28,7 @@ import ch.cyberduck.core.Path; import ch.cyberduck.core.cryptomator.features.CryptoReadFeature; import ch.cyberduck.core.cryptomator.random.FastSecureRandomProvider; +import ch.cyberduck.core.preferences.PreferencesFactory; import ch.cyberduck.core.proxy.DisabledProxyFinder; import ch.cyberduck.core.sftp.SFTPHomeDirectoryService; import ch.cyberduck.core.sftp.SFTPProtocol; @@ -38,6 +39,7 @@ import ch.cyberduck.core.transfer.TransferStatus; import ch.cyberduck.core.vault.DefaultVaultRegistry; import ch.cyberduck.core.vault.VaultCredentials; +import ch.cyberduck.core.vault.VaultMetadata; import org.apache.commons.io.FileUtils; import org.apache.commons.io.IOUtils; @@ -63,6 +65,7 @@ import java.io.InputStream; import java.net.URI; +import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Paths; import java.security.SecureRandom; @@ -101,7 +104,7 @@ public void startSerer() throws Exception { csprng = FastSecureRandomProvider.get().provide(); } final PerpetualMasterkey mk = Masterkey.generate(csprng); - final MasterkeyFileAccess mkAccess = new MasterkeyFileAccess(CryptoVault.VAULT_PEPPER, csprng); + final MasterkeyFileAccess mkAccess = new MasterkeyFileAccess(PreferencesFactory.get().getProperty("cryptomator.vault.pepper").getBytes(StandardCharsets.UTF_8), csprng); final java.nio.file.Path mkPath = Paths.get(vault.toString(), DefaultVaultRegistry.DEFAULT_MASTERKEY_FILE_NAME); mkAccess.persist(mk, mkPath, passphrase); CryptoFileSystemProperties properties = cryptoFileSystemProperties().withKeyLoader(new MasterkeyLoader() { @@ -144,15 +147,16 @@ public void testCryptomatorInteroperabilityLongFilename() throws Exception { session.open(new DisabledProxyFinder(), new DisabledHostKeyCallback(), new DisabledLoginCallback(), new DisabledCancelCallback()); session.login(new DisabledLoginCallback(), new DisabledCancelCallback()); final Path home = new SFTPHomeDirectoryService(session).find(); - final Path vault = new Path(home, "vault", EnumSet.of(Path.Type.directory)); - final CryptoVault cryptomator = new CryptoVault(vault).load(session, new DisabledPasswordCallback() { + final Path vaultPath = new Path(home, "vault", EnumSet.of(Path.Type.directory)); + final AbstractVault cryptomator = new CryptoVaultProvider(session).provide(session, new VaultMetadata(vaultPath, VaultMetadata.Type.V8)); + cryptomator.load(session, new DisabledPasswordCallback() { @Override public Credentials prompt(final Host bookmark, final String title, final String reason, final LoginOptions options) { return new VaultCredentials(passphrase); } }); session.withRegistry(new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator)); - Path p = new Path(new Path(vault, targetFolder.getFileName().toString(), EnumSet.of(Path.Type.directory)), targetFile.getFileName().toString(), EnumSet.of(Path.Type.file)); + Path p = new Path(new Path(vaultPath, targetFolder.getFileName().toString(), EnumSet.of(Path.Type.directory)), targetFile.getFileName().toString(), EnumSet.of(Path.Type.file)); final InputStream read = new CryptoReadFeature(session, new SFTPReadFeature(session), cryptomator).read(p, new TransferStatus(), new DisabledConnectionCallback()); final byte[] readContent = new byte[content.length]; IOUtils.readFully(read, readContent); @@ -178,15 +182,16 @@ public void testCryptomatorInteroperability() throws Exception { session.open(new DisabledProxyFinder(), new DisabledHostKeyCallback(), new DisabledLoginCallback(), new DisabledCancelCallback()); session.login(new DisabledLoginCallback(), new DisabledCancelCallback()); final Path home = new SFTPHomeDirectoryService(session).find(); - final Path vault = new Path(home, "vault", EnumSet.of(Path.Type.directory)); - final CryptoVault cryptomator = new CryptoVault(vault).load(session, new DisabledPasswordCallback() { + final Path vaultPath = new Path(home, "vault", EnumSet.of(Path.Type.directory)); + final AbstractVault cryptomator = new CryptoVaultProvider(session).provide(session, new VaultMetadata(vaultPath, VaultMetadata.Type.V8)); + cryptomator.load(session, new DisabledPasswordCallback() { @Override public Credentials prompt(final Host bookmark, final String title, final String reason, final LoginOptions options) { return new VaultCredentials(passphrase); } }); session.withRegistry(new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator)); - Path p = new Path(new Path(vault, targetFolder.getFileName().toString(), EnumSet.of(Path.Type.directory)), targetFile.getFileName().toString(), EnumSet.of(Path.Type.file)); + Path p = new Path(new Path(vaultPath, targetFolder.getFileName().toString(), EnumSet.of(Path.Type.directory)), targetFile.getFileName().toString(), EnumSet.of(Path.Type.file)); final InputStream read = new CryptoReadFeature(session, new SFTPReadFeature(session), cryptomator).read(p, new TransferStatus(), new DisabledConnectionCallback()); final byte[] readContent = new byte[content.length]; IOUtils.readFully(read, readContent); diff --git a/ssh/src/test/java/ch/cyberduck/core/cryptomator/SFTPDirectoryFeatureTest.java b/ssh/src/test/java/ch/cyberduck/core/cryptomator/SFTPDirectoryFeatureTest.java index c5e2acc3513..8b80a92b5d0 100644 --- a/ssh/src/test/java/ch/cyberduck/core/cryptomator/SFTPDirectoryFeatureTest.java +++ b/ssh/src/test/java/ch/cyberduck/core/cryptomator/SFTPDirectoryFeatureTest.java @@ -33,8 +33,10 @@ import ch.cyberduck.core.transfer.TransferStatus; import ch.cyberduck.core.vault.DefaultVaultRegistry; import ch.cyberduck.core.vault.VaultCredentials; +import ch.cyberduck.core.vault.VaultMetadata; import ch.cyberduck.test.IntegrationTest; +import org.junit.Ignore; import org.junit.Test; import org.junit.experimental.categories.Category; import org.junit.runner.RunWith; @@ -44,7 +46,6 @@ import java.util.EnumSet; import static org.junit.Assert.assertTrue; -import static org.junit.Assume.assumeTrue; @Category(IntegrationTest.class) @RunWith(value = Parameterized.class) @@ -55,8 +56,8 @@ public void testMakeDirectoryEncrypted() throws Exception { final Path home = new SFTPHomeDirectoryService(session).find(); final Path vault = new Path(home, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); final Path test = new Path(vault, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); - final CryptoVault cryptomator = new CryptoVault(vault); - cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); session.withRegistry(new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator)); cryptomator.getFeature(session, Directory.class, new SFTPDirectoryFeature(session)).mkdir( cryptomator.getFeature(session, Write.class, new SFTPWriteFeature(session)), test, new TransferStatus()); @@ -66,13 +67,13 @@ public void testMakeDirectoryEncrypted() throws Exception { } @Test + @Ignore("Filename shortening not implemented yet") public void testMakeDirectoryLongFilenameEncrypted() throws Exception { - assumeTrue(vaultVersion == CryptoVault.VAULT_VERSION_DEPRECATED); final Path home = new SFTPHomeDirectoryService(session).find(); final Path vault = new Path(home, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); final Path test = new Path(vault, new AlphanumericRandomStringService(130).random(), EnumSet.of(Path.Type.directory)); - final CryptoVault cryptomator = new CryptoVault(vault); - cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); session.withRegistry(new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator)); cryptomator.getFeature(session, Directory.class, new SFTPDirectoryFeature(session)).mkdir(new SFTPWriteFeature(session), test, new TransferStatus()); assertTrue(cryptomator.getFeature(session, Find.class, new SFTPFindFeature(session)).find(test)); diff --git a/ssh/src/test/java/ch/cyberduck/core/cryptomator/SFTPFindFeatureTest.java b/ssh/src/test/java/ch/cyberduck/core/cryptomator/SFTPFindFeatureTest.java index 0f2735a8575..9c2839989ab 100644 --- a/ssh/src/test/java/ch/cyberduck/core/cryptomator/SFTPFindFeatureTest.java +++ b/ssh/src/test/java/ch/cyberduck/core/cryptomator/SFTPFindFeatureTest.java @@ -32,8 +32,10 @@ import ch.cyberduck.core.transfer.TransferStatus; import ch.cyberduck.core.vault.DefaultVaultRegistry; import ch.cyberduck.core.vault.VaultCredentials; +import ch.cyberduck.core.vault.VaultMetadata; import ch.cyberduck.test.IntegrationTest; +import org.junit.Ignore; import org.junit.Test; import org.junit.experimental.categories.Category; import org.junit.runner.RunWith; @@ -45,7 +47,6 @@ import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; -import static org.junit.Assume.assumeTrue; @Category(IntegrationTest.class) @RunWith(value = Parameterized.class) @@ -56,8 +57,8 @@ public void testFindCryptomator() throws Exception { final Path home = new SFTPHomeDirectoryService(session).find(); final Path vault = new Path(home, UUID.randomUUID().toString(), EnumSet.of(Path.Type.directory)); final Path test = new Path(vault, UUID.randomUUID().toString(), EnumSet.of(Path.Type.file)); - final CryptoVault cryptomator = new CryptoVault(vault); - cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); session.withRegistry(new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator)); assertFalse(cryptomator.getFeature(session, Find.class, new DefaultFindFeature(session)).find(new Path(vault, "a", EnumSet.of(Path.Type.directory)))); new CryptoTouchFeature<>(session, new CryptoTouchFeature<>(session, new DefaultTouchFeature( @@ -67,14 +68,14 @@ public void testFindCryptomator() throws Exception { } @Test + @Ignore("Filename shortening not implemented yet") public void testFindLongFilenameCryptomator() throws Exception { - assumeTrue(vaultVersion == CryptoVault.VAULT_VERSION_DEPRECATED); final Path home = new SFTPHomeDirectoryService(session).find(); final Path vault = new Path(home, UUID.randomUUID().toString(), EnumSet.of(Path.Type.directory)); final Path test = new Path(vault, new AlphanumericRandomStringService(130).random(), EnumSet.of(Path.Type.file)); - final CryptoVault cryptomator = new CryptoVault(vault); - cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); session.withRegistry(new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator)); new CryptoTouchFeature<>(session, new CryptoTouchFeature<>(session, new DefaultTouchFeature( session), cryptomator), cryptomator).touch(new CryptoWriteFeature<>(session, new SFTPWriteFeature(session), cryptomator), test, new TransferStatus()); diff --git a/ssh/src/test/java/ch/cyberduck/core/cryptomator/SFTPListServiceTest.java b/ssh/src/test/java/ch/cyberduck/core/cryptomator/SFTPListServiceTest.java index f1a060a8956..24cb7e5b757 100644 --- a/ssh/src/test/java/ch/cyberduck/core/cryptomator/SFTPListServiceTest.java +++ b/ssh/src/test/java/ch/cyberduck/core/cryptomator/SFTPListServiceTest.java @@ -41,6 +41,7 @@ import ch.cyberduck.core.transfer.TransferStatus; import ch.cyberduck.core.vault.DefaultVaultRegistry; import ch.cyberduck.core.vault.VaultCredentials; +import ch.cyberduck.core.vault.VaultMetadata; import ch.cyberduck.test.IntegrationTest; import org.junit.Test; @@ -63,8 +64,8 @@ public void testListCryptomator() throws Exception { final Path home = new SFTPHomeDirectoryService(session).find(); final Path vault = new Path(home, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); final Path test = new Path(vault, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.file)); - final CryptoVault cryptomator = new CryptoVault(vault); - cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); session.withRegistry(new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator)); assertTrue(new CryptoListService(session, new SFTPListService(session), cryptomator).list(vault, new DisabledListProgressListener()).isEmpty()); new CryptoTouchFeature<>(session, new CryptoTouchFeature<>(session, new DefaultTouchFeature(session), diff --git a/ssh/src/test/java/ch/cyberduck/core/cryptomator/SFTPMoveFeatureTest.java b/ssh/src/test/java/ch/cyberduck/core/cryptomator/SFTPMoveFeatureTest.java index 067997a6a95..8ab711dd18e 100644 --- a/ssh/src/test/java/ch/cyberduck/core/cryptomator/SFTPMoveFeatureTest.java +++ b/ssh/src/test/java/ch/cyberduck/core/cryptomator/SFTPMoveFeatureTest.java @@ -41,8 +41,10 @@ import ch.cyberduck.core.transfer.TransferStatus; import ch.cyberduck.core.vault.DefaultVaultRegistry; import ch.cyberduck.core.vault.VaultCredentials; +import ch.cyberduck.core.vault.VaultMetadata; import ch.cyberduck.test.IntegrationTest; +import org.junit.Ignore; import org.junit.Test; import org.junit.experimental.categories.Category; import org.junit.runner.RunWith; @@ -54,7 +56,6 @@ import java.util.UUID; import static org.junit.Assert.*; -import static org.junit.Assume.assumeTrue; @Category(IntegrationTest.class) @RunWith(value = Parameterized.class) @@ -66,8 +67,8 @@ public void testMoveSameFolderCryptomator() throws Exception { final Path vault = new Path(home, UUID.randomUUID().toString(), EnumSet.of(Path.Type.directory)); final Path source = new Path(vault, UUID.randomUUID().toString(), EnumSet.of(Path.Type.file)); final Path target = new Path(vault, UUID.randomUUID().toString(), EnumSet.of(Path.Type.file)); - final CryptoVault cryptomator = new CryptoVault(vault); - cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); session.withRegistry(new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator)); new CryptoTouchFeature<>(session, new CryptoTouchFeature<>(session, new DefaultTouchFeature( session), cryptomator), cryptomator).touch(new CryptoWriteFeature<>(session, new SFTPWriteFeature(session), cryptomator), source, new TransferStatus()); @@ -86,8 +87,8 @@ public void testMoveToDifferentFolderCryptomator() throws Exception { final Path source = new Path(vault, UUID.randomUUID().toString(), EnumSet.of(Path.Type.file)); final Path targetFolder = new Path(vault, UUID.randomUUID().toString(), EnumSet.of(Path.Type.directory)); final Path target = new Path(targetFolder, UUID.randomUUID().toString(), EnumSet.of(Path.Type.file)); - final CryptoVault cryptomator = new CryptoVault(vault); - cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); session.withRegistry(new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator)); new CryptoTouchFeature<>(session, new CryptoTouchFeature<>(session, new DefaultTouchFeature( session), cryptomator), cryptomator).touch(new CryptoWriteFeature<>(session, new SFTPWriteFeature(session), cryptomator), source, new TransferStatus()); @@ -103,15 +104,15 @@ public void testMoveToDifferentFolderCryptomator() throws Exception { } @Test + @Ignore("Filename shortening not implemented yet") public void testMoveToDifferentFolderLongFilenameCryptomator() throws Exception { - assumeTrue(vaultVersion == CryptoVault.VAULT_VERSION_DEPRECATED); final Path home = new SFTPHomeDirectoryService(session).find(); final Path vault = new Path(home, UUID.randomUUID().toString(), EnumSet.of(Path.Type.directory)); final Path source = new Path(vault, new AlphanumericRandomStringService(130).random(), EnumSet.of(Path.Type.file)); final Path targetFolder = new Path(vault, new AlphanumericRandomStringService(130).random(), EnumSet.of(Path.Type.directory)); final Path target = new Path(targetFolder, new AlphanumericRandomStringService(130).random(), EnumSet.of(Path.Type.file)); - final CryptoVault cryptomator = new CryptoVault(vault); - cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); session.withRegistry(new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator)); new CryptoTouchFeature<>(session, new CryptoTouchFeature<>(session, new DefaultTouchFeature( session), cryptomator), cryptomator).touch(new CryptoWriteFeature<>(session, new SFTPWriteFeature(session), cryptomator), source, new TransferStatus()); @@ -130,8 +131,8 @@ public void testMoveFile() throws Exception { final Path home = new SFTPHomeDirectoryService(session).find(); final Path vault = new Path(home, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); final Path folder = new Path(vault, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); - final CryptoVault cryptomator = new CryptoVault(vault); - cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); session.withRegistry(new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator)); cryptomator.getFeature(session, Directory.class, new SFTPDirectoryFeature(session)).mkdir( cryptomator.getFeature(session, Write.class, new SFTPWriteFeature(session)), folder, new TransferStatus()); @@ -156,8 +157,8 @@ public void testMoveFolder() throws Exception { final Path home = new SFTPHomeDirectoryService(session).find(); final Path vault = new Path(home, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); final Path folder = new Path(vault, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); - final CryptoVault cryptomator = new CryptoVault(vault); - cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); session.withRegistry(new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator)); cryptomator.getFeature(session, Directory.class, new SFTPDirectoryFeature(session)).mkdir( cryptomator.getFeature(session, Write.class, new SFTPWriteFeature(session)), folder, new TransferStatus()); @@ -177,8 +178,8 @@ public void testMoveFolderWithFile() throws Exception { final Path vault = new Path(home, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); final Path folder = new Path(vault, "folder-1", EnumSet.of(Path.Type.directory)); final Path file = new Path(folder, "file-1", EnumSet.of(Path.Type.file)); - final CryptoVault cryptomator = new CryptoVault(vault); - cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); session.withRegistry(new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator)); cryptomator.getFeature(session, Directory.class, new SFTPDirectoryFeature(session)).mkdir( cryptomator.getFeature(session, Write.class, new SFTPWriteFeature(session)), folder, new TransferStatus()); diff --git a/ssh/src/test/java/ch/cyberduck/core/cryptomator/SFTPReadFeatureTest.java b/ssh/src/test/java/ch/cyberduck/core/cryptomator/SFTPReadFeatureTest.java index adcb3462152..8251ed97db7 100644 --- a/ssh/src/test/java/ch/cyberduck/core/cryptomator/SFTPReadFeatureTest.java +++ b/ssh/src/test/java/ch/cyberduck/core/cryptomator/SFTPReadFeatureTest.java @@ -39,6 +39,7 @@ import ch.cyberduck.core.transfer.TransferStatus; import ch.cyberduck.core.vault.DefaultVaultRegistry; import ch.cyberduck.core.vault.VaultCredentials; +import ch.cyberduck.core.vault.VaultMetadata; import ch.cyberduck.test.IntegrationTest; import org.apache.commons.lang3.RandomUtils; @@ -70,8 +71,8 @@ public void testReadRange() throws Exception { final Path home = new SFTPHomeDirectoryService(session).find(); final Path vault = new Path(home, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); final Path test = new Path(vault, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.file)); - final CryptoVault cryptomator = new CryptoVault(vault); - cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); session.withRegistry(new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator)); final CryptoWriteFeature writer = new CryptoWriteFeature<>(session, new SFTPWriteFeature(session), cryptomator); final FileHeader header = cryptomator.getFileHeaderCryptor().create(); diff --git a/ssh/src/test/java/ch/cyberduck/core/cryptomator/SFTPSymlinkFeatureTest.java b/ssh/src/test/java/ch/cyberduck/core/cryptomator/SFTPSymlinkFeatureTest.java index 7a74f516b4d..d39a63f7696 100644 --- a/ssh/src/test/java/ch/cyberduck/core/cryptomator/SFTPSymlinkFeatureTest.java +++ b/ssh/src/test/java/ch/cyberduck/core/cryptomator/SFTPSymlinkFeatureTest.java @@ -37,8 +37,10 @@ import ch.cyberduck.core.transfer.TransferStatus; import ch.cyberduck.core.vault.DefaultVaultRegistry; import ch.cyberduck.core.vault.VaultCredentials; +import ch.cyberduck.core.vault.VaultMetadata; import ch.cyberduck.test.IntegrationTest; +import org.junit.Ignore; import org.junit.Test; import org.junit.experimental.categories.Category; import org.junit.runner.RunWith; @@ -49,19 +51,18 @@ import java.util.UUID; import static org.junit.Assert.*; -import static org.junit.Assume.assumeTrue; @Category(IntegrationTest.class) @RunWith(value = Parameterized.class) public class SFTPSymlinkFeatureTest extends AbstractSFTPTest { @Test + @Ignore("Filename shortening not yet implemented") public void testSymlink() throws Exception { - assumeTrue(vaultVersion == CryptoVault.VAULT_VERSION_DEPRECATED); final Path home = new SFTPHomeDirectoryService(session).find(); final Path vault = new Path(home, UUID.randomUUID().toString(), EnumSet.of(Path.Type.directory)); - final CryptoVault cryptomator = new CryptoVault(vault); - cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); session.withRegistry(new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator)); final Path target = new Path(vault, UUID.randomUUID().toString(), EnumSet.of(Path.Type.file)); new CryptoTouchFeature<>(session, new CryptoTouchFeature<>(session, new DefaultTouchFeature( diff --git a/ssh/src/test/java/ch/cyberduck/core/cryptomator/SFTPWriteFeatureTest.java b/ssh/src/test/java/ch/cyberduck/core/cryptomator/SFTPWriteFeatureTest.java index e290bdbf760..db460423266 100644 --- a/ssh/src/test/java/ch/cyberduck/core/cryptomator/SFTPWriteFeatureTest.java +++ b/ssh/src/test/java/ch/cyberduck/core/cryptomator/SFTPWriteFeatureTest.java @@ -46,6 +46,7 @@ import ch.cyberduck.core.transfer.TransferStatus; import ch.cyberduck.core.vault.DefaultVaultRegistry; import ch.cyberduck.core.vault.VaultCredentials; +import ch.cyberduck.core.vault.VaultMetadata; import ch.cyberduck.test.IntegrationTest; import org.apache.commons.lang3.RandomUtils; @@ -77,8 +78,8 @@ public void testWrite() throws Exception { final Path home = new SFTPHomeDirectoryService(session).find(); final Path vault = new Path(home, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); final Path test = new Path(vault, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.file)); - final CryptoVault cryptomator = new CryptoVault(vault); - cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); session.withRegistry(new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator)); final CryptoWriteFeature writer = new CryptoWriteFeature<>(session, new SFTPWriteFeature(session), cryptomator); final FileHeader header = cryptomator.getFileHeaderCryptor().create(); @@ -108,8 +109,8 @@ public void testWriteWithCache() throws Exception { final Path home = new SFTPHomeDirectoryService(session).find(); final Path vault = new Path(home, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); final Path test = new Path(vault, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.file)); - final CryptoVault cryptomator = new CryptoVault(vault); - cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); session.withRegistry(new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator)); final CryptoWriteFeature writer = new CryptoWriteFeature<>(session, new SFTPWriteFeature(session), cryptomator); final FileHeader header = cryptomator.getFileHeaderCryptor().create(); diff --git a/ssh/src/test/java/ch/cyberduck/core/sftp/AbstractSFTPTest.java b/ssh/src/test/java/ch/cyberduck/core/sftp/AbstractSFTPTest.java index 8a22f97fd29..75ed42c2039 100644 --- a/ssh/src/test/java/ch/cyberduck/core/sftp/AbstractSFTPTest.java +++ b/ssh/src/test/java/ch/cyberduck/core/sftp/AbstractSFTPTest.java @@ -28,10 +28,10 @@ import ch.cyberduck.core.LoginOptions; import ch.cyberduck.core.Profile; import ch.cyberduck.core.ProtocolFactory; -import ch.cyberduck.core.cryptomator.CryptoVault; import ch.cyberduck.core.serializer.impl.dd.ProfilePlistReader; import ch.cyberduck.core.ssl.DefaultX509KeyManager; import ch.cyberduck.core.ssl.DisabledX509TrustManager; +import ch.cyberduck.core.vault.VaultMetadata; import org.apache.commons.lang3.StringUtils; import org.apache.sshd.common.file.virtualfs.VirtualFileSystemFactory; @@ -71,11 +71,11 @@ public class AbstractSFTPTest { @Parameterized.Parameters(name = "vaultVersion = {0}") public static Object[] data() { - return new Object[]{CryptoVault.VAULT_VERSION_DEPRECATED, CryptoVault.VAULT_VERSION}; + return new Object[]{VaultMetadata.Type.V8, VaultMetadata.Type.UVF}; } @Parameterized.Parameter - public int vaultVersion; + public VaultMetadata.Type vaultVersion; @Before public void start() throws Exception { diff --git a/webdav/src/main/java/ch/cyberduck/core/dav/DAVMoveFeature.java b/webdav/src/main/java/ch/cyberduck/core/dav/DAVMoveFeature.java index bdd8072f601..f8b98e350a1 100644 --- a/webdav/src/main/java/ch/cyberduck/core/dav/DAVMoveFeature.java +++ b/webdav/src/main/java/ch/cyberduck/core/dav/DAVMoveFeature.java @@ -62,7 +62,7 @@ public Path move(final Path file, final Path renamed, final TransferStatus statu status.isExists()); } // Copy original file attributes - return new Path(renamed).withAttributes(new PathAttributes(file.attributes()).setVault(null).setLockId(null)); + return new Path(renamed).withAttributes(new PathAttributes(file.attributes()).setVaultMetadata(null).setLockId(null)); } catch(SardineException e) { throw new DAVExceptionMappingService().map("Cannot rename {0}", e, file); diff --git a/webdav/src/test/java/ch/cyberduck/core/cryptomator/CopyWorkerTest.java b/webdav/src/test/java/ch/cyberduck/core/cryptomator/CopyWorkerTest.java index 20abda9c910..e60b9180028 100644 --- a/webdav/src/test/java/ch/cyberduck/core/cryptomator/CopyWorkerTest.java +++ b/webdav/src/test/java/ch/cyberduck/core/cryptomator/CopyWorkerTest.java @@ -45,12 +45,14 @@ import ch.cyberduck.core.transfer.TransferStatus; import ch.cyberduck.core.vault.DefaultVaultRegistry; import ch.cyberduck.core.vault.VaultCredentials; +import ch.cyberduck.core.vault.VaultMetadata; import ch.cyberduck.core.worker.CopyWorker; import ch.cyberduck.core.worker.DeleteWorker; import ch.cyberduck.test.IntegrationTest; import org.apache.commons.io.IOUtils; import org.apache.commons.lang3.RandomUtils; +import org.junit.Ignore; import org.junit.Test; import org.junit.experimental.categories.Category; import org.junit.runner.RunWith; @@ -63,7 +65,6 @@ import java.util.EnumSet; import static org.junit.Assert.*; -import static org.junit.Assume.assumeTrue; @Category(IntegrationTest.class) @RunWith(value = Parameterized.class) @@ -75,8 +76,8 @@ public void testCopyFile() throws Exception { final Path vault = new Path(home, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); final Path source = new Path(vault, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.file)); final Path target = new Path(vault, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.file)); - final CryptoVault cryptomator = new CryptoVault(vault); - cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); final DefaultVaultRegistry registry = new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator); session.withRegistry(registry); final byte[] content = RandomUtils.nextBytes(40500); @@ -101,8 +102,8 @@ public void testCopyToDifferentFolderCryptomator() throws Exception { final Path source = new Path(vault, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.file)); final Path targetFolder = new Path(vault, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); final Path target = new Path(targetFolder, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.file)); - final CryptoVault cryptomator = new CryptoVault(vault); - cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); final DefaultVaultRegistry registry = new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator); session.withRegistry(registry); new CryptoTouchFeature<>(session, new DefaultTouchFeature( @@ -118,16 +119,17 @@ public void testCopyToDifferentFolderCryptomator() throws Exception { new DeleteWorker(new DisabledLoginCallback(), Collections.singletonList(vault), new DisabledProgressListener()).run(session); } + //TODO @Test + @Ignore(value = "Filename shortening not yet implemented") public void testCopyToDifferentFolderLongFilenameCryptomator() throws Exception { - assumeTrue(vaultVersion == CryptoVault.VAULT_VERSION_DEPRECATED); final Path home = new DefaultHomeFinderService(session).find(); final Path vault = new Path(home, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); final Path source = new Path(vault, new AlphanumericRandomStringService(130).random(), EnumSet.of(Path.Type.file)); final Path targetFolder = new Path(vault, new AlphanumericRandomStringService(130).random(), EnumSet.of(Path.Type.directory)); final Path target = new Path(targetFolder, new AlphanumericRandomStringService(130).random(), EnumSet.of(Path.Type.file)); - final CryptoVault cryptomator = new CryptoVault(vault); - cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); final DefaultVaultRegistry registry = new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator); session.withRegistry(registry); new CryptoTouchFeature<>(session, new DefaultTouchFeature( @@ -149,8 +151,8 @@ public void testCopyFolder() throws Exception { final Path vault = new Path(home, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); final Path folder = new Path(vault, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); final Path file = new Path(folder, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.file)); - final CryptoVault cryptomator = new CryptoVault(vault); - cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); final DefaultVaultRegistry registry = new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator); session.withRegistry(registry); cryptomator.getFeature(session, Directory.class, new DAVDirectoryFeature(session)).mkdir( @@ -185,8 +187,8 @@ public void testCopyFileIntoVault() throws Exception { assertTrue(new DAVFindFeature(session).find(cleartextFile)); final Path encryptedFolder = new Path(vault, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); final Path encryptedFile = new Path(encryptedFolder, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.file)); - final CryptoVault cryptomator = new CryptoVault(vault); - cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); final DefaultVaultRegistry registry = new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator); session.withRegistry(registry); cryptomator.getFeature(session, Directory.class, new DAVDirectoryFeature(session)).mkdir( @@ -215,8 +217,8 @@ public void testCopyDirectoryIntoVault() throws Exception { session).touch(new DAVWriteFeature(session), cleartextFile, new TransferStatus()); assertTrue(new DAVFindFeature(session).find(cleartextFolder)); assertTrue(new DAVFindFeature(session).find(cleartextFile)); - final CryptoVault cryptomator = new CryptoVault(vault); - cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); final DefaultVaultRegistry registry = new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator); session.withRegistry(registry); // move directory into vault @@ -240,8 +242,8 @@ public void testCopyFileOutsideVault() throws Exception { new DAVDirectoryFeature(session).mkdir(new DAVWriteFeature(session), clearFolder, new TransferStatus()); final Path encryptedFolder = new Path(vault, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); final Path encryptedFile = new Path(encryptedFolder, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.file)); - final CryptoVault cryptomator = new CryptoVault(vault); - cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); final DefaultVaultRegistry registry = new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator); session.withRegistry(registry); cryptomator.getFeature(session, Directory.class, new DAVDirectoryFeature(session)).mkdir( @@ -271,8 +273,8 @@ public void testCopyDirectoryOutsideVault() throws Exception { final Path vault = new Path(home, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); final Path encryptedFolder = new Path(vault, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); final Path encryptedFile = new Path(encryptedFolder, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.file)); - final CryptoVault cryptomator = new CryptoVault(vault); - cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); final DefaultVaultRegistry registry = new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator); session.withRegistry(registry); cryptomator.getFeature(session, Directory.class, new DAVDirectoryFeature(session)).mkdir( diff --git a/webdav/src/test/java/ch/cyberduck/core/cryptomator/CryptoDAVSingleTransferWorkerTest.java b/webdav/src/test/java/ch/cyberduck/core/cryptomator/CryptoDAVSingleTransferWorkerTest.java index a7b262d7fa3..8c76f09b678 100644 --- a/webdav/src/test/java/ch/cyberduck/core/cryptomator/CryptoDAVSingleTransferWorkerTest.java +++ b/webdav/src/test/java/ch/cyberduck/core/cryptomator/CryptoDAVSingleTransferWorkerTest.java @@ -47,7 +47,6 @@ import ch.cyberduck.core.io.StreamCopier; import ch.cyberduck.core.local.DefaultLocalDirectoryFeature; import ch.cyberduck.core.notification.DisabledNotificationService; -import ch.cyberduck.core.preferences.PreferencesFactory; import ch.cyberduck.core.shared.DefaultHomeFinderService; import ch.cyberduck.core.transfer.DisabledTransferErrorCallback; import ch.cyberduck.core.transfer.DisabledTransferPrompt; @@ -61,6 +60,7 @@ import ch.cyberduck.core.transfer.UploadTransfer; import ch.cyberduck.core.vault.DefaultVaultRegistry; import ch.cyberduck.core.vault.VaultCredentials; +import ch.cyberduck.core.vault.VaultMetadata; import ch.cyberduck.core.worker.SingleTransferWorker; import ch.cyberduck.test.IntegrationTest; @@ -103,15 +103,14 @@ public void testUpload() throws Exception { final OutputStream out2 = localFile2.getOutputStream(false); IOUtils.write(content, out2); out2.close(); - final CryptoVault cryptomator = new CryptoVault(vault); - cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); session.withRegistry(new DefaultVaultRegistry(new DisabledPasswordCallback() { @Override public Credentials prompt(final Host bookmark, final String title, final String reason, final LoginOptions options) { return new VaultCredentials("test"); } })); - PreferencesFactory.get().setProperty("factory.vault.class", CryptoVault.class.getName()); final Transfer t = new UploadTransfer(new Host(new TestProtocol()), Collections.singletonList(new TransferItem(dir1, localDirectory1)), new NullFilter<>()); assertTrue(new SingleTransferWorker(session, session, t, new TransferOptions(), new TransferSpeedometer(t), new DisabledTransferPrompt() { @Override @@ -145,12 +144,10 @@ public TransferAction prompt(final TransferItem file) { @Test public void testDownload() throws Exception { - PreferencesFactory.get().setProperty("factory.vault.class", CryptoVault.class.getName()); - final Path home = new DefaultHomeFinderService(session).find(); final Path vault = new Path(home, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); - final CryptoVault cryptomator = new CryptoVault(vault); - cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); session.withRegistry(new DefaultVaultRegistry(new DisabledPasswordCallback() { @Override public Credentials prompt(final Host bookmark, final String title, final String reason, final LoginOptions options) { @@ -178,7 +175,7 @@ public TransferAction prompt(final TransferItem file) { return TransferAction.overwrite; } }, new DisabledTransferErrorCallback(), - new DisabledProgressListener(), new DisabledStreamListener(), new DisabledLoginCallback(), new DisabledNotificationService()) { + new DisabledProgressListener(), new DisabledStreamListener(), new DisabledLoginCallback(), new DisabledNotificationService()) { }.run(session)); cryptomator.getFeature(session, Delete.class, new DAVDeleteFeature(session)).delete(Arrays.asList(file1, dir1, vault), new DisabledLoginCallback(), new Delete.DisabledCallback()); diff --git a/webdav/src/test/java/ch/cyberduck/core/cryptomator/DAVDirectoryFeatureTest.java b/webdav/src/test/java/ch/cyberduck/core/cryptomator/DAVDirectoryFeatureTest.java index df3f84fbc08..d4c7d1dd27a 100644 --- a/webdav/src/test/java/ch/cyberduck/core/cryptomator/DAVDirectoryFeatureTest.java +++ b/webdav/src/test/java/ch/cyberduck/core/cryptomator/DAVDirectoryFeatureTest.java @@ -32,8 +32,10 @@ import ch.cyberduck.core.transfer.TransferStatus; import ch.cyberduck.core.vault.DefaultVaultRegistry; import ch.cyberduck.core.vault.VaultCredentials; +import ch.cyberduck.core.vault.VaultMetadata; import ch.cyberduck.test.IntegrationTest; +import org.junit.Ignore; import org.junit.Test; import org.junit.experimental.categories.Category; import org.junit.runner.RunWith; @@ -43,7 +45,6 @@ import java.util.EnumSet; import static org.junit.Assert.assertTrue; -import static org.junit.Assume.assumeTrue; @Category(IntegrationTest.class) @RunWith(value = Parameterized.class) @@ -54,8 +55,8 @@ public void testMakeDirectoryEncrypted() throws Exception { final Path home = new DefaultHomeFinderService(session).find(); final Path vault = new Path(home, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); final Path test = new Path(vault, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); - final CryptoVault cryptomator = new CryptoVault(vault); - cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); session.withRegistry(new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator)); cryptomator.getFeature(session, Directory.class, new DAVDirectoryFeature(session)).mkdir( cryptomator.getFeature(session, Write.class, new DAVWriteFeature(session)), test, new TransferStatus()); @@ -64,13 +65,13 @@ public void testMakeDirectoryEncrypted() throws Exception { } @Test + @Ignore("Filename shortening not yet implemented") public void testMakeDirectoryLongFilenameEncrypted() throws Exception { - assumeTrue(vaultVersion == CryptoVault.VAULT_VERSION_DEPRECATED); final Path home = new DefaultHomeFinderService(session).find(); final Path vault = new Path(home, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); final Path test = new Path(vault, new AlphanumericRandomStringService(130).random(), EnumSet.of(Path.Type.directory)); - final CryptoVault cryptomator = new CryptoVault(vault); - cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); session.withRegistry(new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator)); cryptomator.getFeature(session, Directory.class, new DAVDirectoryFeature(session)).mkdir( cryptomator.getFeature(session, Write.class, new DAVWriteFeature(session)), test, new TransferStatus()); diff --git a/webdav/src/test/java/ch/cyberduck/core/cryptomator/DAVListServiceTest.java b/webdav/src/test/java/ch/cyberduck/core/cryptomator/DAVListServiceTest.java index 857675a1c0e..b842a8ca116 100644 --- a/webdav/src/test/java/ch/cyberduck/core/cryptomator/DAVListServiceTest.java +++ b/webdav/src/test/java/ch/cyberduck/core/cryptomator/DAVListServiceTest.java @@ -33,6 +33,7 @@ import ch.cyberduck.core.transfer.TransferStatus; import ch.cyberduck.core.vault.DefaultVaultRegistry; import ch.cyberduck.core.vault.VaultCredentials; +import ch.cyberduck.core.vault.VaultMetadata; import ch.cyberduck.test.IntegrationTest; import org.junit.Test; @@ -55,8 +56,8 @@ public void testListCryptomator() throws Exception { final Path home = new DefaultHomeFinderService(session).find(); final Path vault = new Path(home, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); final Path test = new Path(vault, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.file)); - final CryptoVault cryptomator = new CryptoVault(vault); - cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); session.withRegistry(new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator)); assertTrue(new CryptoListService(session, new DAVListService(session), cryptomator).list(vault, new DisabledListProgressListener()).isEmpty()); new CryptoTouchFeature<>(session, new DefaultTouchFeature( diff --git a/webdav/src/test/java/ch/cyberduck/core/cryptomator/DAVMoveFeatureTest.java b/webdav/src/test/java/ch/cyberduck/core/cryptomator/DAVMoveFeatureTest.java index 4ec36cda83c..33bf69ea993 100644 --- a/webdav/src/test/java/ch/cyberduck/core/cryptomator/DAVMoveFeatureTest.java +++ b/webdav/src/test/java/ch/cyberduck/core/cryptomator/DAVMoveFeatureTest.java @@ -41,6 +41,7 @@ import ch.cyberduck.core.transfer.TransferStatus; import ch.cyberduck.core.vault.DefaultVaultRegistry; import ch.cyberduck.core.vault.VaultCredentials; +import ch.cyberduck.core.vault.VaultMetadata; import ch.cyberduck.test.IntegrationTest; import org.junit.Test; @@ -62,8 +63,8 @@ public void testMove() throws Exception { final Path home = new DefaultHomeFinderService(session).find(); final Path vault = new Path(home, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); final Path folder = new Path(vault, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); - final CryptoVault cryptomator = new CryptoVault(vault); - cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); session.withRegistry(new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator)); cryptomator.getFeature(session, Directory.class, new DAVDirectoryFeature(session)).mkdir( cryptomator.getFeature(session, Write.class, new DAVWriteFeature(session)), folder, new TransferStatus()); diff --git a/webdav/src/test/java/ch/cyberduck/core/cryptomator/DAVReadFeatureTest.java b/webdav/src/test/java/ch/cyberduck/core/cryptomator/DAVReadFeatureTest.java index 3f38d3f3b81..68c2da6e220 100644 --- a/webdav/src/test/java/ch/cyberduck/core/cryptomator/DAVReadFeatureTest.java +++ b/webdav/src/test/java/ch/cyberduck/core/cryptomator/DAVReadFeatureTest.java @@ -42,6 +42,7 @@ import ch.cyberduck.core.transfer.TransferStatus; import ch.cyberduck.core.vault.DefaultVaultRegistry; import ch.cyberduck.core.vault.VaultCredentials; +import ch.cyberduck.core.vault.VaultMetadata; import ch.cyberduck.test.IntegrationTest; import org.apache.commons.lang3.RandomUtils; @@ -73,8 +74,8 @@ public void testReadRange() throws Exception { final Path home = new DefaultHomeFinderService(session).find(); final Path vault = new Path(home, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); final Path test = new Path(vault, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.file)); - final CryptoVault cryptomator = new CryptoVault(vault); - cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); session.withRegistry(new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator)); final CryptoWriteFeature writer = new CryptoWriteFeature<>(session, new DAVWriteFeature(session), cryptomator); final FileHeader header = cryptomator.getFileHeaderCryptor().create(); diff --git a/webdav/src/test/java/ch/cyberduck/core/cryptomator/DAVTouchFeatureTest.java b/webdav/src/test/java/ch/cyberduck/core/cryptomator/DAVTouchFeatureTest.java index 1dbbdd0c765..596edd3173d 100644 --- a/webdav/src/test/java/ch/cyberduck/core/cryptomator/DAVTouchFeatureTest.java +++ b/webdav/src/test/java/ch/cyberduck/core/cryptomator/DAVTouchFeatureTest.java @@ -35,8 +35,10 @@ import ch.cyberduck.core.transfer.TransferStatus; import ch.cyberduck.core.vault.DefaultVaultRegistry; import ch.cyberduck.core.vault.VaultCredentials; +import ch.cyberduck.core.vault.VaultMetadata; import ch.cyberduck.test.IntegrationTest; +import org.junit.Ignore; import org.junit.Test; import org.junit.experimental.categories.Category; import org.junit.runner.RunWith; @@ -48,19 +50,18 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; -import static org.junit.Assume.assumeTrue; @Category(IntegrationTest.class) @RunWith(value = Parameterized.class) public class DAVTouchFeatureTest extends AbstractDAVTest { @Test + @Ignore(value = "Filename shortening not yet implemented") public void testTouchLongFilenameEncrypted() throws Exception { - assumeTrue(vaultVersion == CryptoVault.VAULT_VERSION_DEPRECATED); final Path home = new DefaultHomeFinderService(session).find(); final Path vault = new Path(home, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); - final CryptoVault cryptomator = new CryptoVault(vault); - cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); session.withRegistry(new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator)); final Path template = new Path(vault, new AlphanumericRandomStringService(130).random(), EnumSet.of(Path.Type.file)); final Path test = new CryptoTouchFeature<>(session, new DefaultTouchFeature( @@ -72,13 +73,13 @@ public void testTouchLongFilenameEncrypted() throws Exception { } @Test + @Ignore(value = "Filename shortening not yet implemented") public void testTouchLongFilenameEncryptedDefaultFeature() throws Exception { - assumeTrue(vaultVersion == CryptoVault.VAULT_VERSION_DEPRECATED); final Path home = new DefaultHomeFinderService(session).find(); final Path vault = new Path(home, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); final Path test = new Path(vault, new AlphanumericRandomStringService(130).random(), EnumSet.of(Path.Type.file)); - final CryptoVault cryptomator = new CryptoVault(vault); - cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); session.withRegistry(new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator)); new CryptoTouchFeature<>(session, new DefaultTouchFeature( session), cryptomator).touch(new CryptoWriteFeature<>(session, new DAVWriteFeature(session), cryptomator), test, new TransferStatus()); @@ -87,13 +88,13 @@ public void testTouchLongFilenameEncryptedDefaultFeature() throws Exception { } @Test + @Ignore(value = "Filename shortening not yet implemented") public void testTouchDeleteTouchLongFilename() throws Exception { - assumeTrue(vaultVersion == CryptoVault.VAULT_VERSION_DEPRECATED); final Path home = new DefaultHomeFinderService(session).find(); final Path vault = new Path(home, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); final Path test = new Path(vault, new AlphanumericRandomStringService(130).random(), EnumSet.of(Path.Type.file)); - final CryptoVault cryptomator = new CryptoVault(vault); - cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); session.withRegistry(new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator)); new CryptoTouchFeature<>(session, new DefaultTouchFeature( session), cryptomator).touch(new CryptoWriteFeature<>(session, new DAVWriteFeature(session), cryptomator), test, new TransferStatus()); diff --git a/webdav/src/test/java/ch/cyberduck/core/cryptomator/DAVWriteFeatureTest.java b/webdav/src/test/java/ch/cyberduck/core/cryptomator/DAVWriteFeatureTest.java index 1ca8f86568d..b8b1360342f 100644 --- a/webdav/src/test/java/ch/cyberduck/core/cryptomator/DAVWriteFeatureTest.java +++ b/webdav/src/test/java/ch/cyberduck/core/cryptomator/DAVWriteFeatureTest.java @@ -16,6 +16,7 @@ */ import ch.cyberduck.core.AlphanumericRandomStringService; +import ch.cyberduck.core.AttributedList; import ch.cyberduck.core.DisabledConnectionCallback; import ch.cyberduck.core.DisabledListProgressListener; import ch.cyberduck.core.DisabledLoginCallback; @@ -42,6 +43,7 @@ import ch.cyberduck.core.transfer.TransferStatus; import ch.cyberduck.core.vault.DefaultVaultRegistry; import ch.cyberduck.core.vault.VaultCredentials; +import ch.cyberduck.core.vault.VaultMetadata; import ch.cyberduck.test.IntegrationTest; import org.apache.commons.lang3.RandomUtils; @@ -73,8 +75,8 @@ public void testWrite() throws Exception { final Path home = new DefaultHomeFinderService(session).find(); final Path vault = new Path(home, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); final Path test = new Path(vault, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.file)); - final CryptoVault cryptomator = new CryptoVault(vault); - cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(vault, vaultVersion)); session.withRegistry(new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator)); final CryptoWriteFeature writer = new CryptoWriteFeature<>(session, new DAVWriteFeature(session), cryptomator); final FileHeader header = cryptomator.getFileHeaderCryptor().create(); @@ -86,7 +88,9 @@ public void testWrite() throws Exception { new StreamCopier(status, status).transfer(new ByteArrayInputStream(content), out); out.close(); assertTrue(cryptomator.getFeature(session, Find.class, new DAVFindFeature(session)).find(test)); - assertEquals(content.length, new CryptoListService(session, new DAVListService(session), cryptomator).list(test.getParent(), new DisabledListProgressListener()).get(test).attributes().getSize()); + final AttributedList list = new CryptoListService(session, new DAVListService(session), cryptomator).list(test.getParent(), new DisabledListProgressListener()); + assertEquals(1, list.size()); + assertEquals(content.length, list.get(test).attributes().getSize()); assertEquals(content.length, new CryptoUploadFeature<>(session, new DAVUploadFeature(session), cryptomator).append(test, status .setRemote(cryptomator.getFeature(session, AttributesFinder.class, new DAVAttributesFinderFeature(session)).find(test))).offset, 0L); final ByteArrayOutputStream buffer = new ByteArrayOutputStream(content.length); diff --git a/webdav/src/test/java/ch/cyberduck/core/dav/AbstractDAVTest.java b/webdav/src/test/java/ch/cyberduck/core/dav/AbstractDAVTest.java index 7ce02f130e9..8592c91d441 100644 --- a/webdav/src/test/java/ch/cyberduck/core/dav/AbstractDAVTest.java +++ b/webdav/src/test/java/ch/cyberduck/core/dav/AbstractDAVTest.java @@ -29,11 +29,11 @@ import ch.cyberduck.core.Profile; import ch.cyberduck.core.ProtocolFactory; import ch.cyberduck.core.Scheme; -import ch.cyberduck.core.cryptomator.CryptoVault; import ch.cyberduck.core.local.FlatTemporaryFileService; import ch.cyberduck.core.serializer.impl.dd.ProfilePlistReader; import ch.cyberduck.core.ssl.DefaultX509KeyManager; import ch.cyberduck.core.ssl.DefaultX509TrustManager; +import ch.cyberduck.core.vault.VaultMetadata; import ch.cyberduck.test.VaultTest; import org.junit.After; @@ -93,11 +93,11 @@ public class AbstractDAVTest extends VaultTest { @Parameterized.Parameters(name = "vaultVersion = {0}") public static Object[] data() { - return new Object[]{CryptoVault.VAULT_VERSION_DEPRECATED, CryptoVault.VAULT_VERSION}; + return new Object[]{VaultMetadata.Type.V8, VaultMetadata.Type.UVF}; } @Parameterized.Parameter - public int vaultVersion; + public VaultMetadata.Type vaultVersion; @After public void disconnect() throws Exception { diff --git a/webdav/src/test/java/ch/cyberduck/core/dav/DAVAttributesFinderFeatureTest.java b/webdav/src/test/java/ch/cyberduck/core/dav/DAVAttributesFinderFeatureTest.java index 4405a6bc4a3..708b3230d4c 100644 --- a/webdav/src/test/java/ch/cyberduck/core/dav/DAVAttributesFinderFeatureTest.java +++ b/webdav/src/test/java/ch/cyberduck/core/dav/DAVAttributesFinderFeatureTest.java @@ -9,7 +9,8 @@ import ch.cyberduck.core.Host; import ch.cyberduck.core.Path; import ch.cyberduck.core.PathAttributes; -import ch.cyberduck.core.cryptomator.CryptoVault; +import ch.cyberduck.core.cryptomator.AbstractVault; +import ch.cyberduck.core.cryptomator.CryptoVaultProvider; import ch.cyberduck.core.cryptomator.features.CryptoTouchFeature; import ch.cyberduck.core.cryptomator.features.CryptoWriteFeature; import ch.cyberduck.core.date.RFC1123DateFormatter; @@ -25,6 +26,7 @@ import ch.cyberduck.core.transfer.TransferStatus; import ch.cyberduck.core.vault.DefaultVaultRegistry; import ch.cyberduck.core.vault.VaultCredentials; +import ch.cyberduck.core.vault.VaultMetadata; import ch.cyberduck.test.IntegrationTest; import org.apache.commons.lang3.StringUtils; @@ -188,8 +190,8 @@ public void testFindLock() throws Exception { public void testFindDefaultAttributesFinderCryptomator() throws Exception { final Path home = new DefaultHomeFinderService(session).find(); final Path vault = new Path(home, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)); - final CryptoVault cryptomator = new CryptoVault(vault); - cryptomator.create(session, new VaultCredentials("test"), vaultVersion); + final AbstractVault cryptomator = new CryptoVaultProvider(session).create(session, null, new VaultCredentials("test"), + new VaultMetadata(new Path(home, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.directory)), vaultVersion)); session.withRegistry(new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator)); final Path test = new CryptoTouchFeature<>(session, new DAVTouchFeature(session), cryptomator).touch( new CryptoWriteFeature<>(session, new DAVWriteFeature(session), cryptomator), new Path(vault, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.file)), new TransferStatus()); diff --git a/windows/src/main/csharp/ch/cyberduck/ui/controller/BrowserController.cs b/windows/src/main/csharp/ch/cyberduck/ui/controller/BrowserController.cs index b1fe476cc53..4402f44e97d 100644 --- a/windows/src/main/csharp/ch/cyberduck/ui/controller/BrowserController.cs +++ b/windows/src/main/csharp/ch/cyberduck/ui/controller/BrowserController.cs @@ -358,10 +358,10 @@ protected override void Invalidate() private void View_LockUnlockVault() { Path directory = new UploadTargetFinder(Workdir).find(SelectedPath); - if (directory.attributes().getVault() != null) + if (directory.attributes().getVaultMetadata() != null) { // Lock and remove all open vaults - LockVaultAction lockVault = new LockVaultAction(this, Pool.getVaultRegistry(), directory.attributes().getVault()); + LockVaultAction lockVault = new LockVaultAction(this, Pool.getVaultRegistry(), directory.attributes().getVaultMetadata().root); Background(lockVault); } else @@ -2069,7 +2069,7 @@ private bool View_ValidateNewFolder() private bool View_ValidateNewVault() { return IsMounted() && Pool.getVaultRegistry() != VaultRegistry.DISABLED && - null == Workdir.attributes().getVault() && + null == Workdir.attributes().getVaultMetadata() && ((Directory)Pool.getFeature(typeof(Directory))).isSupported( new UploadTargetFinder(Workdir).find(SelectedPath), String.Empty); } From 7e334c7a82649b509806da6240a19b78a7e3a77f Mon Sep 17 00:00:00 2001 From: Yves Langisch Date: Wed, 29 Oct 2025 07:27:17 +0100 Subject: [PATCH 06/12] Introduce VaultMetadataProvider. --- .../ch/cyberduck/core/features/Vault.java | 5 ++- .../cyberduck/core/vault/DisabledVault.java | 3 +- .../core/vault/VaultMetadataProvider.java | 23 +++++++++++ .../core/cryptomator/CryptoVaultProvider.java | 7 +++- .../cryptomator/impl/uvf/CryptoVault.java | 40 +++++++++++++++++-- .../uvf/DefaultVaultMetadataUVFProvider.java | 34 ++++++++++++++++ .../impl/uvf/VaultMetadataUVFProvider.java | 36 +++++++++++++++++ .../core/cryptomator/impl/v8/CryptoVault.java | 10 ++++- .../v8/DefaultVaultMetadataV8Provider.java | 32 +++++++++++++++ .../impl/v8/VaultMetadataV8Provider.java | 33 +++++++++++++++ 10 files changed, 213 insertions(+), 10 deletions(-) create mode 100644 core/src/main/java/ch/cyberduck/core/vault/VaultMetadataProvider.java create mode 100644 cryptomator/src/main/java/ch/cyberduck/core/cryptomator/impl/uvf/DefaultVaultMetadataUVFProvider.java create mode 100644 cryptomator/src/main/java/ch/cyberduck/core/cryptomator/impl/uvf/VaultMetadataUVFProvider.java create mode 100644 cryptomator/src/main/java/ch/cyberduck/core/cryptomator/impl/v8/DefaultVaultMetadataV8Provider.java create mode 100644 cryptomator/src/main/java/ch/cyberduck/core/cryptomator/impl/v8/VaultMetadataV8Provider.java diff --git a/core/src/main/java/ch/cyberduck/core/features/Vault.java b/core/src/main/java/ch/cyberduck/core/features/Vault.java index 1267d61d4ca..3f6d75082e8 100644 --- a/core/src/main/java/ch/cyberduck/core/features/Vault.java +++ b/core/src/main/java/ch/cyberduck/core/features/Vault.java @@ -23,8 +23,8 @@ import ch.cyberduck.core.exception.NotfoundException; import ch.cyberduck.core.exception.UnsupportedException; import ch.cyberduck.core.vault.DisabledVault; -import ch.cyberduck.core.vault.VaultCredentials; import ch.cyberduck.core.vault.VaultMetadata; +import ch.cyberduck.core.vault.VaultMetadataProvider; public interface Vault { @@ -36,7 +36,8 @@ public interface Vault { * @throws BackgroundException Failure reading master key from server * @throws NotfoundException No master key file in home */ - Vault create(Session session, String region, VaultCredentials credentials) throws BackgroundException; + + Vault create(Session session, String region, VaultMetadataProvider metadata) throws BackgroundException; /** * Open existing vault diff --git a/core/src/main/java/ch/cyberduck/core/vault/DisabledVault.java b/core/src/main/java/ch/cyberduck/core/vault/DisabledVault.java index 76b7d0541f2..1e0c636f3aa 100644 --- a/core/src/main/java/ch/cyberduck/core/vault/DisabledVault.java +++ b/core/src/main/java/ch/cyberduck/core/vault/DisabledVault.java @@ -18,6 +18,7 @@ import ch.cyberduck.core.PasswordCallback; import ch.cyberduck.core.Path; import ch.cyberduck.core.Session; +import ch.cyberduck.core.exception.BackgroundException; import ch.cyberduck.core.features.Vault; import java.util.EnumSet; @@ -36,7 +37,7 @@ public DisabledVault(final Path home) { } @Override - public Vault create(final Session session, final String region, final VaultCredentials credentials) { + public Vault create(final Session session, final String region, final VaultMetadataProvider metadata) throws BackgroundException { return null; } diff --git a/core/src/main/java/ch/cyberduck/core/vault/VaultMetadataProvider.java b/core/src/main/java/ch/cyberduck/core/vault/VaultMetadataProvider.java new file mode 100644 index 00000000000..ce7465b4195 --- /dev/null +++ b/core/src/main/java/ch/cyberduck/core/vault/VaultMetadataProvider.java @@ -0,0 +1,23 @@ +package ch.cyberduck.core.vault; + +/* + * Copyright (c) 2002-2025 iterate GmbH. All rights reserved. + * https://cyberduck.io/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +public interface VaultMetadataProvider { + + //Map metadataFiles() throws BackgroundException; + + //String dirPath(); +} diff --git a/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/CryptoVaultProvider.java b/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/CryptoVaultProvider.java index aff3414203e..ee6c59a04c3 100644 --- a/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/CryptoVaultProvider.java +++ b/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/CryptoVaultProvider.java @@ -18,6 +18,8 @@ import ch.cyberduck.core.ListProgressListener; import ch.cyberduck.core.Path; import ch.cyberduck.core.Session; +import ch.cyberduck.core.cryptomator.impl.uvf.DefaultVaultMetadataUVFProvider; +import ch.cyberduck.core.cryptomator.impl.v8.DefaultVaultMetadataV8Provider; import ch.cyberduck.core.exception.BackgroundException; import ch.cyberduck.core.features.Find; import ch.cyberduck.core.preferences.HostPreferencesFactory; @@ -94,9 +96,10 @@ public synchronized AbstractVault provide(final Session session, final VaultM public AbstractVault create(final Session session, final String region, final VaultCredentials credentials, final VaultMetadata metadata) throws BackgroundException { switch(metadata.type) { case V8: - return new ch.cyberduck.core.cryptomator.impl.v8.CryptoVault(metadata.root).create(session, region, credentials); + return new ch.cyberduck.core.cryptomator.impl.v8.CryptoVault(metadata.root).create(session, region, new DefaultVaultMetadataV8Provider(credentials)); case UVF: - return new ch.cyberduck.core.cryptomator.impl.uvf.CryptoVault(metadata.root).create(session, region, credentials); + //TODO plain UVF + return new ch.cyberduck.core.cryptomator.impl.uvf.CryptoVault(metadata.root).create(session, region, new DefaultVaultMetadataUVFProvider()); default: log.error("Unknown vault type {}", metadata.type); // TODO schmeissen, DISABLED zurück geben geht nicht weil kein AbstractVault diff --git a/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/impl/uvf/CryptoVault.java b/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/impl/uvf/CryptoVault.java index dc3f86ca87a..386dc3a554a 100644 --- a/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/impl/uvf/CryptoVault.java +++ b/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/impl/uvf/CryptoVault.java @@ -23,6 +23,7 @@ import ch.cyberduck.core.Session; import ch.cyberduck.core.SimplePathPredicate; import ch.cyberduck.core.cryptomator.AbstractVault; +import ch.cyberduck.core.cryptomator.ContentWriter; import ch.cyberduck.core.cryptomator.CryptoDirectory; import ch.cyberduck.core.cryptomator.CryptoFilename; import ch.cyberduck.core.cryptomator.features.CryptoDirectoryUVFFeature; @@ -32,9 +33,13 @@ import ch.cyberduck.core.exception.BackgroundException; import ch.cyberduck.core.exception.UnsupportedException; import ch.cyberduck.core.features.Directory; +import ch.cyberduck.core.features.Encryption; import ch.cyberduck.core.features.Vault; -import ch.cyberduck.core.vault.VaultCredentials; +import ch.cyberduck.core.features.Write; +import ch.cyberduck.core.preferences.PreferencesFactory; +import ch.cyberduck.core.transfer.TransferStatus; import ch.cyberduck.core.vault.VaultMetadata; +import ch.cyberduck.core.vault.VaultMetadataProvider; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -83,8 +88,37 @@ public CryptoVault(final Path home) { } @Override - public AbstractVault create(final Session session, final String region, final VaultCredentials credentials) throws BackgroundException { - throw new UnsupportedOperationException(); + public AbstractVault create(final Session session, final String region, final VaultMetadataProvider metadata) throws BackgroundException { + final VaultMetadataUVFProvider provider = VaultMetadataUVFProvider.cast(metadata); + + final Path home = this.getHome(); + log.debug("Create vault root directory at {}", home); + + // Obtain non encrypted directory writer + final Directory directory = session._getFeature(Directory.class); + final TransferStatus status = new TransferStatus().setRegion(region); + final Encryption encryption = session._getFeature(Encryption.class); + if(encryption != null) { + status.setEncryption(encryption.getDefault(home)); + } + final Path vault = directory.mkdir(session._getFeature(Write.class), home, status); + + final Path dataDir = new Path(vault, "d", EnumSet.of(Path.Type.directory)); + final Path firstLevel = new Path(dataDir, provider.getDirPath().substring(0, 2), EnumSet.of(Path.Type.directory)); + final Path secondLevel = new Path(firstLevel, provider.getDirPath().substring(2), EnumSet.of(Path.Type.directory)); + + directory.mkdir(session._getFeature(Write.class), dataDir, status); + directory.mkdir(session._getFeature(Write.class), firstLevel, status); + directory.mkdir(session._getFeature(Write.class), secondLevel, status); + + // vault.uvf + new ContentWriter(session).write(new Path(home, PreferencesFactory.get().getProperty("cryptomator.vault.config.filename"), + EnumSet.of(Path.Type.file, Path.Type.vault)), provider.getMetadata()); + // dir.uvf + new ContentWriter(session).write(new Path(secondLevel, "dir.uvf", EnumSet.of(Path.Type.file)), + provider.getRootDirectoryMetadata()); + + return this; } // load -> unlock -> open diff --git a/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/impl/uvf/DefaultVaultMetadataUVFProvider.java b/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/impl/uvf/DefaultVaultMetadataUVFProvider.java new file mode 100644 index 00000000000..d4f2b904594 --- /dev/null +++ b/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/impl/uvf/DefaultVaultMetadataUVFProvider.java @@ -0,0 +1,34 @@ +package ch.cyberduck.core.cryptomator.impl.uvf; + +/* + * Copyright (c) 2002-2025 iterate GmbH. All rights reserved. + * https://cyberduck.io/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +public class DefaultVaultMetadataUVFProvider implements VaultMetadataUVFProvider { + + @Override + public byte[] getMetadata() { + return new byte[0]; + } + + @Override + public byte[] getRootDirectoryMetadata() { + return new byte[0]; + } + + @Override + public String getDirPath() { + return ""; + } +} diff --git a/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/impl/uvf/VaultMetadataUVFProvider.java b/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/impl/uvf/VaultMetadataUVFProvider.java new file mode 100644 index 00000000000..69e8fec931e --- /dev/null +++ b/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/impl/uvf/VaultMetadataUVFProvider.java @@ -0,0 +1,36 @@ +package ch.cyberduck.core.cryptomator.impl.uvf; + +/* + * Copyright (c) 2002-2025 iterate GmbH. All rights reserved. + * https://cyberduck.io/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +import ch.cyberduck.core.vault.VaultMetadataProvider; + +public interface VaultMetadataUVFProvider extends VaultMetadataProvider { + + byte[] getMetadata(); + + byte[] getRootDirectoryMetadata(); + + String getDirPath(); + + static VaultMetadataUVFProvider cast(VaultMetadataProvider provider) { + if(provider instanceof VaultMetadataUVFProvider) { + return (VaultMetadataUVFProvider) provider; + } + else { + throw new IllegalArgumentException("Unsupported metadata type " + provider.getClass()); + } + } +} diff --git a/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/impl/v8/CryptoVault.java b/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/impl/v8/CryptoVault.java index 45f4609c4f1..517ae983c8b 100644 --- a/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/impl/v8/CryptoVault.java +++ b/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/impl/v8/CryptoVault.java @@ -42,7 +42,6 @@ import ch.cyberduck.core.exception.NotfoundException; import ch.cyberduck.core.features.Directory; import ch.cyberduck.core.features.Encryption; -import ch.cyberduck.core.features.Write; import ch.cyberduck.core.features.Vault; import ch.cyberduck.core.features.Write; import ch.cyberduck.core.preferences.Preferences; @@ -52,6 +51,7 @@ import ch.cyberduck.core.vault.VaultCredentials; import ch.cyberduck.core.vault.VaultException; import ch.cyberduck.core.vault.VaultMetadata; +import ch.cyberduck.core.vault.VaultMetadataProvider; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -212,8 +212,14 @@ public Pattern getFilenamePattern() { return FILENAME_PATTERN; } + public AbstractVault create(final Session session, final String region, final VaultCredentials credentials) throws BackgroundException { + return this.create(session, region, new DefaultVaultMetadataV8Provider(credentials)); + } + @Override - public synchronized AbstractVault create(final Session session, final String region, final VaultCredentials credentials) throws BackgroundException { + public AbstractVault create(final Session session, final String region, final VaultMetadataProvider metadata) throws BackgroundException { + final VaultMetadataV8Provider provider = VaultMetadataV8Provider.cast(metadata); + final VaultCredentials credentials = provider.getCredentials(); final Host bookmark = session.getHost(); if(credentials.isSaved()) { try { diff --git a/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/impl/v8/DefaultVaultMetadataV8Provider.java b/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/impl/v8/DefaultVaultMetadataV8Provider.java new file mode 100644 index 00000000000..bf338ddc976 --- /dev/null +++ b/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/impl/v8/DefaultVaultMetadataV8Provider.java @@ -0,0 +1,32 @@ +package ch.cyberduck.core.cryptomator.impl.v8; + +/* + * Copyright (c) 2002-2025 iterate GmbH. All rights reserved. + * https://cyberduck.io/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +import ch.cyberduck.core.vault.VaultCredentials; + +public class DefaultVaultMetadataV8Provider implements VaultMetadataV8Provider { + + private VaultCredentials credentials; + + public DefaultVaultMetadataV8Provider(final VaultCredentials credentials) { + this.credentials = credentials; + } + + @Override + public VaultCredentials getCredentials() { + return credentials; + } +} diff --git a/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/impl/v8/VaultMetadataV8Provider.java b/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/impl/v8/VaultMetadataV8Provider.java new file mode 100644 index 00000000000..cd6de72f367 --- /dev/null +++ b/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/impl/v8/VaultMetadataV8Provider.java @@ -0,0 +1,33 @@ +package ch.cyberduck.core.cryptomator.impl.v8; + +/* + * Copyright (c) 2002-2025 iterate GmbH. All rights reserved. + * https://cyberduck.io/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +import ch.cyberduck.core.vault.VaultCredentials; +import ch.cyberduck.core.vault.VaultMetadataProvider; + +public interface VaultMetadataV8Provider extends VaultMetadataProvider { + + VaultCredentials getCredentials(); + + static VaultMetadataV8Provider cast(VaultMetadataProvider provider) { + if(provider instanceof VaultMetadataV8Provider) { + return (VaultMetadataV8Provider) provider; + } + else { + throw new IllegalArgumentException("Unsupported metadata type " + provider.getClass()); + } + } +} From 8d38b8c069b5217aad957f71816803703acf66c4 Mon Sep 17 00:00:00 2001 From: David Kocher Date: Wed, 29 Oct 2025 14:46:45 +0100 Subject: [PATCH 07/12] Add missing registrations. --- .../main/csharp/ch/cyberduck/cli/WindowsTerminalPreferences.cs | 2 +- cli/src/main/java/ch/cyberduck/cli/TerminalPreferences.java | 2 -- .../main/java/ch/cyberduck/core/preferences/Preferences.java | 2 ++ .../cyberduck/ui/cocoa/ApplicationUserDefaultsPreferences.java | 2 +- .../ch/cyberduck/ui/core/preferences/ApplicationPreferences.cs | 1 + 5 files changed, 5 insertions(+), 4 deletions(-) diff --git a/cli/src/main/csharp/ch/cyberduck/cli/WindowsTerminalPreferences.cs b/cli/src/main/csharp/ch/cyberduck/cli/WindowsTerminalPreferences.cs index e4cadaf6cb6..f6c59c0ab32 100644 --- a/cli/src/main/csharp/ch/cyberduck/cli/WindowsTerminalPreferences.cs +++ b/cli/src/main/csharp/ch/cyberduck/cli/WindowsTerminalPreferences.cs @@ -96,7 +96,7 @@ protected override void setFactories() // This is a transient dependency coming from Cyberduck.Cryptomator through Cyberduck.Cli, // which isn't used in duck. Thus crazy stuff happens, and we have to force-load Cyberduck.Cryptomator here. // ref https://github.com/iterate-ch/cyberduck/issues/12812 - this.setDefault("factory.vault.class", typeof(CryptoVault).AssemblyQualifiedName); + this.setDefault("factory.vaultprovider.class", typeof(CryptoVaultProvider).AssemblyQualifiedName); } private class TerminalPropertyStoreFactory : IPropertyStoreFactory diff --git a/cli/src/main/java/ch/cyberduck/cli/TerminalPreferences.java b/cli/src/main/java/ch/cyberduck/cli/TerminalPreferences.java index 9e33bd55c60..a6321cedc09 100644 --- a/cli/src/main/java/ch/cyberduck/cli/TerminalPreferences.java +++ b/cli/src/main/java/ch/cyberduck/cli/TerminalPreferences.java @@ -59,8 +59,6 @@ protected void setFactories() { for(Transfer.Type t : Transfer.Type.values()) { this.setDefault(String.format("factory.transferpromptcallback.%s.class", t.name()), TerminalTransferPrompt.class.getName()); } - //TODO braucht es diesen eintrag noch? - this.setDefault("factory.vault.class", CryptoVault.class.getName()); this.setDefault("factory.vaultprovider.class", CryptoVaultProvider.class.getName()); this.setDefault("factory.securerandom.class", FastSecureRandomProvider.class.getName()); this.setDefault("factory.connectiontimeout.class", DisabledConnectionTimeout.class.getName()); diff --git a/core/src/main/java/ch/cyberduck/core/preferences/Preferences.java b/core/src/main/java/ch/cyberduck/core/preferences/Preferences.java index 0c49248f4d7..e68bf48cd2c 100755 --- a/core/src/main/java/ch/cyberduck/core/preferences/Preferences.java +++ b/core/src/main/java/ch/cyberduck/core/preferences/Preferences.java @@ -62,6 +62,7 @@ import ch.cyberduck.core.urlhandler.DisabledSchemeHandler; import ch.cyberduck.core.vault.DefaultVaultRegistry; import ch.cyberduck.core.vault.DisabledVault; +import ch.cyberduck.core.vault.DisabledVaultProvider; import ch.cyberduck.core.webloc.InternetShortcutFileWriter; import ch.cyberduck.ui.quicklook.ApplicationLauncherQuicklook; @@ -547,6 +548,7 @@ protected void setFactories() { this.setDefault("factory.threadpool.class", DefaultThreadPool.class.getName()); this.setDefault("factory.urlfilewriter.class", InternetShortcutFileWriter.class.getName()); this.setDefault("factory.vault.class", DisabledVault.class.getName()); + this.setDefault("factory.vaultprovider.class", DisabledVaultProvider.class.getName()); this.setDefault("factory.vaultregistry.class", DefaultVaultRegistry.class.getName()); this.setDefault("factory.securerandom.class", DefaultSecureRandomProvider.class.getName()); this.setDefault("factory.providerhelpservice.class", DefaultProviderHelpService.class.getName()); diff --git a/osx/src/main/java/ch/cyberduck/ui/cocoa/ApplicationUserDefaultsPreferences.java b/osx/src/main/java/ch/cyberduck/ui/cocoa/ApplicationUserDefaultsPreferences.java index 311746e7144..bd963836af1 100644 --- a/osx/src/main/java/ch/cyberduck/ui/cocoa/ApplicationUserDefaultsPreferences.java +++ b/osx/src/main/java/ch/cyberduck/ui/cocoa/ApplicationUserDefaultsPreferences.java @@ -104,7 +104,7 @@ protected void setFactories() { this.setDefault("factory.transferpromptcallback.copy.class", CopyPromptController.class.getName()); this.setDefault("factory.transferpromptcallback.sync.class", SyncPromptController.class.getName()); this.setDefault("factory.rendezvous.class", RendezvousResponder.class.getName()); - this.setDefault("factory.vault.class", CryptoVaultProvider.class.getName()); + this.setDefault("factory.vaultprovider.class", CryptoVaultProvider.class.getName()); this.setDefault("factory.securerandom.class", FastSecureRandomProvider.class.getName()); } } diff --git a/windows/src/main/csharp/ch/cyberduck/ui/core/preferences/ApplicationPreferences.cs b/windows/src/main/csharp/ch/cyberduck/ui/core/preferences/ApplicationPreferences.cs index 24a00dd7e6c..41fb2d27260 100644 --- a/windows/src/main/csharp/ch/cyberduck/ui/core/preferences/ApplicationPreferences.cs +++ b/windows/src/main/csharp/ch/cyberduck/ui/core/preferences/ApplicationPreferences.cs @@ -118,6 +118,7 @@ protected override void setFactories() this.setDefault("factory.updater.class", typeof(WinSparklePeriodicUpdateChecker).AssemblyQualifiedName); } this.setDefault("factory.vault.class", typeof(CryptoVault).AssemblyQualifiedName); + this.setDefault("factory.vaultprovider.class", typeof(CryptoVaultProvider).AssemblyQualifiedName); this.setDefault("factory.securerandom.class", typeof(FastSecureRandomProvider).AssemblyQualifiedName); this.setDefault("factory.pasteboardservice.class", typeof(ClipboardService).AssemblyQualifiedName); } From bb779fe48f8d2f3a261d8d3a4e85a9033e4b7a88 Mon Sep 17 00:00:00 2001 From: Yves Langisch Date: Wed, 29 Oct 2025 21:35:06 +0100 Subject: [PATCH 08/12] FilenameEncryptor already adds extension. --- .../core/cryptomator/impl/CryptoDirectoryUVFProvider.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/impl/CryptoDirectoryUVFProvider.java b/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/impl/CryptoDirectoryUVFProvider.java index 4ea8fa352ee..4446018523e 100644 --- a/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/impl/CryptoDirectoryUVFProvider.java +++ b/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/impl/CryptoDirectoryUVFProvider.java @@ -49,7 +49,7 @@ public CryptoDirectoryUVFProvider(final AbstractVault vault, final CryptoFilenam public String toEncrypted(final Session session, final Path parent, final String filename, final EnumSet type) throws BackgroundException { final DirectoryMetadata dirMetadata = load(session, parent); this.vault.getCryptor().directoryContentCryptor().fileNameEncryptor(dirMetadata).encrypt(filename); - final String ciphertextName = this.vault.getCryptor().directoryContentCryptor().fileNameEncryptor(dirMetadata).encrypt(filename) + vault.getRegularFileExtension(); + final String ciphertextName = this.vault.getCryptor().directoryContentCryptor().fileNameEncryptor(dirMetadata).encrypt(filename); log.debug("Encrypted filename {} to {}", filename, ciphertextName); return filenameProvider.deflate(session, ciphertextName); } From c42bc4ad1c51ef2d41683e2486fc8f5fcd956343 Mon Sep 17 00:00:00 2001 From: Yves Langisch Date: Fri, 31 Oct 2025 15:34:24 +0100 Subject: [PATCH 09/12] Add JWKCallback to decrypt keys. --- core/pom.xml | 9 +++++ .../ch/cyberduck/core/features/Vault.java | 2 +- .../cyberduck/core/vault/DisabledVault.java | 2 +- .../ch/cyberduck/core/vault/JWKCallback.java | 36 +++++++++++++++++++ .../cyberduck/core/vault/JWKCredentials.java | 32 +++++++++++++++++ .../vault/LoadingVaultLookupListener.java | 4 ++- .../core/vault/VaultMetadataProvider.java | 5 +-- .../cryptomator/impl/uvf/CryptoVault.java | 32 ++++++++++------- .../core/cryptomator/impl/v8/CryptoVault.java | 2 +- .../features/CryptoReadFeatureTest.java | 3 ++ .../impl/CryptoDirectoryV8ProviderTest.java | 2 ++ .../cryptomator/impl/v8/CryptoVaultTest.java | 7 ++++ .../core/cryptomator/UVFIntegrationTest.java | 2 ++ .../SFTPCryptomatorInteroperabilityTest.java | 3 ++ 14 files changed, 121 insertions(+), 20 deletions(-) create mode 100644 core/src/main/java/ch/cyberduck/core/vault/JWKCallback.java create mode 100644 core/src/main/java/ch/cyberduck/core/vault/JWKCredentials.java diff --git a/core/pom.xml b/core/pom.xml index 06df3b30177..4eb11711906 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -23,6 +23,10 @@ core jar + + 10.5 + + @@ -144,6 +148,11 @@ auto-service-annotations 1.1.1 + + com.nimbusds + nimbus-jose-jwt + ${nimbus-jose.version} + junit junit diff --git a/core/src/main/java/ch/cyberduck/core/features/Vault.java b/core/src/main/java/ch/cyberduck/core/features/Vault.java index 3f6d75082e8..1ad7a427340 100644 --- a/core/src/main/java/ch/cyberduck/core/features/Vault.java +++ b/core/src/main/java/ch/cyberduck/core/features/Vault.java @@ -47,7 +47,7 @@ public interface Vault { * @throws BackgroundException Failure reading master key from server * @throws NotfoundException No master key file in home */ - Vault load(Session session, PasswordCallback prompt) throws BackgroundException; + Vault load(Session session, PasswordCallback prompt, VaultMetadataProvider provider) throws BackgroundException; /** * Close vault diff --git a/core/src/main/java/ch/cyberduck/core/vault/DisabledVault.java b/core/src/main/java/ch/cyberduck/core/vault/DisabledVault.java index 1e0c636f3aa..f252220feff 100644 --- a/core/src/main/java/ch/cyberduck/core/vault/DisabledVault.java +++ b/core/src/main/java/ch/cyberduck/core/vault/DisabledVault.java @@ -42,7 +42,7 @@ public Vault create(final Session session, final String region, final VaultMe } @Override - public Vault load(final Session session, final PasswordCallback prompt) { + public Vault load(final Session session, final PasswordCallback prompt, final VaultMetadataProvider provider) { return this; } diff --git a/core/src/main/java/ch/cyberduck/core/vault/JWKCallback.java b/core/src/main/java/ch/cyberduck/core/vault/JWKCallback.java new file mode 100644 index 00000000000..ce5b2e06926 --- /dev/null +++ b/core/src/main/java/ch/cyberduck/core/vault/JWKCallback.java @@ -0,0 +1,36 @@ +package ch.cyberduck.core.vault; + +/* + * Copyright (c) 2002-2025 iterate GmbH. All rights reserved. + * https://cyberduck.io/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +import ch.cyberduck.core.Host; +import ch.cyberduck.core.LoginOptions; +import ch.cyberduck.core.PasswordCallback; +import ch.cyberduck.core.exception.LoginCanceledException; + +public interface JWKCallback extends PasswordCallback { + + @Override + JWKCredentials prompt(Host bookmark, String title, String reason, LoginOptions options) throws LoginCanceledException; + + static JWKCallback cast(PasswordCallback callback) { + if(callback instanceof JWKCallback) { + return (JWKCallback) callback; + } + else { + throw new IllegalArgumentException("Unsupported metadata type " + callback.getClass()); + } + } +} diff --git a/core/src/main/java/ch/cyberduck/core/vault/JWKCredentials.java b/core/src/main/java/ch/cyberduck/core/vault/JWKCredentials.java new file mode 100644 index 00000000000..b972cd7116c --- /dev/null +++ b/core/src/main/java/ch/cyberduck/core/vault/JWKCredentials.java @@ -0,0 +1,32 @@ +package ch.cyberduck.core.vault; + +/* + * Copyright (c) 2002-2025 iterate GmbH. All rights reserved. + * https://cyberduck.io/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +import com.nimbusds.jose.jwk.JWK; + +public class JWKCredentials extends VaultCredentials { + + private final JWK key; + + public JWKCredentials(final JWK key) { + super(null); + this.key = key; + } + + public JWK getKey() { + return key; + } +} diff --git a/core/src/main/java/ch/cyberduck/core/vault/LoadingVaultLookupListener.java b/core/src/main/java/ch/cyberduck/core/vault/LoadingVaultLookupListener.java index 49ed4fb9d3d..3d9299f2cc6 100644 --- a/core/src/main/java/ch/cyberduck/core/vault/LoadingVaultLookupListener.java +++ b/core/src/main/java/ch/cyberduck/core/vault/LoadingVaultLookupListener.java @@ -43,7 +43,9 @@ public Vault load(final Session session, final VaultMetadata metadata) throws Va log.info("Loading vault for session {}", session); final Vault vault = VaultProviderFactory.get(session).provide(session, metadata); try { - registry.add(vault.load(session, prompt)); + // TODO provide correct metadata provider + registry.add(vault.load(session, prompt, new VaultMetadataProvider() { + })); return vault; } catch(BackgroundException e) { diff --git a/core/src/main/java/ch/cyberduck/core/vault/VaultMetadataProvider.java b/core/src/main/java/ch/cyberduck/core/vault/VaultMetadataProvider.java index ce7465b4195..095e0376e08 100644 --- a/core/src/main/java/ch/cyberduck/core/vault/VaultMetadataProvider.java +++ b/core/src/main/java/ch/cyberduck/core/vault/VaultMetadataProvider.java @@ -16,8 +16,5 @@ */ public interface VaultMetadataProvider { - - //Map metadataFiles() throws BackgroundException; - - //String dirPath(); + // Marker interface } diff --git a/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/impl/uvf/CryptoVault.java b/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/impl/uvf/CryptoVault.java index 386dc3a554a..f47c6842e78 100644 --- a/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/impl/uvf/CryptoVault.java +++ b/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/impl/uvf/CryptoVault.java @@ -15,7 +15,6 @@ * GNU General Public License for more details. */ -import ch.cyberduck.core.LocaleFactory; import ch.cyberduck.core.LoginOptions; import ch.cyberduck.core.PasswordCallback; import ch.cyberduck.core.Path; @@ -38,9 +37,12 @@ import ch.cyberduck.core.features.Write; import ch.cyberduck.core.preferences.PreferencesFactory; import ch.cyberduck.core.transfer.TransferStatus; +import ch.cyberduck.core.vault.JWKCallback; +import ch.cyberduck.core.vault.VaultException; import ch.cyberduck.core.vault.VaultMetadata; import ch.cyberduck.core.vault.VaultMetadataProvider; +import org.apache.commons.lang3.StringUtils; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.cryptomator.cryptolib.api.Cryptor; @@ -51,12 +53,16 @@ import org.cryptomator.cryptolib.api.RevolvingMasterkey; import org.cryptomator.cryptolib.api.UVFMasterkey; -import java.text.MessageFormat; +import java.nio.charset.StandardCharsets; +import java.text.ParseException; import java.util.EnumSet; import java.util.Objects; import java.util.regex.Pattern; import com.google.auto.service.AutoService; +import com.nimbusds.jose.JOSEException; +import com.nimbusds.jose.JWEObjectJSON; +import com.nimbusds.jose.crypto.MultiDecrypter; @AutoService(Vault.class) public class CryptoVault extends AbstractVault { @@ -123,16 +129,18 @@ public AbstractVault create(final Session session, final String region, final // load -> unlock -> open @Override - public CryptoVault load(final Session session, final PasswordCallback prompt) throws BackgroundException { - masterKey = UVFMasterkey.fromDecryptedPayload(prompt.prompt(session.getHost(), - LocaleFactory.localizedString("Unlock Vault", "Cryptomator"), - MessageFormat.format(LocaleFactory.localizedString("Provide your passphrase to unlock the Cryptomator Vault {0}", "Cryptomator"), home.getName()), - new LoginOptions() - .save(false) - .user(false) - .anonymous(false) - .icon("cryptomator.tiff") - .passwordPlaceholder(LocaleFactory.localizedString("Passphrase", "Cryptomator"))).getPassword()); + public CryptoVault load(final Session session, final PasswordCallback callback, final VaultMetadataProvider metadata) throws BackgroundException { + final JWKCallback jwk = JWKCallback.cast(callback); + final VaultMetadataUVFProvider metadataProvider = VaultMetadataUVFProvider.cast(metadata); + final JWEObjectJSON jweObject; + try { + jweObject = JWEObjectJSON.parse(new String(metadataProvider.getMetadata(), StandardCharsets.US_ASCII)); + jweObject.decrypt(new MultiDecrypter(jwk.prompt(session.getHost(), StringUtils.EMPTY, StringUtils.EMPTY, new LoginOptions()).getKey())); + } + catch(ParseException | JOSEException e) { + throw new VaultException("Failure retrieving key material", e); + } + masterKey = UVFMasterkey.fromDecryptedPayload(jweObject.getPayload().toString()); final CryptorProvider provider = CryptorProvider.forScheme(CryptorProvider.Scheme.UVF_DRAFT); log.debug("Initialized crypto provider {}", provider); this.cryptor = provider.provide(masterKey, FastSecureRandomProvider.get().provide()); diff --git a/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/impl/v8/CryptoVault.java b/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/impl/v8/CryptoVault.java index 517ae983c8b..1d6520dae30 100644 --- a/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/impl/v8/CryptoVault.java +++ b/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/impl/v8/CryptoVault.java @@ -279,7 +279,7 @@ private static VaultConfig parseVaultConfigFromMasterKey(final MasterkeyFile mas } @Override - public Vault load(final Session session, final PasswordCallback prompt) throws BackgroundException { + public Vault load(final Session session, final PasswordCallback prompt, final VaultMetadataProvider provider) throws BackgroundException { final Host bookmark = session.getHost(); String passphrase = keychain.getPassword(String.format("Cryptomator Passphrase (%s)", bookmark.getCredentials().getUsername()), new DefaultUrlProvider(bookmark).toUrl(masterkeyPath, EnumSet.of(DescriptiveUrl.Type.provider)).find(DescriptiveUrl.Type.provider).getUrl()); diff --git a/cryptomator/src/test/java/ch/cyberduck/core/cryptomator/features/CryptoReadFeatureTest.java b/cryptomator/src/test/java/ch/cyberduck/core/cryptomator/features/CryptoReadFeatureTest.java index 74863a1eaf3..fd719bfdad9 100644 --- a/cryptomator/src/test/java/ch/cyberduck/core/cryptomator/features/CryptoReadFeatureTest.java +++ b/cryptomator/src/test/java/ch/cyberduck/core/cryptomator/features/CryptoReadFeatureTest.java @@ -29,6 +29,7 @@ import ch.cyberduck.core.features.Read; import ch.cyberduck.core.transfer.TransferStatus; import ch.cyberduck.core.vault.VaultCredentials; +import ch.cyberduck.core.vault.VaultMetadataProvider; import org.apache.commons.io.IOUtils; import org.cryptomator.cryptolib.api.CryptorProvider; @@ -87,6 +88,7 @@ public Credentials prompt(final Host bookmark, final String title, final String final LoginOptions options) { return new VaultCredentials("vault"); } + }, new VaultMetadataProvider() { }). getHome()); @@ -162,6 +164,7 @@ public boolean offset(final Path file) { public Credentials prompt(final Host bookmark, final String title, final String reason, final LoginOptions options) { return new VaultCredentials("vault"); } + }, new VaultMetadataProvider() { }).getHome()); CryptoReadFeature read = new CryptoReadFeature(null, null, vault); { diff --git a/cryptomator/src/test/java/ch/cyberduck/core/cryptomator/impl/CryptoDirectoryV8ProviderTest.java b/cryptomator/src/test/java/ch/cyberduck/core/cryptomator/impl/CryptoDirectoryV8ProviderTest.java index 866d98a1a0f..9cf9fff1555 100644 --- a/cryptomator/src/test/java/ch/cyberduck/core/cryptomator/impl/CryptoDirectoryV8ProviderTest.java +++ b/cryptomator/src/test/java/ch/cyberduck/core/cryptomator/impl/CryptoDirectoryV8ProviderTest.java @@ -31,6 +31,7 @@ import ch.cyberduck.core.features.Read; import ch.cyberduck.core.transfer.TransferStatus; import ch.cyberduck.core.vault.VaultCredentials; +import ch.cyberduck.core.vault.VaultMetadataProvider; import org.apache.commons.io.IOUtils; import org.cryptomator.cryptolib.api.CryptorProvider; @@ -111,6 +112,7 @@ public boolean offset(final Path file) { public Credentials prompt(final Host bookmark, final String title, final String reason, final LoginOptions options) { return new VaultCredentials("vault123"); } + }, new VaultMetadataProvider() { }); final CryptoDirectory provider = new CryptoDirectoryV8Provider(vault, new CryptoFilenameV7Provider()); assertNotNull(provider.toEncrypted(session, home)); diff --git a/cryptomator/src/test/java/ch/cyberduck/core/cryptomator/impl/v8/CryptoVaultTest.java b/cryptomator/src/test/java/ch/cyberduck/core/cryptomator/impl/v8/CryptoVaultTest.java index 494dbf8b510..28d68719e88 100644 --- a/cryptomator/src/test/java/ch/cyberduck/core/cryptomator/impl/v8/CryptoVaultTest.java +++ b/cryptomator/src/test/java/ch/cyberduck/core/cryptomator/impl/v8/CryptoVaultTest.java @@ -41,6 +41,7 @@ import ch.cyberduck.core.vault.DefaultVaultRegistry; import ch.cyberduck.core.vault.VaultCredentials; import ch.cyberduck.core.vault.VaultMetadata; +import ch.cyberduck.core.vault.VaultMetadataProvider; import org.apache.commons.io.IOUtils; import org.cryptomator.cryptolib.api.CryptorProvider; @@ -111,6 +112,7 @@ public boolean offset(final Path file) { public Credentials prompt(final Host bookmark, final String title, final String reason, final LoginOptions options) { return new VaultCredentials("vault123"); } + }, new VaultMetadataProvider() { }); assertTrue(vault.getFileContentCryptor().getClass().getName().contains("v2")); assertTrue(vault.getFileHeaderCryptor().getClass().getName().contains("v2")); @@ -195,6 +197,7 @@ public boolean offset(final Path file) { public Credentials prompt(final Host bookmark, final String title, final String reason, final LoginOptions options) { return new VaultCredentials("vault123"); } + }, new VaultMetadataProvider() { }).getHome()); assertTrue(vault.getFileContentCryptor().getClass().getName().contains("v2")); assertTrue(vault.getFileHeaderCryptor().getClass().getName().contains("v2")); @@ -246,6 +249,7 @@ public boolean offset(final Path file) { public Credentials prompt(final Host bookmark, final String title, final String reason, final LoginOptions options) { return new VaultCredentials("vault123"); } + }, new VaultMetadataProvider() { }).getHome()); assertEquals(Vault.State.open, vault.getState()); assertEquals(home, new PathDictionary<>().deserialize(home.serialize(SerializerFactory.get()))); @@ -305,6 +309,7 @@ public Credentials prompt(final Host bookmark, final String title, final String throw new LoginCanceledException(); } } + }, new VaultMetadataProvider() { }); fail(); } @@ -355,6 +360,7 @@ public boolean offset(final Path file) { public Credentials prompt(final Host bookmark, final String title, final String reason, final LoginOptions options) throws LoginCanceledException { throw new LoginCanceledException(); } + }, new VaultMetadataProvider() { }); fail(); } @@ -404,6 +410,7 @@ public boolean offset(final Path file) { public Credentials prompt(final Host bookmark, final String title, final String reason, final LoginOptions options) { return new VaultCredentials(null); } + }, new VaultMetadataProvider() { }); fail(); } diff --git a/s3/src/test/java/ch/cyberduck/core/cryptomator/UVFIntegrationTest.java b/s3/src/test/java/ch/cyberduck/core/cryptomator/UVFIntegrationTest.java index 58cd2dec3a6..0d33285d89c 100644 --- a/s3/src/test/java/ch/cyberduck/core/cryptomator/UVFIntegrationTest.java +++ b/s3/src/test/java/ch/cyberduck/core/cryptomator/UVFIntegrationTest.java @@ -36,6 +36,7 @@ import ch.cyberduck.core.transfer.TransferItem; import ch.cyberduck.core.transfer.TransferStatus; import ch.cyberduck.core.vault.DefaultVaultRegistry; +import ch.cyberduck.core.vault.VaultMetadataProvider; import ch.cyberduck.core.vault.VaultRegistry; import ch.cyberduck.core.worker.DeleteWorker; import ch.cyberduck.test.TestcontainerTest; @@ -142,6 +143,7 @@ public void listMinio() throws BackgroundException, IOException { public Credentials prompt(final Host bookmark, final String title, final String reason, final LoginOptions options) { return new Credentials().setPassword(jwe); } + }, new VaultMetadataProvider() { })); final PathAttributes attr = storage.getFeature(AttributesFinder.class).find(vault.getHome()); storage.withRegistry(vaults); diff --git a/ssh/src/test/java/ch/cyberduck/core/cryptomator/SFTPCryptomatorInteroperabilityTest.java b/ssh/src/test/java/ch/cyberduck/core/cryptomator/SFTPCryptomatorInteroperabilityTest.java index ad2b72444ad..0afdc151c09 100644 --- a/ssh/src/test/java/ch/cyberduck/core/cryptomator/SFTPCryptomatorInteroperabilityTest.java +++ b/ssh/src/test/java/ch/cyberduck/core/cryptomator/SFTPCryptomatorInteroperabilityTest.java @@ -40,6 +40,7 @@ import ch.cyberduck.core.vault.DefaultVaultRegistry; import ch.cyberduck.core.vault.VaultCredentials; import ch.cyberduck.core.vault.VaultMetadata; +import ch.cyberduck.core.vault.VaultMetadataProvider; import org.apache.commons.io.FileUtils; import org.apache.commons.io.IOUtils; @@ -154,6 +155,7 @@ public void testCryptomatorInteroperabilityLongFilename() throws Exception { public Credentials prompt(final Host bookmark, final String title, final String reason, final LoginOptions options) { return new VaultCredentials(passphrase); } + }, new VaultMetadataProvider() { }); session.withRegistry(new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator)); Path p = new Path(new Path(vaultPath, targetFolder.getFileName().toString(), EnumSet.of(Path.Type.directory)), targetFile.getFileName().toString(), EnumSet.of(Path.Type.file)); @@ -189,6 +191,7 @@ public void testCryptomatorInteroperability() throws Exception { public Credentials prompt(final Host bookmark, final String title, final String reason, final LoginOptions options) { return new VaultCredentials(passphrase); } + }, new VaultMetadataProvider() { }); session.withRegistry(new DefaultVaultRegistry(new DisabledPasswordCallback(), cryptomator)); Path p = new Path(new Path(vaultPath, targetFolder.getFileName().toString(), EnumSet.of(Path.Type.directory)), targetFile.getFileName().toString(), EnumSet.of(Path.Type.file)); From b27f3a228e04b2cb3630a6b5cd38b95f4ade0b13 Mon Sep 17 00:00:00 2001 From: chenkins Date: Thu, 20 Nov 2025 15:25:22 +0100 Subject: [PATCH 10/12] Fix uvf spec.version. --- .../cryptomator/impl/uvf/CryptoVault.java | 38 ++++++++++++++++--- 1 file changed, 32 insertions(+), 6 deletions(-) diff --git a/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/impl/uvf/CryptoVault.java b/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/impl/uvf/CryptoVault.java index f47c6842e78..48cde9ea3cc 100644 --- a/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/impl/uvf/CryptoVault.java +++ b/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/impl/uvf/CryptoVault.java @@ -55,19 +55,25 @@ import java.nio.charset.StandardCharsets; import java.text.ParseException; +import java.util.Collections; import java.util.EnumSet; import java.util.Objects; import java.util.regex.Pattern; +import com.fasterxml.jackson.core.JsonProcessingException; import com.google.auto.service.AutoService; import com.nimbusds.jose.JOSEException; import com.nimbusds.jose.JWEObjectJSON; +import com.nimbusds.jose.Payload; import com.nimbusds.jose.crypto.MultiDecrypter; +import com.nimbusds.jose.jwk.JWK; @AutoService(Vault.class) public class CryptoVault extends AbstractVault { private static final Logger log = LogManager.getLogger(CryptoVault.class); + private static final String UVF_SPEC_VERSION_KEY_PARAM = "uvf.spec.version"; + private static final String REGULAR_FILE_EXTENSION = ".uvf"; private static final String FILENAME_DIRECTORYID = "dir"; private static final String DIRECTORY_METADATA_FILENAME = String.format("%s%s", FILENAME_DIRECTORYID, REGULAR_FILE_EXTENSION); @@ -127,20 +133,40 @@ public AbstractVault create(final Session session, final String region, final return this; } + public static String decryptWithJWK(final String jwe, final JWK jwk) throws ParseException, JOSEException, JsonProcessingException, VaultException { + final JWEObjectJSON jweObject = JWEObjectJSON.parse(jwe); + jweObject.decrypt(new MultiDecrypter(jwk, Collections.singleton(UVF_SPEC_VERSION_KEY_PARAM))); + + // https://datatracker.ietf.org/doc/html/rfc7515#section-4.1.11 + // Recipients MAY consider the JWS to be invalid if the critical + // list contains any Header Parameter names defined by this + // specification or [JWA] for use with JWS or if any other constraints on its use are violated. + final Object uvfSpecVersion = jweObject.getHeader().getCustomParams().get(UVF_SPEC_VERSION_KEY_PARAM); + if(uvfSpecVersion.equals(1)) { + throw new VaultException(String.format("Unexpected value for critical header %s: found %s, expected \"1\"", UVF_SPEC_VERSION_KEY_PARAM, uvfSpecVersion)); + } + + final Payload payload = jweObject.getPayload(); + return payload.toString(); + } + + // load -> unlock -> open @Override public CryptoVault load(final Session session, final PasswordCallback callback, final VaultMetadataProvider metadata) throws BackgroundException { - final JWKCallback jwk = JWKCallback.cast(callback); + final JWKCallback jwkCallback = JWKCallback.cast(callback); final VaultMetadataUVFProvider metadataProvider = VaultMetadataUVFProvider.cast(metadata); - final JWEObjectJSON jweObject; + final String uvfMetadata; try { - jweObject = JWEObjectJSON.parse(new String(metadataProvider.getMetadata(), StandardCharsets.US_ASCII)); - jweObject.decrypt(new MultiDecrypter(jwk.prompt(session.getHost(), StringUtils.EMPTY, StringUtils.EMPTY, new LoginOptions()).getKey())); + final String jwe = new String(metadataProvider.getMetadata(), StandardCharsets.US_ASCII); + final JWK jwk = jwkCallback.prompt(session.getHost(), StringUtils.EMPTY, StringUtils.EMPTY, new LoginOptions()).getKey(); + uvfMetadata = decryptWithJWK(jwe, jwk); } - catch(ParseException | JOSEException e) { + catch(ParseException | JOSEException | JsonProcessingException e) { throw new VaultException("Failure retrieving key material", e); } - masterKey = UVFMasterkey.fromDecryptedPayload(jweObject.getPayload().toString()); + + masterKey = UVFMasterkey.fromDecryptedPayload(uvfMetadata); final CryptorProvider provider = CryptorProvider.forScheme(CryptorProvider.Scheme.UVF_DRAFT); log.debug("Initialized crypto provider {}", provider); this.cryptor = provider.provide(masterKey, FastSecureRandomProvider.get().provide()); From 14babb4e8167d8a14eb4cebc9cadb51ab3c3b5a5 Mon Sep 17 00:00:00 2001 From: David Kocher Date: Mon, 24 Nov 2025 18:44:13 +0100 Subject: [PATCH 11/12] Remove spec version validation. This partially reverts commit 159cad06c6764f6401ebde8632397ef819ad8688. --- .../cryptomator/impl/uvf/CryptoVault.java | 26 ++++--------------- 1 file changed, 5 insertions(+), 21 deletions(-) diff --git a/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/impl/uvf/CryptoVault.java b/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/impl/uvf/CryptoVault.java index 48cde9ea3cc..92740e80b7f 100644 --- a/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/impl/uvf/CryptoVault.java +++ b/cryptomator/src/main/java/ch/cyberduck/core/cryptomator/impl/uvf/CryptoVault.java @@ -60,7 +60,6 @@ import java.util.Objects; import java.util.regex.Pattern; -import com.fasterxml.jackson.core.JsonProcessingException; import com.google.auto.service.AutoService; import com.nimbusds.jose.JOSEException; import com.nimbusds.jose.JWEObjectJSON; @@ -133,24 +132,6 @@ public AbstractVault create(final Session session, final String region, final return this; } - public static String decryptWithJWK(final String jwe, final JWK jwk) throws ParseException, JOSEException, JsonProcessingException, VaultException { - final JWEObjectJSON jweObject = JWEObjectJSON.parse(jwe); - jweObject.decrypt(new MultiDecrypter(jwk, Collections.singleton(UVF_SPEC_VERSION_KEY_PARAM))); - - // https://datatracker.ietf.org/doc/html/rfc7515#section-4.1.11 - // Recipients MAY consider the JWS to be invalid if the critical - // list contains any Header Parameter names defined by this - // specification or [JWA] for use with JWS or if any other constraints on its use are violated. - final Object uvfSpecVersion = jweObject.getHeader().getCustomParams().get(UVF_SPEC_VERSION_KEY_PARAM); - if(uvfSpecVersion.equals(1)) { - throw new VaultException(String.format("Unexpected value for critical header %s: found %s, expected \"1\"", UVF_SPEC_VERSION_KEY_PARAM, uvfSpecVersion)); - } - - final Payload payload = jweObject.getPayload(); - return payload.toString(); - } - - // load -> unlock -> open @Override public CryptoVault load(final Session session, final PasswordCallback callback, final VaultMetadataProvider metadata) throws BackgroundException { @@ -160,9 +141,12 @@ public CryptoVault load(final Session session, final PasswordCallback callbac try { final String jwe = new String(metadataProvider.getMetadata(), StandardCharsets.US_ASCII); final JWK jwk = jwkCallback.prompt(session.getHost(), StringUtils.EMPTY, StringUtils.EMPTY, new LoginOptions()).getKey(); - uvfMetadata = decryptWithJWK(jwe, jwk); + final JWEObjectJSON jweObject = JWEObjectJSON.parse(jwe); + jweObject.decrypt(new MultiDecrypter(jwk, Collections.singleton(UVF_SPEC_VERSION_KEY_PARAM))); + final Payload payload = jweObject.getPayload(); + uvfMetadata = payload.toString(); } - catch(ParseException | JOSEException | JsonProcessingException e) { + catch(ParseException | JOSEException e) { throw new VaultException("Failure retrieving key material", e); } From 0db60a271111f67248c36b14dda2f83d0644cee0 Mon Sep 17 00:00:00 2001 From: David Kocher Date: Thu, 27 Nov 2025 15:19:29 +0100 Subject: [PATCH 12/12] Set snapshot version. --- azure/pom.xml | 2 +- backblaze/pom.xml | 2 +- binding/pom.xml | 2 +- bonjour/dll/pom.xml | 2 +- bonjour/native/pom.xml | 2 +- bonjour/pom.xml | 2 +- box/pom.xml | 2 +- brick/pom.xml | 2 +- cli/dll/pom.xml | 2 +- cli/linux/pom.xml | 2 +- cli/osx/pom.xml | 2 +- cli/pom.xml | 2 +- cli/windows/pom.xml | 2 +- core/dll/pom.xml | 2 +- core/dylib/pom.xml | 2 +- core/native/pom.xml | 2 +- core/native/refresh/pom.xml | 2 +- core/pom.xml | 2 +- cryptomator/dll/pom.xml | 2 +- cryptomator/pom.xml | 2 +- ctera/pom.xml | 2 +- deepbox/pom.xml | 2 +- defaults/pom.xml | 2 +- dracoon/pom.xml | 2 +- dropbox/pom.xml | 2 +- eue/pom.xml | 2 +- freenet/pom.xml | 2 +- ftp/pom.xml | 2 +- googledrive/pom.xml | 2 +- googlestorage/pom.xml | 2 +- hubic/pom.xml | 2 +- i18n/pom.xml | 2 +- importer/dll/pom.xml | 2 +- importer/pom.xml | 2 +- irods/pom.xml | 2 +- jersey/pom.xml | 2 +- manta/pom.xml | 2 +- nextcloud/pom.xml | 2 +- nio/pom.xml | 2 +- oauth/pom.xml | 2 +- onedrive/pom.xml | 2 +- openstack/pom.xml | 2 +- osx/pom.xml | 2 +- owncloud/pom.xml | 2 +- pom.xml | 2 +- profiles/pom.xml | 2 +- protocols/dll/pom.xml | 2 +- protocols/pom.xml | 2 +- s3/pom.xml | 2 +- smb/pom.xml | 2 +- spectra/pom.xml | 2 +- ssh/pom.xml | 2 +- storegate/pom.xml | 2 +- test/pom.xml | 2 +- tus/pom.xml | 2 +- webdav/pom.xml | 2 +- windows/pom.xml | 2 +- 57 files changed, 57 insertions(+), 57 deletions(-) diff --git a/azure/pom.xml b/azure/pom.xml index 5809b9bfd6c..1e0d96a282d 100644 --- a/azure/pom.xml +++ b/azure/pom.xml @@ -18,7 +18,7 @@ ch.cyberduck parent - 9.3.1-SNAPSHOT + 9.3.0.uvfdraft.cryptolib-SNAPSHOT azure diff --git a/backblaze/pom.xml b/backblaze/pom.xml index c5225771f68..942aa94a055 100644 --- a/backblaze/pom.xml +++ b/backblaze/pom.xml @@ -19,7 +19,7 @@ parent ch.cyberduck - 9.3.1-SNAPSHOT + 9.3.0.uvfdraft.cryptolib-SNAPSHOT backblaze jar diff --git a/binding/pom.xml b/binding/pom.xml index 4c9eb5e3b3c..e15d03cf9de 100644 --- a/binding/pom.xml +++ b/binding/pom.xml @@ -19,7 +19,7 @@ ch.cyberduck parent - 9.3.1-SNAPSHOT + 9.3.0.uvfdraft.cryptolib-SNAPSHOT binding jar diff --git a/bonjour/dll/pom.xml b/bonjour/dll/pom.xml index ec4d0c65b58..4fa93806c42 100644 --- a/bonjour/dll/pom.xml +++ b/bonjour/dll/pom.xml @@ -5,7 +5,7 @@ ch.cyberduck parent ../../pom.xml - 9.3.1-SNAPSHOT + 9.3.0.uvfdraft.cryptolib-SNAPSHOT Cyberduck.Bonjour pom diff --git a/bonjour/native/pom.xml b/bonjour/native/pom.xml index 6a772e1be45..37e30fadc52 100644 --- a/bonjour/native/pom.xml +++ b/bonjour/native/pom.xml @@ -5,7 +5,7 @@ ch.cyberduck parent ../../pom.xml - 9.3.1-SNAPSHOT + 9.3.0.uvfdraft.cryptolib-SNAPSHOT Cyberduck.Bonjour.Native pom diff --git a/bonjour/pom.xml b/bonjour/pom.xml index 13f87078ea3..2c27a2ccb1b 100644 --- a/bonjour/pom.xml +++ b/bonjour/pom.xml @@ -18,7 +18,7 @@ parent ch.cyberduck - 9.3.1-SNAPSHOT + 9.3.0.uvfdraft.cryptolib-SNAPSHOT 4.0.0 diff --git a/box/pom.xml b/box/pom.xml index 82a4c915727..da509e71996 100644 --- a/box/pom.xml +++ b/box/pom.xml @@ -19,7 +19,7 @@ parent ch.cyberduck - 9.3.1-SNAPSHOT + 9.3.0.uvfdraft.cryptolib-SNAPSHOT box diff --git a/brick/pom.xml b/brick/pom.xml index 37875063900..3a636158dd8 100644 --- a/brick/pom.xml +++ b/brick/pom.xml @@ -18,7 +18,7 @@ ch.cyberduck parent - 9.3.1-SNAPSHOT + 9.3.0.uvfdraft.cryptolib-SNAPSHOT brick jar diff --git a/cli/dll/pom.xml b/cli/dll/pom.xml index 82ad4cdaafe..2a297b94fdf 100644 --- a/cli/dll/pom.xml +++ b/cli/dll/pom.xml @@ -20,7 +20,7 @@ ch.cyberduck parent ../../pom.xml - 9.3.1-SNAPSHOT + 9.3.0.uvfdraft.cryptolib-SNAPSHOT Cyberduck.Cli pom diff --git a/cli/linux/pom.xml b/cli/linux/pom.xml index 3f503749ae3..a97ffa4f530 100644 --- a/cli/linux/pom.xml +++ b/cli/linux/pom.xml @@ -20,7 +20,7 @@ ch.cyberduck parent ../../pom.xml - 9.3.1-SNAPSHOT + 9.3.0.uvfdraft.cryptolib-SNAPSHOT cli-linux Cyberduck CLI Linux diff --git a/cli/osx/pom.xml b/cli/osx/pom.xml index e91c536e859..c23ff531896 100644 --- a/cli/osx/pom.xml +++ b/cli/osx/pom.xml @@ -20,7 +20,7 @@ ch.cyberduck parent ../../pom.xml - 9.3.1-SNAPSHOT + 9.3.0.uvfdraft.cryptolib-SNAPSHOT cli-osx Cyberduck CLI Mac diff --git a/cli/pom.xml b/cli/pom.xml index a7588457b01..03a7729f2bf 100644 --- a/cli/pom.xml +++ b/cli/pom.xml @@ -19,7 +19,7 @@ ch.cyberduck parent - 9.3.1-SNAPSHOT + 9.3.0.uvfdraft.cryptolib-SNAPSHOT cli diff --git a/cli/windows/pom.xml b/cli/windows/pom.xml index 66438ead729..9ab75e81c5d 100644 --- a/cli/windows/pom.xml +++ b/cli/windows/pom.xml @@ -20,7 +20,7 @@ ch.cyberduck parent ../../pom.xml - 9.3.1-SNAPSHOT + 9.3.0.uvfdraft.cryptolib-SNAPSHOT cli-windows Cyberduck CLI Windows diff --git a/core/dll/pom.xml b/core/dll/pom.xml index de89cae774c..4a01caead0d 100644 --- a/core/dll/pom.xml +++ b/core/dll/pom.xml @@ -5,7 +5,7 @@ ch.cyberduck parent ../../pom.xml - 9.3.1-SNAPSHOT + 9.3.0.uvfdraft.cryptolib-SNAPSHOT Cyberduck.Core pom diff --git a/core/dylib/pom.xml b/core/dylib/pom.xml index 1eafb526a82..398eee705a8 100644 --- a/core/dylib/pom.xml +++ b/core/dylib/pom.xml @@ -5,7 +5,7 @@ ch.cyberduck parent ../../pom.xml - 9.3.1-SNAPSHOT + 9.3.0.uvfdraft.cryptolib-SNAPSHOT libcore diff --git a/core/native/pom.xml b/core/native/pom.xml index 3997223d31f..f36b59cefeb 100644 --- a/core/native/pom.xml +++ b/core/native/pom.xml @@ -5,7 +5,7 @@ ch.cyberduck parent ../../pom.xml - 9.3.1-SNAPSHOT + 9.3.0.uvfdraft.cryptolib-SNAPSHOT Cyberduck.Core.Native pom diff --git a/core/native/refresh/pom.xml b/core/native/refresh/pom.xml index 8c20c2c0ee8..8d0474d5892 100644 --- a/core/native/refresh/pom.xml +++ b/core/native/refresh/pom.xml @@ -5,7 +5,7 @@ ch.cyberduck Cyberduck.Core.Native ../pom.xml - 9.3.1-SNAPSHOT + 9.3.0.uvfdraft.cryptolib-SNAPSHOT Cyberduck.Core.Refresh pom diff --git a/core/pom.xml b/core/pom.xml index 4eb11711906..4e62f705f2e 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -18,7 +18,7 @@ ch.cyberduck parent - 9.3.1-SNAPSHOT + 9.3.0.uvfdraft.cryptolib-SNAPSHOT core jar diff --git a/cryptomator/dll/pom.xml b/cryptomator/dll/pom.xml index 9cc40566316..310f49d9d1a 100644 --- a/cryptomator/dll/pom.xml +++ b/cryptomator/dll/pom.xml @@ -20,7 +20,7 @@ ch.cyberduck parent ../../pom.xml - 9.3.1-SNAPSHOT + 9.3.0.uvfdraft.cryptolib-SNAPSHOT Cyberduck.Cryptomator pom diff --git a/cryptomator/pom.xml b/cryptomator/pom.xml index fa588993b71..ec66f62f008 100644 --- a/cryptomator/pom.xml +++ b/cryptomator/pom.xml @@ -19,7 +19,7 @@ parent ch.cyberduck - 9.3.1-SNAPSHOT + 9.3.0.uvfdraft.cryptolib-SNAPSHOT cryptomator jar diff --git a/ctera/pom.xml b/ctera/pom.xml index be531cea88e..032c6818ab7 100644 --- a/ctera/pom.xml +++ b/ctera/pom.xml @@ -18,7 +18,7 @@ ch.cyberduck parent - 9.3.1-SNAPSHOT + 9.3.0.uvfdraft.cryptolib-SNAPSHOT ctera jar diff --git a/deepbox/pom.xml b/deepbox/pom.xml index 4884408091d..056fa4db5d7 100644 --- a/deepbox/pom.xml +++ b/deepbox/pom.xml @@ -19,7 +19,7 @@ parent ch.cyberduck - 9.3.1-SNAPSHOT + 9.3.0.uvfdraft.cryptolib-SNAPSHOT deepbox diff --git a/defaults/pom.xml b/defaults/pom.xml index 088aad2646b..288193754ca 100644 --- a/defaults/pom.xml +++ b/defaults/pom.xml @@ -19,7 +19,7 @@ parent ch.cyberduck - 9.3.1-SNAPSHOT + 9.3.0.uvfdraft.cryptolib-SNAPSHOT defaults diff --git a/dracoon/pom.xml b/dracoon/pom.xml index 318de4c105c..c42aabe7322 100644 --- a/dracoon/pom.xml +++ b/dracoon/pom.xml @@ -19,7 +19,7 @@ parent ch.cyberduck - 9.3.1-SNAPSHOT + 9.3.0.uvfdraft.cryptolib-SNAPSHOT dracoon diff --git a/dropbox/pom.xml b/dropbox/pom.xml index 8d510d008bd..ac934f31f3b 100644 --- a/dropbox/pom.xml +++ b/dropbox/pom.xml @@ -18,7 +18,7 @@ parent ch.cyberduck - 9.3.1-SNAPSHOT + 9.3.0.uvfdraft.cryptolib-SNAPSHOT 4.0.0 dropbox diff --git a/eue/pom.xml b/eue/pom.xml index 30ebe1fe9fe..81cdc95ea4e 100644 --- a/eue/pom.xml +++ b/eue/pom.xml @@ -19,7 +19,7 @@ parent ch.cyberduck - 9.3.1-SNAPSHOT + 9.3.0.uvfdraft.cryptolib-SNAPSHOT eue jar diff --git a/freenet/pom.xml b/freenet/pom.xml index 9660bb992b7..b966134b128 100644 --- a/freenet/pom.xml +++ b/freenet/pom.xml @@ -19,7 +19,7 @@ parent ch.cyberduck - 9.3.1-SNAPSHOT + 9.3.0.uvfdraft.cryptolib-SNAPSHOT freenet jar diff --git a/ftp/pom.xml b/ftp/pom.xml index 7760c88f68a..0ffd449e0e6 100644 --- a/ftp/pom.xml +++ b/ftp/pom.xml @@ -18,7 +18,7 @@ ch.cyberduck parent - 9.3.1-SNAPSHOT + 9.3.0.uvfdraft.cryptolib-SNAPSHOT ftp jar diff --git a/googledrive/pom.xml b/googledrive/pom.xml index d8313e6e725..527ad5246c5 100644 --- a/googledrive/pom.xml +++ b/googledrive/pom.xml @@ -18,7 +18,7 @@ parent ch.cyberduck - 9.3.1-SNAPSHOT + 9.3.0.uvfdraft.cryptolib-SNAPSHOT 4.0.0 googledrive diff --git a/googlestorage/pom.xml b/googlestorage/pom.xml index 28cec6124a7..2d1972f75ca 100644 --- a/googlestorage/pom.xml +++ b/googlestorage/pom.xml @@ -19,7 +19,7 @@ parent ch.cyberduck - 9.3.1-SNAPSHOT + 9.3.0.uvfdraft.cryptolib-SNAPSHOT googlestorage diff --git a/hubic/pom.xml b/hubic/pom.xml index 903d0be794c..690a0128cf1 100644 --- a/hubic/pom.xml +++ b/hubic/pom.xml @@ -19,7 +19,7 @@ parent ch.cyberduck - 9.3.1-SNAPSHOT + 9.3.0.uvfdraft.cryptolib-SNAPSHOT hubic jar diff --git a/i18n/pom.xml b/i18n/pom.xml index 3ef512059c3..8224c60377d 100644 --- a/i18n/pom.xml +++ b/i18n/pom.xml @@ -18,7 +18,7 @@ parent ch.cyberduck - 9.3.1-SNAPSHOT + 9.3.0.uvfdraft.cryptolib-SNAPSHOT 4.0.0 jar diff --git a/importer/dll/pom.xml b/importer/dll/pom.xml index 32f88d15127..66c70fa8c0d 100644 --- a/importer/dll/pom.xml +++ b/importer/dll/pom.xml @@ -5,7 +5,7 @@ ch.cyberduck parent ../../pom.xml - 9.3.1-SNAPSHOT + 9.3.0.uvfdraft.cryptolib-SNAPSHOT Cyberduck.Importer pom diff --git a/importer/pom.xml b/importer/pom.xml index 531344d529d..6b0a702d314 100644 --- a/importer/pom.xml +++ b/importer/pom.xml @@ -18,7 +18,7 @@ parent ch.cyberduck - 9.3.1-SNAPSHOT + 9.3.0.uvfdraft.cryptolib-SNAPSHOT 4.0.0 diff --git a/irods/pom.xml b/irods/pom.xml index cfbf144abf2..39d14460904 100644 --- a/irods/pom.xml +++ b/irods/pom.xml @@ -18,7 +18,7 @@ ch.cyberduck parent - 9.3.1-SNAPSHOT + 9.3.0.uvfdraft.cryptolib-SNAPSHOT irods jar diff --git a/jersey/pom.xml b/jersey/pom.xml index c394b6bb20f..d892f196f53 100644 --- a/jersey/pom.xml +++ b/jersey/pom.xml @@ -19,7 +19,7 @@ parent ch.cyberduck - 9.3.1-SNAPSHOT + 9.3.0.uvfdraft.cryptolib-SNAPSHOT jersey diff --git a/manta/pom.xml b/manta/pom.xml index 3e44d5efae1..49283fb0bbb 100644 --- a/manta/pom.xml +++ b/manta/pom.xml @@ -19,7 +19,7 @@ parent ch.cyberduck - 9.3.1-SNAPSHOT + 9.3.0.uvfdraft.cryptolib-SNAPSHOT manta diff --git a/nextcloud/pom.xml b/nextcloud/pom.xml index 22865102a9c..141cf5caded 100644 --- a/nextcloud/pom.xml +++ b/nextcloud/pom.xml @@ -18,7 +18,7 @@ ch.cyberduck parent - 9.3.1-SNAPSHOT + 9.3.0.uvfdraft.cryptolib-SNAPSHOT nextcloud jar diff --git a/nio/pom.xml b/nio/pom.xml index 1e4a672c7f1..96ea4129407 100644 --- a/nio/pom.xml +++ b/nio/pom.xml @@ -18,7 +18,7 @@ ch.cyberduck parent - 9.3.1-SNAPSHOT + 9.3.0.uvfdraft.cryptolib-SNAPSHOT nio jar diff --git a/oauth/pom.xml b/oauth/pom.xml index c1fe26a5a4e..71955bdb104 100644 --- a/oauth/pom.xml +++ b/oauth/pom.xml @@ -19,7 +19,7 @@ parent ch.cyberduck - 9.3.1-SNAPSHOT + 9.3.0.uvfdraft.cryptolib-SNAPSHOT oauth diff --git a/onedrive/pom.xml b/onedrive/pom.xml index da7babe1e66..a0f70b8f02f 100644 --- a/onedrive/pom.xml +++ b/onedrive/pom.xml @@ -19,7 +19,7 @@ parent ch.cyberduck - 9.3.1-SNAPSHOT + 9.3.0.uvfdraft.cryptolib-SNAPSHOT onedrive diff --git a/openstack/pom.xml b/openstack/pom.xml index 6c7b2c9e51f..ba4b897caa7 100644 --- a/openstack/pom.xml +++ b/openstack/pom.xml @@ -18,7 +18,7 @@ ch.cyberduck parent - 9.3.1-SNAPSHOT + 9.3.0.uvfdraft.cryptolib-SNAPSHOT openstack jar diff --git a/osx/pom.xml b/osx/pom.xml index 33832bec6e6..5ce04c18020 100644 --- a/osx/pom.xml +++ b/osx/pom.xml @@ -18,7 +18,7 @@ ch.cyberduck parent - 9.3.1-SNAPSHOT + 9.3.0.uvfdraft.cryptolib-SNAPSHOT osx jar diff --git a/owncloud/pom.xml b/owncloud/pom.xml index 1a3b27fd0d9..1e7e8702526 100644 --- a/owncloud/pom.xml +++ b/owncloud/pom.xml @@ -18,7 +18,7 @@ ch.cyberduck parent - 9.3.1-SNAPSHOT + 9.3.0.uvfdraft.cryptolib-SNAPSHOT owncloud jar diff --git a/pom.xml b/pom.xml index 156a6584f23..0a0c9c38a27 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ parent Cyberduck pom - 9.3.1-SNAPSHOT + 9.3.0.uvfdraft.cryptolib-SNAPSHOT defaults diff --git a/profiles/pom.xml b/profiles/pom.xml index a4296d995a9..8da42c84b08 100644 --- a/profiles/pom.xml +++ b/profiles/pom.xml @@ -19,7 +19,7 @@ parent ch.cyberduck - 9.3.1-SNAPSHOT + 9.3.0.uvfdraft.cryptolib-SNAPSHOT profiles jar diff --git a/protocols/dll/pom.xml b/protocols/dll/pom.xml index 39502f50473..671599530f5 100644 --- a/protocols/dll/pom.xml +++ b/protocols/dll/pom.xml @@ -5,7 +5,7 @@ ch.cyberduck parent ../../pom.xml - 9.3.1-SNAPSHOT + 9.3.0.uvfdraft.cryptolib-SNAPSHOT Cyberduck.Protocols pom diff --git a/protocols/pom.xml b/protocols/pom.xml index 69c0040d510..4c1269ce9c2 100644 --- a/protocols/pom.xml +++ b/protocols/pom.xml @@ -18,7 +18,7 @@ parent ch.cyberduck - 9.3.1-SNAPSHOT + 9.3.0.uvfdraft.cryptolib-SNAPSHOT 4.0.0 pom diff --git a/s3/pom.xml b/s3/pom.xml index 8e95e6e77cd..91b1f579460 100644 --- a/s3/pom.xml +++ b/s3/pom.xml @@ -18,7 +18,7 @@ ch.cyberduck parent - 9.3.1-SNAPSHOT + 9.3.0.uvfdraft.cryptolib-SNAPSHOT s3 jar diff --git a/smb/pom.xml b/smb/pom.xml index 2d0faac3002..8a3d6fa41ef 100644 --- a/smb/pom.xml +++ b/smb/pom.xml @@ -18,7 +18,7 @@ ch.cyberduck parent - 9.3.1-SNAPSHOT + 9.3.0.uvfdraft.cryptolib-SNAPSHOT smb jar diff --git a/spectra/pom.xml b/spectra/pom.xml index d59ec4af4ed..9430155495f 100644 --- a/spectra/pom.xml +++ b/spectra/pom.xml @@ -18,7 +18,7 @@ ch.cyberduck parent - 9.3.1-SNAPSHOT + 9.3.0.uvfdraft.cryptolib-SNAPSHOT spectra jar diff --git a/ssh/pom.xml b/ssh/pom.xml index c5747b3f819..100f2d8fe6d 100644 --- a/ssh/pom.xml +++ b/ssh/pom.xml @@ -18,7 +18,7 @@ ch.cyberduck parent - 9.3.1-SNAPSHOT + 9.3.0.uvfdraft.cryptolib-SNAPSHOT ssh jar diff --git a/storegate/pom.xml b/storegate/pom.xml index 3f2b900533e..01a2b430258 100644 --- a/storegate/pom.xml +++ b/storegate/pom.xml @@ -19,7 +19,7 @@ parent ch.cyberduck - 9.3.1-SNAPSHOT + 9.3.0.uvfdraft.cryptolib-SNAPSHOT storegate diff --git a/test/pom.xml b/test/pom.xml index 7296f59dfb7..81c01dff530 100644 --- a/test/pom.xml +++ b/test/pom.xml @@ -18,7 +18,7 @@ ch.cyberduck parent - 9.3.1-SNAPSHOT + 9.3.0.uvfdraft.cryptolib-SNAPSHOT 4.0.0 pom diff --git a/tus/pom.xml b/tus/pom.xml index 714179e6e50..d3b8b11fb17 100644 --- a/tus/pom.xml +++ b/tus/pom.xml @@ -18,7 +18,7 @@ ch.cyberduck parent - 9.3.1-SNAPSHOT + 9.3.0.uvfdraft.cryptolib-SNAPSHOT tus jar diff --git a/webdav/pom.xml b/webdav/pom.xml index 421d8e1692c..729490f1332 100644 --- a/webdav/pom.xml +++ b/webdav/pom.xml @@ -18,7 +18,7 @@ ch.cyberduck parent - 9.3.1-SNAPSHOT + 9.3.0.uvfdraft.cryptolib-SNAPSHOT webdav jar diff --git a/windows/pom.xml b/windows/pom.xml index 4a708e5fa16..c25da00a71a 100644 --- a/windows/pom.xml +++ b/windows/pom.xml @@ -18,7 +18,7 @@ parent ch.cyberduck - 9.3.1-SNAPSHOT + 9.3.0.uvfdraft.cryptolib-SNAPSHOT 4.0.0 Cyberduck.Native