Prechádzať zdrojové kódy

restored bash-based webdav mounting for OS X before 10.10 (issue #211 - to be tested)

Sebastian Stenzel 9 rokov pred
rodič
commit
f16be84aa3

+ 18 - 1
main/commons/pom.xml

@@ -17,11 +17,28 @@
 	<description>Shared utilities</description>
 
 	<dependencies>
+		<!-- Libs -->
 		<dependency>
 			<groupId>com.google.guava</groupId>
 			<artifactId>guava</artifactId>
 		</dependency>
-	
+		<dependency>
+			<groupId>org.apache.commons</groupId>
+			<artifactId>commons-lang3</artifactId>
+		</dependency>
+		
+		<!-- DI -->
+		<dependency>
+			<groupId>com.google.dagger</groupId>
+			<artifactId>dagger</artifactId>
+		</dependency>
+		<dependency>
+			<groupId>com.google.dagger</groupId>
+			<artifactId>dagger-compiler</artifactId>
+			<scope>provided</scope>
+		</dependency>
+		
+		<!-- Test -->
 		<dependency>
 			<groupId>junit</groupId>
 			<artifactId>junit</artifactId>

+ 21 - 0
main/commons/src/main/java/org/cryptomator/common/CommonsModule.java

@@ -0,0 +1,21 @@
+package org.cryptomator.common;
+
+import java.util.Comparator;
+
+import javax.inject.Named;
+import javax.inject.Singleton;
+
+import dagger.Module;
+import dagger.Provides;
+
+@Module
+public class CommonsModule {
+
+	@Provides
+	@Singleton
+	@Named("SemVer")
+	Comparator<String> providesSemVerComparator() {
+		return new SemVerComparator();
+	}
+
+}

+ 1 - 1
main/ui/src/main/java/org/cryptomator/ui/util/SemVerComparator.java

@@ -6,7 +6,7 @@
  * Contributors:
  *     Sebastian Stenzel - initial API and implementation
  *******************************************************************************/
-package org.cryptomator.ui.util;
+package org.cryptomator.common;
 
 import java.util.Comparator;
 

+ 2 - 1
main/ui/src/test/java/org/cryptomator/ui/util/SemVerComparatorTest.java

@@ -6,10 +6,11 @@
  * Contributors:
  *     Sebastian Stenzel - initial API and implementation
  *******************************************************************************/
-package org.cryptomator.ui.util;
+package org.cryptomator.common;
 
 import java.util.Comparator;
 
+import org.cryptomator.common.SemVerComparator;
 import org.junit.Assert;
 import org.junit.Test;
 

+ 3 - 1
main/frontend-webdav/src/main/java/org/cryptomator/frontend/webdav/WebDavComponent.java

@@ -10,10 +10,12 @@ package org.cryptomator.frontend.webdav;
 
 import javax.inject.Singleton;
 
+import org.cryptomator.common.CommonsModule;
+
 import dagger.Component;
 
 @Singleton
-@Component
+@Component(modules = {CommonsModule.class})
 public interface WebDavComponent {
 
 	WebDavServer server();

+ 8 - 3
main/frontend-webdav/src/main/java/org/cryptomator/frontend/webdav/mount/MacOsXWebDavMounter.java

@@ -12,11 +12,13 @@ package org.cryptomator.frontend.webdav.mount;
 import java.io.IOException;
 import java.net.URI;
 import java.nio.charset.StandardCharsets;
+import java.util.Comparator;
 import java.util.Map;
 import java.util.Optional;
 import java.util.concurrent.TimeUnit;
 
 import javax.inject.Inject;
+import javax.inject.Named;
 import javax.inject.Singleton;
 
 import org.apache.commons.io.IOUtils;
@@ -26,15 +28,18 @@ import org.cryptomator.frontend.CommandFailedException;
 import org.cryptomator.frontend.Frontend.MountParam;
 
 @Singleton
-final class MacOsXWebDavMounter implements WebDavMounterStrategy {
+final class MacOsXAppleScriptWebDavMounter implements WebDavMounterStrategy {
+
+	private final Comparator<String> semVerComparator;
 
 	@Inject
-	MacOsXWebDavMounter() {
+	MacOsXAppleScriptWebDavMounter(@Named("SemVer") Comparator<String> semVerComparator) {
+		this.semVerComparator = semVerComparator;
 	}
 
 	@Override
 	public boolean shouldWork() {
-		return SystemUtils.IS_OS_MAC_OSX;
+		return SystemUtils.IS_OS_MAC_OSX && semVerComparator.compare(SystemUtils.OS_VERSION, "10.10") >= 0;
 	}
 
 	@Override

+ 89 - 0
main/frontend-webdav/src/main/java/org/cryptomator/frontend/webdav/mount/MacOsXShellScriptWebDavMounter.java

@@ -0,0 +1,89 @@
+/*******************************************************************************
+ * Copyright (c) 2014, 2016 Sebastian Stenzel, Markus Kreusch
+ * This file is licensed under the terms of the MIT license.
+ * See the LICENSE.txt file for more info.
+ * 
+ * Contributors:
+ *     Sebastian Stenzel - initial API and implementation, strategy fine tuning
+ *     Markus Kreusch - Refactored WebDavMounter to use strategy pattern
+ ******************************************************************************/
+package org.cryptomator.frontend.webdav.mount;
+
+import java.net.URI;
+import java.nio.file.FileSystems;
+import java.nio.file.Files;
+import java.util.Comparator;
+import java.util.Map;
+import java.util.Optional;
+import java.util.UUID;
+
+import javax.inject.Inject;
+import javax.inject.Named;
+import javax.inject.Singleton;
+
+import org.apache.commons.lang3.SystemUtils;
+import org.cryptomator.frontend.CommandFailedException;
+import org.cryptomator.frontend.Frontend.MountParam;
+import org.cryptomator.frontend.webdav.mount.command.Script;
+
+@Singleton
+final class MacOsXShellScriptWebDavMounter implements WebDavMounterStrategy {
+
+	private final Comparator<String> semVerComparator;
+
+	@Inject
+	MacOsXShellScriptWebDavMounter(@Named("SemVer") Comparator<String> semVerComparator) {
+		this.semVerComparator = semVerComparator;
+	}
+
+	@Override
+	public boolean shouldWork() {
+		return SystemUtils.IS_OS_MAC_OSX && semVerComparator.compare(SystemUtils.OS_VERSION, "10.10") < 0;
+	}
+
+	@Override
+	public void warmUp(int serverPort) {
+		// no-op
+	}
+
+	@Override
+	public WebDavMount mount(URI uri, Map<MountParam, Optional<String>> mountParams) throws CommandFailedException {
+		final String mountName = mountParams.getOrDefault(MountParam.MOUNT_NAME, Optional.empty()).orElseThrow(() -> {
+			return new IllegalArgumentException("Missing mount parameter MOUNT_NAME.");
+		});
+
+		// we don't use the uri to derive a path, as it *could* be longer than 255 chars.
+		final String path = "/Volumes/Cryptomator_" + UUID.randomUUID().toString();
+		final Script mountScript = Script.fromLines("mkdir \"$MOUNT_PATH\"", "mount_webdav -S -v $MOUNT_NAME \"$DAV_AUTHORITY$DAV_PATH\" \"$MOUNT_PATH\"").addEnv("DAV_AUTHORITY", uri.getRawAuthority())
+				.addEnv("DAV_PATH", uri.getRawPath()).addEnv("MOUNT_PATH", path).addEnv("MOUNT_NAME", mountName);
+		mountScript.execute();
+		return new MacWebDavMount(path);
+	}
+
+	private static class MacWebDavMount extends AbstractWebDavMount {
+		private final String mountPath;
+		private final Script revealScript;
+		private final Script unmountScript;
+
+		private MacWebDavMount(String mountPath) {
+			this.mountPath = mountPath;
+			this.revealScript = Script.fromLines("open \"$MOUNT_PATH\"").addEnv("MOUNT_PATH", mountPath);
+			this.unmountScript = Script.fromLines("diskutil umount $MOUNT_PATH").addEnv("MOUNT_PATH", mountPath);
+		}
+
+		@Override
+		public void unmount() throws CommandFailedException {
+			// only attempt unmount if user didn't unmount manually:
+			if (Files.exists(FileSystems.getDefault().getPath(mountPath))) {
+				unmountScript.execute();
+			}
+		}
+
+		@Override
+		public void reveal() throws CommandFailedException {
+			revealScript.execute();
+		}
+
+	}
+
+}

+ 19 - 6
main/frontend-webdav/src/main/java/org/cryptomator/frontend/webdav/mount/MountStrategies.java

@@ -19,74 +19,87 @@ import javax.inject.Singleton;
 
 @Singleton
 class MountStrategies implements Collection<WebDavMounterStrategy> {
-	
+
 	private final Collection<WebDavMounterStrategy> delegate;
-	
+
 	@Inject
-	MountStrategies(LinuxGvfsWebDavMounter linuxMounter, MacOsXWebDavMounter osxMounter, WindowsWebDavMounter winMounter) {
-		delegate = unmodifiableList(asList(linuxMounter, osxMounter, winMounter));
+	MountStrategies(LinuxGvfsWebDavMounter linuxMounter, MacOsXAppleScriptWebDavMounter osxAppleScriptMounter, MacOsXShellScriptWebDavMounter osxShellScriptMounter, WindowsWebDavMounter winMounter) {
+		delegate = unmodifiableList(asList(linuxMounter, osxAppleScriptMounter, osxShellScriptMounter, winMounter));
 	}
 
+	@Override
 	public int size() {
 		return delegate.size();
 	}
 
+	@Override
 	public boolean isEmpty() {
 		return delegate.isEmpty();
 	}
 
+	@Override
 	public boolean contains(Object o) {
 		return delegate.contains(o);
 	}
 
+	@Override
 	public Iterator<WebDavMounterStrategy> iterator() {
 		return delegate.iterator();
 	}
 
+	@Override
 	public Object[] toArray() {
 		return delegate.toArray();
 	}
 
+	@Override
 	public <T> T[] toArray(T[] a) {
 		return delegate.toArray(a);
 	}
 
+	@Override
 	public boolean add(WebDavMounterStrategy e) {
 		return delegate.add(e);
 	}
 
+	@Override
 	public boolean remove(Object o) {
 		return delegate.remove(o);
 	}
 
+	@Override
 	public boolean containsAll(Collection<?> c) {
 		return delegate.containsAll(c);
 	}
 
+	@Override
 	public boolean addAll(Collection<? extends WebDavMounterStrategy> c) {
 		return delegate.addAll(c);
 	}
 
+	@Override
 	public boolean removeAll(Collection<?> c) {
 		return delegate.removeAll(c);
 	}
 
+	@Override
 	public boolean retainAll(Collection<?> c) {
 		return delegate.retainAll(c);
 	}
 
+	@Override
 	public void clear() {
 		delegate.clear();
 	}
 
+	@Override
 	public boolean equals(Object o) {
 		return delegate.equals(o);
 	}
 
+	@Override
 	public int hashCode() {
 		return delegate.hashCode();
 	}
 
-
-
 }

+ 6 - 7
main/frontend-webdav/src/main/java/org/cryptomator/frontend/webdav/mount/WindowsWebDavMounter.java

@@ -60,12 +60,12 @@ final class WindowsWebDavMounter implements WebDavMounterStrategy {
 
 	@Override
 	public WebDavMount mount(URI uri, Map<MountParam, Optional<String>> mountParams) throws CommandFailedException {
-		final String driveLetter = mountParams.getOrDefault(MountParam.WIN_DRIVE_LETTER, Optional.of(AUTO_ASSIGN_DRIVE_LETTER)).orElse(AUTO_ASSIGN_DRIVE_LETTER);
+		final String driveLetter = mountParams.getOrDefault(MountParam.WIN_DRIVE_LETTER, Optional.empty()).orElse(AUTO_ASSIGN_DRIVE_LETTER);
 		if (driveLetters.getOccupiedDriveLetters().contains(CharUtils.toChar(driveLetter))) {
 			throw new CommandFailedException("Drive letter occupied.");
 		}
-		
-		final String hostname = mountParams.getOrDefault(MountParam.HOSTNAME, Optional.of(LOCALHOST)).orElse(LOCALHOST);
+
+		final String hostname = mountParams.getOrDefault(MountParam.HOSTNAME, Optional.empty()).orElse(LOCALHOST);
 		try {
 			final URI adjustedUri = new URI(uri.getScheme(), uri.getUserInfo(), hostname, uri.getPort(), uri.getPath(), uri.getQuery(), uri.getFragment());
 			CommandResult mountResult = mount(adjustedUri, driveLetter);
@@ -74,14 +74,13 @@ final class WindowsWebDavMounter implements WebDavMounterStrategy {
 			throw new IllegalArgumentException("Invalid host: " + hostname);
 		}
 	}
-	
+
 	private CommandResult mount(URI uri, String driveLetter) throws CommandFailedException {
-		final Script proxyBypassScript = fromLines(
-				"reg add \"HKCU\\Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings\" /v \"ProxyOverride\" /d \"<local>;%DAV_HOST%;%DAV_HOST%:%DAV_PORT%\" /f");
+		final Script proxyBypassScript = fromLines("reg add \"HKCU\\Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings\" /v \"ProxyOverride\" /d \"<local>;%DAV_HOST%;%DAV_HOST%:%DAV_PORT%\" /f");
 		proxyBypassScript.addEnv("DAV_HOST", uri.getHost());
 		proxyBypassScript.addEnv("DAV_PORT", String.valueOf(uri.getPort()));
 		proxyBypassScript.execute();
-		
+
 		final String driveLetterStr = AUTO_ASSIGN_DRIVE_LETTER.equals(driveLetter) ? AUTO_ASSIGN_DRIVE_LETTER : driveLetter + ":";
 		final Script mountScript = fromLines("net use %DRIVE_LETTER% \\\\%DAV_HOST%@%DAV_PORT%\\DavWWWRoot%DAV_UNC_PATH% /persistent:no");
 		mountScript.addEnv("DRIVE_LETTER", driveLetterStr);

+ 2 - 2
main/pom.xml

@@ -35,12 +35,12 @@
 		<hamcrest.version>1.3</hamcrest.version> <!-- keep in sync with version required by JUnit -->
 		<commons-io.version>2.4</commons-io.version>
 		<commons-collections.version>4.0</commons-collections.version>
-		<commons-lang3.version>3.3.2</commons-lang3.version>
+		<commons-lang3.version>3.4</commons-lang3.version>
 		<commons-codec.version>1.10</commons-codec.version>
 		<commons-httpclient.version>3.1</commons-httpclient.version>
 		<jackson-databind.version>2.4.4</jackson-databind.version>
 		<mockito.version>1.10.19</mockito.version>
-		<dagger.version>2.0.2</dagger.version>
+		<dagger.version>2.4</dagger.version>
 	</properties>
 
 	<repositories>

+ 2 - 10
main/ui/src/main/java/org/cryptomator/ui/CryptomatorModule.java

@@ -8,13 +8,13 @@
  *******************************************************************************/
 package org.cryptomator.ui;
 
-import java.util.Comparator;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
 
 import javax.inject.Named;
 import javax.inject.Singleton;
 
+import org.cryptomator.common.CommonsModule;
 import org.cryptomator.crypto.engine.impl.CryptoEngineModule;
 import org.cryptomator.frontend.FrontendFactory;
 import org.cryptomator.frontend.webdav.WebDavServer;
@@ -24,7 +24,6 @@ import org.cryptomator.ui.model.VaultObjectMapperProvider;
 import org.cryptomator.ui.settings.Settings;
 import org.cryptomator.ui.settings.SettingsProvider;
 import org.cryptomator.ui.util.DeferredCloser;
-import org.cryptomator.ui.util.SemVerComparator;
 
 import com.fasterxml.jackson.databind.ObjectMapper;
 
@@ -33,7 +32,7 @@ import dagger.Provides;
 import javafx.application.Application;
 import javafx.stage.Stage;
 
-@Module(includes = CryptoEngineModule.class)
+@Module(includes = {CryptoEngineModule.class, CommonsModule.class})
 class CryptomatorModule {
 
 	private final Application application;
@@ -65,13 +64,6 @@ class CryptomatorModule {
 		return closer;
 	}
 
-	@Provides
-	@Singleton
-	@Named("SemVer")
-	Comparator<String> provideSemVerComparator() {
-		return new SemVerComparator();
-	}
-
 	@Provides
 	@Singleton
 	@Named("VaultJsonMapper")