diff --git a/main/filesystem-crypto/src/main/java/org/cryptomator/filesystem/crypto/CryptoFileSystemFactory.java b/main/filesystem-crypto/src/main/java/org/cryptomator/filesystem/crypto/CryptoFileSystemFactory.java index ffaa7025a..aff01b82c 100644 --- a/main/filesystem-crypto/src/main/java/org/cryptomator/filesystem/crypto/CryptoFileSystemFactory.java +++ b/main/filesystem-crypto/src/main/java/org/cryptomator/filesystem/crypto/CryptoFileSystemFactory.java @@ -8,6 +8,8 @@ *******************************************************************************/ package org.cryptomator.filesystem.crypto; +import static org.cryptomator.filesystem.crypto.Constants.MASTERKEY_FILENAME; + import java.io.UncheckedIOException; import javax.inject.Inject; @@ -31,6 +33,10 @@ public class CryptoFileSystemFactory { this.blockAlignedFileSystemFactory = blockAlignedFileSystemFactory; } + public boolean isValidVaultStructure(Folder vaultLocation) { + return vaultLocation.file(MASTERKEY_FILENAME).exists(); + } + public void initializeNew(Folder vaultLocation, CharSequence passphrase) { masterkeys.initialize(vaultLocation, passphrase); } diff --git a/main/ui/src/main/java/org/cryptomator/ui/MainApplication.java b/main/ui/src/main/java/org/cryptomator/ui/MainApplication.java index d8c7f17ff..b0c4acd24 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/MainApplication.java +++ b/main/ui/src/main/java/org/cryptomator/ui/MainApplication.java @@ -17,7 +17,6 @@ import java.util.concurrent.ExecutorService; import org.apache.commons.lang3.SystemUtils; import org.cryptomator.ui.controllers.MainController; -import org.cryptomator.ui.model.Vault; import org.cryptomator.ui.util.ActiveWindowStyleSupport; import org.cryptomator.ui.util.DeferredCloser; import org.cryptomator.ui.util.SingleInstanceManager; @@ -90,18 +89,12 @@ public class MainApplication extends Application { } private void handleCommandLineArg(String arg) { - // only open files with our file extension: - if (!arg.endsWith(Vault.VAULT_FILE_EXTENSION)) { - LOG.warn("Invalid vault path %s", arg); - return; - } - // find correct location: final Path path = FileSystems.getDefault().getPath(arg); final Path vaultPath; if (Files.isDirectory(path)) { vaultPath = path; - } else if (Files.isRegularFile(path) && path.getParent().getFileName().toString().endsWith(Vault.VAULT_FILE_EXTENSION)) { + } else if (Files.isRegularFile(path)) { vaultPath = path.getParent(); } else { LOG.warn("Invalid vault path %s", arg); diff --git a/main/ui/src/main/java/org/cryptomator/ui/controllers/MainController.java b/main/ui/src/main/java/org/cryptomator/ui/controllers/MainController.java index a598126f2..b648aa25a 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/controllers/MainController.java +++ b/main/ui/src/main/java/org/cryptomator/ui/controllers/MainController.java @@ -181,7 +181,7 @@ public class MainController extends AbstractFXMLViewController { * @param path non-null, writable, existing directory */ public void addVault(final Path path, boolean select) { - // TODO: Files.isWritable is broken on windows. Fix in Java 8u72, see https://bugs.openjdk.java.net/browse/JDK-8034057 + // TODO: `|| !Files.isWritable(path)` is broken on windows. Fix in Java 8u72, see https://bugs.openjdk.java.net/browse/JDK-8034057 if (path == null) { return; } @@ -189,7 +189,7 @@ public class MainController extends AbstractFXMLViewController { final Path vaultPath; if (path != null && Files.isDirectory(path)) { vaultPath = path; - } else if (path != null && Files.isRegularFile(path) && path.getParent().getFileName().toString().endsWith(Vault.VAULT_FILE_EXTENSION)) { + } else if (path != null && Files.isRegularFile(path)) { vaultPath = path.getParent(); } else { return; @@ -244,16 +244,12 @@ public class MainController extends AbstractFXMLViewController { // **************************************** private void showVault(Vault vault) { - try { - if (vault.isUnlocked()) { - this.showUnlockedView(vault); - } else if (vault.containsMasterKey()) { - this.showUnlockView(vault); - } else { - this.showInitializeView(vault); - } - } catch (IOException e) { - LOG.error("Failed to analyze directory.", e); + if (vault.isUnlocked()) { + this.showUnlockedView(vault); + } else if (vault.isValidVaultDirectory()) { + this.showUnlockView(vault); + } else { + this.showInitializeView(vault); } } diff --git a/main/ui/src/main/java/org/cryptomator/ui/model/Vault.java b/main/ui/src/main/java/org/cryptomator/ui/model/Vault.java index cccb6f82d..6887f937e 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/model/Vault.java +++ b/main/ui/src/main/java/org/cryptomator/ui/model/Vault.java @@ -12,7 +12,6 @@ import java.io.IOException; import java.io.Serializable; import java.io.UncheckedIOException; import java.nio.file.FileAlreadyExistsException; -import java.nio.file.Files; import java.nio.file.Path; import java.text.Normalizer; import java.text.Normalizer.Form; @@ -20,9 +19,11 @@ import java.util.HashSet; import java.util.Map; import java.util.Optional; import java.util.Set; +import java.util.concurrent.atomic.AtomicReference; import org.apache.commons.lang3.CharUtils; import org.apache.commons.lang3.StringUtils; +import org.cryptomator.common.LazyInitializer; import org.cryptomator.common.Optionals; import org.cryptomator.crypto.engine.InvalidPassphraseException; import org.cryptomator.filesystem.FileSystem; @@ -54,9 +55,6 @@ public class Vault implements Serializable, CryptoFileSystemDelegate { public static final String VAULT_FILE_EXTENSION = ".cryptomator"; - @Deprecated - public static final String VAULT_MASTERKEY_FILE = "masterkey.cryptomator"; - private final Path path; private final Lazy frontendFactory; private final DeferredCloser closer; @@ -65,6 +63,7 @@ public class Vault implements Serializable, CryptoFileSystemDelegate { private final ObjectProperty unlocked = new SimpleObjectProperty(this, "unlocked", Boolean.FALSE); private final ObservableList namesOfResourcesWithInvalidMac = FXThreads.observableListOnMainThread(FXCollections.observableArrayList()); private final Set whitelistedResourcesWithInvalidMac = new HashSet<>(); + private final AtomicReference nioFileSystem = new AtomicReference<>(); private String mountName; private Character winDriveLetter; @@ -88,13 +87,17 @@ public class Vault implements Serializable, CryptoFileSystemDelegate { } } + private FileSystem getNioFileSystem() { + return LazyInitializer.initializeLazily(nioFileSystem, () -> NioFileSystem.rootedAt(path)); + } + // ****************************************************************************** // Commands // ********************************************************************************/ public void create(CharSequence passphrase) throws IOException { try { - FileSystem fs = NioFileSystem.rootedAt(path); + FileSystem fs = getNioFileSystem(); if (fs.children().count() > 0) { throw new FileAlreadyExistsException(null, null, "Vault location not empty."); } @@ -106,8 +109,7 @@ public class Vault implements Serializable, CryptoFileSystemDelegate { public void changePassphrase(CharSequence oldPassphrase, CharSequence newPassphrase) throws IOException, InvalidPassphraseException { try { - FileSystem fs = NioFileSystem.rootedAt(path); - cryptoFileSystemFactory.changePassphrase(fs, oldPassphrase, newPassphrase); + cryptoFileSystemFactory.changePassphrase(getNioFileSystem(), oldPassphrase, newPassphrase); } catch (UncheckedIOException e) { throw new IOException(e); } @@ -115,7 +117,7 @@ public class Vault implements Serializable, CryptoFileSystemDelegate { public synchronized void activateFrontend(CharSequence passphrase) throws FrontendCreationFailedException { try { - FileSystem fs = NioFileSystem.rootedAt(path); + FileSystem fs = getNioFileSystem(); FileSystem shorteningFs = shorteningFileSystemFactory.get(fs); FileSystem cryptoFs = cryptoFileSystemFactory.unlockExisting(shorteningFs, passphrase, this); StatsFileSystem statsFs = new StatsFileSystem(cryptoFs); @@ -191,12 +193,7 @@ public class Vault implements Serializable, CryptoFileSystemDelegate { } public boolean isValidVaultDirectory() { - return Files.isDirectory(path) && path.getFileName().toString().endsWith(VAULT_FILE_EXTENSION); - } - - public boolean containsMasterKey() throws IOException { - final Path masterKeyPath = path.resolve(VAULT_MASTERKEY_FILE); - return Files.isRegularFile(masterKeyPath); + return cryptoFileSystemFactory.isValidVaultStructure(getNioFileSystem()); } public ObjectProperty unlockedProperty() { diff --git a/main/ui/src/main/resources/localization.properties b/main/ui/src/main/resources/localization.properties index 79032e80b..98503ff55 100644 --- a/main/ui/src/main/resources/localization.properties +++ b/main/ui/src/main/resources/localization.properties @@ -26,6 +26,7 @@ welcome.newVersionMessage=Version %s can be downloaded. This is %s. initialize.label.password=Password initialize.label.retypePassword=Retype password initialize.button.ok=Create vault +initialize.messageLabel.alreadyInitialized=Vault already initialized # unlock.fxml unlock.label.password=Password