Merge pull request #4081 from cryptomator/feature/hub-vault-archived-dialog

Feature: Show dedicated “Archived Vault” screen on unlock when Hub returns 410
This commit is contained in:
mindmonk
2026-01-06 11:20:29 +01:00
committed by GitHub
4 changed files with 29 additions and 3 deletions

View File

@@ -16,6 +16,7 @@ Changes to prior versions can be found on the [Github release page](https://gith
* App notifications ([#4069](https://github.com/cryptomator/cryptomator/pull/4069))
* Mark files in-use for Hub vaults ([#4078](https://github.com/cryptomator/cryptomator/pull/4078))
* Accessibility labels for GUI elements ([#4064](https://github.com/cryptomator/cryptomator/issues/4064), [#4066](https://github.com/cryptomator/cryptomator/pull/4066), [#4055](https://github.com/cryptomator/cryptomator/issues/4055))
* Show Archived Vault Dialog on unlock when Hub returns 410 ([#4081](https://github.com/cryptomator/cryptomator/pull/4081))
### Changed
* Built using JDK 25 ([#4031](https://github.com/cryptomator/cryptomator/issues/4031))

View File

@@ -61,6 +61,15 @@ public class Dialogs {
.setOkButtonKey(BUTTON_KEY_CLOSE);
}
public SimpleDialog.Builder prepareHubVaultArchived(Stage window, Vault vault) {
return createDialogBuilder().setOwner(window) //
.setTitleKey("unlock.title", vault.getDisplayName()) //
.setMessageKey("hub.archived.message") //
.setDescriptionKey("hub.archived.description") //
.setIcon(FontAwesome5Icon.BAN)//
.setOkButtonKey(BUTTON_KEY_CLOSE);
}
public SimpleDialog.Builder prepareRecoveryVaultAdded(Stage window, String displayName) {
return createDialogBuilder().setOwner(window) //
.setTitleKey("recover.existing.title") //

View File

@@ -11,6 +11,7 @@ import org.cryptomator.common.vaults.Vault;
import org.cryptomator.ui.common.FxController;
import org.cryptomator.ui.common.FxmlFile;
import org.cryptomator.ui.common.FxmlScene;
import org.cryptomator.ui.dialogs.Dialogs;
import org.cryptomator.ui.keyloading.KeyLoading;
import org.cryptomator.ui.keyloading.KeyLoadingScoped;
import org.slf4j.Logger;
@@ -58,6 +59,8 @@ public class ReceiveKeyController implements FxController {
private final Lazy<Scene> accountInitializationScene;
private final Lazy<Scene> invalidLicenseScene;
private final HttpClient httpClient;
private final Dialogs dialogs;
private final Vault vault;
@Inject
public ReceiveKeyController(@KeyLoading Vault vault, //
@@ -72,7 +75,8 @@ public class ReceiveKeyController implements FxController {
@FxmlScene(FxmlFile.HUB_LEGACY_REGISTER_DEVICE) Lazy<Scene> legacyRegisterDeviceScene, //
@FxmlScene(FxmlFile.HUB_UNAUTHORIZED_DEVICE) Lazy<Scene> unauthorizedScene, //
@FxmlScene(FxmlFile.HUB_REQUIRE_ACCOUNT_INIT) Lazy<Scene> accountInitializationScene, //
@FxmlScene(FxmlFile.HUB_INVALID_LICENSE) Lazy<Scene> invalidLicenseScene) {
@FxmlScene(FxmlFile.HUB_INVALID_LICENSE) Lazy<Scene> invalidLicenseScene, //
Dialogs dialogs) {
this.window = window;
this.hubConfig = hubConfig;
this.vaultId = extractVaultId(vault.getVaultConfigCache().getUnchecked().getKeyId()); // TODO: access vault config's JTI directly (requires changes in cryptofs)
@@ -87,6 +91,8 @@ public class ReceiveKeyController implements FxController {
this.invalidLicenseScene = invalidLicenseScene;
this.window.addEventHandler(WindowEvent.WINDOW_HIDING, this::windowClosed);
this.httpClient = HttpClient.newBuilder().version(HttpClient.Version.HTTP_1_1).executor(executor).build();
this.dialogs = dialogs;
this.vault = vault;
}
@FXML
@@ -226,7 +232,8 @@ public class ReceiveKeyController implements FxController {
switch (response.statusCode()) {
case 200 -> receivedBothEncryptedKeys(response.body(), encryptedUserKey);
case 402 -> licenseExceeded();
case 403, 410 -> accessNotGranted(); // or vault has been archived, effectively disallowing access - TODO: add specific dialog?
case 403 -> accessNotGranted();
case 410 -> accessGoneVaultArchived();
case 449 -> accountInitializationRequired();
default -> throw new IllegalStateException("Unexpected response " + response.statusCode());
}
@@ -270,7 +277,8 @@ public class ReceiveKeyController implements FxController {
switch (response.statusCode()) {
case 200 -> receivedLegacyAccessTokenSuccess(response.body());
case 402 -> licenseExceeded();
case 403, 410 -> accessNotGranted(); // or vault has been archived, effectively disallowing access
case 403 -> accessNotGranted();
case 410 -> accessGoneVaultArchived();
case 404 -> needsLegacyDeviceRegistration();
default -> throw new IOException("Unexpected response " + response.statusCode());
}
@@ -303,6 +311,11 @@ public class ReceiveKeyController implements FxController {
window.setScene(unauthorizedScene.get());
}
private void accessGoneVaultArchived() {
window.close();
dialogs.prepareHubVaultArchived((Stage)window.getOwner(), vault).build().showAndWait();
}
private void accountInitializationRequired() {
window.setScene(accountInitializationScene.get());
}

View File

@@ -179,6 +179,9 @@ hub.registerSuccess.legacy.description=To access the vault, your device needs to
hub.registerFailed.message=Device registration failed
hub.registerFailed.description.generic=An error was thrown in the registration process. For more details, look into the application log.
hub.registerFailed.description.deviceAlreadyExists=This device is already registered for a different user. Try to change the user account or use a different device.
### Archived
hub.archived.message=Vault is archived
hub.archived.description=This vault has been archived and is no longer accessible. Please contact the vault owner.
### Unauthorized
hub.unauthorized.message=Access denied
hub.unauthorized.description=You are not authorized to open this vault. Contact the vault's owner to request access.