Using 0 prefix instead of _ suffix to mark directories

This commit is contained in:
Sebastian Stenzel 2016-06-30 18:02:13 +02:00
parent 414bbef1a7
commit 07ba4eb537
6 changed files with 20 additions and 18 deletions

View File

@ -5,7 +5,7 @@ public final class Constants {
private Constants() {
}
static final Integer CURRENT_VAULT_VERSION = 3;
static final Integer CURRENT_VAULT_VERSION = 4;
public static final int PAYLOAD_SIZE = 32 * 1024;
public static final int NONCE_SIZE = 16;

View File

@ -26,7 +26,8 @@ import org.cryptomator.siv.SivMode;
class FilenameCryptorImpl implements FilenameCryptor {
private static final BaseNCodec BASE32 = new Base32();
private static final Pattern BASE32_PATTERN = Pattern.compile("([A-Z0-9]{8})*[A-Z0-9=]{8}");
// https://tools.ietf.org/html/rfc4648#section-6
private static final Pattern BASE32_PATTERN = Pattern.compile("([A-Z2-7]{8})*[A-Z2-7=]{8}");
private static final ThreadLocal<MessageDigest> SHA1 = new ThreadLocalSha1();
private static final ThreadLocal<SivMode> AES_SIV = new ThreadLocal<SivMode>() {
@Override

View File

@ -1,6 +1,6 @@
package org.cryptomator.filesystem.crypto;
import static org.cryptomator.filesystem.crypto.Constants.DIR_SUFFIX;
import static org.cryptomator.filesystem.crypto.Constants.DIR_PREFIX;
import java.util.Optional;
import java.util.UUID;
@ -32,7 +32,7 @@ final class ConflictResolver {
}
public File resolveIfNecessary(File file) {
Matcher m = encryptedNamePattern.matcher(StringUtils.removeEnd(file.name(), DIR_SUFFIX));
Matcher m = encryptedNamePattern.matcher(StringUtils.removeStart(file.name(), DIR_PREFIX));
if (m.matches()) {
// full match, use file as is
return file;
@ -47,11 +47,11 @@ final class ConflictResolver {
private File resolveConflict(File conflictingFile, MatchResult matchResult) {
String ciphertext = matchResult.group();
boolean isDirectory = conflictingFile.name().substring(matchResult.end()).startsWith(DIR_SUFFIX);
boolean isDirectory = conflictingFile.name().startsWith(DIR_PREFIX);
Optional<String> cleartext = nameDecryptor.apply(ciphertext);
if (cleartext.isPresent()) {
Folder folder = conflictingFile.parent().get();
File canonicalFile = folder.file(isDirectory ? ciphertext + DIR_SUFFIX : ciphertext);
File canonicalFile = folder.file(isDirectory ? DIR_PREFIX + ciphertext : ciphertext);
if (canonicalFile.exists()) {
// there must not be two directories pointing to the same directory id. In this case no human interaction is needed to resolve this conflict:
if (isDirectory && FileContents.UTF_8.readContents(canonicalFile).equals(FileContents.UTF_8.readContents(conflictingFile))) {
@ -66,7 +66,7 @@ final class ConflictResolver {
conflictId = createConflictId();
String alternativeCleartext = cleartext.get() + " (Conflict " + conflictId + ")";
String alternativeCiphertext = nameEncryptor.apply(alternativeCleartext).get();
alternativeFile = folder.file(isDirectory ? alternativeCiphertext + DIR_SUFFIX : alternativeCiphertext);
alternativeFile = folder.file(isDirectory ? DIR_PREFIX + alternativeCiphertext : alternativeCiphertext);
} while (alternativeFile.exists());
LOG.info("Detected conflict {}:\n{}\n{}", conflictId, canonicalFile, conflictingFile);
conflictingFile.moveTo(alternativeFile);

View File

@ -11,6 +11,6 @@ public final class Constants {
static final String MASTERKEY_FILENAME = "masterkey.cryptomator";
static final String MASTERKEY_BACKUP_FILENAME = "masterkey.cryptomator.bkup";
static final String DIR_SUFFIX = "_";
static final String DIR_PREFIX = "0";
}

View File

@ -10,7 +10,7 @@ package org.cryptomator.filesystem.crypto;
import static java.lang.String.format;
import static java.nio.charset.StandardCharsets.UTF_8;
import static org.cryptomator.filesystem.crypto.Constants.DIR_SUFFIX;
import static org.cryptomator.filesystem.crypto.Constants.DIR_PREFIX;
import java.io.FileNotFoundException;
import java.io.UncheckedIOException;
@ -54,9 +54,9 @@ class CryptoFolder extends CryptoNode implements Folder {
@Override
protected Optional<String> encryptedName() {
if (parent().isPresent()) {
return parent().get().encryptChildName(name()).map(s -> s + DIR_SUFFIX);
return parent().get().encryptChildName(name()).map(s -> DIR_PREFIX + s);
} else {
return Optional.of(cryptor.getFilenameCryptor().encryptFilename(name()) + DIR_SUFFIX);
return Optional.of(DIR_PREFIX + cryptor.getFilenameCryptor().encryptFilename(name()));
}
}
@ -121,20 +121,20 @@ class CryptoFolder extends CryptoNode implements Folder {
@Override
public Stream<CryptoFile> files() {
return nonConflictingFiles().map(File::name).filter(endsWithDirSuffix().negate()).map(this::decryptChildName).filter(Optional::isPresent).map(Optional::get).map(this::file);
return nonConflictingFiles().map(File::name).filter(startsWithDirPrefix().negate()).map(this::decryptChildName).filter(Optional::isPresent).map(Optional::get).map(this::file);
}
@Override
public Stream<CryptoFolder> folders() {
return nonConflictingFiles().map(File::name).filter(endsWithDirSuffix()).map(this::removeDirSuffix).map(this::decryptChildName).filter(Optional::isPresent).map(Optional::get).map(this::folder);
return nonConflictingFiles().map(File::name).filter(startsWithDirPrefix()).map(this::removeDirPrefix).map(this::decryptChildName).filter(Optional::isPresent).map(Optional::get).map(this::folder);
}
private Predicate<String> endsWithDirSuffix() {
return (String encryptedFolderName) -> StringUtils.endsWith(encryptedFolderName, DIR_SUFFIX);
private Predicate<String> startsWithDirPrefix() {
return (String encryptedFolderName) -> StringUtils.startsWith(encryptedFolderName, DIR_PREFIX);
}
private String removeDirSuffix(String encryptedFolderName) {
return StringUtils.removeEnd(encryptedFolderName, DIR_SUFFIX);
private String removeDirPrefix(String encryptedFolderName) {
return StringUtils.removeStart(encryptedFolderName, DIR_PREFIX);
}
@Override

View File

@ -46,7 +46,7 @@ public class ConflictResolverTest {
unrelatedFile = Mockito.mock(File.class);
String canonicalFileName = encode.apply("test name").get();
String canonicalFolderName = canonicalFileName + Constants.DIR_SUFFIX;
String canonicalFolderName = Constants.DIR_PREFIX + canonicalFileName;
String conflictingFileName = canonicalFileName + " (version 2)";
String conflictingFolderName = canonicalFolderName + " (version 2)";
String unrelatedName = "notBa$e32!";
@ -70,6 +70,7 @@ public class ConflictResolverTest {
Mockito.doReturn(Optional.of(folder)).when(unrelatedFile).parent();
Mockito.when(folder.file(Mockito.startsWith(canonicalFileName.substring(0, 8)))).thenReturn(resolved);
Mockito.when(folder.file(Mockito.startsWith(canonicalFolderName.substring(0, 8)))).thenReturn(resolved);
Mockito.when(folder.file(canonicalFileName)).thenReturn(canonicalFile);
Mockito.when(folder.file(canonicalFolderName)).thenReturn(canonicalFolder);
Mockito.when(folder.file(conflictingFileName)).thenReturn(conflictingFile);