This commit is contained in:
Jan-Peter Klein
2025-07-04 17:16:32 +02:00
parent f623b1ee7e
commit 8089bcd0d0
10 changed files with 101 additions and 130 deletions

View File

@@ -72,7 +72,7 @@ public class VaultListManager {
autoLocker.init();
}
public boolean containsVault(Path vaultPath) {
public boolean isAlreadyAdded(Path vaultPath) {
assert vaultPath.isAbsolute();
assert vaultPath.normalize().equals(vaultPath);
return vaultList.stream().anyMatch(v -> vaultPath.equals(v.getPath()));
@@ -127,7 +127,7 @@ public class VaultListManager {
public void addVault(Vault vault) {
Path path = vault.getPath().normalize().toAbsolutePath();
if (!containsVault(path)) {
if (!isAlreadyAdded(path)) {
vaultList.add(vault);
}
}

View File

@@ -7,28 +7,13 @@ package org.cryptomator.ui.addvaultwizard;
import dagger.Lazy;
import dagger.Subcomponent;
import org.cryptomator.common.recovery.RecoveryActionType;
import org.cryptomator.common.vaults.Vault;
import org.cryptomator.common.vaults.VaultComponent;
import org.cryptomator.common.vaults.VaultListManager;
import org.cryptomator.common.vaults.VaultState;
import org.cryptomator.integrations.mount.MountService;
import org.cryptomator.ui.common.FxmlFile;
import org.cryptomator.ui.common.FxmlScene;
import org.cryptomator.ui.dialogs.Dialogs;
import org.cryptomator.ui.recoverykey.RecoveryKeyComponent;
import javafx.beans.property.SimpleObjectProperty;
import javafx.scene.Scene;
import javafx.stage.DirectoryChooser;
import javafx.stage.Stage;
import javafx.stage.Window;
import java.io.File;
import java.util.List;
import java.util.ResourceBundle;
import static org.cryptomator.ui.addvaultwizard.ChooseExistingVaultController.prepareVault;
@AddVaultWizardScoped
@Subcomponent(modules = {AddVaultModule.class})
public interface AddVaultWizardComponent {
@@ -42,9 +27,6 @@ public interface AddVaultWizardComponent {
@FxmlScene(FxmlFile.ADDVAULT_EXISTING)
Lazy<Scene> sceneExisting();
@FxmlScene(FxmlFile.ADDVAULT_SUCCESS)
Lazy<Scene> sceneSuccess();
default void showAddNewVaultWizard(ResourceBundle resourceBundle) {
Stage stage = window();
stage.setScene(sceneNew().get());
@@ -61,50 +43,6 @@ public interface AddVaultWizardComponent {
stage.show();
}
default void showRecoverExistingVaultWizard(Window mainWindow, //
Dialogs dialogs, //
VaultComponent.Factory vaultComponentFactory, //
List<MountService> mountServices, //
VaultListManager vaultListManager, //
RecoveryKeyComponent.Factory recoveryKeyWindow) {
Stage stage = window();
DirectoryChooser directoryChooser = new DirectoryChooser();
while (true) {
File selectedDirectory = directoryChooser.showDialog(mainWindow);
if (selectedDirectory == null) {
return;
}
boolean hasSubfolderD = new File(selectedDirectory, "d").isDirectory();
if (!hasSubfolderD) {
dialogs.prepareNoDDirectorySelectedDialog(stage).build().showAndWait();
continue;
}
Vault preparedVault = prepareVault(selectedDirectory, vaultComponentFactory, mountServices);
if (!vaultListManager.containsVault(preparedVault.getPath())) {
vaultListManager.addVault(preparedVault);
dialogs.prepareRecoveryVaultAdded(stage).setOkAction(Stage::close).build().showAndWait();
}
VaultListManager.redetermineVaultState(preparedVault);
VaultState.Value state = preparedVault.getState();
switch (state) {
case VAULT_CONFIG_MISSING -> recoveryKeyWindow.create(preparedVault, stage, new SimpleObjectProperty<>(RecoveryActionType.RESTORE_VAULT_CONFIG)) //
.showOnboardingDialogWindow();
case ALL_MISSING -> recoveryKeyWindow.create(preparedVault, stage, new SimpleObjectProperty<>(RecoveryActionType.RESTORE_ALL)) //
.showOnboardingDialogWindow();
default -> dialogs.prepareRecoveryVaultAlreadyExists(stage)//
.setOkAction(Stage::close)//
.build().showAndWait();
}
break;
}
}
@Subcomponent.Builder
interface Builder {

View File

@@ -2,12 +2,8 @@ package org.cryptomator.ui.addvaultwizard;
import dagger.Lazy;
import org.apache.commons.lang3.SystemUtils;
import org.cryptomator.common.settings.VaultSettings;
import org.cryptomator.common.vaults.Vault;
import org.cryptomator.common.vaults.VaultComponent;
import org.cryptomator.common.vaults.VaultConfigCache;
import org.cryptomator.common.vaults.VaultListManager;
import org.cryptomator.integrations.mount.MountService;
import org.cryptomator.integrations.uiappearance.Theme;
import org.cryptomator.ui.common.FxController;
import org.cryptomator.ui.common.FxmlFile;
@@ -18,9 +14,7 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.inject.Inject;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.beans.value.ObservableValue;
import javafx.fxml.FXML;
import javafx.scene.Scene;
@@ -30,12 +24,10 @@ import javafx.stage.Stage;
import java.io.File;
import java.io.IOException;
import java.nio.file.Path;
import java.util.List;
import java.util.Objects;
import java.util.ResourceBundle;
import static org.cryptomator.common.Constants.CRYPTOMATOR_FILENAME_GLOB;
import static org.cryptomator.common.vaults.VaultState.Value.LOCKED;
@AddVaultWizardScoped
public class ChooseExistingVaultController implements FxController {
@@ -51,9 +43,6 @@ public class ChooseExistingVaultController implements FxController {
private final ResourceBundle resourceBundle;
private final ObservableValue<Image> screenshot;
private final BooleanProperty restoreButtonVisible = new SimpleBooleanProperty(false);
@Inject
ChooseExistingVaultController(@AddVaultWizardWindow Stage window, //
@FxmlScene(FxmlFile.ADDVAULT_SUCCESS) Lazy<Scene> successScene, //
@@ -105,33 +94,6 @@ public class ChooseExistingVaultController implements FxController {
}
}
public static Vault prepareVault(File selectedDirectory, VaultComponent.Factory vaultComponentFactory, List<MountService> mountServices) {
Path selectedPath = selectedDirectory.toPath();
VaultSettings vaultSettings = VaultSettings.withRandomId();
vaultSettings.path.set(selectedPath);
if (selectedPath.getFileName() != null) {
vaultSettings.displayName.set(selectedPath.getFileName().toString());
} else {
vaultSettings.displayName.set("defaultVaultName");
}
var wrapper = new VaultConfigCache(vaultSettings);
Vault vault = vaultComponentFactory.create(vaultSettings, wrapper, LOCKED, null).vault();
try {
VaultListManager.determineVaultState(vault.getPath(), vaultSettings);
} catch (IOException e) {
LOG.warn("Failed to determine vault state for {}", vaultSettings.path.get(), e);
}
//due to https://github.com/cryptomator/cryptomator/issues/2880#issuecomment-1680313498
var nameOfWinfspLocalMounter = "org.cryptomator.frontend.fuse.mount.WinFspMountProvider";
if (SystemUtils.IS_OS_WINDOWS && vaultSettings.path.get().toString().contains("Dropbox") && mountServices.stream().anyMatch(s -> s.getClass().getName().equals(nameOfWinfspLocalMounter))) {
vaultSettings.mountService.setValue(nameOfWinfspLocalMounter);
}
return vault;
}
/* Getter */
public ObservableValue<Image> screenshotProperty() {

View File

@@ -58,19 +58,19 @@ public class Dialogs {
.setOkButtonKey(BUTTON_KEY_CLOSE);
}
public SimpleDialog.Builder prepareRecoveryVaultAdded(Stage window) {
public SimpleDialog.Builder prepareRecoveryVaultAdded(Stage window, String displayName) {
return createDialogBuilder().setOwner(window) //
.setTitleKey("recoveryKey.recoverExisting.title") //
.setMessageKey("recoveryKey.recoverExisting.message") //
.setDescriptionKey("recoveryKey.recoverExisting.description") //
.setIcon(FontAwesome5Icon.EXCLAMATION)//
.setDescriptionKey("recoveryKey.recoverExisting.description", displayName) //
.setIcon(FontAwesome5Icon.CHECK)//
.setOkButtonKey(BUTTON_KEY_CLOSE);
}
public SimpleDialog.Builder prepareRecoveryVaultAlreadyExists(Stage window) {
public SimpleDialog.Builder prepareRecoveryVaultAlreadyExists(Stage window, String displayName) {
return createDialogBuilder().setOwner(window) //
.setTitleKey("recoveryKey.alreadyExists.title") //
.setMessageKey("recoveryKey.alreadyExists.message") //
.setDescriptionKey("recoveryKey.alreadyExists.description") //
.setDescriptionKey("recoveryKey.alreadyExists.description", displayName) //
.setIcon(FontAwesome5Icon.EXCLAMATION)//
.setOkButtonKey(BUTTON_KEY_CLOSE);
}

View File

@@ -30,7 +30,7 @@ public class SimpleDialog {
FxmlLoaderFactory loaderFactory = FxmlLoaderFactory.forController( //
new SimpleDialogController(resolveText(builder.messageKey, null), //
resolveText(builder.descriptionKey, null), //
resolveText(builder.descriptionKey, builder.descriptionArgs), //
builder.icon, //
resolveText(builder.okButtonKey, null), //
builder.cancelButtonKey != null ? resolveText(builder.cancelButtonKey, null) : null, //
@@ -66,6 +66,7 @@ public class SimpleDialog {
private String[] titleArgs;
private String messageKey;
private String descriptionKey;
private String[] descriptionArgs;
private String okButtonKey;
private String cancelButtonKey;
private FontAwesome5Icon icon;
@@ -93,8 +94,9 @@ public class SimpleDialog {
return this;
}
public Builder setDescriptionKey(String descriptionKey) {
public Builder setDescriptionKey(String descriptionKey, String... args) {
this.descriptionKey = descriptionKey;
this.descriptionArgs = args;
return this;
}

View File

@@ -1,10 +1,14 @@
package org.cryptomator.ui.mainwindow;
import org.apache.commons.lang3.SystemUtils;
import org.cryptomator.common.recovery.RecoveryActionType;
import org.cryptomator.common.settings.Settings;
import org.cryptomator.common.settings.VaultSettings;
import org.cryptomator.common.vaults.Vault;
import org.cryptomator.common.vaults.VaultComponent;
import org.cryptomator.common.vaults.VaultConfigCache;
import org.cryptomator.common.vaults.VaultListManager;
import org.cryptomator.common.vaults.VaultState;
import org.cryptomator.cryptofs.CryptoFileSystemProvider;
import org.cryptomator.cryptofs.DirStructure;
import org.cryptomator.integrations.mount.MountService;
@@ -25,6 +29,7 @@ import javafx.beans.binding.BooleanBinding;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.value.ObservableValue;
import javafx.collections.ListChangeListener;
import javafx.collections.ObservableList;
@@ -40,6 +45,7 @@ import javafx.scene.input.KeyEvent;
import javafx.scene.input.MouseEvent;
import javafx.scene.input.TransferMode;
import javafx.scene.layout.StackPane;
import javafx.stage.DirectoryChooser;
import javafx.stage.Stage;
import java.io.File;
import java.io.IOException;
@@ -230,7 +236,71 @@ public class VaultListController implements FxController {
@FXML
public void didClickRecoverExistingVault() {
addVaultWizard.build().showRecoverExistingVaultWizard(mainWindow, dialogs, vaultComponentFactory,mountServices,vaultListManager,recoveryKeyWindow);
DirectoryChooser directoryChooser = new DirectoryChooser();
while (true) {
File selectedDirectory = directoryChooser.showDialog(mainWindow);
if (selectedDirectory == null) {
return;
}
boolean hasSubfolderD = new File(selectedDirectory, "d").isDirectory();
if (!hasSubfolderD) {
dialogs.prepareNoDDirectorySelectedDialog(mainWindow).build().showAndWait();
continue;
}
Vault preparedVault = prepareVault(selectedDirectory, vaultComponentFactory, mountServices);
if (vaultListManager.get(preparedVault.getPath()).isPresent()) {
dialogs.prepareRecoveryVaultAlreadyExists(mainWindow, vaultListManager.get(preparedVault.getPath()).get().getDisplayName()) //
.setOkAction(Stage::close) //
.build().showAndWait();
break;
}
VaultListManager.redetermineVaultState(preparedVault);
VaultState.Value state = preparedVault.getState();
switch (state) {
case VAULT_CONFIG_MISSING ->
recoveryKeyWindow.create(preparedVault, mainWindow, new SimpleObjectProperty<>(RecoveryActionType.RESTORE_VAULT_CONFIG)).showOnboardingDialogWindow();
case ALL_MISSING ->
recoveryKeyWindow.create(preparedVault, mainWindow, new SimpleObjectProperty<>(RecoveryActionType.RESTORE_ALL)).showOnboardingDialogWindow();
case LOCKED -> {
vaultListManager.addVault(preparedVault);
dialogs.prepareRecoveryVaultAdded(mainWindow, preparedVault.getDisplayName()).setOkAction(Stage::close).build().showAndWait();
}
}
break;
}
}
public static Vault prepareVault(File selectedDirectory, VaultComponent.Factory vaultComponentFactory, List<MountService> mountServices) {
Path selectedPath = selectedDirectory.toPath();
VaultSettings vaultSettings = VaultSettings.withRandomId();
vaultSettings.path.set(selectedPath);
if (selectedPath.getFileName() != null) {
vaultSettings.displayName.set(selectedPath.getFileName().toString());
} else {
vaultSettings.displayName.set("defaultVaultName");
}
var wrapper = new VaultConfigCache(vaultSettings);
Vault vault = vaultComponentFactory.create(vaultSettings, wrapper, LOCKED, null).vault();
try {
VaultListManager.determineVaultState(vault.getPath(), vaultSettings);
} catch (IOException e) {
LOG.warn("Failed to determine vault state for {}", vaultSettings.path.get(), e);
}
//due to https://github.com/cryptomator/cryptomator/issues/2880#issuecomment-1680313498
var nameOfWinfspLocalMounter = "org.cryptomator.frontend.fuse.mount.WinFspMountProvider";
if (SystemUtils.IS_OS_WINDOWS && vaultSettings.path.get().toString().contains("Dropbox") && mountServices.stream().anyMatch(s -> s.getClass().getName().equals(nameOfWinfspLocalMounter))) {
vaultSettings.mountService.setValue(nameOfWinfspLocalMounter);
}
return vault;
}
private void pressedShortcutToRemoveVault() {

View File

@@ -100,9 +100,9 @@ public class RecoveryKeyCreationController implements FxController {
@FXML
public void initialize() {
if (recoverType.get().equals(RecoveryActionType.SHOW_KEY)) {
if (recoverType.get() == RecoveryActionType.SHOW_KEY) {
window.setTitle(resourceBundle.getString("recoveryKey.display.title"));
} else if (recoverType.get().equals(RecoveryActionType.RESTORE_VAULT_CONFIG)) {
} else if (recoverType.get() == RecoveryActionType.RESTORE_VAULT_CONFIG) {
window.setTitle(resourceBundle.getString("recoveryKey.recoverVaultConfig.title"));
descriptionLabel.formatProperty().set(resourceBundle.getString("recoveryKey.recover.description"));
cancelButton.setOnAction((_) -> back());
@@ -156,7 +156,7 @@ public class RecoveryKeyCreationController implements FxController {
recoveryDirectory.moveRecoveredFile(VAULTCONFIG_FILENAME);
if (!vaultListManager.containsVault(vault.getPath())) {
if (!vaultListManager.isAlreadyAdded(vault.getPath())) {
vaultListManager.add(vault.getPath());
}
window.close();

View File

@@ -21,8 +21,6 @@ import org.cryptomator.ui.common.FxController;
import org.cryptomator.ui.common.FxmlFile;
import org.cryptomator.ui.common.FxmlScene;
import org.cryptomator.ui.controls.NumericTextField;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@RecoveryKeyScoped
public class RecoveryKeyExpertSettingsController implements FxController {
@@ -42,10 +40,10 @@ public class RecoveryKeyExpertSettingsController implements FxController {
private final Lazy<Scene> recoverScene;
private final BooleanBinding validShorteningThreshold;
@FXML public CheckBox expertSettingsCheckBox;
@FXML public NumericTextField shorteningThresholdTextField;
private static final Logger LOG = LoggerFactory.getLogger(RecoveryKeyExpertSettingsController.class);
@FXML
public CheckBox expertSettingsCheckBox;
@FXML
public NumericTextField shorteningThresholdTextField;
@Inject
public RecoveryKeyExpertSettingsController(@RecoveryKeyWindow Stage window, //
@@ -105,19 +103,21 @@ public class RecoveryKeyExpertSettingsController implements FxController {
@FXML
public void back() {
if(recoverType.get().equals(RecoveryActionType.RESTORE_ALL) && vault.getState().equals(VaultState.Value.VAULT_CONFIG_MISSING))
if (recoverType.get() == RecoveryActionType.RESTORE_ALL && vault.getState() == VaultState.Value.VAULT_CONFIG_MISSING) {
window.setScene(recoverScene.get());
else if(recoverType.get().equals(RecoveryActionType.RESTORE_ALL) && vault.getState().equals(VaultState.Value.ALL_MISSING))
} else if (recoverType.get() == RecoveryActionType.RESTORE_ALL && vault.getState() == VaultState.Value.ALL_MISSING) {
window.setScene(recoverScene.get());
else if(recoverType.get().equals(RecoveryActionType.RESTORE_VAULT_CONFIG))
} else if (recoverType.get() == RecoveryActionType.RESTORE_VAULT_CONFIG) {
window.setScene(onBoardingScene.get());
}
}
@FXML
public void next() {
if(recoverType.get().equals(RecoveryActionType.RESTORE_VAULT_CONFIG))
if (recoverType.get() == RecoveryActionType.RESTORE_VAULT_CONFIG) {
window.setScene(createScene.get());
else
} else {
window.setScene(resetPasswordScene.get());
}
}
}

View File

@@ -143,7 +143,7 @@ public class RecoveryKeyResetPasswordController implements FxController {
recoveryDirectory.moveRecoveredFile(MASTERKEY_FILENAME);
recoveryDirectory.moveRecoveredFile(VAULTCONFIG_FILENAME);
if (!vaultListManager.containsVault(vault.getPath())) {
if (!vaultListManager.isAlreadyAdded(vault.getPath())) {
vaultListManager.add(vault.getPath());
}
window.close();

View File

@@ -536,13 +536,12 @@ recoveryKey.recover.resetMasterkeyFileSuccess.message=Masterkey file reset succe
### Recover Kram
recoveryKey.recoverExisting.title=Vault Added
recoveryKey.recoverExisting.message=Recovery Vault added
recoveryKey.recoverExisting.description=Your Vault added successfully.
recoveryKey.recoverExisting.message=The vault was added successfully
recoveryKey.recoverExisting.description=Your vault "%s" has been added to your vault list. No recovery process was started.
recoveryKey.alreadyExists.title=Vault Already Exists
recoveryKey.alreadyExists.message=Vault already exists in VaultList.
recoveryKey.alreadyExists.description=Nothing happend.
recoveryKey.alreadyExists.message=This vault has already been added
recoveryKey.alreadyExists.description=Your vault "%s" is already present in your vault list and was therefore not added again.
recoveryKey.noDDirDetected.title=Invalid Selection
recoveryKey.noDDirDetected.description=The selected folder must contain a subfolder named "d".