瀏覽代碼

Merge branch 'feature/NewMigrationFlow' into develop

Sebastian Stenzel 5 年之前
父節點
當前提交
3618c4b8db

+ 1 - 1
.idea/compiler.xml

@@ -32,9 +32,9 @@
           <entry name="$MAVEN_REPOSITORY$/org/jetbrains/kotlinx/kotlinx-metadata-jvm/0.1.0/kotlinx-metadata-jvm-0.1.0.jar" />
         </processorPath>
         <module name="keychain" />
+        <module name="launcher" />
         <module name="commons" />
         <module name="ui" />
-        <module name="launcher" />
       </profile>
     </annotationProcessing>
   </component>

+ 3 - 0
.idea/runConfigurations/Cryptomator_macOS.xml

@@ -1,5 +1,8 @@
 <component name="ProjectRunConfigurationManager">
   <configuration default="false" name="Cryptomator macOS" type="Application" factoryName="Application">
+    <envs>
+      <env name="LD_LIBRARY_PATH" value="/usr/local/lib" />
+    </envs>
     <option name="MAIN_CLASS_NAME" value="org.cryptomator.launcher.Cryptomator" />
     <module name="launcher" />
     <option name="WORKING_DIRECTORY" value="$PROJECT_DIR$" />

+ 9 - 6
main/commons/src/main/java/org/cryptomator/common/settings/VaultSettings.java

@@ -9,23 +9,20 @@ import com.google.common.base.Strings;
 import com.google.common.io.BaseEncoding;
 import javafx.beans.Observable;
 import javafx.beans.property.BooleanProperty;
+import javafx.beans.property.IntegerProperty;
 import javafx.beans.property.ObjectProperty;
 import javafx.beans.property.SimpleBooleanProperty;
+import javafx.beans.property.SimpleIntegerProperty;
 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.ByteBuffer;
-import java.nio.charset.StandardCharsets;
 import java.nio.file.Path;
-import java.util.Base64;
-import java.util.List;
 import java.util.Objects;
 import java.util.Optional;
 import java.util.Random;
-import java.util.UUID;
 
 /**
  * The settings specific to a single vault.
@@ -38,6 +35,7 @@ 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 int DEFAULT_FILENAME_LENGTH_LIMIT = -1;
 	
 	private static final Random RNG = new Random(); 
 
@@ -51,6 +49,7 @@ public class VaultSettings {
 	private final StringProperty individualMountPath = new SimpleStringProperty();
 	private final BooleanProperty usesReadOnlyMode = new SimpleBooleanProperty(DEFAULT_USES_READONLY_MODE);
 	private final StringProperty mountFlags = new SimpleStringProperty(DEFAULT_MOUNT_FLAGS);
+	private final IntegerProperty filenameLengthLimit = new SimpleIntegerProperty(DEFAULT_FILENAME_LENGTH_LIMIT);
 
 	public VaultSettings(String id) {
 		this.id = Objects.requireNonNull(id);
@@ -59,7 +58,7 @@ public class VaultSettings {
 	}
 
 	Observable[] observables() {
-		return new Observable[]{path, mountName, winDriveLetter, unlockAfterStartup, revealAfterMount, usesIndividualMountPath, individualMountPath, usesReadOnlyMode, mountFlags};
+		return new Observable[]{path, mountName, winDriveLetter, unlockAfterStartup, revealAfterMount, usesIndividualMountPath, individualMountPath, usesReadOnlyMode, mountFlags, filenameLengthLimit};
 	}
 
 	private void deriveMountNameFromPath(Path path) {
@@ -146,6 +145,10 @@ public class VaultSettings {
 	public StringProperty mountFlags() {
 		return mountFlags;
 	}
+	
+	public IntegerProperty filenameLengthLimit() {
+		return filenameLengthLimit;
+	}
 
 	/* Hashcode/Equals */
 

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

@@ -29,6 +29,7 @@ class VaultSettingsJsonAdapter {
 		out.name("individualMountPath").value(value.individualMountPath().get());
 		out.name("usesReadOnlyMode").value(value.usesReadOnlyMode().get());
 		out.name("mountFlags").value(value.mountFlags().get());
+		out.name("filenameLengthLimit").value(value.filenameLengthLimit().get());
 		out.endObject();
 	}
 
