diff --git a/.github/workflows/av-whitelist.yml b/.github/workflows/av-whitelist.yml
index ca74a3281..16dd61bcf 100644
--- a/.github/workflows/av-whitelist.yml
+++ b/.github/workflows/av-whitelist.yml
@@ -7,6 +7,16 @@ on:
description: "Url to the file to upload"
required: true
type: string
+ avast:
+ description: "Upload to Avast"
+ required: false
+ type: boolean
+ default: true
+ kaspersky:
+ description: "Upload to Kaspersky"
+ required: false
+ type: boolean
+ default: true
workflow_dispatch:
inputs:
url:
@@ -39,7 +49,7 @@ jobs:
url="${INPUT_URL}"
echo "fileName=${url##*/}" >> $GITHUB_OUTPUT
- name: Download file
- run: curl --remote-name ${INPUT_URL} -L -o ${{steps.extractName.outputs.fileName}}
+ run: curl "${INPUT_URL}" -L -o "${{steps.extractName.outputs.fileName}}" --fail-with-body
- name: Upload artifact
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
with:
@@ -50,7 +60,7 @@ jobs:
name: Anti Virus Allowlisting Kaspersky
runs-on: ubuntu-latest
needs: download-file
- if: github.event_name == 'workflow_call' || inputs.kaspersky
+ if: inputs.kaspersky
steps:
- name: Download artifact
uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # v5.0.0
@@ -70,7 +80,7 @@ jobs:
name: Anti Virus Allowlisting Avast
runs-on: ubuntu-latest
needs: download-file
- if: github.event_name == 'workflow_call' || inputs.avast
+ if: inputs.avast
steps:
- name: Download artifact
uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # v5.0.0
diff --git a/pom.xml b/pom.xml
index 24f35de0a..75ecf99d9 100644
--- a/pom.xml
+++ b/pom.xml
@@ -33,7 +33,7 @@
org.ow2.asm,org.apache.jackrabbit,org.apache.httpcomponents
- 2.9.0
+ 2.10.0-beta2
1.8.0-beta1
1.5.1
1.5.0-beta1
diff --git a/src/main/java/org/cryptomator/common/FilsystemOwnerSupplier.java b/src/main/java/org/cryptomator/common/FilsystemOwnerSupplier.java
new file mode 100644
index 000000000..addea85ba
--- /dev/null
+++ b/src/main/java/org/cryptomator/common/FilsystemOwnerSupplier.java
@@ -0,0 +1,16 @@
+package org.cryptomator.common;
+
+/**
+ * Objects which has some kind of owner.
+ */
+@FunctionalInterface
+public interface FilsystemOwnerSupplier {
+
+ /**
+ * Get the object owner.
+ *
+ * @return the object owner
+ */
+ String getOwner();
+
+}
diff --git a/src/main/java/org/cryptomator/common/vaults/Vault.java b/src/main/java/org/cryptomator/common/vaults/Vault.java
index 5012e5c78..b5158411b 100644
--- a/src/main/java/org/cryptomator/common/vaults/Vault.java
+++ b/src/main/java/org/cryptomator/common/vaults/Vault.java
@@ -10,6 +10,7 @@ package org.cryptomator.common.vaults;
import org.apache.commons.lang3.SystemUtils;
import org.cryptomator.common.Constants;
+import org.cryptomator.common.FilsystemOwnerSupplier;
import org.cryptomator.common.mount.Mounter;
import org.cryptomator.common.settings.Settings;
import org.cryptomator.common.settings.VaultSettings;
@@ -149,14 +150,17 @@ public class Vault {
LOG.warn("Limiting cleartext filename length on this device to {}.", vaultSettings.maxCleartextFilenameLength.get());
}
- CryptoFileSystemProperties fsProps = CryptoFileSystemProperties.cryptoFileSystemProperties() //
+ var fsPropsBuilder = CryptoFileSystemProperties.cryptoFileSystemProperties() //
.withKeyLoader(keyLoader) //
.withFlags(flags) //
.withMaxCleartextNameLength(vaultSettings.maxCleartextFilenameLength.get()) //
.withVaultConfigFilename(Constants.VAULTCONFIG_FILENAME) //
- .withFilesystemEventConsumer(this::consumeVaultEvent) //
- .build();
- return CryptoFileSystemProvider.newFileSystem(getPath(), fsProps);
+ .withFilesystemEventConsumer(this::consumeVaultEvent);
+ if (keyLoader instanceof FilsystemOwnerSupplier oo) {
+ fsPropsBuilder.withOwnerGetter(oo::getOwner);
+ }
+
+ return CryptoFileSystemProvider.newFileSystem(getPath(), fsPropsBuilder.build());
}
private void destroyCryptoFileSystem() {
diff --git a/src/main/java/org/cryptomator/event/FileSystemEventAggregator.java b/src/main/java/org/cryptomator/event/FileSystemEventAggregator.java
index c871436fd..b27238cee 100644
--- a/src/main/java/org/cryptomator/event/FileSystemEventAggregator.java
+++ b/src/main/java/org/cryptomator/event/FileSystemEventAggregator.java
@@ -6,6 +6,7 @@ import org.cryptomator.cryptofs.event.BrokenFileNodeEvent;
import org.cryptomator.cryptofs.event.ConflictResolutionFailedEvent;
import org.cryptomator.cryptofs.event.ConflictResolvedEvent;
import org.cryptomator.cryptofs.event.DecryptionFailedEvent;
+import org.cryptomator.cryptofs.event.FileIsInUseEvent;
import org.cryptomator.cryptofs.event.FilesystemEvent;
import javax.inject.Inject;
@@ -101,6 +102,7 @@ public class FileSystemEventAggregator {
case ConflictResolutionFailedEvent(_, _, Path conflictingCiphertext, _) -> conflictingCiphertext;
case BrokenDirFileEvent(_, Path ciphertext) -> ciphertext;
case BrokenFileNodeEvent(_, _, Path ciphertext) -> ciphertext;
+ case FileIsInUseEvent(_, _, Path ciphertext, _, _, _) -> ciphertext;
};
return new FSEventBucket(v, p, event.getClass());
}
diff --git a/src/main/java/org/cryptomator/ui/eventview/EventListCellController.java b/src/main/java/org/cryptomator/ui/eventview/EventListCellController.java
index 3157f9f40..4c195db10 100644
--- a/src/main/java/org/cryptomator/ui/eventview/EventListCellController.java
+++ b/src/main/java/org/cryptomator/ui/eventview/EventListCellController.java
@@ -1,5 +1,6 @@
package org.cryptomator.ui.eventview;
+import org.cryptomator.cryptofs.event.FileIsInUseEvent;
import org.cryptomator.event.FSEventBucket;
import org.cryptomator.event.FSEventBucketContent;
import org.cryptomator.event.FileSystemEventAggregator;
@@ -115,7 +116,7 @@ public class EventListCellController implements FxController {
eventActionsMenu.hide();
eventActionsMenu.getItems().clear();
eventTooltip.setText(item.getKey().vault().getDisplayName());
- addAction("generic.action.dismiss", () -> {
+ addLocalizedAction("generic.action.dismiss", () -> {
fileSystemEventAggregator.remove(item.getKey());
});
switch (item.getValue().mostRecentEvent()) {
@@ -124,20 +125,36 @@ public class EventListCellController implements FxController {
case DecryptionFailedEvent fse -> this.adjustToDecryptionFailedEvent(fse);
case BrokenDirFileEvent fse -> this.adjustToBrokenDirFileEvent(fse);
case BrokenFileNodeEvent fse -> this.adjustToBrokenFileNodeEvent(fse);
+ case FileIsInUseEvent fse -> this.adjustToFileInUseEvent(fse);
}
}
+ private void adjustToFileInUseEvent(FileIsInUseEvent fse) {
+ eventIcon.setValue(FontAwesome5Icon.TIMES);
+ eventMessage.setValue("File is in use by " + fse.owner());
+ var indexFileName = fse.cleartextPath().lastIndexOf("/");
+ eventDescription.setValue(fse.cleartextPath().substring(indexFileName + 1));
+ if (revealService != null) {
+ addAction("Show decrypted file", () -> reveal(revealService, convertVaultPathToSystemPath(fse.cleartextPath())));
+ addAction("Show encrypted Path", () -> reveal(revealService, fse.ciphertextPath()));
+ } else {
+ addAction("Copy decrypted Path", () -> copyToClipboard(convertVaultPathToSystemPath(fse.cleartextPath()).toString()));
+ addAction("Copy encrypted Path", () -> copyToClipboard(fse.ciphertextPath().toString()));
+ }
+ addAction("Ignore in use status ", fse.ignoreMethod());
+ }
+
private void adjustToBrokenFileNodeEvent(BrokenFileNodeEvent bfe) {
eventIcon.setValue(FontAwesome5Icon.TIMES);
eventMessage.setValue(resourceBundle.getString("eventView.entry.brokenFileNode.message"));
eventDescription.setValue(bfe.ciphertextPath().getFileName().toString());
if (revealService != null) {
- addAction("eventView.entry.brokenFileNode.showEncrypted", () -> reveal(revealService, bfe.ciphertextPath()));
+ addLocalizedAction("eventView.entry.brokenFileNode.showEncrypted", () -> reveal(revealService, bfe.ciphertextPath()));
} else {
- addAction("eventView.entry.brokenFileNode.copyEncrypted", () -> copyToClipboard(bfe.ciphertextPath().toString()));
+ addLocalizedAction("eventView.entry.brokenFileNode.copyEncrypted", () -> copyToClipboard(bfe.ciphertextPath().toString()));
}
- addAction("eventView.entry.brokenFileNode.copyDecrypted", () -> copyToClipboard(convertVaultPathToSystemPath(bfe.cleartextPath()).toString()));
+ addLocalizedAction("eventView.entry.brokenFileNode.copyDecrypted", () -> copyToClipboard(convertVaultPathToSystemPath(bfe.cleartextPath()).toString()));
}
private void adjustToConflictResolvedEvent(ConflictResolvedEvent cre) {
@@ -145,9 +162,9 @@ public class EventListCellController implements FxController {
eventMessage.setValue(resourceBundle.getString("eventView.entry.conflictResolved.message"));
eventDescription.setValue(cre.resolvedCiphertextPath().getFileName().toString());
if (revealService != null) {
- addAction("eventView.entry.conflictResolved.showDecrypted", () -> reveal(revealService, convertVaultPathToSystemPath(cre.resolvedCleartextPath())));
+ addLocalizedAction("eventView.entry.conflictResolved.showDecrypted", () -> reveal(revealService, convertVaultPathToSystemPath(cre.resolvedCleartextPath())));
} else {
- addAction("eventView.entry.conflictResolved.copyDecrypted", () -> copyToClipboard(convertVaultPathToSystemPath(cre.resolvedCleartextPath()).toString()));
+ addLocalizedAction("eventView.entry.conflictResolved.copyDecrypted", () -> copyToClipboard(convertVaultPathToSystemPath(cre.resolvedCleartextPath()).toString()));
}
}
@@ -156,11 +173,11 @@ public class EventListCellController implements FxController {
eventMessage.setValue(resourceBundle.getString("eventView.entry.conflict.message"));
eventDescription.setValue(cfe.conflictingCiphertextPath().getFileName().toString());
if (revealService != null) {
- addAction("eventView.entry.conflict.showDecrypted", () -> reveal(revealService, convertVaultPathToSystemPath(cfe.canonicalCleartextPath())));
- addAction("eventView.entry.conflict.showEncrypted", () -> reveal(revealService, cfe.conflictingCiphertextPath()));
+ addLocalizedAction("eventView.entry.conflict.showDecrypted", () -> reveal(revealService, convertVaultPathToSystemPath(cfe.canonicalCleartextPath())));
+ addLocalizedAction("eventView.entry.conflict.showEncrypted", () -> reveal(revealService, cfe.conflictingCiphertextPath()));
} else {
- addAction("eventView.entry.conflict.copyDecrypted", () -> copyToClipboard(convertVaultPathToSystemPath(cfe.canonicalCleartextPath()).toString()));
- addAction("eventView.entry.conflict.copyEncrypted", () -> copyToClipboard(cfe.conflictingCiphertextPath().toString()));
+ addLocalizedAction("eventView.entry.conflict.copyDecrypted", () -> copyToClipboard(convertVaultPathToSystemPath(cfe.canonicalCleartextPath()).toString()));
+ addLocalizedAction("eventView.entry.conflict.copyEncrypted", () -> copyToClipboard(cfe.conflictingCiphertextPath().toString()));
}
}
@@ -169,9 +186,9 @@ public class EventListCellController implements FxController {
eventMessage.setValue(resourceBundle.getString("eventView.entry.decryptionFailed.message"));
eventDescription.setValue(dfe.ciphertextPath().getFileName().toString());
if (revealService != null) {
- addAction("eventView.entry.decryptionFailed.showEncrypted", () -> reveal(revealService, dfe.ciphertextPath()));
+ addLocalizedAction("eventView.entry.decryptionFailed.showEncrypted", () -> reveal(revealService, dfe.ciphertextPath()));
} else {
- addAction("eventView.entry.decryptionFailed.copyEncrypted", () -> copyToClipboard(dfe.ciphertextPath().toString()));
+ addLocalizedAction("eventView.entry.decryptionFailed.copyEncrypted", () -> copyToClipboard(dfe.ciphertextPath().toString()));
}
}
@@ -180,14 +197,19 @@ public class EventListCellController implements FxController {
eventMessage.setValue(resourceBundle.getString("eventView.entry.brokenDirFile.message"));
eventDescription.setValue(bde.ciphertextPath().getParent().getFileName().toString());
if (revealService != null) {
- addAction("eventView.entry.brokenDirFile.showEncrypted", () -> reveal(revealService, bde.ciphertextPath()));
+ addLocalizedAction("eventView.entry.brokenDirFile.showEncrypted", () -> reveal(revealService, bde.ciphertextPath()));
} else {
- addAction("eventView.entry.brokenDirFile.copyEncrypted", () -> copyToClipboard(bde.ciphertextPath().toString()));
+ addLocalizedAction("eventView.entry.brokenDirFile.copyEncrypted", () -> copyToClipboard(bde.ciphertextPath().toString()));
}
}
- private void addAction(String localizationKey, Runnable action) {
- var entry = new MenuItem(resourceBundle.getString(localizationKey));
+ private void addLocalizedAction(String localizationKey, Runnable action) {
+ var entryText = resourceBundle.getString(localizationKey);
+ addAction(entryText, action);
+ }
+
+ private void addAction(String entryText, Runnable action) {
+ var entry = new MenuItem(entryText);
entry.getStyleClass().addLast("dropdown-button-context-menu-item");
entry.setOnAction(_ -> action.run());
eventActionsMenu.getItems().addLast(entry);
@@ -234,18 +256,14 @@ public class EventListCellController implements FxController {
}
}
- private Path convertVaultPathToSystemPath(Path p) {
- if (!(p instanceof CryptoPath)) {
- throw new IllegalArgumentException("Path " + p + " is not a vault path");
- }
+ private Path convertVaultPathToSystemPath(String vaultInternalPath) {
var v = eventEntry.getValue().getKey().vault();
if (!v.isUnlocked()) {
return Path.of(System.getProperty("user.home"));
}
var mountUri = v.getMountPoint().uri();
- var internalPath = p.toString().substring(1);
- return Path.of(mountUri.getPath().concat(internalPath).substring(1));
+ return Path.of(mountUri.getPath().concat(vaultInternalPath.substring(1)).substring(1));
}
private void reveal(RevealPathService s, Path p) {
diff --git a/src/main/java/org/cryptomator/ui/health/HealthCheckModule.java b/src/main/java/org/cryptomator/ui/health/HealthCheckModule.java
index c36f486e0..19595e0e9 100644
--- a/src/main/java/org/cryptomator/ui/health/HealthCheckModule.java
+++ b/src/main/java/org/cryptomator/ui/health/HealthCheckModule.java
@@ -63,8 +63,8 @@ abstract class HealthCheckModule {
@Provides
@HealthCheckWindow
@HealthCheckScoped
- static KeyLoadingStrategy provideKeyLoadingStrategy(KeyLoadingComponent.Builder compBuilder, @HealthCheckWindow Vault vault, @Named("unlockWindow") Stage window ) {
- return compBuilder.vault(vault).window(window).build().keyloadingStrategy();
+ static KeyLoadingStrategy provideKeyLoadingStrategy(KeyLoadingComponent.Factory compFactory, @HealthCheckWindow Vault vault, @Named("unlockWindow") Stage window ) {
+ return compFactory.create(vault, window).keyloadingStrategy();
}
@Provides
diff --git a/src/main/java/org/cryptomator/ui/keyloading/KeyLoadingComponent.java b/src/main/java/org/cryptomator/ui/keyloading/KeyLoadingComponent.java
index 190bf0e1f..f035388f6 100644
--- a/src/main/java/org/cryptomator/ui/keyloading/KeyLoadingComponent.java
+++ b/src/main/java/org/cryptomator/ui/keyloading/KeyLoadingComponent.java
@@ -3,11 +3,8 @@ package org.cryptomator.ui.keyloading;
import dagger.BindsInstance;
import dagger.Subcomponent;
import org.cryptomator.common.vaults.Vault;
-import org.cryptomator.cryptolib.api.MasterkeyLoader;
import javafx.stage.Stage;
-import java.util.Map;
-import java.util.function.Supplier;
@KeyLoadingScoped
@Subcomponent(modules = {KeyLoadingModule.class})
@@ -16,16 +13,10 @@ public interface KeyLoadingComponent {
@KeyLoading
KeyLoadingStrategy keyloadingStrategy();
- @Subcomponent.Builder
- interface Builder {
+ @Subcomponent.Factory
+ interface Factory {
- @BindsInstance
- Builder vault(@KeyLoading Vault vault);
-
- @BindsInstance
- Builder window(@KeyLoading Stage window);
-
- KeyLoadingComponent build();
+ KeyLoadingComponent create(@BindsInstance @KeyLoading Vault vault, @KeyLoading @BindsInstance Stage window);
}
}
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 f8710b8c0..97ab2b394 100644
--- a/src/main/java/org/cryptomator/ui/keyloading/hub/HubKeyLoadingModule.java
+++ b/src/main/java/org/cryptomator/ui/keyloading/hub/HubKeyLoadingModule.java
@@ -66,6 +66,13 @@ public abstract class HubKeyLoadingModule {
return new AtomicReference<>();
}
+ @Provides
+ @Named("userName")
+ @KeyLoadingScoped
+ static AtomicReference provideUserNameRef() {
+ return new AtomicReference<>();
+ }
+
@Provides
@KeyLoadingScoped
static CompletableFuture provideResult() {
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 40f845a63..6bf4c0bff 100644
--- a/src/main/java/org/cryptomator/ui/keyloading/hub/HubKeyLoadingStrategy.java
+++ b/src/main/java/org/cryptomator/ui/keyloading/hub/HubKeyLoadingStrategy.java
@@ -2,6 +2,7 @@ package org.cryptomator.ui.keyloading.hub;
import com.google.common.base.Preconditions;
import dagger.Lazy;
+import org.cryptomator.common.FilsystemOwnerSupplier;
import org.cryptomator.common.keychain.KeychainManager;
import org.cryptomator.common.keychain.NoKeychainAccessProviderException;
import org.cryptomator.common.settings.DeviceKey;
@@ -23,25 +24,28 @@ import java.net.URI;
import java.util.concurrent.CancellationException;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
+import java.util.concurrent.atomic.AtomicReference;
@KeyLoading
-public class HubKeyLoadingStrategy implements KeyLoadingStrategy {
+public class HubKeyLoadingStrategy implements KeyLoadingStrategy, FilsystemOwnerSupplier {
- private static final String SCHEME_PREFIX = "hub+";
+ public static final String SCHEME_PREFIX = "hub+";
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;
+ private final AtomicReference userName;
private final Lazy authFlowScene;
private final Lazy noKeychainScene;
private final CompletableFuture result;
private final DeviceKey deviceKey;
@Inject
- public HubKeyLoadingStrategy(@KeyLoading Stage window, @FxmlScene(FxmlFile.HUB_AUTH_FLOW) Lazy authFlowScene, @FxmlScene(FxmlFile.HUB_NO_KEYCHAIN) Lazy noKeychainScene, CompletableFuture result, DeviceKey deviceKey, KeychainManager keychainManager, @Named("windowTitle") String windowTitle) {
+ public HubKeyLoadingStrategy(@KeyLoading Stage window, @FxmlScene(FxmlFile.HUB_AUTH_FLOW) Lazy authFlowScene, @FxmlScene(FxmlFile.HUB_NO_KEYCHAIN) Lazy noKeychainScene, CompletableFuture result, DeviceKey deviceKey, KeychainManager keychainManager, @Named("windowTitle") String windowTitle, @Named("userName") AtomicReference userName) {
this.window = window;
this.keychainManager = keychainManager;
+ this.userName = userName;
window.setTitle(windowTitle);
window.setOnCloseRequest(_ -> result.cancel(true));
this.authFlowScene = authFlowScene;
@@ -90,4 +94,13 @@ public class HubKeyLoadingStrategy implements KeyLoadingStrategy {
});
}
+ @Override
+ public String getOwner() {
+ var name = userName.get();
+ if (name == null) {
+ throw new IllegalStateException("Owner is not yet determined");
+ }
+ return name;
+ }
+
}
diff --git a/src/main/java/org/cryptomator/ui/keyloading/hub/ReceiveKeyController.java b/src/main/java/org/cryptomator/ui/keyloading/hub/ReceiveKeyController.java
index f94d882fa..dd6ae3b68 100644
--- a/src/main/java/org/cryptomator/ui/keyloading/hub/ReceiveKeyController.java
+++ b/src/main/java/org/cryptomator/ui/keyloading/hub/ReceiveKeyController.java
@@ -41,7 +41,6 @@ import java.util.concurrent.atomic.AtomicReference;
public class ReceiveKeyController implements FxController {
private static final Logger LOG = LoggerFactory.getLogger(ReceiveKeyController.class);
- private static final String SCHEME_PREFIX = "hub+";
private static final ObjectMapper JSON = new ObjectMapper().setDefaultLeniency(true);
private static final Duration REQ_TIMEOUT = Duration.ofSeconds(10);
@@ -50,6 +49,7 @@ public class ReceiveKeyController implements FxController {
private final String vaultId;
private final String deviceId;
private final String bearerToken;
+ private final AtomicReference userName;
private final CompletableFuture result;
private final Lazy registerDeviceScene;
private final Lazy legacyRegisterDeviceScene;
@@ -59,12 +59,25 @@ public class ReceiveKeyController implements FxController {
private final HttpClient httpClient;
@Inject
- public ReceiveKeyController(@KeyLoading Vault vault, ExecutorService executor, @KeyLoading Stage window, HubConfig hubConfig, @Named("deviceId") String deviceId, @Named("bearerToken") AtomicReference tokenRef, CompletableFuture result, @FxmlScene(FxmlFile.HUB_REGISTER_DEVICE) Lazy registerDeviceScene, @FxmlScene(FxmlFile.HUB_LEGACY_REGISTER_DEVICE) Lazy legacyRegisterDeviceScene, @FxmlScene(FxmlFile.HUB_UNAUTHORIZED_DEVICE) Lazy unauthorizedScene, @FxmlScene(FxmlFile.HUB_REQUIRE_ACCOUNT_INIT) Lazy accountInitializationScene, @FxmlScene(FxmlFile.HUB_INVALID_LICENSE) Lazy invalidLicenseScene) {
+ public ReceiveKeyController(@KeyLoading Vault vault, //
+ ExecutorService executor, //
+ @KeyLoading Stage window, //
+ HubConfig hubConfig, //
+ @Named("deviceId") String deviceId, //
+ @Named("bearerToken") AtomicReference tokenRef, //
+ @Named("userName") AtomicReference userName, //
+ CompletableFuture result, //
+ @FxmlScene(FxmlFile.HUB_REGISTER_DEVICE) Lazy registerDeviceScene, //
+ @FxmlScene(FxmlFile.HUB_LEGACY_REGISTER_DEVICE) Lazy legacyRegisterDeviceScene, //
+ @FxmlScene(FxmlFile.HUB_UNAUTHORIZED_DEVICE) Lazy unauthorizedScene, //
+ @FxmlScene(FxmlFile.HUB_REQUIRE_ACCOUNT_INIT) Lazy accountInitializationScene, //
+ @FxmlScene(FxmlFile.HUB_INVALID_LICENSE) Lazy invalidLicenseScene) {
this.window = window;
this.hubConfig = hubConfig;
this.vaultId = extractVaultId(vault.getVaultConfigCache().getUnchecked().getKeyId()); // TODO: access vault config's JTI directly (requires changes in cryptofs)
this.deviceId = deviceId;
this.bearerToken = Objects.requireNonNull(tokenRef.get());
+ this.userName = userName;
this.result = result;
this.registerDeviceScene = registerDeviceScene;
this.legacyRegisterDeviceScene = legacyRegisterDeviceScene;
@@ -81,7 +94,34 @@ public class ReceiveKeyController implements FxController {
}
public void receiveKey() {
- requestApiConfig();
+ requestUserData();
+ }
+
+ private void requestUserData() {
+ var userUri = hubConfig.URIs.API.resolve("users/me?withDevices=false");
+ var request = HttpRequest.newBuilder(userUri) //
+ .header("Authorization", "Bearer " + bearerToken) //
+ .GET() //
+ .timeout(REQ_TIMEOUT) //
+ .build();
+ httpClient.sendAsync(request, HttpResponse.BodyHandlers.ofString(StandardCharsets.UTF_8)) //
+ .thenAcceptAsync(this::receivedUserData) //
+ .exceptionally(this::retrievalFailed);
+ }
+
+ private void receivedUserData(HttpResponse response) {
+ LOG.debug("GET {} -> Status Code {}", response.request().uri(), response.statusCode());
+ try {
+ if (response.statusCode() == 200) {
+ var user = JSON.reader().readValue(response.body(), UserDto.class);
+ userName.set(user.name);
+ requestApiConfig();
+ } else {
+ throw new IllegalStateException("Unexpected response " + response.statusCode());
+ }
+ } catch (IOException e) {
+ throw new UncheckedIOException(e);
+ }
}
/**
@@ -289,11 +329,14 @@ public class ReceiveKeyController implements FxController {
}
private static String extractVaultId(URI vaultKeyUri) {
- assert vaultKeyUri.getScheme().startsWith(SCHEME_PREFIX);
+ assert vaultKeyUri.getScheme().startsWith(HubKeyLoadingStrategy.SCHEME_PREFIX);
var path = vaultKeyUri.getPath();
return path.substring(path.lastIndexOf('/') + 1);
}
+ @JsonIgnoreProperties(ignoreUnknown = true)
+ private record UserDto(@JsonProperty(value = "name", required = true) String name) {}
+
@JsonIgnoreProperties(ignoreUnknown = true)
private record DeviceDto(@JsonProperty(value = "userPrivateKey", required = true) String userPrivateKey) {}
diff --git a/src/main/java/org/cryptomator/ui/unlock/UnlockModule.java b/src/main/java/org/cryptomator/ui/unlock/UnlockModule.java
index 1c8d758fc..50240c685 100644
--- a/src/main/java/org/cryptomator/ui/unlock/UnlockModule.java
+++ b/src/main/java/org/cryptomator/ui/unlock/UnlockModule.java
@@ -57,8 +57,8 @@ abstract class UnlockModule {
@Provides
@UnlockWindow
@UnlockScoped
- static KeyLoadingStrategy provideKeyLoadingStrategy(KeyLoadingComponent.Builder compBuilder, @UnlockWindow Vault vault, @UnlockWindow Stage window) {
- return compBuilder.vault(vault).window(window).build().keyloadingStrategy();
+ static KeyLoadingStrategy provideKeyLoadingStrategy(KeyLoadingComponent.Factory compFactory, @UnlockWindow Vault vault, @UnlockWindow Stage window) {
+ return compFactory.create(vault, window).keyloadingStrategy();
}
@Provides
diff --git a/src/main/resources/fxml/addvault_new_expert_settings.fxml b/src/main/resources/fxml/addvault_new_expert_settings.fxml
index 202f7c4d7..220444f71 100644
--- a/src/main/resources/fxml/addvault_new_expert_settings.fxml
+++ b/src/main/resources/fxml/addvault_new_expert_settings.fxml
@@ -39,9 +39,9 @@
-
+
-
+
diff --git a/src/main/resources/fxml/changepassword.fxml b/src/main/resources/fxml/changepassword.fxml
index eaab7b06a..5a4d60813 100644
--- a/src/main/resources/fxml/changepassword.fxml
+++ b/src/main/resources/fxml/changepassword.fxml
@@ -19,7 +19,7 @@
-
+
diff --git a/src/main/resources/fxml/decryptnames.fxml b/src/main/resources/fxml/decryptnames.fxml
index 04e16b8e1..50fbf68e1 100644
--- a/src/main/resources/fxml/decryptnames.fxml
+++ b/src/main/resources/fxml/decryptnames.fxml
@@ -22,7 +22,7 @@
-
-
+
diff --git a/src/main/resources/fxml/eventview.fxml b/src/main/resources/fxml/eventview.fxml
index 3aeb17281..990f81ed4 100644
--- a/src/main/resources/fxml/eventview.fxml
+++ b/src/main/resources/fxml/eventview.fxml
@@ -20,9 +20,9 @@
-
+
-
+
diff --git a/src/main/resources/fxml/eventview_cell.fxml b/src/main/resources/fxml/eventview_cell.fxml
index dc8a679f7..653d22316 100644
--- a/src/main/resources/fxml/eventview_cell.fxml
+++ b/src/main/resources/fxml/eventview_cell.fxml
@@ -5,6 +5,7 @@
+
-
+
+
+
+
diff --git a/src/main/resources/fxml/health_check_details.fxml b/src/main/resources/fxml/health_check_details.fxml
index ac12a09c1..fce0ecaa1 100644
--- a/src/main/resources/fxml/health_check_details.fxml
+++ b/src/main/resources/fxml/health_check_details.fxml
@@ -47,8 +47,8 @@
-
-
+
+
diff --git a/src/main/resources/fxml/health_check_listcell.fxml b/src/main/resources/fxml/health_check_listcell.fxml
index df000fa44..f37e05a67 100644
--- a/src/main/resources/fxml/health_check_listcell.fxml
+++ b/src/main/resources/fxml/health_check_listcell.fxml
@@ -21,6 +21,6 @@
-
+
diff --git a/src/main/resources/fxml/migration_run.fxml b/src/main/resources/fxml/migration_run.fxml
index f154c4a88..9496d42cc 100644
--- a/src/main/resources/fxml/migration_run.fxml
+++ b/src/main/resources/fxml/migration_run.fxml
@@ -21,7 +21,7 @@
-
+
diff --git a/src/main/resources/fxml/preferences_about.fxml b/src/main/resources/fxml/preferences_about.fxml
index 52c620f21..b3142e301 100644
--- a/src/main/resources/fxml/preferences_about.fxml
+++ b/src/main/resources/fxml/preferences_about.fxml
@@ -26,6 +26,6 @@
-
+
diff --git a/src/main/resources/fxml/preferences_contribute.fxml b/src/main/resources/fxml/preferences_contribute.fxml
index a6a52bf4e..a9ff2f36a 100644
--- a/src/main/resources/fxml/preferences_contribute.fxml
+++ b/src/main/resources/fxml/preferences_contribute.fxml
@@ -7,6 +7,7 @@
+
@@ -32,10 +33,13 @@
-
+
+
+
+
@@ -56,7 +60,7 @@
-
+
diff --git a/src/main/resources/fxml/preferences_general.fxml b/src/main/resources/fxml/preferences_general.fxml
index 3e06d9031..af3a9697a 100644
--- a/src/main/resources/fxml/preferences_general.fxml
+++ b/src/main/resources/fxml/preferences_general.fxml
@@ -27,12 +27,12 @@
-
+
-
+
diff --git a/src/main/resources/fxml/preferences_interface.fxml b/src/main/resources/fxml/preferences_interface.fxml
index 36f58ebb3..1f54f6eaa 100644
--- a/src/main/resources/fxml/preferences_interface.fxml
+++ b/src/main/resources/fxml/preferences_interface.fxml
@@ -21,13 +21,13 @@
-
+
-
+
diff --git a/src/main/resources/fxml/preferences_volume.fxml b/src/main/resources/fxml/preferences_volume.fxml
index c173f03e2..670195358 100644
--- a/src/main/resources/fxml/preferences_volume.fxml
+++ b/src/main/resources/fxml/preferences_volume.fxml
@@ -20,9 +20,9 @@
-
+
-
+
@@ -33,7 +33,7 @@
-
+
diff --git a/src/main/resources/fxml/recoverykey_create.fxml b/src/main/resources/fxml/recoverykey_create.fxml
index 2d9f0f418..e74074f1d 100644
--- a/src/main/resources/fxml/recoverykey_create.fxml
+++ b/src/main/resources/fxml/recoverykey_create.fxml
@@ -40,7 +40,7 @@
-
+
diff --git a/src/main/resources/fxml/recoverykey_display.fxml b/src/main/resources/fxml/recoverykey_display.fxml
index 8b414d810..0d25af99c 100644
--- a/src/main/resources/fxml/recoverykey_display.fxml
+++ b/src/main/resources/fxml/recoverykey_display.fxml
@@ -16,7 +16,7 @@
spacing="12"
alignment="TOP_LEFT">
-
+
diff --git a/src/main/resources/fxml/recoverykey_expert_settings.fxml b/src/main/resources/fxml/recoverykey_expert_settings.fxml
index cceac8388..4204d032c 100644
--- a/src/main/resources/fxml/recoverykey_expert_settings.fxml
+++ b/src/main/resources/fxml/recoverykey_expert_settings.fxml
@@ -48,7 +48,7 @@
-
+
@@ -57,7 +57,7 @@
-
+
diff --git a/src/main/resources/fxml/recoverykey_validate.fxml b/src/main/resources/fxml/recoverykey_validate.fxml
index b1420a899..cd599db40 100644
--- a/src/main/resources/fxml/recoverykey_validate.fxml
+++ b/src/main/resources/fxml/recoverykey_validate.fxml
@@ -12,7 +12,7 @@
minHeight="145"
spacing="12">
-
+
diff --git a/src/main/resources/fxml/share_vault.fxml b/src/main/resources/fxml/share_vault.fxml
index fc74079d2..b5466a10d 100644
--- a/src/main/resources/fxml/share_vault.fxml
+++ b/src/main/resources/fxml/share_vault.fxml
@@ -68,7 +68,7 @@
-
+
diff --git a/src/main/resources/fxml/unlock_enter_password.fxml b/src/main/resources/fxml/unlock_enter_password.fxml
index 4d0c4ade8..5242826a2 100644
--- a/src/main/resources/fxml/unlock_enter_password.fxml
+++ b/src/main/resources/fxml/unlock_enter_password.fxml
@@ -46,7 +46,7 @@
-
+
diff --git a/src/main/resources/fxml/vault_detail_unlocked.fxml b/src/main/resources/fxml/vault_detail_unlocked.fxml
index 289814347..943fc6e03 100644
--- a/src/main/resources/fxml/vault_detail_unlocked.fxml
+++ b/src/main/resources/fxml/vault_detail_unlocked.fxml
@@ -15,7 +15,7 @@
alignment="TOP_CENTER"
spacing="9">
-
+
@@ -25,8 +25,11 @@
+
+
+
-
+
@@ -36,6 +39,9 @@
+
+
+
diff --git a/src/main/resources/fxml/vault_list.fxml b/src/main/resources/fxml/vault_list.fxml
index e21237a43..a05d834a3 100644
--- a/src/main/resources/fxml/vault_list.fxml
+++ b/src/main/resources/fxml/vault_list.fxml
@@ -38,14 +38,17 @@
-
+
+
+
+
-
+
@@ -57,10 +60,13 @@
-
+
+
+
+
diff --git a/src/main/resources/fxml/vault_options_general.fxml b/src/main/resources/fxml/vault_options_general.fxml
index fcdac6d53..98a300e63 100644
--- a/src/main/resources/fxml/vault_options_general.fxml
+++ b/src/main/resources/fxml/vault_options_general.fxml
@@ -22,14 +22,14 @@
-
+
-
+
@@ -37,7 +37,7 @@
-
+
diff --git a/src/main/resources/fxml/vault_options_mount.fxml b/src/main/resources/fxml/vault_options_mount.fxml
index 4f6295af8..fd65536cc 100644
--- a/src/main/resources/fxml/vault_options_mount.fxml
+++ b/src/main/resources/fxml/vault_options_mount.fxml
@@ -26,9 +26,9 @@
-
+
-
+
@@ -36,7 +36,7 @@
-
+
@@ -49,7 +49,7 @@
-
+
@@ -58,7 +58,7 @@
-
+
@@ -75,7 +75,7 @@
-
+
@@ -87,7 +87,7 @@
-
+
diff --git a/src/main/resources/i18n/strings.properties b/src/main/resources/i18n/strings.properties
index 10e39debf..ac631abe2 100644
--- a/src/main/resources/i18n/strings.properties
+++ b/src/main/resources/i18n/strings.properties
@@ -259,6 +259,8 @@ health.check.detail.checkFinishedAndFound=The check finished running. Please rev
health.check.detail.checkFailed=The check exited due to an error.
health.check.detail.checkCancelled=The check was cancelled.
health.check.detail.listFilters.label=Filter
+health.check.detail.filterSeverity=Filter by severity
+health.check.detail.filterFixState=Filter by fix state
health.check.detail.fixAllSpecificBtn=Fix all of type
health.check.exportBtn=Export Report
## Result view
@@ -348,6 +350,7 @@ preferences.contribute.promptText=Paste supporter certificate code here
preferences.contribute.thankYou=Thank you for supporting Cryptomator's open-source development!
preferences.contribute.donate=Donate
preferences.contribute.sponsor=Sponsor
+preferences.contribute.removeCert.tooltip=Remove certificate
### Remove License Key Dialog
removeCert.title=Remove Certificate
@@ -357,6 +360,7 @@ removeCert.description=Cryptomator's core features are not affected by this. Nei
## About
preferences.about=About
+preferences.about.thirdPartyLicenses=Third-party licenses
# Vault Statistics
stats.title=Statistics for %s
@@ -406,7 +410,9 @@ main.vaultlist.contextMenu.share=Share…
main.vaultlist.addVaultBtn.menuItemNew=Create New Vault…
main.vaultlist.addVaultBtn.menuItemExisting=Open Existing Vault…
main.vaultlist.addVaultBtn.menuItemRecover=Recover Existing Vault…
-main.vaultlist.showEventsButton.tooltip=Open event view
+main.vaultlist.addVaultButton.tooltip=Add Vault
+main.vaultlist.showEventsButton.tooltip=Open Event View
+main.vaultlist.showPreferencesButton.tooltip=Show Preferences
##Notificaition
main.notification.updateAvailable=Update is available.
main.notification.support=Support Cryptomator.
@@ -470,6 +476,7 @@ vaultOptions.general=General
vaultOptions.general.vaultName=Vault Name
vaultOptions.general.autoLock.lockAfterTimePart1=Lock when idle for
vaultOptions.general.autoLock.lockAfterTimePart2=minutes
+vaultOptions.general.autoLock.accessibleText=Lock timeout in minutes
vaultOptions.general.unlockAfterStartup=Unlock vault when starting Cryptomator
vaultOptions.general.actionAfterUnlock=After successful unlock
vaultOptions.general.actionAfterUnlock.ignore=Do nothing
@@ -653,6 +660,8 @@ decryptNames.filePicker.title=Select encrypted file
decryptNames.filePicker.extensionDescription=Cryptomator encrypted file
decryptNames.copyTable.tooltip=Copy table
decryptNames.clearTable.tooltip=Clear table
+decryptNames.column.encrypted=Encrypted
+decryptNames.column.decrypted=Decrypted
decryptNames.copyHint=Copy cell content with %s
decryptNames.dropZone.message=Drop files or click to select
decryptNames.dropZone.error.vaultInternalFiles=Vault internal files with no decrypt-able name selected
@@ -665,6 +674,8 @@ decryptNames.dropZone.error.generic=Failed to decrypt file names
eventView.title=Events
eventView.filter.allVaults=All
eventView.clearListButton.tooltip=Clear list
+eventView.filterVaults=Filter by vault
+eventView.cell.actionsButton.tooltip=Event actions
## event list entries
eventView.entry.vaultLocked.description=Unlock "%s" for details
eventView.entry.conflictResolved.message=Resolved conflict