mirror of
https://github.com/cryptomator/cryptomator.git
synced 2026-05-14 08:41:28 +00:00
prevent updates while having unlocked vaults
This commit is contained in:
@@ -104,13 +104,6 @@ public class UpdateChecker extends ScheduledService<UpdateInfo<?>> {
|
||||
return new UpdateCheckTask();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void failed() {
|
||||
super.failed();
|
||||
LOG.error("Update check failed.", getException());
|
||||
}
|
||||
|
||||
|
||||
/* Observable Properties */
|
||||
|
||||
public String getLatestVersion() {
|
||||
@@ -165,13 +158,25 @@ public class UpdateChecker extends ScheduledService<UpdateInfo<?>> {
|
||||
private class UpdateCheckTask extends Task<UpdateInfo<?>> {
|
||||
|
||||
@Override
|
||||
protected UpdateInfo<?> call() throws UpdateFailedException {
|
||||
var result = primaryUpdateMechanism.checkForUpdate(env.getAppVersion(), httpClient);
|
||||
if (result == null && primaryUpdateMechanism != fallbackUpdateMechanism) {
|
||||
LOG.debug("Primary update mechanism did not find an update. Try fallback update mechanism...");
|
||||
result = fallbackUpdateMechanism.checkForUpdate(env.getAppVersion(), httpClient);
|
||||
protected UpdateInfo<?> call() {
|
||||
try {
|
||||
var result = primaryUpdateMechanism.checkForUpdate(env.getAppVersion(), httpClient);
|
||||
if (result != null) {
|
||||
return result;
|
||||
}
|
||||
} catch (UpdateFailedException e) {
|
||||
LOG.error("Primary update check failed.", e);
|
||||
}
|
||||
if (primaryUpdateMechanism == fallbackUpdateMechanism) {
|
||||
return null;
|
||||
}
|
||||
LOG.debug("Trying fallback update check...");
|
||||
try {
|
||||
return fallbackUpdateMechanism.checkForUpdate(env.getAppVersion(), httpClient);
|
||||
} catch (UpdateFailedException e) {
|
||||
LOG.error("Fallback update check failed.", e);
|
||||
return null;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2,9 +2,12 @@ package org.cryptomator.ui.preferences;
|
||||
|
||||
import org.cryptomator.common.Environment;
|
||||
import org.cryptomator.common.settings.Settings;
|
||||
import org.cryptomator.common.vaults.Vault;
|
||||
import org.cryptomator.integrations.update.UpdateStep;
|
||||
import org.cryptomator.ui.common.FxController;
|
||||
import org.cryptomator.ui.common.VaultService;
|
||||
import org.cryptomator.ui.fxapp.UpdateChecker;
|
||||
import org.cryptomator.updater.FallbackUpdateInfo;
|
||||
import org.cryptomator.updater.UpdateService;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
@@ -14,12 +17,14 @@ import javafx.animation.PauseTransition;
|
||||
import javafx.application.Application;
|
||||
import javafx.application.Platform;
|
||||
import javafx.beans.binding.Bindings;
|
||||
import javafx.beans.binding.BooleanBinding;
|
||||
import javafx.beans.binding.BooleanExpression;
|
||||
import javafx.beans.binding.ObjectBinding;
|
||||
import javafx.beans.binding.StringBinding;
|
||||
import javafx.beans.property.BooleanProperty;
|
||||
import javafx.beans.property.SimpleBooleanProperty;
|
||||
import javafx.beans.value.ObservableValue;
|
||||
import javafx.collections.ObservableList;
|
||||
import javafx.concurrent.Worker;
|
||||
import javafx.concurrent.WorkerStateEvent;
|
||||
import javafx.fxml.FXML;
|
||||
@@ -47,31 +52,40 @@ public class UpdatesPreferencesController implements FxController {
|
||||
private final Settings settings;
|
||||
private final UpdateChecker updateChecker;
|
||||
private final UpdateService updateService;
|
||||
private final ObservableList<Vault> unlockedVaults;
|
||||
private final VaultService vaultService;
|
||||
private final ObjectBinding<Worker<?>> worker;
|
||||
private final BooleanExpression running;
|
||||
private final StringBinding updateButtonTitle;
|
||||
private final ObjectBinding<ContentDisplay> updateButtonState;
|
||||
private final ObservableValue<String> timeDifferenceMessage;
|
||||
private final StringBinding lastUpdateCheckMessage;
|
||||
|
||||
private final BooleanBinding prohibitUpdateWhileUnlocked;
|
||||
private final BooleanBinding updateButtonDisabled;
|
||||
private final BooleanProperty upToDateLabelVisible = new SimpleBooleanProperty(false);
|
||||
|
||||
/* FXML */
|
||||
public CheckBox checkForUpdatesCheckbox;
|
||||
|
||||
@Inject
|
||||
UpdatesPreferencesController(Application application, Environment environment, ResourceBundle resourceBundle, Settings settings, UpdateChecker updateChecker) {
|
||||
UpdatesPreferencesController(Application application, Environment environment, ResourceBundle resourceBundle, Settings settings, UpdateChecker updateChecker, ObservableList<Vault> vaults, VaultService vaultService) {
|
||||
this.application = application;
|
||||
this.environment = environment;
|
||||
this.resourceBundle = resourceBundle;
|
||||
this.settings = settings;
|
||||
this.updateChecker = updateChecker;
|
||||
this.updateService = new UpdateService(updateChecker.lastValueProperty());
|
||||
this.vaultService = vaultService;
|
||||
this.worker = Bindings.when(updateChecker.updateAvailableProperty()).<Worker<?>>then(this.updateService).otherwise(this.updateChecker);
|
||||
this.running = Bindings.createBooleanBinding(this::isRunning, updateService.stateProperty(), updateChecker.stateProperty());
|
||||
this.updateButtonTitle = Bindings.createStringBinding(this::getUpdateButtonTitle, worker, updateService.stateProperty(), updateService.messageProperty());
|
||||
this.updateButtonState = Bindings.createObjectBinding(this::getUpdateButtonState, updateChecker.stateProperty(), updateService.stateProperty());
|
||||
this.timeDifferenceMessage = Bindings.createStringBinding(this::getTimeDifferenceMessage, updateChecker.lastSuccessfulUpdateCheckProperty());
|
||||
this.lastUpdateCheckMessage = Bindings.createStringBinding(this::getLastUpdateCheckMessage, updateChecker.lastSuccessfulUpdateCheckProperty());
|
||||
this.unlockedVaults = vaults.filtered(Vault::isUnlocked);
|
||||
this.prohibitUpdateWhileUnlocked = Bindings.createBooleanBinding(this::isProhibitUpdateWhileUnlocked, unlockedVaults, updateChecker.lastValueProperty());
|
||||
this.updateButtonDisabled = Bindings.when(worker.isEqualTo(updateChecker)).then(running).otherwise(prohibitUpdateWhileUnlocked.or(running));
|
||||
}
|
||||
|
||||
public void initialize() {
|
||||
@@ -97,8 +111,10 @@ public class UpdatesPreferencesController implements FxController {
|
||||
public void startWork() {
|
||||
if (worker.get().equals(updateChecker)) {
|
||||
updateChecker.checkForUpdatesNow();
|
||||
} else if (!unlockedVaults.isEmpty()) {
|
||||
LOG.warn("Cannot start update due to unlocked vaults.");
|
||||
} else if (worker.get().equals(updateService)) {
|
||||
// TODO: only allow starting if all vaults are locked; show info label beneath button otherwise
|
||||
LOG.info("User started update to version {}", updateChecker.getLastValue().version());
|
||||
updateService.start();
|
||||
}
|
||||
}
|
||||
@@ -122,9 +138,15 @@ public class UpdatesPreferencesController implements FxController {
|
||||
private void updateFailed(WorkerStateEvent workerStateEvent) {
|
||||
assert workerStateEvent.getSource() == updateService;
|
||||
LOG.error("Update failed.", updateService.getException());
|
||||
// TODO: show error to user? use fallback update service?
|
||||
updateService.reset();
|
||||
}
|
||||
|
||||
@FXML
|
||||
public void lockAllGracefully() {
|
||||
vaultService.lockAll(unlockedVaults, false);
|
||||
}
|
||||
|
||||
/* Observable Properties */
|
||||
|
||||
public UpdateChecker getUpdateChecker() {
|
||||
@@ -197,7 +219,6 @@ public class UpdatesPreferencesController implements FxController {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public StringBinding lastUpdateCheckMessageProperty() {
|
||||
return lastUpdateCheckMessage;
|
||||
}
|
||||
@@ -211,6 +232,23 @@ public class UpdatesPreferencesController implements FxController {
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isProhibitUpdateWhileUnlocked() {
|
||||
// If the result of the last update check was from the fallback mechanism, we don't need to show the warning
|
||||
return !unlockedVaults.isEmpty() && !FallbackUpdateInfo.class.isInstance(updateChecker.getLastValue());
|
||||
}
|
||||
|
||||
public BooleanBinding prohibitUpdateWhileUnlockedProperty() {
|
||||
return prohibitUpdateWhileUnlocked;
|
||||
}
|
||||
|
||||
public boolean isUpdateButtonDisabled() {
|
||||
return updateButtonDisabled.get();
|
||||
}
|
||||
|
||||
public BooleanBinding updateButtonDisabledProperty() {
|
||||
return updateButtonDisabled;
|
||||
}
|
||||
|
||||
public BooleanProperty upToDateLabelVisibleProperty() {
|
||||
return upToDateLabelVisible;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
package org.cryptomator.updater;
|
||||
|
||||
import org.cryptomator.integrations.update.UpdateInfo;
|
||||
import org.cryptomator.integrations.update.UpdateMechanism;
|
||||
|
||||
public record FallbackUpdateInfo(String version, UpdateMechanism<FallbackUpdateInfo> updateMechanism) implements UpdateInfo<FallbackUpdateInfo> {}
|
||||
@@ -33,7 +33,7 @@ import java.util.concurrent.TimeUnit;
|
||||
@FxApplicationScoped
|
||||
@Priority(Priority.FALLBACK)
|
||||
@DisplayName("Show Download Page") // TODO localize
|
||||
public class FallbackUpdateMechanism implements UpdateMechanism<BasicUpdateInfo> {
|
||||
public class FallbackUpdateMechanism implements UpdateMechanism<FallbackUpdateInfo> {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(FallbackUpdateMechanism.class);
|
||||
private static final String LATEST_VERSION_API_URL = "https://api.cryptomator.org/connect/apps/desktop/latest-version";
|
||||
@@ -53,7 +53,7 @@ public class FallbackUpdateMechanism implements UpdateMechanism<BasicUpdateInfo>
|
||||
}
|
||||
|
||||
@Override
|
||||
public BasicUpdateInfo checkForUpdate(String currentVersion, HttpClient httpClient) {
|
||||
public FallbackUpdateInfo checkForUpdate(String currentVersion, HttpClient httpClient) {
|
||||
try {
|
||||
HttpRequest request = HttpRequest.newBuilder().uri(URI.create(LATEST_VERSION_API_URL)).build();
|
||||
HttpResponse<InputStream> response = httpClient.send(request, HttpResponse.BodyHandlers.ofInputStream());
|
||||
@@ -63,7 +63,7 @@ public class FallbackUpdateMechanism implements UpdateMechanism<BasicUpdateInfo>
|
||||
var release = MAPPER.readValue(response.body(), LatestVersion.class);
|
||||
var updateVersion = release.versionForCurrentOS();
|
||||
if (UpdateMechanism.isUpdateAvailable(updateVersion, currentVersion)) {
|
||||
return new BasicUpdateInfo(updateVersion, this);
|
||||
return new FallbackUpdateInfo(updateVersion, this);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
@@ -78,7 +78,7 @@ public class FallbackUpdateMechanism implements UpdateMechanism<BasicUpdateInfo>
|
||||
}
|
||||
|
||||
@Override
|
||||
public UpdateStep firstStep(BasicUpdateInfo updateInfo) {
|
||||
public UpdateStep firstStep(FallbackUpdateInfo updateInfo) {
|
||||
return UpdateStep.of("Go to download page", this::openDownloadPage); // TODO localize
|
||||
}
|
||||
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
<VBox alignment="CENTER" spacing="12">
|
||||
<FormattedLabel format="%preferences.updates.updateAvailable" arg1="${controller.updateChecker.latestVersion}" textAlignment="CENTER" wrapText="true" visible="${controller.updateChecker.updateAvailable}"/>
|
||||
|
||||
<Button text="${controller.updateButtonTitle}" defaultButton="true" onAction="#startWork" disable="${controller.running}" contentDisplay="${controller.updateButtonState}">
|
||||
<Button text="${controller.updateButtonTitle}" defaultButton="true" onAction="#startWork" disable="${controller.updateButtonDisabled}" contentDisplay="${controller.updateButtonState}">
|
||||
<graphic>
|
||||
<VBox spacing="5" alignment="CENTER">
|
||||
<ProgressBar maxWidth="200"
|
||||
@@ -42,6 +42,16 @@
|
||||
</graphic>
|
||||
</Button>
|
||||
|
||||
<TextFlow styleClass="text-flow" textAlignment="CENTER" visible="${controller.prohibitUpdateWhileUnlocked}" managed="${controller.prohibitUpdateWhileUnlocked}">
|
||||
<FontAwesome5IconView glyphSize="12" styleClass="glyph-icon-primary" glyph="LOCK_OPEN"/>
|
||||
<Text text=" "/>
|
||||
<Text text="%preferences.updates.prohibitedDueToUnlockedVaults.1"/>
|
||||
<Text text=" "/>
|
||||
<Hyperlink styleClass="hyperlink-underline" text="%preferences.updates.prohibitedDueToUnlockedVaults.2" onAction="#lockAllGracefully"/>
|
||||
<Text text=" "/>
|
||||
<Text text="%preferences.updates.prohibitedDueToUnlockedVaults.3"/>
|
||||
</TextFlow>
|
||||
|
||||
<TextFlow styleClass="text-flow" textAlignment="CENTER" visible="${controller.updateChecker.checkFailed}" managed="${controller.updateChecker.checkFailed}">
|
||||
<FontAwesome5IconView glyphSize="12" styleClass="glyph-icon-orange" glyph="EXCLAMATION_TRIANGLE"/>
|
||||
<Text text=" "/>
|
||||
@@ -49,7 +59,7 @@
|
||||
<Text text=" "/>
|
||||
<Hyperlink styleClass="hyperlink-underline" text="%preferences.general.debugDirectory" onAction="#showLogfileDirectory"/>
|
||||
</TextFlow>
|
||||
<FormattedLabel format="%preferences.updates.lastUpdateCheck" arg1="${controller.timeDifferenceMessage}" textAlignment="CENTER" wrapText="true">
|
||||
<FormattedLabel format="%preferences.updates.lastUpdateCheck" arg1="${controller.timeDifferenceMessage}" textAlignment="CENTER" wrapText="true" visible="${!controller.updateChecker.updateAvailable}" managed="${!controller.updateChecker.updateAvailable}">
|
||||
<tooltip>
|
||||
<Tooltip text="${controller.lastUpdateCheckMessage}" showDelay="10ms"/>
|
||||
</tooltip>
|
||||
|
||||
@@ -330,6 +330,9 @@ preferences.updates.lastUpdateCheck.never=never
|
||||
preferences.updates.lastUpdateCheck.recently=recently
|
||||
preferences.updates.lastUpdateCheck.daysAgo=%s days ago
|
||||
preferences.updates.lastUpdateCheck.hoursAgo=%s hours ago
|
||||
preferences.updates.prohibitedDueToUnlockedVaults.1=Please
|
||||
preferences.updates.prohibitedDueToUnlockedVaults.2=lock your vaults
|
||||
preferences.updates.prohibitedDueToUnlockedVaults.3=to install the update.
|
||||
preferences.updates.checkFailed=Looking for updates failed. Please check your internet connection or try again later.
|
||||
preferences.updates.upToDate=Cryptomator is up-to-date.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user