diff --git a/src/main/java/org/cryptomator/ui/common/FxmlFile.java b/src/main/java/org/cryptomator/ui/common/FxmlFile.java index 9af0578cf..30422db42 100644 --- a/src/main/java/org/cryptomator/ui/common/FxmlFile.java +++ b/src/main/java/org/cryptomator/ui/common/FxmlFile.java @@ -44,6 +44,7 @@ public enum FxmlFile { RECOVERYKEY_RESET_PASSWORD_SUCCESS("/fxml/recoverykey_reset_password_success.fxml"), // RECOVERYKEY_SUCCESS("/fxml/recoverykey_success.fxml"), // REMOVE_VAULT("/fxml/remove_vault.fxml"), // + SHARE_VAULT("/fxml/share_vault.fxml"), // UPDATE_REMINDER("/fxml/update_reminder.fxml"), // UNLOCK_ENTER_PASSWORD("/fxml/unlock_enter_password.fxml"), UNLOCK_REQUIRES_RESTART("/fxml/unlock_requires_restart.fxml"), // diff --git a/src/main/java/org/cryptomator/ui/controls/FontAwesome5Icon.java b/src/main/java/org/cryptomator/ui/controls/FontAwesome5Icon.java index c5ec19929..e454835cf 100644 --- a/src/main/java/org/cryptomator/ui/controls/FontAwesome5Icon.java +++ b/src/main/java/org/cryptomator/ui/controls/FontAwesome5Icon.java @@ -47,6 +47,7 @@ public enum FontAwesome5Icon { QUESTION_CIRCLE("\uf059"), // REDO("\uF01E"), // SEARCH("\uF002"), // + SHARE("\uF064"), // SPINNER("\uF110"), // STETHOSCOPE("\uF0f1"), // SYNC("\uF021"), // diff --git a/src/main/java/org/cryptomator/ui/fxapp/FxApplicationModule.java b/src/main/java/org/cryptomator/ui/fxapp/FxApplicationModule.java index 86ca62c3b..af98e284c 100644 --- a/src/main/java/org/cryptomator/ui/fxapp/FxApplicationModule.java +++ b/src/main/java/org/cryptomator/ui/fxapp/FxApplicationModule.java @@ -13,6 +13,7 @@ import org.cryptomator.ui.lock.LockComponent; import org.cryptomator.ui.mainwindow.MainWindowComponent; import org.cryptomator.ui.preferences.PreferencesComponent; import org.cryptomator.ui.quit.QuitComponent; +import org.cryptomator.ui.sharevault.ShareVaultComponent; import org.cryptomator.ui.traymenu.TrayMenuComponent; import org.cryptomator.ui.unlock.UnlockComponent; import org.cryptomator.ui.updatereminder.UpdateReminderComponent; @@ -22,7 +23,17 @@ import javafx.scene.image.Image; import java.io.IOException; import java.io.InputStream; -@Module(includes = {UpdateCheckerModule.class}, subcomponents = {TrayMenuComponent.class, MainWindowComponent.class, PreferencesComponent.class, VaultOptionsComponent.class, UnlockComponent.class, LockComponent.class, QuitComponent.class, ErrorComponent.class, HealthCheckComponent.class, UpdateReminderComponent.class}) +@Module(includes = {UpdateCheckerModule.class}, subcomponents = {TrayMenuComponent.class, // + MainWindowComponent.class, // + PreferencesComponent.class, // + VaultOptionsComponent.class, // + UnlockComponent.class, // + LockComponent.class, // + QuitComponent.class, // + ErrorComponent.class, // + HealthCheckComponent.class, // + UpdateReminderComponent.class, // + ShareVaultComponent.class}) abstract class FxApplicationModule { private static Image createImageFromResource(String resourceName) throws IOException { diff --git a/src/main/java/org/cryptomator/ui/fxapp/FxApplicationWindows.java b/src/main/java/org/cryptomator/ui/fxapp/FxApplicationWindows.java index 866b1d9df..41a7ca785 100644 --- a/src/main/java/org/cryptomator/ui/fxapp/FxApplicationWindows.java +++ b/src/main/java/org/cryptomator/ui/fxapp/FxApplicationWindows.java @@ -11,6 +11,7 @@ import org.cryptomator.ui.mainwindow.MainWindowComponent; import org.cryptomator.ui.preferences.PreferencesComponent; import org.cryptomator.ui.preferences.SelectedPreferencesTab; import org.cryptomator.ui.quit.QuitComponent; +import org.cryptomator.ui.sharevault.ShareVaultComponent; import org.cryptomator.ui.unlock.UnlockComponent; import org.cryptomator.ui.unlock.UnlockWorkflow; import org.cryptomator.ui.updatereminder.UpdateReminderComponent; @@ -51,6 +52,7 @@ public class FxApplicationWindows { private final ErrorComponent.Factory errorWindowFactory; private final ExecutorService executor; private final VaultOptionsComponent.Factory vaultOptionsWindow; + private final ShareVaultComponent.Factory shareVaultWindow; private final FilteredList visibleWindows; @Inject @@ -64,6 +66,7 @@ public class FxApplicationWindows { LockComponent.Factory lockWorkflowFactory, // ErrorComponent.Factory errorWindowFactory, // VaultOptionsComponent.Factory vaultOptionsWindow, // + ShareVaultComponent.Factory shareVaultWindow, // ExecutorService executor) { this.primaryStage = primaryStage; this.trayIntegration = trayIntegration; @@ -76,6 +79,7 @@ public class FxApplicationWindows { this.errorWindowFactory = errorWindowFactory; this.executor = executor; this.vaultOptionsWindow = vaultOptionsWindow; + this.shareVaultWindow = shareVaultWindow; this.visibleWindows = Window.getWindows().filtered(Window::isShowing); } @@ -122,6 +126,10 @@ public class FxApplicationWindows { return CompletableFuture.supplyAsync(() -> preferencesWindow.get().showPreferencesWindow(selectedTab), Platform::runLater).whenComplete(this::reportErrors); } + public void showShareVaultWindow(Vault vault) { + CompletableFuture.runAsync(() -> shareVaultWindow.create(vault).showShareVaultWindow(), Platform::runLater); + } + public CompletionStage showVaultOptionsWindow(Vault vault, SelectedVaultOptionsTab tab) { return showMainWindow().thenApplyAsync((window) -> vaultOptionsWindow.create(vault).showVaultOptionsWindow(tab), Platform::runLater).whenComplete(this::reportErrors); } diff --git a/src/main/java/org/cryptomator/ui/mainwindow/VaultDetailLockedController.java b/src/main/java/org/cryptomator/ui/mainwindow/VaultDetailLockedController.java index f90ad61c2..8212f598f 100644 --- a/src/main/java/org/cryptomator/ui/mainwindow/VaultDetailLockedController.java +++ b/src/main/java/org/cryptomator/ui/mainwindow/VaultDetailLockedController.java @@ -44,6 +44,11 @@ public class VaultDetailLockedController implements FxController { appWindows.startUnlockWorkflow(vault.get(), mainWindow); } + @FXML + public void share() { + appWindows.showShareVaultWindow(vault.get()); + } + @FXML public void showVaultOptions() { vaultOptionsWindow.create(vault.get()).showVaultOptionsWindow(SelectedVaultOptionsTab.ANY); diff --git a/src/main/java/org/cryptomator/ui/sharevault/ShareVaultComponent.java b/src/main/java/org/cryptomator/ui/sharevault/ShareVaultComponent.java new file mode 100644 index 000000000..b7b41ec7e --- /dev/null +++ b/src/main/java/org/cryptomator/ui/sharevault/ShareVaultComponent.java @@ -0,0 +1,34 @@ +package org.cryptomator.ui.sharevault; + +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 javafx.scene.Scene; +import javafx.stage.Stage; + +@ShareVaultScoped +@Subcomponent(modules = {ShareVaultModule.class}) +public interface ShareVaultComponent { + + @ShareVaultWindow + Stage window(); + + @FxmlScene(FxmlFile.SHARE_VAULT) + Lazy scene(); + + default void showShareVaultWindow(){ + Stage stage = window(); + stage.setScene(scene().get()); + stage.show(); + } + + @Subcomponent.Factory + interface Factory { + ShareVaultComponent create(@BindsInstance @ShareVaultWindow Vault vault); + } + +} diff --git a/src/main/java/org/cryptomator/ui/sharevault/ShareVaultController.java b/src/main/java/org/cryptomator/ui/sharevault/ShareVaultController.java new file mode 100644 index 000000000..c8a5abc5f --- /dev/null +++ b/src/main/java/org/cryptomator/ui/sharevault/ShareVaultController.java @@ -0,0 +1,50 @@ +package org.cryptomator.ui.sharevault; + +import dagger.Lazy; +import org.cryptomator.common.vaults.Vault; +import org.cryptomator.ui.common.FxController; +import org.cryptomator.ui.keyloading.hub.HubKeyLoadingStrategy; + +import javax.inject.Inject; +import javafx.application.Application; +import javafx.fxml.FXML; +import javafx.stage.Stage; + +@ShareVaultScoped +public class ShareVaultController implements FxController { + private static final String VISIT_HUB_URL = "https://cryptomator.org/hub/"; + private static final String OPEN_HUB_URL = "https://cryptomator.org/hub/"; + + private final Stage window; + private final Lazy application; + private final Boolean hubVault; + + @Inject + ShareVaultController(@ShareVaultWindow Stage window, // + Lazy application, // + @ShareVaultWindow Vault vault){ + this.window = window; + this.application = application; + var vaultScheme = vault.getVaultConfigCache().getUnchecked().getKeyId().getScheme(); + this.hubVault = (vaultScheme.equals(HubKeyLoadingStrategy.SCHEME_HUB_HTTP) || vaultScheme.equals(HubKeyLoadingStrategy.SCHEME_HUB_HTTPS)); + } + + @FXML + public void close(){ + window.close(); + } + + @FXML + public void visitHub() { + application.get().getHostServices().showDocument(VISIT_HUB_URL); + } + @FXML + public void openHub() { + application.get().getHostServices().showDocument(OPEN_HUB_URL); + } + + public boolean isHubVault() { + return hubVault; + } + +} diff --git a/src/main/java/org/cryptomator/ui/sharevault/ShareVaultModule.java b/src/main/java/org/cryptomator/ui/sharevault/ShareVaultModule.java new file mode 100644 index 000000000..75742c7ce --- /dev/null +++ b/src/main/java/org/cryptomator/ui/sharevault/ShareVaultModule.java @@ -0,0 +1,54 @@ +package org.cryptomator.ui.sharevault; + +import dagger.Binds; +import dagger.Module; +import dagger.Provides; +import dagger.multibindings.IntoMap; +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 javax.inject.Provider; +import javafx.scene.Scene; +import javafx.stage.Modality; +import javafx.stage.Stage; +import java.util.Map; +import java.util.ResourceBundle; + +@Module +abstract class ShareVaultModule { + + @Provides + @ShareVaultWindow + @ShareVaultScoped + static FxmlLoaderFactory provideFxmlLoaderFactory(Map, Provider> factories, DefaultSceneFactory sceneFactory, ResourceBundle resourceBundle) { + return new FxmlLoaderFactory(factories, sceneFactory, resourceBundle); + } + + @Provides + @ShareVaultWindow + @ShareVaultScoped + static Stage provideStage(StageFactory factory, ResourceBundle resourceBundle) { + Stage stage = factory.create(); + stage.setResizable(false); + stage.initModality(Modality.APPLICATION_MODAL); + stage.setTitle(resourceBundle.getString("shareVault.title")); + return stage; + } + + @Provides + @FxmlScene(FxmlFile.SHARE_VAULT) + @ShareVaultScoped + static Scene provideShareVaultScene(@ShareVaultWindow FxmlLoaderFactory fxmlLoaders) { + return fxmlLoaders.createScene(FxmlFile.SHARE_VAULT); + } + + @Binds + @IntoMap + @FxControllerKey(ShareVaultController.class) + abstract FxController bindShareVaultController(ShareVaultController controller); +} diff --git a/src/main/java/org/cryptomator/ui/sharevault/ShareVaultScoped.java b/src/main/java/org/cryptomator/ui/sharevault/ShareVaultScoped.java new file mode 100644 index 000000000..2a9b97fb1 --- /dev/null +++ b/src/main/java/org/cryptomator/ui/sharevault/ShareVaultScoped.java @@ -0,0 +1,13 @@ +package org.cryptomator.ui.sharevault; + +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 ShareVaultScoped { + +} diff --git a/src/main/java/org/cryptomator/ui/sharevault/ShareVaultWindow.java b/src/main/java/org/cryptomator/ui/sharevault/ShareVaultWindow.java new file mode 100644 index 000000000..ace70180a --- /dev/null +++ b/src/main/java/org/cryptomator/ui/sharevault/ShareVaultWindow.java @@ -0,0 +1,14 @@ +package org.cryptomator.ui.sharevault; + +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 ShareVaultWindow { + +} diff --git a/src/main/resources/fxml/share_vault.fxml b/src/main/resources/fxml/share_vault.fxml new file mode 100644 index 000000000..df9d7dcc8 --- /dev/null +++ b/src/main/resources/fxml/share_vault.fxml @@ -0,0 +1,64 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/main/resources/i18n/strings.properties b/src/main/resources/i18n/strings.properties index 91e56ee13..1abda4a1a 100644 --- a/src/main/resources/i18n/strings.properties +++ b/src/main/resources/i18n/strings.properties @@ -387,6 +387,7 @@ main.vaultDetail.unlockBtn=Unlock… main.vaultDetail.unlockNowBtn=Unlock Now main.vaultDetail.optionsBtn=Vault Options main.vaultDetail.passwordSavedInKeychain=Password saved +main.vaultDetail.share=Share... ### Unlocked main.vaultDetail.unlockedStatus=UNLOCKED main.vaultDetail.accessLocation=Your vault's contents are accessible here: @@ -524,4 +525,24 @@ updateReminder.message=Check for Updates? updateReminder.description=Stay updated with new features, bug fixes, and security improvements. We recommend to automatically check for updates. updateReminder.notNow=Not Now updateReminder.yesOnce=Yes, Once -updateReminder.yesAutomatically=Yes, Automatically \ No newline at end of file +updateReminder.yesAutomatically=Yes, Automatically + +# Share Vault +shareVault.title=Share Vault +shareVault.message=Would you like to share your vault with others? +shareVault.description=Always be careful when sharing your vault with other people. In short, follow these steps: +shareVault.instruction.0=To encrypt files, follow these steps: +shareVault.instruction.1=1. Share access of the encrypted vault folder via cloud storage.\n2. Share vault password in a secure way. +shareVault.more=For more information, check out our best practices. +shareVault.info.1=The secure way to work in teams +shareVault.info.2=Use Cryptomator Hub! +shareVault.info.3=• Zero-knowledge key management +shareVault.info.4=• Strong authentication +shareVault.info.5=• ... +shareVault.visitHub=Visit Cryptomator Hub + +shareVault.hub.message=How to share a Hub vault +shareVault.hub.instruction.0=In order to share the vault content with another team member, you have to perform two steps: +shareVault.hub.instruction.1=1. Share access of the encrypted vault folder via cloud storage. +shareVault.hub.instruction.2=2. Grant access to team member in Cryptomator Hub. +shareVault.hub.openHub=Open Cryptomator Hub \ No newline at end of file diff --git a/src/main/resources/img/share-hub-logo.png b/src/main/resources/img/share-hub-logo.png new file mode 100644 index 000000000..ee7d15b8d Binary files /dev/null and b/src/main/resources/img/share-hub-logo.png differ diff --git a/src/main/resources/img/share-hub-logo@2x.png b/src/main/resources/img/share-hub-logo@2x.png new file mode 100644 index 000000000..a62b3e973 Binary files /dev/null and b/src/main/resources/img/share-hub-logo@2x.png differ