@@ -43,6 +44,7 @@ class VaultSettingsJsonAdapter {
 		boolean usesIndividualMountPath = VaultSettings.DEFAULT_USES_INDIVIDUAL_MOUNTPATH;
 		boolean usesReadOnlyMode = VaultSettings.DEFAULT_USES_READONLY_MODE;
 		String mountFlags = VaultSettings.DEFAULT_MOUNT_FLAGS;
+		int filenameLengthLimit = VaultSettings.DEFAULT_FILENAME_LENGTH_LIMIT;
 
 		in.beginObject();
 		while (in.hasNext()) {
@@ -78,6 +80,9 @@ class VaultSettingsJsonAdapter {
 				case "mountFlags":
 					mountFlags = in.nextString();
 					break;
+				case "filenameLengthLimit":
+					filenameLengthLimit = in.nextInt();
+					break;
 				default:
 					LOG.warn("Unsupported vault setting found in JSON: " + name);
 					in.skipValue();
@@ -96,6 +101,7 @@ class VaultSettingsJsonAdapter {
 		vaultSettings.individualMountPath().set(individualMountPath);
 		vaultSettings.usesReadOnlyMode().set(usesReadOnlyMode);
 		vaultSettings.mountFlags().set(mountFlags);
+		vaultSettings.filenameLengthLimit().set(filenameLengthLimit);
 		return vaultSettings;
 	}
 

+ 11 - 0
main/commons/src/main/java/org/cryptomator/common/vaults/Vault.java

@@ -21,6 +21,8 @@ import org.cryptomator.cryptofs.CryptoFileSystem;
 import org.cryptomator.cryptofs.CryptoFileSystemProperties;
 import org.cryptomator.cryptofs.CryptoFileSystemProperties.FileSystemFlags;
 import org.cryptomator.cryptofs.CryptoFileSystemProvider;
+import org.cryptomator.cryptofs.common.Constants;
+import org.cryptomator.cryptofs.common.FileSystemCapabilityChecker;
 import org.cryptomator.cryptolib.api.CryptoException;
 import org.cryptomator.cryptolib.api.InvalidPassphraseException;
 import org.slf4j.Logger;
@@ -101,10 +103,19 @@ public class Vault {
 		if (vaultSettings.usesReadOnlyMode().get()) {
 			flags.add(FileSystemFlags.READONLY);
 		}
+		if (vaultSettings.filenameLengthLimit().get() == -1) {
+			LOG.debug("Determining file name length limitations...");
+			int limit = new FileSystemCapabilityChecker().determineSupportedFileNameLength(getPath());
+			vaultSettings.filenameLengthLimit().set(limit);
+			LOG.info("Storing file name length limit of {}", limit);
+		}
+		assert vaultSettings.filenameLengthLimit().get() > 0;
 		CryptoFileSystemProperties fsProps = CryptoFileSystemProperties.cryptoFileSystemProperties() //
 				.withPassphrase(passphrase) //
 				.withFlags(flags) //
 				.withMasterkeyFilename(MASTERKEY_FILENAME) //
+				.withMaxPathLength(vaultSettings.filenameLengthLimit().get() + Constants.MAX_ADDITIONAL_PATH_LENGTH) //
+				.withMaxNameLength(vaultSettings.filenameLengthLimit().get()) //
 				.build();
 		return CryptoFileSystemProvider.newFileSystem(getPath(), fsProps);
 	}

+ 3 - 3
main/pom.xml

@@ -24,11 +24,11 @@
 		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
 
 		<!-- cryptomator dependencies -->
-		<cryptomator.cryptofs.version>1.9.7</cryptomator.cryptofs.version>
+		<cryptomator.cryptofs.version>1.9.9</cryptomator.cryptofs.version>
 		<cryptomator.jni.version>2.2.2</cryptomator.jni.version>
 		<cryptomator.fuse.version>1.2.3</cryptomator.fuse.version>
-		<cryptomator.dokany.version>1.1.13</cryptomator.dokany.version>
-		<cryptomator.webdav.version>1.0.10</cryptomator.webdav.version>
+		<cryptomator.dokany.version>1.1.14</cryptomator.dokany.version>
+		<cryptomator.webdav.version>1.0.11</cryptomator.webdav.version>
 
 		<!-- 3rd party dependencies -->
 		<javafx.version>14</javafx.version>

+ 1 - 0
main/ui/src/main/java/org/cryptomator/ui/common/FxmlFile.java

@@ -13,6 +13,7 @@ public enum FxmlFile {
 	FORGET_PASSWORD("/fxml/forget_password.fxml"), //
 	MAIN_WINDOW("/fxml/main_window.fxml"), //
 	MIGRATION_CAPABILITY_ERROR("/fxml/migration_capability_error.fxml"), //
+	MIGRATION_IMPOSSIBLE("/fxml/migration_impossible.fxml"),
 	MIGRATION_RUN("/fxml/migration_run.fxml"), //
 	MIGRATION_START("/fxml/migration_start.fxml"), //
 	MIGRATION_SUCCESS("/fxml/migration_success.fxml"), //

+ 46 - 0
main/ui/src/main/java/org/cryptomator/ui/migration/MigrationImpossibleController.java

@@ -0,0 +1,46 @@
+package org.cryptomator.ui.migration;
+
+import javafx.fxml.FXML;
+import javafx.stage.Stage;
+import org.cryptomator.common.vaults.Vault;
+import org.cryptomator.ui.common.FxController;
+import org.cryptomator.ui.fxapp.FxApplication;
+
+import javax.inject.Inject;
+
+public class MigrationImpossibleController implements FxController {
+
+	private static final String HELP_URI = "https://docs.cryptomator.org/en/1.5/help/manual-migration/";
+
+	private final FxApplication fxApplication;
+	private final Stage window;
+	private final Vault vault;
+
+	@Inject
+	MigrationImpossibleController(FxApplication fxApplication, @MigrationWindow Stage window, @MigrationWindow Vault vault) {
+		this.fxApplication = fxApplication;
+		this.window = window;
+		this.vault = vault;
+	}
+
+	@FXML
+	public void close() {
+		window.close();
+	}
+
+	@FXML
+	public void getMigrationHelp() {
+		fxApplication.getHostServices().showDocument(HELP_URI);
+	}
+
+	/* Getter/Setters */
+
+	public Vault getVault() {
+		return vault;
+	}
+
+	public String getHelpUri() {
+		return HELP_URI;
+	}
+
+}

+ 12 - 1
main/ui/src/main/java/org/cryptomator/ui/migration/MigrationModule.java

@@ -83,6 +83,13 @@ abstract class MigrationModule {
 		return fxmlLoaders.createScene("/fxml/migration_capability_error.fxml");
 	}
 
+	@Provides
+	@FxmlScene(FxmlFile.MIGRATION_IMPOSSIBLE)
+	@MigrationScoped
+	static Scene provideMigrationImpossibleScene(@MigrationWindow FXMLLoaderFactory fxmlLoaders) {
+		return fxmlLoaders.createScene("/fxml/migration_impossible.fxml");
+	}
+
 	// ------------------
 
 	@Binds
@@ -104,5 +111,9 @@ abstract class MigrationModule {
 	@IntoMap
 	@FxControllerKey(MigrationCapabilityErrorController.class)
 	abstract FxController bindMigrationCapabilityErrorController(MigrationCapabilityErrorController controller);
-	
+
+	@Binds
+	@IntoMap
+	@FxControllerKey(MigrationImpossibleController.class)
+	abstract FxController bindMigrationImpossibleController(MigrationImpossibleController controller);
 }

文件差異過大導致無法顯示
+ 20 - 3
main/ui/src/main/java/org/cryptomator/ui/migration/MigrationRunController.java


+ 5 - 1
main/ui/src/main/java/org/cryptomator/ui/unlock/UnlockController.java

@@ -73,7 +73,7 @@ public class UnlockController implements FxController {
 		if (keychainAccess.isPresent()) {
 			loadStoredPassword();
 		} else {
-			savePassword.setDisable(true);
+			savePassword.setSelected(false);
 		}
 		unlockButtonDisabled.bind(vault.stateProperty().isNotEqualTo(VaultState.LOCKED).or(passwordField.textProperty().isEmpty()));
 	}
@@ -187,4 +187,8 @@ public class UnlockController implements FxController {
 	public boolean isUnlockButtonDisabled() {
 		return unlockButtonDisabled.get();
 	}
+
+	public boolean isKeychainAccessAvailable() {
+		return keychainAccess.isPresent();
+	}
 }

+ 1 - 1
main/ui/src/main/resources/css/dark_theme.css

@@ -854,7 +854,7 @@
 .progress-bar > .bar {
 	-fx-background-color: CONTROL_PRIMARY_BG_NORMAL;
 	-fx-background-radius: 4px;
-	-fx-padding: 0.5em;
+	-fx-padding: 1em 0.5em;
 }
 
 .progress-bar:indeterminate > .bar {

+ 1 - 1
main/ui/src/main/resources/css/light_theme.css

@@ -853,7 +853,7 @@
 .progress-bar > .bar {
 	-fx-background-color: CONTROL_PRIMARY_BG_NORMAL;
 	-fx-background-radius: 4px;
-	-fx-padding: 0.5em;
+	-fx-padding: 1em 0.5em;
 }
 
 .progress-bar:indeterminate > .bar {

+ 52 - 0
main/ui/src/main/resources/fxml/migration_impossible.fxml

@@ -0,0 +1,52 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+
+<?import javafx.geometry.Insets?>
+<?import javafx.scene.control.Button?>
+<?import javafx.scene.control.ButtonBar?>
+<?import javafx.scene.control.Hyperlink?>
+<?import javafx.scene.control.Label?>
+<?import javafx.scene.layout.HBox?>
+<?import javafx.scene.layout.StackPane?>
+<?import javafx.scene.layout.VBox?>
+<?import javafx.scene.shape.Circle?>
+<?import javafx.scene.text.Text?>
+<?import javafx.scene.text.TextFlow?>
+<?import org.cryptomator.ui.controls.FontAwesome5IconView?>
+<VBox xmlns="http://javafx.com/javafx"
+	  xmlns:fx="http://javafx.com/fxml"
+	  fx:controller="org.cryptomator.ui.migration.MigrationImpossibleController"
+	  minWidth="400"
+	  maxWidth="400"
+	  minHeight="145"
+	  spacing="12">
+	<padding>
+		<Insets topRightBottomLeft="12"/>
+	</padding>
+
+	<HBox spacing="12" alignment="CENTER_LEFT" VBox.vgrow="ALWAYS">
+		<StackPane alignment="CENTER" HBox.hgrow="NEVER">
+			<Circle styleClass="glyph-icon-red" radius="24"/>
+			<FontAwesome5IconView styleClass="glyph-icon-white" glyph="TIMES" glyphSize="24"/>
+		</StackPane>
+		<VBox spacing="6">
+			<Label styleClass="label-large" text="%migration.impossible.heading"/>
+			<Label text="%migration.impossible.reason" wrapText="true" HBox.hgrow="ALWAYS"/>
+			<TextFlow>
+				<Text text="%migration.impossible.moreInfo"/>
+				<Text text=" "/>
+				<Hyperlink styleClass="hyperlink-underline" text="docs.cryptomator.org" wrapText="true" onAction="#getMigrationHelp"/>
+				<Text text="."/>
+			</TextFlow>
+		</VBox>
+	</HBox>
+
+	<VBox alignment="BOTTOM_CENTER" VBox.vgrow="ALWAYS">
+		<ButtonBar buttonMinWidth="120" buttonOrder="+C">
+			<buttons>
+				<!-- Button text="Try again" ButtonBar.buttonData="to do" onAction="#retry" / also add button to button bar order-->
+				<Button text="%generic.button.close" ButtonBar.buttonData="CANCEL_CLOSE" cancelButton="true" onAction="#close"/>
+			</buttons>
+		</ButtonBar>
+	</VBox>
+</VBox>

+ 7 - 3
main/ui/src/main/resources/fxml/migration_run.fxml

@@ -3,6 +3,7 @@
 <?import javafx.geometry.Insets?>
 <?import javafx.scene.control.Button?>
 <?import javafx.scene.control.ButtonBar?>
+<?import javafx.scene.control.Label?>
 <?import javafx.scene.control.ProgressBar?>
 <?import javafx.scene.control.ProgressIndicator?>
 <?import javafx.scene.layout.VBox?>
@@ -19,17 +20,20 @@
 		<Insets topRightBottomLeft="12"/>
 	</padding>
 	<children>
-		<VBox spacing="6">
+		<VBox spacing="6" visible="${!controller.vault.processing}" managed="${!controller.vault.processing}">
 			<FormattedLabel format="%migration.run.enterPassword" arg1="${controller.vault.displayableName}" wrapText="true"/>
 			<NiceSecurePasswordField fx:id="passwordField"/>
 		</VBox>
 
-		<ProgressBar progress="${controller.migrationProgress}" prefWidth="Infinity" visible="${controller.vault.processing}"/>
+		<VBox spacing="6" visible="${controller.vault.processing}" managed="${controller.vault.processing}">
+			<Label text="%migration.run.progressHint" wrapText="true"/>
+			<ProgressBar progress="${controller.migrationProgress}" prefWidth="Infinity"/>
+		</VBox>
 
 		<VBox alignment="BOTTOM_CENTER" VBox.vgrow="ALWAYS">
 			<ButtonBar buttonMinWidth="120" buttonOrder="B+X">
 				<buttons>
-					<Button text="%generic.button.back" ButtonBar.buttonData="BACK_PREVIOUS" cancelButton="true" onAction="#back"/>
+					<Button text="%generic.button.back" ButtonBar.buttonData="BACK_PREVIOUS" cancelButton="true" onAction="#back" disable="${controller.vault.processing}"/>
 					<Button text="%migration.run.startMigrationBtn" ButtonBar.buttonData="NEXT_FORWARD" defaultButton="true" onAction="#migrate" contentDisplay="${controller.migrateButtonContentDisplay}"
 							disable="${controller.migrationButtonDisabled}">
 						<graphic>

+ 2 - 2
main/ui/src/main/resources/fxml/unlock.fxml

@@ -22,13 +22,13 @@
 		<VBox spacing="6">
 			<FormattedLabel format="%unlock.passwordPrompt" arg1="${controller.vault.displayableName}" wrapText="true"/>
 			<NiceSecurePasswordField fx:id="passwordField"/>
-			<CheckBox fx:id="savePassword" text="%unlock.savePassword" onAction="#didClickSavePasswordCheckbox"/>
+			<CheckBox fx:id="savePassword" text="%unlock.savePassword" onAction="#didClickSavePasswordCheckbox" disable="${controller.vault.processing}" visible="${controller.keychainAccessAvailable}"/>
 		</VBox>
 
 		<VBox alignment="BOTTOM_CENTER" VBox.vgrow="ALWAYS">
 			<ButtonBar buttonMinWidth="120" buttonOrder="+CI">
 				<buttons>
-					<Button text="%generic.button.cancel" ButtonBar.buttonData="CANCEL_CLOSE" cancelButton="true" onAction="#cancel"/>
+					<Button text="%generic.button.cancel" ButtonBar.buttonData="CANCEL_CLOSE" cancelButton="true" onAction="#cancel" disable="${controller.vault.processing}"/>
 					<Button text="%unlock.unlockBtn" ButtonBar.buttonData="FINISH" defaultButton="true" onAction="#unlock" contentDisplay="${controller.unlockButtonState}" disable="${controller.unlockButtonDisabled}">
 						<graphic>
 							<ProgressIndicator progress="-1" prefWidth="12" prefHeight="12"/>

+ 5 - 0
main/ui/src/main/resources/i18n/strings.properties

@@ -108,6 +108,7 @@ migration.start.confirm=Yes, my vault is fully synced
 ## Run
 migration.run.enterPassword=Enter the password for "%s"
 migration.run.startMigrationBtn=Migrate Vault
+migration.run.progressHint=This might take some time…
 ## Sucess
 migration.success.nextStepsInstructions=Migrated "%s" successfully.\nYou can now unlock your vault.
 migration.success.unlockNow=Unlock Now
@@ -118,6 +119,10 @@ migration.error.missingFileSystemCapabilities.reason.LONG_FILENAMES=The file sys
 migration.error.missingFileSystemCapabilities.reason.LONG_PATHS=The file system does not support long paths.
 migration.error.missingFileSystemCapabilities.reason.READ_ACCESS=The file system does not allow to be read.
 migration.error.missingFileSystemCapabilities.reason.WRITE_ACCESS=The file system does not allow to be written to.
+## Impossible
+migration.impossible.heading=Unable to migrate vault
+migration.impossible.reason=The vault cannot be automatically migrated because its storage location or access point is not compatible.
+migration.impossible.moreInfo=The vault can still be opened with an older version. For instructions on how to manually migrate a vault, visit
 
 # Preferences
 preferences.title=Preferences

+ 19 - 18
main/ui/src/main/resources/license/THIRD-PARTY.txt

@@ -11,7 +11,7 @@ GNU General Public License for more details.
 You should have received a copy of the GNU General Public License
 along with this program.  If not, see http://www.gnu.org/licenses/.
 
-Cryptomator uses 49 third-party dependencies under the following licenses:
+Cryptomator uses 50 third-party dependencies under the following licenses:
 	Apache License v2.0:
 		- HKDF-RFC5869 (at.favre.lib:hkdf:1.0.2 - https://github.com/patrickfav/hkdf)
 		- jffi (com.github.jnr:jffi:1.2.23 - http://github.com/jnr/jffi)
@@ -32,15 +32,16 @@ Cryptomator uses 49 third-party dependencies under the following licenses:
 		- Java Native Access (net.java.dev.jna:jna:5.1.0 - https://github.com/java-native-access/jna)
 		- Java Native Access Platform (net.java.dev.jna:jna-platform:5.1.0 - https://github.com/java-native-access/jna)
 		- Apache Commons Lang (org.apache.commons:commons-lang3:3.9 - http://commons.apache.org/proper/commons-lang/)
-		- Jackrabbit WebDAV Library (org.apache.jackrabbit:jackrabbit-webdav:2.19.0 - http://jackrabbit.apache.org/jackrabbit-webdav/)
-		- Jetty :: Http Utility (org.eclipse.jetty:jetty-http:9.4.17.v20190418 - http://www.eclipse.org/jetty)
-		- Jetty :: IO Utility (org.eclipse.jetty:jetty-io:9.4.17.v20190418 - http://www.eclipse.org/jetty)
-		- Jetty :: Security (org.eclipse.jetty:jetty-security:9.4.17.v20190418 - http://www.eclipse.org/jetty)
-		- Jetty :: Server Core (org.eclipse.jetty:jetty-server:9.4.17.v20190418 - http://www.eclipse.org/jetty)
-		- Jetty :: Servlet Handling (org.eclipse.jetty:jetty-servlet:9.4.17.v20190418 - http://www.eclipse.org/jetty)
-		- Jetty :: Utilities (org.eclipse.jetty:jetty-util:9.4.17.v20190418 - http://www.eclipse.org/jetty)
-		- Jetty :: Webapp Application Support (org.eclipse.jetty:jetty-webapp:9.4.17.v20190418 - http://www.eclipse.org/jetty)
-		- Jetty :: XML utilities (org.eclipse.jetty:jetty-xml:9.4.17.v20190418 - http://www.eclipse.org/jetty)
+		- Apache HttpCore (org.apache.httpcomponents:httpcore:4.4.13 - http://hc.apache.org/httpcomponents-core-ga)
+		- Jackrabbit WebDAV Library (org.apache.jackrabbit:jackrabbit-webdav:2.21.0 - http://jackrabbit.apache.org/jackrabbit-webdav/)
+		- Jetty :: Http Utility (org.eclipse.jetty:jetty-http:9.4.28.v20200408 - http://www.eclipse.org/jetty)
+		- Jetty :: IO Utility (org.eclipse.jetty:jetty-io:9.4.28.v20200408 - http://www.eclipse.org/jetty)
+		- Jetty :: Security (org.eclipse.jetty:jetty-security:9.4.28.v20200408 - http://www.eclipse.org/jetty)
+		- Jetty :: Server Core (org.eclipse.jetty:jetty-server:9.4.28.v20200408 - http://www.eclipse.org/jetty)
+		- Jetty :: Servlet Handling (org.eclipse.jetty:jetty-servlet:9.4.28.v20200408 - http://www.eclipse.org/jetty)
+		- Jetty :: Utilities (org.eclipse.jetty:jetty-util:9.4.28.v20200408 - http://www.eclipse.org/jetty)
+		- Jetty :: Webapp Application Support (org.eclipse.jetty:jetty-webapp:9.4.28.v20200408 - http://www.eclipse.org/jetty)
+		- Jetty :: XML utilities (org.eclipse.jetty:jetty-xml:9.4.28.v20200408 - http://www.eclipse.org/jetty)
 	BSD:
 		- asm (org.ow2.asm:asm:7.1 - http://asm.ow2.org/)
 		- asm-analysis (org.ow2.asm:asm-analysis:7.1 - http://asm.ow2.org/)
@@ -48,14 +49,14 @@ Cryptomator uses 49 third-party dependencies under the following licenses:
 		- asm-tree (org.ow2.asm:asm-tree:7.1 - http://asm.ow2.org/)
 		- asm-util (org.ow2.asm:asm-util:7.1 - http://asm.ow2.org/)
 	Eclipse Public License - Version 1.0:
-		- Jetty :: Http Utility (org.eclipse.jetty:jetty-http:9.4.17.v20190418 - http://www.eclipse.org/jetty)
-		- Jetty :: IO Utility (org.eclipse.jetty:jetty-io:9.4.17.v20190418 - http://www.eclipse.org/jetty)
-		- Jetty :: Security (org.eclipse.jetty:jetty-security:9.4.17.v20190418 - http://www.eclipse.org/jetty)
-		- Jetty :: Server Core (org.eclipse.jetty:jetty-server:9.4.17.v20190418 - http://www.eclipse.org/jetty)
-		- Jetty :: Servlet Handling (org.eclipse.jetty:jetty-servlet:9.4.17.v20190418 - http://www.eclipse.org/jetty)
-		- Jetty :: Utilities (org.eclipse.jetty:jetty-util:9.4.17.v20190418 - http://www.eclipse.org/jetty)
-		- Jetty :: Webapp Application Support (org.eclipse.jetty:jetty-webapp:9.4.17.v20190418 - http://www.eclipse.org/jetty)
-		- Jetty :: XML utilities (org.eclipse.jetty:jetty-xml:9.4.17.v20190418 - http://www.eclipse.org/jetty)
+		- Jetty :: Http Utility (org.eclipse.jetty:jetty-http:9.4.28.v20200408 - http://www.eclipse.org/jetty)
+		- Jetty :: IO Utility (org.eclipse.jetty:jetty-io:9.4.28.v20200408 - http://www.eclipse.org/jetty)
+		- Jetty :: Security (org.eclipse.jetty:jetty-security:9.4.28.v20200408 - http://www.eclipse.org/jetty)
+		- Jetty :: Server Core (org.eclipse.jetty:jetty-server:9.4.28.v20200408 - http://www.eclipse.org/jetty)
+		- Jetty :: Servlet Handling (org.eclipse.jetty:jetty-servlet:9.4.28.v20200408 - http://www.eclipse.org/jetty)
+		- Jetty :: Utilities (org.eclipse.jetty:jetty-util:9.4.28.v20200408 - http://www.eclipse.org/jetty)
+		- Jetty :: Webapp Application Support (org.eclipse.jetty:jetty-webapp:9.4.28.v20200408 - http://www.eclipse.org/jetty)
+		- Jetty :: XML utilities (org.eclipse.jetty:jetty-xml:9.4.28.v20200408 - http://www.eclipse.org/jetty)
 	Eclipse Public License - v 2.0:
 		- jnr-posix (com.github.jnr:jnr-posix:3.0.54 - http://nexus.sonatype.org/oss-repository-hosting.html/jnr-posix)
 	GPLv2: