From 3e961dabddf0694a3ade05f151ca90c118e22ffa Mon Sep 17 00:00:00 2001 From: Tobias Hagemann Date: Fri, 21 Jul 2017 15:49:56 +0200 Subject: [PATCH 01/33] updated readme [ci skip] --- CONTRIBUTING.md | 13 +------------ README.md | 9 +-------- SUPPORT.md | 10 ++++++++++ 3 files changed, 12 insertions(+), 20 deletions(-) create mode 100644 SUPPORT.md diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index fb80dfd30..a1165ce99 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -4,20 +4,9 @@ - Ensure you're running the latest version of Cryptomator. - Ensure the bug is related to the desktop version of Cryptomator. Bugs concerning the Cryptomator iOS and Android app can be reported on the [Cryptomator for iOS issues list](https://github.com/cryptomator/cryptomator-ios/issues) and [Cryptomator for Android issues list](https://github.com/cryptomator/cryptomator-android/issues) respectively. -- Ensure the bug was not [already reported](https://github.com/cryptomator/cryptomator/issues). You can also check out our [knowledge base](https://cryptomator.freshdesk.com/support/solutions) and our [Wiki](https://github.com/cryptomator/cryptomator/wiki). +- Ensure the bug was not [already reported](https://github.com/cryptomator/cryptomator/issues). You can also check out our [FAQ](https://community.cryptomator.org/c/faq). - If you're unable to find an open issue addressing the problem, [submit a new one](https://github.com/cryptomator/cryptomator/issues/new). -## Do you have questions? - -- Ask questions by [submitting a new issue](https://github.com/cryptomator/cryptomator/issues/new). -- [Contact us](https://cryptomator.org/contact/) directly by writing an email. Wir sprechen auch Deutsch! -- Have a chat with us on [Gitter](https://gitter.im/cryptomator/cryptomator). - -## Do you miss a feature? - -- Ensure the feature was not [already requested](https://github.com/cryptomator/cryptomator/issues). -- You're welcome to suggest a feature by [submitting a new issue](https://github.com/cryptomator/cryptomator/issues/new). - ## Did you write a patch that fixes a bug? - Open a new pull request with the patch. diff --git a/README.md b/README.md index cd3bbc835..a34f22ba9 100644 --- a/README.md +++ b/README.md @@ -6,6 +6,7 @@ [![Twitter](https://img.shields.io/badge/twitter-@Cryptomator-blue.svg?style=flat)](http://twitter.com/Cryptomator) [![POEditor](https://img.shields.io/badge/POEditor-Help%20Translate-blue.svg?style=flat)](https://poeditor.com/join/project/bHwbvJmx0E) [![Latest Release](https://img.shields.io/github/release/cryptomator/cryptomator.svg)](https://github.com/cryptomator/cryptomator/releases/latest) +[![Community](https://img.shields.io/badge/help-Community-orange.svg)](https://community.cryptomator.org) Multi-platform transparent client-side encryption of your files in the cloud. @@ -58,14 +59,6 @@ mvn clean install -Prelease An executable jar file will be created inside `main/uber-jar/target`. -## Contributing to Cryptomator - -Please read our [contribution guide](https://github.com/cryptomator/cryptomator/blob/master/CONTRIBUTING.md), if you would like to report a bug, ask a question or help us with coding. - -## Code of Conduct - -Help us keep Cryptomator open and inclusive. Please read and follow our [Code of Conduct](https://github.com/cryptomator/cryptomator/blob/master/CODE_OF_CONDUCT.md). - ## License This project is dual-licensed under the GPLv3 for FOSS projects as well as a commercial license for independent software vendors and resellers. If you want to modify this application under different conditions, feel free to contact our support team. diff --git a/SUPPORT.md b/SUPPORT.md new file mode 100644 index 000000000..cdbc8ff88 --- /dev/null +++ b/SUPPORT.md @@ -0,0 +1,10 @@ +# Support for Cryptomator + +For development-related topics, GitHub is the right place. + +For _everything else_, please visit our official [Cryptomator Community](https://community.cryptomator.org) (we are there, too :wink:). Amongst others, you will find: + +- Installation manuals +- Usage guides +- Help with problems +- Tips & tricks From cd3cf3da0e038c55b636659210013b86ef09194d Mon Sep 17 00:00:00 2001 From: Tobias Hagemann Date: Fri, 21 Jul 2017 16:11:04 +0200 Subject: [PATCH 02/33] updated issue template [ci skip] --- ISSUE_TEMPLATE.md | 24 ++++++++---------------- 1 file changed, 8 insertions(+), 16 deletions(-) diff --git a/ISSUE_TEMPLATE.md b/ISSUE_TEMPLATE.md index 0aa4dfbbd..7ecde70d4 100644 --- a/ISSUE_TEMPLATE.md +++ b/ISSUE_TEMPLATE.md @@ -1,24 +1,14 @@ -To tick a checkbox replace [ ] with [x]. Make sure to replace placeholders (…) accordingly. - ## Issue Checklist Before creating a new issue make sure that you -- [ ] searched [existing (and closed) issues](https://github.com/cryptomator/cryptomator/issues). -- [ ] searched the [knowledge base](https://cryptomator.freshdesk.com/support/solutions). -- [ ] have read the [contribution guide](https://github.com/cryptomator/cryptomator/blob/master/CONTRIBUTING.md). -- [ ] have read the [Code of Conduct](https://github.com/cryptomator/cryptomator/blob/master/CODE_OF_CONDUCT.md). +- searched existing (and closed) issues: https://github.com/cryptomator/cryptomator/issues +- searched the FAQ: https://community.cryptomator.org/c/faq +- have read the contribution guide: https://github.com/cryptomator/cryptomator/blob/master/CONTRIBUTING.md +- have read the Code of Conduct: https://github.com/cryptomator/cryptomator/blob/master/CODE_OF_CONDUCT.md ## Basic Info -This is a -- [ ] bug report. -- [ ] feature request. -- [ ] question or something else. - -I'm using -- [ ] Windows in version: … -- [ ] macOS in version: … -- [ ] Linux in version: … +I'm using Windows / macOS / Linux / … in version: … I'm running Cryptomator in version: … (You can check the version in the Cryptomator settings.) @@ -30,7 +20,9 @@ I'm running Cryptomator in version: … ## Attachments (optional) -If you want to add the log file or screenshots, please add them as attachments. If your log file seems empty and doesn't show any errors, you may enable the [debug mode](https://cryptomator.freshdesk.com/support/solutions/articles/16000046480) first and reproduce the problem to ensure all important information is contained in there. You may use test data or redact sensitive information from the log file. +If you want to add the log file or screenshots, please add them as attachments. If your log file seems empty and doesn't show any errors, you may enable the debug mode first. Here is how to do that: https://community.cryptomator.org/t/how-do-i-enable-debug-mode/36 + +Then reproduce the problem to ensure all important information is contained in there. You may use test data or redact sensitive information from the log file. You can find the log file - on Windows: %appdata%/Cryptomator/cryptomator.log From d81bf2e3011caf25b4fb229b8f008bd473aad8ee Mon Sep 17 00:00:00 2001 From: Sebastian Stenzel Date: Sat, 22 Jul 2017 01:29:08 +0200 Subject: [PATCH 03/33] Update README.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is the 1000th commit! 🎉 [ci skip] --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index a34f22ba9..a843d78df 100644 --- a/README.md +++ b/README.md @@ -22,6 +22,7 @@ Download native binaries of Cryptomator on [cryptomator.org](https://cryptomator - File names get encrypted - Folder structure gets obfuscated - Use as many vaults in your Dropbox as you want, each having individual passwords +- One thousand commits for the security of your data!! :tada: ### Privacy From 091fab90eecfcd7c98912d94e16bbbacf0432d04 Mon Sep 17 00:00:00 2001 From: Marc Stammerjohann Date: Tue, 25 Jul 2017 16:01:02 +0800 Subject: [PATCH 04/33] fix english typo [ci skip] --- main/ui/src/main/resources/localization/en.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/main/ui/src/main/resources/localization/en.txt b/main/ui/src/main/resources/localization/en.txt index fe723e5bb..d1b457cee 100644 --- a/main/ui/src/main/resources/localization/en.txt +++ b/main/ui/src/main/resources/localization/en.txt @@ -83,7 +83,7 @@ unlock.messageLabel.startServerFailed=Starting WebDAV server failed. # change_password.fxml changePassword.label.oldPassword=Old Password -changePassword.label.newPassword=New Nassword +changePassword.label.newPassword=New Password changePassword.label.retypePassword=Retype Password changePassword.label.downloadsPageLink=All Cryptomator versions changePassword.button.change=Change Password From 36cf3c2283b4f5faba27fc6dffe4c743cbf5227a Mon Sep 17 00:00:00 2001 From: Sebastian Stenzel Date: Wed, 26 Jul 2017 16:17:02 +0200 Subject: [PATCH 05/33] fixes #546, fixes #557 --- .../org/cryptomator/launcher/InterProcessCommunicator.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/main/launcher/src/main/java/org/cryptomator/launcher/InterProcessCommunicator.java b/main/launcher/src/main/java/org/cryptomator/launcher/InterProcessCommunicator.java index ccb24a528..5c330725a 100644 --- a/main/launcher/src/main/java/org/cryptomator/launcher/InterProcessCommunicator.java +++ b/main/launcher/src/main/java/org/cryptomator/launcher/InterProcessCommunicator.java @@ -17,6 +17,7 @@ import java.nio.file.Path; import java.nio.file.Paths; import java.nio.file.StandardOpenOption; import java.rmi.ConnectException; +import java.rmi.ConnectIOException; import java.rmi.NotBoundException; import java.rmi.Remote; import java.rmi.RemoteException; @@ -62,8 +63,8 @@ abstract class InterProcessCommunicator implements InterProcessCommunicationProt ClientCommunicator client = new ClientCommunicator(port); LOG.trace("Connected to running process."); return client; - } catch (ConnectException | NotBoundException e) { - LOG.debug("Did not find running process."); + } catch (ConnectException | ConnectIOException | NotBoundException e) { + LOG.debug("Could not connect to running process."); // continue } From 1a73f84d83a2148e56757a93e0922d27c40397cf Mon Sep 17 00:00:00 2001 From: Tobias Hagemann Date: Thu, 3 Aug 2017 14:15:39 +0200 Subject: [PATCH 06/33] updated issue template [ci skip] --- CONTRIBUTING.md | 2 +- ISSUE_TEMPLATE.md | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index a1165ce99..4889efd2a 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -18,7 +18,7 @@ ## Code of Conduct -Help us keep Cryptomator open and inclusive. Please read and follow our [Code of Conduct](https://github.com/cryptomator/cryptomator/blob/master/CODE_OF_CONDUCT.md). +Help us keep Cryptomator open and inclusive. Please read and follow our [Code of Conduct](https://github.com/cryptomator/cryptomator/blob/develop/CODE_OF_CONDUCT.md). ## Above all, thank you for your contributions diff --git a/ISSUE_TEMPLATE.md b/ISSUE_TEMPLATE.md index 7ecde70d4..f0908e880 100644 --- a/ISSUE_TEMPLATE.md +++ b/ISSUE_TEMPLATE.md @@ -2,9 +2,10 @@ Before creating a new issue make sure that you - searched existing (and closed) issues: https://github.com/cryptomator/cryptomator/issues -- searched the FAQ: https://community.cryptomator.org/c/faq -- have read the contribution guide: https://github.com/cryptomator/cryptomator/blob/master/CONTRIBUTING.md -- have read the Code of Conduct: https://github.com/cryptomator/cryptomator/blob/master/CODE_OF_CONDUCT.md +- searched the knowledge base: https://community.cryptomator.org/c/kb +- have read the support guide: https://github.com/cryptomator/cryptomator/blob/develop/SUPPORT.md +- have read the contribution guide: https://github.com/cryptomator/cryptomator/blob/develop/CONTRIBUTING.md +- have read the code of conduct: https://github.com/cryptomator/cryptomator/blob/develop/CODE_OF_CONDUCT.md ## Basic Info From d1a92335577b1a3879f19d952d8a99aa223caa23 Mon Sep 17 00:00:00 2001 From: Tobias Hagemann Date: Mon, 7 Aug 2017 11:04:44 +0200 Subject: [PATCH 07/33] fixed #567: added drag & drop support for password fields --- .../ui/controls/SecPasswordField.java | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/main/ui/src/main/java/org/cryptomator/ui/controls/SecPasswordField.java b/main/ui/src/main/java/org/cryptomator/ui/controls/SecPasswordField.java index a6339ed24..19d01cfbd 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/controls/SecPasswordField.java +++ b/main/ui/src/main/java/org/cryptomator/ui/controls/SecPasswordField.java @@ -11,6 +11,9 @@ package org.cryptomator.ui.controls; import java.util.Arrays; import javafx.scene.control.PasswordField; +import javafx.scene.input.DragEvent; +import javafx.scene.input.Dragboard; +import javafx.scene.input.TransferMode; /** * Compromise in security. While the text can be swiped, any access to the {@link #getText()} method will create a copy of the String in the heap. @@ -19,6 +22,27 @@ public class SecPasswordField extends PasswordField { private static final char SWIPE_CHAR = ' '; + public SecPasswordField() { + this.onDragOverProperty().set(this::handleDragOver); + this.onDragDroppedProperty().set(this::handleDragDropped); + } + + private void handleDragOver(DragEvent event) { + Dragboard dragboard = event.getDragboard(); + if (dragboard.hasString() && dragboard.getString() != null) { + event.acceptTransferModes(TransferMode.COPY); + } + event.consume(); + } + + private void handleDragDropped(DragEvent event) { + Dragboard dragboard = event.getDragboard(); + if (dragboard.hasString() && dragboard.getString() != null) { + insertText(getCaretPosition(), dragboard.getString()); + } + event.consume(); + } + /** * {@link #getContent()} uses a StringBuilder, which in turn is backed by a char[]. * The delete operation of AbstractStringBuilder closes the gap, that forms by deleting chars, by moving up the following chars. From f84bb4710fb6aec54649de524f5f1be42632459d Mon Sep 17 00:00:00 2001 From: Sebastian Stenzel Date: Wed, 16 Aug 2017 21:06:28 +0200 Subject: [PATCH 08/33] Updated webdav-nio-adapter to 1.0.0 --- main/pom.xml | 2 +- .../java/org/cryptomator/ui/model/Vault.java | 17 +++++++++++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/main/pom.xml b/main/pom.xml index ef45bb5f6..ce0fe40b0 100644 --- a/main/pom.xml +++ b/main/pom.xml @@ -26,7 +26,7 @@ 1.1.5 1.4.1 - 0.6.2 + 1.0.0 1.0.2 2.5 diff --git a/main/ui/src/main/java/org/cryptomator/ui/model/Vault.java b/main/ui/src/main/java/org/cryptomator/ui/model/Vault.java index 23c76429b..16ff849a1 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/model/Vault.java +++ b/main/ui/src/main/java/org/cryptomator/ui/model/Vault.java @@ -9,6 +9,8 @@ package org.cryptomator.ui.model; import java.io.IOException; +import java.net.InetAddress; +import java.net.UnknownHostException; import java.nio.file.DirectoryNotEmptyException; import java.nio.file.DirectoryStream; import java.nio.file.FileAlreadyExistsException; @@ -60,6 +62,7 @@ public class Vault { public static final Predicate NOT_LOCKED = hasState(State.LOCKED).negate(); private static final Logger LOG = LoggerFactory.getLogger(Vault.class); private static final String MASTERKEY_FILENAME = "masterkey.cryptomator"; + private static final String LOCALHOST_ALIAS = "cryptomator-vault"; private final Settings settings; private final VaultSettings vaultSettings; @@ -137,6 +140,7 @@ public class Vault { MountParams mountParams = MountParams.create() // .withWindowsDriveLetter(vaultSettings.winDriveLetter().get()) // .withPreferredGvfsScheme(settings.preferredGvfsScheme().get()) // + .withWebdavHostname(getLocalhostAliasOrNull()) // .build(); Platform.runLater(() -> { @@ -148,6 +152,19 @@ public class Vault { }); } + private String getLocalhostAliasOrNull() { + try { + InetAddress alias = InetAddress.getByName(LOCALHOST_ALIAS); + if (alias.getHostAddress().equals("127.0.0.1")) { + return LOCALHOST_ALIAS; + } else { + return null; + } + } catch (UnknownHostException e) { + return null; + } + } + public synchronized void unmount() throws CommandFailedException { unmount(Function.identity()); } From c41973a8d6e7416fec5e4ec69db5d71e26692fb2 Mon Sep 17 00:00:00 2001 From: swiesend Date: Tue, 12 Sep 2017 11:31:31 +0200 Subject: [PATCH 09/33] Hide tmp file under Linux --- .../java/org/cryptomator/launcher/InterProcessCommunicator.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/main/launcher/src/main/java/org/cryptomator/launcher/InterProcessCommunicator.java b/main/launcher/src/main/java/org/cryptomator/launcher/InterProcessCommunicator.java index 5c330725a..9dd282bab 100644 --- a/main/launcher/src/main/java/org/cryptomator/launcher/InterProcessCommunicator.java +++ b/main/launcher/src/main/java/org/cryptomator/launcher/InterProcessCommunicator.java @@ -80,7 +80,7 @@ abstract class InterProcessCommunicator implements InterProcessCommunicationProt final String settingsPathProperty = System.getProperty("cryptomator.ipcPortPath"); if (settingsPathProperty == null) { LOG.warn("System property cryptomator.ipcPortPath not set."); - return Paths.get("ipcPort.tmp"); + return Paths.get(".ipcPort.tmp"); } else { return Paths.get(replaceHomeDir(settingsPathProperty)); } From e62e9a1dffce9f0f33df1e26b4a5b1331eafeda0 Mon Sep 17 00:00:00 2001 From: hodyroff Date: Wed, 27 Sep 2017 15:54:08 +0200 Subject: [PATCH 10/33] Add ownCloud Cryptomator is used by many ownCloud users and the interview and installation guidance was well received. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index a843d78df..235d688a3 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ Download native binaries of Cryptomator on [cryptomator.org](https://cryptomator ## Features -- Works with Dropbox, Google Drive, OneDrive, Nextcloud and any other cloud storage service which synchronizes with a local directory +- Works with Dropbox, Google Drive, OneDrive, ownCloud, Nextcloud and any other cloud storage service which synchronizes with a local directory - Open Source means: No backdoors, control is better than trust - Client-side: No accounts, no data shared with any online service - Totally transparent: Just work on the virtual drive as if it were a USB flash drive From 69d379d03b7faa1218e909d4c2d64eac37eb3010 Mon Sep 17 00:00:00 2001 From: Sebastian Stenzel Date: Wed, 18 Oct 2017 12:34:53 +0200 Subject: [PATCH 11/33] fixes #583 --- main/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/main/pom.xml b/main/pom.xml index ce0fe40b0..a4b939426 100644 --- a/main/pom.xml +++ b/main/pom.xml @@ -26,7 +26,7 @@ 1.1.5 1.4.1 - 1.0.0 + 1.0.1 1.0.2 2.5 From 95b8240a21a31ac671d84c38125e9eb684003b37 Mon Sep 17 00:00:00 2001 From: Sebastian Stenzel Date: Wed, 18 Oct 2017 12:35:20 +0200 Subject: [PATCH 12/33] fixed vault migration version 3 to 4: conflicting .lng files are now properly migrated --- .../ui/model/UpgradeVersion3to4.java | 54 ++++++++++++------- 1 file changed, 34 insertions(+), 20 deletions(-) diff --git a/main/ui/src/main/java/org/cryptomator/ui/model/UpgradeVersion3to4.java b/main/ui/src/main/java/org/cryptomator/ui/model/UpgradeVersion3to4.java index 3dd4b6010..421eda002 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/model/UpgradeVersion3to4.java +++ b/main/ui/src/main/java/org/cryptomator/ui/model/UpgradeVersion3to4.java @@ -42,9 +42,10 @@ class UpgradeVersion3to4 extends UpgradeStrategy { private static final Logger LOG = LoggerFactory.getLogger(UpgradeVersion3to4.class); private static final Pattern LVL1_DIR_PATTERN = Pattern.compile("[A-Z2-7]{2}"); private static final Pattern LVL2_DIR_PATTERN = Pattern.compile("[A-Z2-7]{30}"); - private static final Pattern BASE32_FOLLOWED_BY_UNDERSCORE_PATTERN = Pattern.compile("^(([A-Z2-7]{8})*[A-Z2-7=]{8})_"); + private static final Pattern BASE32_PATTERN = Pattern.compile("^(([A-Z2-7]{8})*[A-Z2-7=]{8})"); + private static final Pattern BASE32_FOLLOWED_BY_UNDERSCORE_PATTERN = Pattern.compile(BASE32_PATTERN.pattern() + "_"); private static final int FILE_MIN_SIZE = 88; // vault version 3 files have a header of 88 bytes (assuming no chunks at all) - private static final String LONG_FILENAME_SUFFIX = ".lng"; + private static final String LONG_FILENAME_EXT = ".lng"; private static final String OLD_FOLDER_SUFFIX = "_"; private static final String NEW_FOLDER_PREFIX = "0"; @@ -96,10 +97,12 @@ class UpgradeVersion3to4 extends UpgradeStrategy { @Override public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { String name = file.getFileName().toString(); - if (name.endsWith(LONG_FILENAME_SUFFIX)) { + if (!attrs.isRegularFile() || attrs.size() > FILE_MIN_SIZE) { + LOG.trace("Skipping non-directory file {}.", file); + } else if (name.endsWith(LONG_FILENAME_EXT)) { migrateLong(metadataDir, file); } else { - migrate(file, attrs); + migrate(file); } return FileVisitResult.CONTINUE; } @@ -112,14 +115,13 @@ class UpgradeVersion3to4 extends UpgradeStrategy { LOG.info("Migration finished."); } - private void migrate(Path file, BasicFileAttributes attrs) throws IOException { + private void migrate(Path file) throws IOException { String name = file.getFileName().toString(); - long size = attrs.size(); Matcher m = BASE32_FOLLOWED_BY_UNDERSCORE_PATTERN.matcher(name); - if (attrs.isRegularFile() && m.find(0) && size < FILE_MIN_SIZE) { + if (m.find(0)) { String base32 = m.group(1); String suffix = name.substring(m.end()); - String renamed = NEW_FOLDER_PREFIX + base32 + (suffix.isEmpty() ? "" : " " + suffix); + String renamed = NEW_FOLDER_PREFIX + base32 + StringUtils.prependIfMissing(suffix, " "); renameWithoutOverwriting(file, renamed); } } @@ -135,22 +137,34 @@ class UpgradeVersion3to4 extends UpgradeStrategy { private void migrateLong(Path metadataDir, Path path) throws IOException { String oldName = path.getFileName().toString(); - Path oldMetadataFile = metadataDir.resolve(oldName.substring(0, 2)).resolve(oldName.substring(2, 4)).resolve(oldName); - if (Files.isRegularFile(oldMetadataFile)) { - String oldContent = new String(Files.readAllBytes(oldMetadataFile), UTF_8); - if (oldContent.endsWith(OLD_FOLDER_SUFFIX)) { - String newContent = NEW_FOLDER_PREFIX + StringUtils.removeEnd(oldContent, OLD_FOLDER_SUFFIX); - String newName = base32.encodeAsString(sha1.digest(newContent.getBytes(UTF_8))) + LONG_FILENAME_SUFFIX; + assert oldName.endsWith(LONG_FILENAME_EXT); + String oldNameBase = StringUtils.removeEnd(oldName, LONG_FILENAME_EXT); + + Matcher m = BASE32_PATTERN.matcher(oldNameBase); + if (m.find(0)) { + String oldNameBase32 = m.group(1); + String oldNameSuffix = oldNameBase.substring(m.end()); + String oldCanonicalName = oldNameBase32 + LONG_FILENAME_EXT; + + Path oldMetadataFile = metadataDir.resolve(oldCanonicalName.substring(0, 2)).resolve(oldCanonicalName.substring(2, 4)).resolve(oldCanonicalName); + if (!Files.isRegularFile(oldMetadataFile)) { + LOG.warn("Found uninflatable long file name. Expected: {}", oldMetadataFile); + return; + } + + String oldLongName = new String(Files.readAllBytes(oldMetadataFile), UTF_8); + if (oldLongName.endsWith(OLD_FOLDER_SUFFIX)) { + String newLongName = NEW_FOLDER_PREFIX + StringUtils.removeEnd(oldLongName, OLD_FOLDER_SUFFIX); + String newCanonicalBase32 = base32.encodeAsString(sha1.digest(newLongName.getBytes(UTF_8))); + String newCanonicalName = newCanonicalBase32 + LONG_FILENAME_EXT; + Path newMetadataFile = metadataDir.resolve(newCanonicalName.substring(0, 2)).resolve(newCanonicalName.substring(2, 4)).resolve(newCanonicalName); + String newName = newCanonicalBase32 + oldNameSuffix + LONG_FILENAME_EXT; Path newPath = path.resolveSibling(newName); - Path newMetadataFile = metadataDir.resolve(newName.substring(0, 2)).resolve(newName.substring(2, 4)).resolve(newName); Files.move(path, newPath); Files.createDirectories(newMetadataFile.getParent()); - Files.write(newMetadataFile, newContent.getBytes(UTF_8)); - Files.delete(oldMetadataFile); - LOG.info("Renaming {} to {}\nDeleting {}\nCreating {}", path, newName, oldMetadataFile, newMetadataFile); + Files.write(newMetadataFile, newLongName.getBytes(UTF_8)); + LOG.info("Renaming {} to {}\nCreating {}", path, newName, newMetadataFile); } - } else { - LOG.warn("Found uninflatable long file name. Expected: {}", oldMetadataFile); } } From a850e8b816109c5cb0b80406b8d36e43a18c3c18 Mon Sep 17 00:00:00 2001 From: Sebastian Stenzel Date: Thu, 19 Oct 2017 13:10:29 +0200 Subject: [PATCH 13/33] Added unit tests for vault format "3 to 4" migration --- main/ui/pom.xml | 8 + .../ui/model/UpgradeVersion3to4.java | 5 +- .../cryptomator/ui/l10n/LocalizationMock.java | 10 ++ .../ui/model/UpgradeVersion3to4Test.java | 164 ++++++++++++++++++ 4 files changed, 185 insertions(+), 2 deletions(-) create mode 100644 main/ui/src/test/java/org/cryptomator/ui/l10n/LocalizationMock.java create mode 100644 main/ui/src/test/java/org/cryptomator/ui/model/UpgradeVersion3to4Test.java diff --git a/main/ui/pom.xml b/main/ui/pom.xml index 4e26f7590..e09ff0db5 100644 --- a/main/ui/pom.xml +++ b/main/ui/pom.xml @@ -86,5 +86,13 @@ slf4j-simple test + + + + com.google.jimfs + jimfs + 1.1 + test + diff --git a/main/ui/src/main/java/org/cryptomator/ui/model/UpgradeVersion3to4.java b/main/ui/src/main/java/org/cryptomator/ui/model/UpgradeVersion3to4.java index 421eda002..eefb5990c 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/model/UpgradeVersion3to4.java +++ b/main/ui/src/main/java/org/cryptomator/ui/model/UpgradeVersion3to4.java @@ -121,7 +121,7 @@ class UpgradeVersion3to4 extends UpgradeStrategy { if (m.find(0)) { String base32 = m.group(1); String suffix = name.substring(m.end()); - String renamed = NEW_FOLDER_PREFIX + base32 + StringUtils.prependIfMissing(suffix, " "); + String renamed = NEW_FOLDER_PREFIX + base32 + suffix; renameWithoutOverwriting(file, renamed); } } @@ -163,7 +163,8 @@ class UpgradeVersion3to4 extends UpgradeStrategy { Files.move(path, newPath); Files.createDirectories(newMetadataFile.getParent()); Files.write(newMetadataFile, newLongName.getBytes(UTF_8)); - LOG.info("Renaming {} to {}\nCreating {}", path, newName, newMetadataFile); + LOG.info("Renaming {} to {}.", path, newName); + LOG.info("Creating {}.", newMetadataFile); } } } diff --git a/main/ui/src/test/java/org/cryptomator/ui/l10n/LocalizationMock.java b/main/ui/src/test/java/org/cryptomator/ui/l10n/LocalizationMock.java new file mode 100644 index 000000000..67f95cbbf --- /dev/null +++ b/main/ui/src/test/java/org/cryptomator/ui/l10n/LocalizationMock.java @@ -0,0 +1,10 @@ +package org.cryptomator.ui.l10n; + +public class LocalizationMock extends Localization { + + @Override + public String handleGetObject(String key) { + return key; + } + +} diff --git a/main/ui/src/test/java/org/cryptomator/ui/model/UpgradeVersion3to4Test.java b/main/ui/src/test/java/org/cryptomator/ui/model/UpgradeVersion3to4Test.java new file mode 100644 index 000000000..8b1f18e88 --- /dev/null +++ b/main/ui/src/test/java/org/cryptomator/ui/model/UpgradeVersion3to4Test.java @@ -0,0 +1,164 @@ +package org.cryptomator.ui.model; + +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.nio.file.FileSystem; +import java.nio.file.Files; +import java.nio.file.Path; + +import org.cryptomator.ui.l10n.Localization; +import org.cryptomator.ui.l10n.LocalizationMock; +import org.cryptomator.ui.model.UpgradeStrategy.UpgradeFailedException; +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; +import org.mockito.Mockito; + +import com.google.common.jimfs.Configuration; +import com.google.common.jimfs.Jimfs; + +public class UpgradeVersion3to4Test { + + private static final Localization L10N = new LocalizationMock(); + private static final String NULL_KEY_CONTENTS = "{" // + + " \"version\": 3," // + + " \"scryptSalt\": \"AAAAAAAAAAA=\"," // + + " \"scryptCostParam\": 16384," // + + " \"scryptBlockSize\": 8," // + + " \"primaryMasterKey\": \"BJPIq5pvhN24iDtPJLMFPLaVJWdGog9k4n0P03j4ru+ivbWY9OaRGQ==\"," // + + " \"hmacMasterKey\": \"BJPIq5pvhN24iDtPJLMFPLaVJWdGog9k4n0P03j4ru+ivbWY9OaRGQ==\"," // + + " \"versionMac\": \"iUmRRHITuyJsJbVNqGNw+82YQ4A3Rma7j/y1v0DCVLA=\"" // + + "}"; + + @Rule + public final ExpectedException thrown = ExpectedException.none(); + private final UpgradeStrategy upgradeStrategy = new UpgradeVersion3to4(L10N); + private FileSystem fs; + private Path fsRoot; + private Vault vault; + private Path dataDir; + private Path metadataDir; + + @Before + public void setup() throws IOException { + fs = Jimfs.newFileSystem(Configuration.unix()); + fsRoot = fs.getPath("/"); + dataDir = fsRoot.resolve("d"); + metadataDir = fsRoot.resolve("m"); + vault = Mockito.mock(Vault.class); + Mockito.when(vault.getPath()).thenReturn(fsRoot); + + Files.write(fsRoot.resolve("masterkey.cryptomator"), NULL_KEY_CONTENTS.getBytes(StandardCharsets.US_ASCII)); + } + + @After + public void teardown() throws IOException { + fs.close(); + } + + @Test + public void upgradeFailsWithWrongPassword() throws UpgradeFailedException { + thrown.expect(UpgradeFailedException.class); + thrown.expectMessage("unlock.errorMessage.wrongPassword"); + upgradeStrategy.upgrade(vault, "asdd"); + } + + @Test + public void upgradeCreatesBackup() throws UpgradeFailedException { + upgradeStrategy.upgrade(vault, "asd"); + Assert.assertTrue(Files.exists(fsRoot.resolve("masterkey.cryptomator.bkup"))); + } + + @Test + public void upgradeRenamesSimpleDirFile() throws IOException, UpgradeFailedException { + Path lvl2Dir = dataDir.resolve("AB/CDEFGHIJKLMNOPQRSTUVWXYZ234567"); + Files.createDirectories(lvl2Dir); + Path oldFile = lvl2Dir.resolve("ABCDEFGH_"); + Files.createFile(oldFile); + + upgradeStrategy.upgrade(vault, "asd"); + Path newFile = lvl2Dir.resolve("0ABCDEFGH"); + Assert.assertTrue(Files.exists(newFile)); + Assert.assertTrue(Files.notExists(oldFile)); + } + + @Test + public void upgradeRenamesConflictingDirFile() throws IOException, UpgradeFailedException { + Path lvl2Dir = dataDir.resolve("AB/CDEFGHIJKLMNOPQRSTUVWXYZ234567"); + Files.createDirectories(lvl2Dir); + Path oldFile = lvl2Dir.resolve("ABCDEFGH_ (1)"); + Files.createFile(oldFile); + + upgradeStrategy.upgrade(vault, "asd"); + Path newFile = lvl2Dir.resolve("0ABCDEFGH (1)"); + Assert.assertTrue(Files.exists(newFile)); + Assert.assertTrue(Files.notExists(oldFile)); + } + + @Test + public void upgradeDontRenameNonDirFile() throws IOException, UpgradeFailedException { + Path lvl2Dir = dataDir.resolve("AB/CDEFGHIJKLMNOPQRSTUVWXYZ234567"); + Files.createDirectories(lvl2Dir); + Path oldFile = lvl2Dir.resolve("ABCDEFGH"); + Files.createFile(oldFile); + + upgradeStrategy.upgrade(vault, "asd"); + Assert.assertTrue(Files.exists(oldFile)); + } + + @Test + public void upgradeRenameSimpleLongDirFile() throws IOException, UpgradeFailedException { + Path lvl2Dir = dataDir.resolve("AB/CDEFGHIJKLMNOPQRSTUVWXYZ234567"); + Files.createDirectories(lvl2Dir); + Path oldFile = lvl2Dir.resolve("ABCDEFGH.lng"); + Files.createFile(oldFile); + Path oldMetadataFile = metadataDir.resolve("AB/CD/ABCDEFGH.lng"); + Files.createDirectories(oldMetadataFile.getParent()); + Files.write(oldMetadataFile, "OPQRSTUVWXYZ====_".getBytes(StandardCharsets.UTF_8)); + + upgradeStrategy.upgrade(vault, "asd"); + // hex2base32(sha1("0OPQRSTUVWXYZ====")) = DDLCFQ3ODTEAHEZJPHIJQRDHROB3K42G + Path newMetadataFile = metadataDir.resolve("DD/LC/DDLCFQ3ODTEAHEZJPHIJQRDHROB3K42G.lng"); + Path newFile = lvl2Dir.resolve("DDLCFQ3ODTEAHEZJPHIJQRDHROB3K42G.lng"); + Assert.assertTrue(Files.exists(newFile)); + Assert.assertTrue(Files.exists(newMetadataFile)); + Assert.assertTrue(Files.notExists(oldFile)); + } + + @Test + public void upgradeRenameConflictingLongDirFile() throws IOException, UpgradeFailedException { + Path lvl2Dir = dataDir.resolve("AB/CDEFGHIJKLMNOPQRSTUVWXYZ234567"); + Files.createDirectories(lvl2Dir); + Path oldFile = lvl2Dir.resolve("ABCDEFGH (1).lng"); + Files.createFile(oldFile); + Path oldMetadataFile = metadataDir.resolve("AB/CD/ABCDEFGH.lng"); + Files.createDirectories(oldMetadataFile.getParent()); + Files.write(oldMetadataFile, "OPQRSTUVWXYZ====_".getBytes(StandardCharsets.UTF_8)); + + upgradeStrategy.upgrade(vault, "asd"); + // hex2base32(sha1("0OPQRSTUVWXYZ====")) = DDLCFQ3ODTEAHEZJPHIJQRDHROB3K42G + Path newMetadataFile = metadataDir.resolve("DD/LC/DDLCFQ3ODTEAHEZJPHIJQRDHROB3K42G.lng"); + Path newFile = lvl2Dir.resolve("DDLCFQ3ODTEAHEZJPHIJQRDHROB3K42G (1).lng"); + Assert.assertTrue(Files.exists(newFile)); + Assert.assertTrue(Files.exists(newMetadataFile)); + Assert.assertTrue(Files.notExists(oldFile)); + } + + @Test + public void upgradeDontRenameLongNonDirFile() throws IOException, UpgradeFailedException { + Path lvl2Dir = dataDir.resolve("AB/CDEFGHIJKLMNOPQRSTUVWXYZ234567"); + Files.createDirectories(lvl2Dir); + Path oldFile = lvl2Dir.resolve("ABCDEFGH.lng"); + Files.createFile(oldFile); + Path oldMetadataFile = metadataDir.resolve("AB/CD/ABCDEFGH.lng"); + Files.createDirectories(oldMetadataFile.getParent()); + Files.write(oldMetadataFile, "OPQRSTUVWXYZ====".getBytes(StandardCharsets.UTF_8)); + + upgradeStrategy.upgrade(vault, "asd"); + Assert.assertTrue(Files.exists(oldFile)); + } + +} From 17bbd9161f309db46c663e9b2dceb08c6eea5049 Mon Sep 17 00:00:00 2001 From: armin Date: Tue, 24 Oct 2017 18:04:19 +0200 Subject: [PATCH 14/33] adapted project-files such that project can be used with intellij IDEA IDE --- .gitignore | 1 + main/commons/pom.xml | 5 +++++ main/keychain/pom.xml | 4 ++++ main/launcher/pom.xml | 4 ++++ main/pom.xml | 15 +++++++-------- main/ui/pom.xml | 4 ++++ 6 files changed, 25 insertions(+), 8 deletions(-) diff --git a/.gitignore b/.gitignore index 5ddd9fc95..4568d7a75 100644 --- a/.gitignore +++ b/.gitignore @@ -17,3 +17,4 @@ test-output/ out/ .idea_modules/ *.iws +*.iml diff --git a/main/commons/pom.xml b/main/commons/pom.xml index 80d96e00c..592f54595 100644 --- a/main/commons/pom.xml +++ b/main/commons/pom.xml @@ -34,6 +34,11 @@ com.google.dagger dagger + + + com.google.dagger + dagger-compiler + diff --git a/main/keychain/pom.xml b/main/keychain/pom.xml index 1d2ae0e0a..97721fd3b 100644 --- a/main/keychain/pom.xml +++ b/main/keychain/pom.xml @@ -34,6 +34,10 @@ com.google.dagger dagger + + com.google.dagger + dagger-compiler + diff --git a/main/launcher/pom.xml b/main/launcher/pom.xml index bb55d145b..3c97807ef 100644 --- a/main/launcher/pom.xml +++ b/main/launcher/pom.xml @@ -34,6 +34,10 @@ com.google.dagger dagger + + com.google.dagger + dagger-compiler + diff --git a/main/pom.xml b/main/pom.xml index a4b939426..f972debd3 100644 --- a/main/pom.xml +++ b/main/pom.xml @@ -164,6 +164,12 @@ dagger ${dagger.version} + + com.google.dagger + dagger-compiler + ${dagger.version} + true + com.google.code.gson gson @@ -302,17 +308,10 @@ maven-compiler-plugin - 3.6.1 + 3.7.0 1.8 1.8 - - - com.google.dagger - dagger-compiler - ${dagger.version} - - diff --git a/main/ui/pom.xml b/main/ui/pom.xml index e09ff0db5..c5a0980c9 100644 --- a/main/ui/pom.xml +++ b/main/ui/pom.xml @@ -72,6 +72,10 @@ com.google.dagger dagger + + com.google.dagger + dagger-compiler + From a7b036d441e6277dc888443c1651eb4bc69e0728 Mon Sep 17 00:00:00 2001 From: Sebastian Stenzel Date: Thu, 2 Nov 2017 11:16:41 +0100 Subject: [PATCH 15/33] fixes #598 --- .../ui/util/PasswordStrengthUtil.java | 6 ++++-- .../ui/util/PasswordStrengthUtilTest.java | 21 +++++++++++++++++++ 2 files changed, 25 insertions(+), 2 deletions(-) create mode 100644 main/ui/src/test/java/org/cryptomator/ui/util/PasswordStrengthUtilTest.java diff --git a/main/ui/src/main/java/org/cryptomator/ui/util/PasswordStrengthUtil.java b/main/ui/src/main/java/org/cryptomator/ui/util/PasswordStrengthUtil.java index 52b854530..056ba8f97 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/util/PasswordStrengthUtil.java +++ b/main/ui/src/main/java/org/cryptomator/ui/util/PasswordStrengthUtil.java @@ -14,9 +14,9 @@ import java.util.List; import javax.inject.Inject; import javax.inject.Singleton; -import org.apache.commons.lang3.StringUtils; import org.cryptomator.ui.l10n.Localization; +import com.google.common.base.Strings; import com.nulabinc.zxcvbn.Zxcvbn; import javafx.geometry.Insets; @@ -41,8 +41,10 @@ public class PasswordStrengthUtil { } public int computeRate(String password) { - if (StringUtils.isEmpty(password)) { + if (Strings.isNullOrEmpty(password)) { return -1; + } else if (password.length() > 100) { + return 4; // assume this is strong. zxcvbn memory and runtime depends vastly on the password length } else { return zxcvbn.measure(password, sanitizedInputs).getScore(); } diff --git a/main/ui/src/test/java/org/cryptomator/ui/util/PasswordStrengthUtilTest.java b/main/ui/src/test/java/org/cryptomator/ui/util/PasswordStrengthUtilTest.java new file mode 100644 index 000000000..6981e1b23 --- /dev/null +++ b/main/ui/src/test/java/org/cryptomator/ui/util/PasswordStrengthUtilTest.java @@ -0,0 +1,21 @@ +package org.cryptomator.ui.util; + +import org.cryptomator.ui.l10n.Localization; +import org.junit.Assert; +import org.junit.Test; +import org.mockito.Mockito; + +public class PasswordStrengthUtilTest { + + @Test + public void testLongPasswordsWillBeRatedAsStrong() { + PasswordStrengthUtil util = new PasswordStrengthUtil(Mockito.mock(Localization.class)); + StringBuilder longPwBuilder = new StringBuilder(); + for (int i = 0; i < 101; i++) { + longPwBuilder.append('x'); + } + int strength = util.computeRate(longPwBuilder.toString()); + Assert.assertEquals(4, strength); + } + +} From ecdd3bc5ec6790bd8d03b5a266241b719e7a2600 Mon Sep 17 00:00:00 2001 From: Markus Kreusch Date: Fri, 10 Nov 2017 15:04:21 +0100 Subject: [PATCH 16/33] Fixes #600 --- .gitignore | 3 +++ main/commons/pom.xml | 4 ++++ .../ui/controllers/InitializeController.java | 3 --- .../ui/controllers/MainController.java | 20 ++++++++++++++++++- .../java/org/cryptomator/ui/model/Vault.java | 9 --------- .../ui/src/main/resources/localization/en.txt | 4 +++- 6 files changed, 29 insertions(+), 14 deletions(-) diff --git a/.gitignore b/.gitignore index 4568d7a75..6ff6c8689 100644 --- a/.gitignore +++ b/.gitignore @@ -18,3 +18,6 @@ out/ .idea_modules/ *.iws *.iml + +# Temporary file created by test launcher +main/launcher/ipcPort.tmp diff --git a/main/commons/pom.xml b/main/commons/pom.xml index 592f54595..fcef4fb7e 100644 --- a/main/commons/pom.xml +++ b/main/commons/pom.xml @@ -34,6 +34,10 @@ com.google.dagger dagger + + com.google.dagger + dagger-compiler + com.google.dagger diff --git a/main/ui/src/main/java/org/cryptomator/ui/controllers/InitializeController.java b/main/ui/src/main/java/org/cryptomator/ui/controllers/InitializeController.java index a718cd4eb..38e905bcb 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/controllers/InitializeController.java +++ b/main/ui/src/main/java/org/cryptomator/ui/controllers/InitializeController.java @@ -10,7 +10,6 @@ package org.cryptomator.ui.controllers; import java.io.IOException; -import java.nio.file.DirectoryNotEmptyException; import java.nio.file.FileAlreadyExistsException; import java.util.Objects; import java.util.Optional; @@ -125,8 +124,6 @@ public class InitializeController implements ViewController { listener.ifPresent(this::invokeListenerLater); } catch (FileAlreadyExistsException ex) { messageLabel.setText(localization.getString("initialize.messageLabel.alreadyInitialized")); - } catch (DirectoryNotEmptyException ex) { - messageLabel.setText(localization.getString("initialize.messageLabel.notEmpty")); } catch (IOException ex) { LOG.error("I/O Exception", ex); messageLabel.setText(localization.getString("initialize.messageLabel.initializationFailed")); diff --git a/main/ui/src/main/java/org/cryptomator/ui/controllers/MainController.java b/main/ui/src/main/java/org/cryptomator/ui/controllers/MainController.java index cd661655f..e610d7aad 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/controllers/MainController.java +++ b/main/ui/src/main/java/org/cryptomator/ui/controllers/MainController.java @@ -9,6 +9,8 @@ ******************************************************************************/ package org.cryptomator.ui.controllers; +import static org.cryptomator.ui.util.DialogBuilderUtil.buildErrorDialog; + import java.io.File; import java.io.IOException; import java.io.InputStream; @@ -20,6 +22,7 @@ import java.util.Map; import java.util.Optional; import java.util.concurrent.BlockingQueue; import java.util.concurrent.ExecutorService; +import java.util.stream.Stream; import javax.inject.Inject; import javax.inject.Named; @@ -261,7 +264,18 @@ public class MainController implements ViewController { } try { final Path vaultDir = file.toPath(); - if (!Files.exists(vaultDir)) { + if (Files.exists(vaultDir)) { + try (Stream stream = Files.list(vaultDir)) { + if (stream.filter(this::isNotHidden).findAny().isPresent()) { + buildErrorDialog( // + localization.getString("main.createVault.nonEmptyDir.title"), // + localization.getString("main.createVault.nonEmptyDir.header"), // + localization.getString("main.createVault.nonEmptyDir.content"), // + ButtonType.OK).show(); + return; + } + } + } else { Files.createDirectory(vaultDir); } addVault(vaultDir, true); @@ -270,6 +284,10 @@ public class MainController implements ViewController { } } + private boolean isNotHidden(Path file) { + return !file.getFileName().toString().startsWith("."); + } + @FXML private void didClickAddExistingVaults(ActionEvent event) { final FileChooser fileChooser = new FileChooser(); diff --git a/main/ui/src/main/java/org/cryptomator/ui/model/Vault.java b/main/ui/src/main/java/org/cryptomator/ui/model/Vault.java index 16ff849a1..2b57d14ab 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/model/Vault.java +++ b/main/ui/src/main/java/org/cryptomator/ui/model/Vault.java @@ -11,8 +11,6 @@ package org.cryptomator.ui.model; import java.io.IOException; import java.net.InetAddress; import java.net.UnknownHostException; -import java.nio.file.DirectoryNotEmptyException; -import java.nio.file.DirectoryStream; import java.nio.file.FileAlreadyExistsException; import java.nio.file.FileSystem; import java.nio.file.Files; @@ -102,13 +100,6 @@ public class Vault { } public void create(CharSequence passphrase) throws IOException { - try (DirectoryStream stream = Files.newDirectoryStream(getPath())) { - for (Path file : stream) { - if (!file.getFileName().toString().startsWith(".")) { - throw new DirectoryNotEmptyException(getPath().toString()); - } - } - } if (!isValidVaultDirectory()) { CryptoFileSystemProvider.initialize(getPath(), MASTERKEY_FILENAME, passphrase); } else { diff --git a/main/ui/src/main/resources/localization/en.txt b/main/ui/src/main/resources/localization/en.txt index d1b457cee..fb27ddf01 100644 --- a/main/ui/src/main/resources/localization/en.txt +++ b/main/ui/src/main/resources/localization/en.txt @@ -16,6 +16,9 @@ main.addDirectory.contextMenu.open=Open Existing Vault main.directoryList.remove.confirmation.title=Remove Vault main.directoryList.remove.confirmation.header=Do you really want to remove this vault? main.directoryList.remove.confirmation.content=The vault will only be removed from the list. To permanently delete it, please delete the vault from your filesystem. +main.createVault.nonEmptyDir.title=Creating vault failed +main.createVault.nonEmptyDir.header=Chosen directory is not empty +main.createVault.nonEmptyDir.content=The selected directory already contains files (possibly hidden). A vault can only be created in an empty directory. # welcome.fxml welcome.checkForUpdates.label.currentlyChecking=Checking for Updates... @@ -26,7 +29,6 @@ initialize.label.password=Password initialize.label.retypePassword=Retype Password initialize.button.ok=Create Vault initialize.messageLabel.alreadyInitialized=Vault already initialized -initialize.messageLabel.notEmpty=Vault not empty initialize.messageLabel.initializationFailed=Could not initialize vault. See log file for details. initialize.messageLabel.passwordStrength.0=Very weak initialize.messageLabel.passwordStrength.1=Weak From a7c42c3d5996a5898c3e7cb1e65eed58b1ee5c8c Mon Sep 17 00:00:00 2001 From: Sebastian Stenzel Date: Tue, 14 Nov 2017 18:12:22 +0100 Subject: [PATCH 17/33] Removed use of Files.isRegularFile from UI module, references #592 --- .../java/org/cryptomator/ui/model/UpgradeStrategy.java | 9 ++------- .../org/cryptomator/ui/model/UpgradeVersion3to4.java | 4 ++-- .../org/cryptomator/ui/model/UpgradeVersion4to5.java | 2 +- 3 files changed, 5 insertions(+), 10 deletions(-) diff --git a/main/ui/src/main/java/org/cryptomator/ui/model/UpgradeStrategy.java b/main/ui/src/main/java/org/cryptomator/ui/model/UpgradeStrategy.java index 426a9b200..29c51ff2b 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/model/UpgradeStrategy.java +++ b/main/ui/src/main/java/org/cryptomator/ui/model/UpgradeStrategy.java @@ -112,13 +112,8 @@ public abstract class UpgradeStrategy { public boolean isApplicable(Vault vault) { final Path masterkeyFile = vault.getPath().resolve(MASTERKEY_FILENAME); try { - if (Files.isRegularFile(masterkeyFile)) { - byte[] masterkeyFileContents = Files.readAllBytes(masterkeyFile); - return KeyFile.parse(masterkeyFileContents).getVersion() == vaultVersionBeforeUpgrade; - } else { - LOG.warn("Not a file: {}", masterkeyFile); - return false; - } + byte[] masterkeyFileContents = Files.readAllBytes(masterkeyFile); + return KeyFile.parse(masterkeyFileContents).getVersion() == vaultVersionBeforeUpgrade; } catch (IOException e) { LOG.warn("Could not determine, whether upgrade is applicable.", e); return false; diff --git a/main/ui/src/main/java/org/cryptomator/ui/model/UpgradeVersion3to4.java b/main/ui/src/main/java/org/cryptomator/ui/model/UpgradeVersion3to4.java index eefb5990c..3c9e6aa2e 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/model/UpgradeVersion3to4.java +++ b/main/ui/src/main/java/org/cryptomator/ui/model/UpgradeVersion3to4.java @@ -97,7 +97,7 @@ class UpgradeVersion3to4 extends UpgradeStrategy { @Override public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { String name = file.getFileName().toString(); - if (!attrs.isRegularFile() || attrs.size() > FILE_MIN_SIZE) { + if (attrs.size() > FILE_MIN_SIZE) { LOG.trace("Skipping non-directory file {}.", file); } else if (name.endsWith(LONG_FILENAME_EXT)) { migrateLong(metadataDir, file); @@ -147,7 +147,7 @@ class UpgradeVersion3to4 extends UpgradeStrategy { String oldCanonicalName = oldNameBase32 + LONG_FILENAME_EXT; Path oldMetadataFile = metadataDir.resolve(oldCanonicalName.substring(0, 2)).resolve(oldCanonicalName.substring(2, 4)).resolve(oldCanonicalName); - if (!Files.isRegularFile(oldMetadataFile)) { + if (!Files.isReadable(oldMetadataFile)) { LOG.warn("Found uninflatable long file name. Expected: {}", oldMetadataFile); return; } diff --git a/main/ui/src/main/java/org/cryptomator/ui/model/UpgradeVersion4to5.java b/main/ui/src/main/java/org/cryptomator/ui/model/UpgradeVersion4to5.java index ae26f75da..89b2847d1 100644 --- a/main/ui/src/main/java/org/cryptomator/ui/model/UpgradeVersion4to5.java +++ b/main/ui/src/main/java/org/cryptomator/ui/model/UpgradeVersion4to5.java @@ -83,7 +83,7 @@ class UpgradeVersion4to5 extends UpgradeStrategy { @Override public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { - if (attrs.isRegularFile() && BASE32_PATTERN.matcher(file.getFileName().toString()).find() && attrs.size() > cryptor.fileHeaderCryptor().headerSize()) { + if (BASE32_PATTERN.matcher(file.getFileName().toString()).find() && attrs.size() > cryptor.fileHeaderCryptor().headerSize()) { migrate(file, attrs, cryptor); } else { LOG.info("Skipping irrelevant file {}.", file); From 40caba847b08434c611fab4b0a578a2931a8ac54 Mon Sep 17 00:00:00 2001 From: Sebastian Stenzel Date: Thu, 16 Nov 2017 14:54:54 +0100 Subject: [PATCH 18/33] Removes ipc port file after shutdown, reduced so timeout for rmi clients --- .../launcher/InterProcessCommunicator.java | 89 +++++++++++-------- 1 file changed, 54 insertions(+), 35 deletions(-) diff --git a/main/launcher/src/main/java/org/cryptomator/launcher/InterProcessCommunicator.java b/main/launcher/src/main/java/org/cryptomator/launcher/InterProcessCommunicator.java index 9dd282bab..7c2e56cf1 100644 --- a/main/launcher/src/main/java/org/cryptomator/launcher/InterProcessCommunicator.java +++ b/main/launcher/src/main/java/org/cryptomator/launcher/InterProcessCommunicator.java @@ -9,6 +9,7 @@ import java.io.Closeable; import java.io.IOException; import java.net.InetAddress; import java.net.ServerSocket; +import java.net.Socket; import java.nio.ByteBuffer; import java.nio.channels.ReadableByteChannel; import java.nio.channels.WritableByteChannel; @@ -56,11 +57,9 @@ abstract class InterProcessCommunicator implements InterProcessCommunicationProt // visible for testing static InterProcessCommunicator start(Path portFilePath, InterProcessCommunicationProtocol endpoint) throws IOException { System.setProperty("java.rmi.server.hostname", "localhost"); - // try to connect to existing server: - int port = readPort(portFilePath); - LOG.debug("Connecting to running process on TCP port {}...", port); try { - ClientCommunicator client = new ClientCommunicator(port); + // try to connect to existing server: + ClientCommunicator client = new ClientCommunicator(portFilePath); LOG.trace("Connected to running process."); return client; } catch (ConnectException | ConnectIOException | NotBoundException e) { @@ -70,8 +69,7 @@ abstract class InterProcessCommunicator implements InterProcessCommunicationProt // spawn a new server: LOG.trace("Spawning new server..."); - ServerCommunicator server = new ServerCommunicator(endpoint); - writePort(portFilePath, server.getPort()); + ServerCommunicator server = new ServerCommunicator(endpoint, portFilePath); LOG.debug("Server listening on port {}.", server.getPort()); return server; } @@ -98,12 +96,30 @@ abstract class InterProcessCommunicator implements InterProcessCommunicationProt private final IpcProtocolRemote remote; - private ClientCommunicator(int port) throws ConnectException, NotBoundException, RemoteException { - if (port == 0) { - throw new ConnectException("Can not connect to port 0."); + private ClientCommunicator(Path portFilePath) throws ConnectException, NotBoundException, RemoteException { + if (Files.notExists(portFilePath)) { + throw new ConnectException("No IPC port file."); + } + try { + int port = ClientCommunicator.readPort(portFilePath); + LOG.debug("Connecting to port {}..."); + Registry registry = LocateRegistry.getRegistry("localhost", port, new ClientSocketFactory()); + this.remote = (IpcProtocolRemote) registry.lookup(RMI_NAME); + } catch (IOException e) { + throw new ConnectException("Error reading IPC port file."); + } + } + + private static int readPort(Path portFilePath) throws IOException { + ByteBuffer buf = ByteBuffer.allocate(Integer.BYTES); + try (ReadableByteChannel ch = Files.newByteChannel(portFilePath, StandardOpenOption.READ)) { + if (ch.read(buf) == Integer.BYTES) { + buf.flip(); + return buf.getInt(); + } else { + throw new IOException("Invalid IPC port file."); + } } - Registry registry = LocateRegistry.getRegistry("localhost", port); - this.remote = (IpcProtocolRemote) registry.lookup(RMI_NAME); } @Override @@ -132,8 +148,9 @@ abstract class InterProcessCommunicator implements InterProcessCommunicationProt private final ServerSocket socket; private final Registry registry; private final IpcProtocolRemoteImpl remote; + private final Path portFilePath; - private ServerCommunicator(InterProcessCommunicationProtocol delegate) throws IOException { + private ServerCommunicator(InterProcessCommunicationProtocol delegate, Path portFilePath) throws IOException { this.socket = new ServerSocket(0, Byte.MAX_VALUE, InetAddress.getByName("localhost")); RMIClientSocketFactory csf = RMISocketFactory.getDefaultSocketFactory(); SingletonServerSocketFactory ssf = new SingletonServerSocketFactory(socket); @@ -141,6 +158,20 @@ abstract class InterProcessCommunicator implements InterProcessCommunicationProt this.remote = new IpcProtocolRemoteImpl(delegate); UnicastRemoteObject.exportObject(remote, 0); registry.rebind(RMI_NAME, remote); + this.portFilePath = portFilePath; + ServerCommunicator.writePort(portFilePath, socket.getLocalPort()); + } + + private static void writePort(Path portFilePath, int port) throws IOException { + ByteBuffer buf = ByteBuffer.allocate(Integer.BYTES); + buf.putInt(port); + buf.flip(); + MoreFiles.createParentDirectories(portFilePath); + try (WritableByteChannel ch = Files.newByteChannel(portFilePath, StandardOpenOption.WRITE, StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING)) { + if (ch.write(buf) != Integer.BYTES) { + throw new IOException("Did not write expected number of bytes."); + } + } } @Override @@ -163,6 +194,7 @@ abstract class InterProcessCommunicator implements InterProcessCommunicationProt registry.unbind(RMI_NAME); UnicastRemoteObject.unexportObject(remote, true); socket.close(); + Files.deleteIfExists(portFilePath); LOG.debug("Server shut down."); } catch (NotBoundException | IOException e) { LOG.warn("Failed to close IPC Server.", e); @@ -211,31 +243,18 @@ abstract class InterProcessCommunicator implements InterProcessCommunicationProt } - private static int readPort(Path path) throws IOException { - if (Files.notExists(path)) { - return 0; - } - ByteBuffer buf = ByteBuffer.allocate(Integer.BYTES); - try (ReadableByteChannel ch = Files.newByteChannel(path, StandardOpenOption.READ)) { - if (ch.read(buf) == Integer.BYTES) { - buf.flip(); - return buf.getInt(); - } else { - return 0; - } - } - } + /** + * Creates client sockets with short timeouts. + */ + private static class ClientSocketFactory implements RMIClientSocketFactory { - private static void writePort(Path path, int port) throws IOException { - ByteBuffer buf = ByteBuffer.allocate(Integer.BYTES); - buf.putInt(port); - buf.flip(); - MoreFiles.createParentDirectories(path); - try (WritableByteChannel ch = Files.newByteChannel(path, StandardOpenOption.WRITE, StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING)) { - if (ch.write(buf) != Integer.BYTES) { - throw new IOException("Did not write expected number of bytes."); - } + @Override + public Socket createSocket(String host, int port) throws IOException { + Socket socket = new Socket(host, port); + socket.setSoTimeout(1000); // 1s + return socket; } + } } From 02f3f5ad536edb8a6799bf90c5eb64e4888d0e48 Mon Sep 17 00:00:00 2001 From: Sebastian Stenzel Date: Thu, 16 Nov 2017 14:56:16 +0100 Subject: [PATCH 19/33] fixed log message [ci skip] --- .../java/org/cryptomator/launcher/InterProcessCommunicator.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/main/launcher/src/main/java/org/cryptomator/launcher/InterProcessCommunicator.java b/main/launcher/src/main/java/org/cryptomator/launcher/InterProcessCommunicator.java index 7c2e56cf1..1c5770189 100644 --- a/main/launcher/src/main/java/org/cryptomator/launcher/InterProcessCommunicator.java +++ b/main/launcher/src/main/java/org/cryptomator/launcher/InterProcessCommunicator.java @@ -102,7 +102,7 @@ abstract class InterProcessCommunicator implements InterProcessCommunicationProt } try { int port = ClientCommunicator.readPort(portFilePath); - LOG.debug("Connecting to port {}..."); + LOG.debug("Connecting to port {}...", port); Registry registry = LocateRegistry.getRegistry("localhost", port, new ClientSocketFactory()); this.remote = (IpcProtocolRemote) registry.lookup(RMI_NAME); } catch (IOException e) { From 9ff710ddf5498139ffb2606e7ffa639046660dd2 Mon Sep 17 00:00:00 2001 From: Markus Kreusch Date: Thu, 16 Nov 2017 15:29:11 +0100 Subject: [PATCH 20/33] Forcing RMI to use sotimeout set by socket factory --- .gitignore | 2 +- .../launcher/InterProcessCommunicator.java | 20 ++++++++++++++++--- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/.gitignore b/.gitignore index 6ff6c8689..7051b0cd0 100644 --- a/.gitignore +++ b/.gitignore @@ -20,4 +20,4 @@ out/ *.iml # Temporary file created by test launcher -main/launcher/ipcPort.tmp +main/launcher/.ipcPort.tmp diff --git a/main/launcher/src/main/java/org/cryptomator/launcher/InterProcessCommunicator.java b/main/launcher/src/main/java/org/cryptomator/launcher/InterProcessCommunicator.java index 1c5770189..e9108cb75 100644 --- a/main/launcher/src/main/java/org/cryptomator/launcher/InterProcessCommunicator.java +++ b/main/launcher/src/main/java/org/cryptomator/launcher/InterProcessCommunicator.java @@ -10,6 +10,8 @@ import java.io.IOException; import java.net.InetAddress; import java.net.ServerSocket; import java.net.Socket; +import java.net.SocketException; +import java.net.UnknownHostException; import java.nio.ByteBuffer; import java.nio.channels.ReadableByteChannel; import java.nio.channels.WritableByteChannel; @@ -250,9 +252,21 @@ abstract class InterProcessCommunicator implements InterProcessCommunicationProt @Override public Socket createSocket(String host, int port) throws IOException { - Socket socket = new Socket(host, port); - socket.setSoTimeout(1000); // 1s - return socket; + return new SocketWithFixedTimeout(host, port, 1000); + } + + } + + private static class SocketWithFixedTimeout extends Socket { + + public SocketWithFixedTimeout(String host, int port, int timeoutInMs) throws UnknownHostException, IOException { + super(host, port); + super.setSoTimeout(timeoutInMs); + } + + @Override + public synchronized void setSoTimeout(int timeout) throws SocketException { + // do nothing, timeout is fixed } } From e18d62d57fde2f65d5bd5886b35410dd50777300 Mon Sep 17 00:00:00 2001 From: armin Date: Fri, 17 Nov 2017 23:54:00 +0100 Subject: [PATCH 21/33] closes #547 --- main/ui/src/main/resources/fxml/main.fxml | 8 ++++---- main/ui/src/main/resources/fxml/unlocked.fxml | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/main/ui/src/main/resources/fxml/main.fxml b/main/ui/src/main/resources/fxml/main.fxml index afc023ea2..93444fc9e 100644 --- a/main/ui/src/main/resources/fxml/main.fxml +++ b/main/ui/src/main/resources/fxml/main.fxml @@ -53,7 +53,7 @@ - + - -