From 6c440dfbbb17a3a2e81c2e57ddf69c844baf1dbf Mon Sep 17 00:00:00 2001 From: JaniruTEC Date: Wed, 18 Nov 2020 15:53:33 +0100 Subject: [PATCH 01/51] Re-Added check for non-emtpy dirs --- .../common/mountpoint/IrregularUnmountCleaner.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/main/commons/src/main/java/org/cryptomator/common/mountpoint/IrregularUnmountCleaner.java b/main/commons/src/main/java/org/cryptomator/common/mountpoint/IrregularUnmountCleaner.java index 6bcb36f9a..556c3012a 100644 --- a/main/commons/src/main/java/org/cryptomator/common/mountpoint/IrregularUnmountCleaner.java +++ b/main/commons/src/main/java/org/cryptomator/common/mountpoint/IrregularUnmountCleaner.java @@ -73,6 +73,7 @@ class IrregularUnmountCleaner { private void deleteEmptyDir(Path dir) throws IOException { assert Files.isDirectory(dir, LinkOption.NOFOLLOW_LINKS); try { + ensureIsEmpty(dir); Files.delete(dir); // attempt to delete dir non-recursively (will fail, if there are contents) } catch (DirectoryNotEmptyException e) { LOG.info("Found non-empty directory in mountpoint dir: {}", dir); @@ -86,4 +87,9 @@ class IrregularUnmountCleaner { } } + private void ensureIsEmpty(Path dir) throws IOException { + if(Files.newDirectoryStream(dir).iterator().hasNext()) { + throw new DirectoryNotEmptyException(dir.toString()); + } + } } From 52cd560cb205697ad21be74e60349c4f77569b2e Mon Sep 17 00:00:00 2001 From: JaniruTEC Date: Wed, 18 Nov 2020 16:09:09 +0100 Subject: [PATCH 02/51] Generifyed #chooseMountPoint() --- .../mountpoint/MacVolumeMountChooser.java | 24 +++++++++++-------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/main/commons/src/main/java/org/cryptomator/common/mountpoint/MacVolumeMountChooser.java b/main/commons/src/main/java/org/cryptomator/common/mountpoint/MacVolumeMountChooser.java index d6ebb4da5..3a017273f 100644 --- a/main/commons/src/main/java/org/cryptomator/common/mountpoint/MacVolumeMountChooser.java +++ b/main/commons/src/main/java/org/cryptomator/common/mountpoint/MacVolumeMountChooser.java @@ -31,26 +31,30 @@ class MacVolumeMountChooser implements MountPointChooser { @Override public Optional chooseMountPoint(Volume caller) { + return Optional.of(VOLUME_PATH).map(this::choose); + } + + private Path choose(Path parent) { String basename = this.vaultSettings.mountName().get(); - // regular - Path mountPoint = VOLUME_PATH.resolve(basename); + //regular + Path mountPoint = parent.resolve(basename); if (Files.notExists(mountPoint)) { - return Optional.of(mountPoint); + return mountPoint; } - // with id - mountPoint = VOLUME_PATH.resolve(basename + " (" + vaultSettings.getId() + ")"); + //with id + mountPoint = parent.resolve(basename + " (" + vaultSettings.getId() + ")"); if (Files.notExists(mountPoint)) { - return Optional.of(mountPoint); + return mountPoint; } - // with id and count + //with id and count for (int i = 1; i < MAX_MOUNTPOINT_CREATION_RETRIES; i++) { - mountPoint = VOLUME_PATH.resolve(basename + "_(" + vaultSettings.getId() + ")_" + i); + mountPoint = parent.resolve(basename + "_(" + vaultSettings.getId() + ")_" + i); if (Files.notExists(mountPoint)) { - return Optional.of(mountPoint); + return mountPoint; } } LOG.error("Failed to find feasible mountpoint at /Volumes/{}_x. Giving up after {} attempts.", basename, MAX_MOUNTPOINT_CREATION_RETRIES); - return Optional.empty(); + return null; } @Override From 21387bd76c9e20017ddadd3ef772e048b32ba2a8 Mon Sep 17 00:00:00 2001 From: JaniruTEC Date: Wed, 18 Nov 2020 16:18:31 +0100 Subject: [PATCH 03/51] Renamed IrregularUnmountCleaner to MountPointHelper --- ...rregularUnmountCleaner.java => MountPointHelper.java} | 6 +++--- .../common/mountpoint/TemporaryMountPointChooser.java | 9 ++++----- 2 files changed, 7 insertions(+), 8 deletions(-) rename main/commons/src/main/java/org/cryptomator/common/mountpoint/{IrregularUnmountCleaner.java => MountPointHelper.java} (94%) diff --git a/main/commons/src/main/java/org/cryptomator/common/mountpoint/IrregularUnmountCleaner.java b/main/commons/src/main/java/org/cryptomator/common/mountpoint/MountPointHelper.java similarity index 94% rename from main/commons/src/main/java/org/cryptomator/common/mountpoint/IrregularUnmountCleaner.java rename to main/commons/src/main/java/org/cryptomator/common/mountpoint/MountPointHelper.java index 556c3012a..8bfef7f32 100644 --- a/main/commons/src/main/java/org/cryptomator/common/mountpoint/IrregularUnmountCleaner.java +++ b/main/commons/src/main/java/org/cryptomator/common/mountpoint/MountPointHelper.java @@ -15,15 +15,15 @@ import java.nio.file.attribute.BasicFileAttributes; import java.util.Optional; @Singleton -class IrregularUnmountCleaner { +class MountPointHelper { - public static Logger LOG = LoggerFactory.getLogger(IrregularUnmountCleaner.class); + public static Logger LOG = LoggerFactory.getLogger(MountPointHelper.class); private final Optional tmpMountPointDir; private volatile boolean alreadyChecked = false; @Inject - public IrregularUnmountCleaner(Environment env) { + public MountPointHelper(Environment env) { this.tmpMountPointDir = env.getMountPointsDir(); } diff --git a/main/commons/src/main/java/org/cryptomator/common/mountpoint/TemporaryMountPointChooser.java b/main/commons/src/main/java/org/cryptomator/common/mountpoint/TemporaryMountPointChooser.java index 071ed7d1a..43ce79134 100644 --- a/main/commons/src/main/java/org/cryptomator/common/mountpoint/TemporaryMountPointChooser.java +++ b/main/commons/src/main/java/org/cryptomator/common/mountpoint/TemporaryMountPointChooser.java @@ -20,14 +20,13 @@ class TemporaryMountPointChooser implements MountPointChooser { private final VaultSettings vaultSettings; private final Environment environment; - private final IrregularUnmountCleaner cleaner; - private volatile boolean clearedDebris; + private final MountPointHelper helper; @Inject - public TemporaryMountPointChooser(VaultSettings vaultSettings, Environment environment, IrregularUnmountCleaner cleaner) { + public TemporaryMountPointChooser(VaultSettings vaultSettings, Environment environment, MountPointHelper helper) { this.vaultSettings = vaultSettings; this.environment = environment; - this.cleaner = cleaner; + this.helper = helper; } @Override @@ -44,7 +43,7 @@ class TemporaryMountPointChooser implements MountPointChooser { assert environment.getMountPointsDir().isPresent(); //clean leftovers of not-regularly unmounted vaults //see https://github.com/cryptomator/cryptomator/issues/1013 and https://github.com/cryptomator/cryptomator/issues/1061 - cleaner.clearIrregularUnmountDebrisIfNeeded(); + helper.clearIrregularUnmountDebrisIfNeeded(); return this.environment.getMountPointsDir().map(this::choose); } From 422ce4a3873c8b7acb35d5832ec796e1e9bdd3b8 Mon Sep 17 00:00:00 2001 From: JaniruTEC Date: Wed, 18 Nov 2020 16:27:43 +0100 Subject: [PATCH 04/51] Moved actual choosing of MPCs to MountPointHelper --- .../mountpoint/MacVolumeMountChooser.java | 34 +++---------------- .../common/mountpoint/MountPointHelper.java | 28 ++++++++++++++- .../TemporaryMountPointChooser.java | 28 +-------------- 3 files changed, 32 insertions(+), 58 deletions(-) diff --git a/main/commons/src/main/java/org/cryptomator/common/mountpoint/MacVolumeMountChooser.java b/main/commons/src/main/java/org/cryptomator/common/mountpoint/MacVolumeMountChooser.java index 3a017273f..64c0ed979 100644 --- a/main/commons/src/main/java/org/cryptomator/common/mountpoint/MacVolumeMountChooser.java +++ b/main/commons/src/main/java/org/cryptomator/common/mountpoint/MacVolumeMountChooser.java @@ -3,25 +3,22 @@ package org.cryptomator.common.mountpoint; import org.apache.commons.lang3.SystemUtils; import org.cryptomator.common.settings.VaultSettings; import org.cryptomator.common.vaults.Volume; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import javax.inject.Inject; -import java.nio.file.Files; import java.nio.file.Path; import java.util.Optional; class MacVolumeMountChooser implements MountPointChooser { - private static final Logger LOG = LoggerFactory.getLogger(MacVolumeMountChooser.class); - private static final int MAX_MOUNTPOINT_CREATION_RETRIES = 10; private static final Path VOLUME_PATH = Path.of("/Volumes"); private final VaultSettings vaultSettings; + private final MountPointHelper helper; @Inject - public MacVolumeMountChooser(VaultSettings vaultSettings) { + public MacVolumeMountChooser(VaultSettings vaultSettings, MountPointHelper helper) { this.vaultSettings = vaultSettings; + this.helper = helper; } @Override @@ -31,30 +28,7 @@ class MacVolumeMountChooser implements MountPointChooser { @Override public Optional chooseMountPoint(Volume caller) { - return Optional.of(VOLUME_PATH).map(this::choose); - } - - private Path choose(Path parent) { - String basename = this.vaultSettings.mountName().get(); - //regular - Path mountPoint = parent.resolve(basename); - if (Files.notExists(mountPoint)) { - return mountPoint; - } - //with id - mountPoint = parent.resolve(basename + " (" + vaultSettings.getId() + ")"); - if (Files.notExists(mountPoint)) { - return mountPoint; - } - //with id and count - for (int i = 1; i < MAX_MOUNTPOINT_CREATION_RETRIES; i++) { - mountPoint = parent.resolve(basename + "_(" + vaultSettings.getId() + ")_" + i); - if (Files.notExists(mountPoint)) { - return mountPoint; - } - } - LOG.error("Failed to find feasible mountpoint at /Volumes/{}_x. Giving up after {} attempts.", basename, MAX_MOUNTPOINT_CREATION_RETRIES); - return null; + return Optional.of(VOLUME_PATH).map(dir -> this.helper.chooseTemporaryMountPoint(this.vaultSettings, dir)); } @Override diff --git a/main/commons/src/main/java/org/cryptomator/common/mountpoint/MountPointHelper.java b/main/commons/src/main/java/org/cryptomator/common/mountpoint/MountPointHelper.java index 8bfef7f32..c72aeb44c 100644 --- a/main/commons/src/main/java/org/cryptomator/common/mountpoint/MountPointHelper.java +++ b/main/commons/src/main/java/org/cryptomator/common/mountpoint/MountPointHelper.java @@ -1,11 +1,13 @@ package org.cryptomator.common.mountpoint; import org.cryptomator.common.Environment; +import org.cryptomator.common.settings.VaultSettings; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import javax.inject.Inject; import javax.inject.Singleton; +import java.io.File; import java.io.IOException; import java.nio.file.DirectoryNotEmptyException; import java.nio.file.Files; @@ -19,6 +21,8 @@ class MountPointHelper { public static Logger LOG = LoggerFactory.getLogger(MountPointHelper.class); + private static final int MAX_TMPMOUNTPOINT_CREATION_RETRIES = 10; + private final Optional tmpMountPointDir; private volatile boolean alreadyChecked = false; @@ -27,6 +31,28 @@ class MountPointHelper { this.tmpMountPointDir = env.getMountPointsDir(); } + public Path chooseTemporaryMountPoint(VaultSettings vaultSettings, Path parentDir) { + String basename = vaultSettings.mountName().get(); + //regular + Path mountPoint = parentDir.resolve(basename); + if (Files.notExists(mountPoint)) { + return mountPoint; + } + //with id + mountPoint = parentDir.resolve(basename + " (" + vaultSettings.getId() + ")"); + if (Files.notExists(mountPoint)) { + return mountPoint; + } + //with id and count + for (int i = 1; i < MAX_TMPMOUNTPOINT_CREATION_RETRIES; i++) { + mountPoint = parentDir.resolve(basename + "_(" + vaultSettings.getId() + ")_" + i); + if (Files.notExists(mountPoint)) { + return mountPoint; + } + } + LOG.error("Failed to find feasible mountpoint at {}{}{}_x. Giving up after {} attempts.", parentDir, File.separator, basename, MAX_TMPMOUNTPOINT_CREATION_RETRIES); + return null; + } public synchronized void clearIrregularUnmountDebrisIfNeeded() { if (alreadyChecked || tmpMountPointDir.isEmpty()) { @@ -88,7 +114,7 @@ class MountPointHelper { } private void ensureIsEmpty(Path dir) throws IOException { - if(Files.newDirectoryStream(dir).iterator().hasNext()) { + if (Files.newDirectoryStream(dir).iterator().hasNext()) { throw new DirectoryNotEmptyException(dir.toString()); } } diff --git a/main/commons/src/main/java/org/cryptomator/common/mountpoint/TemporaryMountPointChooser.java b/main/commons/src/main/java/org/cryptomator/common/mountpoint/TemporaryMountPointChooser.java index 43ce79134..eb1d8d0b1 100644 --- a/main/commons/src/main/java/org/cryptomator/common/mountpoint/TemporaryMountPointChooser.java +++ b/main/commons/src/main/java/org/cryptomator/common/mountpoint/TemporaryMountPointChooser.java @@ -7,7 +7,6 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import javax.inject.Inject; -import java.io.File; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; @@ -16,7 +15,6 @@ import java.util.Optional; class TemporaryMountPointChooser implements MountPointChooser { private static final Logger LOG = LoggerFactory.getLogger(TemporaryMountPointChooser.class); - private static final int MAX_TMPMOUNTPOINT_CREATION_RETRIES = 10; private final VaultSettings vaultSettings; private final Environment environment; @@ -44,31 +42,7 @@ class TemporaryMountPointChooser implements MountPointChooser { //clean leftovers of not-regularly unmounted vaults //see https://github.com/cryptomator/cryptomator/issues/1013 and https://github.com/cryptomator/cryptomator/issues/1061 helper.clearIrregularUnmountDebrisIfNeeded(); - return this.environment.getMountPointsDir().map(this::choose); - } - - - private Path choose(Path parent) { - String basename = this.vaultSettings.mountName().get(); - //regular - Path mountPoint = parent.resolve(basename); - if (Files.notExists(mountPoint)) { - return mountPoint; - } - //with id - mountPoint = parent.resolve(basename + " (" + vaultSettings.getId() + ")"); - if (Files.notExists(mountPoint)) { - return mountPoint; - } - //with id and count - for (int i = 1; i < MAX_TMPMOUNTPOINT_CREATION_RETRIES; i++) { - mountPoint = parent.resolve(basename + "_(" + vaultSettings.getId() + ")_" + i); - if (Files.notExists(mountPoint)) { - return mountPoint; - } - } - LOG.error("Failed to find feasible mountpoint at {}{}{}_x. Giving up after {} attempts.", parent, File.separator, basename, MAX_TMPMOUNTPOINT_CREATION_RETRIES); - return null; + return this.environment.getMountPointsDir().map(dir -> this.helper.chooseTemporaryMountPoint(this.vaultSettings, dir)); } @Override From bcf2a3d20cc57425db4df996a25e151e9b6eba92 Mon Sep 17 00:00:00 2001 From: Armin Schrenk Date: Wed, 18 Nov 2020 17:16:43 +0100 Subject: [PATCH 05/51] Setting default onFailed handler in lock tasks --- .../ui/src/main/java/org/cryptomator/ui/common/VaultService.java | 1 + 1 file changed, 1 insertion(+) diff --git a/main/ui/src/main/java/org/cryptomator/ui/common/VaultService.java b/main/ui/src/main/java/org/cryptomator/ui/common/VaultService.java index 35ed49870..1f4ffc3fd 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/common/VaultService.java +++ b/main/ui/src/main/java/org/cryptomator/ui/common/VaultService.java @@ -65,6 +65,7 @@ public class VaultService { public Task createLockTask(Vault vault, boolean forced) { Task task = new LockVaultTask(vault, forced); task.setOnSucceeded(evt -> LOG.info("Locked {}", vault.getDisplayName())); + task.setOnFailed(evt -> LOG.info("Failed to lock {}.", vault.getDisplayName(), evt.getSource().getException())); return task; } From c44911dcac8a3936a27b789466de0c03a6978837 Mon Sep 17 00:00:00 2001 From: Armin Schrenk Date: Wed, 18 Nov 2020 17:16:58 +0100 Subject: [PATCH 06/51] Prepare strucutre and classes for lock workflow --- .../cryptomator/ui/fxapp/FxApplication.java | 7 ++++ .../cryptomator/ui/lock/LockComponent.java | 39 +++++++++++++++++++ .../ui/lock/LockForcedController.java | 5 +++ .../org/cryptomator/ui/lock/LockModule.java | 8 ++++ .../org/cryptomator/ui/lock/LockScoped.java | 13 +++++++ .../org/cryptomator/ui/lock/LockWindow.java | 14 +++++++ .../org/cryptomator/ui/lock/LockWorkflow.java | 11 ++++++ 7 files changed, 97 insertions(+) create mode 100644 main/ui/src/main/java/org/cryptomator/ui/lock/LockComponent.java create mode 100644 main/ui/src/main/java/org/cryptomator/ui/lock/LockForcedController.java create mode 100644 main/ui/src/main/java/org/cryptomator/ui/lock/LockModule.java create mode 100644 main/ui/src/main/java/org/cryptomator/ui/lock/LockScoped.java create mode 100644 main/ui/src/main/java/org/cryptomator/ui/lock/LockWindow.java create mode 100644 main/ui/src/main/java/org/cryptomator/ui/lock/LockWorkflow.java diff --git a/main/ui/src/main/java/org/cryptomator/ui/fxapp/FxApplication.java b/main/ui/src/main/java/org/cryptomator/ui/fxapp/FxApplication.java index 650254649..643d7827d 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/fxapp/FxApplication.java +++ b/main/ui/src/main/java/org/cryptomator/ui/fxapp/FxApplication.java @@ -107,6 +107,13 @@ public class FxApplication extends Application { }); } + public void startLockWorkflow(Vault vault, Optional owner) { + Platform.runLater(() -> { + //TODO + LOG.debug("Locking vault {}", vault.getDisplayName()); + }); + } + public void showQuitWindow(QuitResponse response) { Platform.runLater(() -> { quitWindowBuilderProvider.get().quitResponse(response).build().showQuitWindow(); diff --git a/main/ui/src/main/java/org/cryptomator/ui/lock/LockComponent.java b/main/ui/src/main/java/org/cryptomator/ui/lock/LockComponent.java new file mode 100644 index 000000000..a348d4807 --- /dev/null +++ b/main/ui/src/main/java/org/cryptomator/ui/lock/LockComponent.java @@ -0,0 +1,39 @@ +package org.cryptomator.ui.lock; + +import dagger.BindsInstance; +import dagger.Subcomponent; +import org.cryptomator.common.vaults.Vault; + +import javax.inject.Named; +import javafx.stage.Stage; +import java.util.Optional; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Future; + + +@LockScoped +@Subcomponent(modules = {LockModule.class}) +public interface LockComponent { + + ExecutorService defaultExecutorService(); + + LockWorkflow lockWorkflow(); + + default Future startUnlockWorkflow() { + LockWorkflow workflow = lockWorkflow(); + defaultExecutorService().submit(workflow); + return workflow; + } + + @Subcomponent.Builder + interface Builder { + + @BindsInstance + LockComponent.Builder vault(@LockWindow Vault vault); + + @BindsInstance + LockComponent.Builder owner(@Named("lockWindowOwner") Optional owner); + + LockComponent build(); + } +} diff --git a/main/ui/src/main/java/org/cryptomator/ui/lock/LockForcedController.java b/main/ui/src/main/java/org/cryptomator/ui/lock/LockForcedController.java new file mode 100644 index 000000000..a5746082d --- /dev/null +++ b/main/ui/src/main/java/org/cryptomator/ui/lock/LockForcedController.java @@ -0,0 +1,5 @@ +package org.cryptomator.ui.lock; + +public class LockForcedController { + +} diff --git a/main/ui/src/main/java/org/cryptomator/ui/lock/LockModule.java b/main/ui/src/main/java/org/cryptomator/ui/lock/LockModule.java new file mode 100644 index 000000000..a4ccc97cd --- /dev/null +++ b/main/ui/src/main/java/org/cryptomator/ui/lock/LockModule.java @@ -0,0 +1,8 @@ +package org.cryptomator.ui.lock; + +import dagger.Module; + +@Module +public class LockModule { + +} diff --git a/main/ui/src/main/java/org/cryptomator/ui/lock/LockScoped.java b/main/ui/src/main/java/org/cryptomator/ui/lock/LockScoped.java new file mode 100644 index 000000000..68d05f6e0 --- /dev/null +++ b/main/ui/src/main/java/org/cryptomator/ui/lock/LockScoped.java @@ -0,0 +1,13 @@ +package org.cryptomator.ui.lock; + +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 LockScoped { + +} diff --git a/main/ui/src/main/java/org/cryptomator/ui/lock/LockWindow.java b/main/ui/src/main/java/org/cryptomator/ui/lock/LockWindow.java new file mode 100644 index 000000000..10d6445ab --- /dev/null +++ b/main/ui/src/main/java/org/cryptomator/ui/lock/LockWindow.java @@ -0,0 +1,14 @@ +package org.cryptomator.ui.lock; + +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 LockWindow { + +} diff --git a/main/ui/src/main/java/org/cryptomator/ui/lock/LockWorkflow.java b/main/ui/src/main/java/org/cryptomator/ui/lock/LockWorkflow.java new file mode 100644 index 000000000..b038fea4b --- /dev/null +++ b/main/ui/src/main/java/org/cryptomator/ui/lock/LockWorkflow.java @@ -0,0 +1,11 @@ +package org.cryptomator.ui.lock; + +import javafx.concurrent.Task; + +public class LockWorkflow extends Task { + + @Override + protected Boolean call() throws Exception { + return true; + } +} From 2de151aebe463c010d51219e2d79087894ca03c0 Mon Sep 17 00:00:00 2001 From: Sebastian Stenzel Date: Wed, 18 Nov 2020 18:08:00 +0100 Subject: [PATCH 07/51] use less generic name --- .../common/mountpoint/MountPointHelper.java | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/main/commons/src/main/java/org/cryptomator/common/mountpoint/MountPointHelper.java b/main/commons/src/main/java/org/cryptomator/common/mountpoint/MountPointHelper.java index c72aeb44c..704f2f62d 100644 --- a/main/commons/src/main/java/org/cryptomator/common/mountpoint/MountPointHelper.java +++ b/main/commons/src/main/java/org/cryptomator/common/mountpoint/MountPointHelper.java @@ -20,11 +20,10 @@ import java.util.Optional; class MountPointHelper { public static Logger LOG = LoggerFactory.getLogger(MountPointHelper.class); - private static final int MAX_TMPMOUNTPOINT_CREATION_RETRIES = 10; private final Optional tmpMountPointDir; - private volatile boolean alreadyChecked = false; + private volatile boolean unmountDebrisCleared = false; @Inject public MountPointHelper(Environment env) { @@ -55,13 +54,13 @@ class MountPointHelper { } public synchronized void clearIrregularUnmountDebrisIfNeeded() { - if (alreadyChecked || tmpMountPointDir.isEmpty()) { - return; //nuthin to do + if (unmountDebrisCleared || tmpMountPointDir.isEmpty()) { + return; // nothing to do } if (Files.exists(tmpMountPointDir.get(), LinkOption.NOFOLLOW_LINKS)) { clearIrregularUnmountDebris(tmpMountPointDir.get()); } - alreadyChecked = true; + unmountDebrisCleared = true; } private void clearIrregularUnmountDebris(Path dirContainingMountPoints) { @@ -92,7 +91,7 @@ class MountPointHelper { } catch (IOException e) { LOG.warn("Unable to perform cleanup of mountpoint dir {}.", dirContainingMountPoints, e); } finally { - alreadyChecked = true; + unmountDebrisCleared = true; } } From 4c66f81736dd05300404efd7a7d9804df66508a6 Mon Sep 17 00:00:00 2001 From: Sebastian Stenzel Date: Wed, 18 Nov 2020 18:09:30 +0100 Subject: [PATCH 08/51] simplified line --- .../cryptomator/common/mountpoint/MacVolumeMountChooser.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/main/commons/src/main/java/org/cryptomator/common/mountpoint/MacVolumeMountChooser.java b/main/commons/src/main/java/org/cryptomator/common/mountpoint/MacVolumeMountChooser.java index 64c0ed979..334746860 100644 --- a/main/commons/src/main/java/org/cryptomator/common/mountpoint/MacVolumeMountChooser.java +++ b/main/commons/src/main/java/org/cryptomator/common/mountpoint/MacVolumeMountChooser.java @@ -28,7 +28,7 @@ class MacVolumeMountChooser implements MountPointChooser { @Override public Optional chooseMountPoint(Volume caller) { - return Optional.of(VOLUME_PATH).map(dir -> this.helper.chooseTemporaryMountPoint(this.vaultSettings, dir)); + return Optional.of(helper.chooseTemporaryMountPoint(vaultSettings, VOLUME_PATH)); } @Override From 02fc9b263a55bc1045b194a1bada6caef5cebdfd Mon Sep 17 00:00:00 2001 From: Sebastian Stenzel Date: Wed, 18 Nov 2020 18:12:41 +0100 Subject: [PATCH 09/51] re-added applicable choosers to exception text --- .../java/org/cryptomator/common/vaults/AbstractVolume.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/main/commons/src/main/java/org/cryptomator/common/vaults/AbstractVolume.java b/main/commons/src/main/java/org/cryptomator/common/vaults/AbstractVolume.java index 6a09683ca..d66ad19d8 100644 --- a/main/commons/src/main/java/org/cryptomator/common/vaults/AbstractVolume.java +++ b/main/commons/src/main/java/org/cryptomator/common/vaults/AbstractVolume.java @@ -20,7 +20,8 @@ public abstract class AbstractVolume implements Volume { } protected Path determineMountPoint() throws InvalidMountPointException { - for (var chooser : Iterables.filter(choosers, c -> c.isApplicable(this))) { + var applicableChoosers = Iterables.filter(choosers, c -> c.isApplicable(this)); + for (var chooser : applicableChoosers) { Optional chosenPath = chooser.chooseMountPoint(this); if (chosenPath.isEmpty()) { // chooser couldn't find a feasible mountpoint continue; @@ -29,7 +30,7 @@ public abstract class AbstractVolume implements Volume { this.usedChooser = chooser; return chosenPath.get(); } - throw new InvalidMountPointException("No feasible MountPoint found!"); + throw new InvalidMountPointException(String.format("No feasible MountPoint found by choosers: %s", applicableChoosers)); } protected void cleanupMountPoint() { From 57bfa3276dcd44f266021965f1b08fe01319554f Mon Sep 17 00:00:00 2001 From: Armin Schrenk Date: Thu, 19 Nov 2020 11:42:00 +0100 Subject: [PATCH 10/51] Integrate new lockWorkflow into application (gui and tray) --- .../cryptomator/ui/fxapp/FxApplication.java | 7 +- .../ui/fxapp/FxApplicationModule.java | 3 +- .../cryptomator/ui/lock/LockComponent.java | 2 +- .../org/cryptomator/ui/lock/LockWorkflow.java | 72 ++++++++++++++++++- .../VaultDetailUnlockedController.java | 12 +++- .../ui/traymenu/TrayMenuController.java | 2 +- 6 files changed, 89 insertions(+), 9 deletions(-) diff --git a/main/ui/src/main/java/org/cryptomator/ui/fxapp/FxApplication.java b/main/ui/src/main/java/org/cryptomator/ui/fxapp/FxApplication.java index 643d7827d..18c9a499c 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/fxapp/FxApplication.java +++ b/main/ui/src/main/java/org/cryptomator/ui/fxapp/FxApplication.java @@ -12,6 +12,7 @@ import org.cryptomator.integrations.uiappearance.UiAppearanceException; import org.cryptomator.integrations.uiappearance.UiAppearanceListener; import org.cryptomator.integrations.uiappearance.UiAppearanceProvider; import org.cryptomator.ui.common.VaultService; +import org.cryptomator.ui.lock.LockComponent; import org.cryptomator.ui.mainwindow.MainWindowComponent; import org.cryptomator.ui.preferences.PreferencesComponent; import org.cryptomator.ui.preferences.SelectedPreferencesTab; @@ -41,6 +42,7 @@ public class FxApplication extends Application { private final Lazy mainWindow; private final Lazy preferencesWindow; private final Provider unlockWindowBuilderProvider; + private final Provider lockWindowBuilderProvider; private final Provider quitWindowBuilderProvider; private final Optional trayIntegration; private final Optional appearanceProvider; @@ -50,11 +52,12 @@ public class FxApplication extends Application { private final UiAppearanceListener systemInterfaceThemeListener = this::systemInterfaceThemeChanged; @Inject - FxApplication(Settings settings, Lazy mainWindow, Lazy preferencesWindow, Provider unlockWindowBuilderProvider, Provider quitWindowBuilderProvider, Optional trayIntegration, Optional appearanceProvider, VaultService vaultService, LicenseHolder licenseHolder, ObservableSet visibleStages) { + FxApplication(Settings settings, Lazy mainWindow, Lazy preferencesWindow, Provider unlockWindowBuilderProvider, Provider lockWindowBuilderProvider, Provider quitWindowBuilderProvider, Optional trayIntegration, Optional appearanceProvider, VaultService vaultService, LicenseHolder licenseHolder, ObservableSet visibleStages) { this.settings = settings; this.mainWindow = mainWindow; this.preferencesWindow = preferencesWindow; this.unlockWindowBuilderProvider = unlockWindowBuilderProvider; + this.lockWindowBuilderProvider = lockWindowBuilderProvider; this.quitWindowBuilderProvider = quitWindowBuilderProvider; this.trayIntegration = trayIntegration; this.appearanceProvider = appearanceProvider; @@ -109,7 +112,7 @@ public class FxApplication extends Application { public void startLockWorkflow(Vault vault, Optional owner) { Platform.runLater(() -> { - //TODO + lockWindowBuilderProvider.get().vault(vault).owner(owner).build().startLockWorkflow(); LOG.debug("Locking vault {}", vault.getDisplayName()); }); } diff --git a/main/ui/src/main/java/org/cryptomator/ui/fxapp/FxApplicationModule.java b/main/ui/src/main/java/org/cryptomator/ui/fxapp/FxApplicationModule.java index a6297ce4a..39b3020be 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/fxapp/FxApplicationModule.java +++ b/main/ui/src/main/java/org/cryptomator/ui/fxapp/FxApplicationModule.java @@ -11,6 +11,7 @@ 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.lock.LockComponent; import org.cryptomator.ui.mainwindow.MainWindowComponent; import org.cryptomator.ui.preferences.PreferencesComponent; import org.cryptomator.ui.quit.QuitComponent; @@ -28,7 +29,7 @@ import java.io.UncheckedIOException; import java.util.Collections; import java.util.List; -@Module(includes = {UpdateCheckerModule.class}, subcomponents = {MainWindowComponent.class, PreferencesComponent.class, UnlockComponent.class, QuitComponent.class, ErrorComponent.class}) +@Module(includes = {UpdateCheckerModule.class}, subcomponents = {MainWindowComponent.class, PreferencesComponent.class, UnlockComponent.class, LockComponent.class, QuitComponent.class, ErrorComponent.class}) abstract class FxApplicationModule { @Provides diff --git a/main/ui/src/main/java/org/cryptomator/ui/lock/LockComponent.java b/main/ui/src/main/java/org/cryptomator/ui/lock/LockComponent.java index a348d4807..972ebc5f9 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/lock/LockComponent.java +++ b/main/ui/src/main/java/org/cryptomator/ui/lock/LockComponent.java @@ -19,7 +19,7 @@ public interface LockComponent { LockWorkflow lockWorkflow(); - default Future startUnlockWorkflow() { + default Future startLockWorkflow() { LockWorkflow workflow = lockWorkflow(); defaultExecutorService().submit(workflow); return workflow; diff --git a/main/ui/src/main/java/org/cryptomator/ui/lock/LockWorkflow.java b/main/ui/src/main/java/org/cryptomator/ui/lock/LockWorkflow.java index b038fea4b..381c6fdb9 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/lock/LockWorkflow.java +++ b/main/ui/src/main/java/org/cryptomator/ui/lock/LockWorkflow.java @@ -1,11 +1,81 @@ package org.cryptomator.ui.lock; +import org.cryptomator.common.vaults.Vault; +import org.cryptomator.common.vaults.VaultState; +import org.cryptomator.common.vaults.Volume; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.inject.Inject; import javafx.concurrent.Task; public class LockWorkflow extends Task { + private static final Logger LOG = LoggerFactory.getLogger(LockWorkflow.class); + + private final Vault vault; + + @Inject + public LockWorkflow(@LockWindow Vault vault) { + this.vault = vault; + } + @Override protected Boolean call() throws Exception { - return true; + // change vault state to processing -- done by overriding scheduled method of Task + if (attemptLock() || attemptForcedLock()) { + handleSuccess(); + return true; + } else { + //canceled -- for error the overriden failed() method is responsible + return false; + } } + + private boolean attemptLock() { + try { + vault.lock(false); + return true; + } catch (Volume.VolumeException e) { + e.printStackTrace(); + return false; + } + } + + private boolean attemptForcedLock() { + // show forcedLock dialogue + // wait for answer + // depening on answer do one of two things + // a) force Lock -> needs to throw exception on failure + // b) cancel + // if lock was performed over main window, show it again + return false; + } + + private void handleSuccess() { + LOG.info("Lock of {} succeeded.", vault.getDisplayName()); + // set vault state to locked + } + + @Override + protected void scheduled() { + vault.setState(VaultState.PROCESSING); + } + + @Override + protected void succeeded() { + vault.setState(VaultState.LOCKED); + } + + @Override + protected void failed() { + LOG.info("Failed to lock {}.", vault.getDisplayName()); + vault.setState(VaultState.UNLOCKED); + } + + @Override + protected void cancelled() { + vault.setState(VaultState.UNLOCKED); + } + } diff --git a/main/ui/src/main/java/org/cryptomator/ui/mainwindow/VaultDetailUnlockedController.java b/main/ui/src/main/java/org/cryptomator/ui/mainwindow/VaultDetailUnlockedController.java index 1806d9e5e..0af909bbc 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/mainwindow/VaultDetailUnlockedController.java +++ b/main/ui/src/main/java/org/cryptomator/ui/mainwindow/VaultDetailUnlockedController.java @@ -6,25 +6,32 @@ import com.google.common.cache.LoadingCache; import org.cryptomator.common.vaults.Vault; import org.cryptomator.ui.common.FxController; import org.cryptomator.ui.common.VaultService; +import org.cryptomator.ui.fxapp.FxApplication; import org.cryptomator.ui.stats.VaultStatisticsComponent; import javax.inject.Inject; import javafx.beans.property.ObjectProperty; import javafx.beans.property.ReadOnlyObjectProperty; import javafx.fxml.FXML; +import javafx.stage.Stage; +import java.util.Optional; @MainWindowScoped public class VaultDetailUnlockedController implements FxController { private final ReadOnlyObjectProperty vault; + private final FxApplication application; private final VaultService vaultService; + private final Stage mainWindow; private final LoadingCache vaultStats; private final VaultStatisticsComponent.Builder vaultStatsBuilder; @Inject - public VaultDetailUnlockedController(ObjectProperty vault, VaultService vaultService, VaultStatisticsComponent.Builder vaultStatsBuilder) { + public VaultDetailUnlockedController(ObjectProperty vault, FxApplication application, VaultService vaultService, VaultStatisticsComponent.Builder vaultStatsBuilder, @MainWindow Stage mainWindow) { this.vault = vault; + this.application = application; this.vaultService = vaultService; + this.mainWindow = mainWindow; this.vaultStats = CacheBuilder.newBuilder().weakValues().build(CacheLoader.from(this::buildVaultStats)); this.vaultStatsBuilder = vaultStatsBuilder; } @@ -40,8 +47,7 @@ public class VaultDetailUnlockedController implements FxController { @FXML public void lock() { - vaultService.lock(vault.get(), false); - // TODO count lock attempts, and allow forced lock + application.startLockWorkflow(vault.get(), Optional.of(mainWindow)); } @FXML diff --git a/main/ui/src/main/java/org/cryptomator/ui/traymenu/TrayMenuController.java b/main/ui/src/main/java/org/cryptomator/ui/traymenu/TrayMenuController.java index 51f7c2225..a65f1e493 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/traymenu/TrayMenuController.java +++ b/main/ui/src/main/java/org/cryptomator/ui/traymenu/TrayMenuController.java @@ -108,7 +108,7 @@ class TrayMenuController { } private void lockVault(Vault vault) { - fxApplicationStarter.get(true).thenAccept(app -> app.getVaultService().lock(vault, false)); + fxApplicationStarter.get(true).thenAccept(app -> app.startLockWorkflow(vault, Optional.empty())); } private void lockAllVaults(ActionEvent actionEvent) { From 432a9a27f1b073fe611dee32a8ec4de49bdd976c Mon Sep 17 00:00:00 2001 From: Armin Schrenk Date: Thu, 19 Nov 2020 12:52:16 +0100 Subject: [PATCH 11/51] Add forceLock Dialogue: * integrate it in workflow if normal lock throws exception * add stubs if also forced lock fails --- .../org/cryptomator/ui/common/FxmlFile.java | 2 + .../ui/lock/LockFailedController.java | 14 ++++ .../ui/lock/LockForcedController.java | 45 +++++++++- .../org/cryptomator/ui/lock/LockModule.java | 83 ++++++++++++++++++- .../org/cryptomator/ui/lock/LockWorkflow.java | 55 +++++++++--- .../src/main/resources/fxml/lock_failed.fxml | 20 +++++ .../src/main/resources/fxml/lock_forced.fxml | 40 +++++++++ 7 files changed, 245 insertions(+), 14 deletions(-) create mode 100644 main/ui/src/main/java/org/cryptomator/ui/lock/LockFailedController.java create mode 100644 main/ui/src/main/resources/fxml/lock_failed.fxml create mode 100644 main/ui/src/main/resources/fxml/lock_forced.fxml diff --git a/main/ui/src/main/java/org/cryptomator/ui/common/FxmlFile.java b/main/ui/src/main/java/org/cryptomator/ui/common/FxmlFile.java index 43074a605..310e11747 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/common/FxmlFile.java +++ b/main/ui/src/main/java/org/cryptomator/ui/common/FxmlFile.java @@ -11,6 +11,8 @@ public enum FxmlFile { CHANGEPASSWORD("/fxml/changepassword.fxml"), // ERROR("/fxml/error.fxml"), // FORGET_PASSWORD("/fxml/forget_password.fxml"), // + LOCK_FORCED("/fxml/lock_forced.fxml"), // + LOCK_FAILED("/fxml/lock_failed.fxml"), // MAIN_WINDOW("/fxml/main_window.fxml"), // MIGRATION_CAPABILITY_ERROR("/fxml/migration_capability_error.fxml"), // MIGRATION_IMPOSSIBLE("/fxml/migration_impossible.fxml"), diff --git a/main/ui/src/main/java/org/cryptomator/ui/lock/LockFailedController.java b/main/ui/src/main/java/org/cryptomator/ui/lock/LockFailedController.java new file mode 100644 index 000000000..66dd203ea --- /dev/null +++ b/main/ui/src/main/java/org/cryptomator/ui/lock/LockFailedController.java @@ -0,0 +1,14 @@ +package org.cryptomator.ui.lock; + +import org.cryptomator.ui.common.FxController; + +import javax.inject.Inject; + +public class LockFailedController implements FxController { + + @Inject + public LockFailedController() { + + } + +} diff --git a/main/ui/src/main/java/org/cryptomator/ui/lock/LockForcedController.java b/main/ui/src/main/java/org/cryptomator/ui/lock/LockForcedController.java index a5746082d..a66af9902 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/lock/LockForcedController.java +++ b/main/ui/src/main/java/org/cryptomator/ui/lock/LockForcedController.java @@ -1,5 +1,48 @@ package org.cryptomator.ui.lock; -public class LockForcedController { +import org.cryptomator.common.vaults.Vault; +import org.cryptomator.ui.common.FxController; +import org.cryptomator.ui.common.UserInteractionLock; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.inject.Inject; +import javafx.event.ActionEvent; +import javafx.stage.Stage; +import javafx.stage.WindowEvent; + +public class LockForcedController implements FxController { + + private static final Logger LOG = LoggerFactory.getLogger(LockForcedController.class); + + private final Stage window; + private final Vault vault; + private final UserInteractionLock forceLockDecisionLock; + + @Inject + public LockForcedController(@LockWindow Stage window, @LockWindow Vault vault, UserInteractionLock forceLockDecisionLock) { + this.window = window; + this.vault = vault; + this.forceLockDecisionLock = forceLockDecisionLock; + this.window.setOnHiding(this::windowClosed); + } + + public void cancel() { + forceLockDecisionLock.interacted(LockModule.ForceLockDecision.CANCEL); + window.close(); + } + + public void confirmForcedLock(ActionEvent actionEvent) { + forceLockDecisionLock.interacted(LockModule.ForceLockDecision.FORCE); + window.close(); + } + + private void windowClosed(WindowEvent windowEvent) { + // if not already interacted, mark this workflow as cancelled: + if (forceLockDecisionLock.awaitingInteraction().get()) { + LOG.debug("Lock canceled in force-lock-phase by user."); + forceLockDecisionLock.interacted(LockModule.ForceLockDecision.CANCEL); + } + } } diff --git a/main/ui/src/main/java/org/cryptomator/ui/lock/LockModule.java b/main/ui/src/main/java/org/cryptomator/ui/lock/LockModule.java index a4ccc97cd..bbc8c2209 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/lock/LockModule.java +++ b/main/ui/src/main/java/org/cryptomator/ui/lock/LockModule.java @@ -1,8 +1,89 @@ package org.cryptomator.ui.lock; +import dagger.Binds; import dagger.Module; +import dagger.Provides; +import dagger.multibindings.IntoMap; +import org.cryptomator.common.vaults.Vault; +import org.cryptomator.ui.common.DefaultSceneFactory; +import org.cryptomator.ui.common.FXMLLoaderFactory; +import org.cryptomator.ui.common.FxController; +import org.cryptomator.ui.common.FxControllerKey; +import org.cryptomator.ui.common.FxmlFile; +import org.cryptomator.ui.common.FxmlScene; +import org.cryptomator.ui.common.StageFactory; +import org.cryptomator.ui.common.UserInteractionLock; + +import javax.inject.Named; +import javax.inject.Provider; +import javafx.scene.Scene; +import javafx.stage.Modality; +import javafx.stage.Stage; +import java.util.Map; +import java.util.Optional; +import java.util.ResourceBundle; @Module -public class LockModule { +abstract class LockModule { + + enum ForceLockDecision { + CANCEL, + FORCE; + } + + @Provides + @LockScoped + static UserInteractionLock provideForceLockDecisionLock() { + return new UserInteractionLock<>(null); + } + + @Provides + @LockWindow + @LockScoped + static FXMLLoaderFactory provideFxmlLoaderFactory(Map, Provider> factories, DefaultSceneFactory sceneFactory, ResourceBundle resourceBundle) { + return new FXMLLoaderFactory(factories, sceneFactory, resourceBundle); + } + + @Provides + @LockWindow + @LockScoped + static Stage provideWindow(StageFactory factory, @LockWindow Vault vault, @Named("lockWindowOwner") Optional owner) { + Stage stage = factory.create(); + stage.setTitle(vault.getDisplayName()); + stage.setResizable(false); + if (owner.isPresent()) { + stage.initOwner(owner.get()); + stage.initModality(Modality.WINDOW_MODAL); + } else { + stage.initModality(Modality.APPLICATION_MODAL); + } + return stage; + } + + @Provides + @FxmlScene(FxmlFile.LOCK_FORCED) + @LockScoped + static Scene provideForceLockScene(@LockWindow FXMLLoaderFactory fxmlLoaders) { + return fxmlLoaders.createScene("/fxml/lock_forced.fxml"); + } + + @Provides + @FxmlScene(FxmlFile.LOCK_FAILED) + @LockScoped + static Scene provideLockFailedScene(@LockWindow FXMLLoaderFactory fxmlLoaders) { + return fxmlLoaders.createScene("/fxml/lock_failed.fxml"); + } + + // ------------------ + + @Binds + @IntoMap + @FxControllerKey(LockForcedController.class) + abstract FxController bindLockForcedController(LockForcedController controller); + + @Binds + @IntoMap + @FxControllerKey(LockFailedController.class) + abstract FxController bindLockFailedController(LockFailedController controller); } diff --git a/main/ui/src/main/java/org/cryptomator/ui/lock/LockWorkflow.java b/main/ui/src/main/java/org/cryptomator/ui/lock/LockWorkflow.java index 381c6fdb9..d63661e02 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/lock/LockWorkflow.java +++ b/main/ui/src/main/java/org/cryptomator/ui/lock/LockWorkflow.java @@ -1,27 +1,43 @@ package org.cryptomator.ui.lock; +import dagger.Lazy; import org.cryptomator.common.vaults.Vault; import org.cryptomator.common.vaults.VaultState; import org.cryptomator.common.vaults.Volume; +import org.cryptomator.ui.common.FxmlFile; +import org.cryptomator.ui.common.FxmlScene; +import org.cryptomator.ui.common.UserInteractionLock; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import javax.inject.Inject; +import javafx.application.Platform; import javafx.concurrent.Task; +import javafx.scene.Scene; +import javafx.stage.Stage; +import javafx.stage.Window; public class LockWorkflow extends Task { private static final Logger LOG = LoggerFactory.getLogger(LockWorkflow.class); + private final Stage lockWindow; private final Vault vault; + private final UserInteractionLock forceLockDecisionLock; + private final Lazy lockForcedScene; + private final Lazy lockFailedScene; @Inject - public LockWorkflow(@LockWindow Vault vault) { + public LockWorkflow(@LockWindow Stage lockWindow, @LockWindow Vault vault, UserInteractionLock forceLockDecisionLock, @FxmlScene(FxmlFile.LOCK_FORCED) Lazy lockForcedScene, @FxmlScene(FxmlFile.LOCK_FAILED) Lazy lockFailedScene) { + this.lockWindow = lockWindow; this.vault = vault; + this.forceLockDecisionLock = forceLockDecisionLock; + this.lockForcedScene = lockForcedScene; + this.lockFailedScene = lockFailedScene; } @Override - protected Boolean call() throws Exception { + protected Boolean call() throws Volume.VolumeException, InterruptedException { // change vault state to processing -- done by overriding scheduled method of Task if (attemptLock() || attemptForcedLock()) { handleSuccess(); @@ -42,19 +58,34 @@ public class LockWorkflow extends Task { } } - private boolean attemptForcedLock() { - // show forcedLock dialogue - // wait for answer - // depening on answer do one of two things - // a) force Lock -> needs to throw exception on failure - // b) cancel - // if lock was performed over main window, show it again - return false; + private boolean attemptForcedLock() throws Volume.VolumeException, InterruptedException { + // show forcedLock dialogue ... + Platform.runLater(() -> { + lockWindow.setScene(lockForcedScene.get()); + lockWindow.show(); + Window owner = lockWindow.getOwner(); + if (owner != null) { + lockWindow.setX(owner.getX() + (owner.getWidth() - lockWindow.getWidth()) / 2); + lockWindow.setY(owner.getY() + (owner.getHeight() - lockWindow.getHeight()) / 2); + } else { + lockWindow.centerOnScreen(); + } + }); + // ... and wait for answer + switch (forceLockDecisionLock.awaitInteraction()) { + case FORCE: + vault.lock(true); + return true; + case CANCEL: + // if lock was performed over main window, show it again + return false; + default: + return false; + } } private void handleSuccess() { - LOG.info("Lock of {} succeeded.", vault.getDisplayName()); - // set vault state to locked + LOG.info("Lock of {} succeeded.", vault.getDisplayName()); } @Override diff --git a/main/ui/src/main/resources/fxml/lock_failed.fxml b/main/ui/src/main/resources/fxml/lock_failed.fxml new file mode 100644 index 000000000..9b4e0a2b9 --- /dev/null +++ b/main/ui/src/main/resources/fxml/lock_failed.fxml @@ -0,0 +1,20 @@ + + + + + + + + + + + + + diff --git a/main/ui/src/main/resources/fxml/lock_forced.fxml b/main/ui/src/main/resources/fxml/lock_forced.fxml new file mode 100644 index 000000000..be311261d --- /dev/null +++ b/main/ui/src/main/resources/fxml/lock_forced.fxml @@ -0,0 +1,40 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + +