diff --git a/main/pom.xml b/main/pom.xml index d1f8131ed..11d1c064d 100644 --- a/main/pom.xml +++ b/main/pom.xml @@ -28,7 +28,7 @@ 1.1.2 - 1.3.0 + 1.4.0 0.6.1 1.0.2 1.7.25 diff --git a/main/ui/src/main/java/org/cryptomator/ui/model/UpgradeStrategies.java b/main/ui/src/main/java/org/cryptomator/ui/model/UpgradeStrategies.java index e5c020aed..0d569b430 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/model/UpgradeStrategies.java +++ b/main/ui/src/main/java/org/cryptomator/ui/model/UpgradeStrategies.java @@ -19,8 +19,8 @@ public class UpgradeStrategies { private final Collection strategies; @Inject - public UpgradeStrategies(UpgradeVersion3DropBundleExtension upgrader1, UpgradeVersion3to4 upgrader2, UpgradeVersion4to5 upgrader3) { - strategies = Collections.unmodifiableList(Arrays.asList(upgrader1, upgrader2, upgrader3)); + public UpgradeStrategies(UpgradeVersion3DropBundleExtension upgrader1, UpgradeVersion3to4 upgrader2, UpgradeVersion4to5 upgrader3, UpgradeVersion5toX upgrader4) { + strategies = Collections.unmodifiableList(Arrays.asList(upgrader1, upgrader2, upgrader3, upgrader4)); } public UpgradeStrategy getUpgradeStrategy(Vault vault) { diff --git a/main/ui/src/main/java/org/cryptomator/ui/model/UpgradeStrategy.java b/main/ui/src/main/java/org/cryptomator/ui/model/UpgradeStrategy.java index dbadd27f3..426a9b200 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/model/UpgradeStrategy.java +++ b/main/ui/src/main/java/org/cryptomator/ui/model/UpgradeStrategy.java @@ -63,18 +63,17 @@ public abstract class UpgradeStrategy { */ public void upgrade(Vault vault, CharSequence passphrase) throws UpgradeFailedException { LOG.info("Upgrading {} from {} to {}.", vault.getPath(), vaultVersionBeforeUpgrade, vaultVersionAfterUpgrade); - final Path masterkeyFile = vault.getPath().resolve(MASTERKEY_FILENAME); - try (Cryptor cryptor = cryptorProvider.createFromKeyFile(KeyFile.parse(Files.readAllBytes(masterkeyFile)), passphrase, vaultVersionBeforeUpgrade)) { + final Path masterkeyFileBeforeUpgrade = vault.getPath().resolve(MASTERKEY_FILENAME); + try (Cryptor cryptor = readMasterkeyFile(masterkeyFileBeforeUpgrade, passphrase)) { // create backup, as soon as we know the password was correct: - final Path masterkeyBackupFile = vault.getPath().resolve(MASTERKEY_BACKUP_FILENAME); - Files.copy(masterkeyFile, masterkeyBackupFile, StandardCopyOption.REPLACE_EXISTING); + Path masterkeyBackupFile = vault.getPath().resolve(MASTERKEY_BACKUP_FILENAME); + Files.copy(masterkeyFileBeforeUpgrade, masterkeyBackupFile, StandardCopyOption.REPLACE_EXISTING); LOG.info("Backuped masterkey."); // do stuff: upgrade(vault, cryptor); // write updated masterkey file: - final byte[] upgradedMasterkeyFileContents = cryptor.writeKeysToMasterkeyFile(passphrase, vaultVersionAfterUpgrade).serialize(); - final Path masterkeyFileAfterUpgrade = vault.getPath().resolve(MASTERKEY_FILENAME); // path may have changed - Files.write(masterkeyFileAfterUpgrade, upgradedMasterkeyFileContents, StandardOpenOption.TRUNCATE_EXISTING); + Path masterkeyFileAfterUpgrade = vault.getPath().resolve(MASTERKEY_FILENAME); // path may have changed + writeMasterkeyFile(masterkeyFileAfterUpgrade, cryptor, passphrase); LOG.info("Updated masterkey."); } catch (InvalidPassphraseException e) { throw new UpgradeFailedException(localization.getString("unlock.errorMessage.wrongPassword")); @@ -92,6 +91,17 @@ public abstract class UpgradeStrategy { } } + protected Cryptor readMasterkeyFile(Path masterkeyFile, CharSequence passphrase) throws UnsupportedVaultFormatException, InvalidPassphraseException, IOException { + byte[] fileContents = Files.readAllBytes(masterkeyFile); + KeyFile keyFile = KeyFile.parse(fileContents); + return cryptorProvider.createFromKeyFile(keyFile, passphrase, vaultVersionBeforeUpgrade); + } + + protected void writeMasterkeyFile(Path masterkeyFile, Cryptor cryptor, CharSequence passphrase) throws IOException { + byte[] fileContents = cryptor.writeKeysToMasterkeyFile(passphrase, vaultVersionAfterUpgrade).serialize(); + Files.write(masterkeyFile, fileContents, StandardOpenOption.TRUNCATE_EXISTING); + } + protected abstract void upgrade(Vault vault, Cryptor cryptor) throws UpgradeFailedException; /** diff --git a/main/ui/src/main/java/org/cryptomator/ui/model/UpgradeVersion5toX.java b/main/ui/src/main/java/org/cryptomator/ui/model/UpgradeVersion5toX.java new file mode 100644 index 000000000..a502459b6 --- /dev/null +++ b/main/ui/src/main/java/org/cryptomator/ui/model/UpgradeVersion5toX.java @@ -0,0 +1,70 @@ +/******************************************************************************* + * Copyright (c) 2017 Skymatic UG (haftungsbeschränkt). + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the accompanying LICENSE file. + *******************************************************************************/ +package org.cryptomator.ui.model; + +import java.io.IOException; + +import javax.inject.Inject; +import javax.inject.Singleton; + +import org.cryptomator.cryptofs.migration.Migrators; +import org.cryptomator.cryptofs.migration.api.NoApplicableMigratorException; +import org.cryptomator.cryptolib.Cryptors; +import org.cryptomator.cryptolib.api.Cryptor; +import org.cryptomator.cryptolib.api.InvalidPassphraseException; +import org.cryptomator.ui.l10n.Localization; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +@Singleton +class UpgradeVersion5toX extends UpgradeStrategy { + + private static final Logger LOG = LoggerFactory.getLogger(UpgradeVersion5toX.class); + + @Inject + public UpgradeVersion5toX(Localization localization) { + super(Cryptors.version1(UpgradeStrategy.strongSecureRandom()), localization, 5, Integer.MAX_VALUE); + } + + @Override + public String getTitle(Vault vault) { + return localization.getString("upgrade.version5toX.title"); + } + + @Override + public String getMessage(Vault vault) { + return localization.getString("upgrade.version5toX.msg"); + } + + @Override + public void upgrade(Vault vault, CharSequence passphrase) throws UpgradeFailedException { + try { + Migrators.get().migrate(vault.getPath(), "masterkey.cryptomator", passphrase); + } catch (InvalidPassphraseException e) { + throw new UpgradeFailedException(localization.getString("unlock.errorMessage.wrongPassword")); + } catch (NoApplicableMigratorException | IOException e) { + LOG.warn("Upgrade failed.", e); + throw new UpgradeFailedException("Upgrade failed. Details in log message."); + } + } + + @Override + protected void upgrade(Vault vault, Cryptor cryptor) throws UpgradeFailedException { + // called by #upgrade(Vault, CharSequence), which got overwritten. + throw new AssertionError("Method can not be called."); + } + + @Override + public boolean isApplicable(Vault vault) { + try { + return Migrators.get().needsMigration(vault.getPath(), "masterkey.cryptomator"); + } catch (IOException e) { + LOG.warn("Could not determine, whether upgrade is applicable.", e); + return false; + } + } + +} 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 bb1c87227..65f4e16e5 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 @@ -16,7 +16,6 @@ import java.nio.file.FileSystem; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; -import java.util.EnumSet; import java.util.Objects; import java.util.concurrent.atomic.AtomicReference; import java.util.function.Function; @@ -32,7 +31,6 @@ import org.cryptomator.common.settings.Settings; import org.cryptomator.common.settings.VaultSettings; import org.cryptomator.cryptofs.CryptoFileSystem; import org.cryptomator.cryptofs.CryptoFileSystemProperties; -import org.cryptomator.cryptofs.CryptoFileSystemProperties.FileSystemFlags; import org.cryptomator.cryptofs.CryptoFileSystemProvider; import org.cryptomator.cryptolib.api.CryptoException; import org.cryptomator.cryptolib.api.InvalidPassphraseException; @@ -86,14 +84,14 @@ public class Vault { // Commands // ********************************************************************************/ - private CryptoFileSystem getCryptoFileSystem(CharSequence passphrase) throws IOException, CryptoException { + private CryptoFileSystem getCryptoFileSystem(CharSequence passphrase) throws IOException, InvalidPassphraseException, CryptoException { return LazyInitializer.initializeLazily(cryptoFileSystem, () -> unlockCryptoFileSystem(passphrase), IOException.class); } - private CryptoFileSystem unlockCryptoFileSystem(CharSequence passphrase) throws IOException, CryptoException { + private CryptoFileSystem unlockCryptoFileSystem(CharSequence passphrase) throws IOException, InvalidPassphraseException, CryptoException { CryptoFileSystemProperties fsProps = CryptoFileSystemProperties.cryptoFileSystemProperties() // .withPassphrase(passphrase) // - .withFlags(EnumSet.noneOf(FileSystemFlags.class)) // TODO: use withFlags() with CryptoFS 1.3.1 + .withFlags() // .withMasterkeyFilename(MASTERKEY_FILENAME) // .build(); return CryptoFileSystemProvider.newFileSystem(getPath(), fsProps); @@ -118,7 +116,7 @@ public class Vault { CryptoFileSystemProvider.changePassphrase(getPath(), MASTERKEY_FILENAME, oldPassphrase, newPassphrase); } - public synchronized void unlock(CharSequence passphrase) throws ServerLifecycleException { + public synchronized void unlock(CharSequence passphrase) throws InvalidPassphraseException, ServerLifecycleException { try { FileSystem fs = getCryptoFileSystem(passphrase); if (!server.isRunning()) { diff --git a/main/ui/src/main/resources/localization/en.txt b/main/ui/src/main/resources/localization/en.txt index 3cad2a15d..dfc92f9a4 100644 --- a/main/ui/src/main/resources/localization/en.txt +++ b/main/ui/src/main/resources/localization/en.txt @@ -54,6 +54,9 @@ upgrade.version4to5.title=Vault Version 4 to 5 Upgrade upgrade.version4to5.msg=This vault needs to be migrated to a newer format.\nEncrypted files will be updated.\nPlease make sure synchronization has finished before proceeding.\n\nNote: Modification date of all files will be changed to the current date/time in the process. upgrade.version4to5.err.io=Migration failed due to an I/O Exception. See log file for details. +upgrade.version5toX.title=Vault Version Upgrade +upgrade.version5toX.msg=This vault needs to be migrated to a newer format.\nPlease make sure synchronization has finished before proceeding. + # unlock.fxml unlock.label.password=Password unlock.label.savePassword=Save Password