Parcourir la source

Merge branch 'feature/375-readonly' into develop
fixes #375

Sebastian Stenzel il y a 6 ans
Parent
commit
d8ef402607

+ 7 - 1
main/commons/src/main/java/org/cryptomator/common/settings/VaultSettings.java

@@ -31,6 +31,7 @@ public class VaultSettings {
 	public static final boolean DEFAULT_UNLOCK_AFTER_STARTUP = false;
 	public static final boolean DEFAULT_REAVEAL_AFTER_MOUNT = true;
 	public static final boolean DEFAULT_USES_INDIVIDUAL_MOUNTPATH = false;
+	public static final boolean DEFAULT_USES_READONLY_MODE = false;
 
 	private final String id;
 	private final ObjectProperty<Path> path = new SimpleObjectProperty<>();
@@ -40,6 +41,7 @@ public class VaultSettings {
 	private final BooleanProperty revealAfterMount = new SimpleBooleanProperty(DEFAULT_REAVEAL_AFTER_MOUNT);
 	private final BooleanProperty usesIndividualMountPath = new SimpleBooleanProperty(DEFAULT_USES_INDIVIDUAL_MOUNTPATH);
 	private final StringProperty individualMountPath = new SimpleStringProperty();
+	private final BooleanProperty usesReadOnlyMode = new SimpleBooleanProperty(DEFAULT_USES_READONLY_MODE);
 
 	public VaultSettings(String id) {
 		this.id = Objects.requireNonNull(id);
@@ -48,7 +50,7 @@ public class VaultSettings {
 	}
 
 	Observable[] observables() {
-		return new Observable[]{path, mountName, winDriveLetter, unlockAfterStartup, revealAfterMount, usesIndividualMountPath, individualMountPath};
+		return new Observable[]{path, mountName, winDriveLetter, unlockAfterStartup, revealAfterMount, usesIndividualMountPath, individualMountPath, usesReadOnlyMode};
 	}
 
 	private void deriveMountNameFromPath(Path path) {
@@ -131,6 +133,10 @@ public class VaultSettings {
 		return individualMountPath;
 	}
 
+	public BooleanProperty usesReadOnlyMode() {
+		return usesReadOnlyMode;
+	}
+
 	/* Hashcode/Equals */
 
 	@Override

+ 6 - 0
main/commons/src/main/java/org/cryptomator/common/settings/VaultSettingsJsonAdapter.java

@@ -27,6 +27,7 @@ class VaultSettingsJsonAdapter {
 		out.name("revealAfterMount").value(value.revealAfterMount().get());
 		out.name("usesIndividualMountPath").value(value.usesIndividualMountPath().get());
 		out.name("individualMountPath").value(value.individualMountPath().get());    //TODO: should this always be written? ( because it could contain metadata, which the user may not want to save!)
+		out.name("usesReadOnlyMode").value(value.usesReadOnlyMode().get());
 		out.endObject();
 	}
 
@@ -39,6 +40,7 @@ class VaultSettingsJsonAdapter {
 		boolean unlockAfterStartup = VaultSettings.DEFAULT_UNLOCK_AFTER_STARTUP;
 		boolean revealAfterMount = VaultSettings.DEFAULT_REAVEAL_AFTER_MOUNT;
 		boolean usesIndividualMountPath = VaultSettings.DEFAULT_USES_INDIVIDUAL_MOUNTPATH;
+		boolean usesReadOnlyMode = VaultSettings.DEFAULT_USES_READONLY_MODE;
 
 		in.beginObject();
 		while (in.hasNext()) {
@@ -68,6 +70,9 @@ class VaultSettingsJsonAdapter {
 				case "individualMountPath":
 					individualMountPath = in.nextString();
 					break;
+				case "usesReadOnlyMode":
+					usesReadOnlyMode = in.nextBoolean();
+					break;
 				default:
 					LOG.warn("Unsupported vault setting found in JSON: " + name);
 					in.skipValue();
@@ -83,6 +88,7 @@ class VaultSettingsJsonAdapter {
 		vaultSettings.revealAfterMount().set(revealAfterMount);
 		vaultSettings.usesIndividualMountPath().set(usesIndividualMountPath);
 		vaultSettings.individualMountPath().set(individualMountPath);
+		vaultSettings.usesReadOnlyMode().set(usesReadOnlyMode);
 		return vaultSettings;
 	}
 

+ 5 - 2
main/ui/src/main/java/org/cryptomator/ui/controllers/UnlockController.java

@@ -150,6 +150,9 @@ public class UnlockController implements ViewController {
 	@FXML
 	private CheckBox unlockAfterStartup;
 
+	@FXML
+	private CheckBox useReadOnlyMode;
+
 	@Override
 	public void initialize() {
 		advancedOptions.managedProperty().bind(advancedOptions.visibleProperty());
@@ -240,7 +243,7 @@ public class UnlockController implements ViewController {
 		VaultSettings vaultSettings = vault.getVaultSettings();
 		unlockAfterStartup.setSelected(savePassword.isSelected() && vaultSettings.unlockAfterStartup().get());
 		revealAfterMount.setSelected(vaultSettings.revealAfterMount().get());
-
+		useReadOnlyMode.setSelected(vaultSettings.usesReadOnlyMode().get());
 		if (!settings.preferredVolumeImpl().get().equals(VolumeImpl.WEBDAV)) {
 			useCustomMountPoint.setSelected(vaultSettings.usesIndividualMountPath().get());
 			customMountPointField.textProperty().setValue(vaultSettings.individualMountPath().getValueSafe());
@@ -249,7 +252,7 @@ public class UnlockController implements ViewController {
 		vaultSubs = vaultSubs.and(EasyBind.subscribe(unlockAfterStartup.selectedProperty(), vaultSettings.unlockAfterStartup()::set));
 		vaultSubs = vaultSubs.and(EasyBind.subscribe(revealAfterMount.selectedProperty(), vaultSettings.revealAfterMount()::set));
 		vaultSubs = vaultSubs.and(EasyBind.subscribe(useCustomMountPoint.selectedProperty(), vaultSettings.usesIndividualMountPath()::set));
-
+		vaultSubs = vaultSubs.and(EasyBind.subscribe(useReadOnlyMode.selectedProperty(), vaultSettings.usesReadOnlyMode()::set));
 	}
 
 	// ****************************************

+ 8 - 1
main/ui/src/main/java/org/cryptomator/ui/model/Vault.java

@@ -21,6 +21,7 @@ import org.cryptomator.common.settings.Settings;
 import org.cryptomator.common.settings.VaultSettings;
 import org.cryptomator.cryptofs.CryptoFileSystem;
 import org.cryptomator.cryptofs.CryptoFileSystemProperties;
+import org.cryptomator.cryptofs.CryptoFileSystemProperties.FileSystemFlags;
 import org.cryptomator.cryptofs.CryptoFileSystemProvider;
 import org.cryptomator.cryptolib.api.CryptoException;
 import org.cryptomator.cryptolib.api.InvalidPassphraseException;
@@ -38,6 +39,8 @@ import java.nio.file.NoSuchFileException;
 import java.nio.file.NotDirectoryException;
 import java.nio.file.Path;
 import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.List;
 import java.util.Objects;
 import java.util.concurrent.atomic.AtomicReference;
 import java.util.function.Predicate;
@@ -78,9 +81,13 @@ public class Vault {
 	}
 
 	private CryptoFileSystem unlockCryptoFileSystem(CharSequence passphrase) throws NoSuchFileException, IOException, InvalidPassphraseException, CryptoException {
+		List<FileSystemFlags> flags = new ArrayList<>();
+		if (vaultSettings.usesReadOnlyMode().get()) {
+			flags.add(FileSystemFlags.READONLY);
+		}
 		CryptoFileSystemProperties fsProps = CryptoFileSystemProperties.cryptoFileSystemProperties() //
 				.withPassphrase(passphrase) //
-				.withFlags() //
+				.withFlags(flags) //
 				.withMasterkeyFilename(MASTERKEY_FILENAME) //
 				.build();
 		return CryptoFileSystemProvider.newFileSystem(getPath(), fsProps);

+ 9 - 6
main/ui/src/main/resources/fxml/unlock.fxml

@@ -80,14 +80,17 @@
 			<CheckBox GridPane.rowIndex="4" GridPane.columnIndex="0" GridPane.columnSpan="2" fx:id="revealAfterMount" text="%unlock.label.revealAfterMount" cacheShape="true" cache="true" />
 
 			<!-- Row 3.5 -->
-			<CheckBox GridPane.rowIndex="5" GridPane.columnIndex="0" GridPane.columnSpan="2" fx:id="useCustomMountPoint" text="%unlock.label.useOwnMountPath" cacheShape="true" cache="true" />
+			<CheckBox GridPane.rowIndex="5" GridPane.columnIndex="0" GridPane.columnSpan="2" fx:id="useReadOnlyMode" text="%unlock.label.useReadOnlyMode" cacheShape="true" cache="true" />
 
-			<!-- Row 3.6 Alt1 -->
-			<Label GridPane.rowIndex="6" GridPane.columnIndex="0" fx:id="winDriveLetterLabel" text="%unlock.label.winDriveLetter" cacheShape="true" cache="true" />
-			<ChoiceBox GridPane.rowIndex="6" GridPane.columnIndex="1" fx:id="winDriveLetter" GridPane.hgrow="ALWAYS" maxWidth="Infinity" cacheShape="true" cache="true" />
+			<!-- Row 3.6 -->
+			<CheckBox GridPane.rowIndex="6" GridPane.columnIndex="0" GridPane.columnSpan="2" fx:id="useCustomMountPoint" text="%unlock.label.useOwnMountPath" cacheShape="true" cache="true" />
 
-			<!-- Row 3.6 Alt2 -->
-			<HBox fx:id="customMountPoint" GridPane.rowIndex="6" GridPane.columnIndex="0" GridPane.columnSpan="2" spacing="6">
+			<!-- Row 3.7 Alt1 -->
+			<Label GridPane.rowIndex="7" GridPane.columnIndex="0" fx:id="winDriveLetterLabel" text="%unlock.label.winDriveLetter" cacheShape="true" cache="true" />
+			<ChoiceBox GridPane.rowIndex="7" GridPane.columnIndex="1" fx:id="winDriveLetter" GridPane.hgrow="ALWAYS" maxWidth="Infinity" cacheShape="true" cache="true" />
+
+			<!-- Row 3.7 Alt2 -->
+			<HBox fx:id="customMountPoint" GridPane.rowIndex="7" GridPane.columnIndex="0" GridPane.columnSpan="2" spacing="6">
 				<Label HBox.hgrow="NEVER" minWidth="-Infinity" text="%unlock.label.mountPath" cacheShape="true" cache="true" />
 				<Label HBox.hgrow="ALWAYS" fx:id="customMountPointField" textOverrun="LEADING_ELLIPSIS" cacheShape="true" cache="true" />
 				<Button HBox.hgrow="NEVER" minWidth="-Infinity" text="&#xf434;" styleClass="ionicons" onAction="#didClickChooseCustomMountPoint" focusTraversable="true" cacheShape="true" cache="true"/>

+ 1 - 0
main/ui/src/main/resources/localization/en.txt

@@ -73,6 +73,7 @@ unlock.label.savePassword=Save Password
 unlock.label.mountName=Drive Name
 unlock.label.unlockAfterStartup=Auto-Unlock on Start (Experimental)
 unlock.label.revealAfterMount=Reveal Drive
+unlock.label.useReadOnlyMode=Read-only
 unlock.label.winDriveLetter=Drive Letter
 unlock.label.useOwnMountPath=Use Custom Mount Point
 unlock.label.mountPath=Mount path