Skip to content

Commit

Permalink
Merge pull request #14829 from iterate-ch/feature/GH-14827
Browse files Browse the repository at this point in the history
 Refactor vault implementation to allow for different implementations
  • Loading branch information
dkocher authored Jun 20, 2023
2 parents 5a8ee64 + e600ae2 commit d57b7d9
Show file tree
Hide file tree
Showing 23 changed files with 243 additions and 137 deletions.
10 changes: 5 additions & 5 deletions cli/src/main/java/ch/cyberduck/cli/Terminal.java
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@
import ch.cyberduck.core.transfer.TransferPrompt;
import ch.cyberduck.core.transfer.TransferSpeedometer;
import ch.cyberduck.core.vault.LoadingVaultLookupListener;
import ch.cyberduck.core.vault.VaultRegistry;
import ch.cyberduck.core.vault.VaultRegistryFactory;
import ch.cyberduck.core.worker.AttributesWorker;
import ch.cyberduck.core.worker.CreateDirectoryWorker;
Expand Down Expand Up @@ -276,10 +277,10 @@ public void uncaughtException(final Thread t, final Throwable e) {
final Host host = new CommandLineUriParser(input, protocols).parse(uri);
final LoginConnectionService connect = new LoginConnectionService(new TerminalLoginService(input),
login, new TerminalHostKeyVerifier(reader), progress);
final VaultRegistry registry = VaultRegistryFactory.get(login);
source = SessionPoolFactory.create(connect, transcript, host,
new CertificateStoreX509TrustManager(new DisabledCertificateTrustCallback(), new DefaultTrustManagerHostnameCallback(host), new TerminalCertificateStore(reader)),
new PreferencesX509KeyManager(host, new TerminalCertificateStore(reader)),
VaultRegistryFactory.create(login));
new PreferencesX509KeyManager(host, new TerminalCertificateStore(reader)), registry);
final Path remote;
if(StringUtils.startsWith(new CommandLinePathParser(input, protocols).parse(uri).getAbsolute(), TildePathExpander.PREFIX)) {
final Path home = this.execute(new TerminalBackgroundAction<>(controller, source, new HomeFinderWorker()));
Expand All @@ -301,7 +302,7 @@ public void uncaughtException(final Thread t, final Throwable e) {
log.debug(String.format("Attempting to load vault from %s", vault));
}
try {
this.execute(new TerminalBackgroundAction<>(controller, source, new LoadVaultWorker(new LoadingVaultLookupListener(source.getVault(),
this.execute(new TerminalBackgroundAction<>(controller, source, new LoadVaultWorker(new LoadingVaultLookupListener(source.getVaultRegistry(),
new TerminalPasswordCallback()), vault)));
}
catch(TerminalBackgroundException e) {
Expand Down Expand Up @@ -367,8 +368,7 @@ public void uncaughtException(final Thread t, final Throwable e) {
final Host target = new CommandLineUriParser(input).parse(input.getOptionValues(action.name())[1]);
destination = SessionPoolFactory.create(connect, transcript, target,
new CertificateStoreX509TrustManager(new DisabledCertificateTrustCallback(), new DefaultTrustManagerHostnameCallback(target), new TerminalCertificateStore(reader)),
new PreferencesX509KeyManager(target, new TerminalCertificateStore(reader)),
VaultRegistryFactory.create(new TerminalPasswordCallback()));
new PreferencesX509KeyManager(target, new TerminalCertificateStore(reader)), registry);
return this.transfer(login, new CopyTransfer(
host, target, Collections.singletonMap(remote, new CommandLinePathParser(input, protocols).parse(input.getOptionValues(action.name())[1]))).withCache(cache),
source, destination);
Expand Down
6 changes: 3 additions & 3 deletions core/src/main/java/ch/cyberduck/core/SessionPoolFactory.java
Original file line number Diff line number Diff line change
Expand Up @@ -73,9 +73,9 @@ public static SessionPool create(final Controller controller, final Host bookmar
final LoginConnectionService connect = new LoginConnectionService(login, key, keychain, listener);
final CertificateStore certificates = CertificateStoreFactory.get();
return create(connect, transcript, bookmark,
new KeychainX509TrustManager(CertificateTrustCallbackFactory.get(controller), new DefaultTrustManagerHostnameCallback(bookmark), certificates),
new KeychainX509KeyManager(CertificateIdentityCallbackFactory.get(controller), bookmark, certificates),
VaultRegistryFactory.create(keychain, login), usage);
new KeychainX509TrustManager(CertificateTrustCallbackFactory.get(controller), new DefaultTrustManagerHostnameCallback(bookmark), certificates),
new KeychainX509KeyManager(CertificateIdentityCallbackFactory.get(controller), bookmark, certificates),
VaultRegistryFactory.get(keychain, login), usage);
}

public static SessionPool create(final ConnectionService connect, final TranscriptListener transcript,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -245,7 +245,7 @@ public Host getHost() {
}

@Override
public VaultRegistry getVault() {
public VaultRegistry getVaultRegistry() {
return registry;
}

Expand Down
6 changes: 3 additions & 3 deletions core/src/main/java/ch/cyberduck/core/pool/SessionPool.java
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ public interface SessionPool {
/**
* @return Shared vaults for sessions
*/
VaultRegistry getVault();
VaultRegistry getVaultRegistry();

/**
* @return Current pool connection state
Expand Down Expand Up @@ -105,7 +105,7 @@ public Host getHost() {
}

@Override
public VaultRegistry getVault() {
public VaultRegistry getVaultRegistry() {
return VaultRegistry.DISABLED;
}

Expand Down Expand Up @@ -177,7 +177,7 @@ public Host getHost() {
}

@Override
public VaultRegistry getVault() {
public VaultRegistry getVaultRegistry() {
return VaultRegistry.DISABLED;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ public Host getHost() {
}

@Override
public VaultRegistry getVault() {
public VaultRegistry getVaultRegistry() {
return registry;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@
import ch.cyberduck.core.updater.DisabledPeriodicUpdater;
import ch.cyberduck.core.updater.DisabledUpdateCheckerArguments;
import ch.cyberduck.core.urlhandler.DisabledSchemeHandler;
import ch.cyberduck.core.vault.DefaultVaultRegistry;
import ch.cyberduck.core.vault.DisabledVault;
import ch.cyberduck.core.webloc.InternetShortcutFileWriter;
import ch.cyberduck.ui.quicklook.ApplicationLauncherQuicklook;
Expand Down Expand Up @@ -511,6 +512,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.vaultregistry.class", DefaultVaultRegistry.class.getName());
this.setDefault("factory.securerandom.class", DefaultSecureRandomProvider.class.getName());
this.setDefault("factory.providerhelpservice.class", DefaultProviderHelpService.class.getName());
this.setDefault("factory.quicklook.class", ApplicationLauncherQuicklook.class.getName());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -102,17 +102,13 @@ public void clear() {
super.clear();
}

@Override
public Vault find(final Session session, final Path file) throws VaultUnlockCancelException {
return this.find(session, file, true);
}

/**
* @param session Connection
* @param file File
* @param lookup Find and load any vault
* @return Open or disabled vault
*/
@Override
public Vault find(final Session session, final Path file, final boolean lookup) throws VaultUnlockCancelException {
for(Vault vault : this) {
if(vault.contains(file)) {
Expand Down Expand Up @@ -148,6 +144,10 @@ public <T> T getFeature(final Session<?> session, final Class<T> type, final T p
// No proxying for disabled features
return null;
}
return this._getFeature(session, type, proxy);
}

protected <T> T _getFeature(final Session<?> session, final Class<T> type, final T proxy) {
if(type == ListService.class) {
return (T) new VaultRegistryListService(session, (ListService) proxy, this,
new LoadingVaultLookupListener(this, prompt))
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,10 @@ public VaultFinderListProgressListener(final Session<?> session, final VaultLook
@Override
public void visit(final AttributedList<Path> list, final int index, final Path file) throws ConnectionCanceledException {
final Path directory = file.getParent();
if(new HostPreferences(session.getHost()).getProperty("cryptomator.vault.masterkey.filename").equals(file.getName())) {
if(new HostPreferences(session.getHost()).getProperty("cryptomator.vault.config.filename").equals(file.getName()) ||
new HostPreferences(session.getHost()).getProperty("cryptomator.vault.masterkey.filename").equals(file.getName())) {
if(log.isInfoEnabled()) {
log.info(String.format("Found master key %s", file));
log.info(String.format("Found vault config or masterkey file %s", file));
}
try {
final Vault vault = listener.load(session, directory,
Expand Down
59 changes: 57 additions & 2 deletions core/src/main/java/ch/cyberduck/core/vault/VaultRegistry.java
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,21 @@ public interface VaultRegistry {
* @param session Connection
* @param file File
* @return Vault for file or disabled vault if file is not inside a vault
* @throws VaultUnlockCancelException Attempt to unlock vault was canceled by user
* @see Vault#DISABLED
*/
Vault find(Session session, Path file) throws VaultUnlockCancelException;
default Vault find(final Session session, final Path file) throws VaultUnlockCancelException {
return this.find(session, file, true);
}

/**
* @param session Connection
* @param file File
* @param lookup Attempt to unlock vault when not already registered
* @return Vault for file or disabled vault if file is not inside a vault
* @throws VaultUnlockCancelException Attempt to unlock vault was canceled by user
*/
Vault find(Session session, Path file, boolean lookup) throws VaultUnlockCancelException;

/**
* Add vault to registry
Expand All @@ -50,8 +62,51 @@ public interface VaultRegistry {
*/
void clear();

/**
* Wrap proxy with implementation looking up vault and wrap with cryptographic feature
*
* @param session Connection
* @param type Feature type
* @param proxy Proxy implementation to wrap with vault lookup
* @return Feature implementation or null when not supported
*/
@SuppressWarnings("unchecked")
<T> T getFeature(Session<?> session, Class<T> type, T proxy);

boolean contains(Path vault);
/**
* @return True if directory is registered as vault or is contained in vault
*/
boolean contains(Path directory);

class DisabledVaultRegistry implements VaultRegistry {
@Override
public Vault find(final Session session, final Path file, final boolean lookup) throws VaultUnlockCancelException {
return Vault.DISABLED;
}

@Override
public void clear() {
//
}

@Override
public <T> T getFeature(final Session<?> session, final Class<T> type, final T proxy) {
return proxy;
}

@Override
public boolean contains(final Path vault) {
return false;
}

@Override
public boolean add(final Vault vault) {
return false;
}

@Override
public boolean close(final Path vault) {
return false;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,19 +15,54 @@
* GNU General Public License for more details.
*/

import ch.cyberduck.core.Factory;
import ch.cyberduck.core.FactoryException;
import ch.cyberduck.core.HostPasswordStore;
import ch.cyberduck.core.PasswordCallback;
import ch.cyberduck.core.PasswordStoreFactory;
import ch.cyberduck.core.preferences.PreferencesFactory;

public class VaultRegistryFactory {
import org.apache.commons.lang3.reflect.ConstructorUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

public static VaultRegistry create(final PasswordCallback callback) {
return create(PasswordStoreFactory.get(), callback);
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;

public class VaultRegistryFactory extends Factory<VaultRegistry> {
private static final Logger log = LogManager.getLogger(VaultRegistryFactory.class);

public VaultRegistryFactory() {
super("factory.vaultregistry.class");
}

public static VaultRegistry get(final PasswordCallback callback) {
return get(PasswordStoreFactory.get(), callback);
}

public static VaultRegistry create(final HostPasswordStore keychain, final PasswordCallback callback) {
public static VaultRegistry get(final HostPasswordStore keychain, final PasswordCallback callback) {
return PreferencesFactory.get().getBoolean("cryptomator.enable") ?
new DefaultVaultRegistry(keychain, callback) : VaultRegistry.DISABLED;
new VaultRegistryFactory().create(keychain, callback) : VaultRegistry.DISABLED;
}

public VaultRegistry create(final HostPasswordStore keychain, final PasswordCallback callback) {
if(null == clazz) {
throw new FactoryException(String.format("No implementation given for factory %s", this.getClass().getSimpleName()));
}
try {
final Constructor<? extends VaultRegistry> constructor = ConstructorUtils
.getMatchingAccessibleConstructor(clazz, keychain.getClass(), callback.getClass());
if(null == constructor) {
log.warn(String.format("No matching constructor for parameters %s,%s", keychain.getClass(), callback.getClass()));
// Call default constructor for disabled implementations
return clazz.getDeclaredConstructor().newInstance();
}
return constructor.newInstance(keychain, callback);
}
catch(InstantiationException | InvocationTargetException | IllegalAccessException |
NoSuchMethodException e) {
log.error(String.format("Failure loading callback class %s. %s", clazz, e.getMessage()));
return VaultRegistry.DISABLED;
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,18 +23,18 @@
import ch.cyberduck.core.features.Vault;
import ch.cyberduck.core.io.StreamListener;
import ch.cyberduck.core.transfer.TransferStatus;
import ch.cyberduck.core.vault.DefaultVaultRegistry;
import ch.cyberduck.core.vault.VaultRegistry;
import ch.cyberduck.core.vault.VaultUnlockCancelException;

public class VaultRegistryCopyFeature implements Copy {

private final Session<?> session;
private Session<?> destination;
private final Copy proxy;
private final DefaultVaultRegistry registry;
private final VaultRegistry registry;


public VaultRegistryCopyFeature(final Session<?> session, final Copy proxy, final DefaultVaultRegistry registry) {
public VaultRegistryCopyFeature(final Session<?> session, final Copy proxy, final VaultRegistry registry) {
this.session = session;
this.destination = session;
this.proxy = proxy;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import ch.cyberduck.core.features.Vault;
import ch.cyberduck.core.transfer.TransferStatus;
import ch.cyberduck.core.vault.VaultRegistry;
import ch.cyberduck.core.vault.VaultUnlockCancelException;

import java.util.HashMap;
import java.util.LinkedHashMap;
Expand Down Expand Up @@ -64,7 +65,12 @@ public void delete(final Map<Path, TransferStatus> files, final PasswordCallback

@Override
public boolean isSupported(final Path file) {
return proxy.isSupported(file);
try {
return registry.find(session, file, false).getFeature(session, Delete.class, proxy).isSupported(file);
}
catch(VaultUnlockCancelException e) {
return proxy.isSupported(file);
}
}

@Override
Expand Down
Loading

0 comments on commit d57b7d9

Please sign in to comment.