diff --git a/.github/no-response.yml b/.github/no-response.yml deleted file mode 100644 index 090694a5b..000000000 --- a/.github/no-response.yml +++ /dev/null @@ -1,13 +0,0 @@ -# Configuration for probot-no-response - https://github.com/probot/no-response - -# Number of days of inactivity before an Issue is closed for lack of response -daysUntilClose: 14 -# Label requiring a response -responseRequiredLabel: state:awaiting-response -# Comment to post when closing an Issue for lack of response. Set to `false` to disable -closeComment: > - This issue has been automatically closed because there has been no response - to our request for more information from the original author. With only the - information that is currently in the issue, we don't have enough information - to take action. Please reach out if you have or find the answers we need so - that we can investigate further. diff --git a/.github/stale.yml b/.github/stale.yml deleted file mode 100644 index e32981b00..000000000 --- a/.github/stale.yml +++ /dev/null @@ -1,24 +0,0 @@ -# Number of days of inactivity before an issue becomes stale -daysUntilStale: 365 -# Number of days of inactivity before a stale issue is closed -daysUntilClose: 90 -# Issues with these labels will never be considered stale -exemptLabels: - - type:security-issue # never close automatically - - type:feature-request # never close automatically - - type:enhancement # never close automatically - - type:upstream-bug # never close automatically - - state:awaiting-response # handled by different bot - - state:blocked - - state:confirmed -# Set to true to ignore issues in a milestone (defaults to false) -exemptMilestones: true -# Label to use when marking an issue as stale -staleLabel: state:stale -# Comment to post when marking an issue as stale. Set to `false` to disable -markComment: > - This issue has been automatically marked as stale because it has not had - recent activity. It will be closed if no further activity occurs. Thank you - for your contributions. -# Comment to post when closing a stale issue. Set to `false` to disable -closeComment: false diff --git a/.github/workflows/no-response.yml b/.github/workflows/no-response.yml new file mode 100644 index 000000000..1e5a848dd --- /dev/null +++ b/.github/workflows/no-response.yml @@ -0,0 +1,22 @@ +# Configuration for close-stale-issues - https://github.com/marketplace/actions/close-stale-issues + +name: 'Close awaiting response issues' +on: + schedule: + - cron: '00 09 * * *' + +jobs: + no-response: + runs-on: ubuntu-latest + permissions: + issues: write + pull-requests: write + steps: + - uses: actions/stale@v8 + with: + days-before-stale: 14 + days-before-close: 0 + days-before-pr-close: -1 + stale-issue-label: 'state:stale' + close-issue-message: "This issue has been automatically closed because there has been no response to our request for more information from the original author. With only the information that is currently in the issue, we don't have enough information to take action. Please reach out if you have or find the answers we need so that we can investigate further." + only-labels: 'state:awaiting-response' diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml new file mode 100644 index 000000000..f3a57687d --- /dev/null +++ b/.github/workflows/stale.yml @@ -0,0 +1,24 @@ +# Configuration for close-stale-issues - https://github.com/marketplace/actions/close-stale-issues + +name: 'Close stale issues' +on: + schedule: + - cron: '00 09 * * *' + +jobs: + stale: + runs-on: ubuntu-latest + permissions: + issues: write + pull-requests: write + steps: + - uses: actions/stale@v8 + with: + days-before-stale: 365 + days-before-close: 90 + exempt-issue-labels: 'type:security-issue,type:feature-request,type:enhancement,type:upstream-bug,state:awaiting-response,state:blocked,state:confirmed' + exempt-all-milestones: true + stale-issue-label: 'state:stale' + stale-pr-label: 'state:stale' + stale-issue-message: 'This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.' + stale-pr-message: 'This PR has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.' diff --git a/dist/linux/common/org.cryptomator.Cryptomator.metainfo.xml b/dist/linux/common/org.cryptomator.Cryptomator.metainfo.xml index 2b830e108..107261f2b 100644 --- a/dist/linux/common/org.cryptomator.Cryptomator.metainfo.xml +++ b/dist/linux/common/org.cryptomator.Cryptomator.metainfo.xml @@ -66,6 +66,7 @@ + diff --git a/pom.xml b/pom.xml index a23c377fb..3a0c6e320 100644 --- a/pom.xml +++ b/pom.xml @@ -3,7 +3,7 @@ 4.0.0 org.cryptomator cryptomator - 1.7.5 + 1.8.0 Cryptomator Desktop App diff --git a/src/main/java/org/cryptomator/common/Constants.java b/src/main/java/org/cryptomator/common/Constants.java index 5069002e7..105fba3d6 100644 --- a/src/main/java/org/cryptomator/common/Constants.java +++ b/src/main/java/org/cryptomator/common/Constants.java @@ -1,5 +1,9 @@ package org.cryptomator.common; +import org.cryptomator.ui.keyloading.masterkeyfile.MasterkeyFileLoadingStrategy; + +import java.net.URI; + public interface Constants { String MASTERKEY_FILENAME = "masterkey.cryptomator"; @@ -7,6 +11,7 @@ public interface Constants { String VAULTCONFIG_FILENAME = "vault.cryptomator"; String CRYPTOMATOR_FILENAME_EXT = ".cryptomator"; String CRYPTOMATOR_FILENAME_GLOB = "*.cryptomator"; + URI DEFAULT_KEY_ID = URI.create(MasterkeyFileLoadingStrategy.SCHEME + ":" + MASTERKEY_FILENAME); byte[] PEPPER = new byte[0]; } diff --git a/src/main/java/org/cryptomator/ui/addvaultwizard/AddVaultModule.java b/src/main/java/org/cryptomator/ui/addvaultwizard/AddVaultModule.java index c6acbadf6..02327aaf4 100644 --- a/src/main/java/org/cryptomator/ui/addvaultwizard/AddVaultModule.java +++ b/src/main/java/org/cryptomator/ui/addvaultwizard/AddVaultModule.java @@ -11,8 +11,8 @@ import org.cryptomator.ui.common.FxControllerKey; import org.cryptomator.ui.common.FxmlFile; import org.cryptomator.ui.common.FxmlLoaderFactory; import org.cryptomator.ui.common.FxmlScene; -import org.cryptomator.ui.common.NewPasswordController; -import org.cryptomator.ui.common.PasswordStrengthUtil; +import org.cryptomator.ui.changepassword.NewPasswordController; +import org.cryptomator.ui.changepassword.PasswordStrengthUtil; import org.cryptomator.ui.common.StageFactory; import org.cryptomator.ui.fxapp.PrimaryStage; import org.cryptomator.ui.recoverykey.RecoveryKeyDisplayController; diff --git a/src/main/java/org/cryptomator/ui/addvaultwizard/CreateNewVaultPasswordController.java b/src/main/java/org/cryptomator/ui/addvaultwizard/CreateNewVaultPasswordController.java index 0148686f3..81c6ce2da 100644 --- a/src/main/java/org/cryptomator/ui/addvaultwizard/CreateNewVaultPasswordController.java +++ b/src/main/java/org/cryptomator/ui/addvaultwizard/CreateNewVaultPasswordController.java @@ -13,7 +13,7 @@ import org.cryptomator.cryptolib.common.MasterkeyFileAccess; import org.cryptomator.ui.common.FxController; import org.cryptomator.ui.common.FxmlFile; import org.cryptomator.ui.common.FxmlScene; -import org.cryptomator.ui.common.NewPasswordController; +import org.cryptomator.ui.changepassword.NewPasswordController; import org.cryptomator.ui.common.Tasks; import org.cryptomator.ui.fxapp.FxApplicationWindows; import org.cryptomator.ui.keyloading.masterkeyfile.MasterkeyFileLoadingStrategy; @@ -48,13 +48,13 @@ import java.util.ResourceBundle; import java.util.concurrent.ExecutorService; import static java.nio.charset.StandardCharsets.US_ASCII; +import static org.cryptomator.common.Constants.DEFAULT_KEY_ID; import static org.cryptomator.common.Constants.MASTERKEY_FILENAME; @AddVaultWizardScoped public class CreateNewVaultPasswordController implements FxController { private static final Logger LOG = LoggerFactory.getLogger(CreateNewVaultPasswordController.class); - private static final URI DEFAULT_KEY_ID = URI.create(MasterkeyFileLoadingStrategy.SCHEME + ":" + MASTERKEY_FILENAME); // TODO better place? private final Stage window; private final Lazy chooseLocationScene; diff --git a/src/main/java/org/cryptomator/ui/changepassword/ChangePasswordController.java b/src/main/java/org/cryptomator/ui/changepassword/ChangePasswordController.java index 200a70328..4d9666785 100644 --- a/src/main/java/org/cryptomator/ui/changepassword/ChangePasswordController.java +++ b/src/main/java/org/cryptomator/ui/changepassword/ChangePasswordController.java @@ -9,7 +9,6 @@ import org.cryptomator.cryptolib.common.MasterkeyFileAccess; import org.cryptomator.integrations.keychain.KeychainAccessException; import org.cryptomator.ui.common.Animations; import org.cryptomator.ui.common.FxController; -import org.cryptomator.ui.common.NewPasswordController; import org.cryptomator.ui.controls.NiceSecurePasswordField; import org.cryptomator.ui.fxapp.FxApplicationWindows; import org.slf4j.Logger; diff --git a/src/main/java/org/cryptomator/ui/changepassword/ChangePasswordModule.java b/src/main/java/org/cryptomator/ui/changepassword/ChangePasswordModule.java index d95b19410..947f87aeb 100644 --- a/src/main/java/org/cryptomator/ui/changepassword/ChangePasswordModule.java +++ b/src/main/java/org/cryptomator/ui/changepassword/ChangePasswordModule.java @@ -10,8 +10,6 @@ import org.cryptomator.ui.common.FxControllerKey; import org.cryptomator.ui.common.FxmlFile; import org.cryptomator.ui.common.FxmlLoaderFactory; import org.cryptomator.ui.common.FxmlScene; -import org.cryptomator.ui.common.NewPasswordController; -import org.cryptomator.ui.common.PasswordStrengthUtil; import org.cryptomator.ui.common.StageFactory; import javax.inject.Named; diff --git a/src/main/java/org/cryptomator/ui/common/NewPasswordController.java b/src/main/java/org/cryptomator/ui/changepassword/NewPasswordController.java similarity index 94% rename from src/main/java/org/cryptomator/ui/common/NewPasswordController.java rename to src/main/java/org/cryptomator/ui/changepassword/NewPasswordController.java index 6f029efe1..99e43f623 100644 --- a/src/main/java/org/cryptomator/ui/common/NewPasswordController.java +++ b/src/main/java/org/cryptomator/ui/changepassword/NewPasswordController.java @@ -1,5 +1,7 @@ -package org.cryptomator.ui.common; +package org.cryptomator.ui.changepassword; +import org.cryptomator.common.Passphrase; +import org.cryptomator.ui.common.FxController; import org.cryptomator.ui.controls.FontAwesome5IconView; import org.cryptomator.ui.controls.NiceSecurePasswordField; @@ -91,4 +93,8 @@ public class NewPasswordController implements FxController { return passwordStrength.get(); } + public Passphrase getNewPassword() { + return passwordField.getCharacters(); + } + } diff --git a/src/main/java/org/cryptomator/ui/common/PasswordStrengthUtil.java b/src/main/java/org/cryptomator/ui/changepassword/PasswordStrengthUtil.java similarity index 98% rename from src/main/java/org/cryptomator/ui/common/PasswordStrengthUtil.java rename to src/main/java/org/cryptomator/ui/changepassword/PasswordStrengthUtil.java index 0224118cd..202e2f9cb 100644 --- a/src/main/java/org/cryptomator/ui/common/PasswordStrengthUtil.java +++ b/src/main/java/org/cryptomator/ui/changepassword/PasswordStrengthUtil.java @@ -6,7 +6,7 @@ * Contributors: * Jean-Noël Charon - initial API and implementation *******************************************************************************/ -package org.cryptomator.ui.common; +package org.cryptomator.ui.changepassword; import com.nulabinc.zxcvbn.Zxcvbn; import org.cryptomator.common.Environment; diff --git a/src/main/java/org/cryptomator/ui/common/FxmlFile.java b/src/main/java/org/cryptomator/ui/common/FxmlFile.java index c5b66498a..3bec75899 100644 --- a/src/main/java/org/cryptomator/ui/common/FxmlFile.java +++ b/src/main/java/org/cryptomator/ui/common/FxmlFile.java @@ -9,6 +9,9 @@ public enum FxmlFile { ADDVAULT_SUCCESS("/fxml/addvault_success.fxml"), // ADDVAULT_WELCOME("/fxml/addvault_welcome.fxml"), // CHANGEPASSWORD("/fxml/changepassword.fxml"), // + CONVERTVAULT_HUBTOPASSWORD_START("/fxml/convertvault_hubtopassword_start.fxml"), // + CONVERTVAULT_HUBTOPASSWORD_CONVERT("/fxml/convertvault_hubtopassword_convert.fxml"), // + CONVERTVAULT_HUBTOPASSWORD_SUCCESS("/fxml/convertvault_hubtopassword_success.fxml"), // ERROR("/fxml/error.fxml"), // FORGET_PASSWORD("/fxml/forget_password.fxml"), // HEALTH_START("/fxml/health_start.fxml"), // diff --git a/src/main/java/org/cryptomator/ui/controls/FontAwesome5Icon.java b/src/main/java/org/cryptomator/ui/controls/FontAwesome5Icon.java index 60f37719b..77c3cb042 100644 --- a/src/main/java/org/cryptomator/ui/controls/FontAwesome5Icon.java +++ b/src/main/java/org/cryptomator/ui/controls/FontAwesome5Icon.java @@ -18,6 +18,7 @@ public enum FontAwesome5Icon { COPY("\uF0C5"), // CROWN("\uF521"), // EDIT("\uF044"), // + EXCHANGE_ALT("\uF362"), // EXCLAMATION("\uF12A"), // EXCLAMATION_CIRCLE("\uF06A"), // EXCLAMATION_TRIANGLE("\uF071"), // diff --git a/src/main/java/org/cryptomator/ui/controls/SecurePasswordField.java b/src/main/java/org/cryptomator/ui/controls/SecurePasswordField.java index a7ec9df6a..40ef67058 100644 --- a/src/main/java/org/cryptomator/ui/controls/SecurePasswordField.java +++ b/src/main/java/org/cryptomator/ui/controls/SecurePasswordField.java @@ -43,7 +43,7 @@ public class SecurePasswordField extends TextField { private static final char WIPE_CHAR = ' '; private static final int INITIAL_BUFFER_SIZE = 50; private static final int GROW_BUFFER_SIZE = 50; - private static final String DEFAULT_PLACEHOLDER = "●"; + private static final String DEFAULT_PLACEHOLDER = "•"; private static final String STYLE_CLASS = "secure-password-field"; private static final KeyCodeCombination SHORTCUT_BACKSPACE = new KeyCodeCombination(KeyCode.BACK_SPACE, KeyCombination.SHORTCUT_DOWN); diff --git a/src/main/java/org/cryptomator/ui/convertvault/ConvertVaultComponent.java b/src/main/java/org/cryptomator/ui/convertvault/ConvertVaultComponent.java new file mode 100644 index 000000000..5b162c070 --- /dev/null +++ b/src/main/java/org/cryptomator/ui/convertvault/ConvertVaultComponent.java @@ -0,0 +1,41 @@ +/******************************************************************************* + * 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.convertvault; + +import dagger.BindsInstance; +import dagger.Lazy; +import dagger.Subcomponent; +import org.cryptomator.common.vaults.Vault; +import org.cryptomator.ui.common.FxmlFile; +import org.cryptomator.ui.common.FxmlScene; + +import javax.inject.Named; +import javafx.scene.Scene; +import javafx.stage.Stage; + +@ConvertVaultScoped +@Subcomponent(modules = {ConvertVaultModule.class}) +public interface ConvertVaultComponent { + + @ConvertVaultWindow + Stage window(); + + @FxmlScene(FxmlFile.CONVERTVAULT_HUBTOPASSWORD_START) + Lazy hubToPasswordScene(); + + default void showHubToPasswordWindow() { + Stage stage = window(); + stage.setScene(hubToPasswordScene().get()); + stage.sizeToScene(); + stage.show(); + } + + @Subcomponent.Factory + interface Factory { + + ConvertVaultComponent create(@BindsInstance @ConvertVaultWindow Vault vault, @BindsInstance @Named("convertVaultOwner") Stage owner); + } +} \ No newline at end of file diff --git a/src/main/java/org/cryptomator/ui/convertvault/ConvertVaultModule.java b/src/main/java/org/cryptomator/ui/convertvault/ConvertVaultModule.java new file mode 100644 index 000000000..f70242d2b --- /dev/null +++ b/src/main/java/org/cryptomator/ui/convertvault/ConvertVaultModule.java @@ -0,0 +1,126 @@ +package org.cryptomator.ui.convertvault; + +import dagger.Binds; +import dagger.Module; +import dagger.Provides; +import dagger.multibindings.IntoMap; +import org.cryptomator.common.vaults.Vault; +import org.cryptomator.cryptofs.VaultConfig; +import org.cryptomator.ui.changepassword.NewPasswordController; +import org.cryptomator.ui.changepassword.PasswordStrengthUtil; +import org.cryptomator.ui.common.DefaultSceneFactory; +import org.cryptomator.ui.common.FxController; +import org.cryptomator.ui.common.FxControllerKey; +import org.cryptomator.ui.common.FxmlFile; +import org.cryptomator.ui.common.FxmlLoaderFactory; +import org.cryptomator.ui.common.FxmlScene; +import org.cryptomator.ui.common.StageFactory; +import org.cryptomator.ui.recoverykey.RecoveryKeyFactory; +import org.cryptomator.ui.recoverykey.RecoveryKeyValidateController; + +import javax.inject.Named; +import javax.inject.Provider; +import javafx.beans.property.SimpleStringProperty; +import javafx.beans.property.StringProperty; +import javafx.scene.Scene; +import javafx.stage.Modality; +import javafx.stage.Stage; +import java.io.IOException; +import java.util.Map; +import java.util.ResourceBundle; + +@Module +abstract class ConvertVaultModule { + + //TODO: if this fails, we cannot display an error + @Provides + @ConvertVaultWindow + @ConvertVaultScoped + static VaultConfig.UnverifiedVaultConfig vaultConfig(@ConvertVaultWindow Vault vault) { + try { + return vault.getVaultConfigCache().get(); + } catch (IOException e) { + return null; + } + } + + @Provides + @ConvertVaultWindow + @ConvertVaultScoped + static StringProperty provideRecoveryKeyProperty() { + return new SimpleStringProperty(); + } + + @Provides + @ConvertVaultWindow + @ConvertVaultScoped + static FxmlLoaderFactory provideFxmlLoaderFactory(Map, Provider> factories, DefaultSceneFactory sceneFactory, ResourceBundle resourceBundle) { + return new FxmlLoaderFactory(factories, sceneFactory, resourceBundle); + } + + @Provides + @ConvertVaultWindow + @ConvertVaultScoped + static Stage provideStage(StageFactory factory, @Named("convertVaultOwner") Stage owner, ResourceBundle resourceBundle) { + Stage stage = factory.create(); + stage.setResizable(false); + stage.initModality(Modality.WINDOW_MODAL); + stage.initOwner(owner); + stage.setTitle(resourceBundle.getString("convertVault.title")); + return stage; + } + + @Provides + @FxmlScene(FxmlFile.CONVERTVAULT_HUBTOPASSWORD_START) + @ConvertVaultScoped + static Scene provideHubToPasswordStartScene(@ConvertVaultWindow FxmlLoaderFactory fxmlLoaders) { + return fxmlLoaders.createScene(FxmlFile.CONVERTVAULT_HUBTOPASSWORD_START); + } + + @Provides + @FxmlScene(FxmlFile.CONVERTVAULT_HUBTOPASSWORD_CONVERT) + @ConvertVaultScoped + static Scene provideHubToPasswordConvertScene(@ConvertVaultWindow FxmlLoaderFactory fxmlLoaders) { + return fxmlLoaders.createScene(FxmlFile.CONVERTVAULT_HUBTOPASSWORD_CONVERT); + } + + @Provides + @FxmlScene(FxmlFile.CONVERTVAULT_HUBTOPASSWORD_SUCCESS) + @ConvertVaultScoped + static Scene provideHubToPasswordSuccessScene(@ConvertVaultWindow FxmlLoaderFactory fxmlLoaders) { + return fxmlLoaders.createScene(FxmlFile.CONVERTVAULT_HUBTOPASSWORD_SUCCESS); + } + + // ------------------ + + @Binds + @IntoMap + @FxControllerKey(HubToPasswordStartController.class) + abstract FxController bindHubToPasswordStartController(HubToPasswordStartController controller); + + @Binds + @IntoMap + @FxControllerKey(HubToPasswordConvertController.class) + abstract FxController bindHubToPasswordConvertController(HubToPasswordConvertController controller); + + @Binds + @IntoMap + @FxControllerKey(HubToPasswordSuccessController.class) + abstract FxController bindHubToPasswordSuccessController(HubToPasswordSuccessController controller); + + + @Provides + @IntoMap + @FxControllerKey(NewPasswordController.class) + static FxController provideNewPasswordController(ResourceBundle resourceBundle, PasswordStrengthUtil strengthRater) { + return new NewPasswordController(resourceBundle, strengthRater); + } + + @Provides + @IntoMap + @FxControllerKey(RecoveryKeyValidateController.class) + static FxController bindRecoveryKeyValidateController(@ConvertVaultWindow Vault vault, @ConvertVaultWindow VaultConfig.UnverifiedVaultConfig vaultConfig, @ConvertVaultWindow StringProperty recoveryKey, RecoveryKeyFactory recoveryKeyFactory) { + return new RecoveryKeyValidateController(vault, vaultConfig, recoveryKey, recoveryKeyFactory); + } + +} diff --git a/src/main/java/org/cryptomator/ui/convertvault/ConvertVaultScoped.java b/src/main/java/org/cryptomator/ui/convertvault/ConvertVaultScoped.java new file mode 100644 index 000000000..45ff780ae --- /dev/null +++ b/src/main/java/org/cryptomator/ui/convertvault/ConvertVaultScoped.java @@ -0,0 +1,13 @@ +package org.cryptomator.ui.convertvault; + +import javax.inject.Scope; +import java.lang.annotation.Documented; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +@Scope +@Documented +@Retention(RetentionPolicy.RUNTIME) +@interface ConvertVaultScoped { + +} diff --git a/src/main/java/org/cryptomator/ui/convertvault/ConvertVaultWindow.java b/src/main/java/org/cryptomator/ui/convertvault/ConvertVaultWindow.java new file mode 100644 index 000000000..4ea9dc935 --- /dev/null +++ b/src/main/java/org/cryptomator/ui/convertvault/ConvertVaultWindow.java @@ -0,0 +1,14 @@ +package org.cryptomator.ui.convertvault; + +import javax.inject.Qualifier; +import java.lang.annotation.Documented; +import java.lang.annotation.Retention; + +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +@Qualifier +@Documented +@Retention(RUNTIME) +@interface ConvertVaultWindow { + +} diff --git a/src/main/java/org/cryptomator/ui/convertvault/HubToPasswordConvertController.java b/src/main/java/org/cryptomator/ui/convertvault/HubToPasswordConvertController.java new file mode 100644 index 000000000..51ff65ec1 --- /dev/null +++ b/src/main/java/org/cryptomator/ui/convertvault/HubToPasswordConvertController.java @@ -0,0 +1,171 @@ +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.VaultConfig; +import org.cryptomator.cryptofs.VaultVersionMismatchException; +import org.cryptomator.cryptofs.common.BackupHelper; +import org.cryptomator.cryptolib.api.MasterkeyLoadingFailedException; +import org.cryptomator.cryptolib.common.MasterkeyFileAccess; +import org.cryptomator.ui.changepassword.NewPasswordController; +import org.cryptomator.ui.common.FxController; +import org.cryptomator.ui.common.FxmlFile; +import org.cryptomator.ui.common.FxmlScene; +import org.cryptomator.ui.fxapp.FxApplicationWindows; +import org.cryptomator.ui.recoverykey.RecoveryKeyFactory; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.inject.Inject; +import javafx.application.Platform; +import javafx.beans.binding.Bindings; +import javafx.beans.property.BooleanProperty; +import javafx.beans.property.SimpleBooleanProperty; +import javafx.beans.property.StringProperty; +import javafx.fxml.FXML; +import javafx.scene.Scene; +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; +import java.util.ResourceBundle; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CompletionException; +import java.util.concurrent.ExecutorService; + +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; + +public class HubToPasswordConvertController implements FxController { + + private static final Logger LOG = LoggerFactory.getLogger(HubToPasswordConvertController.class); + + private final Stage window; + private final Lazy successScene; + private final FxApplicationWindows applicationWindows; + private final Vault vault; + private final StringProperty recoveryKey; + private final RecoveryKeyFactory recoveryKeyFactory; + private final MasterkeyFileAccess masterkeyFileAccess; + private final ExecutorService backgroundExecutorService; + private final ResourceBundle resourceBundle; + private final BooleanProperty conversionStarted; + + @FXML + NewPasswordController newPasswordController; + public Button convertBtn; + + @Inject + public HubToPasswordConvertController(@ConvertVaultWindow Stage window, @FxmlScene(FxmlFile.CONVERTVAULT_HUBTOPASSWORD_SUCCESS) Lazy successScene, FxApplicationWindows applicationWindows, @ConvertVaultWindow Vault vault, @ConvertVaultWindow StringProperty recoveryKey, RecoveryKeyFactory recoveryKeyFactory, MasterkeyFileAccess masterkeyFileAccess, ExecutorService backgroundExecutorService, ResourceBundle resourceBundle) { + this.window = window; + this.successScene = successScene; + this.applicationWindows = applicationWindows; + this.vault = vault; + this.recoveryKey = recoveryKey; + this.recoveryKeyFactory = recoveryKeyFactory; + this.masterkeyFileAccess = masterkeyFileAccess; + this.backgroundExecutorService = backgroundExecutorService; + this.resourceBundle = resourceBundle; + this.conversionStarted = new SimpleBooleanProperty(false); + + } + + @FXML + public void initialize() { + convertBtn.disableProperty().bind(Bindings.createBooleanBinding( // + () -> !newPasswordController.isGoodPassword() || conversionStarted.get(), // + newPasswordController.goodPasswordProperty(), // + conversionStarted)); + convertBtn.contentDisplayProperty().bind(Bindings.createObjectBinding( // + () -> conversionStarted.getValue() ? ContentDisplay.LEFT : ContentDisplay.TEXT_ONLY, // + conversionStarted)); + convertBtn.textProperty().bind(Bindings.createStringBinding( // + () -> resourceBundle.getString("convertVault.convert.convertBtn." + (conversionStarted.get() ? "processing" : "before")), // + conversionStarted)); + } + + @FXML + public void close() { + window.close(); + } + + @FXML + public void convert() { + Preconditions.checkState(newPasswordController.isGoodPassword()); + LOG.info("Converting access method of vault {} from hub to password", vault.getPath()); + CompletableFuture.runAsync(() -> conversionStarted.setValue(true), Platform::runLater) // + .thenRunAsync(this::convertInternal, backgroundExecutorService) // + .whenCompleteAsync((result, exception) -> { + if (exception == null) { + LOG.info("Conversion of vault {} succeeded.", vault.getPath()); + window.setScene(successScene.get()); + } else { + LOG.error("Conversion of vault {} failed.", vault.getPath(), exception); + applicationWindows.showErrorWindow(exception, window, null); + } + }, Platform::runLater); // + } + + //visible for testing + void convertInternal() throws CompletionException, IllegalArgumentException { + var passphrase = newPasswordController.getNewPassword(); + var vaultPath = vault.getPath(); + try { + //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) { + throw new CompletionException("Vault conversion failed", e); + } finally { + passphrase.destroy(); + } + } + + //visible for testing + void backupHubConfig(Path hubConfigPath) throws IOException { + byte[] hubConfigBytes = Files.readAllBytes(hubConfigPath); + 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 + Path createPasswordConfig(Path passwordConfigPath, Path masterkeyFile, Passphrase passphrase) throws IOException, MasterkeyLoadingFailedException { + var unverifiedVaultConfig = vault.getVaultConfigCache().get(); + 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(); + 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; + } + } + +} diff --git a/src/main/java/org/cryptomator/ui/convertvault/HubToPasswordStartController.java b/src/main/java/org/cryptomator/ui/convertvault/HubToPasswordStartController.java new file mode 100644 index 000000000..04d7167c2 --- /dev/null +++ b/src/main/java/org/cryptomator/ui/convertvault/HubToPasswordStartController.java @@ -0,0 +1,47 @@ +package org.cryptomator.ui.convertvault; + +import dagger.Lazy; +import org.cryptomator.ui.common.FxController; +import org.cryptomator.ui.common.FxmlFile; +import org.cryptomator.ui.common.FxmlScene; +import org.cryptomator.ui.recoverykey.RecoveryKeyValidateController; + +import javax.inject.Inject; +import javafx.fxml.FXML; +import javafx.scene.Scene; +import javafx.stage.Stage; + +public class HubToPasswordStartController implements FxController { + + private final Stage window; + private final Lazy convertScene; + + @FXML + RecoveryKeyValidateController recoveryKeyValidateController; + + @Inject + public HubToPasswordStartController(@ConvertVaultWindow Stage window, @FxmlScene(FxmlFile.CONVERTVAULT_HUBTOPASSWORD_CONVERT) Lazy convertScene) { + this.window = window; + this.convertScene = convertScene; + } + + @FXML + public void initialize() { + } + + @FXML + public void close() { + window.close(); + } + + @FXML + public void next() { + window.setScene(convertScene.get()); + } + + /* Getter/Setter */ + + public RecoveryKeyValidateController getValidateController() { + return recoveryKeyValidateController; + } +} diff --git a/src/main/java/org/cryptomator/ui/convertvault/HubToPasswordSuccessController.java b/src/main/java/org/cryptomator/ui/convertvault/HubToPasswordSuccessController.java new file mode 100644 index 000000000..3aee13383 --- /dev/null +++ b/src/main/java/org/cryptomator/ui/convertvault/HubToPasswordSuccessController.java @@ -0,0 +1,32 @@ +package org.cryptomator.ui.convertvault; + +import org.cryptomator.common.vaults.Vault; +import org.cryptomator.ui.common.FxController; + +import javax.inject.Inject; +import javafx.fxml.FXML; +import javafx.stage.Stage; + +public class HubToPasswordSuccessController implements FxController { + + private final Stage window; + private final Vault vault; + + @Inject + HubToPasswordSuccessController(@ConvertVaultWindow Stage window, @ConvertVaultWindow Vault vault) { + this.window = window; + this.vault = vault; + } + + @FXML + public void close() { + window.close(); + window.getOwner().hide(); + } + + /* Observables */ + + public Vault getVault() { + return vault; + } +} diff --git a/src/main/java/org/cryptomator/ui/common/ErrorComponent.java b/src/main/java/org/cryptomator/ui/error/ErrorComponent.java similarity index 83% rename from src/main/java/org/cryptomator/ui/common/ErrorComponent.java rename to src/main/java/org/cryptomator/ui/error/ErrorComponent.java index 8cb430584..554aa65f1 100644 --- a/src/main/java/org/cryptomator/ui/common/ErrorComponent.java +++ b/src/main/java/org/cryptomator/ui/error/ErrorComponent.java @@ -1,8 +1,10 @@ -package org.cryptomator.ui.common; +package org.cryptomator.ui.error; import dagger.BindsInstance; import dagger.Subcomponent; import org.cryptomator.common.Nullable; +import org.cryptomator.ui.common.FxmlFile; +import org.cryptomator.ui.common.FxmlScene; import javafx.scene.Scene; import javafx.stage.Stage; diff --git a/src/main/java/org/cryptomator/ui/common/ErrorController.java b/src/main/java/org/cryptomator/ui/error/ErrorController.java similarity index 98% rename from src/main/java/org/cryptomator/ui/common/ErrorController.java rename to src/main/java/org/cryptomator/ui/error/ErrorController.java index 15d2ee41f..422a44157 100644 --- a/src/main/java/org/cryptomator/ui/common/ErrorController.java +++ b/src/main/java/org/cryptomator/ui/error/ErrorController.java @@ -1,8 +1,9 @@ -package org.cryptomator.ui.common; +package org.cryptomator.ui.error; import org.cryptomator.common.Environment; import org.cryptomator.common.ErrorCode; import org.cryptomator.common.Nullable; +import org.cryptomator.ui.common.FxController; import javax.inject.Inject; import javax.inject.Named; diff --git a/src/main/java/org/cryptomator/ui/common/ErrorModule.java b/src/main/java/org/cryptomator/ui/error/ErrorModule.java similarity index 81% rename from src/main/java/org/cryptomator/ui/common/ErrorModule.java rename to src/main/java/org/cryptomator/ui/error/ErrorModule.java index 01b8790c1..d9ac6eab9 100644 --- a/src/main/java/org/cryptomator/ui/common/ErrorModule.java +++ b/src/main/java/org/cryptomator/ui/error/ErrorModule.java @@ -1,10 +1,16 @@ -package org.cryptomator.ui.common; +package org.cryptomator.ui.error; import dagger.Binds; import dagger.Module; import dagger.Provides; import dagger.multibindings.IntoMap; import org.cryptomator.common.ErrorCode; +import org.cryptomator.ui.common.DefaultSceneFactory; +import org.cryptomator.ui.common.FxController; +import org.cryptomator.ui.common.FxControllerKey; +import org.cryptomator.ui.common.FxmlFile; +import org.cryptomator.ui.common.FxmlLoaderFactory; +import org.cryptomator.ui.common.FxmlScene; import javax.inject.Named; import javax.inject.Provider; diff --git a/src/main/java/org/cryptomator/ui/forgetPassword/ForgetPasswordComponent.java b/src/main/java/org/cryptomator/ui/forgetpassword/ForgetPasswordComponent.java similarity index 96% rename from src/main/java/org/cryptomator/ui/forgetPassword/ForgetPasswordComponent.java rename to src/main/java/org/cryptomator/ui/forgetpassword/ForgetPasswordComponent.java index e7300bb79..347065b85 100644 --- a/src/main/java/org/cryptomator/ui/forgetPassword/ForgetPasswordComponent.java +++ b/src/main/java/org/cryptomator/ui/forgetpassword/ForgetPasswordComponent.java @@ -1,4 +1,4 @@ -package org.cryptomator.ui.forgetPassword; +package org.cryptomator.ui.forgetpassword; import dagger.BindsInstance; import dagger.Lazy; diff --git a/src/main/java/org/cryptomator/ui/forgetPassword/ForgetPasswordController.java b/src/main/java/org/cryptomator/ui/forgetpassword/ForgetPasswordController.java similarity index 97% rename from src/main/java/org/cryptomator/ui/forgetPassword/ForgetPasswordController.java rename to src/main/java/org/cryptomator/ui/forgetpassword/ForgetPasswordController.java index 8cd43ae22..f8a4fc4dd 100644 --- a/src/main/java/org/cryptomator/ui/forgetPassword/ForgetPasswordController.java +++ b/src/main/java/org/cryptomator/ui/forgetpassword/ForgetPasswordController.java @@ -1,4 +1,4 @@ -package org.cryptomator.ui.forgetPassword; +package org.cryptomator.ui.forgetpassword; import org.cryptomator.common.keychain.KeychainManager; import org.cryptomator.common.vaults.Vault; diff --git a/src/main/java/org/cryptomator/ui/forgetPassword/ForgetPasswordModule.java b/src/main/java/org/cryptomator/ui/forgetpassword/ForgetPasswordModule.java similarity index 98% rename from src/main/java/org/cryptomator/ui/forgetPassword/ForgetPasswordModule.java rename to src/main/java/org/cryptomator/ui/forgetpassword/ForgetPasswordModule.java index b0c34e9f5..1a06678cb 100644 --- a/src/main/java/org/cryptomator/ui/forgetPassword/ForgetPasswordModule.java +++ b/src/main/java/org/cryptomator/ui/forgetpassword/ForgetPasswordModule.java @@ -1,4 +1,4 @@ -package org.cryptomator.ui.forgetPassword; +package org.cryptomator.ui.forgetpassword; import dagger.Binds; import dagger.Module; diff --git a/src/main/java/org/cryptomator/ui/forgetPassword/ForgetPasswordScoped.java b/src/main/java/org/cryptomator/ui/forgetpassword/ForgetPasswordScoped.java similarity index 85% rename from src/main/java/org/cryptomator/ui/forgetPassword/ForgetPasswordScoped.java rename to src/main/java/org/cryptomator/ui/forgetpassword/ForgetPasswordScoped.java index 5be483753..bc0bd738e 100644 --- a/src/main/java/org/cryptomator/ui/forgetPassword/ForgetPasswordScoped.java +++ b/src/main/java/org/cryptomator/ui/forgetpassword/ForgetPasswordScoped.java @@ -1,4 +1,4 @@ -package org.cryptomator.ui.forgetPassword; +package org.cryptomator.ui.forgetpassword; import javax.inject.Scope; import java.lang.annotation.Documented; diff --git a/src/main/java/org/cryptomator/ui/forgetPassword/ForgetPasswordWindow.java b/src/main/java/org/cryptomator/ui/forgetpassword/ForgetPasswordWindow.java similarity index 85% rename from src/main/java/org/cryptomator/ui/forgetPassword/ForgetPasswordWindow.java rename to src/main/java/org/cryptomator/ui/forgetpassword/ForgetPasswordWindow.java index 285119e0a..e9162f45d 100644 --- a/src/main/java/org/cryptomator/ui/forgetPassword/ForgetPasswordWindow.java +++ b/src/main/java/org/cryptomator/ui/forgetpassword/ForgetPasswordWindow.java @@ -1,4 +1,4 @@ -package org.cryptomator.ui.forgetPassword; +package org.cryptomator.ui.forgetpassword; import javax.inject.Qualifier; import java.lang.annotation.Documented; diff --git a/src/main/java/org/cryptomator/ui/fxapp/FxApplicationModule.java b/src/main/java/org/cryptomator/ui/fxapp/FxApplicationModule.java index cdeb764be..877675b9c 100644 --- a/src/main/java/org/cryptomator/ui/fxapp/FxApplicationModule.java +++ b/src/main/java/org/cryptomator/ui/fxapp/FxApplicationModule.java @@ -7,9 +7,7 @@ package org.cryptomator.ui.fxapp; import dagger.Module; import dagger.Provides; -import org.apache.commons.lang3.SystemUtils; -import org.cryptomator.ui.common.ErrorComponent; -import org.cryptomator.ui.common.StageFactory; +import org.cryptomator.ui.error.ErrorComponent; import org.cryptomator.ui.lock.LockComponent; import org.cryptomator.ui.mainwindow.MainWindowComponent; import org.cryptomator.ui.preferences.PreferencesComponent; @@ -18,13 +16,9 @@ import org.cryptomator.ui.quit.QuitComponent; import org.cryptomator.ui.traymenu.TrayMenuComponent; import org.cryptomator.ui.unlock.UnlockComponent; -import javax.inject.Named; import javafx.scene.image.Image; import java.io.IOException; import java.io.InputStream; -import java.io.UncheckedIOException; -import java.util.Collections; -import java.util.List; @Module(includes = {UpdateCheckerModule.class}, subcomponents = {TrayMenuComponent.class, MainWindowComponent.class, PreferencesComponent.class, UnlockComponent.class, LockComponent.class, QuitComponent.class, ErrorComponent.class}) abstract class FxApplicationModule { diff --git a/src/main/java/org/cryptomator/ui/fxapp/FxApplicationWindows.java b/src/main/java/org/cryptomator/ui/fxapp/FxApplicationWindows.java index 5d38a9017..2b4f8e7bc 100644 --- a/src/main/java/org/cryptomator/ui/fxapp/FxApplicationWindows.java +++ b/src/main/java/org/cryptomator/ui/fxapp/FxApplicationWindows.java @@ -5,7 +5,7 @@ import dagger.Lazy; import org.cryptomator.common.vaults.Vault; import org.cryptomator.common.vaults.VaultState; import org.cryptomator.integrations.tray.TrayIntegrationProvider; -import org.cryptomator.ui.common.ErrorComponent; +import org.cryptomator.ui.error.ErrorComponent; import org.cryptomator.ui.lock.LockComponent; import org.cryptomator.ui.mainwindow.MainWindowComponent; import org.cryptomator.ui.preferences.PreferencesComponent; diff --git a/src/main/java/org/cryptomator/ui/keyloading/hub/HubKeyLoadingModule.java b/src/main/java/org/cryptomator/ui/keyloading/hub/HubKeyLoadingModule.java index 6f63ee98e..7b8aae875 100644 --- a/src/main/java/org/cryptomator/ui/keyloading/hub/HubKeyLoadingModule.java +++ b/src/main/java/org/cryptomator/ui/keyloading/hub/HubKeyLoadingModule.java @@ -15,8 +15,6 @@ import org.cryptomator.ui.common.FxControllerKey; import org.cryptomator.ui.common.FxmlFile; import org.cryptomator.ui.common.FxmlLoaderFactory; import org.cryptomator.ui.common.FxmlScene; -import org.cryptomator.ui.common.NewPasswordController; -import org.cryptomator.ui.common.PasswordStrengthUtil; import org.cryptomator.ui.keyloading.KeyLoading; import org.cryptomator.ui.keyloading.KeyLoadingScoped; import org.cryptomator.ui.keyloading.KeyLoadingStrategy; @@ -153,13 +151,6 @@ public abstract class HubKeyLoadingModule { @FxControllerKey(AuthFlowController.class) abstract FxController bindAuthFlowController(AuthFlowController controller); - @Provides - @IntoMap - @FxControllerKey(NewPasswordController.class) - static FxController provideNewPasswordController(ResourceBundle resourceBundle, PasswordStrengthUtil strengthRater) { - return new NewPasswordController(resourceBundle, strengthRater); - } - @Binds @IntoMap @FxControllerKey(InvalidLicenseController.class) diff --git a/src/main/java/org/cryptomator/ui/keyloading/hub/HubKeyLoadingStrategy.java b/src/main/java/org/cryptomator/ui/keyloading/hub/HubKeyLoadingStrategy.java index d1a3742ae..cc5edfcb4 100644 --- a/src/main/java/org/cryptomator/ui/keyloading/hub/HubKeyLoadingStrategy.java +++ b/src/main/java/org/cryptomator/ui/keyloading/hub/HubKeyLoadingStrategy.java @@ -29,8 +29,8 @@ import java.util.concurrent.ExecutionException; public class HubKeyLoadingStrategy implements KeyLoadingStrategy { private static final String SCHEME_PREFIX = "hub+"; - static final String SCHEME_HUB_HTTP = SCHEME_PREFIX + "http"; - static final String SCHEME_HUB_HTTPS = SCHEME_PREFIX + "https"; + public static final String SCHEME_HUB_HTTP = SCHEME_PREFIX + "http"; + public static final String SCHEME_HUB_HTTPS = SCHEME_PREFIX + "https"; private final Stage window; private final KeychainManager keychainManager; diff --git a/src/main/java/org/cryptomator/ui/keyloading/masterkeyfile/MasterkeyFileLoadingModule.java b/src/main/java/org/cryptomator/ui/keyloading/masterkeyfile/MasterkeyFileLoadingModule.java index 9375b0cff..5e4d148cb 100644 --- a/src/main/java/org/cryptomator/ui/keyloading/masterkeyfile/MasterkeyFileLoadingModule.java +++ b/src/main/java/org/cryptomator/ui/keyloading/masterkeyfile/MasterkeyFileLoadingModule.java @@ -8,7 +8,7 @@ import dagger.multibindings.StringKey; import org.cryptomator.common.keychain.KeychainManager; import org.cryptomator.common.vaults.Vault; import org.cryptomator.integrations.keychain.KeychainAccessException; -import org.cryptomator.ui.forgetPassword.ForgetPasswordComponent; +import org.cryptomator.ui.forgetpassword.ForgetPasswordComponent; import org.cryptomator.ui.keyloading.KeyLoading; import org.cryptomator.ui.keyloading.KeyLoadingScoped; import org.cryptomator.ui.keyloading.KeyLoadingStrategy; diff --git a/src/main/java/org/cryptomator/ui/keyloading/masterkeyfile/PassphraseEntryController.java b/src/main/java/org/cryptomator/ui/keyloading/masterkeyfile/PassphraseEntryController.java index baadb9a12..6d52362b3 100644 --- a/src/main/java/org/cryptomator/ui/keyloading/masterkeyfile/PassphraseEntryController.java +++ b/src/main/java/org/cryptomator/ui/keyloading/masterkeyfile/PassphraseEntryController.java @@ -7,7 +7,7 @@ import org.cryptomator.common.vaults.Vault; import org.cryptomator.ui.common.FxController; import org.cryptomator.ui.common.WeakBindings; import org.cryptomator.ui.controls.NiceSecurePasswordField; -import org.cryptomator.ui.forgetPassword.ForgetPasswordComponent; +import org.cryptomator.ui.forgetpassword.ForgetPasswordComponent; import org.cryptomator.ui.keyloading.KeyLoading; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/src/main/java/org/cryptomator/ui/mainwindow/MainWindowModule.java b/src/main/java/org/cryptomator/ui/mainwindow/MainWindowModule.java index 94acba3cc..6fbb8e16e 100644 --- a/src/main/java/org/cryptomator/ui/mainwindow/MainWindowModule.java +++ b/src/main/java/org/cryptomator/ui/mainwindow/MainWindowModule.java @@ -6,7 +6,7 @@ import dagger.Provides; import dagger.multibindings.IntoMap; import org.cryptomator.common.vaults.Vault; import org.cryptomator.ui.addvaultwizard.AddVaultWizardComponent; -import org.cryptomator.ui.common.ErrorComponent; +import org.cryptomator.ui.error.ErrorComponent; import org.cryptomator.ui.common.FxController; import org.cryptomator.ui.common.FxControllerKey; import org.cryptomator.ui.common.FxmlFile; diff --git a/src/main/java/org/cryptomator/ui/recoverykey/RecoveryKeyComponent.java b/src/main/java/org/cryptomator/ui/recoverykey/RecoveryKeyComponent.java index cfec43e3e..3986fa01d 100644 --- a/src/main/java/org/cryptomator/ui/recoverykey/RecoveryKeyComponent.java +++ b/src/main/java/org/cryptomator/ui/recoverykey/RecoveryKeyComponent.java @@ -38,16 +38,11 @@ public interface RecoveryKeyComponent { stage.show(); } - @Subcomponent.Builder - interface Builder { - @BindsInstance - Builder vault(@RecoveryKeyWindow Vault vault); + @Subcomponent.Factory + interface Factory { - @BindsInstance - Builder owner(@Named("keyRecoveryOwner") Stage owner); - - RecoveryKeyComponent build(); + RecoveryKeyComponent create(@BindsInstance @RecoveryKeyWindow Vault vault, @BindsInstance @Named("keyRecoveryOwner") Stage owner); } } diff --git a/src/main/java/org/cryptomator/ui/recoverykey/RecoveryKeyFactory.java b/src/main/java/org/cryptomator/ui/recoverykey/RecoveryKeyFactory.java index a1180dd9f..73279396d 100644 --- a/src/main/java/org/cryptomator/ui/recoverykey/RecoveryKeyFactory.java +++ b/src/main/java/org/cryptomator/ui/recoverykey/RecoveryKeyFactory.java @@ -81,7 +81,7 @@ public class RecoveryKeyFactory { * @throws IllegalArgumentException If the recoveryKey is invalid * @apiNote This is a long-running operation and should be invoked in a background thread */ - public void resetPasswordWithRecoveryKey(Path vaultPath, String recoveryKey, CharSequence newPassword) throws IOException, IllegalArgumentException { + public void newMasterkeyFileWithPassphrase(Path vaultPath, String recoveryKey, CharSequence newPassword) throws IOException, IllegalArgumentException { final byte[] rawKey = decodeRecoveryKey(recoveryKey); try (var masterkey = new Masterkey(rawKey)) { Path masterkeyPath = vaultPath.resolve(MASTERKEY_FILENAME); diff --git a/src/main/java/org/cryptomator/ui/recoverykey/RecoveryKeyModule.java b/src/main/java/org/cryptomator/ui/recoverykey/RecoveryKeyModule.java index a5a0b7ec8..06095eebc 100644 --- a/src/main/java/org/cryptomator/ui/recoverykey/RecoveryKeyModule.java +++ b/src/main/java/org/cryptomator/ui/recoverykey/RecoveryKeyModule.java @@ -13,8 +13,8 @@ import org.cryptomator.ui.common.FxControllerKey; import org.cryptomator.ui.common.FxmlFile; import org.cryptomator.ui.common.FxmlLoaderFactory; import org.cryptomator.ui.common.FxmlScene; -import org.cryptomator.ui.common.NewPasswordController; -import org.cryptomator.ui.common.PasswordStrengthUtil; +import org.cryptomator.ui.changepassword.NewPasswordController; +import org.cryptomator.ui.changepassword.PasswordStrengthUtil; import org.cryptomator.ui.common.StageFactory; import javax.inject.Named; @@ -140,6 +140,13 @@ abstract class RecoveryKeyModule { @FxControllerKey(RecoveryKeyResetPasswordSuccessController.class) abstract FxController bindRecoveryKeyResetPasswordSuccessController(RecoveryKeyResetPasswordSuccessController controller); + @Provides + @IntoMap + @FxControllerKey(RecoveryKeyValidateController.class) + static FxController bindRecoveryKeyValidateController(@RecoveryKeyWindow Vault vault, @RecoveryKeyWindow @Nullable VaultConfig.UnverifiedVaultConfig vaultConfig, @RecoveryKeyWindow StringProperty recoveryKey, RecoveryKeyFactory recoveryKeyFactory) { + return new RecoveryKeyValidateController(vault, vaultConfig, recoveryKey, recoveryKeyFactory); + } + @Provides @IntoMap @FxControllerKey(NewPasswordController.class) diff --git a/src/main/java/org/cryptomator/ui/recoverykey/RecoveryKeyRecoverController.java b/src/main/java/org/cryptomator/ui/recoverykey/RecoveryKeyRecoverController.java index 9082d7311..944c52043 100644 --- a/src/main/java/org/cryptomator/ui/recoverykey/RecoveryKeyRecoverController.java +++ b/src/main/java/org/cryptomator/ui/recoverykey/RecoveryKeyRecoverController.java @@ -1,14 +1,9 @@ package org.cryptomator.ui.recoverykey; -import com.google.common.base.CharMatcher; -import com.google.common.base.Strings; import dagger.Lazy; import org.cryptomator.common.Nullable; -import org.cryptomator.common.ObservableUtil; import org.cryptomator.common.vaults.Vault; import org.cryptomator.cryptofs.VaultConfig; -import org.cryptomator.cryptofs.VaultConfigLoadException; -import org.cryptomator.cryptofs.VaultKeyInvalidException; import org.cryptomator.ui.common.FxController; import org.cryptomator.ui.common.FxmlFile; import org.cryptomator.ui.common.FxmlScene; @@ -16,96 +11,34 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import javax.inject.Inject; -import javafx.beans.property.ObjectProperty; -import javafx.beans.property.SimpleObjectProperty; +import javafx.beans.Observable; import javafx.beans.property.StringProperty; import javafx.beans.value.ObservableValue; import javafx.fxml.FXML; import javafx.scene.Scene; -import javafx.scene.control.TextArea; -import javafx.scene.control.TextFormatter; -import javafx.scene.input.KeyCode; -import javafx.scene.input.KeyEvent; import javafx.stage.Stage; -import java.util.Optional; import java.util.ResourceBundle; @RecoveryKeyScoped public class RecoveryKeyRecoverController implements FxController { private static final Logger LOG = LoggerFactory.getLogger(RecoveryKeyCreationController.class); - private static final CharMatcher ALLOWED_CHARS = CharMatcher.inRange('a', 'z').or(CharMatcher.is(' ')); private final Stage window; - private final Vault vault; - private final VaultConfig.UnverifiedVaultConfig unverifiedVaultConfig; - private final StringProperty recoveryKey; - private final ObservableValue recoveryKeyCorrect; - private final ObservableValue recoveryKeyWrong; - private final ObservableValue recoveryKeyInvalid; - private final RecoveryKeyFactory recoveryKeyFactory; - private final ObjectProperty recoveryKeyState; private final Lazy resetPasswordScene; - private final AutoCompleter autoCompleter; - private volatile boolean isWrongKey; - - public TextArea textarea; + @FXML + RecoveryKeyValidateController recoveryKeyValidateController; @Inject - public RecoveryKeyRecoverController(@RecoveryKeyWindow Stage window, @RecoveryKeyWindow Vault vault, @RecoveryKeyWindow @Nullable VaultConfig.UnverifiedVaultConfig unverifiedVaultConfig, @RecoveryKeyWindow StringProperty recoveryKey, RecoveryKeyFactory recoveryKeyFactory, @FxmlScene(FxmlFile.RECOVERYKEY_RESET_PASSWORD) Lazy resetPasswordScene, ResourceBundle resourceBundle) { + public RecoveryKeyRecoverController(@RecoveryKeyWindow Stage window, @RecoveryKeyWindow Vault vault, @RecoveryKeyWindow StringProperty recoveryKey, @FxmlScene(FxmlFile.RECOVERYKEY_RESET_PASSWORD) Lazy resetPasswordScene, ResourceBundle resourceBundle) { this.window = window; window.setTitle(resourceBundle.getString("recoveryKey.recover.title")); - this.vault = vault; - this.unverifiedVaultConfig = unverifiedVaultConfig; - this.recoveryKey = recoveryKey; - this.recoveryKeyFactory = recoveryKeyFactory; this.resetPasswordScene = resetPasswordScene; - this.autoCompleter = new AutoCompleter(recoveryKeyFactory.getDictionary()); - this.recoveryKeyState = new SimpleObjectProperty<>(); - this.recoveryKeyCorrect = ObservableUtil.mapWithDefault(recoveryKeyState, RecoveryKeyState.CORRECT::equals, false); - this.recoveryKeyWrong = ObservableUtil.mapWithDefault(recoveryKeyState, RecoveryKeyState.WRONG::equals, false); - this.recoveryKeyInvalid = ObservableUtil.mapWithDefault(recoveryKeyState, RecoveryKeyState.INVALID::equals, false); } @FXML public void initialize() { - recoveryKey.bind(textarea.textProperty()); - textarea.textProperty().addListener(((observable, oldValue, newValue) -> validateRecoveryKey())); - } - - private TextFormatter.Change filterTextChange(TextFormatter.Change change) { - if (Strings.isNullOrEmpty(change.getText())) { - // pass-through caret/selection changes that don't affect the text - return change; - } - if (!ALLOWED_CHARS.matchesAllOf(change.getText())) { - return null; // reject change - } - - String text = change.getControlNewText(); - int caretPos = change.getCaretPosition(); - if (caretPos == text.length() || text.charAt(caretPos) == ' ') { // are we at the end of a word? - int beginOfWord = Math.max(text.substring(0, caretPos).lastIndexOf(' ') + 1, 0); - String currentWord = text.substring(beginOfWord, caretPos); - Optional suggestion = autoCompleter.autocomplete(currentWord); - if (suggestion.isPresent()) { - String completion = suggestion.get().substring(currentWord.length()); - change.setText(change.getText() + completion); - change.setAnchor(caretPos + completion.length()); - } - } - return change; - } - - @FXML - public void onKeyPressed(KeyEvent keyEvent) { - if (keyEvent.getCode() == KeyCode.TAB && textarea.getAnchor() > textarea.getCaretPosition()) { - // apply autocompletion: - int pos = textarea.getAnchor(); - textarea.insertText(pos, " "); - textarea.positionCaret(pos + 1); - } } @FXML @@ -118,85 +51,10 @@ public class RecoveryKeyRecoverController implements FxController { window.setScene(resetPasswordScene.get()); } - /** - * Checks, if vault config is signed with the given key. - * - * @param key byte array of possible signing key - * @return true, if vault config is signed with this key - */ - private boolean checkKeyAgainstVaultConfig(byte[] key) { - try { - var config = unverifiedVaultConfig.verify(key, unverifiedVaultConfig.allegedVaultVersion()); - LOG.info("Provided recovery key matches vault config signature for vault {}", config.getId()); - return true; - } catch (VaultKeyInvalidException e) { - LOG.debug("Provided recovery key does not match vault config signature."); - isWrongKey = true; - return false; - } catch (VaultConfigLoadException e) { - LOG.error("Failed to parse vault config", e); - return false; - } - } - - private void validateRecoveryKey() { - isWrongKey = false; - var valid = recoveryKeyFactory.validateRecoveryKey(recoveryKey.get(), unverifiedVaultConfig != null ? this::checkKeyAgainstVaultConfig : null); - if (valid) { - recoveryKeyState.set(RecoveryKeyState.CORRECT); - } else if (isWrongKey) { //set via side effect in checkKeyAgainstVaultConfig() - recoveryKeyState.set(RecoveryKeyState.WRONG); - } else { - recoveryKeyState.set(RecoveryKeyState.INVALID); - } - } - /* Getter/Setter */ - public Vault getVault() { - return vault; + public RecoveryKeyValidateController getValidateController() { + return recoveryKeyValidateController; } - public TextFormatter getRecoveryKeyTextFormatter() { - return new TextFormatter<>(this::filterTextChange); - } - - public ObservableValue recoveryKeyInvalidProperty() { - return recoveryKeyInvalid; - } - - public boolean isRecoveryKeyInvalid() { - return recoveryKeyInvalid.getValue(); - } - - public ObservableValue recoveryKeyCorrectProperty() { - return recoveryKeyCorrect; - } - - public boolean isRecoveryKeyCorrect() { - return recoveryKeyCorrect.getValue(); - } - - public ObservableValue recoveryKeyWrongProperty() { - return recoveryKeyWrong; - } - - public boolean isRecoveryKeyWrong() { - return recoveryKeyWrong.getValue(); - } - - private enum RecoveryKeyState { - /** - * Recovery key is a valid key and belongs to this vault - */ - CORRECT, - /** - * Recovery key is a valid key, but does not belong to this vault - */ - WRONG, - /** - * Recovery key is not a valid key. - */ - INVALID; - } } diff --git a/src/main/java/org/cryptomator/ui/recoverykey/RecoveryKeyResetPasswordController.java b/src/main/java/org/cryptomator/ui/recoverykey/RecoveryKeyResetPasswordController.java index 69e1373e1..18a952ea5 100644 --- a/src/main/java/org/cryptomator/ui/recoverykey/RecoveryKeyResetPasswordController.java +++ b/src/main/java/org/cryptomator/ui/recoverykey/RecoveryKeyResetPasswordController.java @@ -5,7 +5,7 @@ import org.cryptomator.common.vaults.Vault; import org.cryptomator.ui.common.FxController; import org.cryptomator.ui.common.FxmlFile; import org.cryptomator.ui.common.FxmlScene; -import org.cryptomator.ui.common.NewPasswordController; +import org.cryptomator.ui.changepassword.NewPasswordController; import org.cryptomator.ui.fxapp.FxApplicationWindows; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -76,7 +76,7 @@ public class RecoveryKeyResetPasswordController implements FxController { @Override protected Void call() throws IOException, IllegalArgumentException { - recoveryKeyFactory.resetPasswordWithRecoveryKey(vault.getPath(), recoveryKey.get(), newPasswordController.passwordField.getCharacters()); + recoveryKeyFactory.newMasterkeyFileWithPassphrase(vault.getPath(), recoveryKey.get(), newPasswordController.passwordField.getCharacters()); return null; } diff --git a/src/main/java/org/cryptomator/ui/recoverykey/RecoveryKeyValidateController.java b/src/main/java/org/cryptomator/ui/recoverykey/RecoveryKeyValidateController.java new file mode 100644 index 000000000..4a8224ffe --- /dev/null +++ b/src/main/java/org/cryptomator/ui/recoverykey/RecoveryKeyValidateController.java @@ -0,0 +1,180 @@ +package org.cryptomator.ui.recoverykey; + + +import com.google.common.base.CharMatcher; +import com.google.common.base.Strings; +import org.cryptomator.common.Nullable; +import org.cryptomator.common.ObservableUtil; +import org.cryptomator.common.vaults.Vault; +import org.cryptomator.cryptofs.VaultConfig; +import org.cryptomator.cryptofs.VaultConfigLoadException; +import org.cryptomator.cryptofs.VaultKeyInvalidException; +import org.cryptomator.ui.common.FxController; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javafx.beans.property.ObjectProperty; +import javafx.beans.property.SimpleObjectProperty; +import javafx.beans.property.StringProperty; +import javafx.beans.value.ObservableValue; +import javafx.fxml.FXML; +import javafx.scene.control.TextArea; +import javafx.scene.control.TextFormatter; +import javafx.scene.input.KeyCode; +import javafx.scene.input.KeyEvent; + +public class RecoveryKeyValidateController implements FxController { + + private static final Logger LOG = LoggerFactory.getLogger(RecoveryKeyCreationController.class); + private static final CharMatcher ALLOWED_CHARS = CharMatcher.inRange('a', 'z').or(CharMatcher.is(' ')); + + private final Vault vault; + private final VaultConfig.UnverifiedVaultConfig unverifiedVaultConfig; + private final StringProperty recoveryKey; + private final ObservableValue recoveryKeyCorrect; + private final ObservableValue recoveryKeyWrong; + private final ObservableValue recoveryKeyInvalid; + private final RecoveryKeyFactory recoveryKeyFactory; + private final ObjectProperty recoveryKeyState; + private final AutoCompleter autoCompleter; + + private volatile boolean isWrongKey; + + public TextArea textarea; + + public RecoveryKeyValidateController(Vault vault, @Nullable VaultConfig.UnverifiedVaultConfig vaultConfig, StringProperty recoveryKey, RecoveryKeyFactory recoveryKeyFactory) { + this.vault = vault; + this.unverifiedVaultConfig = vaultConfig; + this.recoveryKey = recoveryKey; + this.recoveryKeyFactory = recoveryKeyFactory; + this.autoCompleter = new AutoCompleter(recoveryKeyFactory.getDictionary()); + this.recoveryKeyState = new SimpleObjectProperty<>(); + this.recoveryKeyCorrect = ObservableUtil.mapWithDefault(recoveryKeyState, RecoveryKeyState.CORRECT::equals, false); + this.recoveryKeyWrong = ObservableUtil.mapWithDefault(recoveryKeyState, RecoveryKeyState.WRONG::equals, false); + this.recoveryKeyInvalid = ObservableUtil.mapWithDefault(recoveryKeyState, RecoveryKeyState.INVALID::equals, false); + } + + @FXML + public void initialize() { + recoveryKey.bind(textarea.textProperty()); + textarea.textProperty().addListener(((observable, oldValue, newValue) -> validateRecoveryKey())); + } + + private TextFormatter.Change filterTextChange(TextFormatter.Change change) { + if (Strings.isNullOrEmpty(change.getText())) { + // pass-through caret/selection changes that don't affect the text + return change; + } + if (!ALLOWED_CHARS.matchesAllOf(change.getText())) { + return null; // reject change + } + + String text = change.getControlNewText(); + int caretPos = change.getCaretPosition(); + if (caretPos == text.length() || text.charAt(caretPos) == ' ') { // are we at the end of a word? + int beginOfWord = Math.max(text.substring(0, caretPos).lastIndexOf(' ') + 1, 0); + String currentWord = text.substring(beginOfWord, caretPos); + var suggestion = autoCompleter.autocomplete(currentWord); + if (suggestion.isPresent()) { + String completion = suggestion.get().substring(currentWord.length()); + change.setText(change.getText() + completion); + change.setAnchor(caretPos + completion.length()); + } + } + return change; + } + + @FXML + public void onKeyPressed(KeyEvent keyEvent) { + if (keyEvent.getCode() == KeyCode.TAB && textarea.getAnchor() > textarea.getCaretPosition()) { + // apply autocompletion: + int pos = textarea.getAnchor(); + textarea.insertText(pos, " "); + textarea.positionCaret(pos + 1); + } + } + + /** + * Checks, if vault config is signed with the given key. + * + * @param key byte array of possible signing key + * @return true, if vault config is signed with this key + */ + private boolean checkKeyAgainstVaultConfig(byte[] key) { + assert unverifiedVaultConfig != null; + try { + var config = unverifiedVaultConfig.verify(key, unverifiedVaultConfig.allegedVaultVersion()); + LOG.info("Provided recovery key matches vault config signature for vault {}", config.getId()); + return true; + } catch (VaultKeyInvalidException e) { + LOG.debug("Provided recovery key does not match vault config signature."); + isWrongKey = true; + return false; + } catch (VaultConfigLoadException e) { + LOG.error("Failed to parse vault config", e); + return false; + } + } + + private void validateRecoveryKey() { + isWrongKey = false; + var valid = recoveryKeyFactory.validateRecoveryKey(recoveryKey.get(), unverifiedVaultConfig != null ? this::checkKeyAgainstVaultConfig : null); + if (valid) { + recoveryKeyState.set(RecoveryKeyState.CORRECT); + } else if (isWrongKey) { //set via side effect in checkKeyAgainstVaultConfig() + recoveryKeyState.set(RecoveryKeyState.WRONG); + } else { + recoveryKeyState.set(RecoveryKeyState.INVALID); + } + } + + /* Getter/Setter */ + + public Vault getVault() { + return vault; + } + + public TextFormatter getRecoveryKeyTextFormatter() { + return new TextFormatter<>(this::filterTextChange); + } + + public ObservableValue recoveryKeyInvalidProperty() { + return recoveryKeyInvalid; + } + + public boolean isRecoveryKeyInvalid() { + return recoveryKeyInvalid.getValue(); + } + + public ObservableValue recoveryKeyCorrectProperty() { + return recoveryKeyCorrect; + } + + public boolean isRecoveryKeyCorrect() { + return recoveryKeyCorrect.getValue(); + } + + public ObservableValue recoveryKeyWrongProperty() { + return recoveryKeyWrong; + } + + public boolean isRecoveryKeyWrong() { + return recoveryKeyWrong.getValue(); + } + + private enum RecoveryKeyState { + /** + * Recovery key is a valid key and belongs to this vault + */ + CORRECT, + /** + * Recovery key is a valid key, but does not belong to this vault + */ + WRONG, + /** + * Recovery key is not a valid key. + */ + INVALID; + } + +} diff --git a/src/main/java/org/cryptomator/ui/vaultoptions/HubOptionsController.java b/src/main/java/org/cryptomator/ui/vaultoptions/HubOptionsController.java new file mode 100644 index 000000000..b4eede771 --- /dev/null +++ b/src/main/java/org/cryptomator/ui/vaultoptions/HubOptionsController.java @@ -0,0 +1,27 @@ +package org.cryptomator.ui.vaultoptions; + +import org.cryptomator.common.vaults.Vault; +import org.cryptomator.ui.common.FxController; +import org.cryptomator.ui.convertvault.ConvertVaultComponent; + +import javax.inject.Inject; +import javafx.stage.Stage; + +public class HubOptionsController implements FxController { + + private final Vault vault; + private final Stage window; + private final ConvertVaultComponent.Factory convertVaultFactory; + + + @Inject + public HubOptionsController(@VaultOptionsWindow Vault vault, @VaultOptionsWindow Stage window, ConvertVaultComponent.Factory convertVaultFactory) { + this.vault = vault; + this.window = window; + this.convertVaultFactory = convertVaultFactory; + } + + public void startConversion() { + convertVaultFactory.create(vault,window).showHubToPasswordWindow(); + } +} diff --git a/src/main/java/org/cryptomator/ui/vaultoptions/MasterkeyOptionsController.java b/src/main/java/org/cryptomator/ui/vaultoptions/MasterkeyOptionsController.java index 4978335c7..dd003d93d 100644 --- a/src/main/java/org/cryptomator/ui/vaultoptions/MasterkeyOptionsController.java +++ b/src/main/java/org/cryptomator/ui/vaultoptions/MasterkeyOptionsController.java @@ -4,7 +4,7 @@ import org.cryptomator.common.keychain.KeychainManager; import org.cryptomator.common.vaults.Vault; import org.cryptomator.ui.changepassword.ChangePasswordComponent; import org.cryptomator.ui.common.FxController; -import org.cryptomator.ui.forgetPassword.ForgetPasswordComponent; +import org.cryptomator.ui.forgetpassword.ForgetPasswordComponent; import org.cryptomator.ui.recoverykey.RecoveryKeyComponent; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -23,14 +23,14 @@ public class MasterkeyOptionsController implements FxController { private final Vault vault; private final Stage window; private final ChangePasswordComponent.Builder changePasswordWindow; - private final RecoveryKeyComponent.Builder recoveryKeyWindow; + private final RecoveryKeyComponent.Factory recoveryKeyWindow; private final ForgetPasswordComponent.Builder forgetPasswordWindow; private final KeychainManager keychain; private final ObservableValue passwordSaved; @Inject - MasterkeyOptionsController(@VaultOptionsWindow Vault vault, @VaultOptionsWindow Stage window, ChangePasswordComponent.Builder changePasswordWindow, RecoveryKeyComponent.Builder recoveryKeyWindow, ForgetPasswordComponent.Builder forgetPasswordWindow, KeychainManager keychain) { + MasterkeyOptionsController(@VaultOptionsWindow Vault vault, @VaultOptionsWindow Stage window, ChangePasswordComponent.Builder changePasswordWindow, RecoveryKeyComponent.Factory recoveryKeyWindow, ForgetPasswordComponent.Builder forgetPasswordWindow, KeychainManager keychain) { this.vault = vault; this.window = window; this.changePasswordWindow = changePasswordWindow; @@ -51,12 +51,12 @@ public class MasterkeyOptionsController implements FxController { @FXML public void showRecoveryKey() { - recoveryKeyWindow.vault(vault).owner(window).build().showRecoveryKeyCreationWindow(); + recoveryKeyWindow.create(vault, window).showRecoveryKeyCreationWindow(); } @FXML public void showRecoverVaultDialog() { - recoveryKeyWindow.vault(vault).owner(window).build().showRecoveryKeyRecoverWindow(); + recoveryKeyWindow.create(vault, window).showRecoveryKeyRecoverWindow(); } @FXML diff --git a/src/main/java/org/cryptomator/ui/vaultoptions/SelectedVaultOptionsTab.java b/src/main/java/org/cryptomator/ui/vaultoptions/SelectedVaultOptionsTab.java index 3fc738fb0..f9470af96 100644 --- a/src/main/java/org/cryptomator/ui/vaultoptions/SelectedVaultOptionsTab.java +++ b/src/main/java/org/cryptomator/ui/vaultoptions/SelectedVaultOptionsTab.java @@ -21,4 +21,9 @@ public enum SelectedVaultOptionsTab { */ KEY, + /** + * Show hub tab + */ + HUB + } diff --git a/src/main/java/org/cryptomator/ui/vaultoptions/VaultOptionsController.java b/src/main/java/org/cryptomator/ui/vaultoptions/VaultOptionsController.java index c0023acb8..3abc23e9e 100644 --- a/src/main/java/org/cryptomator/ui/vaultoptions/VaultOptionsController.java +++ b/src/main/java/org/cryptomator/ui/vaultoptions/VaultOptionsController.java @@ -2,6 +2,8 @@ package org.cryptomator.ui.vaultoptions; import org.cryptomator.common.vaults.Vault; import org.cryptomator.ui.common.FxController; +import org.cryptomator.ui.keyloading.hub.HubKeyLoadingStrategy; +import org.cryptomator.ui.keyloading.masterkeyfile.MasterkeyFileLoadingStrategy; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -25,6 +27,7 @@ public class VaultOptionsController implements FxController { public Tab generalTab; public Tab mountTab; public Tab keyTab; + public Tab hubTab; @Inject VaultOptionsController(@VaultOptionsWindow Stage window, @VaultOptionsWindow Vault vault, ObjectProperty selectedTabProperty) { @@ -38,9 +41,13 @@ public class VaultOptionsController implements FxController { window.setOnShowing(this::windowWillAppear); selectedTabProperty.addListener(observable -> this.selectChosenTab()); tabPane.getSelectionModel().selectedItemProperty().addListener(observable -> this.selectedTabChanged()); - if(!vault.getVaultConfigCache().getUnchecked().getKeyId().getScheme().equals("masterkeyfile")){ + var vaultScheme = vault.getVaultConfigCache().getUnchecked().getKeyId().getScheme(); + if(!vaultScheme.equals(MasterkeyFileLoadingStrategy.SCHEME)){ tabPane.getTabs().remove(keyTab); } + if(!(vaultScheme.equals(HubKeyLoadingStrategy.SCHEME_HUB_HTTP) || vaultScheme.equals(HubKeyLoadingStrategy.SCHEME_HUB_HTTPS))){ + tabPane.getTabs().remove(hubTab); + } } private void selectChosenTab() { @@ -53,6 +60,7 @@ public class VaultOptionsController implements FxController { case ANY, GENERAL -> generalTab; case MOUNT -> mountTab; case KEY -> keyTab; + case HUB -> hubTab; }; } diff --git a/src/main/java/org/cryptomator/ui/vaultoptions/VaultOptionsModule.java b/src/main/java/org/cryptomator/ui/vaultoptions/VaultOptionsModule.java index a9014cc54..59dd5ae77 100644 --- a/src/main/java/org/cryptomator/ui/vaultoptions/VaultOptionsModule.java +++ b/src/main/java/org/cryptomator/ui/vaultoptions/VaultOptionsModule.java @@ -13,7 +13,8 @@ import org.cryptomator.ui.common.FxmlFile; import org.cryptomator.ui.common.FxmlLoaderFactory; import org.cryptomator.ui.common.FxmlScene; import org.cryptomator.ui.common.StageFactory; -import org.cryptomator.ui.forgetPassword.ForgetPasswordComponent; +import org.cryptomator.ui.convertvault.ConvertVaultComponent; +import org.cryptomator.ui.forgetpassword.ForgetPasswordComponent; import org.cryptomator.ui.fxapp.PrimaryStage; import org.cryptomator.ui.recoverykey.RecoveryKeyComponent; @@ -26,7 +27,7 @@ import javafx.stage.Stage; import java.util.Map; import java.util.ResourceBundle; -@Module(subcomponents = {ChangePasswordComponent.class, RecoveryKeyComponent.class, ForgetPasswordComponent.class}) +@Module(subcomponents = {ChangePasswordComponent.class, RecoveryKeyComponent.class, ForgetPasswordComponent.class, ConvertVaultComponent.class}) abstract class VaultOptionsModule { @Provides @@ -84,4 +85,9 @@ abstract class VaultOptionsModule { @IntoMap @FxControllerKey(MasterkeyOptionsController.class) abstract FxController bindMasterkeyOptionsController(MasterkeyOptionsController controller); + + @Binds + @IntoMap + @FxControllerKey(HubOptionsController.class) + abstract FxController bindHubOptionsController(HubOptionsController controller); } diff --git a/src/main/resources/fxml/convertvault_hubtopassword_convert.fxml b/src/main/resources/fxml/convertvault_hubtopassword_convert.fxml new file mode 100644 index 000000000..7ea190fd4 --- /dev/null +++ b/src/main/resources/fxml/convertvault_hubtopassword_convert.fxml @@ -0,0 +1,38 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/main/resources/fxml/convertvault_hubtopassword_start.fxml b/src/main/resources/fxml/convertvault_hubtopassword_start.fxml new file mode 100644 index 000000000..d5c0a5e0b --- /dev/null +++ b/src/main/resources/fxml/convertvault_hubtopassword_start.fxml @@ -0,0 +1,33 @@ + + + + + + + + + + + + + + + + + + + +