mirror of
https://github.com/cryptomator/cryptomator.git
synced 2026-04-20 01:26:52 -04:00
Merge branch 'feature/#1289-introduceVaultname' into hotfix/1.5.8
This commit is contained in:
@@ -8,6 +8,8 @@ package org.cryptomator.common.settings;
|
||||
import com.google.common.base.Strings;
|
||||
import com.google.common.io.BaseEncoding;
|
||||
import javafx.beans.Observable;
|
||||
import javafx.beans.binding.Bindings;
|
||||
import javafx.beans.binding.StringBinding;
|
||||
import javafx.beans.property.BooleanProperty;
|
||||
import javafx.beans.property.IntegerProperty;
|
||||
import javafx.beans.property.ObjectProperty;
|
||||
@@ -17,7 +19,6 @@ import javafx.beans.property.SimpleObjectProperty;
|
||||
import javafx.beans.property.SimpleStringProperty;
|
||||
import javafx.beans.property.StringProperty;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.fxmisc.easybind.EasyBind;
|
||||
|
||||
import java.nio.file.Path;
|
||||
import java.util.Objects;
|
||||
@@ -34,7 +35,6 @@ public class VaultSettings {
|
||||
public static final boolean DEFAULT_USES_INDIVIDUAL_MOUNTPATH = false;
|
||||
public static final boolean DEFAULT_USES_READONLY_MODE = false;
|
||||
public static final String DEFAULT_MOUNT_FLAGS = "";
|
||||
public static final String DEFAULT_MOUNT_NAME = "Vault";
|
||||
public static final int DEFAULT_FILENAME_LENGTH_LIMIT = -1;
|
||||
public static final WhenUnlocked DEFAULT_ACTION_AFTER_UNLOCK = WhenUnlocked.ASK;
|
||||
|
||||
@@ -42,7 +42,7 @@ public class VaultSettings {
|
||||
|
||||
private final String id;
|
||||
private final ObjectProperty<Path> path = new SimpleObjectProperty();
|
||||
private final StringProperty mountName = new SimpleStringProperty();
|
||||
private final StringProperty displayName = new SimpleStringProperty();
|
||||
private final StringProperty winDriveLetter = new SimpleStringProperty();
|
||||
private final BooleanProperty unlockAfterStartup = new SimpleBooleanProperty(DEFAULT_UNLOCK_AFTER_STARTUP);
|
||||
private final BooleanProperty revealAfterMount = new SimpleBooleanProperty(DEFAULT_REAVEAL_AFTER_MOUNT);
|
||||
@@ -53,30 +53,15 @@ public class VaultSettings {
|
||||
private final IntegerProperty filenameLengthLimit = new SimpleIntegerProperty(DEFAULT_FILENAME_LENGTH_LIMIT);
|
||||
private final ObjectProperty<WhenUnlocked> actionAfterUnlock = new SimpleObjectProperty<>(DEFAULT_ACTION_AFTER_UNLOCK);
|
||||
|
||||
private final StringBinding mountName;
|
||||
|
||||
public VaultSettings(String id) {
|
||||
this.id = Objects.requireNonNull(id);
|
||||
|
||||
EasyBind.subscribe(path, this::deriveMountNameFromPathOrUseDefault);
|
||||
this.mountName = Bindings.createStringBinding(this::normalizeDisplayName, displayName);
|
||||
}
|
||||
|
||||
Observable[] observables() {
|
||||
return new Observable[]{path, mountName, winDriveLetter, unlockAfterStartup, revealAfterMount, useCustomMountPath, customMountPath, usesReadOnlyMode, mountFlags, filenameLengthLimit, actionAfterUnlock};
|
||||
}
|
||||
|
||||
private void deriveMountNameFromPathOrUseDefault(Path newPath) {
|
||||
final boolean mountNameSet = !StringUtils.isBlank(mountName.get());
|
||||
final boolean dirnameExists = (newPath != null) && (newPath.getFileName() != null);
|
||||
|
||||
if (!mountNameSet && dirnameExists) {
|
||||
mountName.set(normalizeMountName(newPath.getFileName().toString()));
|
||||
} else if (!mountNameSet && !dirnameExists) {
|
||||
mountName.set(DEFAULT_MOUNT_NAME + id);
|
||||
} else if (mountNameSet && dirnameExists) {
|
||||
if (mountName.get().equals(DEFAULT_MOUNT_NAME + id)) {
|
||||
//this is okay, since this function is only executed if the path changes (aka, the vault is created or added)
|
||||
mountName.set(newPath.getFileName().toString());
|
||||
}
|
||||
}
|
||||
return new Observable[]{path, displayName, winDriveLetter, unlockAfterStartup, revealAfterMount, useCustomMountPath, customMountPath, usesReadOnlyMode, mountFlags, filenameLengthLimit, actionAfterUnlock};
|
||||
}
|
||||
|
||||
public static VaultSettings withRandomId() {
|
||||
@@ -89,8 +74,9 @@ public class VaultSettings {
|
||||
return BaseEncoding.base64Url().encode(randomBytes);
|
||||
}
|
||||
|
||||
public static String normalizeMountName(String mountName) {
|
||||
String normalizedMountName = StringUtils.stripAccents(mountName);
|
||||
//visible for testing
|
||||
String normalizeDisplayName() {
|
||||
String normalizedMountName = StringUtils.stripAccents(displayName.get());
|
||||
StringBuilder builder = new StringBuilder();
|
||||
for (char c : normalizedMountName.toCharArray()) {
|
||||
if (Character.isWhitespace(c)) {
|
||||
@@ -118,7 +104,11 @@ public class VaultSettings {
|
||||
return path;
|
||||
}
|
||||
|
||||
public StringProperty mountName() {
|
||||
public StringProperty displayName() {
|
||||
return displayName;
|
||||
}
|
||||
|
||||
public StringBinding mountName() {
|
||||
return mountName;
|
||||
}
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@ class VaultSettingsJsonAdapter {
|
||||
out.beginObject();
|
||||
out.name("id").value(value.getId());
|
||||
out.name("path").value(value.path().get().toString());
|
||||
out.name("mountName").value(value.mountName().get());
|
||||
out.name("displayName").value(value.displayName().get());
|
||||
out.name("winDriveLetter").value(value.winDriveLetter().get());
|
||||
out.name("unlockAfterStartup").value(value.unlockAfterStartup().get());
|
||||
out.name("revealAfterMount").value(value.revealAfterMount().get());
|
||||
@@ -37,7 +37,8 @@ class VaultSettingsJsonAdapter {
|
||||
public VaultSettings read(JsonReader in) throws IOException {
|
||||
String id = null;
|
||||
String path = null;
|
||||
String mountName = null;
|
||||
String mountName = null; //see https://github.com/cryptomator/cryptomator/pull/1318
|
||||
String displayName = null;
|
||||
String customMountPath = null;
|
||||
String winDriveLetter = null;
|
||||
boolean unlockAfterStartup = VaultSettings.DEFAULT_UNLOCK_AFTER_STARTUP;
|
||||
@@ -54,7 +55,8 @@ class VaultSettingsJsonAdapter {
|
||||
switch (name) {
|
||||
case "id" -> id = in.nextString();
|
||||
case "path" -> path = in.nextString();
|
||||
case "mountName" -> mountName = in.nextString();
|
||||
case "mountName" -> mountName = in.nextString(); //see https://github.com/cryptomator/cryptomator/pull/1318
|
||||
case "displayName" -> displayName = in.nextString();
|
||||
case "winDriveLetter" -> winDriveLetter = in.nextString();
|
||||
case "unlockAfterStartup" -> unlockAfterStartup = in.nextBoolean();
|
||||
case "revealAfterMount" -> revealAfterMount = in.nextBoolean();
|
||||
@@ -73,7 +75,11 @@ class VaultSettingsJsonAdapter {
|
||||
in.endObject();
|
||||
|
||||
VaultSettings vaultSettings = (id == null) ? VaultSettings.withRandomId() : new VaultSettings(id);
|
||||
vaultSettings.mountName().set(mountName);
|
||||
if (displayName != null) { //see https://github.com/cryptomator/cryptomator/pull/1318
|
||||
vaultSettings.displayName().set(displayName);
|
||||
} else {
|
||||
vaultSettings.displayName().set(mountName);
|
||||
}
|
||||
vaultSettings.path().set(Paths.get(path));
|
||||
vaultSettings.winDriveLetter().set(winDriveLetter);
|
||||
vaultSettings.unlockAfterStartup().set(unlockAfterStartup);
|
||||
|
||||
@@ -47,9 +47,9 @@ public class DokanyVolume implements Volume {
|
||||
@Override
|
||||
public void mount(CryptoFileSystem fs, String mountFlags) throws VolumeException, IOException {
|
||||
this.mountPoint = determineMountPoint();
|
||||
String mountName = vaultSettings.mountName().get();
|
||||
String mountName = vaultSettings.displayName().get();
|
||||
try {
|
||||
this.mount = mountFactory.mount(fs.getPath("/"), mountPoint, mountName, FS_TYPE_NAME, mountFlags.strip());
|
||||
this.mount = mountFactory.mount(fs.getPath("/"), mountPoint, vaultSettings.mountName().get(), FS_TYPE_NAME, mountFlags.strip());
|
||||
} catch (MountFailedException e) {
|
||||
if (vaultSettings.getCustomMountPath().isPresent()) {
|
||||
LOG.warn("Failed to mount vault into {}. Is this directory currently accessed by another process (e.g. Windows Explorer)?", mountPoint);
|
||||
|
||||
@@ -56,7 +56,7 @@ public class Vault {
|
||||
private final ObjectProperty<VaultState> state;
|
||||
private final ObjectProperty<Exception> lastKnownException;
|
||||
private final VaultStats stats;
|
||||
private final StringBinding displayableName;
|
||||
private final StringBinding displayName;
|
||||
private final StringBinding displayablePath;
|
||||
private final BooleanBinding locked;
|
||||
private final BooleanBinding processing;
|
||||
@@ -78,7 +78,7 @@ public class Vault {
|
||||
this.state = state;
|
||||
this.lastKnownException = lastKnownException;
|
||||
this.stats = stats;
|
||||
this.displayableName = Bindings.createStringBinding(this::getDisplayableName, vaultSettings.path());
|
||||
this.displayName = Bindings.createStringBinding(this::getDisplayName, vaultSettings.displayName());
|
||||
this.displayablePath = Bindings.createStringBinding(this::getDisplayablePath, vaultSettings.path());
|
||||
this.locked = Bindings.createBooleanBinding(this::isLocked, state);
|
||||
this.processing = Bindings.createBooleanBinding(this::isProcessing, state);
|
||||
@@ -225,13 +225,12 @@ public class Vault {
|
||||
return state.get() == VaultState.ERROR;
|
||||
}
|
||||
|
||||
public StringBinding displayableNameProperty() {
|
||||
return displayableName;
|
||||
public StringBinding displayNameProperty() {
|
||||
return displayName;
|
||||
}
|
||||
|
||||
public String getDisplayableName() {
|
||||
Path p = vaultSettings.path().get();
|
||||
return p.getFileName().toString();
|
||||
public String getDisplayName() {
|
||||
return vaultSettings.displayName().get();
|
||||
}
|
||||
|
||||
public StringBinding accessPointProperty() {
|
||||
|
||||
@@ -20,11 +20,11 @@ import org.slf4j.LoggerFactory;
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.NoSuchFileException;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Collection;
|
||||
import java.util.Optional;
|
||||
import java.util.ResourceBundle;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static org.cryptomator.common.Constants.MASTERKEY_FILENAME;
|
||||
@@ -36,10 +36,12 @@ public class VaultListManager {
|
||||
|
||||
private final VaultComponent.Builder vaultComponentBuilder;
|
||||
private final ObservableList<Vault> vaultList;
|
||||
private final String defaultVaultName;
|
||||
|
||||
@Inject
|
||||
public VaultListManager(VaultComponent.Builder vaultComponentBuilder, Settings settings) {
|
||||
public VaultListManager(VaultComponent.Builder vaultComponentBuilder, ResourceBundle resourceBundle, Settings settings) {
|
||||
this.vaultComponentBuilder = vaultComponentBuilder;
|
||||
this.defaultVaultName = resourceBundle.getString("defaults.vault.vaultName");
|
||||
this.vaultList = FXCollections.observableArrayList(Vault::observables);
|
||||
|
||||
addAll(settings.getDirectories());
|
||||
@@ -59,14 +61,23 @@ public class VaultListManager {
|
||||
if (alreadyExistingVault.isPresent()) {
|
||||
return alreadyExistingVault.get();
|
||||
} else {
|
||||
VaultSettings vaultSettings = VaultSettings.withRandomId();
|
||||
vaultSettings.path().set(normalizedPathToVault);
|
||||
Vault newVault = create(vaultSettings);
|
||||
Vault newVault = create(newVaultSettings(normalizedPathToVault));
|
||||
vaultList.add(newVault);
|
||||
return newVault;
|
||||
}
|
||||
}
|
||||
|
||||
private VaultSettings newVaultSettings(Path path) {
|
||||
VaultSettings vaultSettings = VaultSettings.withRandomId();
|
||||
vaultSettings.path().set(path);
|
||||
if (path.getFileName() != null) {
|
||||
vaultSettings.displayName().set(path.getFileName().toString());
|
||||
} else {
|
||||
vaultSettings.displayName().set(defaultVaultName);
|
||||
}
|
||||
return vaultSettings;
|
||||
}
|
||||
|
||||
private void addAll(Collection<VaultSettings> vaultSettings) {
|
||||
Collection<Vault> vaults = vaultSettings.stream().map(this::create).collect(Collectors.toList());
|
||||
vaultList.addAll(vaults);
|
||||
@@ -92,7 +103,7 @@ public class VaultListManager {
|
||||
}
|
||||
return compBuilder.build().vault();
|
||||
}
|
||||
|
||||
|
||||
public static VaultState redetermineVaultState(Vault vault) {
|
||||
VaultState previousState = vault.getState();
|
||||
return switch (previousState) {
|
||||
|
||||
@@ -77,7 +77,7 @@ public class VaultModule {
|
||||
@DefaultMountFlags
|
||||
public StringBinding provideDefaultMountFlags(Settings settings, VaultSettings vaultSettings) {
|
||||
ObjectProperty<VolumeImpl> preferredVolumeImpl = settings.preferredVolumeImpl();
|
||||
StringProperty mountName = vaultSettings.mountName();
|
||||
StringProperty mountName = vaultSettings.displayName();
|
||||
BooleanProperty readOnly = vaultSettings.usesReadOnlyMode();
|
||||
|
||||
return Bindings.createStringBinding(() -> {
|
||||
|
||||
@@ -98,7 +98,7 @@ public class WebDavVolume implements Volume {
|
||||
|
||||
@Override
|
||||
public Optional<Path> getMountPoint() {
|
||||
return Optional.ofNullable(mountPoint);
|
||||
return Optional.ofNullable(mountPoint); //TODO
|
||||
}
|
||||
|
||||
private String getLocalhostAliasOrNull() {
|
||||
|
||||
@@ -29,7 +29,7 @@ public class SettingsTest {
|
||||
Mockito.verify(changeListener, Mockito.times(2)).accept(settings);
|
||||
|
||||
// third change (to property of list item):
|
||||
vaultSettings.mountName().set("asd");
|
||||
vaultSettings.displayName().set("asd");
|
||||
Mockito.verify(changeListener, Mockito.times(3)).accept(settings);
|
||||
}
|
||||
|
||||
|
||||
@@ -23,13 +23,13 @@ public class VaultSettingsJsonAdapterTest {
|
||||
|
||||
@Test
|
||||
public void testDeserialize() throws IOException {
|
||||
String json = "{\"id\": \"foo\", \"path\": \"/foo/bar\", \"mountName\": \"test\", \"winDriveLetter\": \"X\", \"shouldBeIgnored\": true, \"individualMountPath\": \"/home/test/crypto\", \"mountFlags\":\"--foo --bar\"}";
|
||||
String json = "{\"id\": \"foo\", \"path\": \"/foo/bar\", \"displayName\": \"test\", \"winDriveLetter\": \"X\", \"shouldBeIgnored\": true, \"individualMountPath\": \"/home/test/crypto\", \"mountFlags\":\"--foo --bar\"}";
|
||||
JsonReader jsonReader = new JsonReader(new StringReader(json));
|
||||
|
||||
VaultSettings vaultSettings = adapter.read(jsonReader);
|
||||
Assertions.assertEquals("foo", vaultSettings.getId());
|
||||
Assertions.assertEquals(Paths.get("/foo/bar"), vaultSettings.path().get());
|
||||
Assertions.assertEquals("test", vaultSettings.mountName().get());
|
||||
Assertions.assertEquals("test", vaultSettings.displayName().get());
|
||||
Assertions.assertEquals("X", vaultSettings.winDriveLetter().get());
|
||||
Assertions.assertEquals("/home/test/crypto", vaultSettings.customMountPath().get());
|
||||
Assertions.assertEquals("--foo --bar", vaultSettings.mountFlags().get());
|
||||
@@ -41,7 +41,7 @@ public class VaultSettingsJsonAdapterTest {
|
||||
public void testSerialize() throws IOException {
|
||||
VaultSettings vaultSettings = new VaultSettings("test");
|
||||
vaultSettings.path().set(Paths.get("/foo/bar"));
|
||||
vaultSettings.mountName().set("mountyMcMountFace");
|
||||
vaultSettings.displayName().set("mountyMcMountFace");
|
||||
vaultSettings.mountFlags().set("--foo --bar");
|
||||
|
||||
StringWriter buf = new StringWriter();
|
||||
@@ -55,7 +55,7 @@ public class VaultSettingsJsonAdapterTest {
|
||||
} else {
|
||||
MatcherAssert.assertThat(result, CoreMatchers.containsString("\"path\":\"/foo/bar\""));
|
||||
}
|
||||
MatcherAssert.assertThat(result, CoreMatchers.containsString("\"mountName\":\"mountyMcMountFace\""));
|
||||
MatcherAssert.assertThat(result, CoreMatchers.containsString("\"displayName\":\"mountyMcMountFace\""));
|
||||
MatcherAssert.assertThat(result, CoreMatchers.containsString("\"mountFlags\":\"--foo --bar\""));
|
||||
}
|
||||
|
||||
|
||||
@@ -8,19 +8,19 @@
|
||||
*******************************************************************************/
|
||||
package org.cryptomator.common.settings;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.CsvSource;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
public class VaultSettingsTest {
|
||||
|
||||
@Test
|
||||
public void testNormalize() throws Exception {
|
||||
assertEquals("_", VaultSettings.normalizeMountName(" "));
|
||||
assertEquals("a", VaultSettings.normalizeMountName("ä"));
|
||||
assertEquals("C", VaultSettings.normalizeMountName("Ĉ"));
|
||||
assertEquals("_", VaultSettings.normalizeMountName(":"));
|
||||
assertEquals("_", VaultSettings.normalizeMountName("汉语"));
|
||||
@ParameterizedTest
|
||||
@CsvSource({"a a,a_a", "ä,a", "Ĉ,C", ":,_", "汉语,_"})
|
||||
public void testNormalize(String test, String expected) {
|
||||
VaultSettings settings = new VaultSettings("id");
|
||||
settings.displayName().setValue(test);
|
||||
assertEquals(expected, settings.normalizeDisplayName());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -28,7 +28,7 @@ public class VaultModuleTest {
|
||||
|
||||
@BeforeEach
|
||||
public void setup(@TempDir Path tmpDir) {
|
||||
Mockito.when(vaultSettings.mountName()).thenReturn(new SimpleStringProperty("TEST"));
|
||||
Mockito.when(vaultSettings.displayName()).thenReturn(new SimpleStringProperty("TEST"));
|
||||
Mockito.when(vaultSettings.usesReadOnlyMode()).thenReturn(new SimpleBooleanProperty(true));
|
||||
System.setProperty("user.home", tmpDir.toString());
|
||||
}
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
<cryptomator.jni.version>2.2.3</cryptomator.jni.version>
|
||||
<cryptomator.fuse.version>1.2.3</cryptomator.fuse.version>
|
||||
<cryptomator.dokany.version>1.1.15</cryptomator.dokany.version>
|
||||
<cryptomator.webdav.version>1.0.11</cryptomator.webdav.version>
|
||||
<cryptomator.webdav.version>1.0.12</cryptomator.webdav.version>
|
||||
|
||||
<!-- 3rd party dependencies -->
|
||||
<javafx.version>14</javafx.version>
|
||||
|
||||
@@ -68,7 +68,7 @@ public class ChangePasswordController implements FxController {
|
||||
public void finish() {
|
||||
try {
|
||||
CryptoFileSystemProvider.changePassphrase(vault.getPath(), MASTERKEY_FILENAME, oldPasswordField.getCharacters(), newPassword.get());
|
||||
LOG.info("Successfully changed password for {}", vault.getDisplayableName());
|
||||
LOG.info("Successfully changed password for {}", vault.getDisplayName());
|
||||
window.close();
|
||||
updatePasswordInSystemkeychain();
|
||||
} catch (IOException e) {
|
||||
@@ -85,7 +85,7 @@ public class ChangePasswordController implements FxController {
|
||||
if (keychain.isPresent()) {
|
||||
try {
|
||||
keychain.get().changePassphrase(vault.getId(), CharBuffer.wrap(newPassword.get()));
|
||||
LOG.info("Successfully updated password in system keychain for {}", vault.getDisplayableName());
|
||||
LOG.info("Successfully updated password in system keychain for {}", vault.getDisplayName());
|
||||
} catch (KeychainAccessException e) {
|
||||
LOG.error("Failed to update password in system keychain.", e);
|
||||
}
|
||||
|
||||
@@ -44,8 +44,8 @@ public class VaultService {
|
||||
*/
|
||||
public Task<Vault> createRevealTask(Vault vault) {
|
||||
Task<Vault> task = new RevealVaultTask(vault);
|
||||
task.setOnSucceeded(evt -> LOG.info("Revealed {}", vault.getDisplayableName()));
|
||||
task.setOnFailed(evt -> LOG.error("Failed to reveal " + vault.getDisplayableName(), evt.getSource().getException()));
|
||||
task.setOnSucceeded(evt -> LOG.info("Revealed {}", vault.getDisplayName()));
|
||||
task.setOnFailed(evt -> LOG.error("Failed to reveal " + vault.getDisplayName(), evt.getSource().getException()));
|
||||
return task;
|
||||
}
|
||||
|
||||
@@ -68,8 +68,8 @@ public class VaultService {
|
||||
*/
|
||||
public Task<Vault> createLockTask(Vault vault, boolean forced) {
|
||||
Task<Vault> task = new LockVaultTask(vault, forced);
|
||||
task.setOnSucceeded(evt -> LOG.info("Locked {}", vault.getDisplayableName()));
|
||||
task.setOnFailed(evt -> LOG.error("Failed to lock " + vault.getDisplayableName(), evt.getSource().getException()));
|
||||
task.setOnSucceeded(evt -> LOG.info("Locked {}", vault.getDisplayName()));
|
||||
task.setOnFailed(evt -> LOG.error("Failed to lock " + vault.getDisplayName(), evt.getSource().getException()));
|
||||
return task;
|
||||
}
|
||||
|
||||
@@ -94,7 +94,7 @@ public class VaultService {
|
||||
List<Task<Vault>> lockTasks = vaults.stream().map(v -> new LockVaultTask(v, forced)).collect(Collectors.toUnmodifiableList());
|
||||
lockTasks.forEach(executorService::execute);
|
||||
Task<Collection<Vault>> task = new WaitForTasksTask(lockTasks);
|
||||
String vaultNames = vaults.stream().map(Vault::getDisplayableName).collect(Collectors.joining(", "));
|
||||
String vaultNames = vaults.stream().map(Vault::getDisplayName).collect(Collectors.joining(", "));
|
||||
task.setOnSucceeded(evt -> LOG.info("Locked {}", vaultNames));
|
||||
task.setOnFailed(evt -> LOG.error("Failed to lock vaults " + vaultNames, evt.getSource().getException()));
|
||||
return task;
|
||||
|
||||
@@ -41,7 +41,7 @@ public class ForgetPasswordController implements FxController {
|
||||
if (keychain.isPresent()) {
|
||||
try {
|
||||
keychain.get().deletePassphrase(vault.getId());
|
||||
LOG.debug("Forgot password for vault {}.", vault.getDisplayableName());
|
||||
LOG.debug("Forgot password for vault {}.", vault.getDisplayName());
|
||||
confirmedResult.setValue(true);
|
||||
} catch (KeychainAccessException e) {
|
||||
LOG.error("Failed to remove entry from system keychain.", e);
|
||||
|
||||
@@ -100,7 +100,7 @@ public class FxApplication extends Application {
|
||||
public void startUnlockWorkflow(Vault vault, Optional<Stage> owner) {
|
||||
Platform.runLater(() -> {
|
||||
unlockWindowBuilderProvider.get().vault(vault).owner(owner).build().startUnlockWorkflow();
|
||||
LOG.debug("Showing UnlockWindow for {}", vault.getDisplayableName());
|
||||
LOG.debug("Showing UnlockWindow for {}", vault.getDisplayName());
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -116,10 +116,10 @@ public class MigrationRunController implements FxController {
|
||||
return migrators.needsMigration(vault.getPath(), MASTERKEY_FILENAME);
|
||||
}).onSuccess(needsAnotherMigration -> {
|
||||
if (needsAnotherMigration) {
|
||||
LOG.info("Migration of '{}' succeeded, but another migration is required.", vault.getDisplayableName());
|
||||
LOG.info("Migration of '{}' succeeded, but another migration is required.", vault.getDisplayName());
|
||||
vault.setState(VaultState.NEEDS_MIGRATION);
|
||||
} else {
|
||||
LOG.info("Migration of '{}' succeeded.", vault.getDisplayableName());
|
||||
LOG.info("Migration of '{}' succeeded.", vault.getDisplayName());
|
||||
vault.setState(VaultState.LOCKED);
|
||||
passwordField.wipe();
|
||||
window.setScene(successScene.get());
|
||||
|
||||
@@ -53,7 +53,7 @@ public class QuitController implements FxController {
|
||||
|
||||
Task<Collection<Vault>> lockAllTask = vaultService.createLockAllTask(unlockedVaults, false);
|
||||
lockAllTask.setOnSucceeded(evt -> {
|
||||
LOG.info("Locked {}", lockAllTask.getValue().stream().map(Vault::getDisplayableName).collect(Collectors.joining(", ")));
|
||||
LOG.info("Locked {}", lockAllTask.getValue().stream().map(Vault::getDisplayName).collect(Collectors.joining(", ")));
|
||||
if (unlockedVaults.isEmpty()) {
|
||||
window.close();
|
||||
response.performQuit();
|
||||
|
||||
@@ -9,7 +9,6 @@ import javafx.beans.property.SimpleObjectProperty;
|
||||
import javafx.beans.property.SimpleStringProperty;
|
||||
import javafx.beans.property.StringProperty;
|
||||
import javafx.scene.Scene;
|
||||
import javafx.scene.image.Image;
|
||||
import javafx.stage.Modality;
|
||||
import javafx.stage.Stage;
|
||||
import org.cryptomator.common.vaults.Vault;
|
||||
@@ -25,7 +24,6 @@ import org.cryptomator.ui.common.StageFactory;
|
||||
|
||||
import javax.inject.Named;
|
||||
import javax.inject.Provider;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.ResourceBundle;
|
||||
|
||||
@@ -107,7 +105,7 @@ abstract class RecoveryKeyModule {
|
||||
@IntoMap
|
||||
@FxControllerKey(RecoveryKeyDisplayController.class)
|
||||
static FxController provideRecoveryKeyDisplayController(@RecoveryKeyWindow Stage window, @RecoveryKeyWindow Vault vault, @RecoveryKeyWindow StringProperty recoveryKey, ResourceBundle localization) {
|
||||
return new RecoveryKeyDisplayController(window, vault.getDisplayableName(), recoveryKey.get(), localization);
|
||||
return new RecoveryKeyDisplayController(window, vault.getDisplayName(), recoveryKey.get(), localization);
|
||||
}
|
||||
|
||||
@Binds
|
||||
|
||||
@@ -34,7 +34,7 @@ public class RemoveVaultController implements FxController {
|
||||
@FXML
|
||||
public void finish() {
|
||||
vaults.remove(vault);
|
||||
LOG.debug("Removing vault {}.", vault.getDisplayableName());
|
||||
LOG.debug("Removing vault {}.", vault.getDisplayName());
|
||||
window.close();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -80,7 +80,7 @@ class TrayMenuController {
|
||||
}
|
||||
|
||||
private Menu buildSubmenu(Vault vault) {
|
||||
Menu submenu = new Menu(vault.getDisplayableName());
|
||||
Menu submenu = new Menu(vault.getDisplayName());
|
||||
|
||||
if (vault.isLocked()) {
|
||||
MenuItem unlockItem = new MenuItem(resourceBundle.getString("traymenu.vault.unlock"));
|
||||
|
||||
@@ -77,7 +77,7 @@ public class UnlockController implements FxController {
|
||||
this.unlockButtonContentDisplay = Bindings.createObjectBinding(this::getUnlockButtonContentDisplay, passwordEntryLock.awaitingInteraction());
|
||||
this.userInteractionDisabled = passwordEntryLock.awaitingInteraction().not();
|
||||
this.unlockButtonDisabled = new SimpleBooleanProperty();
|
||||
this.vaultName = WeakBindings.bindString(vault.displayableNameProperty());
|
||||
this.vaultName = WeakBindings.bindString(vault.displayNameProperty());
|
||||
this.window.setOnCloseRequest(windowEvent -> cancel());
|
||||
}
|
||||
|
||||
|
||||
@@ -82,7 +82,7 @@ abstract class UnlockModule {
|
||||
@UnlockScoped
|
||||
static Stage provideStage(StageFactory factory, @UnlockWindow Vault vault, @Named("unlockWindowOwner") Optional<Stage> owner) {
|
||||
Stage stage = factory.create();
|
||||
stage.setTitle(vault.getDisplayableName());
|
||||
stage.setTitle(vault.getDisplayName());
|
||||
stage.setResizable(false);
|
||||
if (owner.isPresent()) {
|
||||
stage.initOwner(owner.get());
|
||||
|
||||
@@ -128,7 +128,7 @@ public class UnlockWorkflow extends Task<Boolean> {
|
||||
}
|
||||
|
||||
private void handleSuccess() {
|
||||
LOG.info("Unlock of '{}' succeeded.", vault.getDisplayableName());
|
||||
LOG.info("Unlock of '{}' succeeded.", vault.getDisplayName());
|
||||
if (savePassword.get()) {
|
||||
savePasswordToSystemkeychain();
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ package org.cryptomator.ui.vaultoptions;
|
||||
import javafx.fxml.FXML;
|
||||
import javafx.scene.control.CheckBox;
|
||||
import javafx.scene.control.ChoiceBox;
|
||||
import javafx.scene.control.TextField;
|
||||
import javafx.util.StringConverter;
|
||||
import org.cryptomator.common.settings.UiTheme;
|
||||
import org.cryptomator.common.settings.WhenUnlocked;
|
||||
@@ -18,6 +19,7 @@ public class GeneralVaultOptionsController implements FxController {
|
||||
private final Vault vault;
|
||||
private final ResourceBundle resourceBundle;
|
||||
|
||||
public TextField vaultName;
|
||||
public CheckBox unlockOnStartupCheckbox;
|
||||
public ChoiceBox<WhenUnlocked> actionAfterUnlockChoiceBox;
|
||||
|
||||
@@ -29,6 +31,7 @@ public class GeneralVaultOptionsController implements FxController {
|
||||
|
||||
@FXML
|
||||
public void initialize() {
|
||||
vaultName.textProperty().bindBidirectional(vault.getVaultSettings().displayName());
|
||||
unlockOnStartupCheckbox.selectedProperty().bindBidirectional(vault.getVaultSettings().unlockAfterStartup());
|
||||
actionAfterUnlockChoiceBox.getItems().addAll(WhenUnlocked.values());
|
||||
actionAfterUnlockChoiceBox.valueProperty().bindBidirectional(vault.getVaultSettings().actionAfterUnlock());
|
||||
|
||||
@@ -42,7 +42,6 @@ public class MountOptionsController implements FxController {
|
||||
private final BooleanBinding webDavAndWindows;
|
||||
private final WindowsDriveLetters windowsDriveLetters;
|
||||
private final ResourceBundle resourceBundle;
|
||||
public TextField driveName;
|
||||
public CheckBox readOnlyCheckbox;
|
||||
public CheckBox customMountFlagsCheckbox;
|
||||
public TextField mountFlags;
|
||||
@@ -63,7 +62,6 @@ public class MountOptionsController implements FxController {
|
||||
|
||||
@FXML
|
||||
public void initialize() {
|
||||
driveName.textProperty().bindBidirectional(vault.getVaultSettings().mountName());
|
||||
|
||||
// readonly:
|
||||
readOnlyCheckbox.selectedProperty().bindBidirectional(vault.getVaultSettings().usesReadOnlyMode());
|
||||
|
||||
@@ -5,7 +5,6 @@ import dagger.Module;
|
||||
import dagger.Provides;
|
||||
import dagger.multibindings.IntoMap;
|
||||
import javafx.scene.Scene;
|
||||
import javafx.scene.image.Image;
|
||||
import javafx.stage.Modality;
|
||||
import javafx.stage.Stage;
|
||||
import org.cryptomator.common.vaults.Vault;
|
||||
@@ -20,9 +19,7 @@ import org.cryptomator.ui.common.StageFactory;
|
||||
import org.cryptomator.ui.mainwindow.MainWindow;
|
||||
import org.cryptomator.ui.recoverykey.RecoveryKeyComponent;
|
||||
|
||||
import javax.inject.Named;
|
||||
import javax.inject.Provider;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.ResourceBundle;
|
||||
|
||||
@@ -41,7 +38,7 @@ abstract class VaultOptionsModule {
|
||||
@VaultOptionsScoped
|
||||
static Stage provideStage(StageFactory factory, @MainWindow Stage owner, @VaultOptionsWindow Vault vault) {
|
||||
Stage stage = factory.create();
|
||||
stage.setTitle(vault.getDisplayableName());
|
||||
stage.setTitle(vault.getDisplayName());
|
||||
stage.setResizable(true);
|
||||
stage.setMinWidth(400);
|
||||
stage.setMinHeight(300);
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
|
||||
<Region VBox.vgrow="ALWAYS"/>
|
||||
|
||||
<FormattedLabel format="%addvaultwizard.success.nextStepsInstructions" arg1="${controller.vault.displayableName}" wrapText="true" HBox.hgrow="ALWAYS"/>
|
||||
<FormattedLabel format="%addvaultwizard.success.nextStepsInstructions" arg1="${controller.vault.displayName}" wrapText="true" HBox.hgrow="ALWAYS"/>
|
||||
|
||||
<Region VBox.vgrow="ALWAYS"/>
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
</padding>
|
||||
<children>
|
||||
<VBox spacing="6">
|
||||
<FormattedLabel format="%changepassword.enterOldPassword" arg1="${controller.vault.displayableName}" wrapText="true"/>
|
||||
<FormattedLabel format="%changepassword.enterOldPassword" arg1="${controller.vault.displayName}" wrapText="true"/>
|
||||
<NiceSecurePasswordField fx:id="oldPasswordField"/>
|
||||
</VBox>
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
</padding>
|
||||
<children>
|
||||
<VBox spacing="6" visible="${!controller.vault.processing}" managed="${!controller.vault.processing}">
|
||||
<FormattedLabel format="%migration.run.enterPassword" arg1="${controller.vault.displayableName}" wrapText="true"/>
|
||||
<FormattedLabel format="%migration.run.enterPassword" arg1="${controller.vault.displayName}" wrapText="true"/>
|
||||
<NiceSecurePasswordField fx:id="passwordField"/>
|
||||
</VBox>
|
||||
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
</StackPane>
|
||||
|
||||
<VBox spacing="6" HBox.hgrow="ALWAYS">
|
||||
<FormattedLabel format="%migration.start.prompt" arg1="${controller.vault.displayableName}" wrapText="true" />
|
||||
<FormattedLabel format="%migration.start.prompt" arg1="${controller.vault.displayName}" wrapText="true" />
|
||||
<CheckBox fx:id="confirmSyncDone" text="%migration.start.confirm"/>
|
||||
</VBox>
|
||||
</HBox>
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
<Circle styleClass="glyph-icon-primary" radius="24"/>
|
||||
<FontAwesome5IconView styleClass="glyph-icon-white" glyph="CHECK" glyphSize="24"/>
|
||||
</StackPane>
|
||||
<FormattedLabel format="%migration.success.nextStepsInstructions" arg1="${controller.vault.displayableName}" wrapText="true" HBox.hgrow="ALWAYS"/>
|
||||
<FormattedLabel format="%migration.success.nextStepsInstructions" arg1="${controller.vault.displayName}" wrapText="true" HBox.hgrow="ALWAYS"/>
|
||||
</HBox>
|
||||
|
||||
<VBox alignment="BOTTOM_CENTER" VBox.vgrow="ALWAYS">
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
</padding>
|
||||
<children>
|
||||
<VBox spacing="6">
|
||||
<FormattedLabel format="%recoveryKey.enterPassword.prompt" arg1="${controller.vault.displayableName}" wrapText="true"/>
|
||||
<FormattedLabel format="%recoveryKey.enterPassword.prompt" arg1="${controller.vault.displayName}" wrapText="true"/>
|
||||
<NiceSecurePasswordField fx:id="passwordField" HBox.hgrow="ALWAYS"/>
|
||||
</VBox>
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
<Insets topRightBottomLeft="12"/>
|
||||
</padding>
|
||||
<children>
|
||||
<FormattedLabel format="%recoveryKey.recover.prompt" arg1="${controller.vault.displayableName}" wrapText="true"/>
|
||||
<FormattedLabel format="%recoveryKey.recover.prompt" arg1="${controller.vault.displayName}" wrapText="true"/>
|
||||
|
||||
<TextArea wrapText="true" prefRowCount="4" fx:id="textarea" textFormatter="${controller.recoveryKeyTextFormatter}" onKeyPressed="#onKeyPressed"/>
|
||||
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
<FontAwesome5IconView styleClass="glyph-icon-white" glyph="CHECK" glyphSize="24"/>
|
||||
</StackPane>
|
||||
<VBox spacing="6">
|
||||
<FormattedLabel format="%unlock.success.message" arg1="${controller.vault.displayableName}" wrapText="true" HBox.hgrow="ALWAYS"/>
|
||||
<FormattedLabel format="%unlock.success.message" arg1="${controller.vault.displayName}" wrapText="true" HBox.hgrow="ALWAYS"/>
|
||||
<CheckBox text="%unlock.success.rememberChoice" fx:id="rememberChoiceCheckbox"/>
|
||||
</VBox>
|
||||
</HBox>
|
||||
|
||||
@@ -26,9 +26,9 @@
|
||||
</StackPane>
|
||||
<VBox spacing="4" HBox.hgrow="ALWAYS">
|
||||
<HBox spacing="12">
|
||||
<Label styleClass="label-large" text="${controller.vault.displayableName}">
|
||||
<Label styleClass="label-large" text="${controller.vault.displayName}">
|
||||
<tooltip>
|
||||
<Tooltip text="${controller.vault.displayableName}"/>
|
||||
<Tooltip text="${controller.vault.displayName}"/>
|
||||
</tooltip>
|
||||
</Label>
|
||||
<Region HBox.hgrow="ALWAYS"/>
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
<FontAwesome5IconView glyph="${controller.glyph}" HBox.hgrow="NEVER" glyphSize="16"/>
|
||||
</VBox>
|
||||
<VBox spacing="4" HBox.hgrow="ALWAYS">
|
||||
<Label styleClass="header-label" text="${controller.vault.displayableName}"/>
|
||||
<Label styleClass="header-label" text="${controller.vault.displayName}"/>
|
||||
<Label styleClass="detail-label" text="${controller.vault.displayablePath}" textOverrun="CENTER_ELLIPSIS"/>
|
||||
</VBox>
|
||||
</children>
|
||||
|
||||
@@ -2,10 +2,11 @@
|
||||
|
||||
<?import javafx.geometry.Insets?>
|
||||
<?import javafx.scene.control.CheckBox?>
|
||||
<?import javafx.scene.layout.VBox?>
|
||||
<?import javafx.scene.control.ChoiceBox?>
|
||||
<?import javafx.scene.layout.HBox?>
|
||||
<?import javafx.scene.control.Label?>
|
||||
<?import javafx.scene.control.TextField?>
|
||||
<?import javafx.scene.layout.HBox?>
|
||||
<?import javafx.scene.layout.VBox?>
|
||||
<VBox xmlns="http://javafx.com/javafx"
|
||||
xmlns:fx="http://javafx.com/fxml"
|
||||
fx:controller="org.cryptomator.ui.vaultoptions.GeneralVaultOptionsController"
|
||||
@@ -14,6 +15,11 @@
|
||||
<Insets topRightBottomLeft="12"/>
|
||||
</padding>
|
||||
<children>
|
||||
<HBox spacing="6" alignment="CENTER_LEFT">
|
||||
<Label text="%vaultOptions.general.vaultName"/>
|
||||
<TextField fx:id="vaultName"/>
|
||||
</HBox>
|
||||
|
||||
<CheckBox text="%vaultOptions.general.unlockAfterStartup" fx:id="unlockOnStartupCheckbox"/>
|
||||
|
||||
<HBox spacing="6" alignment="CENTER_LEFT">
|
||||
|
||||
@@ -23,11 +23,6 @@
|
||||
<Insets topRightBottomLeft="12"/>
|
||||
</padding>
|
||||
<children>
|
||||
<HBox spacing="6" alignment="CENTER_LEFT">
|
||||
<Label text="%vaultOptions.mount.driveName"/>
|
||||
<AlphanumericTextField fx:id="driveName"/>
|
||||
</HBox>
|
||||
|
||||
<CheckBox fx:id="readOnlyCheckbox" text="%vaultOptions.mount.readonly"/>
|
||||
|
||||
<CheckBox fx:id="customMountFlagsCheckbox" text="%vaultOptions.mount.customMountFlags" onAction="#toggleUseCustomMountFlags" visible="${!controller.webDavAndWindows}" managed="${!controller.webDavAndWindows}"/>
|
||||
|
||||
@@ -17,6 +17,9 @@ generic.button.print=Print
|
||||
generic.error.title=An unexpected error occured
|
||||
generic.error.instruction=This should not have happened. Please report the error text below and include a description of what steps did lead to this error.
|
||||
|
||||
# Defaults
|
||||
defaults.vault.vaultName=Vault
|
||||
|
||||
# Tray Menu
|
||||
traymenu.showMainWindow=Show
|
||||
traymenu.showPreferencesWindow=Preferences
|
||||
@@ -214,6 +217,7 @@ wrongFileAlert.link=For further assistance, visit
|
||||
# Vault Options
|
||||
## General
|
||||
vaultOptions.general=General
|
||||
vaultOptions.general.vaultName=Vault Name
|
||||
vaultOptions.general.unlockAfterStartup=Unlock vault when starting Cryptomator
|
||||
vaultOptions.general.actionAfterUnlock=After successful unlock
|
||||
vaultOptions.general.actionAfterUnlock.ignore=Do nothing
|
||||
@@ -222,7 +226,6 @@ vaultOptions.general.actionAfterUnlock.ask=Ask
|
||||
## Mount
|
||||
vaultOptions.mount=Mounting
|
||||
vaultOptions.mount.readonly=Read-Only
|
||||
vaultOptions.mount.driveName=Drive Name
|
||||
vaultOptions.mount.customMountFlags=Custom Mount Flags
|
||||
vaultOptions.mount.winDriveLetterOccupied=occupied
|
||||
vaultOptions.mount.mountPoint=Mount Point
|
||||
|
||||
Reference in New Issue
Block a user