From 97a0f9c435f43f16ed9a2baad6ec7b7b9ab2d1a4 Mon Sep 17 00:00:00 2001 From: Ralph Plawetzki Date: Mon, 2 Dec 2024 07:56:23 +0100 Subject: [PATCH] Migrate keychain entries on Mac on provider change --- .../GeneralPreferencesController.java | 39 ++++++++++++++++++- 1 file changed, 38 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/cryptomator/ui/preferences/GeneralPreferencesController.java b/src/main/java/org/cryptomator/ui/preferences/GeneralPreferencesController.java index 800a292a9..f7867ea11 100644 --- a/src/main/java/org/cryptomator/ui/preferences/GeneralPreferencesController.java +++ b/src/main/java/org/cryptomator/ui/preferences/GeneralPreferencesController.java @@ -1,10 +1,14 @@ package org.cryptomator.ui.preferences; +import org.apache.commons.lang3.SystemUtils; import org.cryptomator.common.Environment; +import org.cryptomator.common.Passphrase; +import org.cryptomator.common.keychain.KeychainManager; import org.cryptomator.common.settings.Settings; import org.cryptomator.integrations.autostart.AutoStartProvider; import org.cryptomator.integrations.autostart.ToggleAutoStartFailedException; import org.cryptomator.integrations.common.NamedServiceProvider; +import org.cryptomator.integrations.keychain.KeychainAccessException; import org.cryptomator.integrations.keychain.KeychainAccessProvider; import org.cryptomator.integrations.quickaccess.QuickAccessService; import org.cryptomator.ui.common.FxController; @@ -14,6 +18,7 @@ import org.slf4j.LoggerFactory; import javax.inject.Inject; import javafx.application.Application; +import javafx.beans.Observable; import javafx.beans.binding.Bindings; import javafx.fxml.FXML; import javafx.scene.control.CheckBox; @@ -36,6 +41,7 @@ public class GeneralPreferencesController implements FxController { private final Application application; private final Environment environment; private final List keychainAccessProviders; + private final KeychainManager keychain; private final FxApplicationWindows appWindows; public CheckBox useKeychainCheckbox; public ChoiceBox keychainBackendChoiceBox; @@ -48,11 +54,12 @@ public class GeneralPreferencesController implements FxController { public ToggleGroup nodeOrientation; @Inject - GeneralPreferencesController(@PreferencesWindow Stage window, Settings settings, Optional autoStartProvider, List keychainAccessProviders, Application application, Environment environment, FxApplicationWindows appWindows) { + GeneralPreferencesController(@PreferencesWindow Stage window, Settings settings, Optional autoStartProvider, List keychainAccessProviders, KeychainManager keychain, Application application, Environment environment, FxApplicationWindows appWindows) { this.window = window; this.settings = settings; this.autoStartProvider = autoStartProvider; this.keychainAccessProviders = keychainAccessProviders; + this.keychain = keychain; this.quickAccessServices = QuickAccessService.get().toList(); this.application = application; this.environment = environment; @@ -73,6 +80,7 @@ public class GeneralPreferencesController implements FxController { Bindings.bindBidirectional(settings.keychainProvider, keychainBackendChoiceBox.valueProperty(), keychainSettingsConverter); useKeychainCheckbox.selectedProperty().bindBidirectional(settings.useKeychain); keychainBackendChoiceBox.disableProperty().bind(useKeychainCheckbox.selectedProperty().not()); + keychainBackendChoiceBox.valueProperty().addListener(this::migrateKeychainEntriesOnMac); useQuickAccessCheckbox.selectedProperty().bindBidirectional(settings.useQuickAccess); var quickAccessSettingsConverter = new ServiceToSettingsConverter<>(quickAccessServices); @@ -83,6 +91,35 @@ public class GeneralPreferencesController implements FxController { quickAccessServiceChoiceBox.disableProperty().bind(useQuickAccessCheckbox.selectedProperty().not()); } + public void migrateKeychainEntriesOnMac(Observable observable) { + if (!SystemUtils.IS_OS_MAC) { + return; + } + + var provider = keychainBackendChoiceBox.getSelectionModel().getSelectedItem(); + var providerId = "org.cryptomator.macos.keychain.MacSystemKeychainAccess"; + var isSystemKeychain = provider.getClass().getName().equals(providerId); + + List vaults = settings.directories.stream() + .map(vault -> vault.id) + .toList(); + + if (!vaults.isEmpty()) { + LOG.info("Migrating keychain entries for vaults: {}", vaults); + } + for (String vaultId :vaults) { + try { + if (keychain.isPassphraseStored(vaultId)) { + var passphrase = keychain.loadPassphrase(vaultId); + keychain.deletePassphrase(vaultId); + keychain.storePassphrase(vaultId, vaultId, new Passphrase(passphrase), !isSystemKeychain); + } + } catch (KeychainAccessException e) { + LOG.error("Failed to migrate keychain entries.", e); + } + } + } + public boolean isAutoStartSupported() { return autoStartProvider.isPresent(); }