replace config manually instead of using CryptoFileSystem.init()

This commit is contained in:
Armin Schrenk
2023-04-21 09:40:34 +02:00
parent 864454e6fc
commit 2e0908ab15
2 changed files with 114 additions and 40 deletions

View File

@@ -2,12 +2,12 @@ package org.cryptomator.ui.convertvault;
import com.google.common.base.Preconditions;
import dagger.Lazy;
import org.cryptomator.common.Constants;
import org.cryptomator.common.Passphrase;
import org.cryptomator.common.vaults.Vault;
import org.cryptomator.cryptofs.CryptoFileSystemProperties;
import org.cryptomator.cryptofs.CryptoFileSystemProvider;
import org.cryptomator.cryptofs.VaultConfig;
import org.cryptomator.cryptofs.VaultVersionMismatchException;
import org.cryptomator.cryptofs.common.BackupHelper;
import org.cryptomator.cryptolib.api.MasterkeyLoader;
import org.cryptomator.cryptolib.api.MasterkeyLoadingFailedException;
import org.cryptomator.cryptolib.common.MasterkeyFileAccess;
import org.cryptomator.ui.changepassword.NewPasswordController;
@@ -31,6 +31,7 @@ import javafx.scene.control.Button;
import javafx.scene.control.ContentDisplay;
import javafx.stage.Stage;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardCopyOption;
@@ -39,7 +40,8 @@ import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionException;
import java.util.concurrent.ExecutorService;
import static org.cryptomator.common.Constants.DEFAULT_KEY_ID;
import static java.nio.file.StandardOpenOption.CREATE_NEW;
import static java.nio.file.StandardOpenOption.WRITE;
import static org.cryptomator.common.Constants.MASTERKEY_BACKUP_SUFFIX;
import static org.cryptomator.common.Constants.MASTERKEY_FILENAME;
import static org.cryptomator.common.Constants.VAULTCONFIG_FILENAME;
@@ -100,9 +102,9 @@ public class HubToPasswordConvertController implements FxController {
@FXML
public void convert() {
Preconditions.checkState(newPasswordController.isGoodPassword());
LOG.info("Converting hub vault {} to password", vault.getPath());
LOG.info("Converting access method of vault {} from hub to password", vault.getPath());
CompletableFuture.runAsync(() -> conversionStarted.setValue(true), Platform::runLater) //
.thenRunAsync(this::convertInternal, backgroundExecutorService)
.thenRunAsync(this::convertInternal, backgroundExecutorService) //
.whenCompleteAsync((result, exception) -> {
if (exception == null) {
LOG.info("Conversion of vault {} succeeded.", vault.getPath());
@@ -117,11 +119,19 @@ public class HubToPasswordConvertController implements FxController {
//visible for testing
void convertInternal() throws CompletionException, IllegalArgumentException {
var passphrase = newPasswordController.getNewPassword();
var vaultPath = vault.getPath();
try {
recoveryKeyFactory.newMasterkeyFileWithPassphrase(vault.getPath(), recoveryKey.get(), passphrase);
LOG.debug("Successfully created masterkey file for vault {}", vault.getPath());
backupHubConfig(vault.getPath().resolve(VAULTCONFIG_FILENAME));
replaceWithPasswordConfig(passphrase);
//create masterkey
recoveryKeyFactory.newMasterkeyFileWithPassphrase(vaultPath, recoveryKey.get(), passphrase);
LOG.debug("Successfully created masterkey file for vault {}", vaultPath);
//create password config
Path passwordConfigPath = vaultPath.resolve("passwordBased." + VAULTCONFIG_FILENAME + ".tmp");
passwordConfigPath = createPasswordConfig(passwordConfigPath, vaultPath.resolve(MASTERKEY_FILENAME), passphrase);
//backup hub config
var hubConfigPath = vaultPath.resolve(VAULTCONFIG_FILENAME);
backupHubConfig(hubConfigPath);
//replace hub by password
Files.move(passwordConfigPath, hubConfigPath, StandardCopyOption.REPLACE_EXISTING, StandardCopyOption.ATOMIC_MOVE);
} catch (MasterkeyLoadingFailedException e) {
throw new CompletionException(new IOException("Vault conversion failed", e));
} catch (IOException e) {
@@ -134,25 +144,28 @@ public class HubToPasswordConvertController implements FxController {
//visible for testing
void backupHubConfig(Path hubConfigPath) throws IOException {
byte[] hubConfigBytes = Files.readAllBytes(hubConfigPath);
Path backupPath = vault.getPath().resolve(VAULTCONFIG_FILENAME + BackupHelper.generateFileIdSuffix(hubConfigBytes) + MASTERKEY_BACKUP_SUFFIX);
Files.move(hubConfigPath, backupPath, StandardCopyOption.REPLACE_EXISTING, StandardCopyOption.ATOMIC_MOVE); //TODO: should this be an atomic move?
LOG.debug("Successfully created vault config backup {} for vault {}", backupPath.getFileName(), vault.getPath());
Path backupPath = hubConfigPath.resolveSibling(VAULTCONFIG_FILENAME + BackupHelper.generateFileIdSuffix(hubConfigBytes) + MASTERKEY_BACKUP_SUFFIX);
Files.copy(hubConfigPath, backupPath, StandardCopyOption.REPLACE_EXISTING);
LOG.debug("Successfully created hub config backup {}", backupPath.getFileName());
}
//visible for testing
void replaceWithPasswordConfig(Passphrase passphrase) throws IOException, MasterkeyLoadingFailedException {
Path createPasswordConfig(Path passwordConfigPath, Path masterkeyFile, Passphrase passphrase) throws IOException, MasterkeyLoadingFailedException {
var unverifiedVaultConfig = vault.getVaultConfigCache().get();
try (var masterkey = masterkeyFileAccess.load(vault.getPath().resolve(MASTERKEY_FILENAME), passphrase)) {
var vaultConfig = unverifiedVaultConfig.verify(masterkey.getEncoded(), unverifiedVaultConfig.allegedVaultVersion());
MasterkeyLoader loader = ignored -> masterkey.copy();
CryptoFileSystemProperties fsProps = CryptoFileSystemProperties.cryptoFileSystemProperties() //
.withCipherCombo(vaultConfig.getCipherCombo()) //
.withKeyLoader(loader) //
try (var masterkey = masterkeyFileAccess.load(masterkeyFile, passphrase)) {
var hubConfig = unverifiedVaultConfig.verify(masterkey.getEncoded(), unverifiedVaultConfig.allegedVaultVersion());
var passwordConfig = VaultConfig.createNew() //
.cipherCombo(hubConfig.getCipherCombo()) //
.shorteningThreshold(hubConfig.getShorteningThreshold()) //
.build();
CryptoFileSystemProvider.initialize(vault.getPath(), fsProps, DEFAULT_KEY_ID);
if (passwordConfig.getVaultVersion() != hubConfig.getVaultVersion()) {
throw new VaultVersionMismatchException("Only vaults of version " + passwordConfig.getVaultVersion() + "can be converted.");
}
var token = passwordConfig.toToken(Constants.DEFAULT_KEY_ID.toString(), masterkey.getEncoded());
Files.writeString(passwordConfigPath, token, StandardCharsets.US_ASCII, WRITE, CREATE_NEW);
LOG.debug("Successfully created password config {}", passwordConfigPath);
return passwordConfigPath;
}
}
/* Getter/Setter */
}